如何在DOCPLEX(Python)上为IF-THEN约束使用连续变量



我正在使用DOCPLEX构建一个混合整数线性规划(MILP(问题,然后通过Python上的CPLEX解决该问题。然而,在尝试使用IF-THEN约束来解决MILP问题时,我收到了以下错误:

DOcplexException: Model.if_then(), nbBus40 >= 3.0 is not discrete

之所以发生这种情况,是因为我已将nbbus40变量声明为连续,如下代码所示:

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)

然而,如果我将nbbus40变量保持为整数,则我得到MILP问题的解决方案,如下所示:

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)

结果:

nbBus40  =  0
nbBus30  =  10.0

如何将DOCPLEX中的IF-THEN约束用于连续变量?

从这里复制我的答案:

不能将连续变量用于if-then约束。

原因是:"if"子句可以取true或false值。根据这一点,"then"子句是否被激活。如果nbBus40是连续的,则CPLEX必须区分nbBus40>=3和nbBus40<3.注意,后者是严格不等式!严格不等式没有得到线性规划理论的支持。

如果nbBus40是整数,则要区分的情况可以写成nbBus40>=3和nbBus40<=2.这些都不是严格的不等式。

解决这一问题的典型方法是使用ε并定义两种情况nbBus40>=3和nbBus40<=3-eps。这也将得到支持。然而,eps应该取决于实际表达式,因此没有很好的方法来选择通用eps。这就是docplex将其留给用户的原因。

你可以这样写你的约束:

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()

然而,请注意,拥有这些eps经常会带来数字上的麻烦。因此,最好避免使用连续表达式上的if_then。也许你可以详细说明为什么你想考虑公交车的小数。很可能还有其他方法可以实现你想要的。

最新更新