- SOS2: use SOS2 variables to model the piecewise linear functions. This is an easy modeling exercise.
- BIGM_BIN: use binary variables and big-M constraints to enable and disable constraints. This is a more complex undertaking, especially if we want to use the smallest possible values for the big-M constants. Pyomo has bug in this version.
- BIGM_SOS1: a slight variation of the BIGM_BIN model. Pyomo has the same problem with this model.
Here I show a few more formulations:
Note that part 3 [2] will discuss some newer formulations: LOG and DLOG that only need a logarithmic number of binary variables.
For demonstration purposes we use the same small example with 4 breakpoints and 3 segments.
- DCC: Disaggregated Convex Combination formulation is a simulation of the SOS2 model by binary variables.
- CC: Convex Combination formulation is a similar SOS2 like approach using binary variables only.
- MC: Multiple Choice model uses a semi-continuous approach.
- INCR: Incremental formulation is using all previous segments.
Note that part 3 [2] will discuss some newer formulations: LOG and DLOG that only need a logarithmic number of binary variables.
For demonstration purposes we use the same small example with 4 breakpoints and 3 segments.
Method 4: DCC - Disaggregated Convex Combination Model
This is an impressive name for a model that is actually not very complicated.
DCC - Disaggregated Convex Combination Formulation |
---|
x=∑s,k|SK(s,k)ˉxkλs,ky=∑s,k|SK(s,k)ˉykλs,kδs=∑k|SK(s,k)λs,k∑sδs=1λs,k≥0δs∈{0,1} |
Here the mapping set SK(s,k) is TRUE for the two breakpoints k belonging to segment s.
We can also write the model more directly, without the mapping SK(s,k):
DCC - Disaggregated Convex Combination Formulation 2 |
---|
x=∑s(ˉxsλs,s+ˉxs+1λs,s+1)y=∑s(ˉysλs,s+ˉys+1λs,s+1)δs=λs,s+λs,s+1∑sδs=1λs,k≥0δs∈{0,1} |
Here is the GAMS version:
set
k 'breakpoints' /point1*point4/ s 'segments' /segment1*segment3/ sk(s,k) 'mapping' ; sk(s,k) = ord(s)=ord(k) or ord(s)=ord(k)-1; display sk; table data(k,*) x y point1 1 6 point2 3 2 point3 6 8 point4 10 7 ; positive variable lambda(s,k) 'interpolation'; binary variable delta(s) 'select segment'; variable x,y; equations xdef 'x' ydef 'y' link(s) 'link delta-lambda' sumdelta 'select segment' ; xdef.. x =e= sum(sk(s,k), lambda(s,k)*data(k,'x')); ydef.. y =e= sum(sk(s,k), lambda(s,k)*data(k,'y')); link(s).. delta(s) =e= sum(sk(s,k),lambda(s,k)); sumdelta.. sum(s, delta(s)) =e= 1; x.fx = 5; model m /all/; option optcr=0; solve m maximizing y using mip; display x.l,y.l,delta.l,lambda.l; |
In this model I made a strong distinction between segments s and breakpoints k. This will help the GAMS model to perform domain checking (type checking), so we get a bit better protection against errors in the model. Of course, if you prefer you just can indicate segments by 1,…,K−1.
Note that the linking constraints link, perform two functions. First: they make sure that for unselected segments (with δs=0), we have λs,k=0. Second, for the selected segment, we automatically sum the λ's to 1.
The output of the model looks like:
---- 13 SET sk mapping point1 point2 point3 point4 segment1 YES YES segment2 YES YES segment3 YES YES ---- 45 VARIABLE x.L = 5.000 VARIABLE y.L = 6.000 ---- 45 VARIABLE delta.L segment2 1.000 ---- 45 VARIABLE lambda.L point2 point3 segment2 0.333 0.667
The display of the set SK confirms we setup the topography correctly: segment k uses points k,k+1.
We fixed x=5 which yields y=6. We see δ2=1 so the second segment is selected, and this is also visible from the variables λs,k indicating we interpolate between points 2 and 3.
We can have a look at the generated equations:
---- xdef =E= xdef.. - lambda(segment1,point1) - 3*lambda(segment1,point2) - 3*lambda(segment2,point2) - 6*lambda(segment2,point3) - 6*lambda(segment3,point3) - 10*lambda(segment3,point4) + x =E= 0 ; (LHS = 5, INFES = 5 ****) ---- ydef =E= ydef.. - 6*lambda(segment1,point1) - 2*lambda(segment1,point2) - 2*lambda(segment2,point2) - 8*lambda(segment2,point3) - 8*lambda(segment3,point3) - 7*lambda(segment3,point4) + y =E= 0 ; (LHS = 0) ---- link =E= link(segment1).. - lambda(segment1,point1) - lambda(segment1,point2) + delta(segment1) =E= 0 ; (LHS = 0) link(segment2).. - lambda(segment2,point2) - lambda(segment2,point3) + delta(segment2) =E= 0 ; (LHS = 0) link(segment3).. - lambda(segment3,point3) - lambda(segment3,point4) + delta(segment3) =E= 0 ; (LHS = 0) ---- sumdelta =E= sumdelta.. delta(segment1) + delta(segment2) + delta(segment3) =E= 1 ; (LHS = 0, INFES = 1 ****)
In a sense we simulated the SOS2 model using binary variables. More visible here is the two-step approach:
- Select the segment s using the binary variables δs.
- Interpolate between the breakpoints of this segment using the positive variables λs,k.
Of course in a MIP model we have simultaneous equations, so these things happen actually at the same time. The 2-step paradigm is more of a useful mental model.
For completeness, here is the GAMS model without set SK(s,k):
For completeness, here is the GAMS model without set SK(s,k):
* DCC2: Disaggregated Convex Combination formulation 2
* without mapping SK(s,k) set k 'breakpoints' /point1*point4/ s(k) 'segments' /point1*point3/ ; table data(k,*) x y point1 1 6 point2 3 2 point3 6 8 point4 10 7 ; positive variable lambda(s,k) 'interpolation'; binary variable delta(s) 'select segment'; variable x,y; equations xdef 'x' ydef 'y' link(s) 'link delta-lambda' sumdelta 'select segment' ; xdef.. x =e= sum(s(k), lambda(s,k)*data(k,'x')+lambda(s,k+1)*data(k+1,'x')); ydef.. y =e= sum(s(k), lambda(s,k)*data(k,'y')+lambda(s,k+1)*data(k+1,'y')); link(s(k)).. delta(s) =e= lambda(s,k)+lambda(s,k+1); sumdelta.. sum(s, delta(s)) =e= 1; x.fx = 5; model m /all/; option optcr=0; solve m maximizing y using mip; display x.l,y.l,delta.l,lambda.l; |
Method 5: CC - Convex Combination Model
This formulation is very similar to the previous one. The main difference is the structure of the λ variables. We index them by k only. This is more like the SOS2 model. The manner in which we link λk to δs becomes somewhat different. Instead of an equality we use an inequality λk≤∑s|SK(s,k)δs This make sure that only for a selected segment with δs=1, the corresponding λk's can be nonzero. We need to add explicitly that ∑kλk=1 as this is no longer implied by the linking constraints. The model looks like:
CC - Convex Combination Formulation |
---|
x=∑kˉxkλky=∑kˉykλk∑kλk=1λk≤∑s|SK(s,k)δs∑sδs=1λk≥0δs∈{0,1} |
This model has fewer continuous variables than the DCC model. The GAMS version looks like:
set
k 'breakpoints' /point1*point4/ s 'segments' /segment1*segment3/ sk(s,k) 'mapping' ; sk(s,k) = ord(s)=ord(k) or ord(s)=ord(k)-1; display sk; table data(k,*) x y point1 1 6 point2 3 2 point3 6 8 point4 10 7 ; positive variable lambda(k) 'interpolation'; binary variable delta(s) 'select segment'; variable x,y; equations xdef 'x' ydef 'y' link(k) 'link delta-lambda' sumlambda 'interpolation' sumdelta 'select segment' ; xdef.. x =e= sum(k, lambda(k)*data(k,'x')); ydef.. y =e= sum(k, lambda(k)*data(k,'y')); link(k).. lambda(k) =l= sum(sk(s,k),delta(s)); sumlambda.. sum(k, lambda(k)) =e= 1; sumdelta.. sum(s, delta(s)) =e= 1; x.fx = 5; model m /all/; option optcr=0; solve m maximizing y using mip; display x.l,y.l,delta.l,lambda.l; |
The output (including the generated equations) is:
Generated equations
---- xdef =E= x xdef.. - lambda(point1) - 3*lambda(point2) - 6*lambda(point3) - 10*lambda(point4) + x =E= 0 ; (LHS = 5, INFES = 5 ****) ---- ydef =E= y ydef.. - 6*lambda(point1) - 2*lambda(point2) - 8*lambda(point3) - 7*lambda(point4) + y =E= 0 ; (LHS = 0) ---- link =L= link delta-lambda link(point1).. lambda(point1) - delta(segment1) =L= 0 ; (LHS = 0) link(point2).. lambda(point2) - delta(segment1) - delta(segment2) =L= 0 ; (LHS = 0) link(point3).. lambda(point3) - delta(segment2) - delta(segment3) =L= 0 ; (LHS = 0) link(point4).. lambda(point4) - delta(segment3) =L= 0 ; (LHS = 0)
Solution
---- sumlambda =E= interpolation sumlambda.. lambda(point1) + lambda(point2) + lambda(point3) + lambda(point4) =E= 1 ; (LHS = 0, INFES = 1 ****) ---- sumdelta =E= select segment sumdelta.. delta(segment1) + delta(segment2) + delta(segment3) =E= 1 ; (LHS = 0, INFES = 1 ****) ---- 49 VARIABLE x.L = 5.000 VARIABLE y.L = 6.000 ---- 49 VARIABLE delta.L select segment segment2 1.000 ---- 49 VARIABLE lambda.L interpolation point2 0.333, point3 0.667
The methods DCC and CC simulate our SOS2 model from [1] using binary variables. This means the model can handle step functions (we don't need to form a slope). The models are not too difficult to setup, as is illustrated by the GAMS models implementing them.
An early reference to this method is [4].
Method 6: MC - Multiple Choice formulation
This is a well-known method. We assume we can calculate slopes and intercepts for each segment. I.e. we have y=as+bsx if ˉxs≤x≤ˉxs+1 with as=ˉys+1−ˉysˉxs+1−ˉxsbs=ˉys−asˉxs
For the model we introduce binary variables δs to indicate which segment is selected, and so-called semi-continuous variables vs∈0∪[ˉxs,ˉxs+1]. The variable vs can be modeled as ˉxsδs≤vs≤ˉxs+1δs
With this we can formulate the complete model:
MC - Multiple Choice Formulation |
---|
x=∑svsy=∑s(asvs+bsδs)ˉxsδs≤vs≤ˉxs+1δs∑sδs=1δs∈{0,1}as=ˉys+1−ˉysˉxs+1−ˉxsbs=ˉys−asˉxs |
- The sandwich equation ˉxsδs≤vs≤ˉxs+1δs must likely be implemented as two inequalities.
- This construct says: vs=0 or vs∈[ˉxs,ˉxs+1]. vs is sometimes called semi-continuous.
- The variables δs and vs are connected: δs=0⇒vs=0δs=1⇒vs=x I.e. they operate in parallel.
- I have seen cases where this model outperformed the SOS2 formulation.
The GAMS model is simple:
set
k 'breakpoints' /k1*k4/ s(k) 'segments' /k1*k3/ ; table data(k,*) x y k1 1 6 k2 3 2 k3 6 8 k4 10 7 ; data(s(k),'dx') = data(k+1,'x')-data(k,'x'); data(s(k),'dy') = data(k+1,'y')-data(k,'y'); data(s(k),'slope') = data(k,'dy')/data(k,'dx'); data(s(k),'intercept') = data(k,'y')-data(k,'slope')*data(k,'x'); display data; variable v(s) 'equal to x or 0'; binary variable delta(s) 'select segment'; variable x,y; equations xdef 'x' ydef 'y' semicont1(k) semicont2(k) sumdelta 'select segment' ; xdef.. x =e= sum(s, v(s)); ydef.. y =e= sum(s, data(s,'slope')*v(s)+data(s,'intercept')*delta(s)); semicont1(s(k)).. v(s) =l= data(k+1,'x')*delta(s); semicont2(s).. v(s) =g= data(s,'y')*delta(s); sumdelta.. sum(s, delta(s)) =e= 1; x.fx = 5; model m /all/; option optcr=0; solve m maximizing y using mip; display data,x.l,y.l,delta.l,v.l; |
The results look like:
---- 43 PARAMETER data x y dx dy slope intercept k1 1.000 6.000 2.000 -4.000 -2.000 8.000 k2 3.000 2.000 3.000 6.000 2.000 -4.000 k3 6.000 8.000 4.000 -1.000 -0.250 9.500 k4 10.000 7.000 ---- 43 VARIABLE x.L = 5.000 VARIABLE y.L = 6.000 ---- 43 VARIABLE delta.L select segment k2 1.000 ---- 43 VARIABLE v.L equal to x or 0 k2 5.000
Segment 2 is selected. We can see that directly from the binary variable δs, but also from the semi-continuous variable vs.
Method 7: INC - Incremental Formulation
In the incremental or delta method we add up all contributions of "earlier" segments, to find our x and y.
Let s′ be the segment that contains our current x. We define a binary variable δs as δs={1for s<s′0for s≥s′ In addition we use a continuous variable λs∈[0,1] indicating how much of each segment we "use up". The contribution for earlier segments is 1 and for the current segment we have a fractional value. So we have: {λs=1for s<s′λs∈[0,1]for s=s′λs=0for s>s′ With these definitions we can write: x=ˉx1+∑sλs(ˉxs+1−ˉxs)y=ˉy1+∑sλs(ˉys+1−ˉys)
Now we need to formulate a structure that enforce these rules on δ and λ. The following will do that: λs+1≤δs≤λs Typically you will need to implement this as two separate constraints.
The complete model looks like:
INC - Incremental Formulation |
---|
x=ˉx1+∑sλs(ˉxs+1−ˉxs)y=ˉy1+∑sλs(ˉys+1−ˉys)λs+1≤δs≤λsδs∈{0,1}λs∈[0,1] |
We can see that we can fix the last δs=0. The model will behave correctly without this, but we may help the presolver a bit with this.
The GAMS model can look like:
set
k 'breakpoints' /k1*k4/ s(k) 'segments' /k1*k3/ ; table data(k,*) x y k1 1 6 k2 3 2 k3 6 8 k4 10 7 ; positive variable lambda(s) 'contribution factor of segment'; lambda.up(s) = 1; binary variable delta(s) 'previously contributing segments'; variable x,y; equations xdef 'x' ydef 'y' link1(s) 'links lambda delta' link2(s) 'links lambda delta' ; * fix last delta(s) to 0. * this is not strictly needed delta.fx(s)$(ord(s)=card(s)) = 0; xdef.. x =e= data('k1','x')+ sum(s(k), lambda(s)*(data(k+1,'x')-data(k,'x'))); ydef.. y =e= data('k1','y')+ sum(s(k), lambda(s)*(data(k+1,'y')-data(k,'y'))); link1(s).. lambda(s+1) =l= delta(s); link2(s).. delta(s) =l= lambda(s); x.fx = 5; model m /all/; option optcr=0; solve m maximizing y using mip; display x.l,y.l,delta.l,lambda.l; |
Note that in equation link1, we go one position too far when addressing λs+1 for the last s. GAMS will make that reference zero, and that is correct for this case. We see in the equation listing:
---- link1 =L= links lambda delta link1(k1).. lambda(k2) - delta(k1) =L= 0 ; (LHS = 0) link1(k2).. lambda(k3) - delta(k2) =L= 0 ; (LHS = 0) link1(k3).. - delta(k3) =L= 0 ; (LHS = 0)
The solution is
---- 36 VARIABLE x.L = 5.000 VARIABLE y.L = 6.000 ---- 36 VARIABLE delta.L previously contributing segments k1 1.000 ---- 36 VARIABLE lambda.L contribution factor of segment k1 1.000, k2 0.667
Notes:
- A slightly different formulation is the following. Use the definition: δs={1for s≤s′0for s>s′ Now we use the sandwich equation: δs+1≤λs≤δs With this formulation we can fix: δ1=1.
- This approach goes back to [5].
References
- Piecewise linear functions and formulations for interpolation (part 1). This post discusses formulations SOS2, BIGM_BIN and BIGM_SOS1. The SOS2 formulation is the most important. Also illustrated how a Pyomo implementation is not implementing BIGM_BIN and BIGM_SOS1 correctly. http://yetanothermathprogrammingconsultant.blogspot.com/2019/02/piecewise-linear-functions-and.html
- Piecewise linear functions and formulations for interpolation (part 3). This post describes the LOG and DLOG formulations, which have a logarithmic number of binary variables. We see also some issues with the Pyomo implementation. http://yetanothermathprogrammingconsultant.blogspot.com/2019/03/piecewise-linear-functions-and.html
- Keely L. Croxton, Bernard Gendron, Thomas L. Magnanti, A Comparison of Mixed-Integer Programming Models for Non-Convex Piecewise Linear Cost Minimization Problems, Management Science, Volume 49, Issue 9, 2003, pages 1121-1273
- G. Dantzig, On the significance of solving linear programming problems with some integer variables, Econometrica 28, 30-44, 1960
- H. Markowitz, A. Manne, On the solution of discrete programming problems, Econometrica 25, 84-110, 1957