Lindo Systems

MODEL:                               ! (PieceLinearSOS2.lng);
!  Demonstrates the SOS2 feature of LINGO for representing
  arbitrary, piecewise-linear cost curves.
   We have two suppliers. Each with his
  own piecewise-linear cost curve. 
   How much should we buy from each to
  buy a given total amount at minimum cost? ;
! Keywords: Linearization, Non-convex function, 
 Piecewise linear, Purchasing, Quantity discount, SOS2;
SETS:
 ! Suppliers with ...;
  SPLR: TCOST, TVOL;
  POINT; ! Price schedules with breakpoints;
  SXP( SPLR, POINT): WP, VOLP, COSTP;
ENDSETS

DATA:
  POINT = 1..8; ! Up to 5 break points;
  SPLR = V1 V2;  ! Two vendors;
 ! Total cost at each breakpoint, 
    linear interpolate between adjacent breakpoints;
 ! Volume & total cost  at each breakpoint;
    SXP   VOLP  COSTP = 
   V1 1     0     0    ! Supplier 1;
   V1 2   999   5994   ! $6/unit up this interval;
   V1 3  1000   5000   ! $5/unit starting here;
   V1 4  9999  49995   ! $5/unit up to here;
   V1 5 10000  45000   ! $4.5/unit starting here;
   V1 6 19999  89995.5 ! $4.5/unit up to here;
   V1 7 20000  80000   ! $4/unit starting here;
   V1 8 50000 200000   ! $4/unit up to here;
   V2 1     0     0    ! Supplier 2;
   V2 2   999   5994   ! $6/unit up this interval;
   V2 3  1000   5000   ! $5/unit starting here;
   V2 4  9999  49995   ! $5/unit up to here;
   V2 5 10000  45000   ! $4.5/unit starting here;
   V2 6 19999  89995.5 ! $4.5/unit up to here;
   V2 7 20000  80000   ! $4/unit starting here;
   V2 8 50000 200000 ; ! $4/unit up to here;

   NEED = 18000; ! Total units needed;
ENDDATA
! To see the scalar version of the model, click on:
   Solver | Generate | Display model;

! Minimize total cost of purchases from all suppliers;
 MIN = @SUM( SPLR(i): TCOST(i));

! Volume we need. For some price schedules,
  it might be cheaper to buy more than needed;
 [NC] @SUM( SPLR(i): TVOL(i)) >= NEED;

 ! For each supplier i;
 @FOR( SPLR(i):
  ! Calculate weighted cost;
   [WCOST] TCOST(i) = @SUM( SXP( i, p): COSTP( i, p) * WP( i,p));

  ! Calculate weighted volume;
   [WVOL] TVOL(i)  = @SUM( SXP( i,p): VOLP( i,p) * WP( i,p));

  ! Weights must sum to 1 for each supplier i;
   [SUM21]   1 = @SUM( SXP( i,p): WP( i,p));

  !  Weights must satisfy SOS2 condition:
    at most 2 weights > 0, and must be adjacent.
     Exploit fact that in LINGO, 
    string concatenation operator is "+", and
    member names are text strings; 
    @FOR( SXP( i,p): @SOS2( 'SOS2'+SPLR(i), WP( i,p)));
     );
  END