Lindo Systems
! Multi-period inventory planning with a (PieceLinMultPer.lng)
piecewise linear, quantity discount purchasing cost;
! Keywords: Linearization, Multi-period, Non-convex function,
Piecewise linear, Purchasing, Quantity discount, SOS2;
SETS:
period: PDem, PCost, PInv, PUnitsB;
BrkPnt: Vol, TotC;
PxB( Period, BrkPnt): WP, VolP, CostP;
ENDSETS
DATA:
! We can buy in any of these periods;
Period = 1..12;
! We need this much each period to satisfy demand;
PDem = 90 95 74 98 93 78 98 90 92 83 93 82;
! Holding cost per unit per period;
HC = .20;
! Here are the break points for a purchasing curve where,
! we pay $50 if we buy anything in the period.
$2/unit if < 100,
$1.90/unit if >= 100 but < 1000,
$1.80/unit if <=1000 but <= 5000.;
BrkPnt = 1..7;
Vol TotC =
0 0
1 52
99 248
100 240
999 1948.1
1000 1850
5000 9050 ;
ENDDATA
! The optimization model;
! Minimize the purchase and inventory cost over all periods;
MIN = @SUM( Period( i): PCost( i) + HC* PInv( i));
! (Ending) inventory balance constraints.
Ending inventory = previous + purchased - demand.
Period 1;
PInv(1) = PUnitsB(1) - PDem( 1);
! Periods after 1st;
@FOR( period(i)| i #gt# 1:
PInv(i) = PInv(i-1) + PUnitsB(i) - PDem( i);
);
! For each Period i,
Calculate cost of goods purchased based on break point curve.
You can choose any point on the cost curve by applying weights
to the two adjacent break points. Weights must sum to 1;
@FOR( Period(i):
! Calculate weighted volume;
[WVOL] PUnitsB( i)= @SUM( PxB( i, p): Vol( p) * WP( i, p));
! Calculate weighted cost;
[WCOST] PCost( i) = @SUM( PxB( i, p): TotC( p)* WP( i, p));
! Weights must sum to 1 for each supplier i;
[SUM21] 1 = @SUM( PxB( i, p): WP( i, p));
! Weights must satisfy SOS2 (Special Ordered Set) 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( PxB( i, p): @SOS2( 'SOS2'+Period(i), WP( i, p)));
);