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