|
So-called Big M formulations often exhibit trickle flow, and at times, they behave unstably. The main purpose of indicator constraints is to avoid the unwanted side-effects of Big M formulations. Generally, the use of indicator constraints is not warranted when the unwanted side-effects of Big M formulations are not present.
For example, instead of the following Big M formulation, which relies on the x values summing to less than one billion (a formulation that can cause numeric instability or undesirable solutions in some situations):
constr01.. x1 + x2 + x3 =l= 1e+9*y; // may cause problemsa natural way of entering an indicator constraint, where y is a binary variable, would look like this:
constr01$(y=0).. x1 + x2 + x3 =e= 0; // alternativeSince indicators are currently supported by CPLEX only, we have delayed the necessary chance of the GAMS syntax to allow for endogenous varibles in the $-condition. We still want to give GAMS/CPLEX user's access to this new feature, therefore the mapping between constraints and binary variables is described in a Cplex option file cplex.opt. The example from above would be implemented in the following way:
constr01.. x1 + x2 + x3 =e= 0;plus additional information in the Cplex option file cplex.opt:
indic constr01$y 0This has the following effect: Equation constr01 will become an indicator constraint and becomes effective in a solution where the binary variable takes the value 0. If the value of y in a solution is 1, the constraint is not active.
Note, that this way of entering an indicator constraint is dangerous since the option files changes the model (usually an option file has some effect on the performance of the algorithm). Therefore, GAMS/CPLEX will abort if there is a problem processing the indicator options in the Cplex option file. Moreover, if the model is given to a different solver or to CPLEX without the option file containt the indicator mapping, a very different model is solved. The current experimental implementation of indicator constraints requires a significant amount of caution from the user.
There are two ways of entering the equation/binary variable mapping in a Cplex option file: (1) using an indexed format, (2) using labels.
The indexed format is a convenient short hand notation which borrows its syntax from the GAMS syntax. It requires that the indices for the binary variable are already present in the index set of the equation. For example, the following invalid GAMS syntax with an endogenous variable in the $-condition
equ1(i,j,k)$(ord(i)<ord(j) and bin1(i,k)=1).. lhs =l= rhs;would be specified like this in the GAMS file
equ1(i,j,k)$(ord(i)<ord(j)).. lhs =l= rhs;plus the Cplex option file
indic equ1(i,j,k)$bin1(i,k) 1In cases where the binary variable indices are not present in the equation indices (or is adjusted using lags or leads), one needs to specify the mapping of all individual equations and variables of the indicator constraints. For example,
set i /i1*i3/, j /j1*j2/; binary variable bin1(j); equation equ1(i,j); equ1(i,j)$(bin1(j++1)=0) lhs =e= 0;This would be specified using the label format of indicator constraint as follows. The GAMS file
equ1(i,j).. lhs =e= 0;plus the Cplex option file
indic equ1('i1','j1')$bin1('j2') 0
indic equ1('i1','j2')$bin1('j1') 0
indic equ1('i2','j1')$bin1('j2') 0
indic equ1('i2','j2')$bin1('j1') 0
indic equ1('i3','j1')$bin1('j2') 0
indic equ1('i3','j2')$bin1('j1') 0
Finally, we want to present a fixed-charge network example based on
the TRNSPORT model from the
GAMS Model library that used indicator
constraints, big M forumulations and a forumulation that makes it easy
to switch between these two.
$Title Fixed Charge Transportation Problem with Indicator Constraints
Sets
i canning plants / seattle, san-diego /
j markets / new-york, chicago, topeka / ;
Parameters
a(i) capacity of plant i in cases
/ seattle 350
san-diego 600 /
b(j) demand at market j in cases
/ new-york 325
chicago 300
topeka 275 / ;
Table d(i,j) distance in thousands of miles
new-york chicago topeka
seattle 2.5 1.7 1.8
san-diego 2.5 1.8 1.4 ;
Scalar f freight in dollars per case per thousand miles /90/ ;
Parameter c(i,j) transport cost in thousands of dollars per case ;
c(i,j) = f * d(i,j) / 1000 ;
Parameter fixcost(i,j) fixed cost in thousands of dollars ;
fixcost(i,j) = 10*d(i,j) / 1000 ;
Scalar minshipping minimum shipping of cases /100/;
Scalar bigM sufficiently large number; bigM = smax(i, a(i));
Variables
x(i,j) shipment quantities in cases
use(i,j) is 1 if arc is used in solution
z total transportation costs in thousands of dollars ;
Positive Variable x ; Binary Variable use;
Equations
cost define objective function
supply(i) observe supply limit at plant i
demand(j) satisfy demand at market j
minship(i,j) ensure minimum shipping
maxship(i,j) ensure zero shipping if use variable is 0;
cost .. z =e= sum((i,j), c(i,j)*x(i,j) + fixcost(i,j)*use(i,j)) ;
supply(i) .. sum(j, x(i,j)) =l= a(i) ;
demand(j) .. sum(i, x(i,j)) =g= b(j) ;
minship(i,j).. x(i,j) =g= minshipping*use(i,j);
maxship(i,j).. x(i,j) =l= bigM*use(i,j);
Option limrow=0, limcol=0, optcr=0, mip=cplex;
Model bigMModel /all/ ;
Solve bigMModel using mip minimizing z ;
* Now let's build a model for the same problem using indicator constraints
Equations
iminship(i,j) ensure minimum shipping using indicator constraints
imaxship(i,j) ensure zero shipping if use variable is 0 using indicator constraints;
iminship(i,j).. x(i,j) =g= minshipping;
imaxship(i,j).. x(i,j) =e= 0;
Model indicatorModel /cost, supply, demand, iminship, imaxship/ ;
file fcpx Cplex Option file / cplex.opt /;
putclose fcpx 'indic iminship(i,j)$use(i,j) 1' / 'indic imaxship(i,j)$use(i,j) 0';
indicatorModel.optfile = 1; Solve indicatorModel using mip minimizing z ;
* Let's do the same using indicator option with labels
loop((i,j),
put fcpx 'indic ' iminship.tn(i,j) '$' use.tn(i,j) yes
/ 'indic ' imaxship.tn(i,j) '$' use.tn(i,j) no / );
putclose fcpx;
Solve indicatorModel using mip minimizing z ;
* Now let's build a model for the same problem that can be used with
* and without indicator constraints. This can become handy when
* debugging a model with indicator constraints
Positive Variable minslack(i,j), maxslack(i,j);
Equations
xminship(i,j) ensure minimum shipping using indicator constraints and bigM
xmaxship(i,j) ensure zero shipping ig use variable is 0 using indicator constraints and bigM
bndminslack(i,j) ensure minslack is zero if use variable is 1
bndmaxslack(i,j) ensure maxslack is zero if use variable is 0;
xminship(i,j).. x(i,j) =g= minshipping - minslack(i,j);
xmaxship(i,j).. x(i,j) =e= 0 + maxslack(i,j);
bndminslack(i,j).. minslack(i,j) =l= bigM*(1-use(i,j));
bndmaxslack(i,j).. maxslack(i,j) =l= bigM*use(i,j);
Model indicatorbigMModel /cost, supply, demand, xminship, xmaxship, bndminslack, bndmaxslack/ ;
* Let's first solve this without use of indicators
indicatorbigMModel.optfile = 0; Solve indicatorbigMModel using mip minimizing z ;
* Now we will use indicators and therefore we don't need the slacks
putclose fcpx 'indic xminship(i,j)$use(i,j) 1' / 'indic xmaxship(i,j)$use(i,j) 0';
minslack.fx(i,j) = 0; maxslack.fx(i,j) = 0;
indicatorbigMModel.optfile = 1; Solve indicatorbigMModel using mip minimizing z ;
* We can also mix and match bigM with indicator constraints
putclose fcpx 'indic xminship(i,j)$use(i,j) 1';
minslack.fx(i,j) = 0; maxslack.up(i,j) = inf;
indicatorbigMModel.optfile = 1; Solve indicatorbigMModel using mip minimizing z ;