MODEL:
! Illustrates how to append cuts in a loop to generate the K-Best
solutions for a binary MILP;
! Keywords: K-Best solutions, generating multiple solutions for IPs;
! Requires Lingo 12, or higher;
DATA:
! Number of solutions to try and generate;
K = 10;
ENDDATA
SETS:
ITEMS: INCLUDE, WEIGHT, RATING;
MYFAVORITES( ITEMS);
KSOLUTIONS /1..K/: OBJ, RHS;
ENDSETS
DATA:
KNAPSACK_CAPACITY = 15;
ITEMS WEIGHT RATING =
BRATS 3 1
BROWNIES 3 1
BEER 3 1
ANT_REPEL 7 1
BLANKET 4 6
FRISBEE 1 6
SALAD 5 10
WATERMELON 7 9;
MYFAVORITES = BRATS BROWNIES BEER;
ENDDATA
SETS:
KXI( KSOLUTIONS, ITEMS): CUT, INCLUDE2;
ENDSETS
! The core knapsack model;
SUBMODEL KNAPSACK:
[R_OBJ] MAX = @SUM( ITEMS( I): RATING( I) * INCLUDE( I));
@SUM( ITEMS( I): WEIGHT( I) * INCLUDE( I)) <= KNAPSACK_CAPACITY;
@FOR( ITEMS( I): @BIN( INCLUDE( I)));
ENDSUBMODEL
! The solution cutoff constraints;
SUBMODEL KBESTCUTS:
@FOR( KSOLUTIONS( I2) | I2 #LE# I:
[R_CUT] @SUM( ITEMS( J): CUT( I2, J) * INCLUDE( J)) >= RHS( I2)
);
ENDSUBMODEL
CALC:
!Set some parameters;
@SET( 'DEFAULT');
@SET( 'TERSEO', 2);
! Loop to generate K-best solutions;
I = 0;
ISTATUS = 0;
@WHILE( I #LT# K #AND# ISTATUS #EQ# 0:
!@GEN( KNAPSACK, KBESTCUTS);
! Solve current knapsack;
@SOLVE( KNAPSACK, KBESTCUTS);
ISTATUS = @STATUS();
! Generate next cut to cutoff current solution;
I = I + 1;
RHS( I) = 1;
@FOR( ITEMS( J):
@IFC( INCLUDE( J) #LT# .1:
CUT( I, J) = 1;
@ELSE
CUT( I, J) = -1;
RHS( I) = RHS( I) - 1;
);
);
! Save current solution;
OBJ( I) = R_OBJ;
@FOR( ITEMS( J): INCLUDE2( I, J) = INCLUDE( J));
);
! Write a report;
@WRITE( ' OBJECTIVE');
@FOR( ITEMS( J): @WRITE( @FORMAT( ITEMS( J), '14s')));
@WRITE( @NEWLINE( 1));
@FOR( KSOLUTIONS( I2) | I2 #LE# I:
@WRITE( @FORMAT( OBJ( I2), '14g'));
@FOR( ITEMS( J2):
@IFC( INCLUDE2( I2, J2) #GT# .1:
@WRITE( @FORMAT( INCLUDE2( I2, J2), '14g'));
@ELSE
@WRITE( 13*' ', '.');
);
);
@WRITE( @NEWLINE( 1));
);
ENDCALC
END
|