MODEL:
! Find alternative primal optimal extreme point solutions (EnumrXtrmC.lng)
to a Linear Program, and report the average of all of them.
All the solutions found are written to the file:
\temp\AltOpt.txt
! Example: The following model has
3 alternative primal extreme point optima
(X1 = 1 or X2 = 1 or X3 =1) and
3 alternative dual extreme point optima,
(DP1 = 1 or DP2 = 1/2 or DP3 = 1/3) for a total of
9 alternative optimal extreme point solutions.
We consider only the primal extreme point solutions as distinct.
MIN= X1 + X2 + X3,
X1 + X2 + X3 >= 1,
2* X1 + 2* X2 + 2* X3 >= 2,
3* X1 + 3* X2 + 3* X3 >= 3,
It reports
The average interior solution is:
X1 = 0.3333333333333333
X2 = 0.3333333333333333
X3 = 0.3333333333333333
Method: It is computationally expensive to enumerate every
distinct alternative optimal solution.
The approach used here is to randomly choose a large number of
random objectives/directions and then
minimize this objective subject to:
the solution is feasible and is
optimal for the original objective.
If enough random directions are generated, then
all alternative primal optimal solutions will be generated.;
! Keywords: Alternative optima, Average solution, Basic solution,
Corner point, Enumeration, Extreme point, K-Best solutions;
SETS:
ROW: RHS, TYPER;
COL: OBJ, X, SUB, OBJPTRB;
NONZ( ROW, COL): COEF;
SLIST;
SXC( SLIST, COL): XSV;
ENDSETS DATA:
! Here are a number of cases;
! Case Murty: Example based on
"A Problem in Enumerating Extreme Points, and an efficient Algorithm,"
by Katta G. Murty, Dept Ind. and Opns Eng.
U. Michigan, March 2007.
! Number of desired extreme points. (There appear to be 6 distinct primal solutions);
!Cmurty NDXP = 12;
!Cmurty SLIST = 1..NDXP;
!Find all extreme points;
! Names of rows;
!Cmurty ROW= R01 R02 R03 R04 R05 R06 R07 R08 R09 R10 R11 R12 R13 R14 R15 ;
!Cmurty RHS= 1;
!Cmurty TYPER = 0; !Cmurty COL =
X01 X02 X03 X04 S01 S02 S03 S04 S05 S06 S07 S08 S09 S10 S11 S12 S13 S14 S15 ;
!Cmurty OBJ= 0;
! Upper bounds;
!Cmurty SUB=
1 1 1 1 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5;
! Constraint coefficients, with slacks explicitly added;
!Cmurty COEF =
1 1 1 -1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0
1, 1, -1 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0
1, 1, -1, -1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0
1, -1, 1, 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0
1, -1, 1, -1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0
1, -1, -1, 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0
1, -1, -1 -1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0
-1, 1, 1, 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0
-1, 1, 1, -1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0
-1, 1, -1, 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0
-1, 1, -1, -1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0
-1, -1, 1, 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0
-1, -1, 1, -1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0
-1 -1 -1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0
-1, -1, -1, -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 ;
! Case OML6: Example from chapter 6 of Optimization Modeling with LINGO.
! It has two alternative optima;
!Number of desired extreme points.;
!COLM6 NDXP = 3;
!COLM6 SLIST = 1..3;
!Find all extreme points with profit contribution = optimal value;
! Names of rows;
!COLM6 ROW= MACH CAP HOURS SHIP PROD1 PROD2 PROD3;
!COLM6 RHS= 35 35 36 600 218 114 111 ;
!COLM6 TYPER= 1 1 1 1 -1 -1 -1; !COLM6 COL =
B34 B38 B48 B58 B42 B52 ;
!COLM6 OBJ=
-15.89 -17.89 -16.5 -15.22 -17.5 -16.22 ;
! Upper bounds;
!COLM6 SUB=
999 999 999 999 999 999 ;
! Constraint coefficients triples, ( Row Col Coefficient);
!COLM6 NONZ COEF =
MACH B34 0.11111 MACH B38 0.11111
CAP B48 0.16667 CAP B42 0.16667
HOURS B58 0.22222 HOURS B52 0.22222
SHIP B34 1 SHIP B38 1 SHIP B48 1 SHIP B58 1 SHIP B42 1 SHIP B52 1
PROD1 B34 1
PROD2 B38 1 PROD2 B48 1 PROD2 B58 1
PROD3 B42 1 PROD3 B52 1;
! Case Dyera: Example from Dyer and Proll, Math. Programming, vol. 12, 1977
in <= constraint form;
! It has 10 primal extreme points;
! Number of desired extreme point tries;
!CDyera NDXP = 60;
!Number of desired extreme points.;
!CDyera SLIST = 1..NDXP;
!CDyera ROW= ROW1 ROW2 ROW3 ROW4 ROW5;
!CDyera RHS= 5 16 3 17 10;
!CDyera TYPER = 1; !CDyera COL= X1 X2 X3 ;
!CDyera OBJ= 0 0 0;
!CDyera SUB= 99 99 99;
! Constraint coefficients;
!CDyera COEF =
3 2 -1
3 2 4
3 0 -4
2.25 4 3
1 2 1
;
! Case Xueyu 1;
! It has two alternative optima;
! Number of desired extreme points to try.;
!CX1 NDXP = 5;
!CX1 SLIST = 1..NDXP;
! Names of rows;
!CX1 ROW = CON1 CON2 CON3 CON4;
!CX1 RHS = -6 4 8 6;
!CX1 TYPER = 0; !CX1 COL =
X1 X2 SLK1 SLK2 SLK3 SLK4;
! Upper bounds;
!CX1 SUB=
999 999 999 999 999 999 ;
!CX1 OBJ =
-2 -1 0 0 0 0;
! Constraint coefficients;
!CX1 COEF =
-3 -2 1 0 0 0
2 -1 0 1 0 0
2 1 0 0 1 0
-1 2 0 0 0 1
;
! Case Xueyu 2;
! It has 7 extreme points;
! Number of desired extreme points tries.;
!CX2 NDXP = 10;
!CX2 SLIST = 1..NDXP;
! Names of rows;
!CX2 ROW = CON1 CON2 CON3 CON4 CON5 CON6 CON7;
!CX2 RHS = -1 -4 -12 -36 -26 -3 14;
!CX2 TYPER = 0; !CX2 COL =
X1 X2 SLK1 SLK2 SLK3 SLK4 SLK5 SLK6 SLK7;
! Upper bounds;
!CX2 SUB=
999 999 999 999 999 999 999 999 999;
!CX2 OBJ =
0 0 0 0 0 0 0 0 0;
! Constraint coefficients;
!CX2 COEF =
2 -1 -1 0 0 0 0 0 0
3 -2 0 -1 0 0 0 0 0
1 -2 0 0 -1 0 0 0 0
-3 -2 0 0 0 -1 0 0 0
-4 1 0 0 0 0 -1 0 0
-1 2 0 0 0 0 0 -1 0
2 4 0 0 0 0 0 0 -1
;
! Case: Variant of Astro-Cosmo problem.
! It has two alternative optima;
! Max = 15 A + 30 C
A <= 60,
C <= 50,
A + 2 C <= 120,
! Number of desired extreme points tries.;
!CAC1 NDXP = 3;
!CAC1 SLIST = 1..NDXP;
! The last three variables in the tableau,
cols 3-5, are the slack variables;
!CAC1 ROW = ALIM CLIM LABOR;
!CAC1 RHS = 60 50 120;
!CAC1 TYPER = 0; ! Names of columns;
!CAC1 COL = A__ C__ S_1 S_2 S_3;
!CAC1 OBJ = -15 -30 0 0 0;
! Upper bounds;
!CAC1 SUB = 60 50 999 999 999;
! Names of rows;
! Matrix coefficients, including Obj and RHS;
!CAC1 COEF =
1 0 1 0 0
0 1 0 1 0
1 2 0 0 1 ;
! Case 2: Variant of extended Astro-Cosmo problem.
! It has two alternative optima;
! Max = 15 A + 30 C + 44 D,
A + D <= 60,
C + D <= 50,
A + 2 C + 3 D <= 120,
! Case PD3;
! It has 3 alternative primal extreme point optima, and
3 alternative dual extreme point optima, for a total
of 9 alternative extreme point optima;
! MIN= X1 + X2 + X3,
X1 + X2 + X3 >= 1,
2* X1 + 2* X2 + 2* X3 >= 2,
3* X1 + 3* X2 + 3* X3 >= 3,
! Number of desired extreme points tries.;
!CPD3 NDXP = 8;
!CPD3 SLIST = 1..NDXP;
! Names of rows;
!CPD3 ROW = CON1 CON2 CON3 ;
!CPD3 RHS = 1 2 3;
!CPD3 TYPER = -1; !CPD3 COL =
X1 X2 X3 ;
! Upper bounds;
!CPD3 SUB=
999 999 999 ;
!CPD3 OBJ =
1 1 1 ;
! Constraint coefficients in sparse form;
!CPD3 NONZ, COEF =
CON1 X1 1
CON1 X2 1
CON1 X3 1
CON2 X1 2
CON2 X2 2
CON2 X3 2
CON3 X1 3
CON3 X2 3
CON3 X3 3
;
! Number of desired extreme points tries.;
!CAC2 NDXP = 3;
!CAC2 SLIST = 1..NDXP;
! Names of rows;
!CAC2 ROW = ALIM CLIM LABOR;
!CAC2 RHS = 60 50 120;
!CAC2 TYPER = 0; ! The last three variables in the tableau,
cols 4-6, are the slack variables;
! Names of columns;
!CAC2 COL= A__ C__ D__ S_1 S_2 S_3 ;
!CAC2 OBJ= -15 -30 -44 0 0 0 ;
! Upper bounds;
!CAC2 SUB = 60 50 40 999 999 999;
! Constraint coefficients in sparse form;
!CAC2 NONZ, COEF =
ALIM A__ 1
ALIM D__ 1
ALIM S_1 1
CLIM C__ 1
CLIM D__ 1
CLIM S_2 1
LABOR A__ 1
LABOR C__ 2
LABOR D__ 3
LABOR S_3 1;
! Case 3: Example from Dyer and Proll, Math. Programming, vol. 12, 1977
in equality constraint form;
! It has 10 primal extreme points;
! Number of desired extreme point tries;
!CDyer; NDXP = 60!Number of desired extreme points.;
!CDyer; SLIST = 1..NDXP!CDyer; ROW= ROW1 ROW2 ROW3 ROW4 ROW5!CDyer; RHS= 5 16 3 17 10!CDyer; TYPER = 0!CDyer; COL= X1 X2 X3 X4 X5 X6 X7 X8 !CDyer; OBJ= 0 0 0 0 0 0 0 0!CDyer; SUB= 99 99 99 99 99 99 99 99! Constraint coefficients;
!CDyer; COEF =
3 2 -1 1 0 0 0 0
3 2 4 0 1 0 0 0
3 0 -4 0 0 1 0 0
2.25 4 3 0 0 0 1 0
1 2 1 0 0 0 0 1
;
! We can read the data from a currently open( only one)
spreadsheet with range names matching LINGO names;
!CExcel NDXP = @OLE() ;
!Number of desired extreme points.;
!CExcel SLIST = 1..NDXP;
! Names of rows;
!CExcel ROW = @OLE();
!CExcel RHS = @OLE();
!CExcel TYPER = @OLE(); ! Names of columns;
!CExcel COL= @OLE();
! Objective coefficients;
!CExcel OBJ= @OLE();
! Upper bounds;
!CExcel SUB = @OLE();
! Constraint coefficients in sparse form;
!CExcel NONZ, COEF = @OLE();
ENDDATA
SUBMODEL Simple ! A weighted objective;
MIN = ALPHA* OBVTRUE + (1 - ALPHA)* OBVPRTRB;
@FREE( OBVTRUE); ! The true objective;
OBVTRUE = @SUM( COL( j) : OBJ( j)* X( j));
@FREE( OBVPRTRB); ! The perturbed objective;
OBVPRTRB = @SUM( COL( j) : OBJPTRB( j)* X( j));
! Allow an upper bound constraint on the true Objective value;
OBVTRUE <= OBVUL;
@FREE( OBVUL); ! It could be negative;
@FOR( ROW( I) | TYPER( I) #GT# 0: ! <= rows;
@SUM( NONZ( I, J): COEF( I, J) * X( J)) <= RHS( I)
);
@FOR( ROW( I) | TYPER( I) #EQ# 0:! = rows;
@SUM( NONZ( I, J): COEF( I, J) * X( J)) = RHS( I)
);
@FOR( ROW( I) | TYPER( I) #LT# 0: ! >= rows;
@SUM( NONZ( I, J): COEF( I, J) * X( J)) >= RHS( I)
);
@FOR( COL( J): ! All vars are bounded: 0 <= X( J) <= SUB( J);
@BND( 0, X( J), SUB( J))
);
ENDSUBMODEL
CALC:
@SET( 'OROUTE', 1); ! Buffer size for routing output to window;
@SET( 'TERSEO', 3); ! Output level (0:verb, 1:terse, 2:only errors, 3:none);
@SET( 'SOLVEL', 3); ! Linear solver (0:LINGO decides,1:primal,2:dual,3:barrier);
TOFILE = 1; ! 1 means send solutions to file \temp\AltOpt.txt;
NCOL = @SIZE( COL);
TOLDIF = 0.00000001; ! Tolerance for considering two values different;
ALPHA = 1; ! Use original true objective;
@FOR( COL( j): OBJPTRB( j) = 0); ! Initially, no perturbations;
@SOLVE( SimpleMODEL);
@WRITE( 'The Objective value= ', OBVTRUE, @NEWLINE( 1));
ISTAT = @STATUS();
@WRITE( ' Solve Status= ', ISTAT, @NEWLINE( 1));
ITER = 1;
NSFND = 1; ! Number of solutions found;
! Save this solution;
@FOR( COL( j): XSV( NSFND, j) = X( j)); ! Save current solution;
@WRITE(' Solution# ', NSFND, ' (Iter: ', ITER,')', @NEWLINE( 1));
@DIVERT( '\temp\AltOpt.txt'); ! Send output to a file;
@WRITE(' Solution# ', NSFND, ' (Iter: ', ITER,')', @NEWLINE( 1));
@FOR( COL( j) | X( j) #GT# 0:
TEMP = X( j);
@WRITE(' ', COL( j),' ', TEMP, @NEWLINE( 1));
);
@WRITE(@NEWLINE( 1));
@DIVERT(); ! Revert to output to the screen;
! Restrict to just optimal solutions;
OBVUL = OBVTRUE;
! Switch to perturb objective;
ALPHA = 0;
! How to choose next direction;
MODE = 1; ! 1: random, 2: flip, 3: mod;
! Generate a perturbed objective;
! A arbitrary random starting seed;
URANDV = 0.13245768;
@WHILE( ITER #LT# NDXP:
ITER = ITER + 1;
! Generate a direction, try to make different from previous directions;
@IFC( MODE #EQ# 1: !1) Choose a random direction;
@FOR( COL( j):
URANDV = @RAND( URANDV); ! Get next random uniform;
OBJPTRB( j) = URANDV - 0.5; ! Uniform in ( -0.5, +0.5);
);
);
@IFC( MODE #EQ# 2 #OR# MODE #EQ# 4: !2) Choose opposite direction;
@FOR( COL( j):
OBJPTRB( j) = - OBJPTRB( j);
);
);
@IFC( MODE #EQ# 3: !3) Choose approximately orthogonal direction,
e.g. ( -0.1, +0.4) becomes (+0.4, -0.1);
@FOR( COL( j):
TEMP = OBJPTRB( j) + 0.5;
@IFC( TEMP #GT# 0.5: TEMP = TEMP - 1.0;
OBJPTRB( j) = TEMP;
);
);
);
MODE = MODE + 1; ! Use different direction for next iteration;
@IFC( MODE #GT# 4: MODE = 1);
@SOLVE( SimpleMODEL);
ISTAT = @STATUS();
@WRITE( ' Solve Status= ', ISTAT, @NEWLINE( 1));
! Check if we have already seen this primal solution;
NOTDUP = 1; ! Is it a duplicate? ;
IA = 0; ! Loop over already found solutions;
@WHILE( IA #LT# NSFND #AND# NOTDUP:
IA = IA + 1;
ISAME = 1; ! Duplicate until found otherwise;
IB = 0; ! Loop over variables in solution IA;
@WHILE( IB #LT# NCOL #AND# ISAME:
IB = IB + 1;
@IFC( @ABS( X( IB) - XSV( IA, IB)) #GT# TOLDIF:
ISAME = 0; ! Current soln and soln IA are different;
);
);
@IFC( ISAME: NOTDUP = 0); ! Current soln and soln IA are same;
);
@IFC( NOTDUP:
! We found a new primal alternative optima;
NSFND = NSFND + 1;
@WRITE(' Solution# ', NSFND, ' (Iter: ', ITER,')', @NEWLINE( 1));
@DIVERT( '\temp\AltOpt.txt', 'A'); ! Send output to file, Appending to existing contents;
@WRITE(' Solution# ', NSFND, ' (Iter: ', ITER,')', @NEWLINE( 1));
@FOR( COL( j) :
XSV( NSFND, j) = X( j); ! Save it;
@IFC( X( j) #GT# 0: ! Write out the nonzeroes;
TEMP = X( j);
@WRITE(' ', COL( j),' ', TEMP, @NEWLINE( 1));
);
);
@WRITE(@NEWLINE( 1));
@DIVERT(); ! Revert to output to the screen;
);
);
@WRITE(' Completed ', ITER, ' iterations', @NEWLINE( 1));
@DIVERT( '\temp\AltOpt.txt', 'A'); ! Send output to file, Appending to existing contents;
@WRITE( @NEWLINE( 1),' The average interior solution is:', @NEWLINE( 1));
@FOR( COL( j) :
TEMP = @SUM( SLIST( i) | i #LE# NSFND: XSV( i, j))/ NSFND; ! Save it;
@WRITE(' ', COL( j),' ', TEMP, @NEWLINE( 1));
);
@DIVERT(); ! Revert to output to the screen;
ENDCALC
|