问题
I'm using DOCPLEX to build up a Mixed Integer Linear Programming (MILP) problem which is then solved via CPLEX on Python. However, upon trying to solve the MILP problem using IF-THEN constraints, I receive the following error:
DOcplexException: Model.if_then(), nbBus40 >= 3.0 is not discrete
This is happening because I have declared nbbus40 variable to be continuous, as shown in the code below:
from docplex.mp.model import Model
mdl = Model(name='buses')
nbbus40 = mdl.continuous_var(name='nbBus40')
nbbus30 = mdl.integer_var(name='nbBus30')
mdl.add_constraint(nbbus40*40 + nbbus30*30 >= 300, 'kids')
mdl.add(mdl.if_then((nbbus40>=3),(nbbus30>=7)))
mdl.minimize(nbbus40*500 + nbbus30*400)
mdl.solve()
for v in mdl.iter_integer_vars():
print(v," = ",v.solution_value)
However, if I keep the nbbus40 variable as an integer, then I get the solution to the MILP problem, as shown below:
from docplex.mp.model import Model
mdl = Model(name='buses')
nbbus40 = mdl.integer_var(name='nbBus40')
nbbus30 = mdl.integer_var(name='nbBus30')
mdl.add_constraint(nbbus40*40 + nbbus30*30 >= 300, 'kids')
mdl.add(mdl.if_then((nbbus40>=3),(nbbus30>=7)))
mdl.minimize(nbbus40*500 + nbbus30*400)
mdl.solve()
for v in mdl.iter_integer_vars():
print(v," = ",v.solution_value)
RESULT:
nbBus40 = 0
nbBus30 = 10.0
How can I use the IF-THEN constraint in DOCPLEX for continuous variables?
回答1:
Copying my answer from here:
You cannot use continuous variables for if-then constraints.
The reason is this: the 'if' clause can take value either true or false. Depending on this, the 'then' clause is activated or not. If nbBus40 is continuous then CPLEX does have to distinguish the cases nbBus40 >= 3 and nbBus40 < 3. Note that the latter is strict inequality! Strict inequality is not supported by the theory of linear programming.
If nbBus40 is instead integer then the cases to distinguish can be written as nbBus40 >= 3 and nbBus40 <= 2. None of these is a strict inequality.
A typical way around this is to use an epsilon and define the two cases nbBus40 >= 3 and nbBus40 <= 3 - eps. That will then be supported as well. However, the eps should depend on the actual expression, so there is no good way to choose a generic eps. That is why docplex leaves that to the user.
You can write your constraints like so:
with Model() as m:
nbBus40 = m.continuous_var()
nbBus30 = m.continuous_var()
helper = m.binary_var()
eps = 1e-3
m.add(m.if_then(helper == 0, nbBus40 <= 3 - eps))
m.add(m.if_then(helper == 1, nbBus40 >= 3))
m.add(m.if_then(helper == 1, nbBus30 >= 7))
m.solve()
Notice however that having these eps is frequently asking for numerical trouble. So if_then on continuous expressions is best avoided. Maybe you can elaborate why you want to consider a fractional number of buses. It could well be that there are other ways to achieve what you want.
来源:https://stackoverflow.com/questions/58853258/how-to-use-continuous-variables-for-if-then-constraints-on-docplex-python