不论用什么求解器,数学规划模型中一般不支持直接输入 if ... else 条件,也就是说在编写模型代码时,if..else 条件判断中不能含有模型变量。遇到有变量需要做 if 判断的时候,需要做线性化处理。
线性化的方法很多,既可以通过引入中间变量(辅助变量)的方式实现,一般就是加上大M和一个01变量来实现,也可以直接调用 Gurobi 的 Indicator 约束实现。gurobi原厂也提供了一个示范案例,可以参考 https://support.gurobi.com/hc/en-us/articles/4414392016529-How-do-I-model-conditional-statements-in-Gurobi-
一、举例:
原问题:
如果 x>y则z=w1;否则 z=w2;
(1)首先,考虑引入0和1变量b:
目的是为了实现:当b = 1 时,x ≥ y
(2) 引入大M实现第一步的公式:
约束(1)
约束(2)
同理接下来继续实现:
约束(3)
约束(4)
转为:
最判断转为:
groubi的可以通过指标约束(indicator constraints)实现约束(3)和约束(4):
变量及其上下限:
x,y,z,w1,w2 均为实数,其中
x、y∈[0,5],z,w1,w2无上下限约束
约束为上述的约束(1)~ 约束(4)
二、Gurobi Indicator 用法
Gurobi Indicator 约束用来表达 z = f >> ax<=b 这样的逻辑条件。其中
(1)z 需要是 0/1 变量, f 是 0/1 (True/False)数值, >> 左边 不能是其他表达式
(2)>> 右边需要是线性表达式,不能是二次或者广义约束表达式。如果是二次或者广义表达式,可以引入中间变量=二次或者广义表达式放在约束中,然后用中间变量替换,使得 >> 右边是线性表达式。
约束和变量在gurobi中的构建代码:
import gurobipy as gp
from gurobipy import GRB # 创建一个新模型
m = gp.Model( "test" ) # 创建变量
x = m.addVar(ub= 10 , vtype=GRB.CONTINUOUS, name= "x" )
y = m.addVar(ub= 5 , vtype=GRB.CONTINUOUS, name= "y" )
z = m.addVar(vtype=GRB.CONTINUOUS, name= "z" )
w1 = m.addVar(vtype=GRB.CONTINUOUS, name= "w1" )
w2 = m.addVar(vtype=GRB.CONTINUOUS, name= "w2" )
b = m.addVar(vtype=GRB.BINARY, name= "b")
# 常量
eps = 0.0001
M = 10 + eps # x 和 y 上可能给定的最小边界
# 建模如果 x > y,则 b = 1,否则 b = 0
m.addConstr(x >= y + eps - M * ( 1 - b), name= "bigM_constr1" )
m.addConstr(x <= y + M * b, name= "bigM_constr2" ) # 添加指标约束
m.addConstr((b == 1 ) >> (z == w1 ), name= "indicator_constr1" )
m.addConstr((b == 0 ) >> (z == w2), name= "indicator_constr2" )
# 请继续构建模型的其余部分# ..