Как использовать непрерывные переменные для ограничений IF-THEN в DOCPLEX (Python)?

Я использую DOCPLEX для создания проблемы смешанного целочисленного линейного программирования (MILP), которая затем решается с помощью CPLEX на Python. Однако при попытке решить проблему MILP с использованием ограничений IF-THEN я получаю следующую ошибку:

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

Как я могу использовать ограничение IF-THEN в DOCPLEX для непрерывных переменных?


person Muhammad Ali    schedule 14.11.2019    source источник


Ответы (1)


Копирование моего ответа из здесь:

Вы не можете использовать непрерывные переменные для ограничений «если-то».

Причина в следующем: предложение 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 в непрерывных выражениях. Может быть, вы объясните, почему вы хотите учитывать дробное количество автобусов. Вполне возможно, что есть другие способы добиться того, чего вы хотите.

person Daniel Junglas    schedule 14.11.2019