Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagesmc
Path: blob/master/build/pkgs/cddlib/patches/cddlp.c
8818 views
1
/* cddlp.c: dual simplex method c-code
2
written by Komei Fukuda, [email protected]
3
Version 0.94f, February 7, 2008
4
*/
5
6
/* cddlp.c : C-Implementation of the dual simplex method for
7
solving an LP: max/min A_(m-1).x subject to x in P, where
8
P= {x : A_i.x >= 0, i=0,...,m-2, and x_0=1}, and
9
A_i is the i-th row of an m x n matrix A.
10
Please read COPYING (GNU General Public Licence) and
11
the manual cddlibman.tex for detail.
12
*/
13
14
#include "setoper.h" /* set operation library header (Ver. May 18, 2000 or later) */
15
#include "cdd.h"
16
#include "random.h"
17
#include <stdio.h>
18
#include <stdlib.h>
19
#include <time.h>
20
#include <math.h>
21
#include <string.h>
22
23
#if defined GMPRATIONAL
24
#include "cdd_f.h"
25
#endif
26
27
#include "random.h" /* include last - overrides RAND_MAX */
28
29
#define dd_CDDLPVERSION "Version 0.94b (August 25, 2005)"
30
31
#define dd_FALSE 0
32
#define dd_TRUE 1
33
34
typedef set_type rowset; /* set_type defined in setoper.h */
35
typedef set_type colset;
36
37
void dd_CrissCrossSolve(dd_LPPtr lp,dd_ErrorType *);
38
void dd_DualSimplexSolve(dd_LPPtr lp,dd_ErrorType *);
39
void dd_CrissCrossMinimize(dd_LPPtr,dd_ErrorType *);
40
void dd_CrissCrossMaximize(dd_LPPtr,dd_ErrorType *);
41
void dd_DualSimplexMinimize(dd_LPPtr,dd_ErrorType *);
42
void dd_DualSimplexMaximize(dd_LPPtr,dd_ErrorType *);
43
void dd_FindLPBasis(dd_rowrange,dd_colrange,dd_Amatrix,dd_Bmatrix,dd_rowindex,dd_rowset,
44
dd_colindex,dd_rowindex,dd_rowrange,dd_colrange,
45
dd_colrange *,int *,dd_LPStatusType *,long *);
46
void dd_FindDualFeasibleBasis(dd_rowrange,dd_colrange,dd_Amatrix,dd_Bmatrix,dd_rowindex,
47
dd_colindex,long *,dd_rowrange,dd_colrange,dd_boolean,
48
dd_colrange *,dd_ErrorType *,dd_LPStatusType *,long *, long maxpivots);
49
50
51
#ifdef GMPRATIONAL
52
void dd_BasisStatus(ddf_LPPtr lpf, dd_LPPtr lp, dd_boolean*);
53
void dd_BasisStatusMinimize(dd_rowrange,dd_colrange, dd_Amatrix,dd_Bmatrix,dd_rowset,
54
dd_rowrange,dd_colrange,ddf_LPStatusType,mytype *,dd_Arow,dd_Arow,dd_rowset,ddf_colindex,
55
ddf_rowrange,ddf_colrange,dd_colrange *,long *, int *, int *);
56
void dd_BasisStatusMaximize(dd_rowrange,dd_colrange,dd_Amatrix,dd_Bmatrix,dd_rowset,
57
dd_rowrange,dd_colrange,ddf_LPStatusType,mytype *,dd_Arow,dd_Arow,dd_rowset,ddf_colindex,
58
ddf_rowrange,ddf_colrange,dd_colrange *,long *, int *, int *);
59
#endif
60
61
void dd_WriteBmatrix(FILE *f,dd_colrange d_size,dd_Bmatrix T);
62
void dd_SetNumberType(char *line,dd_NumberType *number,dd_ErrorType *Error);
63
void dd_ComputeRowOrderVector2(dd_rowrange m_size,dd_colrange d_size,dd_Amatrix A,
64
dd_rowindex OV,dd_RowOrderType ho,unsigned int rseed);
65
void dd_SelectPreorderedNext2(dd_rowrange m_size,dd_colrange d_size,
66
rowset excluded,dd_rowindex OV,dd_rowrange *hnext);
67
void dd_SetSolutions(dd_rowrange,dd_colrange,
68
dd_Amatrix,dd_Bmatrix,dd_rowrange,dd_colrange,dd_LPStatusType,
69
mytype *,dd_Arow,dd_Arow,dd_rowset,dd_colindex,dd_rowrange,dd_colrange,dd_rowindex);
70
71
void dd_WriteTableau(FILE *,dd_rowrange,dd_colrange,dd_Amatrix,dd_Bmatrix,
72
dd_colindex,dd_rowindex);
73
74
void dd_WriteSignTableau(FILE *,dd_rowrange,dd_colrange,dd_Amatrix,dd_Bmatrix,
75
dd_colindex,dd_rowindex);
76
77
78
dd_LPSolutionPtr dd_CopyLPSolution(dd_LPPtr lp)
79
{
80
dd_LPSolutionPtr lps;
81
dd_colrange j;
82
long i;
83
84
lps=(dd_LPSolutionPtr) calloc(1,sizeof(dd_LPSolutionType));
85
for (i=1; i<=dd_filenamelen; i++) lps->filename[i-1]=lp->filename[i-1];
86
lps->objective=lp->objective;
87
lps->solver=lp->solver;
88
lps->m=lp->m;
89
lps->d=lp->d;
90
lps->numbtype=lp->numbtype;
91
92
lps->LPS=lp->LPS; /* the current solution status */
93
dd_init(lps->optvalue);
94
dd_set(lps->optvalue,lp->optvalue); /* optimal value */
95
dd_InitializeArow(lp->d+1,&(lps->sol));
96
dd_InitializeArow(lp->d+1,&(lps->dsol));
97
lps->nbindex=(long*) calloc((lp->d)+1,sizeof(long)); /* dual solution */
98
for (j=0; j<=lp->d; j++){
99
dd_set(lps->sol[j],lp->sol[j]);
100
dd_set(lps->dsol[j],lp->dsol[j]);
101
lps->nbindex[j]=lp->nbindex[j];
102
}
103
lps->pivots[0]=lp->pivots[0];
104
lps->pivots[1]=lp->pivots[1];
105
lps->pivots[2]=lp->pivots[2];
106
lps->pivots[3]=lp->pivots[3];
107
lps->pivots[4]=lp->pivots[4];
108
lps->total_pivots=lp->total_pivots;
109
110
return lps;
111
}
112
113
114
dd_LPPtr dd_CreateLPData(dd_LPObjectiveType obj,
115
dd_NumberType nt,dd_rowrange m,dd_colrange d)
116
{
117
dd_LPType *lp;
118
119
lp=(dd_LPPtr) calloc(1,sizeof(dd_LPType));
120
lp->solver=dd_choiceLPSolverDefault; /* set the default lp solver */
121
lp->d=d;
122
lp->m=m;
123
lp->numbtype=nt;
124
lp->objrow=m;
125
lp->rhscol=1L;
126
lp->objective=dd_LPnone;
127
lp->LPS=dd_LPSundecided;
128
lp->eqnumber=0; /* the number of equalities */
129
130
lp->nbindex=(long*) calloc(d+1,sizeof(long));
131
lp->given_nbindex=(long*) calloc(d+1,sizeof(long));
132
set_initialize(&(lp->equalityset),m);
133
/* i must be in the set iff i-th row is equality . */
134
135
lp->redcheck_extensive=dd_FALSE; /* this is on only for RedundantExtensive */
136
lp->ired=0;
137
set_initialize(&(lp->redset_extra),m);
138
/* i is in the set if i-th row is newly recognized redundant (during the checking the row ired). */
139
set_initialize(&(lp->redset_accum),m);
140
/* i is in the set if i-th row is recognized redundant (during the checking the row ired). */
141
set_initialize(&(lp->posset_extra),m);
142
/* i is in the set if i-th row is recognized non-linearity (during the course of computation). */
143
lp->lexicopivot=dd_choiceLexicoPivotQ; /* dd_choice... is set in dd_set_global_constants() */
144
145
lp->m_alloc=lp->m+2;
146
lp->d_alloc=lp->d+2;
147
lp->objective=obj;
148
dd_InitializeBmatrix(lp->d_alloc,&(lp->B));
149
dd_InitializeAmatrix(lp->m_alloc,lp->d_alloc,&(lp->A));
150
dd_InitializeArow(lp->d_alloc,&(lp->sol));
151
dd_InitializeArow(lp->d_alloc,&(lp->dsol));
152
dd_init(lp->optvalue);
153
return lp;
154
}
155
156
157
dd_LPPtr dd_Matrix2LP(dd_MatrixPtr M, dd_ErrorType *err)
158
{
159
dd_rowrange m, i, irev, linc;
160
dd_colrange d, j;
161
dd_LPType *lp;
162
dd_boolean localdebug=dd_FALSE;
163
164
*err=dd_NoError;
165
linc=set_card(M->linset);
166
m=M->rowsize+1+linc;
167
/* We represent each equation by two inequalities.
168
This is not the best way but makes the code simple. */
169
d=M->colsize;
170
if (localdebug) fprintf(stderr,"number of equalities = %ld\n", linc);
171
172
lp=dd_CreateLPData(M->objective, M->numbtype, m, d);
173
lp->Homogeneous = dd_TRUE;
174
lp->eqnumber=linc; /* this records the number of equations */
175
176
irev=M->rowsize; /* the first row of the linc reversed inequalities. */
177
for (i = 1; i <= M->rowsize; i++) {
178
if (set_member(i, M->linset)) {
179
irev=irev+1;
180
set_addelem(lp->equalityset,i); /* it is equality. */
181
/* the reversed row irev is not in the equality set. */
182
for (j = 1; j <= M->colsize; j++) {
183
dd_neg(lp->A[irev-1][j-1],M->matrix[i-1][j-1]);
184
} /*of j*/
185
if (localdebug) fprintf(stderr,"equality row %ld generates the reverse row %ld.\n",i,irev);
186
}
187
for (j = 1; j <= M->colsize; j++) {
188
dd_set(lp->A[i-1][j-1],M->matrix[i-1][j-1]);
189
if (j==1 && i<M->rowsize && dd_Nonzero(M->matrix[i-1][j-1])) lp->Homogeneous = dd_FALSE;
190
} /*of j*/
191
} /*of i*/
192
for (j = 1; j <= M->colsize; j++) {
193
dd_set(lp->A[m-1][j-1],M->rowvec[j-1]); /* objective row */
194
} /*of j*/
195
196
return lp;
197
}
198
199
dd_LPPtr dd_Matrix2Feasibility(dd_MatrixPtr M, dd_ErrorType *err)
200
/* Load a matrix to create an LP object for feasibility. It is
201
essentially the dd_Matrix2LP except that the objject function
202
is set to identically ZERO (maximization).
203
204
*/
205
/* 094 */
206
{
207
dd_rowrange m, linc;
208
dd_colrange j;
209
dd_LPType *lp;
210
211
*err=dd_NoError;
212
linc=set_card(M->linset);
213
m=M->rowsize+1+linc;
214
/* We represent each equation by two inequalities.
215
This is not the best way but makes the code simple. */
216
217
lp=dd_Matrix2LP(M, err);
218
lp->objective = dd_LPmax; /* since the objective is zero, this is not important */
219
for (j = 1; j <= M->colsize; j++) {
220
dd_set(lp->A[m-1][j-1],dd_purezero); /* set the objective to zero. */
221
} /*of j*/
222
223
return lp;
224
}
225
226
dd_LPPtr dd_Matrix2Feasibility2(dd_MatrixPtr M, dd_rowset R, dd_rowset S, dd_ErrorType *err)
227
/* Load a matrix to create an LP object for feasibility with additional equality and
228
strict inequality constraints given by R and S. There are three types of inequalities:
229
230
b_r + A_r x = 0 Linearity (Equations) specified by M
231
b_s + A_s x > 0 Strict Inequalities specified by row index set S
232
b_t + A_t x >= 0 The rest inequalities in M
233
234
Where the linearity is considered here as the union of linearity specified by
235
M and the additional set R. When S contains any linearity rows, those
236
rows are considered linearity (equation). Thus S does not overlide linearity.
237
To find a feasible solution, we set an LP
238
239
maximize z
240
subject to
241
b_r + A_r x = 0 all r in Linearity
242
b_s + A_s x - z >= 0 for all s in S
243
b_t + A_t x >= 0 for all the rest rows t
244
1 - z >= 0 to make the LP bounded.
245
246
Clearly, the feasibility problem has a solution iff the LP has a positive optimal value.
247
The variable z will be the last variable x_{d+1}.
248
249
*/
250
/* 094 */
251
{
252
dd_rowrange m, i, irev, linc;
253
dd_colrange d, j;
254
dd_LPType *lp;
255
dd_rowset L;
256
dd_boolean localdebug=dd_FALSE;
257
258
*err=dd_NoError;
259
set_initialize(&L, M->rowsize);
260
set_uni(L,M->linset,R);
261
linc=set_card(L);
262
m=M->rowsize+1+linc+1;
263
/* We represent each equation by two inequalities.
264
This is not the best way but makes the code simple. */
265
d=M->colsize+1;
266
if (localdebug) fprintf(stderr,"number of equalities = %ld\n", linc);
267
268
lp=dd_CreateLPData(dd_LPmax, M->numbtype, m, d);
269
lp->Homogeneous = dd_TRUE;
270
lp->eqnumber=linc; /* this records the number of equations */
271
272
irev=M->rowsize; /* the first row of the linc reversed inequalities. */
273
for (i = 1; i <= M->rowsize; i++) {
274
if (set_member(i, L)) {
275
irev=irev+1;
276
set_addelem(lp->equalityset,i); /* it is equality. */
277
/* the reversed row irev is not in the equality set. */
278
for (j = 1; j <= M->colsize; j++) {
279
dd_neg(lp->A[irev-1][j-1],M->matrix[i-1][j-1]);
280
} /*of j*/
281
if (localdebug) fprintf(stderr,"equality row %ld generates the reverse row %ld.\n",i,irev);
282
} else if (set_member(i, S)) {
283
dd_set(lp->A[i-1][M->colsize],dd_minusone);
284
}
285
for (j = 1; j <= M->colsize; j++) {
286
dd_set(lp->A[i-1][j-1],M->matrix[i-1][j-1]);
287
if (j==1 && i<M->rowsize && dd_Nonzero(M->matrix[i-1][j-1])) lp->Homogeneous = dd_FALSE;
288
} /*of j*/
289
} /*of i*/
290
for (j = 1; j <= d; j++) {
291
dd_set(lp->A[m-2][j-1],dd_purezero); /* initialize */
292
} /*of j*/
293
dd_set(lp->A[m-2][0],dd_one); /* the bounding constraint. */
294
dd_set(lp->A[m-2][M->colsize],dd_minusone); /* the bounding constraint. */
295
for (j = 1; j <= d; j++) {
296
dd_set(lp->A[m-1][j-1],dd_purezero); /* initialize */
297
} /*of j*/
298
dd_set(lp->A[m-1][M->colsize],dd_one); /* maximize z */
299
300
set_free(L);
301
return lp;
302
}
303
304
305
306
void dd_FreeLPData(dd_LPPtr lp)
307
{
308
if ((lp)!=NULL){
309
dd_clear(lp->optvalue);
310
dd_FreeArow(lp->d_alloc,lp->dsol);
311
dd_FreeArow(lp->d_alloc,lp->sol);
312
dd_FreeBmatrix(lp->d_alloc,lp->B);
313
dd_FreeAmatrix(lp->m_alloc,lp->d_alloc,lp->A);
314
set_free(lp->equalityset);
315
set_free(lp->redset_extra);
316
set_free(lp->redset_accum);
317
set_free(lp->posset_extra);
318
free(lp->nbindex);
319
free(lp->given_nbindex);
320
free(lp);
321
}
322
}
323
324
void dd_FreeLPSolution(dd_LPSolutionPtr lps)
325
{
326
if (lps!=NULL){
327
free(lps->nbindex);
328
dd_FreeArow(lps->d+1,lps->dsol);
329
dd_FreeArow(lps->d+1,lps->sol);
330
dd_clear(lps->optvalue);
331
332
free(lps);
333
}
334
}
335
336
int dd_LPReverseRow(dd_LPPtr lp, dd_rowrange i)
337
{
338
dd_colrange j;
339
int success=0;
340
341
if (i>=1 && i<=lp->m){
342
lp->LPS=dd_LPSundecided;
343
for (j=1; j<=lp->d; j++) {
344
dd_neg(lp->A[i-1][j-1],lp->A[i-1][j-1]);
345
/* negating the i-th constraint of A */
346
}
347
success=1;
348
}
349
return success;
350
}
351
352
int dd_LPReplaceRow(dd_LPPtr lp, dd_rowrange i, dd_Arow a)
353
{
354
dd_colrange j;
355
int success=0;
356
357
if (i>=1 && i<=lp->m){
358
lp->LPS=dd_LPSundecided;
359
for (j=1; j<=lp->d; j++) {
360
dd_set(lp->A[i-1][j-1],a[j-1]);
361
/* replacing the i-th constraint by a */
362
}
363
success=1;
364
}
365
return success;
366
}
367
368
dd_Arow dd_LPCopyRow(dd_LPPtr lp, dd_rowrange i)
369
{
370
dd_colrange j;
371
dd_Arow a;
372
373
if (i>=1 && i<=lp->m){
374
dd_InitializeArow(lp->d, &a);
375
for (j=1; j<=lp->d; j++) {
376
dd_set(a[j-1],lp->A[i-1][j-1]);
377
/* copying the i-th row to a */
378
}
379
}
380
return a;
381
}
382
383
384
void dd_SetNumberType(char *line,dd_NumberType *number,dd_ErrorType *Error)
385
{
386
if (strncmp(line,"integer",7)==0) {
387
*number = dd_Integer;
388
return;
389
}
390
else if (strncmp(line,"rational",8)==0) {
391
*number = dd_Rational;
392
return;
393
}
394
else if (strncmp(line,"real",4)==0) {
395
*number = dd_Real;
396
return;
397
}
398
else {
399
*number=dd_Unknown;
400
*Error=dd_ImproperInputFormat;
401
}
402
}
403
404
405
void dd_WriteTableau(FILE *f,dd_rowrange m_size,dd_colrange d_size,dd_Amatrix A,dd_Bmatrix T,
406
dd_colindex nbindex,dd_rowindex bflag)
407
/* Write the tableau A.T */
408
{
409
dd_colrange j;
410
dd_rowrange i;
411
mytype x;
412
413
dd_init(x);
414
fprintf(f," %ld %ld real\n",m_size,d_size);
415
fprintf(f," |");
416
for (j=1; j<= d_size; j++) {
417
fprintf(f," %ld",nbindex[j]);
418
} fprintf(f,"\n");
419
for (j=1; j<= d_size+1; j++) {
420
fprintf(f," ----");
421
} fprintf(f,"\n");
422
for (i=1; i<= m_size; i++) {
423
fprintf(f," %3ld(%3ld) |",i,bflag[i]);
424
for (j=1; j<= d_size; j++) {
425
dd_TableauEntry(&x,m_size,d_size,A,T,i,j);
426
dd_WriteNumber(f,x);
427
}
428
fprintf(f,"\n");
429
}
430
fprintf(f,"end\n");
431
dd_clear(x);
432
}
433
434
void dd_WriteSignTableau(FILE *f,dd_rowrange m_size,dd_colrange d_size,dd_Amatrix A,dd_Bmatrix T,
435
dd_colindex nbindex,dd_rowindex bflag)
436
/* Write the sign tableau A.T */
437
{
438
dd_colrange j;
439
dd_rowrange i;
440
mytype x;
441
442
dd_init(x);
443
fprintf(f," %ld %ld real\n",m_size,d_size);
444
fprintf(f," |");
445
for (j=1; j<= d_size; j++) {
446
fprintf(f,"%3ld",nbindex[j]);
447
} fprintf(f,"\n ------- | ");
448
for (j=1; j<= d_size; j++) {
449
fprintf(f,"---");
450
} fprintf(f,"\n");
451
for (i=1; i<= m_size; i++) {
452
fprintf(f," %3ld(%3ld) |",i,bflag[i]);
453
for (j=1; j<= d_size; j++) {
454
dd_TableauEntry(&x,m_size,d_size,A,T,i,j);
455
if (dd_Positive(x)) fprintf(f, " +");
456
else if (dd_Negative(x)) fprintf(f, " -");
457
else fprintf(f, " 0");
458
}
459
fprintf(f,"\n");
460
}
461
fprintf(f,"end\n");
462
dd_clear(x);
463
}
464
465
void dd_WriteSignTableau2(FILE *f,dd_rowrange m_size,dd_colrange d_size,dd_Amatrix A,dd_Bmatrix T,
466
dd_colindex nbindex_ref, dd_colindex nbindex,dd_rowindex bflag)
467
/* Write the sign tableau A.T and the reference basis */
468
{
469
dd_colrange j;
470
dd_rowrange i;
471
mytype x;
472
473
dd_init(x);
474
fprintf(f," %ld %ld real\n",m_size,d_size);
475
fprintf(f," |");
476
for (j=1; j<= d_size; j++) fprintf(f,"%3ld",nbindex_ref[j]);
477
fprintf(f,"\n |");
478
for (j=1; j<= d_size; j++) {
479
fprintf(f,"%3ld",nbindex[j]);
480
} fprintf(f,"\n ------- | ");
481
for (j=1; j<= d_size; j++) {
482
fprintf(f,"---");
483
} fprintf(f,"\n");
484
for (i=1; i<= m_size; i++) {
485
fprintf(f," %3ld(%3ld) |",i,bflag[i]);
486
for (j=1; j<= d_size; j++) {
487
dd_TableauEntry(&x,m_size,d_size,A,T,i,j);
488
if (dd_Positive(x)) fprintf(f, " +");
489
else if (dd_Negative(x)) fprintf(f, " -");
490
else fprintf(f, " 0");
491
}
492
fprintf(f,"\n");
493
}
494
fprintf(f,"end\n");
495
dd_clear(x);
496
}
497
498
499
void dd_GetRedundancyInformation(dd_rowrange m_size,dd_colrange d_size,dd_Amatrix A,dd_Bmatrix T,
500
dd_colindex nbindex,dd_rowindex bflag, dd_rowset redset)
501
/* Some basic variables that are forced to be nonnegative will be output. These are
502
variables whose dictionary row components are all nonnegative. */
503
{
504
dd_colrange j;
505
dd_rowrange i;
506
mytype x;
507
dd_boolean red=dd_FALSE,localdebug=dd_FALSE;
508
long numbred=0;
509
510
dd_init(x);
511
for (i=1; i<= m_size; i++) {
512
red=dd_TRUE;
513
for (j=1; j<= d_size; j++) {
514
dd_TableauEntry(&x,m_size,d_size,A,T,i,j);
515
if (red && dd_Negative(x)) red=dd_FALSE;
516
}
517
if (bflag[i]<0 && red) {
518
numbred+=1;
519
set_addelem(redset,i);
520
}
521
}
522
if (localdebug) fprintf(stderr,"\ndd_GetRedundancyInformation: %ld redundant rows over %ld\n",numbred, m_size);
523
dd_clear(x);
524
}
525
526
527
void dd_SelectDualSimplexPivot(dd_rowrange m_size,dd_colrange d_size,
528
int Phase1,dd_Amatrix A,dd_Bmatrix T,dd_rowindex OV,
529
dd_colindex nbindex_ref, dd_colindex nbindex,dd_rowindex bflag,
530
dd_rowrange objrow,dd_colrange rhscol, dd_boolean lexicopivot,
531
dd_rowrange *r,dd_colrange *s,int *selected,dd_LPStatusType *lps)
532
{
533
/* selects a dual simplex pivot (*r,*s) if the current
534
basis is dual feasible and not optimal. If not dual feasible,
535
the procedure returns *selected=dd_FALSE and *lps=LPSundecided.
536
If Phase1=dd_TRUE, the RHS column will be considered as the negative
537
of the column of the largest variable (==m_size). For this case, it is assumed
538
that the caller used the auxiliary row (with variable m_size) to make the current
539
dictionary dual feasible before calling this routine so that the nonbasic
540
column for m_size corresponds to the auxiliary variable.
541
*/
542
dd_boolean colselected=dd_FALSE,rowselected=dd_FALSE,
543
dualfeasible=dd_TRUE,localdebug=dd_FALSE;
544
dd_rowrange i,iref;
545
dd_colrange j,k;
546
mytype val,valn, minval,rat,minrat;
547
static dd_Arow rcost;
548
static dd_colrange d_last=0;
549
static dd_colset tieset,stieset; /* store the column indices with tie */
550
551
dd_init(val); dd_init(valn); dd_init(minval); dd_init(rat); dd_init(minrat);
552
if (d_last<d_size) {
553
if (d_last>0) {
554
for (j=1; j<=d_last; j++){ dd_clear(rcost[j-1]);}
555
free(rcost);
556
set_free(tieset);
557
set_free(stieset);
558
}
559
rcost=(mytype*) calloc(d_size,sizeof(mytype));
560
for (j=1; j<=d_size; j++){ dd_init(rcost[j-1]);}
561
set_initialize(&tieset,d_size);
562
set_initialize(&stieset,d_size);
563
}
564
d_last=d_size;
565
566
*r=0; *s=0;
567
*selected=dd_FALSE;
568
*lps=dd_LPSundecided;
569
for (j=1; j<=d_size; j++){
570
if (j!=rhscol){
571
dd_TableauEntry(&(rcost[j-1]),m_size,d_size,A,T,objrow,j);
572
if (dd_Positive(rcost[j-1])) {
573
dualfeasible=dd_FALSE;
574
}
575
}
576
}
577
if (dualfeasible){
578
while ((*lps==dd_LPSundecided) && (!rowselected) && (!colselected)) {
579
for (i=1; i<=m_size; i++) {
580
if (i!=objrow && bflag[i]==-1) { /* i is a basic variable */
581
if (Phase1){
582
dd_TableauEntry(&val, m_size,d_size,A,T,i,bflag[m_size]);
583
dd_neg(val,val);
584
/* for dual Phase I. The RHS (dual objective) is the negative of the auxiliary variable column. */
585
}
586
else {dd_TableauEntry(&val,m_size,d_size,A,T,i,rhscol);}
587
if (dd_Smaller(val,minval)) {
588
*r=i;
589
dd_set(minval,val);
590
}
591
}
592
}
593
if (dd_Nonnegative(minval)) {
594
*lps=dd_Optimal;
595
}
596
else {
597
rowselected=dd_TRUE;
598
set_emptyset(tieset);
599
for (j=1; j<=d_size; j++){
600
dd_TableauEntry(&val,m_size,d_size,A,T,*r,j);
601
if (j!=rhscol && dd_Positive(val)) {
602
dd_div(rat,rcost[j-1],val);
603
dd_neg(rat,rat);
604
if (*s==0 || dd_Smaller(rat,minrat)){
605
dd_set(minrat,rat);
606
*s=j;
607
set_emptyset(tieset);
608
set_addelem(tieset, j);
609
} else if (dd_Equal(rat,minrat)){
610
set_addelem(tieset,j);
611
}
612
}
613
}
614
if (*s>0) {
615
if (!lexicopivot || set_card(tieset)==1){
616
colselected=dd_TRUE; *selected=dd_TRUE;
617
} else { /* lexicographic rule with respect to the given reference cobasis. */
618
if (localdebug) {printf("Tie occurred at:"); set_write(tieset); printf("\n");
619
dd_WriteTableau(stderr,m_size,d_size,A,T,nbindex,bflag);
620
}
621
*s=0;
622
k=2; /* k runs through the column indices except RHS. */
623
do {
624
iref=nbindex_ref[k]; /* iref runs though the reference basic indices */
625
if (iref>0) {
626
j=bflag[iref];
627
if (j>0) {
628
if (set_member(j,tieset) && set_card(tieset)==1) {
629
*s=j;
630
colselected=dd_TRUE;
631
} else {
632
set_delelem(tieset, j);
633
/* iref is cobasic, and the corresponding col is not the pivot column except it is the last one. */
634
}
635
} else {
636
*s=0;
637
for (j=1; j<=d_size; j++){
638
if (set_member(j,tieset)) {
639
dd_TableauEntry(&val,m_size,d_size,A,T,*r,j);
640
dd_TableauEntry(&valn,m_size,d_size,A,T,iref,j);
641
if (j!=rhscol && dd_Positive(val)) {
642
dd_div(rat,valn,val);
643
if (*s==0 || dd_Smaller(rat,minrat)){
644
dd_set(minrat,rat);
645
*s=j;
646
set_emptyset(stieset);
647
set_addelem(stieset, j);
648
} else if (dd_Equal(rat,minrat)){
649
set_addelem(stieset,j);
650
}
651
}
652
}
653
}
654
set_copy(tieset,stieset);
655
if (set_card(tieset)==1) colselected=dd_TRUE;
656
}
657
}
658
k+=1;
659
} while (!colselected && k<=d_size);
660
*selected=dd_TRUE;
661
}
662
} else *lps=dd_Inconsistent;
663
}
664
} /* end of while */
665
}
666
if (localdebug) {
667
if (Phase1) fprintf(stderr,"Phase 1 : select %ld,%ld\n",*r,*s);
668
else fprintf(stderr,"Phase 2 : select %ld,%ld\n",*r,*s);
669
}
670
dd_clear(val); dd_clear(valn); dd_clear(minval); dd_clear(rat); dd_clear(minrat);
671
}
672
673
void dd_TableauEntry(mytype *x,dd_rowrange m_size, dd_colrange d_size, dd_Amatrix X, dd_Bmatrix T,
674
dd_rowrange r, dd_colrange s)
675
/* Compute the (r,s) entry of X.T */
676
{
677
dd_colrange j;
678
mytype temp;
679
680
dd_init(temp);
681
dd_set(*x,dd_purezero);
682
for (j=0; j< d_size; j++) {
683
dd_mul(temp,X[r-1][j], T[j][s-1]);
684
dd_add(*x, *x, temp);
685
}
686
dd_clear(temp);
687
}
688
689
void dd_SelectPivot2(dd_rowrange m_size,dd_colrange d_size,dd_Amatrix A,dd_Bmatrix T,
690
dd_RowOrderType roworder,dd_rowindex ordervec, rowset equalityset,
691
dd_rowrange rowmax,rowset NopivotRow,
692
colset NopivotCol,dd_rowrange *r,dd_colrange *s,
693
dd_boolean *selected)
694
/* Select a position (*r,*s) in the matrix A.T such that (A.T)[*r][*s] is nonzero
695
The choice is feasible, i.e., not on NopivotRow and NopivotCol, and
696
best with respect to the specified roworder
697
*/
698
{
699
int stop;
700
dd_rowrange i,rtemp;
701
rowset rowexcluded;
702
mytype Xtemp;
703
dd_boolean localdebug=dd_FALSE;
704
705
stop = dd_FALSE;
706
localdebug=dd_debug;
707
dd_init(Xtemp);
708
set_initialize(&rowexcluded,m_size);
709
set_copy(rowexcluded,NopivotRow);
710
for (i=rowmax+1;i<=m_size;i++) {
711
set_addelem(rowexcluded,i); /* cannot pivot on any row > rmax */
712
}
713
*selected = dd_FALSE;
714
do {
715
rtemp=0; i=1;
716
while (i<=m_size && rtemp==0) { /* equalityset vars have highest priorities */
717
if (set_member(i,equalityset) && !set_member(i,rowexcluded)){
718
if (localdebug) fprintf(stderr,"marked set %ld chosen as a candidate\n",i);
719
rtemp=i;
720
}
721
i++;
722
}
723
if (rtemp==0) dd_SelectPreorderedNext2(m_size,d_size,rowexcluded,ordervec,&rtemp);;
724
if (rtemp>=1) {
725
*r=rtemp;
726
*s=1;
727
while (*s <= d_size && !*selected) {
728
dd_TableauEntry(&Xtemp,m_size,d_size,A,T,*r,*s);
729
if (!set_member(*s,NopivotCol) && dd_Nonzero(Xtemp)) {
730
*selected = dd_TRUE;
731
stop = dd_TRUE;
732
} else {
733
(*s)++;
734
}
735
}
736
if (!*selected) {
737
set_addelem(rowexcluded,rtemp);
738
}
739
}
740
else {
741
*r = 0;
742
*s = 0;
743
stop = dd_TRUE;
744
}
745
} while (!stop);
746
set_free(rowexcluded); dd_clear(Xtemp);
747
}
748
749
void dd_GaussianColumnPivot(dd_rowrange m_size, dd_colrange d_size,
750
dd_Amatrix X, dd_Bmatrix T, dd_rowrange r, dd_colrange s)
751
/* Update the Transformation matrix T with the pivot operation on (r,s)
752
This procedure performs a implicit pivot operation on the matrix X by
753
updating the dual basis inverse T.
754
*/
755
{
756
dd_colrange j, j1;
757
mytype Xtemp0, Xtemp1, Xtemp;
758
static dd_Arow Rtemp;
759
static dd_colrange last_d=0;
760
761
dd_init(Xtemp0); dd_init(Xtemp1); dd_init(Xtemp);
762
if (last_d!=d_size){
763
if (last_d>0) {
764
for (j=1; j<=last_d; j++) dd_clear(Rtemp[j-1]);
765
free(Rtemp);
766
}
767
Rtemp=(mytype*)calloc(d_size,sizeof(mytype));
768
for (j=1; j<=d_size; j++) dd_init(Rtemp[j-1]);
769
last_d=d_size;
770
}
771
772
for (j=1; j<=d_size; j++) {
773
dd_TableauEntry(&(Rtemp[j-1]), m_size, d_size, X, T, r,j);
774
}
775
dd_set(Xtemp0,Rtemp[s-1]);
776
for (j = 1; j <= d_size; j++) {
777
if (j != s) {
778
dd_div(Xtemp,Rtemp[j-1],Xtemp0);
779
dd_set(Xtemp1,dd_purezero);
780
for (j1 = 1; j1 <= d_size; j1++){
781
dd_mul(Xtemp1,Xtemp,T[j1-1][s - 1]);
782
dd_sub(T[j1-1][j-1],T[j1-1][j-1],Xtemp1);
783
/* T[j1-1][j-1] -= T[j1-1][s - 1] * Xtemp / Xtemp0; */
784
}
785
}
786
}
787
for (j = 1; j <= d_size; j++)
788
dd_div(T[j-1][s - 1],T[j-1][s - 1],Xtemp0);
789
790
dd_clear(Xtemp0); dd_clear(Xtemp1); dd_clear(Xtemp);
791
}
792
793
void dd_GaussianColumnPivot2(dd_rowrange m_size,dd_colrange d_size,
794
dd_Amatrix A,dd_Bmatrix T,dd_colindex nbindex,dd_rowindex bflag,dd_rowrange r,dd_colrange s)
795
/* Update the Transformation matrix T with the pivot operation on (r,s)
796
This procedure performs a implicit pivot operation on the matrix A by
797
updating the dual basis inverse T.
798
*/
799
{
800
int localdebug=dd_FALSE;
801
long entering;
802
803
if (dd_debug) localdebug=dd_debug;
804
dd_GaussianColumnPivot(m_size,d_size,A,T,r,s);
805
entering=nbindex[s];
806
bflag[r]=s; /* the nonbasic variable r corresponds to column s */
807
nbindex[s]=r; /* the nonbasic variable on s column is r */
808
809
if (entering>0) bflag[entering]=-1;
810
/* original variables have negative index and should not affect the row index */
811
812
if (localdebug) {
813
fprintf(stderr,"dd_GaussianColumnPivot2\n");
814
fprintf(stderr," pivot: (leaving, entering) = (%ld, %ld)\n", r,entering);
815
fprintf(stderr, " bflag[%ld] is set to %ld\n", r, s);
816
}
817
}
818
819
820
void dd_ResetTableau(dd_rowrange m_size,dd_colrange d_size,dd_Bmatrix T,
821
dd_colindex nbindex,dd_rowindex bflag,dd_rowrange objrow,dd_colrange rhscol)
822
{
823
dd_rowrange i;
824
dd_colrange j;
825
826
/* Initialize T and nbindex */
827
for (j=1; j<=d_size; j++) nbindex[j]=-j;
828
nbindex[rhscol]=0;
829
/* RHS is already in nonbasis and is considered to be associated
830
with the zero-th row of input. */
831
dd_SetToIdentity(d_size,T);
832
833
/* Set the bflag according to nbindex */
834
for (i=1; i<=m_size; i++) bflag[i]=-1;
835
/* all basic variables have index -1 */
836
bflag[objrow]= 0;
837
/* bflag of the objective variable is 0,
838
different from other basic variables which have -1 */
839
for (j=1; j<=d_size; j++) if (nbindex[j]>0) bflag[nbindex[j]]=j;
840
/* bflag of a nonbasic variable is its column number */
841
842
}
843
844
void dd_SelectCrissCrossPivot(dd_rowrange m_size,dd_colrange d_size,dd_Amatrix A,dd_Bmatrix T,
845
dd_rowindex bflag,dd_rowrange objrow,dd_colrange rhscol,
846
dd_rowrange *r,dd_colrange *s,
847
int *selected,dd_LPStatusType *lps)
848
{
849
int colselected=dd_FALSE,rowselected=dd_FALSE;
850
dd_rowrange i;
851
mytype val;
852
853
dd_init(val);
854
*selected=dd_FALSE;
855
*lps=dd_LPSundecided;
856
while ((*lps==dd_LPSundecided) && (!rowselected) && (!colselected)) {
857
for (i=1; i<=m_size; i++) {
858
if (i!=objrow && bflag[i]==-1) { /* i is a basic variable */
859
dd_TableauEntry(&val,m_size,d_size,A,T,i,rhscol);
860
if (dd_Negative(val)) {
861
rowselected=dd_TRUE;
862
*r=i;
863
break;
864
}
865
}
866
else if (bflag[i] >0) { /* i is nonbasic variable */
867
dd_TableauEntry(&val,m_size,d_size,A,T,objrow,bflag[i]);
868
if (dd_Positive(val)) {
869
colselected=dd_TRUE;
870
*s=bflag[i];
871
break;
872
}
873
}
874
}
875
if ((!rowselected) && (!colselected)) {
876
*lps=dd_Optimal;
877
return;
878
}
879
else if (rowselected) {
880
for (i=1; i<=m_size; i++) {
881
if (bflag[i] >0) { /* i is nonbasic variable */
882
dd_TableauEntry(&val,m_size,d_size,A,T,*r,bflag[i]);
883
if (dd_Positive(val)) {
884
colselected=dd_TRUE;
885
*s=bflag[i];
886
*selected=dd_TRUE;
887
break;
888
}
889
}
890
}
891
}
892
else if (colselected) {
893
for (i=1; i<=m_size; i++) {
894
if (i!=objrow && bflag[i]==-1) { /* i is a basic variable */
895
dd_TableauEntry(&val,m_size,d_size,A,T,i,*s);
896
if (dd_Negative(val)) {
897
rowselected=dd_TRUE;
898
*r=i;
899
*selected=dd_TRUE;
900
break;
901
}
902
}
903
}
904
}
905
if (!rowselected) {
906
*lps=dd_DualInconsistent;
907
}
908
else if (!colselected) {
909
*lps=dd_Inconsistent;
910
}
911
}
912
dd_clear(val);
913
}
914
915
void dd_CrissCrossSolve(dd_LPPtr lp, dd_ErrorType *err)
916
{
917
switch (lp->objective) {
918
case dd_LPmax:
919
dd_CrissCrossMaximize(lp,err);
920
break;
921
922
case dd_LPmin:
923
dd_CrissCrossMinimize(lp,err);
924
break;
925
926
case dd_LPnone: *err=dd_NoLPObjective; break;
927
}
928
929
}
930
931
void dd_DualSimplexSolve(dd_LPPtr lp, dd_ErrorType *err)
932
{
933
switch (lp->objective) {
934
case dd_LPmax:
935
dd_DualSimplexMaximize(lp,err);
936
break;
937
938
case dd_LPmin:
939
dd_DualSimplexMinimize(lp,err);
940
break;
941
942
case dd_LPnone: *err=dd_NoLPObjective; break;
943
}
944
}
945
946
#ifdef GMPRATIONAL
947
948
dd_LPStatusType LPSf2LPS(ddf_LPStatusType lpsf)
949
{
950
dd_LPStatusType lps=dd_LPSundecided;
951
952
switch (lpsf) {
953
case ddf_LPSundecided: lps=dd_LPSundecided; break;
954
case ddf_Optimal: lps=dd_Optimal; break;
955
case ddf_Inconsistent: lps=dd_Inconsistent; break;
956
case ddf_DualInconsistent: lps=dd_DualInconsistent; break;
957
case ddf_StrucInconsistent: lps=dd_StrucInconsistent; break;
958
case ddf_StrucDualInconsistent: lps=dd_StrucDualInconsistent; break;
959
case ddf_Unbounded: lps=dd_Unbounded; break;
960
case ddf_DualUnbounded: lps=dd_DualUnbounded; break;
961
}
962
return lps;
963
}
964
965
966
void dd_BasisStatus(ddf_LPPtr lpf, dd_LPPtr lp, dd_boolean *LPScorrect)
967
{
968
int i;
969
dd_colrange se, j;
970
dd_boolean basisfound;
971
972
switch (lp->objective) {
973
case dd_LPmax:
974
dd_BasisStatusMaximize(lp->m,lp->d,lp->A,lp->B,lp->equalityset,lp->objrow,lp->rhscol,
975
lpf->LPS,&(lp->optvalue),lp->sol,lp->dsol,lp->posset_extra,lpf->nbindex,lpf->re,lpf->se,&se,lp->pivots,
976
&basisfound, LPScorrect);
977
if (*LPScorrect) {
978
/* printf("BasisStatus Check: the current basis is verified with GMP\n"); */
979
lp->LPS=LPSf2LPS(lpf->LPS);
980
lp->re=lpf->re;
981
lp->se=se;
982
for (j=1; j<=lp->d; j++) lp->nbindex[j]=lpf->nbindex[j];
983
}
984
for (i=1; i<=5; i++) lp->pivots[i-1]+=lpf->pivots[i-1];
985
break;
986
case dd_LPmin:
987
dd_BasisStatusMinimize(lp->m,lp->d,lp->A,lp->B,lp->equalityset,lp->objrow,lp->rhscol,
988
lpf->LPS,&(lp->optvalue),lp->sol,lp->dsol,lp->posset_extra,lpf->nbindex,lpf->re,lpf->se,&se,lp->pivots,
989
&basisfound, LPScorrect);
990
if (*LPScorrect) {
991
/* printf("BasisStatus Check: the current basis is verified with GMP\n"); */
992
lp->LPS=LPSf2LPS(lpf->LPS);
993
lp->re=lpf->re;
994
lp->se=se;
995
for (j=1; j<=lp->d; j++) lp->nbindex[j]=lpf->nbindex[j];
996
}
997
for (i=1; i<=5; i++) lp->pivots[i-1]+=lpf->pivots[i-1];
998
break;
999
case dd_LPnone: break;
1000
}
1001
}
1002
#endif
1003
1004
void dd_FindLPBasis(dd_rowrange m_size,dd_colrange d_size,
1005
dd_Amatrix A, dd_Bmatrix T,dd_rowindex OV,dd_rowset equalityset, dd_colindex nbindex,
1006
dd_rowindex bflag,dd_rowrange objrow,dd_colrange rhscol,
1007
dd_colrange *cs,int *found,dd_LPStatusType *lps,long *pivot_no)
1008
{
1009
/* Find a LP basis using Gaussian pivots.
1010
If the problem has an LP basis,
1011
the procedure returns *found=dd_TRUE,*lps=LPSundecided and an LP basis.
1012
If the constraint matrix A (excluding the rhs and objective) is not
1013
column independent, there are two cases. If the dependency gives a dual
1014
inconsistency, this returns *found=dd_FALSE, *lps=dd_StrucDualInconsistent and
1015
the evidence column *s. Otherwise, this returns *found=dd_TRUE,
1016
*lps=LPSundecided and an LP basis of size less than d_size. Columns j
1017
that do not belong to the basis (i.e. cannot be chosen as pivot because
1018
they are all zero) will be indicated in nbindex vector: nbindex[j] will
1019
be negative and set to -j.
1020
*/
1021
int chosen,stop;
1022
long pivots_p0=0,rank;
1023
colset ColSelected;
1024
rowset RowSelected;
1025
mytype val;
1026
1027
dd_rowrange r;
1028
dd_colrange j,s;
1029
1030
dd_init(val);
1031
*found=dd_FALSE; *cs=0; rank=0;
1032
stop=dd_FALSE;
1033
*lps=dd_LPSundecided;
1034
1035
set_initialize(&RowSelected,m_size);
1036
set_initialize(&ColSelected,d_size);
1037
set_addelem(RowSelected,objrow);
1038
set_addelem(ColSelected,rhscol);
1039
1040
stop=dd_FALSE;
1041
do { /* Find a LP basis */
1042
dd_SelectPivot2(m_size,d_size,A,T,dd_MinIndex,OV,equalityset,
1043
m_size,RowSelected,ColSelected,&r,&s,&chosen);
1044
if (chosen) {
1045
set_addelem(RowSelected,r);
1046
set_addelem(ColSelected,s);
1047
dd_GaussianColumnPivot2(m_size,d_size,A,T,nbindex,bflag,r,s);
1048
pivots_p0++;
1049
rank++;
1050
} else {
1051
for (j=1;j<=d_size && *lps==dd_LPSundecided; j++) {
1052
if (j!=rhscol && nbindex[j]<0){
1053
dd_TableauEntry(&val,m_size,d_size,A,T,objrow,j);
1054
if (dd_Nonzero(val)){ /* dual inconsistent */
1055
*lps=dd_StrucDualInconsistent;
1056
*cs=j;
1057
/* dual inconsistent because the nonzero reduced cost */
1058
}
1059
}
1060
}
1061
if (*lps==dd_LPSundecided) *found=dd_TRUE;
1062
/* dependent columns but not dual inconsistent. */
1063
stop=dd_TRUE;
1064
}
1065
/* printf("d_size=%ld, rank=%ld\n",d_size,rank); */
1066
if (rank==d_size-1) {
1067
stop = dd_TRUE;
1068
*found=dd_TRUE;
1069
}
1070
} while (!stop);
1071
1072
*pivot_no=pivots_p0;
1073
dd_statBApivots+=pivots_p0;
1074
set_free(RowSelected);
1075
set_free(ColSelected);
1076
dd_clear(val);
1077
}
1078
1079
1080
void dd_FindLPBasis2(dd_rowrange m_size,dd_colrange d_size,
1081
dd_Amatrix A, dd_Bmatrix T,dd_rowindex OV,dd_rowset equalityset, dd_colindex nbindex,
1082
dd_rowindex bflag,dd_rowrange objrow,dd_colrange rhscol,
1083
dd_colrange *cs,int *found,long *pivot_no)
1084
{
1085
/* Similar to dd_FindLPBasis but it is much simpler. This tries to recompute T for
1086
the specified basis given by nbindex. It will return *found=dd_FALSE if the specified
1087
basis is not a basis.
1088
*/
1089
int chosen,stop;
1090
long pivots_p0=0,rank;
1091
dd_colset ColSelected,DependentCols;
1092
dd_rowset RowSelected, NopivotRow;
1093
mytype val;
1094
dd_boolean localdebug=dd_FALSE;
1095
1096
dd_rowrange r,negcount=0;
1097
dd_colrange j,s;
1098
1099
dd_init(val);
1100
*found=dd_FALSE; *cs=0; rank=0;
1101
1102
set_initialize(&RowSelected,m_size);
1103
set_initialize(&DependentCols,d_size);
1104
set_initialize(&ColSelected,d_size);
1105
set_initialize(&NopivotRow,m_size);
1106
set_addelem(RowSelected,objrow);
1107
set_addelem(ColSelected,rhscol);
1108
set_compl(NopivotRow, NopivotRow); /* set NopivotRow to be the groundset */
1109
1110
for (j=2; j<=d_size; j++)
1111
if (nbindex[j]>0)
1112
set_delelem(NopivotRow, nbindex[j]);
1113
else if (nbindex[j]<0){
1114
negcount++;
1115
set_addelem(DependentCols, -nbindex[j]);
1116
set_addelem(ColSelected, -nbindex[j]);
1117
}
1118
1119
set_uni(RowSelected, RowSelected, NopivotRow); /* RowSelected is the set of rows not allowed to poviot on */
1120
1121
stop=dd_FALSE;
1122
do { /* Find a LP basis */
1123
dd_SelectPivot2(m_size,d_size,A,T,dd_MinIndex,OV,equalityset, m_size,RowSelected,ColSelected,&r,&s,&chosen);
1124
if (chosen) {
1125
set_addelem(RowSelected,r);
1126
set_addelem(ColSelected,s);
1127
1128
dd_GaussianColumnPivot2(m_size,d_size,A,T,nbindex,bflag,r,s);
1129
if (localdebug && m_size <=10){
1130
dd_WriteBmatrix(stderr,d_size,T);
1131
dd_WriteTableau(stderr,m_size,d_size,A,T,nbindex,bflag);
1132
}
1133
pivots_p0++;
1134
rank++;
1135
} else{
1136
*found=dd_FALSE; /* cannot pivot on any of the spacified positions. */
1137
stop=dd_TRUE;
1138
}
1139
if (rank==d_size-1-negcount) {
1140
if (negcount){
1141
/* Now it tries to pivot on rows that are supposed to be dependent. */
1142
set_diff(ColSelected, ColSelected, DependentCols);
1143
dd_SelectPivot2(m_size,d_size,A,T,dd_MinIndex,OV,equalityset, m_size,RowSelected,ColSelected,&r,&s,&chosen);
1144
if (chosen) *found=dd_FALSE; /* not supposed to be independent */
1145
else *found=dd_TRUE;
1146
if (localdebug){
1147
printf("Try to check the dependent cols:");
1148
set_write(DependentCols);
1149
if (chosen) printf("They are not dependent. Can still pivot on (%ld, %ld)\n",r, s);
1150
else printf("They are indeed dependent.\n");
1151
}
1152
} else {
1153
*found=dd_TRUE;
1154
}
1155
stop = dd_TRUE;
1156
}
1157
} while (!stop);
1158
1159
for (j=1; j<=d_size; j++) if (nbindex[j]>0) bflag[nbindex[j]]=j;
1160
*pivot_no=pivots_p0;
1161
set_free(RowSelected);
1162
set_free(ColSelected);
1163
set_free(NopivotRow);
1164
set_free(DependentCols);
1165
dd_clear(val);
1166
}
1167
1168
void dd_FindDualFeasibleBasis(dd_rowrange m_size,dd_colrange d_size,
1169
dd_Amatrix A,dd_Bmatrix T,dd_rowindex OV,
1170
dd_colindex nbindex,dd_rowindex bflag,dd_rowrange objrow,dd_colrange rhscol, dd_boolean lexicopivot,
1171
dd_colrange *s,dd_ErrorType *err,dd_LPStatusType *lps,long *pivot_no, long maxpivots)
1172
{
1173
/* Find a dual feasible basis using Phase I of Dual Simplex method.
1174
If the problem is dual feasible,
1175
the procedure returns *err=NoError, *lps=LPSundecided and a dual feasible
1176
basis. If the problem is dual infeasible, this returns
1177
*err=NoError, *lps=DualInconsistent and the evidence column *s.
1178
Caution: matrix A must have at least one extra row: the row space A[m_size] must
1179
have been allocated.
1180
*/
1181
dd_boolean phase1,dualfeasible=dd_TRUE;
1182
dd_boolean localdebug=dd_FALSE,chosen,stop;
1183
dd_LPStatusType LPSphase1;
1184
long pivots_p1=0;
1185
dd_rowrange i,r_val;
1186
dd_colrange j,l,ms=0,s_val,local_m_size;
1187
mytype x,val,maxcost,axvalue,maxratio;
1188
static dd_colrange d_last=0;
1189
static dd_Arow rcost;
1190
static dd_colindex nbindex_ref; /* to be used to store the initial feasible basis for lexico rule */
1191
1192
mytype scaling,svalue; /* random scaling mytype value */
1193
mytype minval;
1194
1195
if (dd_debug) localdebug=dd_debug;
1196
dd_init(x); dd_init(val); dd_init(scaling); dd_init(svalue); dd_init(axvalue);
1197
dd_init(maxcost); dd_set(maxcost,dd_minuszero);
1198
dd_init(maxratio); dd_set(maxratio,dd_minuszero);
1199
if (d_last<d_size) {
1200
if (d_last>0) {
1201
for (j=1; j<=d_last; j++){ dd_clear(rcost[j-1]);}
1202
free(rcost);
1203
free(nbindex_ref);
1204
}
1205
rcost=(mytype*) calloc(d_size,sizeof(mytype));
1206
nbindex_ref=(long*) calloc(d_size+1,sizeof(long));
1207
for (j=1; j<=d_size; j++){ dd_init(rcost[j-1]);}
1208
}
1209
d_last=d_size;
1210
1211
*err=dd_NoError; *lps=dd_LPSundecided; *s=0;
1212
local_m_size=m_size+1; /* increase m_size by 1 */
1213
1214
ms=0; /* ms will be the index of column which has the largest reduced cost */
1215
for (j=1; j<=d_size; j++){
1216
if (j!=rhscol){
1217
dd_TableauEntry(&(rcost[j-1]),local_m_size,d_size,A,T,objrow,j);
1218
if (dd_Larger(rcost[j-1],maxcost)) {dd_set(maxcost,rcost[j-1]); ms = j;}
1219
}
1220
}
1221
if (dd_Positive(maxcost)) dualfeasible=dd_FALSE;
1222
1223
if (!dualfeasible){
1224
for (j=1; j<=d_size; j++){
1225
dd_set(A[local_m_size-1][j-1], dd_purezero);
1226
for (l=1; l<=d_size; l++){
1227
if (nbindex[l]>0) {
1228
dd_set_si(scaling,l+10);
1229
dd_mul(svalue,A[nbindex[l]-1][j-1],scaling);
1230
dd_sub(A[local_m_size-1][j-1],A[local_m_size-1][j-1],svalue);
1231
/* To make the auxiliary row (0,-11,-12,...,-d-10).
1232
It is likely to be better than (0, -1, -1, ..., -1)
1233
to avoid a degenerate LP. Version 093c. */
1234
}
1235
}
1236
}
1237
1238
if (localdebug){
1239
fprintf(stderr,"\ndd_FindDualFeasibleBasis: curruent basis is not dual feasible.\n");
1240
fprintf(stderr,"because of the column %ld assoc. with var %ld dual cost =",
1241
ms,nbindex[ms]);
1242
dd_WriteNumber(stderr, maxcost);
1243
if (localdebug) {
1244
if (m_size <=100 && d_size <=30){
1245
printf("\ndd_FindDualFeasibleBasis: the starting dictionary.\n");
1246
dd_WriteTableau(stdout,m_size+1,d_size,A,T,nbindex,bflag);
1247
}
1248
}
1249
}
1250
1251
ms=0;
1252
/* Ratio Test: ms will be now the index of column which has the largest reduced cost
1253
over the auxiliary row entry */
1254
for (j=1; j<=d_size; j++){
1255
if ((j!=rhscol) && dd_Positive(rcost[j-1])){
1256
dd_TableauEntry(&axvalue,local_m_size,d_size,A,T,local_m_size,j);
1257
if (dd_Nonnegative(axvalue)) {
1258
*err=dd_NumericallyInconsistent;
1259
/* This should not happen as they are set negative above. Quit the phase I.*/
1260
if (localdebug) fprintf(stderr,"dd_FindDualFeasibleBasis: Numerical Inconsistency detected.\n");
1261
goto _L99;
1262
}
1263
dd_neg(axvalue,axvalue);
1264
dd_div(axvalue,rcost[j-1],axvalue); /* axvalue is the negative of ratio that is to be maximized. */
1265
if (dd_Larger(axvalue,maxratio)) {
1266
dd_set(maxratio,axvalue);
1267
ms = j;
1268
}
1269
}
1270
}
1271
1272
if (ms==0) {
1273
*err=dd_NumericallyInconsistent; /* This should not happen. Quit the phase I.*/
1274
if (localdebug) fprintf(stderr,"dd_FindDualFeasibleBasis: Numerical Inconsistency detected.\n");
1275
goto _L99;
1276
}
1277
1278
/* Pivot on (local_m_size,ms) so that the dual basic solution becomes feasible */
1279
dd_GaussianColumnPivot2(local_m_size,d_size,A,T,nbindex,bflag,local_m_size,ms);
1280
pivots_p1=pivots_p1+1;
1281
if (localdebug) {
1282
printf("\ndd_FindDualFeasibleBasis: Pivot on %ld %ld.\n",local_m_size,ms);
1283
}
1284
1285
for (j=1; j<=d_size; j++) nbindex_ref[j]=nbindex[j];
1286
/* set the reference basis to be the current feasible basis. */
1287
if (localdebug){
1288
fprintf(stderr, "Store the current feasible basis:");
1289
for (j=1; j<=d_size; j++) fprintf(stderr, " %ld", nbindex_ref[j]);
1290
fprintf(stderr, "\n");
1291
if (m_size <=100 && d_size <=30)
1292
dd_WriteSignTableau2(stdout,m_size+1,d_size,A,T,nbindex_ref,nbindex,bflag);
1293
}
1294
1295
phase1=dd_TRUE; stop=dd_FALSE;
1296
do { /* Dual Simplex Phase I */
1297
chosen=dd_FALSE; LPSphase1=dd_LPSundecided;
1298
if (pivots_p1>maxpivots) {
1299
*err=dd_LPCycling;
1300
fprintf(stderr,"max number %ld of pivots performed in Phase I. Switch to the anticycling phase.\n", maxpivots);
1301
goto _L99; /* failure due to max no. of pivots performed */
1302
}
1303
dd_SelectDualSimplexPivot(local_m_size,d_size,phase1,A,T,OV,nbindex_ref,nbindex,bflag,
1304
objrow,rhscol,lexicopivot,&r_val,&s_val,&chosen,&LPSphase1);
1305
if (!chosen) {
1306
/* The current dictionary is terminal. There are two cases:
1307
dd_TableauEntry(local_m_size,d_size,A,T,objrow,ms) is negative or zero.
1308
The first case implies dual infeasible,
1309
and the latter implies dual feasible but local_m_size is still in nonbasis.
1310
We must pivot in the auxiliary variable local_m_size.
1311
*/
1312
dd_TableauEntry(&x,local_m_size,d_size,A,T,objrow,ms);
1313
if (dd_Negative(x)){
1314
*err=dd_NoError; *lps=dd_DualInconsistent; *s=ms;
1315
}
1316
if (localdebug) {
1317
fprintf(stderr,"\ndd_FindDualFeasibleBasis: the auxiliary variable was forced to enter the basis (# pivots = %ld).\n",pivots_p1);
1318
fprintf(stderr," -- objrow %ld, ms %ld entry: ",objrow,ms);
1319
dd_WriteNumber(stderr, x); fprintf(stderr,"\n");
1320
if (dd_Negative(x)){
1321
fprintf(stderr,"->The basis is dual inconsistent. Terminate.\n");
1322
} else {
1323
fprintf(stderr,"->The basis is feasible. Go to phase II.\n");
1324
}
1325
}
1326
1327
dd_init(minval);
1328
r_val=0;
1329
for (i=1; i<=local_m_size; i++){
1330
if (bflag[i]<0) {
1331
/* i is basic and not the objective variable */
1332
dd_TableauEntry(&val,local_m_size,d_size,A,T,i,ms); /* auxiliary column*/
1333
if (dd_Smaller(val, minval)) {
1334
r_val=i;
1335
dd_set(minval,val);
1336
}
1337
}
1338
}
1339
dd_clear(minval);
1340
1341
if (r_val==0) {
1342
*err=dd_NumericallyInconsistent; /* This should not happen. Quit the phase I.*/
1343
if (localdebug) fprintf(stderr,"dd_FindDualFeasibleBasis: Numerical Inconsistency detected (r_val is 0).\n");
1344
goto _L99;
1345
}
1346
1347
dd_GaussianColumnPivot2(local_m_size,d_size,A,T,nbindex,bflag,r_val,ms);
1348
pivots_p1=pivots_p1+1;
1349
if (localdebug) {
1350
printf("\ndd_FindDualFeasibleBasis: make the %ld-th pivot on %ld %ld to force the auxiliary variable to enter the basis.\n",pivots_p1,r_val,ms);
1351
if (m_size <=100 && d_size <=30)
1352
dd_WriteSignTableau2(stdout,m_size+1,d_size,A,T,nbindex_ref,nbindex,bflag);
1353
}
1354
1355
stop=dd_TRUE;
1356
1357
} else {
1358
dd_GaussianColumnPivot2(local_m_size,d_size,A,T,nbindex,bflag,r_val,s_val);
1359
pivots_p1=pivots_p1+1;
1360
if (localdebug) {
1361
printf("\ndd_FindDualFeasibleBasis: make a %ld-th pivot on %ld %ld\n",pivots_p1,r_val,s_val);
1362
if (m_size <=100 && d_size <=30)
1363
dd_WriteSignTableau2(stdout,local_m_size,d_size,A,T,nbindex_ref,nbindex,bflag);
1364
}
1365
1366
1367
if (bflag[local_m_size]<0) {
1368
stop=dd_TRUE;
1369
if (localdebug)
1370
fprintf(stderr,"\nDualSimplex Phase I: the auxiliary variable entered the basis (# pivots = %ld).\nGo to phase II\n",pivots_p1);
1371
}
1372
}
1373
} while(!stop);
1374
}
1375
_L99:
1376
*pivot_no=pivots_p1;
1377
dd_statDS1pivots+=pivots_p1;
1378
dd_clear(x); dd_clear(val); dd_clear(maxcost); dd_clear(maxratio);
1379
dd_clear(scaling); dd_clear(svalue); dd_clear(axvalue);
1380
}
1381
1382
void dd_DualSimplexMinimize(dd_LPPtr lp,dd_ErrorType *err)
1383
{
1384
dd_colrange j;
1385
1386
*err=dd_NoError;
1387
for (j=1; j<=lp->d; j++)
1388
dd_neg(lp->A[lp->objrow-1][j-1],lp->A[lp->objrow-1][j-1]);
1389
dd_DualSimplexMaximize(lp,err);
1390
dd_neg(lp->optvalue,lp->optvalue);
1391
for (j=1; j<=lp->d; j++){
1392
if (lp->LPS!=dd_Inconsistent) {
1393
/* Inconsistent certificate stays valid for minimization, 0.94e */
1394
dd_neg(lp->dsol[j-1],lp->dsol[j-1]);
1395
}
1396
dd_neg(lp->A[lp->objrow-1][j-1],lp->A[lp->objrow-1][j-1]);
1397
}
1398
}
1399
1400
void dd_DualSimplexMaximize(dd_LPPtr lp,dd_ErrorType *err)
1401
/*
1402
When LP is inconsistent then lp->re returns the evidence row.
1403
When LP is dual-inconsistent then lp->se returns the evidence column.
1404
*/
1405
{
1406
int stop,chosen,phase1,found;
1407
long pivots_ds=0,pivots_p0=0,pivots_p1=0,pivots_pc=0,maxpivots,maxpivfactor=20;
1408
dd_boolean localdebug=dd_FALSE,localdebug1=dd_FALSE;
1409
1410
#if !defined GMPRATIONAL
1411
long maxccpivots,maxccpivfactor=100;
1412
/* criss-cross should not cycle, but with floating-point arithmetics, it happens
1413
(very rarely). Jorg Rambau reported such an LP, in August 2003. Thanks Jorg!
1414
*/
1415
#endif
1416
1417
dd_rowrange i,r;
1418
dd_colrange j,s;
1419
static dd_rowindex bflag;
1420
static long mlast=0,nlast=0;
1421
static dd_rowindex OrderVector; /* the permutation vector to store a preordered row indeces */
1422
static dd_colindex nbindex_ref; /* to be used to store the initial feasible basis for lexico rule */
1423
1424
double redpercent=0,redpercent_prev=0,redgain=0;
1425
unsigned int rseed=1;
1426
1427
/* *err=dd_NoError; */
1428
if (dd_debug) localdebug=dd_debug;
1429
set_emptyset(lp->redset_extra);
1430
for (i=0; i<= 4; i++) lp->pivots[i]=0;
1431
maxpivots=maxpivfactor*lp->d; /* maximum pivots to be performed before cc pivot is applied. */
1432
#if !defined GMPRATIONAL
1433
maxccpivots=maxccpivfactor*lp->d; /* maximum pivots to be performed with emergency cc pivots. */
1434
#endif
1435
if (mlast!=lp->m || nlast!=lp->d){
1436
if (mlast>0) { /* called previously with different lp->m */
1437
free(OrderVector);
1438
free(bflag);
1439
free(nbindex_ref);
1440
}
1441
OrderVector=(long *)calloc(lp->m+1,sizeof(*OrderVector));
1442
bflag=(long *) calloc(lp->m+2,sizeof(*bflag)); /* one more element for an auxiliary variable */
1443
nbindex_ref=(long*) calloc(lp->d+1,sizeof(long));
1444
mlast=lp->m;nlast=lp->d;
1445
}
1446
/* Initializing control variables. */
1447
dd_ComputeRowOrderVector2(lp->m,lp->d,lp->A,OrderVector,dd_MinIndex,rseed);
1448
1449
lp->re=0; lp->se=0;
1450
1451
dd_ResetTableau(lp->m,lp->d,lp->B,lp->nbindex,bflag,lp->objrow,lp->rhscol);
1452
1453
dd_FindLPBasis(lp->m,lp->d,lp->A,lp->B,OrderVector,lp->equalityset,lp->nbindex,bflag,
1454
lp->objrow,lp->rhscol,&s,&found,&(lp->LPS),&pivots_p0);
1455
lp->pivots[0]=pivots_p0;
1456
1457
if (!found){
1458
lp->se=s;
1459
goto _L99;
1460
/* No LP basis is found, and thus Inconsistent.
1461
Output the evidence column. */
1462
}
1463
1464
dd_FindDualFeasibleBasis(lp->m,lp->d,lp->A,lp->B,OrderVector,lp->nbindex,bflag,
1465
lp->objrow,lp->rhscol,lp->lexicopivot,&s, err,&(lp->LPS),&pivots_p1, maxpivots);
1466
lp->pivots[1]=pivots_p1;
1467
1468
for (j=1; j<=lp->d; j++) nbindex_ref[j]=lp->nbindex[j];
1469
/* set the reference basis to be the current feasible basis. */
1470
if (localdebug){
1471
fprintf(stderr, "dd_DualSimplexMaximize: Store the current feasible basis:");
1472
for (j=1; j<=lp->d; j++) fprintf(stderr, " %ld", nbindex_ref[j]);
1473
fprintf(stderr, "\n");
1474
if (lp->m <=100 && lp->d <=30)
1475
dd_WriteSignTableau2(stdout,lp->m+1,lp->d,lp->A,lp->B,nbindex_ref,lp->nbindex,bflag);
1476
}
1477
1478
if (*err==dd_LPCycling || *err==dd_NumericallyInconsistent){
1479
if (localdebug) fprintf(stderr, "Phase I failed and thus switch to the Criss-Cross method\n");
1480
dd_CrissCrossMaximize(lp,err);
1481
return;
1482
}
1483
1484
if (lp->LPS==dd_DualInconsistent){
1485
lp->se=s;
1486
goto _L99;
1487
/* No dual feasible basis is found, and thus DualInconsistent.
1488
Output the evidence column. */
1489
}
1490
1491
/* Dual Simplex Method */
1492
stop=dd_FALSE;
1493
do {
1494
chosen=dd_FALSE; lp->LPS=dd_LPSundecided; phase1=dd_FALSE;
1495
if (pivots_ds<maxpivots) {
1496
dd_SelectDualSimplexPivot(lp->m,lp->d,phase1,lp->A,lp->B,OrderVector,nbindex_ref,lp->nbindex,bflag,
1497
lp->objrow,lp->rhscol,lp->lexicopivot,&r,&s,&chosen,&(lp->LPS));
1498
}
1499
if (chosen) {
1500
pivots_ds=pivots_ds+1;
1501
if (lp->redcheck_extensive) {
1502
dd_GetRedundancyInformation(lp->m,lp->d,lp->A,lp->B,lp->nbindex, bflag, lp->redset_extra);
1503
set_uni(lp->redset_accum, lp->redset_accum,lp->redset_extra);
1504
redpercent=100*(double)set_card(lp->redset_extra)/(double)lp->m;
1505
redgain=redpercent-redpercent_prev;
1506
redpercent_prev=redpercent;
1507
if (localdebug1){
1508
fprintf(stderr,"\ndd_DualSimplexMaximize: Phase II pivot %ld on (%ld, %ld).\n",pivots_ds,r,s);
1509
fprintf(stderr," redundancy %f percent: redset size = %ld\n",redpercent,set_card(lp->redset_extra));
1510
}
1511
}
1512
}
1513
if (!chosen && lp->LPS==dd_LPSundecided) {
1514
if (localdebug1){
1515
fprintf(stderr,"Warning: an emergency CC pivot in Phase II is performed\n");
1516
/* In principle this should not be executed because we already have dual feasibility
1517
attained and dual simplex pivot should have been chosen. This might occur
1518
under floating point computation, or the case of cycling.
1519
*/
1520
if (localdebug && lp->m <=100 && lp->d <=30){
1521
fprintf(stderr,"\ndd_DualSimplexMaximize: The current dictionary.\n");
1522
dd_WriteSignTableau2(stdout,lp->m,lp->d,lp->A,lp->B,nbindex_ref,lp->nbindex,bflag);
1523
}
1524
}
1525
1526
#if !defined GMPRATIONAL
1527
if (pivots_pc>maxccpivots) {
1528
*err=dd_LPCycling;
1529
stop=dd_TRUE;
1530
goto _L99;
1531
}
1532
#endif
1533
1534
dd_SelectCrissCrossPivot(lp->m,lp->d,lp->A,lp->B,bflag,
1535
lp->objrow,lp->rhscol,&r,&s,&chosen,&(lp->LPS));
1536
if (chosen) pivots_pc=pivots_pc+1;
1537
}
1538
if (chosen) {
1539
dd_GaussianColumnPivot2(lp->m,lp->d,lp->A,lp->B,lp->nbindex,bflag,r,s);
1540
if (localdebug && lp->m <=100 && lp->d <=30){
1541
fprintf(stderr,"\ndd_DualSimplexMaximize: The current dictionary.\n");
1542
dd_WriteSignTableau2(stdout,lp->m,lp->d,lp->A,lp->B,nbindex_ref,lp->nbindex,bflag);
1543
}
1544
} else {
1545
switch (lp->LPS){
1546
case dd_Inconsistent: lp->re=r;
1547
case dd_DualInconsistent: lp->se=s;
1548
1549
default: break;
1550
}
1551
stop=dd_TRUE;
1552
}
1553
} while(!stop);
1554
_L99:
1555
lp->pivots[2]=pivots_ds;
1556
lp->pivots[3]=pivots_pc;
1557
dd_statDS2pivots+=pivots_ds;
1558
dd_statACpivots+=pivots_pc;
1559
1560
dd_SetSolutions(lp->m,lp->d,lp->A,lp->B,lp->objrow,lp->rhscol,lp->LPS,&(lp->optvalue),lp->sol,lp->dsol,lp->posset_extra,lp->nbindex,lp->re,lp->se,bflag);
1561
1562
}
1563
1564
1565
1566
void dd_CrissCrossMinimize(dd_LPPtr lp,dd_ErrorType *err)
1567
{
1568
dd_colrange j;
1569
1570
*err=dd_NoError;
1571
for (j=1; j<=lp->d; j++)
1572
dd_neg(lp->A[lp->objrow-1][j-1],lp->A[lp->objrow-1][j-1]);
1573
dd_CrissCrossMaximize(lp,err);
1574
dd_neg(lp->optvalue,lp->optvalue);
1575
for (j=1; j<=lp->d; j++){
1576
if (lp->LPS!=dd_Inconsistent) {
1577
/* Inconsistent certificate stays valid for minimization, 0.94e */
1578
dd_neg(lp->dsol[j-1],lp->dsol[j-1]);
1579
}
1580
dd_neg(lp->A[lp->objrow-1][j-1],lp->A[lp->objrow-1][j-1]);
1581
}
1582
}
1583
1584
void dd_CrissCrossMaximize(dd_LPPtr lp,dd_ErrorType *err)
1585
/*
1586
When LP is inconsistent then lp->re returns the evidence row.
1587
When LP is dual-inconsistent then lp->se returns the evidence column.
1588
*/
1589
{
1590
int stop,chosen,found;
1591
long pivots0,pivots1;
1592
#if !defined GMPRATIONAL
1593
long maxpivots,maxpivfactor=1000;
1594
/* criss-cross should not cycle, but with floating-point arithmetics, it happens
1595
(very rarely). Jorg Rambau reported such an LP, in August 2003. Thanks Jorg!
1596
*/
1597
#endif
1598
1599
dd_rowrange i,r;
1600
dd_colrange s;
1601
static dd_rowindex bflag;
1602
static long mlast=0;
1603
static dd_rowindex OrderVector; /* the permutation vector to store a preordered row indeces */
1604
unsigned int rseed=1;
1605
dd_colindex nbtemp;
1606
1607
*err=dd_NoError;
1608
#if !defined GMPRATIONAL
1609
maxpivots=maxpivfactor*lp->d; /* maximum pivots to be performed when floating-point arithmetics is used. */
1610
#endif
1611
nbtemp=(long *) calloc(lp->d+1,sizeof(long));
1612
for (i=0; i<= 4; i++) lp->pivots[i]=0;
1613
if (bflag==NULL || mlast!=lp->m){
1614
if (mlast!=lp->m && mlast>0) {
1615
free(bflag); /* called previously with different lp->m */
1616
free(OrderVector);
1617
}
1618
bflag=(long *) calloc(lp->m+1,sizeof(long));
1619
OrderVector=(long *)calloc(lp->m+1,sizeof(long));
1620
/* initialize only for the first time or when a larger space is needed */
1621
1622
mlast=lp->m;
1623
}
1624
/* Initializing control variables. */
1625
dd_ComputeRowOrderVector2(lp->m,lp->d,lp->A,OrderVector,dd_MinIndex,rseed);
1626
1627
lp->re=0; lp->se=0; pivots1=0;
1628
1629
dd_ResetTableau(lp->m,lp->d,lp->B,lp->nbindex,bflag,lp->objrow,lp->rhscol);
1630
1631
dd_FindLPBasis(lp->m,lp->d,lp->A,lp->B,OrderVector,lp->equalityset,
1632
lp->nbindex,bflag,lp->objrow,lp->rhscol,&s,&found,&(lp->LPS),&pivots0);
1633
lp->pivots[0]+=pivots0;
1634
1635
if (!found){
1636
lp->se=s;
1637
goto _L99;
1638
/* No LP basis is found, and thus Inconsistent.
1639
Output the evidence column. */
1640
}
1641
1642
stop=dd_FALSE;
1643
do { /* Criss-Cross Method */
1644
#if !defined GMPRATIONAL
1645
if (pivots1>maxpivots) {
1646
*err=dd_LPCycling;
1647
fprintf(stderr,"max number %ld of pivots performed by the criss-cross method. Most likely due to the floating-point arithmetics error.\n", maxpivots);
1648
goto _L99; /* failure due to max no. of pivots performed */
1649
}
1650
#endif
1651
1652
dd_SelectCrissCrossPivot(lp->m,lp->d,lp->A,lp->B,bflag,
1653
lp->objrow,lp->rhscol,&r,&s,&chosen,&(lp->LPS));
1654
if (chosen) {
1655
dd_GaussianColumnPivot2(lp->m,lp->d,lp->A,lp->B,lp->nbindex,bflag,r,s);
1656
pivots1++;
1657
} else {
1658
switch (lp->LPS){
1659
case dd_Inconsistent: lp->re=r;
1660
case dd_DualInconsistent: lp->se=s;
1661
1662
default: break;
1663
}
1664
stop=dd_TRUE;
1665
}
1666
} while(!stop);
1667
1668
_L99:
1669
lp->pivots[1]+=pivots1;
1670
dd_statCCpivots+=pivots1;
1671
dd_SetSolutions(lp->m,lp->d,lp->A,lp->B,
1672
lp->objrow,lp->rhscol,lp->LPS,&(lp->optvalue),lp->sol,lp->dsol,lp->posset_extra,lp->nbindex,lp->re,lp->se,bflag);
1673
free(nbtemp);
1674
}
1675
1676
void dd_SetSolutions(dd_rowrange m_size,dd_colrange d_size,
1677
dd_Amatrix A,dd_Bmatrix T,
1678
dd_rowrange objrow,dd_colrange rhscol,dd_LPStatusType LPS,
1679
mytype *optvalue,dd_Arow sol,dd_Arow dsol,dd_rowset posset, dd_colindex nbindex,
1680
dd_rowrange re,dd_colrange se,dd_rowindex bflag)
1681
/*
1682
Assign the solution vectors to sol,dsol,*optvalue after solving
1683
the LP.
1684
*/
1685
{
1686
dd_rowrange i;
1687
dd_colrange j;
1688
mytype x,sw;
1689
int localdebug=dd_FALSE;
1690
1691
dd_init(x); dd_init(sw);
1692
if (localdebug) fprintf(stderr,"SetSolutions:\n");
1693
switch (LPS){
1694
case dd_Optimal:
1695
for (j=1;j<=d_size; j++) {
1696
dd_set(sol[j-1],T[j-1][rhscol-1]);
1697
dd_TableauEntry(&x,m_size,d_size,A,T,objrow,j);
1698
dd_neg(dsol[j-1],x);
1699
dd_TableauEntry(optvalue,m_size,d_size,A,T,objrow,rhscol);
1700
if (localdebug) {fprintf(stderr,"dsol[%ld]= ",nbindex[j]); dd_WriteNumber(stderr, dsol[j-1]); }
1701
}
1702
for (i=1; i<=m_size; i++) {
1703
if (bflag[i]==-1) { /* i is a basic variable */
1704
dd_TableauEntry(&x,m_size,d_size,A,T,i,rhscol);
1705
if (dd_Positive(x)) set_addelem(posset, i);
1706
}
1707
}
1708
1709
break;
1710
case dd_Inconsistent:
1711
if (localdebug) fprintf(stderr,"SetSolutions: LP is inconsistent.\n");
1712
for (j=1;j<=d_size; j++) {
1713
dd_set(sol[j-1],T[j-1][rhscol-1]);
1714
dd_TableauEntry(&x,m_size,d_size,A,T,re,j);
1715
dd_neg(dsol[j-1],x);
1716
if (localdebug) {fprintf(stderr,"dsol[%ld]=",nbindex[j]);
1717
dd_WriteNumber(stderr,dsol[j-1]);
1718
fprintf(stderr,"\n");
1719
}
1720
}
1721
break;
1722
1723
case dd_DualInconsistent:
1724
if (localdebug) printf( "SetSolutions: LP is dual inconsistent.\n");
1725
for (j=1;j<=d_size; j++) {
1726
dd_set(sol[j-1],T[j-1][se-1]);
1727
dd_TableauEntry(&x,m_size,d_size,A,T,objrow,j);
1728
dd_neg(dsol[j-1],x);
1729
if (localdebug) {fprintf(stderr,"dsol[%ld]=",nbindex[j]);
1730
dd_WriteNumber(stderr,dsol[j-1]);
1731
fprintf(stderr,"\n");
1732
}
1733
}
1734
break;
1735
1736
case dd_StrucDualInconsistent:
1737
dd_TableauEntry(&x,m_size,d_size,A,T,objrow,se);
1738
if (dd_Positive(x)) dd_set(sw,dd_one);
1739
else dd_neg(sw,dd_one);
1740
for (j=1;j<=d_size; j++) {
1741
dd_mul(sol[j-1],sw,T[j-1][se-1]);
1742
dd_TableauEntry(&x,m_size,d_size,A,T,objrow,j);
1743
dd_neg(dsol[j-1],x);
1744
if (localdebug) {fprintf(stderr,"dsol[%ld]= ",nbindex[j]);dd_WriteNumber(stderr,dsol[j-1]);}
1745
}
1746
if (localdebug) fprintf(stderr,"SetSolutions: LP is dual inconsistent.\n");
1747
break;
1748
1749
default:break;
1750
}
1751
dd_clear(x); dd_clear(sw);
1752
}
1753
1754
1755
void dd_RandomPermutation2(dd_rowindex OV,long t,unsigned int seed)
1756
{
1757
long k,j,ovj;
1758
double u,xk,r,rand_max=(double) RAND_MAX;
1759
int localdebug=dd_FALSE;
1760
1761
portable_srand(seed);
1762
for (j=t; j>1 ; j--) {
1763
r=portable_rand();
1764
u=r/rand_max;
1765
xk=(double)(j*u +1);
1766
k=(long)xk;
1767
if (localdebug) fprintf(stderr,"u=%g, k=%ld, r=%g, randmax= %g\n",u,k,r,rand_max);
1768
ovj=OV[j];
1769
OV[j]=OV[k];
1770
OV[k]=ovj;
1771
if (localdebug) fprintf(stderr,"row %ld is exchanged with %ld\n",j,k);
1772
}
1773
}
1774
1775
void dd_ComputeRowOrderVector2(dd_rowrange m_size,dd_colrange d_size,dd_Amatrix A,
1776
dd_rowindex OV,dd_RowOrderType ho,unsigned int rseed)
1777
{
1778
long i,itemp;
1779
1780
OV[0]=0;
1781
switch (ho){
1782
case dd_MaxIndex:
1783
for(i=1; i<=m_size; i++) OV[i]=m_size-i+1;
1784
break;
1785
1786
case dd_LexMin:
1787
for(i=1; i<=m_size; i++) OV[i]=i;
1788
dd_QuickSort(OV,1,m_size,A,d_size);
1789
break;
1790
1791
case dd_LexMax:
1792
for(i=1; i<=m_size; i++) OV[i]=i;
1793
dd_QuickSort(OV,1,m_size,A,d_size);
1794
for(i=1; i<=m_size/2;i++){ /* just reverse the order */
1795
itemp=OV[i];
1796
OV[i]=OV[m_size-i+1];
1797
OV[m_size-i+1]=itemp;
1798
}
1799
break;
1800
1801
case dd_RandomRow:
1802
for(i=1; i<=m_size; i++) OV[i]=i;
1803
if (rseed<=0) rseed=1;
1804
dd_RandomPermutation2(OV,m_size,rseed);
1805
break;
1806
1807
case dd_MinIndex:
1808
for(i=1; i<=m_size; i++) OV[i]=i;
1809
break;
1810
1811
default:
1812
for(i=1; i<=m_size; i++) OV[i]=i;
1813
break;
1814
}
1815
}
1816
1817
void dd_SelectPreorderedNext2(dd_rowrange m_size,dd_colrange d_size,
1818
rowset excluded,dd_rowindex OV,dd_rowrange *hnext)
1819
{
1820
dd_rowrange i,k;
1821
1822
*hnext=0;
1823
for (i=1; i<=m_size && *hnext==0; i++){
1824
k=OV[i];
1825
if (!set_member(k,excluded)) *hnext=k ;
1826
}
1827
}
1828
1829
#ifdef GMPRATIONAL
1830
1831
ddf_LPObjectiveType Obj2Obj(dd_LPObjectiveType obj)
1832
{
1833
ddf_LPObjectiveType objf=ddf_LPnone;
1834
1835
switch (obj) {
1836
case dd_LPnone: objf=ddf_LPnone; break;
1837
case dd_LPmax: objf=ddf_LPmax; break;
1838
case dd_LPmin: objf=ddf_LPmin; break;
1839
}
1840
return objf;
1841
}
1842
1843
ddf_LPPtr dd_LPgmp2LPf(dd_LPPtr lp)
1844
{
1845
dd_rowrange i;
1846
dd_colrange j;
1847
ddf_LPType *lpf;
1848
double val;
1849
dd_boolean localdebug=dd_FALSE;
1850
1851
if (localdebug) fprintf(stderr,"Converting a GMP-LP to a float-LP.\n");
1852
1853
lpf=ddf_CreateLPData(Obj2Obj(lp->objective), ddf_Real, lp->m, lp->d);
1854
lpf->Homogeneous = lp->Homogeneous;
1855
lpf->eqnumber=lp->eqnumber; /* this records the number of equations */
1856
1857
for (i = 1; i <= lp->m; i++) {
1858
if (set_member(i, lp->equalityset)) set_addelem(lpf->equalityset,i);
1859
/* it is equality. Its reversed row will not be in this set */
1860
for (j = 1; j <= lp->d; j++) {
1861
val=mpq_get_d(lp->A[i-1][j-1]);
1862
ddf_set_d(lpf->A[i-1][j-1],val);
1863
} /*of j*/
1864
} /*of i*/
1865
1866
return lpf;
1867
}
1868
1869
1870
#endif
1871
1872
1873
dd_boolean dd_LPSolve(dd_LPPtr lp,dd_LPSolverType solver,dd_ErrorType *err)
1874
/*
1875
The current version of dd_LPSolve that solves an LP with floating-arithmetics first
1876
and then with the specified arithimetics if it is GMP.
1877
1878
When LP is inconsistent then *re returns the evidence row.
1879
When LP is dual-inconsistent then *se returns the evidence column.
1880
*/
1881
{
1882
int i;
1883
dd_boolean found=dd_FALSE;
1884
#ifdef GMPRATIONAL
1885
ddf_LPPtr lpf;
1886
ddf_ErrorType errf;
1887
dd_boolean LPScorrect=dd_FALSE;
1888
dd_boolean localdebug=dd_FALSE;
1889
if (dd_debug) localdebug=dd_debug;
1890
#endif
1891
1892
*err=dd_NoError;
1893
lp->solver=solver;
1894
1895
time(&lp->starttime);
1896
1897
#ifndef GMPRATIONAL
1898
switch (lp->solver) {
1899
case dd_CrissCross:
1900
dd_CrissCrossSolve(lp,err);
1901
break;
1902
case dd_DualSimplex:
1903
dd_DualSimplexSolve(lp,err);
1904
break;
1905
}
1906
#else
1907
lpf=dd_LPgmp2LPf(lp);
1908
switch (lp->solver) {
1909
case dd_CrissCross:
1910
ddf_CrissCrossSolve(lpf,&errf); /* First, run with double float. */
1911
if (errf==ddf_NoError){ /* 094a: fix for a bug reported by Dima Pasechnik */
1912
dd_BasisStatus(lpf,lp, &LPScorrect); /* Check the basis. */
1913
} else {LPScorrect=dd_FALSE;}
1914
if (!LPScorrect) {
1915
if (localdebug) printf("BasisStatus: the current basis is NOT verified with GMP. Rerun with GMP.\n");
1916
dd_CrissCrossSolve(lp,err); /* Rerun with GMP if fails. */
1917
} else {
1918
if (localdebug) printf("BasisStatus: the current basis is verified with GMP. The LP Solved.\n");
1919
}
1920
break;
1921
case dd_DualSimplex:
1922
ddf_DualSimplexSolve(lpf,&errf); /* First, run with double float. */
1923
if (errf==ddf_NoError){ /* 094a: fix for a bug reported by Dima Pasechnik */
1924
dd_BasisStatus(lpf,lp, &LPScorrect); /* Check the basis. */
1925
} else {LPScorrect=dd_FALSE;}
1926
if (!LPScorrect){
1927
if (localdebug) printf("BasisStatus: the current basis is NOT verified with GMP. Rerun with GMP.\n");
1928
dd_DualSimplexSolve(lp,err); /* Rerun with GMP if fails. */
1929
if (localdebug){
1930
printf("*total number pivots = %ld (ph0 = %ld, ph1 = %ld, ph2 = %ld, ph3 = %ld, ph4 = %ld)\n",
1931
lp->total_pivots,lp->pivots[0],lp->pivots[1],lp->pivots[2],lp->pivots[3],lp->pivots[4]);
1932
ddf_WriteLPResult(stdout, lpf, errf);
1933
dd_WriteLP(stdout, lp);
1934
}
1935
} else {
1936
if (localdebug) printf("BasisStatus: the current basis is verified with GMP. The LP Solved.\n");
1937
}
1938
break;
1939
}
1940
ddf_FreeLPData(lpf);
1941
#endif
1942
1943
time(&lp->endtime);
1944
lp->total_pivots=0;
1945
for (i=0; i<=4; i++) lp->total_pivots+=lp->pivots[i];
1946
if (*err==dd_NoError) found=dd_TRUE;
1947
return found;
1948
}
1949
1950
1951
dd_boolean dd_LPSolve0(dd_LPPtr lp,dd_LPSolverType solver,dd_ErrorType *err)
1952
/*
1953
The original version of dd_LPSolve that solves an LP with specified arithimetics.
1954
1955
When LP is inconsistent then *re returns the evidence row.
1956
When LP is dual-inconsistent then *se returns the evidence column.
1957
*/
1958
{
1959
int i;
1960
dd_boolean found=dd_FALSE;
1961
1962
*err=dd_NoError;
1963
lp->solver=solver;
1964
time(&lp->starttime);
1965
1966
switch (lp->solver) {
1967
case dd_CrissCross:
1968
dd_CrissCrossSolve(lp,err);
1969
break;
1970
case dd_DualSimplex:
1971
dd_DualSimplexSolve(lp,err);
1972
break;
1973
}
1974
1975
time(&lp->endtime);
1976
lp->total_pivots=0;
1977
for (i=0; i<=4; i++) lp->total_pivots+=lp->pivots[i];
1978
if (*err==dd_NoError) found=dd_TRUE;
1979
return found;
1980
}
1981
1982
1983
dd_LPPtr dd_MakeLPforInteriorFinding(dd_LPPtr lp)
1984
/* Delete the objective row,
1985
add an extra column with -1's to the matrix A,
1986
add an extra row with (bceil, 0,...,0,-1),
1987
add an objective row with (0,...,0,1), and
1988
rows & columns, and change m_size and d_size accordingly, to output new_A.
1989
This sets up the LP:
1990
maximize x_{d+1}
1991
s.t. A x + x_{d+1} <= b
1992
x_{d+1} <= bm * bmax,
1993
where bm is set to 2 by default, and bmax=max{1, b[1],...,b[m_size]}.
1994
Note that the equalitions (linearity) in the input lp will be ignored.
1995
*/
1996
{
1997
dd_rowrange m;
1998
dd_colrange d;
1999
dd_NumberType numbtype;
2000
dd_LPObjectiveType obj;
2001
dd_LPType *lpnew;
2002
dd_rowrange i;
2003
dd_colrange j;
2004
mytype bm,bmax,bceil;
2005
int localdebug=dd_FALSE;
2006
2007
dd_init(bm); dd_init(bmax); dd_init(bceil);
2008
dd_add(bm,dd_one,dd_one); dd_set(bmax,dd_one);
2009
numbtype=lp->numbtype;
2010
m=lp->m+1;
2011
d=lp->d+1;
2012
obj=dd_LPmax;
2013
2014
lpnew=dd_CreateLPData(obj, numbtype, m, d);
2015
2016
for (i=1; i<=lp->m; i++) {
2017
if (dd_Larger(lp->A[i-1][lp->rhscol-1],bmax))
2018
dd_set(bmax,lp->A[i-1][lp->rhscol-1]);
2019
}
2020
dd_mul(bceil,bm,bmax);
2021
if (localdebug) {fprintf(stderr,"bceil is set to "); dd_WriteNumber(stderr, bceil);}
2022
2023
for (i=1; i <= lp->m; i++) {
2024
for (j=1; j <= lp->d; j++) {
2025
dd_set(lpnew->A[i-1][j-1],lp->A[i-1][j-1]);
2026
}
2027
}
2028
2029
for (i=1;i<=lp->m; i++){
2030
dd_neg(lpnew->A[i-1][lp->d],dd_one); /* new column with all minus one's */
2031
}
2032
2033
for (j=1;j<=lp->d;j++){
2034
dd_set(lpnew->A[m-2][j-1],dd_purezero); /* new row (bceil, 0,...,0,-1) */
2035
}
2036
dd_set(lpnew->A[m-2][0],bceil); /* new row (bceil, 0,...,0,-1) */
2037
2038
for (j=1;j<= d-1;j++) {
2039
dd_set(lpnew->A[m-1][j-1],dd_purezero); /* new obj row with (0,...,0,1) */
2040
}
2041
dd_set(lpnew->A[m-1][d-1],dd_one); /* new obj row with (0,...,0,1) */
2042
2043
if (localdebug) dd_WriteAmatrix(stderr, lp->A, lp->m, lp->d);
2044
if (localdebug) dd_WriteAmatrix(stderr, lpnew->A, lpnew->m, lpnew->d);
2045
dd_clear(bm); dd_clear(bmax); dd_clear(bceil);
2046
2047
return lpnew;
2048
}
2049
2050
2051
void dd_WriteLPResult(FILE *f,dd_LPPtr lp,dd_ErrorType err)
2052
{
2053
long j;
2054
2055
fprintf(f,"* cdd LP solver result\n");
2056
2057
if (err!=dd_NoError) {
2058
dd_WriteErrorMessages(f,err);
2059
goto _L99;
2060
}
2061
2062
dd_WriteProgramDescription(f);
2063
2064
fprintf(f,"* #constraints = %ld\n",lp->m-1);
2065
fprintf(f,"* #variables = %ld\n",lp->d-1);
2066
2067
switch (lp->solver) {
2068
case dd_DualSimplex:
2069
fprintf(f,"* Algorithm: dual simplex algorithm\n");break;
2070
case dd_CrissCross:
2071
fprintf(f,"* Algorithm: criss-cross method\n");break;
2072
}
2073
2074
switch (lp->objective) {
2075
case dd_LPmax:
2076
fprintf(f,"* maximization is chosen\n");break;
2077
case dd_LPmin:
2078
fprintf(f,"* minimization is chosen\n");break;
2079
case dd_LPnone:
2080
fprintf(f,"* no objective type (max or min) is chosen\n");break;
2081
}
2082
2083
if (lp->objective==dd_LPmax||lp->objective==dd_LPmin){
2084
fprintf(f,"* Objective function is\n");
2085
for (j=0; j<lp->d; j++){
2086
if (j>0 && dd_Nonnegative(lp->A[lp->objrow-1][j]) ) fprintf(f," +");
2087
if (j>0 && (j % 5) == 0) fprintf(f,"\n");
2088
dd_WriteNumber(f,lp->A[lp->objrow-1][j]);
2089
if (j>0) fprintf(f," X[%3ld]",j);
2090
}
2091
fprintf(f,"\n");
2092
}
2093
2094
switch (lp->LPS){
2095
case dd_Optimal:
2096
fprintf(f,"* LP status: a dual pair (x,y) of optimal solutions found.\n");
2097
fprintf(f,"begin\n");
2098
fprintf(f," primal_solution\n");
2099
for (j=1; j<lp->d; j++) {
2100
fprintf(f," %3ld : ",j);
2101
dd_WriteNumber(f,lp->sol[j]);
2102
fprintf(f,"\n");
2103
}
2104
fprintf(f," dual_solution\n");
2105
for (j=1; j<lp->d; j++){
2106
if (lp->nbindex[j+1]>0) {
2107
fprintf(f," %3ld : ",lp->nbindex[j+1]);
2108
dd_WriteNumber(f,lp->dsol[j]); fprintf(f,"\n");
2109
}
2110
}
2111
fprintf(f," optimal_value : "); dd_WriteNumber(f,lp->optvalue);
2112
fprintf(f,"\nend\n");
2113
break;
2114
2115
case dd_Inconsistent:
2116
fprintf(f,"* LP status: LP is inconsistent.\n");
2117
fprintf(f,"* The positive combination of original inequalities with\n");
2118
fprintf(f,"* the following coefficients will prove the inconsistency.\n");
2119
fprintf(f,"begin\n");
2120
fprintf(f," dual_direction\n");
2121
fprintf(f," %3ld : ",lp->re);
2122
dd_WriteNumber(f,dd_one); fprintf(f,"\n");
2123
for (j=1; j<lp->d; j++){
2124
if (lp->nbindex[j+1]>0) {
2125
fprintf(f," %3ld : ",lp->nbindex[j+1]);
2126
dd_WriteNumber(f,lp->dsol[j]); fprintf(f,"\n");
2127
}
2128
}
2129
fprintf(f,"end\n");
2130
break;
2131
2132
case dd_DualInconsistent: case dd_StrucDualInconsistent:
2133
fprintf(f,"* LP status: LP is dual inconsistent.\n");
2134
fprintf(f,"* The linear combination of columns with\n");
2135
fprintf(f,"* the following coefficients will prove the dual inconsistency.\n");
2136
fprintf(f,"* (It is also an unbounded direction for the primal LP.)\n");
2137
fprintf(f,"begin\n");
2138
fprintf(f," primal_direction\n");
2139
for (j=1; j<lp->d; j++) {
2140
fprintf(f," %3ld : ",j);
2141
dd_WriteNumber(f,lp->sol[j]);
2142
fprintf(f,"\n");
2143
}
2144
fprintf(f,"end\n");
2145
break;
2146
2147
default:
2148
break;
2149
}
2150
fprintf(f,"* number of pivot operations = %ld (ph0 = %ld, ph1 = %ld, ph2 = %ld, ph3 = %ld, ph4 = %ld)\n",lp->total_pivots,lp->pivots[0],lp->pivots[1],lp->pivots[2],lp->pivots[3],lp->pivots[4]);
2151
dd_WriteLPTimes(f, lp);
2152
_L99:;
2153
}
2154
2155
dd_LPPtr dd_CreateLP_H_ImplicitLinearity(dd_MatrixPtr M)
2156
{
2157
dd_rowrange m, i, irev, linc;
2158
dd_colrange d, j;
2159
dd_LPPtr lp;
2160
dd_boolean localdebug=dd_FALSE;
2161
2162
linc=set_card(M->linset);
2163
m=M->rowsize+1+linc+1;
2164
/* We represent each equation by two inequalities.
2165
This is not the best way but makes the code simple. */
2166
d=M->colsize+1;
2167
2168
lp=dd_CreateLPData(M->objective, M->numbtype, m, d);
2169
lp->Homogeneous = dd_TRUE;
2170
lp->objective = dd_LPmax;
2171
lp->eqnumber=linc; /* this records the number of equations */
2172
lp->redcheck_extensive=dd_FALSE; /* this is default */
2173
2174
irev=M->rowsize; /* the first row of the linc reversed inequalities. */
2175
for (i = 1; i <= M->rowsize; i++) {
2176
if (set_member(i, M->linset)) {
2177
irev=irev+1;
2178
set_addelem(lp->equalityset,i); /* it is equality. */
2179
/* the reversed row irev is not in the equality set. */
2180
for (j = 1; j <= M->colsize; j++) {
2181
dd_neg(lp->A[irev-1][j-1],M->matrix[i-1][j-1]);
2182
} /*of j*/
2183
} else {
2184
dd_set(lp->A[i-1][d-1],dd_minusone); /* b_I + A_I x - 1 z >= 0 (z=x_d) */
2185
}
2186
for (j = 1; j <= M->colsize; j++) {
2187
dd_set(lp->A[i-1][j-1],M->matrix[i-1][j-1]);
2188
if (j==1 && i<M->rowsize && dd_Nonzero(M->matrix[i-1][j-1])) lp->Homogeneous = dd_FALSE;
2189
} /*of j*/
2190
} /*of i*/
2191
dd_set(lp->A[m-2][0],dd_one); dd_set(lp->A[m-2][d-1],dd_minusone);
2192
/* make the LP bounded. */
2193
2194
dd_set(lp->A[m-1][d-1],dd_one);
2195
/* objective is to maximize z. */
2196
2197
if (localdebug) {
2198
fprintf(stderr,"dd_CreateLP_H_ImplicitLinearity: an new lp is\n");
2199
dd_WriteLP(stderr,lp);
2200
}
2201
2202
return lp;
2203
}
2204
2205
dd_LPPtr dd_CreateLP_V_ImplicitLinearity(dd_MatrixPtr M)
2206
{
2207
dd_rowrange m, i, irev, linc;
2208
dd_colrange d, j;
2209
dd_LPPtr lp;
2210
dd_boolean localdebug=dd_FALSE;
2211
2212
linc=set_card(M->linset);
2213
m=M->rowsize+1+linc+1;
2214
/* We represent each equation by two inequalities.
2215
This is not the best way but makes the code simple. */
2216
d=(M->colsize)+2;
2217
/* Two more columns. This is different from the H-reprentation case */
2218
2219
/* The below must be modified for V-representation!!! */
2220
2221
lp=dd_CreateLPData(M->objective, M->numbtype, m, d);
2222
lp->Homogeneous = dd_FALSE;
2223
lp->objective = dd_LPmax;
2224
lp->eqnumber=linc; /* this records the number of equations */
2225
lp->redcheck_extensive=dd_FALSE; /* this is default */
2226
2227
irev=M->rowsize; /* the first row of the linc reversed inequalities. */
2228
for (i = 1; i <= M->rowsize; i++) {
2229
dd_set(lp->A[i-1][0],dd_purezero); /* It is almost completely degerate LP */
2230
if (set_member(i, M->linset)) {
2231
irev=irev+1;
2232
set_addelem(lp->equalityset,i); /* it is equality. */
2233
/* the reversed row irev is not in the equality set. */
2234
for (j = 2; j <= (M->colsize)+1; j++) {
2235
dd_neg(lp->A[irev-1][j-1],M->matrix[i-1][j-2]);
2236
} /*of j*/
2237
if (localdebug) fprintf(stderr,"equality row %ld generates the reverse row %ld.\n",i,irev);
2238
} else {
2239
dd_set(lp->A[i-1][d-1],dd_minusone); /* b_I x_0 + A_I x - 1 z >= 0 (z=x_d) */
2240
}
2241
for (j = 2; j <= (M->colsize)+1; j++) {
2242
dd_set(lp->A[i-1][j-1],M->matrix[i-1][j-2]);
2243
} /*of j*/
2244
} /*of i*/
2245
dd_set(lp->A[m-2][0],dd_one); dd_set(lp->A[m-2][d-1],dd_minusone);
2246
/* make the LP bounded. */
2247
dd_set(lp->A[m-1][d-1],dd_one);
2248
/* objective is to maximize z. */
2249
2250
if (localdebug) {
2251
fprintf(stderr,"dd_CreateLP_V_ImplicitLinearity: an new lp is\n");
2252
dd_WriteLP(stderr,lp);
2253
}
2254
2255
return lp;
2256
}
2257
2258
2259
dd_LPPtr dd_CreateLP_H_Redundancy(dd_MatrixPtr M, dd_rowrange itest)
2260
{
2261
dd_rowrange m, i, irev, linc;
2262
dd_colrange d, j;
2263
dd_LPPtr lp;
2264
dd_boolean localdebug=dd_FALSE;
2265
2266
linc=set_card(M->linset);
2267
m=M->rowsize+1+linc;
2268
/* We represent each equation by two inequalities.
2269
This is not the best way but makes the code simple. */
2270
d=M->colsize;
2271
2272
lp=dd_CreateLPData(M->objective, M->numbtype, m, d);
2273
lp->Homogeneous = dd_TRUE;
2274
lp->objective = dd_LPmin;
2275
lp->eqnumber=linc; /* this records the number of equations */
2276
lp->redcheck_extensive=dd_FALSE; /* this is default */
2277
2278
irev=M->rowsize; /* the first row of the linc reversed inequalities. */
2279
for (i = 1; i <= M->rowsize; i++) {
2280
if (set_member(i, M->linset)) {
2281
irev=irev+1;
2282
set_addelem(lp->equalityset,i); /* it is equality. */
2283
/* the reversed row irev is not in the equality set. */
2284
for (j = 1; j <= M->colsize; j++) {
2285
dd_neg(lp->A[irev-1][j-1],M->matrix[i-1][j-1]);
2286
} /*of j*/
2287
if (localdebug) fprintf(stderr,"equality row %ld generates the reverse row %ld.\n",i,irev);
2288
}
2289
for (j = 1; j <= M->colsize; j++) {
2290
dd_set(lp->A[i-1][j-1],M->matrix[i-1][j-1]);
2291
if (j==1 && i<M->rowsize && dd_Nonzero(M->matrix[i-1][j-1])) lp->Homogeneous = dd_FALSE;
2292
} /*of j*/
2293
} /*of i*/
2294
for (j = 1; j <= M->colsize; j++) {
2295
dd_set(lp->A[m-1][j-1],M->matrix[itest-1][j-1]);
2296
/* objective is to violate the inequality in question. */
2297
} /*of j*/
2298
dd_add(lp->A[itest-1][0],lp->A[itest-1][0],dd_one); /* relax the original inequality by one */
2299
2300
return lp;
2301
}
2302
2303
2304
dd_LPPtr dd_CreateLP_V_Redundancy(dd_MatrixPtr M, dd_rowrange itest)
2305
{
2306
dd_rowrange m, i, irev, linc;
2307
dd_colrange d, j;
2308
dd_LPPtr lp;
2309
dd_boolean localdebug=dd_FALSE;
2310
2311
linc=set_card(M->linset);
2312
m=M->rowsize+1+linc;
2313
/* We represent each equation by two inequalities.
2314
This is not the best way but makes the code simple. */
2315
d=(M->colsize)+1;
2316
/* One more column. This is different from the H-reprentation case */
2317
2318
/* The below must be modified for V-representation!!! */
2319
2320
lp=dd_CreateLPData(M->objective, M->numbtype, m, d);
2321
lp->Homogeneous = dd_FALSE;
2322
lp->objective = dd_LPmin;
2323
lp->eqnumber=linc; /* this records the number of equations */
2324
lp->redcheck_extensive=dd_FALSE; /* this is default */
2325
2326
irev=M->rowsize; /* the first row of the linc reversed inequalities. */
2327
for (i = 1; i <= M->rowsize; i++) {
2328
if (i==itest){
2329
dd_set(lp->A[i-1][0],dd_one); /* this is to make the LP bounded, ie. the min >= -1 */
2330
} else {
2331
dd_set(lp->A[i-1][0],dd_purezero); /* It is almost completely degerate LP */
2332
}
2333
if (set_member(i, M->linset)) {
2334
irev=irev+1;
2335
set_addelem(lp->equalityset,i); /* it is equality. */
2336
/* the reversed row irev is not in the equality set. */
2337
for (j = 2; j <= (M->colsize)+1; j++) {
2338
dd_neg(lp->A[irev-1][j-1],M->matrix[i-1][j-2]);
2339
} /*of j*/
2340
if (localdebug) fprintf(stderr,"equality row %ld generates the reverse row %ld.\n",i,irev);
2341
}
2342
for (j = 2; j <= (M->colsize)+1; j++) {
2343
dd_set(lp->A[i-1][j-1],M->matrix[i-1][j-2]);
2344
} /*of j*/
2345
} /*of i*/
2346
for (j = 2; j <= (M->colsize)+1; j++) {
2347
dd_set(lp->A[m-1][j-1],M->matrix[itest-1][j-2]);
2348
/* objective is to violate the inequality in question. */
2349
} /*of j*/
2350
dd_set(lp->A[m-1][0],dd_purezero); /* the constant term for the objective is zero */
2351
2352
if (localdebug) dd_WriteLP(stdout, lp);
2353
2354
return lp;
2355
}
2356
2357
2358
dd_LPPtr dd_CreateLP_V_SRedundancy(dd_MatrixPtr M, dd_rowrange itest)
2359
{
2360
/*
2361
V-representation (=boundary problem)
2362
g* = maximize
2363
1^T b_{I-itest} x_0 + 1^T A_{I-itest} (the sum of slacks)
2364
subject to
2365
b_itest x_0 + A_itest x = 0 (the point has to lie on the boundary)
2366
b_{I-itest} x_0 + A_{I-itest} x >= 0 (all nonlinearity generators in one side)
2367
1^T b_{I-itest} x_0 + 1^T A_{I-itest} x <= 1 (to make an LP bounded)
2368
b_L x_0 + A_L x = 0. (linearity generators)
2369
2370
The redundant row is strongly redundant if and only if g* is zero.
2371
*/
2372
2373
dd_rowrange m, i, irev, linc;
2374
dd_colrange d, j;
2375
dd_LPPtr lp;
2376
dd_boolean localdebug=dd_FALSE;
2377
2378
linc=set_card(M->linset);
2379
m=M->rowsize+1+linc+2;
2380
/* We represent each equation by two inequalities.
2381
This is not the best way but makes the code simple.
2382
Two extra constraints are for the first equation and the bouding inequality.
2383
*/
2384
d=(M->colsize)+1;
2385
/* One more column. This is different from the H-reprentation case */
2386
2387
/* The below must be modified for V-representation!!! */
2388
2389
lp=dd_CreateLPData(M->objective, M->numbtype, m, d);
2390
lp->Homogeneous = dd_FALSE;
2391
lp->objective = dd_LPmax;
2392
lp->eqnumber=linc; /* this records the number of equations */
2393
2394
irev=M->rowsize; /* the first row of the linc reversed inequalities. */
2395
for (i = 1; i <= M->rowsize; i++) {
2396
if (i==itest){
2397
dd_set(lp->A[i-1][0],dd_purezero); /* this is a half of the boundary constraint. */
2398
} else {
2399
dd_set(lp->A[i-1][0],dd_purezero); /* It is almost completely degerate LP */
2400
}
2401
if (set_member(i, M->linset) || i==itest) {
2402
irev=irev+1;
2403
set_addelem(lp->equalityset,i); /* it is equality. */
2404
/* the reversed row irev is not in the equality set. */
2405
for (j = 2; j <= (M->colsize)+1; j++) {
2406
dd_neg(lp->A[irev-1][j-1],M->matrix[i-1][j-2]);
2407
} /*of j*/
2408
if (localdebug) fprintf(stderr,"equality row %ld generates the reverse row %ld.\n",i,irev);
2409
}
2410
for (j = 2; j <= (M->colsize)+1; j++) {
2411
dd_set(lp->A[i-1][j-1],M->matrix[i-1][j-2]);
2412
dd_add(lp->A[m-1][j-1],lp->A[m-1][j-1],lp->A[i-1][j-1]); /* the objective is the sum of all ineqalities */
2413
} /*of j*/
2414
} /*of i*/
2415
for (j = 2; j <= (M->colsize)+1; j++) {
2416
dd_neg(lp->A[m-2][j-1],lp->A[m-1][j-1]);
2417
/* to make an LP bounded. */
2418
} /*of j*/
2419
dd_set(lp->A[m-2][0],dd_one); /* the constant term for the bounding constraint is 1 */
2420
2421
if (localdebug) dd_WriteLP(stdout, lp);
2422
2423
return lp;
2424
}
2425
2426
dd_boolean dd_Redundant(dd_MatrixPtr M, dd_rowrange itest, dd_Arow certificate, dd_ErrorType *error)
2427
/* 092 */
2428
{
2429
/* Checks whether the row itest is redundant for the representation.
2430
All linearity rows are not checked and considered NONredundant.
2431
This code works for both H- and V-representations. A certificate is
2432
given in the case of non-redundancy, showing a solution x violating only the itest
2433
inequality for H-representation, a hyperplane RHS and normal (x_0, x) that
2434
separates the itest from the rest. More explicitly, the LP to be setup is
2435
2436
H-representation
2437
f* = minimize
2438
b_itest + A_itest x
2439
subject to
2440
b_itest + 1 + A_itest x >= 0 (relaxed inequality to make an LP bounded)
2441
b_{I-itest} + A_{I-itest} x >= 0 (all inequalities except for itest)
2442
b_L + A_L x = 0. (linearity)
2443
2444
V-representation (=separation problem)
2445
f* = minimize
2446
b_itest x_0 + A_itest x
2447
subject to
2448
b_itest x_0 + A_itest x >= -1 (to make an LP bounded)
2449
b_{I-itest} x_0 + A_{I-itest} x >= 0 (all nonlinearity generators except for itest in one side)
2450
b_L x_0 + A_L x = 0. (linearity generators)
2451
2452
Here, the input matrix is considered as (b, A), i.e. b corresponds to the first column of input
2453
and the row indices of input is partitioned into I and L where L is the set of linearity.
2454
In both cases, the itest data is nonredundant if and only if the optimal value f* is negative.
2455
The certificate has dimension one more for V-representation case.
2456
*/
2457
2458
dd_colrange j;
2459
dd_LPPtr lp;
2460
dd_LPSolutionPtr lps;
2461
dd_ErrorType err=dd_NoError;
2462
dd_boolean answer=dd_FALSE,localdebug=dd_FALSE;
2463
2464
*error=dd_NoError;
2465
if (set_member(itest, M->linset)){
2466
if (localdebug) printf("The %ld th row is linearity and redundancy checking is skipped.\n",itest);
2467
goto _L99;
2468
}
2469
2470
/* Create an LP data for redundancy checking */
2471
if (M->representation==dd_Generator){
2472
lp=dd_CreateLP_V_Redundancy(M, itest);
2473
} else {
2474
lp=dd_CreateLP_H_Redundancy(M, itest);
2475
}
2476
2477
dd_LPSolve(lp,dd_choiceRedcheckAlgorithm,&err);
2478
if (err!=dd_NoError){
2479
*error=err;
2480
goto _L999;
2481
} else {
2482
lps=dd_CopyLPSolution(lp);
2483
2484
for (j=0; j<lps->d; j++) {
2485
dd_set(certificate[j], lps->sol[j]);
2486
}
2487
2488
if (dd_Negative(lps->optvalue)){
2489
answer=dd_FALSE;
2490
if (localdebug) fprintf(stderr,"==> %ld th row is nonredundant.\n",itest);
2491
} else {
2492
answer=dd_TRUE;
2493
if (localdebug) fprintf(stderr,"==> %ld th row is redundant.\n",itest);
2494
}
2495
dd_FreeLPSolution(lps);
2496
}
2497
_L999:
2498
dd_FreeLPData(lp);
2499
_L99:
2500
return answer;
2501
}
2502
2503
dd_boolean dd_RedundantExtensive(dd_MatrixPtr M, dd_rowrange itest, dd_Arow certificate,
2504
dd_rowset *redset,dd_ErrorType *error)
2505
/* 094 */
2506
{
2507
/* This uses the same LP construction as dd_Reduandant. But, while it is checking
2508
the redundancy of itest, it also tries to find some other variable that are
2509
redundant (i.e. forced to be nonnegative). This is expensive as it used
2510
the complete tableau information at each DualSimplex pivot. The redset must
2511
be initialized before this function is called.
2512
*/
2513
2514
dd_colrange j;
2515
dd_LPPtr lp;
2516
dd_LPSolutionPtr lps;
2517
dd_ErrorType err=dd_NoError;
2518
dd_boolean answer=dd_FALSE,localdebug=dd_FALSE;
2519
2520
*error=dd_NoError;
2521
if (set_member(itest, M->linset)){
2522
if (localdebug) printf("The %ld th row is linearity and redundancy checking is skipped.\n",itest);
2523
goto _L99;
2524
}
2525
2526
/* Create an LP data for redundancy checking */
2527
if (M->representation==dd_Generator){
2528
lp=dd_CreateLP_V_Redundancy(M, itest);
2529
} else {
2530
lp=dd_CreateLP_H_Redundancy(M, itest);
2531
}
2532
2533
lp->redcheck_extensive=dd_TRUE;
2534
2535
dd_LPSolve0(lp,dd_DualSimplex,&err);
2536
if (err!=dd_NoError){
2537
*error=err;
2538
goto _L999;
2539
} else {
2540
set_copy(*redset,lp->redset_extra);
2541
set_delelem(*redset, itest);
2542
/* itest row might be redundant in the lp but this has nothing to do with its redundancy
2543
in the original system M. Thus we must delete it. */
2544
if (localdebug){
2545
fprintf(stderr, "dd_RedundantExtensive: checking for %ld, extra redset with cardinality %ld (%ld)\n",itest,set_card(*redset),set_card(lp->redset_extra));
2546
set_fwrite(stderr, *redset); fprintf(stderr, "\n");
2547
}
2548
lps=dd_CopyLPSolution(lp);
2549
2550
for (j=0; j<lps->d; j++) {
2551
dd_set(certificate[j], lps->sol[j]);
2552
}
2553
2554
if (dd_Negative(lps->optvalue)){
2555
answer=dd_FALSE;
2556
if (localdebug) fprintf(stderr,"==> %ld th row is nonredundant.\n",itest);
2557
} else {
2558
answer=dd_TRUE;
2559
if (localdebug) fprintf(stderr,"==> %ld th row is redundant.\n",itest);
2560
}
2561
dd_FreeLPSolution(lps);
2562
}
2563
_L999:
2564
dd_FreeLPData(lp);
2565
_L99:
2566
return answer;
2567
}
2568
2569
dd_rowset dd_RedundantRows(dd_MatrixPtr M, dd_ErrorType *error) /* 092 */
2570
{
2571
dd_rowrange i,m;
2572
dd_colrange d;
2573
dd_rowset redset;
2574
dd_MatrixPtr Mcopy;
2575
dd_Arow cvec; /* certificate */
2576
dd_boolean localdebug=dd_FALSE;
2577
2578
m=M->rowsize;
2579
if (M->representation==dd_Generator){
2580
d=(M->colsize)+1;
2581
} else {
2582
d=M->colsize;
2583
}
2584
Mcopy=dd_MatrixCopy(M);
2585
dd_InitializeArow(d,&cvec);
2586
set_initialize(&redset, m);
2587
for (i=m; i>=1; i--) {
2588
if (dd_Redundant(Mcopy, i, cvec, error)) {
2589
if (localdebug) printf("dd_RedundantRows: the row %ld is redundant.\n", i);
2590
set_addelem(redset, i);
2591
dd_MatrixRowRemove(&Mcopy, i);
2592
} else {
2593
if (localdebug) printf("dd_RedundantRows: the row %ld is essential.\n", i);
2594
}
2595
if (*error!=dd_NoError) goto _L99;
2596
}
2597
_L99:
2598
dd_FreeMatrix(Mcopy);
2599
dd_FreeArow(d, cvec);
2600
return redset;
2601
}
2602
2603
2604
dd_boolean dd_MatrixRedundancyRemove(dd_MatrixPtr *M, dd_rowset *redset,dd_rowindex *newpos, dd_ErrorType *error) /* 094 */
2605
{
2606
/* It returns the set of all redundant rows. This should be called after all
2607
implicit linearity are recognized with dd_MatrixCanonicalizeLinearity.
2608
*/
2609
2610
2611
dd_rowrange i,k,m,m1;
2612
dd_colrange d;
2613
dd_rowset redset1;
2614
dd_rowindex newpos1;
2615
dd_MatrixPtr M1=NULL;
2616
dd_Arow cvec; /* certificate */
2617
dd_boolean success=dd_FALSE, localdebug=dd_FALSE;
2618
2619
m=(*M)->rowsize;
2620
set_initialize(redset, m);
2621
M1=dd_MatrixSortedUniqueCopy(*M,newpos);
2622
for (i=1; i<=m; i++){
2623
if ((*newpos)[i]<=0) set_addelem(*redset,i);
2624
if (localdebug) printf(" %ld:%ld",i,(*newpos)[i]);
2625
}
2626
if (localdebug) printf("\n");
2627
2628
if ((*M)->representation==dd_Generator){
2629
d=((*M)->colsize)+1;
2630
} else {
2631
d=(*M)->colsize;
2632
}
2633
m1=M1->rowsize;
2634
if (localdebug){
2635
fprintf(stderr,"dd_MatrixRedundancyRemove: By sorting, %ld rows have been removed. The remaining has %ld rows.\n",m-m1,m1);
2636
/* dd_WriteMatrix(stdout,M1); */
2637
}
2638
dd_InitializeArow(d,&cvec);
2639
set_initialize(&redset1, M1->rowsize);
2640
k=1;
2641
do {
2642
if (dd_RedundantExtensive(M1, k, cvec, &redset1,error)) {
2643
set_addelem(redset1, k);
2644
dd_MatrixRowsRemove2(&M1,redset1,&newpos1);
2645
for (i=1; i<=m; i++){
2646
if ((*newpos)[i]>0){
2647
if (set_member((*newpos)[i],redset1)){
2648
set_addelem(*redset,i);
2649
(*newpos)[i]=0; /* now the original row i is recognized redundant and removed from M1 */
2650
} else {
2651
(*newpos)[i]=newpos1[(*newpos)[i]]; /* update the new pos vector */
2652
}
2653
}
2654
}
2655
set_free(redset1);
2656
set_initialize(&redset1, M1->rowsize);
2657
if (localdebug) {
2658
printf("dd_MatrixRedundancyRemove: the row %ld is redundant. The new matrix has %ld rows.\n", k, M1->rowsize);
2659
/* dd_WriteMatrix(stderr, M1); */
2660
}
2661
free(newpos1);
2662
} else {
2663
if (set_card(redset1)>0) {
2664
dd_MatrixRowsRemove2(&M1,redset1,&newpos1);
2665
for (i=1; i<=m; i++){
2666
if ((*newpos)[i]>0){
2667
if (set_member((*newpos)[i],redset1)){
2668
set_addelem(*redset,i);
2669
(*newpos)[i]=0; /* now the original row i is recognized redundant and removed from M1 */
2670
} else {
2671
(*newpos)[i]=newpos1[(*newpos)[i]]; /* update the new pos vector */
2672
}
2673
}
2674
}
2675
set_free(redset1);
2676
set_initialize(&redset1, M1->rowsize);
2677
free(newpos1);
2678
}
2679
if (localdebug) {
2680
printf("dd_MatrixRedundancyRemove: the row %ld is essential. The new matrix has %ld rows.\n", k, M1->rowsize);
2681
/* dd_WriteMatrix(stderr, M1); */
2682
}
2683
k=k+1;
2684
}
2685
if (*error!=dd_NoError) goto _L99;
2686
} while (k<=M1->rowsize);
2687
if (localdebug) dd_WriteMatrix(stderr, M1);
2688
success=dd_TRUE;
2689
2690
_L99:
2691
dd_FreeMatrix(*M);
2692
*M=M1;
2693
dd_FreeArow(d, cvec);
2694
set_free(redset1);
2695
return success;
2696
}
2697
2698
2699
dd_boolean dd_SRedundant(dd_MatrixPtr M, dd_rowrange itest, dd_Arow certificate, dd_ErrorType *error)
2700
/* 093a */
2701
{
2702
/* Checks whether the row itest is strongly redundant for the representation.
2703
A row is strongly redundant in H-representation if every point in
2704
the polyhedron satisfies it with strict inequality.
2705
A row is strongly redundant in V-representation if this point is in
2706
the interior of the polyhedron.
2707
2708
All linearity rows are not checked and considered NOT strongly redundant.
2709
This code works for both H- and V-representations. A certificate is
2710
given in the case of non-redundancy, showing a solution x violating only the itest
2711
inequality for H-representation, a hyperplane RHS and normal (x_0, x) that
2712
separates the itest from the rest. More explicitly, the LP to be setup is
2713
2714
H-representation
2715
f* = minimize
2716
b_itest + A_itest x
2717
subject to
2718
b_itest + 1 + A_itest x >= 0 (relaxed inequality to make an LP bounded)
2719
b_{I-itest} + A_{I-itest} x >= 0 (all inequalities except for itest)
2720
b_L + A_L x = 0. (linearity)
2721
2722
V-representation (=separation problem)
2723
f* = minimize
2724
b_itest x_0 + A_itest x
2725
subject to
2726
b_itest x_0 + A_itest x >= -1 (to make an LP bounded)
2727
b_{I-itest} x_0 + A_{I-itest} x >= 0 (all nonlinearity generators except for itest in one side)
2728
b_L x_0 + A_L x = 0. (linearity generators)
2729
2730
Here, the input matrix is considered as (b, A), i.e. b corresponds to the first column of input
2731
and the row indices of input is partitioned into I and L where L is the set of linearity.
2732
In H-representation, the itest data is strongly redundant if and only if the optimal value f* is positive.
2733
In V-representation, the itest data is redundant if and only if the optimal value f* is zero (as the LP
2734
is homogeneous and the optimal value is always non-positive). To recognize strong redundancy, one
2735
can set up a second LP
2736
2737
V-representation (=boundary problem)
2738
g* = maximize
2739
1^T b_{I-itest} x_0 + 1^T A_{I-itest} (the sum of slacks)
2740
subject to
2741
b_itest x_0 + A_itest x = 0 (the point has to lie on the boundary)
2742
b_{I-itest} x_0 + A_{I-itest} x >= 0 (all nonlinearity generators in one side)
2743
1^T b_{I-itest} x_0 + 1^T A_{I-itest} x <= 1 (to make an LP bounded)
2744
b_L x_0 + A_L x = 0. (linearity generators)
2745
2746
The redundant row is strongly redundant if and only if g* is zero.
2747
2748
The certificate has dimension one more for V-representation case.
2749
*/
2750
2751
dd_colrange j;
2752
dd_LPPtr lp;
2753
dd_LPSolutionPtr lps;
2754
dd_ErrorType err=dd_NoError;
2755
dd_boolean answer=dd_FALSE,localdebug=dd_FALSE;
2756
2757
*error=dd_NoError;
2758
if (set_member(itest, M->linset)){
2759
if (localdebug) printf("The %ld th row is linearity and strong redundancy checking is skipped.\n",itest);
2760
goto _L99;
2761
}
2762
2763
/* Create an LP data for redundancy checking */
2764
if (M->representation==dd_Generator){
2765
lp=dd_CreateLP_V_Redundancy(M, itest);
2766
} else {
2767
lp=dd_CreateLP_H_Redundancy(M, itest);
2768
}
2769
2770
dd_LPSolve(lp,dd_choiceRedcheckAlgorithm,&err);
2771
if (err!=dd_NoError){
2772
*error=err;
2773
goto _L999;
2774
} else {
2775
lps=dd_CopyLPSolution(lp);
2776
2777
for (j=0; j<lps->d; j++) {
2778
dd_set(certificate[j], lps->sol[j]);
2779
}
2780
2781
if (localdebug){
2782
printf("Optimum value:");
2783
dd_WriteNumber(stdout, lps->optvalue);
2784
printf("\n");
2785
}
2786
2787
if (M->representation==dd_Inequality){
2788
if (dd_Positive(lps->optvalue)){
2789
answer=dd_TRUE;
2790
if (localdebug) fprintf(stderr,"==> %ld th inequality is strongly redundant.\n",itest);
2791
} else {
2792
answer=dd_FALSE;
2793
if (localdebug) fprintf(stderr,"==> %ld th inequality is not strongly redundant.\n",itest);
2794
}
2795
} else {
2796
if (dd_Negative(lps->optvalue)){
2797
answer=dd_FALSE;
2798
if (localdebug) fprintf(stderr,"==> %ld th point is not strongly redundant.\n",itest);
2799
} else {
2800
/* for V-representation, we have to solve another LP */
2801
dd_FreeLPData(lp);
2802
dd_FreeLPSolution(lps);
2803
lp=dd_CreateLP_V_SRedundancy(M, itest);
2804
dd_LPSolve(lp,dd_DualSimplex,&err);
2805
lps=dd_CopyLPSolution(lp);
2806
if (localdebug) dd_WriteLPResult(stdout,lp,err);
2807
if (dd_Positive(lps->optvalue)){
2808
answer=dd_FALSE;
2809
if (localdebug) fprintf(stderr,"==> %ld th point is not strongly redundant.\n",itest);
2810
} else {
2811
answer=dd_TRUE;
2812
if (localdebug) fprintf(stderr,"==> %ld th point is strongly redundant.\n",itest);
2813
}
2814
}
2815
}
2816
dd_FreeLPSolution(lps);
2817
}
2818
_L999:
2819
dd_FreeLPData(lp);
2820
_L99:
2821
return answer;
2822
}
2823
2824
dd_rowset dd_SRedundantRows(dd_MatrixPtr M, dd_ErrorType *error) /* 093a */
2825
{
2826
dd_rowrange i,m;
2827
dd_colrange d;
2828
dd_rowset redset;
2829
dd_MatrixPtr Mcopy;
2830
dd_Arow cvec; /* certificate */
2831
dd_boolean localdebug=dd_FALSE;
2832
2833
m=M->rowsize;
2834
if (M->representation==dd_Generator){
2835
d=(M->colsize)+1;
2836
} else {
2837
d=M->colsize;
2838
}
2839
Mcopy=dd_MatrixCopy(M);
2840
dd_InitializeArow(d,&cvec);
2841
set_initialize(&redset, m);
2842
for (i=m; i>=1; i--) {
2843
if (dd_SRedundant(Mcopy, i, cvec, error)) {
2844
if (localdebug) printf("dd_SRedundantRows: the row %ld is strongly redundant.\n", i);
2845
set_addelem(redset, i);
2846
dd_MatrixRowRemove(&Mcopy, i);
2847
} else {
2848
if (localdebug) printf("dd_SRedundantRows: the row %ld is not strongly redundant.\n", i);
2849
}
2850
if (*error!=dd_NoError) goto _L99;
2851
}
2852
_L99:
2853
dd_FreeMatrix(Mcopy);
2854
dd_FreeArow(d, cvec);
2855
return redset;
2856
}
2857
2858
dd_rowset dd_RedundantRowsViaShooting(dd_MatrixPtr M, dd_ErrorType *error) /* 092 */
2859
{
2860
/*
2861
For H-representation only and not quite reliable,
2862
especially when floating-point arithmetic is used.
2863
Use the ordinary (slower) method dd_RedundantRows.
2864
*/
2865
2866
dd_rowrange i,m, ired, irow=0;
2867
dd_colrange j,k,d;
2868
dd_rowset redset;
2869
dd_rowindex rowflag;
2870
/* ith comp is negative if the ith inequality (i-1 st row) is redundant.
2871
zero if it is not decided.
2872
k > 0 if it is nonredundant and assigned to the (k-1)th row of M1.
2873
*/
2874
dd_MatrixPtr M1;
2875
dd_Arow shootdir, cvec=NULL;
2876
dd_LPPtr lp0, lp;
2877
dd_LPSolutionPtr lps;
2878
dd_ErrorType err;
2879
dd_LPSolverType solver=dd_DualSimplex;
2880
dd_boolean localdebug=dd_FALSE;
2881
2882
m=M->rowsize;
2883
d=M->colsize;
2884
M1=dd_CreateMatrix(m,d);
2885
M1->rowsize=0; /* cheat the rowsize so that smaller matrix can be stored */
2886
set_initialize(&redset, m);
2887
dd_InitializeArow(d, &shootdir);
2888
dd_InitializeArow(d, &cvec);
2889
2890
rowflag=(long *)calloc(m+1, sizeof(long));
2891
2892
/* First find some (likely) nonredundant inequalities by Interior Point Find. */
2893
lp0=dd_Matrix2LP(M, &err);
2894
lp=dd_MakeLPforInteriorFinding(lp0);
2895
dd_FreeLPData(lp0);
2896
dd_LPSolve(lp, solver, &err); /* Solve the LP */
2897
lps=dd_CopyLPSolution(lp);
2898
2899
if (dd_Positive(lps->optvalue)){
2900
/* An interior point is found. Use rayshooting to find some nonredundant
2901
inequalities. */
2902
for (j=1; j<d; j++){
2903
for (k=1; k<=d; k++) dd_set(shootdir[k-1], dd_purezero);
2904
dd_set(shootdir[j], dd_one); /* j-th unit vector */
2905
ired=dd_RayShooting(M, lps->sol, shootdir);
2906
if (localdebug) printf("nonredundant row %3ld found by shooting.\n", ired);
2907
if (ired>0 && rowflag[ired]<=0) {
2908
irow++;
2909
rowflag[ired]=irow;
2910
for (k=1; k<=d; k++) dd_set(M1->matrix[irow-1][k-1], M->matrix[ired-1][k-1]);
2911
}
2912
2913
dd_neg(shootdir[j], dd_one); /* negative of the j-th unit vector */
2914
ired=dd_RayShooting(M, lps->sol, shootdir);
2915
if (localdebug) printf("nonredundant row %3ld found by shooting.\n", ired);
2916
if (ired>0 && rowflag[ired]<=0) {
2917
irow++;
2918
rowflag[ired]=irow;
2919
for (k=1; k<=d; k++) dd_set(M1->matrix[irow-1][k-1], M->matrix[ired-1][k-1]);
2920
}
2921
}
2922
2923
M1->rowsize=irow;
2924
if (localdebug) {
2925
printf("The initial nonredundant set is:");
2926
for (i=1; i<=m; i++) if (rowflag[i]>0) printf(" %ld", i);
2927
printf("\n");
2928
}
2929
2930
i=1;
2931
while(i<=m){
2932
if (rowflag[i]==0){ /* the ith inequality is not yet checked */
2933
if (localdebug) fprintf(stderr, "Checking redundancy of %ld th inequality\n", i);
2934
irow++; M1->rowsize=irow;
2935
for (k=1; k<=d; k++) dd_set(M1->matrix[irow-1][k-1], M->matrix[i-1][k-1]);
2936
if (!dd_Redundant(M1, irow, cvec, &err)){
2937
for (k=1; k<=d; k++) dd_sub(shootdir[k-1], cvec[k-1], lps->sol[k-1]);
2938
ired=dd_RayShooting(M, lps->sol, shootdir);
2939
rowflag[ired]=irow;
2940
for (k=1; k<=d; k++) dd_set(M1->matrix[irow-1][k-1], M->matrix[ired-1][k-1]);
2941
if (localdebug) {
2942
fprintf(stderr, "The %ld th inequality is nonredundant for the subsystem\n", i);
2943
fprintf(stderr, "The nonredundancy of %ld th inequality is found by shooting.\n", ired);
2944
}
2945
} else {
2946
if (localdebug) fprintf(stderr, "The %ld th inequality is redundant for the subsystem and thus for the whole.\n", i);
2947
rowflag[i]=-1;
2948
set_addelem(redset, i);
2949
i++;
2950
}
2951
} else {
2952
i++;
2953
}
2954
} /* endwhile */
2955
} else {
2956
/* No interior point is found. Apply the standard LP technique. */
2957
redset=dd_RedundantRows(M, error);
2958
}
2959
2960
dd_FreeLPData(lp);
2961
dd_FreeLPSolution(lps);
2962
2963
M1->rowsize=m; M1->colsize=d; /* recover the original sizes */
2964
dd_FreeMatrix(M1);
2965
dd_FreeArow(d, shootdir);
2966
dd_FreeArow(d, cvec);
2967
free(rowflag);
2968
return redset;
2969
}
2970
2971
dd_SetFamilyPtr dd_Matrix2Adjacency(dd_MatrixPtr M, dd_ErrorType *error) /* 093 */
2972
{
2973
/* This is to generate the (facet) graph of a polyheron (H) V-represented by M using LPs.
2974
Since it does not use the representation conversion, it should work for a large
2975
scale problem.
2976
*/
2977
dd_rowrange i,m;
2978
dd_colrange d;
2979
dd_rowset redset;
2980
dd_MatrixPtr Mcopy;
2981
dd_SetFamilyPtr F=NULL;
2982
2983
m=M->rowsize;
2984
d=M->colsize;
2985
if (m<=0 ||d<=0) {
2986
*error=dd_EmptyRepresentation;
2987
goto _L999;
2988
}
2989
Mcopy=dd_MatrixCopy(M);
2990
F=dd_CreateSetFamily(m, m);
2991
for (i=1; i<=m; i++) {
2992
if (!set_member(i, M->linset)){
2993
set_addelem(Mcopy->linset, i);
2994
redset=dd_RedundantRows(Mcopy, error); /* redset should contain all nonadjacent ones */
2995
set_uni(redset, redset, Mcopy->linset); /* all linearity elements should be nonadjacent */
2996
set_compl(F->set[i-1], redset); /* set the adjacency list of vertex i */
2997
set_delelem(Mcopy->linset, i);
2998
set_free(redset);
2999
if (*error!=dd_NoError) goto _L99;
3000
}
3001
}
3002
_L99:
3003
dd_FreeMatrix(Mcopy);
3004
_L999:
3005
return F;
3006
}
3007
3008
dd_SetFamilyPtr dd_Matrix2WeakAdjacency(dd_MatrixPtr M, dd_ErrorType *error) /* 093a */
3009
{
3010
/* This is to generate the weak-adjacency (facet) graph of a polyheron (H) V-represented by M using LPs.
3011
Since it does not use the representation conversion, it should work for a large
3012
scale problem.
3013
*/
3014
dd_rowrange i,m;
3015
dd_colrange d;
3016
dd_rowset redset;
3017
dd_MatrixPtr Mcopy;
3018
dd_SetFamilyPtr F=NULL;
3019
3020
m=M->rowsize;
3021
d=M->colsize;
3022
if (m<=0 ||d<=0) {
3023
*error=dd_EmptyRepresentation;
3024
goto _L999;
3025
}
3026
Mcopy=dd_MatrixCopy(M);
3027
F=dd_CreateSetFamily(m, m);
3028
for (i=1; i<=m; i++) {
3029
if (!set_member(i, M->linset)){
3030
set_addelem(Mcopy->linset, i);
3031
redset=dd_SRedundantRows(Mcopy, error); /* redset should contain all weakly nonadjacent ones */
3032
set_uni(redset, redset, Mcopy->linset); /* all linearity elements should be nonadjacent */
3033
set_compl(F->set[i-1], redset); /* set the adjacency list of vertex i */
3034
set_delelem(Mcopy->linset, i);
3035
set_free(redset);
3036
if (*error!=dd_NoError) goto _L99;
3037
}
3038
}
3039
_L99:
3040
dd_FreeMatrix(Mcopy);
3041
_L999:
3042
return F;
3043
}
3044
3045
3046
dd_boolean dd_ImplicitLinearity(dd_MatrixPtr M, dd_rowrange itest, dd_Arow certificate, dd_ErrorType *error)
3047
/* 092 */
3048
{
3049
/* Checks whether the row itest is implicit linearity for the representation.
3050
All linearity rows are not checked and considered non implicit linearity (dd_FALSE).
3051
This code works for both H- and V-representations. A certificate is
3052
given in the case of dd_FALSE, showing a feasible solution x satisfying the itest
3053
strict inequality for H-representation, a hyperplane RHS and normal (x_0, x) that
3054
separates the itest from the rest. More explicitly, the LP to be setup is
3055
the same thing as redundancy case but with maximization:
3056
3057
H-representation
3058
f* = maximize
3059
b_itest + A_itest x
3060
subject to
3061
b_itest + 1 + A_itest x >= 0 (relaxed inequality. This is not necessary but kept for simplicity of the code)
3062
b_{I-itest} + A_{I-itest} x >= 0 (all inequalities except for itest)
3063
b_L + A_L x = 0. (linearity)
3064
3065
V-representation (=separation problem)
3066
f* = maximize
3067
b_itest x_0 + A_itest x
3068
subject to
3069
b_itest x_0 + A_itest x >= -1 (again, this is not necessary but kept for simplicity.)
3070
b_{I-itest} x_0 + A_{I-itest} x >= 0 (all nonlinearity generators except for itest in one side)
3071
b_L x_0 + A_L x = 0. (linearity generators)
3072
3073
Here, the input matrix is considered as (b, A), i.e. b corresponds to the first column of input
3074
and the row indices of input is partitioned into I and L where L is the set of linearity.
3075
In both cases, the itest data is implicit linearity if and only if the optimal value f* is nonpositive.
3076
The certificate has dimension one more for V-representation case.
3077
*/
3078
3079
dd_colrange j;
3080
dd_LPPtr lp;
3081
dd_LPSolutionPtr lps;
3082
dd_ErrorType err=dd_NoError;
3083
dd_boolean answer=dd_FALSE,localdebug=dd_FALSE;
3084
3085
*error=dd_NoError;
3086
if (set_member(itest, M->linset)){
3087
if (localdebug) printf("The %ld th row is linearity and redundancy checking is skipped.\n",itest);
3088
goto _L99;
3089
}
3090
3091
/* Create an LP data for redundancy checking */
3092
if (M->representation==dd_Generator){
3093
lp=dd_CreateLP_V_Redundancy(M, itest);
3094
} else {
3095
lp=dd_CreateLP_H_Redundancy(M, itest);
3096
}
3097
3098
lp->objective = dd_LPmax; /* the lp->objective is set by CreateLP* to LPmin */
3099
dd_LPSolve(lp,dd_choiceRedcheckAlgorithm,&err);
3100
if (err!=dd_NoError){
3101
*error=err;
3102
goto _L999;
3103
} else {
3104
lps=dd_CopyLPSolution(lp);
3105
3106
for (j=0; j<lps->d; j++) {
3107
dd_set(certificate[j], lps->sol[j]);
3108
}
3109
3110
if (lps->LPS==dd_Optimal && dd_EqualToZero(lps->optvalue)){
3111
answer=dd_TRUE;
3112
if (localdebug) fprintf(stderr,"==> %ld th data is an implicit linearity.\n",itest);
3113
} else {
3114
answer=dd_FALSE;
3115
if (localdebug) fprintf(stderr,"==> %ld th data is not an implicit linearity.\n",itest);
3116
}
3117
dd_FreeLPSolution(lps);
3118
}
3119
_L999:
3120
dd_FreeLPData(lp);
3121
_L99:
3122
return answer;
3123
}
3124
3125
3126
int dd_FreeOfImplicitLinearity(dd_MatrixPtr M, dd_Arow certificate, dd_rowset *imp_linrows, dd_ErrorType *error)
3127
/* 092 */
3128
{
3129
/* Checks whether the matrix M constains any implicit linearity at all.
3130
It returns 1 if it is free of any implicit linearity. This means that
3131
the present linearity rows define the linearity correctly. It returns
3132
nonpositive values otherwise.
3133
3134
3135
H-representation
3136
f* = maximize z
3137
subject to
3138
b_I + A_I x - 1 z >= 0
3139
b_L + A_L x = 0 (linearity)
3140
z <= 1.
3141
3142
V-representation (=separation problem)
3143
f* = maximize z
3144
subject to
3145
b_I x_0 + A_I x - 1 z >= 0 (all nonlinearity generators in one side)
3146
b_L x_0 + A_L x = 0 (linearity generators)
3147
z <= 1.
3148
3149
Here, the input matrix is considered as (b, A), i.e. b corresponds to the first column of input
3150
and the row indices of input is partitioned into I and L where L is the set of linearity.
3151
In both cases, any implicit linearity exists if and only if the optimal value f* is nonpositive.
3152
The certificate has dimension one more for V-representation case.
3153
*/
3154
3155
dd_LPPtr lp;
3156
dd_rowrange i,m;
3157
dd_colrange j,d1;
3158
dd_ErrorType err=dd_NoError;
3159
dd_Arow cvec; /* certificate for implicit linearity */
3160
3161
int answer=0,localdebug=dd_FALSE;
3162
3163
*error=dd_NoError;
3164
/* Create an LP data for redundancy checking */
3165
if (M->representation==dd_Generator){
3166
lp=dd_CreateLP_V_ImplicitLinearity(M);
3167
} else {
3168
lp=dd_CreateLP_H_ImplicitLinearity(M);
3169
}
3170
3171
dd_LPSolve(lp,dd_choiceRedcheckAlgorithm,&err);
3172
if (err!=dd_NoError){
3173
*error=err;
3174
goto _L999;
3175
} else {
3176
3177
for (j=0; j<lp->d; j++) {
3178
dd_set(certificate[j], lp->sol[j]);
3179
}
3180
3181
if (localdebug) dd_WriteLPResult(stderr,lp,err);
3182
3183
/* *posset contains a set of row indices that are recognized as nonlinearity. */
3184
if (localdebug) {
3185
fprintf(stderr,"==> The following variables are not implicit linearity:\n");
3186
set_fwrite(stderr, lp->posset_extra);
3187
fprintf(stderr,"\n");
3188
}
3189
3190
if (M->representation==dd_Generator){
3191
d1=(M->colsize)+1;
3192
} else {
3193
d1=M->colsize;
3194
}
3195
m=M->rowsize;
3196
dd_InitializeArow(d1,&cvec);
3197
set_initialize(imp_linrows,m);
3198
3199
if (lp->LPS==dd_Optimal){
3200
if (dd_Positive(lp->optvalue)){
3201
answer=1;
3202
if (localdebug) fprintf(stderr,"==> The matrix has no implicit linearity.\n");
3203
} else if (dd_Negative(lp->optvalue)) {
3204
answer=-1;
3205
if (localdebug) fprintf(stderr,"==> The matrix defines the trivial system.\n");
3206
} else {
3207
answer=0;
3208
if (localdebug) fprintf(stderr,"==> The matrix has some implicit linearity.\n");
3209
}
3210
} else {
3211
answer=-2;
3212
if (localdebug) fprintf(stderr,"==> The LP fails.\n");
3213
}
3214
if (answer==0){
3215
/* List the implicit linearity rows */
3216
for (i=m; i>=1; i--) {
3217
if (!set_member(i,lp->posset_extra)) {
3218
if (dd_ImplicitLinearity(M, i, cvec, error)) {
3219
set_addelem(*imp_linrows, i);
3220
if (localdebug) {
3221
fprintf(stderr," row %ld is implicit linearity\n",i);
3222
fprintf(stderr,"\n");
3223
}
3224
}
3225
if (*error!=dd_NoError) goto _L999;
3226
}
3227
}
3228
} /* end of if (answer==0) */
3229
if (answer==-1) {
3230
for (i=m; i>=1; i--) set_addelem(*imp_linrows, i);
3231
} /* all rows are considered implicit linearity */
3232
3233
dd_FreeArow(d1,cvec);
3234
}
3235
_L999:
3236
dd_FreeLPData(lp);
3237
3238
return answer;
3239
}
3240
3241
3242
dd_rowset dd_ImplicitLinearityRows(dd_MatrixPtr M, dd_ErrorType *error) /* 092 */
3243
{
3244
dd_colrange d;
3245
dd_rowset imp_linset;
3246
dd_Arow cvec; /* certificate */
3247
int foi;
3248
dd_boolean localdebug=dd_FALSE;
3249
3250
if (M->representation==dd_Generator){
3251
d=(M->colsize)+2;
3252
} else {
3253
d=M->colsize+1;
3254
}
3255
3256
dd_InitializeArow(d,&cvec);
3257
if (localdebug) fprintf(stdout, "\ndd_ImplicitLinearityRows: Check whether the system contains any implicit linearity.\n");
3258
foi=dd_FreeOfImplicitLinearity(M, cvec, &imp_linset, error);
3259
if (localdebug){
3260
switch (foi) {
3261
case 1:
3262
fprintf(stdout, " It is free of implicit linearity.\n");
3263
break;
3264
3265
case 0:
3266
fprintf(stdout, " It is not free of implicit linearity.\n");
3267
break;
3268
3269
case -1:
3270
fprintf(stdout, " The input system is trivial (i.e. the empty H-polytope or the V-rep of the whole space.\n");
3271
break;
3272
3273
default:
3274
fprintf(stdout, " The LP was not solved correctly.\n");
3275
break;
3276
3277
}
3278
}
3279
3280
if (localdebug){
3281
fprintf(stderr, " Implicit linearity rows are:\n");
3282
set_fwrite(stderr,imp_linset);
3283
fprintf(stderr, "\n");
3284
}
3285
dd_FreeArow(d, cvec);
3286
return imp_linset;
3287
}
3288
3289
dd_boolean dd_MatrixCanonicalizeLinearity(dd_MatrixPtr *M, dd_rowset *impl_linset,dd_rowindex *newpos,
3290
dd_ErrorType *error) /* 094 */
3291
{
3292
/* This is to recongnize all implicit linearities, and put all linearities at the top of
3293
the matrix. All implicit linearities will be returned by *impl_linset.
3294
*/
3295
dd_rowrange rank;
3296
dd_rowset linrows,ignoredrows,basisrows;
3297
dd_colset ignoredcols,basiscols;
3298
dd_rowrange i,k,m;
3299
dd_rowindex newpos1;
3300
dd_boolean success=dd_FALSE;
3301
3302
linrows=dd_ImplicitLinearityRows(*M, error);
3303
if (*error!=dd_NoError) goto _L99;
3304
3305
m=(*M)->rowsize;
3306
3307
set_uni((*M)->linset, (*M)->linset, linrows);
3308
/* add the implicit linrows to the explicit linearity rows */
3309
3310
/* To remove redundancy of the linearity part,
3311
we need to compute the rank and a basis of the linearity part. */
3312
set_initialize(&ignoredrows, (*M)->rowsize);
3313
set_initialize(&ignoredcols, (*M)->colsize);
3314
set_compl(ignoredrows, (*M)->linset);
3315
rank=dd_MatrixRank(*M,ignoredrows,ignoredcols,&basisrows,&basiscols);
3316
set_diff(ignoredrows, (*M)->linset, basisrows);
3317
dd_MatrixRowsRemove2(M,ignoredrows,newpos);
3318
3319
dd_MatrixShiftupLinearity(M,&newpos1);
3320
3321
for (i=1; i<=m; i++){
3322
k=(*newpos)[i];
3323
if (k>0) {
3324
(*newpos)[i]=newpos1[k];
3325
}
3326
}
3327
3328
*impl_linset=linrows;
3329
success=dd_TRUE;
3330
free(newpos1);
3331
set_free(basisrows);
3332
set_free(basiscols);
3333
set_free(ignoredrows);
3334
set_free(ignoredcols);
3335
_L99:
3336
return success;
3337
}
3338
3339
dd_boolean dd_MatrixCanonicalize(dd_MatrixPtr *M, dd_rowset *impl_linset, dd_rowset *redset,
3340
dd_rowindex *newpos, dd_ErrorType *error) /* 094 */
3341
{
3342
/* This is to find a canonical representation of a matrix *M by
3343
recognizing all implicit linearities and all redundancies.
3344
All implicit linearities will be returned by *impl_linset and
3345
redundancies will be returned by *redset.
3346
*/
3347
dd_rowrange i,k,m;
3348
dd_rowindex newpos1,revpos;
3349
dd_rowset redset1;
3350
dd_boolean success=dd_TRUE;
3351
3352
m=(*M)->rowsize;
3353
set_initialize(redset, m);
3354
revpos=(long *)calloc(m+1,sizeof(long));
3355
3356
success=dd_MatrixCanonicalizeLinearity(M, impl_linset, newpos, error);
3357
3358
if (!success) goto _L99;
3359
3360
for (i=1; i<=m; i++){
3361
k=(*newpos)[i];
3362
if (k>0) revpos[k]=i; /* inverse of *newpos[] */
3363
}
3364
3365
success=dd_MatrixRedundancyRemove(M, &redset1, &newpos1, error); /* 094 */
3366
3367
if (!success) goto _L99;
3368
3369
for (i=1; i<=m; i++){
3370
k=(*newpos)[i];
3371
if (k>0) {
3372
(*newpos)[i]=newpos1[k];
3373
if (newpos1[k]<0) (*newpos)[i]=-revpos[-newpos1[k]]; /* update the certificate of its duplicate removal. */
3374
if (set_member(k,redset1)) set_addelem(*redset, i);
3375
}
3376
}
3377
3378
_L99:
3379
set_free(redset1);
3380
free(newpos1);
3381
free(revpos);
3382
return success;
3383
}
3384
3385
3386
dd_boolean dd_ExistsRestrictedFace(dd_MatrixPtr M, dd_rowset R, dd_rowset S, dd_ErrorType *err)
3387
/* 0.94 */
3388
{
3389
/* This function checkes if there is a point that satifies all the constraints of
3390
the matrix M (interpreted as an H-representation) with additional equality contraints
3391
specified by R and additional strict inequality constraints specified by S.
3392
The set S is supposed to be disjoint from both R and M->linset. When it is not,
3393
the set S will be considered as S\(R U M->linset).
3394
*/
3395
dd_boolean answer=dd_FALSE;
3396
dd_LPPtr lp=NULL;
3397
3398
/*
3399
printf("\n--- ERF ---\n");
3400
printf("R = "); set_write(R);
3401
printf("S = "); set_write(S);
3402
*/
3403
3404
lp=dd_Matrix2Feasibility2(M, R, S, err);
3405
3406
if (*err!=dd_NoError) goto _L99;
3407
3408
/* Solve the LP by cdd LP solver. */
3409
dd_LPSolve(lp, dd_DualSimplex, err); /* Solve the LP */
3410
if (*err!=dd_NoError) goto _L99;
3411
if (lp->LPS==dd_Optimal && dd_Positive(lp->optvalue)) {
3412
answer=dd_TRUE;
3413
}
3414
3415
dd_FreeLPData(lp);
3416
_L99:
3417
return answer;
3418
}
3419
3420
dd_boolean dd_ExistsRestrictedFace2(dd_MatrixPtr M, dd_rowset R, dd_rowset S, dd_LPSolutionPtr *lps, dd_ErrorType *err)
3421
/* 0.94 */
3422
{
3423
/* This function checkes if there is a point that satifies all the constraints of
3424
the matrix M (interpreted as an H-representation) with additional equality contraints
3425
specified by R and additional strict inequality constraints specified by S.
3426
The set S is supposed to be disjoint from both R and M->linset. When it is not,
3427
the set S will be considered as S\(R U M->linset).
3428
3429
This function returns a certificate of the answer in terms of the associated LP solutions.
3430
*/
3431
dd_boolean answer=dd_FALSE;
3432
dd_LPPtr lp=NULL;
3433
3434
/*
3435
printf("\n--- ERF ---\n");
3436
printf("R = "); set_write(R);
3437
printf("S = "); set_write(S);
3438
*/
3439
3440
lp=dd_Matrix2Feasibility2(M, R, S, err);
3441
3442
if (*err!=dd_NoError) goto _L99;
3443
3444
/* Solve the LP by cdd LP solver. */
3445
dd_LPSolve(lp, dd_DualSimplex, err); /* Solve the LP */
3446
if (*err!=dd_NoError) goto _L99;
3447
if (lp->LPS==dd_Optimal && dd_Positive(lp->optvalue)) {
3448
answer=dd_TRUE;
3449
}
3450
3451
3452
(*lps)=dd_CopyLPSolution(lp);
3453
dd_FreeLPData(lp);
3454
_L99:
3455
return answer;
3456
}
3457
3458
dd_boolean dd_FindRelativeInterior(dd_MatrixPtr M, dd_rowset *ImL, dd_rowset *Lbasis, dd_LPSolutionPtr *lps, dd_ErrorType *err)
3459
/* 0.94 */
3460
{
3461
/* This function computes a point in the relative interior of the H-polyhedron given by M.
3462
Even the representation is V-representation, it simply interprete M as H-representation.
3463
lps returns the result of solving an LP whose solution is a relative interior point.
3464
ImL returns all row indices of M that are implicit linearities, i.e. their inqualities
3465
are satisfied by equality by all points in the polyhedron. Lbasis returns a row basis
3466
of the submatrix of M consisting of all linearities and implicit linearities. This means
3467
that the dimension of the polyhedron is M->colsize - set_card(Lbasis) -1.
3468
*/
3469
3470
dd_rowset S;
3471
dd_colset T, Lbasiscols;
3472
dd_boolean success=dd_FALSE;
3473
dd_rowrange i;
3474
dd_colrange rank;
3475
3476
3477
*ImL=dd_ImplicitLinearityRows(M, err);
3478
3479
if (*err!=dd_NoError) goto _L99;
3480
3481
set_initialize(&S, M->rowsize); /* the empty set */
3482
for (i=1; i <=M->rowsize; i++) {
3483
if (!set_member(i, M->linset) && !set_member(i, *ImL)){
3484
set_addelem(S, i); /* all nonlinearity rows go to S */
3485
}
3486
}
3487
if (dd_ExistsRestrictedFace2(M, *ImL, S, lps, err)){
3488
/* printf("a relative interior point found\n"); */
3489
success=dd_TRUE;
3490
}
3491
3492
set_initialize(&T, M->colsize); /* empty set */
3493
rank=dd_MatrixRank(M,S,T,Lbasis,&Lbasiscols); /* the rank of the linearity submatrix of M. */
3494
3495
set_free(S);
3496
set_free(T);
3497
set_free(Lbasiscols);
3498
3499
_L99:
3500
return success;
3501
}
3502
3503
3504
dd_rowrange dd_RayShooting(dd_MatrixPtr M, dd_Arow p, dd_Arow r)
3505
{
3506
/* 092, find the first inequality "hit" by a ray from an intpt. */
3507
dd_rowrange imin=-1,i,m;
3508
dd_colrange j, d;
3509
dd_Arow vecmin, vec;
3510
mytype min,t1,t2,alpha, t1min;
3511
dd_boolean started=dd_FALSE;
3512
dd_boolean localdebug=dd_FALSE;
3513
3514
m=M->rowsize;
3515
d=M->colsize;
3516
if (!dd_Equal(dd_one, p[0])){
3517
fprintf(stderr, "Warning: RayShooting is called with a point with first coordinate not 1.\n");
3518
dd_set(p[0],dd_one);
3519
}
3520
if (!dd_EqualToZero(r[0])){
3521
fprintf(stderr, "Warning: RayShooting is called with a direction with first coordinate not 0.\n");
3522
dd_set(r[0],dd_purezero);
3523
}
3524
3525
dd_init(alpha); dd_init(min); dd_init(t1); dd_init(t2); dd_init(t1min);
3526
dd_InitializeArow(d,&vecmin);
3527
dd_InitializeArow(d,&vec);
3528
3529
for (i=1; i<=m; i++){
3530
dd_InnerProduct(t1, d, M->matrix[i-1], p);
3531
if (dd_Positive(t1)) {
3532
dd_InnerProduct(t2, d, M->matrix[i-1], r);
3533
dd_div(alpha, t2, t1);
3534
if (!started){
3535
imin=i; dd_set(min, alpha);
3536
dd_set(t1min, t1); /* store the denominator. */
3537
started=dd_TRUE;
3538
if (localdebug) {
3539
fprintf(stderr," Level 1: imin = %ld and min = ", imin);
3540
dd_WriteNumber(stderr, min);
3541
fprintf(stderr,"\n");
3542
}
3543
} else {
3544
if (dd_Smaller(alpha, min)){
3545
imin=i; dd_set(min, alpha);
3546
dd_set(t1min, t1); /* store the denominator. */
3547
if (localdebug) {
3548
fprintf(stderr," Level 2: imin = %ld and min = ", imin);
3549
dd_WriteNumber(stderr, min);
3550
fprintf(stderr,"\n");
3551
}
3552
} else {
3553
if (dd_Equal(alpha, min)) { /* tie break */
3554
for (j=1; j<= d; j++){
3555
dd_div(vecmin[j-1], M->matrix[imin-1][j-1], t1min);
3556
dd_div(vec[j-1], M->matrix[i-1][j-1], t1);
3557
}
3558
if (dd_LexSmaller(vec,vecmin, d)){
3559
imin=i; dd_set(min, alpha);
3560
dd_set(t1min, t1); /* store the denominator. */
3561
if (localdebug) {
3562
fprintf(stderr," Level 3: imin = %ld and min = ", imin);
3563
dd_WriteNumber(stderr, min);
3564
fprintf(stderr,"\n");
3565
}
3566
}
3567
}
3568
}
3569
}
3570
}
3571
}
3572
3573
dd_clear(alpha); dd_clear(min); dd_clear(t1); dd_clear(t2); dd_clear(t1min);
3574
dd_FreeArow(d, vecmin);
3575
dd_FreeArow(d, vec);
3576
return imin;
3577
}
3578
3579
#ifdef GMPRATIONAL
3580
void dd_BasisStatusMaximize(dd_rowrange m_size,dd_colrange d_size,
3581
dd_Amatrix A,dd_Bmatrix T,dd_rowset equalityset,
3582
dd_rowrange objrow,dd_colrange rhscol,ddf_LPStatusType LPS,
3583
mytype *optvalue,dd_Arow sol,dd_Arow dsol,dd_rowset posset, ddf_colindex nbindex,
3584
ddf_rowrange re,ddf_colrange se, dd_colrange *nse, long *pivots, int *found, int *LPScorrect)
3585
/* This is just to check whether the status LPS of the basis given by
3586
nbindex with extra certificates se or re is correct. It is done
3587
by recomputing the basis inverse matrix T. It does not solve the LP
3588
when the status *LPS is undecided. Thus the input is
3589
m_size, d_size, A, equalityset, LPS, nbindex, re and se.
3590
Other values will be recomputed from scratch.
3591
3592
The main purpose of the function is to verify the correctness
3593
of the result of floating point computation with the GMP rational
3594
arithmetics.
3595
*/
3596
{
3597
long pivots0,pivots1,fbasisrank;
3598
dd_rowrange i,is;
3599
dd_colrange s,senew,j;
3600
static dd_rowindex bflag;
3601
static long mlast=0;
3602
static dd_rowindex OrderVector; /* the permutation vector to store a preordered row indices */
3603
unsigned int rseed=1;
3604
mytype val;
3605
dd_colindex nbtemp;
3606
dd_LPStatusType ddlps;
3607
dd_boolean localdebug=dd_FALSE;
3608
3609
if (dd_debug) localdebug=dd_debug;
3610
if (localdebug){
3611
printf("\nEvaluating dd_BasisStatusMaximize:\n");
3612
}
3613
dd_init(val);
3614
nbtemp=(long *) calloc(d_size+1,sizeof(long));
3615
for (i=0; i<= 4; i++) pivots[i]=0;
3616
if (bflag==NULL || mlast!=m_size){
3617
if (mlast!=m_size && mlast>0) {
3618
free(bflag); /* called previously with different m_size */
3619
free(OrderVector);
3620
}
3621
bflag=(long *) calloc(m_size+1,sizeof(long));
3622
OrderVector=(long *)calloc(m_size+1,sizeof(long));
3623
/* initialize only for the first time or when a larger space is needed */
3624
mlast=m_size;
3625
}
3626
3627
/* Initializing control variables. */
3628
dd_ComputeRowOrderVector2(m_size,d_size,A,OrderVector,dd_MinIndex,rseed);
3629
3630
pivots1=0;
3631
3632
dd_ResetTableau(m_size,d_size,T,nbtemp,bflag,objrow,rhscol);
3633
3634
if (localdebug){
3635
printf("\nnbindex:");
3636
for (j=1; j<=d_size; j++) printf(" %ld", nbindex[j]);
3637
printf("\n");
3638
printf("re = %ld, se=%ld\n", re, se);
3639
}
3640
3641
is=nbindex[se];
3642
if (localdebug) printf("se=%ld, is=%ld\n", se, is);
3643
3644
fbasisrank=d_size-1;
3645
for (j=1; j<=d_size; j++){
3646
if (nbindex[j]<0) fbasisrank=fbasisrank-1;
3647
/* fbasisrank=the basis rank computed by floating-point */
3648
}
3649
3650
if (fbasisrank<d_size-1) {
3651
if (localdebug) {
3652
printf("d_size = %ld, the size of basis = %ld\n", d_size, fbasisrank);
3653
printf("dd_BasisStatusMaximize: the size of basis is smaller than d-1.\nIt is safer to run the LP solver with GMP\n");
3654
}
3655
*found=dd_FALSE;
3656
goto _L99;
3657
/* Suspicious case. Rerun the LP solver with GMP. */
3658
}
3659
3660
3661
3662
dd_FindLPBasis2(m_size,d_size,A,T,OrderVector, equalityset,nbindex,bflag,
3663
objrow,rhscol,&s,found,&pivots0);
3664
3665
/* set up the new se column and corresponding variable */
3666
senew=bflag[is];
3667
is=nbindex[senew];
3668
if (localdebug) printf("new se=%ld, is=%ld\n", senew, is);
3669
3670
pivots[4]=pivots0; /*GMP postopt pivots */
3671
dd_statBSpivots+=pivots0;
3672
3673
if (!(*found)){
3674
if (localdebug) {
3675
printf("dd_BasisStatusMaximize: a specified basis DOES NOT exist.\n");
3676
}
3677
3678
goto _L99;
3679
/* No speficied LP basis is found. */
3680
}
3681
3682
if (localdebug) {
3683
printf("dd_BasisStatusMaximize: a specified basis exists.\n");
3684
if (m_size <=100 && d_size <=30)
3685
dd_WriteTableau(stdout,m_size,d_size,A,T,nbindex,bflag);
3686
}
3687
3688
/* Check whether a recomputed basis is of the type specified by LPS */
3689
*LPScorrect=dd_TRUE;
3690
switch (LPS){
3691
case dd_Optimal:
3692
for (i=1; i<=m_size; i++) {
3693
if (i!=objrow && bflag[i]==-1) { /* i is a basic variable */
3694
dd_TableauEntry(&val,m_size,d_size,A,T,i,rhscol);
3695
if (dd_Negative(val)) {
3696
if (localdebug) printf("RHS entry for %ld is negative\n", i);
3697
*LPScorrect=dd_FALSE;
3698
break;
3699
}
3700
} else if (bflag[i] >0) { /* i is nonbasic variable */
3701
dd_TableauEntry(&val,m_size,d_size,A,T,objrow,bflag[i]);
3702
if (dd_Positive(val)) {
3703
if (localdebug) printf("Reduced cost entry for %ld is positive\n", i);
3704
*LPScorrect=dd_FALSE;
3705
break;
3706
}
3707
}
3708
};
3709
break;
3710
case dd_Inconsistent:
3711
for (j=1; j<=d_size; j++){
3712
dd_TableauEntry(&val,m_size,d_size,A,T,re,j);
3713
if (j==rhscol){
3714
if (dd_Nonnegative(val)){
3715
if (localdebug) printf("RHS entry for %ld is nonnegative\n", re);
3716
*LPScorrect=dd_FALSE;
3717
break;
3718
}
3719
} else if (dd_Positive(val)){
3720
if (localdebug) printf("the row entry for(%ld, %ld) is positive\n", re, j);
3721
*LPScorrect=dd_FALSE;
3722
break;
3723
}
3724
};
3725
break;
3726
case dd_DualInconsistent:
3727
for (i=1; i<=m_size; i++){
3728
dd_TableauEntry(&val,m_size,d_size,A,T,i,bflag[is]);
3729
if (i==objrow){
3730
if (dd_Nonpositive(val)){
3731
if (localdebug) printf("Reduced cost entry for %ld is nonpositive\n", bflag[is]);
3732
*LPScorrect=dd_FALSE;
3733
break;
3734
}
3735
} else if (dd_Negative(val)){
3736
if (localdebug) printf("the column entry for(%ld, %ld) is positive\n", i, bflag[is]);
3737
*LPScorrect=dd_FALSE;
3738
break;
3739
}
3740
};
3741
break;
3742
;
3743
default: break;
3744
}
3745
3746
ddlps=LPSf2LPS(LPS);
3747
3748
dd_SetSolutions(m_size,d_size,A,T,
3749
objrow,rhscol,ddlps,optvalue,sol,dsol,posset,nbindex,re,senew,bflag);
3750
*nse=senew;
3751
3752
3753
_L99:
3754
dd_clear(val);
3755
free(nbtemp);
3756
}
3757
3758
void dd_BasisStatusMinimize(dd_rowrange m_size,dd_colrange d_size,
3759
dd_Amatrix A,dd_Bmatrix T,dd_rowset equalityset,
3760
dd_rowrange objrow,dd_colrange rhscol,ddf_LPStatusType LPS,
3761
mytype *optvalue,dd_Arow sol,dd_Arow dsol, dd_rowset posset, ddf_colindex nbindex,
3762
ddf_rowrange re,ddf_colrange se,dd_colrange *nse,long *pivots, int *found, int *LPScorrect)
3763
{
3764
dd_colrange j;
3765
3766
for (j=1; j<=d_size; j++) dd_neg(A[objrow-1][j-1],A[objrow-1][j-1]);
3767
dd_BasisStatusMaximize(m_size,d_size,A,T,equalityset, objrow,rhscol,
3768
LPS,optvalue,sol,dsol,posset,nbindex,re,se,nse,pivots,found,LPScorrect);
3769
dd_neg(*optvalue,*optvalue);
3770
for (j=1; j<=d_size; j++){
3771
if (LPS!=dd_Inconsistent) {
3772
/* Inconsistent certificate stays valid for minimization, 0.94e */
3773
dd_neg(dsol[j-1],dsol[j-1]);
3774
}
3775
dd_neg(A[objrow-1][j-1],A[objrow-1][j-1]);
3776
}
3777
}
3778
#endif
3779
3780
/* end of cddlp.c */
3781
3782
3783