Lindo Systems

! Cutting stock model in LINGO         (cutsgen)
   with credit given for modest overage
   of certain finished good sizes. We enumerate
   different patterns for cutting each size of
   raw material, and then determine how many
   copies to run of each pattern so as to:
    a) Minimize net cost of rm used,
    b) do not use more rm than is available,
    c) produce at least as much as is required
         of each fg;
 ! Keywords: cutting stock, remnant inventory;
SETS:
! Each raw material has a size, quantity, and cost;
  rm: lenr, qr, cr;
! Each finished good has a size, min quantity
  needed, max quantity useful, and value of excess;
  fg: lenf, qf, qful, valul, uexcess;
ENDSETS
DATA:
! Describe the raw materials available;
  rm, lenr, qr,   cr =
  R72  72   9999  28
  R48  48   9999  19
  R36  36   9999  15;
! Describe the finished goods needed.
  We must produce at least qf units of each fg.
  For any amount we produce above qf 
  up to qful, we get credit valul/unit;
  fg, lenf, qf , qful, valul=
  F60  60   500  500     0
  F56  56   400  400     0
  F42  42   300  300     0
  F38  38   450  450     0
  F34  34   350  350     0
  F24  24   100  100     0
  F15  15   800  800     0
  F10  10  1000 1000     0;
ENDDATA

SETS:
! Enumerate all possible cutting patterns with 1 fg;
  rxf(rm,fg)| lenf(&2) #le# lenr(&1): x1, w1;
! Enumerate all possible patterns with 2 fg;
  rxf2( rxf, fg) | &2 #le# &3 #and# (lenf(&2) + lenf(&3) #le# lenr(&1)): x2,w2;
! Enumerate all possible patterns with 3 fg;
  rxf3( rxf2, fg)| &3 #le# &4 #and# (lenf(&2) + lenf(&3)+ lenf(&4) #le# lenr(&1)): x3,w3;
! Enumerate all possible patterns with 4 fg;
  rxf4( rxf3, fg)| &4 #le# &5 #and# (lenf(&2) + lenf(&3)+ lenf(&4)+lenf(&5)
          #le# lenr(&1)): x4,w4;
! Enumerate all possible patterns with 5 fg;
  rxf5( rxf4, fg)| &5 #le# &6 #and# (lenf(&2) + lenf(&3)+ lenf(&4)+lenf(&5)+lenf(&6)
          #le# lenr(&1)): x5,w5;
! Enumerate all possible patterns with 6 fg;
  rxf6( rxf5, fg)| &6 #le# &7 #and# (lenf(&2) + lenf(&3)+ lenf(&4)+lenf(&5)
      +lenf(&6)+lenf(&7) #le# lenr(&1)): x6,w6;
! Enumerate all possible patterns with 7 fg;
  rxf7( rxf6, fg)| &7 #le# &8 #and# (lenf(&2) + lenf(&3)+ lenf(&4)+lenf(&5)
      +lenf(&6)+lenf(&7)+lenf(&8) #le# lenr(&1)): x7,w7;
! We assume that no cutting pattern need include more than 7 pieces;
ENDSETS

! Minimize cost of material used;
  MIN = @SUM( rxf(r,f1): cr(r)*x1(r,f1))
      + @SUM( rxf2(r,f1,f2): cr(r)*x2(r,f1,f2))
      + @SUM( rxf3(r,f1,f2,f3): cr(r)*x3(r,f1,f2,f3))
      + @SUM( rxf4(r,f1,f2,f3,f4): cr(r)*x4(r,f1,f2,f3,f4))
      + @SUM( rxf5(r,f1,f2,f3,f4,f5): cr(r)*x5(r,f1,f2,f3,f4,f5))
      + @SUM( rxf6(r,f1,f2,f3,f4,f5,f6): cr(r)*x6(r,f1,f2,f3,f4,f5,f6))
      + @SUM( rxf7(r,f1,f2,f3,f4,f5,f6,f7): cr(r)*x7(r,f1,f2,f3,f4,f5,f6,f7))
  ! minus credit for overage that is not too huge;
      - @SUM( fg( f): valul(f)*uexcess( f));

! We cannot use more of each raw material type r, than is available;
  @FOR( rm( r):
     @SUM(rxf(r,f): x1(r,f))
   + @SUM(rxf2(r,f1,f2): x2(r,f1,f2))
   + @SUM(rxf3(r,f1,f2,f3): x3(r,f1,f2,f3))
   + @SUM(rxf4(r,f1,f2,f3,f4): x4(r,f1,f2,f3,f4))
   + @SUM(rxf5(r,f1,f2,f3,f4,f5): x5(r,f1,f2,f3,f4,f5))
   + @SUM(rxf6(r,f1,f2,f3,f4,f5,f6): x6(r,f1,f2,f3,f4,f5,f6))
   + @SUM(rxf7(r,f1,f2,f3,f4,f5,f6,f7): x7(r,f1,f2,f3,f4,f5,f6,f7))
    <= qr(r);
      );

