Lindo Systems

! Report generation in LINGO.         (RangeReport.lng);
!  Illustrates how to accesses dual prices and range analysis,
  and in general, how to analyze an LP solution report.
  For example, if a row of the standard solution report has a pair of zeros,
  so-called snake eyes, then there may be alternative optima;
! Key words: @FORMAT, @WRAP, Alternative optima, Dual prices,  LINGO, MOD function, 
   Parametric analysis, Range analysis, Reduced cost, Report generation, 
   Sensitivity analysis, Snake eyes, Solution report, Staff scheduling, Submodel;
SETS:
  DAYS : REQUIRED, START;
ENDSETS
DATA:
      DAYS = MON TUE WED THU FRI SAT SUN;
  REQUIRED = 20  16  13  16  19  14  12;
ENDDATA

SUBMODEL STAFFIT:
! A simple 5 days on, 2 days off staffing model with wraparound;
! Minimize total number starting over all days;
 MIN = @SUM( DAYS( d): START( d));
 @FOR( DAYS( d): 
! The @WRAP function is a variation of the MOD function;
  [REQDAY] @SUM( DAYS( i) | i #LE# 5: 
     START( @WRAP( d - i + 1, 7))) >= REQUIRED( d)
     );
ENDSUBMODEL

CALC:
  @SET( 'DUALCO', 2);! Compute dual prices/reduced costs (0:No, 1:Prices, 2:+Ranges);
  @SET( 'TERSEO',2); ! Output level (0:verb, 1:terse, 2:only errors, 3:none);

  @SOLVE( STAFFIT);

! Write a variables section report;
  @WRITE('                       Variables report', @NEWLINE(1));
  @WRITE('                             Allowable  Allowable', @NEWLINE(1));
  @WRITE(' Variable    Value  RedCost   Increase   Decrease', @NEWLINE(1));
  @FOR( DAYS( d):
    XV = START( d);           ! Primal values;
    PRC = @DUAL( START( d));  ! Dual values;
    RUP = @RANGEU( START( d));! Range up;
    RDN = @RANGED( START( d));! Range down;
 ! Replace infinity by 99999;
    RUP = @SMIN( RUP, 99999);
    RDN = @SMIN( RDN, 99999);
    @WRITE( 'START(',DAYS(d),') ', @FORMAT( XV,'7.2f'), ' ', @FORMAT( PRC, '8.3f'),
         ' ',@FORMAT( RUP, '10.3f'), ' ',@FORMAT( RDN, '10.3f'), @NEWLINE( 1));
       );

! Write a constraints section report;
    @WRITE( @NEWLINE( 1));
    @WRITE('                     Constraints report', @NEWLINE(1));
    @WRITE('                             Allowable  Allowable', @NEWLINE(1));
    @WRITE('       Row   Slack    DualP   Increase   Decrease', @NEWLINE(1));
    @FOR( DAYS( d):
      XS = @SUM( DAYS( i) | i #LE# 5: ! Primal values;
          START( @WRAP( d - i + 1, 7))) - REQUIRED( d);

      PRC = @DUAL( REQDAY( d));  ! Dual values;
      RUP = @RANGEU( REQDAY( d));! Range up;
      RDN = @RANGED( REQDAY( d));! Range down;
 ! Replace infinity by 99999;
      RUP = @SMIN( RUP, 99999);
      RDN = @SMIN( RDN, 99999);
      @WRITE( '      ', DAYS( d),') ', @FORMAT( XS,'7.2f'), ' ', @FORMAT( PRC, '8.3f'),
         ' ',@FORMAT( RUP, '10.3f'), ' ',@FORMAT( RDN, '10.3f'), @NEWLINE( 1));
       );
 ENDCALC