How to use Continuous Variables for IF-THEN constraints on DOCPLEX (Python)?

随声附和 提交于 2021-02-10 14:27:43

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!