你要寻找的搜索词是"指示变量"或"big-M约束"。
据我所知,PULP并不直接支持指示变量,因此采用big-M约束是解决问题的方法。
一个简单的例子:
x1 <= 0 IF x2 > 2
,其中<=代表小于等于,>代表大于。
from pulp import *
prob = LpProblem("MILP", LpMaximize)
x1 = LpVariable("x1", lowBound=0, upBound=10, cat = 'Continuous')
x2 = LpVariable("x2", lowBound=0, upBound=10, cat = 'Continuous')
prob += 0.5*x1 + x2, "Objective Function"
b1 = LpVariable("b1", cat='Binary')
M1 = 1e6
prob += b1 >= (x1 - 2)/M1
M2 = 1e3
prob += x2 <= M2*(1 - b1)
status = prob.solve()
print(LpStatus[status])
print(x1.varValue, x2.varValue, b1.varValue, pulp.value(prob.objective))
我们希望当 x2 > 2 时存在限制条件 x1 <= 0。当 x2 <= 2 时,不存在这样的限制条件(x1 可以是正数或负数)。
首先,我们创建一个二进制变量:
b1 = LpVariable("b1", cat='Binary')
选择这个表示条件x2 > 2
的选项。实现这个条件最简单的方法是添加一个约束:
M1 = 1e6
prob += b1 >= (x2 - 2)/M1
这里的
M1
是大M值。需要选择它,以使对于可能的
x2
的最大值,表达式
(x2-2)/M
的值为
<=1
。它应该尽可能小,以避免数值/缩放问题。在这里,一个10的值就足够了(
x2
的上限是10)。
要理解这个约束条件的工作原理,请考虑以下情况:当 x2<=2 时,右侧最多为0,因此没有影响(二进制变量的下限已设置为0)。但是,如果 x2>2,则右侧将强制
b1
大于0,并且作为二进制变量,它将被强制为1。
最后,我们需要构建所需的约束条件:
M2 = 1e3
prob += x1 <= M2*(b1 - 1)
为了更好地理解这个约束条件的工作方式,考虑以下情况:如果b1是true(1
),则该约束条件是活动的并且变为:x1 <= 0
。如果b1是false(0
),则该约束条件变成x1 <= M2
,前提是M2
足够大,这将不会产生任何效果(在这里,它可以小到10,因为x1
已经有一个上界为10)。
在上面的完整代码中,如果您改变目标函数中x1
的系数,您应该会注意到b1被激活/去激活,并且对x1
应用了额外的约束条件,就如预期那样。