! We have to satisfy each finished good demand;
  @FOR( fg(f):
   [dem]  @SUM(rxf(r,f): x1(r,f))
   + @SUM(rxf2(r,f1,f2)| f #eq# f1: x2(r,f1,f2))
   + @SUM(rxf2(r,f1,f2)| f #eq# f2: x2(r,f1,f2))
   + @SUM(rxf3(r,f1,f2,f3)| f #eq# f1: x3(r,f1,f2,f3))
   + @SUM(rxf3(r,f1,f2,f3)| f #eq# f2: x3(r,f1,f2,f3))
   + @SUM(rxf3(r,f1,f2,f3)| f #eq# f3: x3(r,f1,f2,f3))
   + @SUM(rxf4(r,f1,f2,f3,f4)| f #eq# f1: x4(r,f1,f2,f3,f4))
   + @SUM(rxf4(r,f1,f2,f3,f4)| f #eq# f2: x4(r,f1,f2,f3,f4))
   + @SUM(rxf4(r,f1,f2,f3,f4)| f #eq# f3: x4(r,f1,f2,f3,f4))
   + @SUM(rxf4(r,f1,f2,f3,f4)| f #eq# f4: x4(r,f1,f2,f3,f4))
   + @SUM(rxf5(r,f1,f2,f3,f4,f5)| f #eq# f1: x5(r,f1,f2,f3,f4,f5))
   + @SUM(rxf5(r,f1,f2,f3,f4,f5)| f #eq# f2: x5(r,f1,f2,f3,f4,f5))
   + @SUM(rxf5(r,f1,f2,f3,f4,f5)| f #eq# f3: x5(r,f1,f2,f3,f4,f5))
   + @SUM(rxf5(r,f1,f2,f3,f4,f5)| f #eq# f4: x5(r,f1,f2,f3,f4,f5))
   + @SUM(rxf5(r,f1,f2,f3,f4,f5)| f #eq# f5: x5(r,f1,f2,f3,f4,f5))
   + @SUM(rxf6(r,f1,f2,f3,f4,f5,f6)| f #eq# f1: x6(r,f1,f2,f3,f4,f5,f6))
   + @SUM(rxf6(r,f1,f2,f3,f4,f5,f6)| f #eq# f2: x6(r,f1,f2,f3,f4,f5,f6))
   + @SUM(rxf6(r,f1,f2,f3,f4,f5,f6)| f #eq# f3: x6(r,f1,f2,f3,f4,f5,f6))
   + @SUM(rxf6(r,f1,f2,f3,f4,f5,f6)| f #eq# f4: x6(r,f1,f2,f3,f4,f5,f6))
   + @SUM(rxf6(r,f1,f2,f3,f4,f5,f6)| f #eq# f5: x6(r,f1,f2,f3,f4,f5,f6))
   + @SUM(rxf6(r,f1,f2,f3,f4,f5,f6)| f #eq# f6: x6(r,f1,f2,f3,f4,f5,f6))
   + @SUM(rxf7(r,f1,f2,f3,f4,f5,f6,f7)| f #eq# f1: x7(r,f1,f2,f3,f4,f5,f6,f7))
   + @SUM(rxf7(r,f1,f2,f3,f4,f5,f6,f7)| f #eq# f2: x7(r,f1,f2,f3,f4,f5,f6,f7))
   + @SUM(rxf7(r,f1,f2,f3,f4,f5,f6,f7)| f #eq# f3: x7(r,f1,f2,f3,f4,f5,f6,f7))
   + @SUM(rxf7(r,f1,f2,f3,f4,f5,f6,f7)| f #eq# f4: x7(r,f1,f2,f3,f4,f5,f6,f7))
   + @SUM(rxf7(r,f1,f2,f3,f4,f5,f6,f7)| f #eq# f5: x7(r,f1,f2,f3,f4,f5,f6,f7))
   + @SUM(rxf7(r,f1,f2,f3,f4,f5,f6,f7)| f #eq# f6: x7(r,f1,f2,f3,f4,f5,f6,f7))
   + @SUM(rxf7(r,f1,f2,f3,f4,f5,f6,f7)| f #eq# f7: x7(r,f1,f2,f3,f4,f5,f6,f7))
    >= qf(f) + uexcess(f);
 ! Cannot claim credit for huge amount of excess;
     uexcess(f) <= qful(f) - qf(f);
      );

 ! Can only run integer quantities of each pattern;
     @FOR(rxf:  @GIN(x1));
     @FOR(rxf2: @GIN(x2));
     @FOR(rxf3: @GIN(x3));
     @FOR(rxf4: @GIN(x4));
     @FOR(rxf5: @GIN(x5));
     @FOR(rxf6: @GIN(x6));
     @FOR(rxf7: @GIN(x7));

! Compute leftover of each pattern just for curiousity;
@FOR( rxf( r, f1):
    w1(r,f1) = lenr( r) - lenf(f1);
    );
@FOR( rxf2(r,f1,f2):
    w2(r,f1,f2) = lenr(r) - lenf(f1) - lenf(f2);
    );
@FOR( rxf3(r,f1,f2,f3):
    w3(r,f1,f2,f3) = lenr(r) - lenf(f1) - lenf(f2)- lenf(f3);
    );
@FOR( rxf4(r,f1,f2,f3,f4):
    w4(r,f1,f2,f3,f4) = lenr(r) - lenf(f1) - lenf(f2)- lenf(f3) - lenf(f4);
    );
@FOR( rxf5(r,f1,f2,f3,f4,f5):
    w5(r,f1,f2,f3,f4,f5) = lenr(r)-lenf(f1)-lenf(f2)-lenf(f3)-lenf(f4)-lenf(f5);
    );
@FOR( rxf6(r,f1,f2,f3,f4,f5,f6):
    w6(r,f1,f2,f3,f4,f5,f6) = lenr(r)-lenf(f1)-lenf(f2)-lenf(f3)-lenf(f4)-lenf(f5)-lenf(f6);
    );
@FOR( rxf7(r,f1,f2,f3,f4,f5,f6,f7):
    w7(r,f1,f2,f3,f4,f5,f6,f7) = 
     lenr(r)-lenf(f1)-lenf(f2)-lenf(f3)-lenf(f4)-lenf(f5)-lenf(f6)-lenf(f7);
    );