Lindo Systems

MODEL:
! A model with three criteria with "Pre-emptive" importance.
 ! Staffing example:
    Step 1: (Give 1st priority to)
       - Minimize total cost
    Step 2: (Give 2nd priority to)
       - Fix costs to level from Step 1
       - Solve to minimize max staff overage
         on any given day, thereby spreading
         excess staff through the week
    Step 3: (Give 2nd priority to)
       - Fix max overage to it's level from  
         Step 2
       - Solve to minimize the number working
         on a Sunday
 ! Any Preemptive optimal solution is also Pareto optimal;
! Keywords:  Goal programming, Lexico-goal programming,
   Preemptimve criteria, Pareto optimal, Staff Scheduling;

 SETS:
   DAY :
       NEED, START, COST, EXCESS;
 ENDSETS

 DATA:
     DAY = MON, TUE, WED, THU, FRI, SAT, SUN;
    NEED =  19,  17,  15,  19,  17,  14,  12;
    COST = 200, 200, 200, 200, 200, 200, 200;
 ENDDATA

 SUBMODEL OBJ_COST:
   MIN = TTL_COST;
 ENDSUBMODEL

 SUBMODEL OBJ_MAX_EXCESS:
   MIN = MAX_EXCESS;
 ENDSUBMODEL

 SUBMODEL OBJ_MIN_SUNDAY_STAFF:
   MIN = EXCESS( @INDEX( DAY, SUN));
 ENDSUBMODEL

 SUBMODEL BASE:
   ! Compute cost;
   TTL_COST = @SUM( DAY( D) : START( D) * COST( D));

   ! The constraints;
   @FOR( DAY( D):
    @SUM( DAY( COUNT)| COUNT #LE# 5:
    START( @WRAP( D - COUNT + 1, @SIZE( DAY)))) - 
     EXCESS( D)= NEED( D)
   );

   ! Computes the maximum staff excess;
   @FOR( DAY( D): MAX_EXCESS >= EXCESS( D)); 

   ! Starts must be integral;
   @FOR( DAY: @GIN( START));

   @BND( 0, TTL_COST, BNDU_COST);
   @BND( 0, MAX_EXCESS, BNDU_MAX_EXCESS);
 ENDSUBMODEL

 PROCEDURE REPORT:
!  Procedure to write a standard report;
   @WRITE('               ');
   @WRITEFOR( DAY( D): DAY( D), '   ');
   @WRITE( 'TOTAL COST', @NEWLINE( 1)); 
   @WRITE( '     Start: ');
   @WRITEFOR( DAY: @FORMAT( START, '6.0f'));
   @WRITE( @FORMAT( @SUM( DAY: COST*START), '8.0f'));
   @WRITE( @NEWLINE( 1));
   @WRITE( '   On Duty: ');
   @WRITEFOR( DAY: @FORMAT( NEED + EXCESS, '6.0f'));
   @WRITE( @NEWLINE( 1));
   @WRITE( '  Required: ');
   @WRITEFOR( DAY: @FORMAT( NEED, '6.0f'));
   @WRITE( @NEWLINE( 1));
   @WRITE( '    Excess: ');
   @WRITEFOR( DAY: @FORMAT( EXCESS, '6.0f'));
   @WRITE( @NEWLINE( 2));
 ENDPROCEDURE

 CALC:
   !Run in quiet mode;
   @SET( 'TERSEO', 2);
 
   !Free up bounds;
   BNDU_COST =  1.E10;
   BNDU_MAX_EXCESS =  1.E10;

   @WRITE('Illustrate preemptive objectives in staffing:', @NEWLINE(1),
     ' 1) Minimize cost, 2) Minimize max excess any day, 3) Minimize Sunday staffing.',@NEWLINE(2));

   !Solve to minimize cost;
   @SOLVE( OBJ_COST, BASE);

   @WRITE( 'Solution 1 - Simply minimize cost:', @NEWLINE( 1));
   REPORT;  ! Display standard report;

   !Fix TTL_COST to optimal value;
   BNDU_COST = TTL_COST;

   !Re-solve to minimize the max excess staff on any given day
    in order to spread any excess staff throughout the week;
   @SOLVE( OBJ_MAX_EXCESS, BASE);

   @WRITE( 'Solution 2 - min cost, then minimize max excess:', @NEWLINE( 1));
   REPORT;

   !Fix max excess to optimal level;
   BNDU_MAX_EXCESS = MAX_EXCESS;

   !Re-solve to minimize total workers on Sundays;
   @SOLVE( OBJ_MIN_SUNDAY_STAFF, BASE);

   @WRITE( 'Solution 3 - min cost / min max excess / min Sunday:', @NEWLINE( 1)); 
   REPORT;

 ENDCALC
      
END