Reputation: 113
How can we reify a constraint (and enforce it) in linear programming:
delta == 1 ==> a*x <= b
delta == 1 ==> a*x >= b
delta == 1 ==> a*x == b
where delta
is a boolean variable
I am aware that through commercial solvers like gurobi, cplex we have already a built in capability of indicator constraints, but while using an open source linear solver how can we express constraint reification.
Upvotes: 2
Views: 260
Reputation: 17526
With the python library PuLP
which ships bundling the open source Coin-OR suite we can realize it as a big-M constraint:
import pulp
problem = pulp.LpProblem("BigMConstraintProblem", pulp.LpMinimize)
a = 2
b = 5
M = 100 # Big M value
x = pulp.LpVariable("x", lowBound=0, cat='Continuous')
delta = pulp.LpVariable("delta", lowBound=0, upBound=1, cat='Binary')
problem += a * x
# Add the Big M constraint
problem += a * x <= b + (1 - delta) * M
problem.solve()
PuLP
ships with both a linear and integer solver.
To install PuLP
:
python -m pip install pulp
Upvotes: 0
Reputation: 16782
(1) Using big-M constraints. E.g. for the first:
a*x <= b + (1-δ)M
where M is a large enough constant. This needs to be chosen with some care: the smaller, the better (but it should be large enough to make the constraint non-binding when δ=0).
(2) Using SOS1 variables. This does not require a big-M constant. Not all open-source solvers/modeling tools support SOS1 variables.
(3) Using indicator constraints. Again no big-M constants are needed. Often not available in open-source solvers and modeling tools. It would be good if there is more support for this as it is a very useful modeling concept.
Upvotes: 1
Reputation: 1029
Would advise you to read Model building in Mathematical programming by HP Williams
, especially chapter 9
I have used Google-ortool's linear solver (python API) to express your indicator constraints. You can install ortools
via pip install ortools
. Solvers such cbc, SCIP, etc gets shipped with ortools
from ortools.linear_solver import pywraplp
# CASE 1 :
# delta == 1 ==> a*x <= b
# concrete example :
# delta == 1 ==> 3x + 2y <= 8
solver = pywraplp.Solver("", pywraplp.Solver.SCIP_MIXED_INTEGER_PROGRAMMING)
delta = solver.BoolVar("")
x = solver.IntVar(0, 10, name= "")
y = solver.IntVar(0, 10, name= "")
big_M = 8 # upper bound for the expression a*x - b
# a*x - b <= big_M * (1 - delta)
solver.Add(3*x + 2*y - 8 <= big_M * (1-delta))
# check : fix delta == 1
delta.SetBounds(lb = 1, ub = 1)
solver.Maximize(3*x + 2*y)
sol = solver.Solve()
solver.Objective().Value() # results in 8
x.SolutionValue() # x = 2
y.SolutionValue() # y = 1
delta.SolutionValue() # delta = 1
# CASE 2 :
# delta == 1 ==> a*x <= b
# concrete example :
# delta == 1 => 3*x + 2*y >= 8
solver = pywraplp.Solver("", pywraplp.Solver.SCIP_MIXED_INTEGER_PROGRAMMING)
delta = solver.BoolVar("")
x = solver.IntVar(0, 10, name= "")
y = solver.IntVar(0, 10, name= "")
small_M = -8 # lower bound for the expression a*x - b
# a*x >= small_M * (1 - delta) + b
solver.Add(3*x + 2*y >= -small_M * (1 - delta) + 8)
# check : fix delta == 1
delta.SetBounds(lb = 1, ub = 1)
solver.Minimize(3*x + 2*y)
sol = solver.Solve()
solver.Objective().Value() # results in 8
x.SolutionValue() # x = 0
y.SolutionValue() # y = 4
delta.SolutionValue() # delta = 1
# CASE 3 :
# delta == 1 ==> a*x <= b
# concrete example :
# delta == 1 => 3*x + 2*y == 13
solver = pywraplp.Solver("", pywraplp.Solver.SCIP_MIXED_INTEGER_PROGRAMMING)
delta = solver.BoolVar("")
x = solver.IntVar(0, 10, name= "")
y = solver.IntVar(0, 10, name= "")
big_M = 13 # upper bound for the expression a*x - b
small_M = -13 # lower bound for the expression a*x - b
# a*x - b <= big_M * (1 - delta)
# a*x >= small_M * (1 - delta) + b
solver.Add(3*x + 2*y - 13 <= big_M * (1-delta))
solver.Add(3*x + 2*y >= -small_M * (1 - delta) + 8)
# check : fix delta == 1
delta.SetBounds(lb = 1, ub = 1)
solver.Maximize(3*x + 2*y)
sol = solver.Solve()
solver.Objective().Value() # results in 8
x.SolutionValue() # x = 0
y.SolutionValue() # y = 4
delta.SolutionValue() # delta = 1
Upvotes: 2