Lindo Systems

! Small bucket production sequencing with changeovers (prodseqk);
! Minimize the sum of setup plus inventory costs
  for producing multiple products on a single
  machine over multiple periods,
    Subject to:
     At most one product in a time period( the small bucket feature),
     Upper limit on amount produced in a period,
     No backlogging of demand; 
! Keywords: Changeover costs, lot sizing, scheduling, sequencing,
   production scheduling, ;
SETS:
 prod: iinv, ci, insetup;
 timep;
 pxt(prod,timep): dem, inv, x, z;
 pxp( prod, prod): cs;
 pxpxt( pxp, timep): y;
ENDSETS

DATA:
! The products;
    prod = A  B  C  D  E  F  G  H  I  J  K;
! How many machines producing which product at beginning;
  insetup= 1  0  0  0  0  0  0  0  0  0  0;
  
! Initial inventory;
   iinv = 0   2  9  8  6  7  8  3  7  9  8;
! Inventory cost for each product per period;
     ci = 3  2  2  1  2  4  2  1  1  2  1;
! The time periods;
  timep = 1..20;
! Changeover cost for each product pair;
   cs =
!   A  B  C  D  E  F  G  H  I  J  K;
!A; 0  1  2  1  1  3  1  2  1  1  3
!B; 9  0  1  3  1  1  1  1  1  1  1
!C; 8  6  0  1  1  1  1  3  1  1  2
!D; 9  9  9  0  1  1  1  1  1  1  1
!E; 8  9  9  9  0  1  1  1  3  1  3
!F; 9  7  9  9  9  0  1  1  1  1  1
!G; 9  9  9  9  9  9  0  1  1  1  1
!H; 9  9  9  9  9  9  9  0  1  1  1
!I; 9  9  9  9  9  9  9  9  0  1  1
!J; 9  9  9  9  9  9  9  9  9  0  1
!K; 7  9  6  9  9  7  9  9  8  9  0
;

! Demands for each 
    product(row)and period(col);
!     1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20;
 dem =
 !A; 0  0  7  0  5  0  1  0  0  0  0  0  0  0  1  1  0  0  0  0
 !B; 0  0  2  0  1  0  0  0  0  0  0  2  0  0  0  0  7  0  0  0
 !C; 0  0  1  0  1  0  2  0  0  0  0  0  0  0  1  0  0  1  0  0   
 !D; 0  0  0  0  0  0  0  1  0  1  0  1  0  0  0  3  0  0  0  1
 !E; 0  0  0  0  2  0  0  3  0  0  1  0  0  0  0  1  1  0  0  1
 !F; 0  0  0  0  0  0  0  0  0  0  9  3  0  0  8  3  0  0  0  0
 !G; 0  0  1  0  0  3  0  0  1  0  1  2  0  1  8  0  0  0  0  0
 !H; 0  0  0  0  0  1  0  2  0  1  1  0  0  0  0  1  0  0  0  0
 !I; 3  0  0  0  1  1  0  0  0  0  0  0  0  3  0  0  0  0  0  0
 !J; 0  0  2  4  0  2  1  0  0  0  0  0  0  7  0  0  0  0  1  0
 !K; 1  0  0  4  1  0  0  0  0  0  0  0  8  7  6  0  0  0  0  0
 ;

 ! Production capacity per period. All products measured in 
   same units;
 caplim = 11;
ENDDATA

SUBMODEL SCHED:
 ! Definitions:
   y( i, j, t)= 1 if machine is changed from
                 i to j at end of time period t.

   x( i, t)   = amount produced of product i in period t,

   z( i, t)   = 1 if machine produces (or is capable of)
                 product i during period t; 

! Minimize the sum over all periods of the cost of
   changeovers + inventory;
  MIN = CCOST + ICOST;
        CCOST = @SUM( pxpxt(i,j,t): cs(i,j)*y(i,j,t));
        ICOST = @SUM( pxt(i,t): ci(i)*inv(i,t));
          
! Which product is being produced initially, and if
  setup for k, must change to some j at end of period;
 @FOR( prod( k):
    z( k, 1) = insetup( k);
    z( k, 1) = @SUM( prod( j): y( k, j, 1);
     );

! If we changed from k to some j at the end of s,
  we had to change from some i to k at end of s-1;
 @FOR( pxt( k, s)| s #GT# 1:
    z( k, s) = @SUM( prod( i): y( i, k, s-1));
    z( k, s) = @SUM( prod( j): y( k, j, s));
     );

! Setups must be 0 or 1;
 @FOR( pxt( i, s):
    @BIN( z( i, s))
     );

! If we produce product i in period s, the machine
   must be in product i mode in period s.
   An upper limit on production is total demand of product;
  @FOR( pxt( i, s):
     x( i, s) <= @SMIN( caplim, @SUM( timep( t) | t #GE# s: dem( i, t)))* z( i, s)
       );
     );

 ! Inventory at end of period 1;
 @FOR( prod(i):
  [IEND1]  inv( i, 1) = iinv( i) + x( i, 1) - dem( i, 1);
     );
 ! and subsequent periods;
! Compute ending inventory in each period;
 @FOR( pxt( i, s)| s #gt# 1:
  [IEND]  inv( i, s) = inv( i, s-1) + x( i, s) - dem( i, s);
      );

 ! Production capacity constraints;
 @FOR( timep( t):
   @SUM( prod( i): x( i, t)) <= caplim;
     );

 ENDSUBMODEL


 CALC:
 ! Turn off default output;
   @SET("TERSEO", 2);
 ! Set relative optimality tolerance;
   @SET("IPTOLR", .015);
 ! Time in seconds at which to apply rel tolerance;
   @SET("TIM2RL", 30); 
   @SOLVE(SCHED);

  ! Produce a little report;
   @WRITE(@NEWLINE(2),'Inventory cost  = ',@FORMAT(ICOST,"9.2f"), @NEWLINE(1));
   @WRITE(            'Changeover costs= ',@FORMAT(CCOST,"9.2f"), @NEWLINE(1));
   @WRITE(            'Total costs     = ',@FORMAT(ICOST+CCOST,"9.2f"), @NEWLINE(1));
   @WRITE(@NEWLINE(1),' Period  Product Production', @NEWLINE(1));
   @FOR(timep(s): 
     @WRITE('    ',@FORMAT(s,"2.0f"),'     ');
     @FOR(prod(j) | z(j,s) #GT# .5:
        @WRITE(prod(j),'   ',@FORMAT(@ABS(x(j,s)),"8.1f"),@NEWLINE(1)));
       );
 ENDCALC