Lindo Systems

!Two vendors each offer their own price discount schedule.	    (QdiscSupL.lng)
How much should we buy from each to minimize total cost?	
Vendor A gives discounts on all units.  
Vendor B gives discounts only on incremental units past breakpoint;	
!Keywords: Discount, Linearization, Non-convex Function, Purchasing, Quantity discount, Vendor selection;
SETS:
  POINT: AELVL, ARATE, AIQ, AICOST, ZA, 
         BELVL, BRATE, BIQ, BICOST, ZB, BIPRVCOST ;
ENDSETS
DATA:
 QNEED = 6000;  ! Amount we need to buy;
! Entry level for each interval, and rate for the interval;
 AELVL, ARATE=
     0     9	
  1000     8  
  2500     7  
  7500     5  
 15000     3  
 20000 99999; !<<==Max possible;  

 BELVL, BRATE=
     0     8  
  1200     7  
  3000     6  
  7500     4  
 14000     2  
 20000 99999; !<<==Max possible;  
ENDDATA

! Minimize the total cost from vendors A & B;
  MIN = TOTCOST;
   TOTCOST = ATCOST + BTCOST;
 ! Quantity from A and B must be >= amount we need;
    ATQ + BTQ >= QNEED;

 ! Model of Vendor A discount schedule (All Units);
    @FOR( POINT( i) | i #LT# @SIZE( POINT):
      @BIN( ZA( i));  ! Either use (1) or not use (0) this interval;
! AIQ( i) = amount purchased from A if in interval i, else 0;
! AIQ( i) must be large enough for this interval;
      AIQ( i) >=  AELVL( i) * ZA( i);
! AIQ( i) must not be too large for interval;
      AIQ( i) <=  AELVL( i+1 ) * ZA( i);
! Cost if we use this interval;
      AICOST( i) = ARATE( i) * AIQ( i);
        );

! Tie all intervals for A together;
  ! Can choose at most 1 interval;
      @SUM( POINT( i) | i #LT# @SIZE( POINT):  ZA( i)) <= 1;
  ! Quantity purchased from A; 
      @SUM( POINT( i) | i #LT# @SIZE( POINT): AIQ( i)) = ATQ;
  ! Total cost of purchases from A; 
      @SUM( POINT( i) | i #LT# @SIZE( POINT): AICOST( i)) = ATCOST;

  
    ! Model of Vendor B discount schedule (Incremental units);
    BIPRVCOST(1) = 0; ! Cost of purchase in previous intervals;
    @FOR( POINT( i) | i #LT# @SIZE( POINT):
      @BIN( ZB( i));  ! Either use (1) or not use (0) this interval;
! BIQ( i) = amount purchased from B if in interval i, else 0;
! BIQ( i) must be large enough for this interval;
      BIQ( i) >=  BELVL( i) * ZB( i);
! BIQ( i) must not be too large for interval;
      BIQ( i) <=  BELVL( i+1 ) * ZB( i);
! Cost of previous intervls + incremental cost in this interval;
      BICOST( i) = ( BIPRVCOST( i) - BRATE( i)* BELVL( i))* ZB( i)
                                   + BRATE( i)* BIQ( i);
! Get ready for next interval. Cost if we use this interval;
      BIPRVCOST( i+1) = BIPRVCOST( i) + BRATE( i)*( BELVL( i+1) - BELVL( i));
        );
! Tie all intervals for B together;
  ! Can choose at most 1 interval;
      @SUM( POINT( i) | i #LT# @SIZE( POINT):     ZB( i)) <= 1;
  ! Quantity purchased from B; 
      @SUM( POINT( i) | i #LT# @SIZE( POINT):    BIQ( i)) = BTQ;
  ! Total cost of purchases from B; 
      @SUM( POINT( i) | i #LT# @SIZE( POINT): BICOST( i)) = BTCOST;