数学模型tricks | 大M法线性化注意事项
问题
有如下二次项:
g
x
gx
gx
其中
g
∈
{
0
,
1
}
,
−
10
≤
x
≤
0
g \in \{0,1\},-10 \leq x \leq 0
g∈{0,1},−10≤x≤0
用大M法线性化
令
y
=
g
x
y = gx
y=gx,转化为
y
≥
x
,
y
≥
−
M
g
,
y
≤
x
+
M
(
1
−
g
)
y \geq x,y \geq -Mg,y \leq x + M(1-g)
y≥x,y≥−Mg,y≤x+M(1−g)
即:
g
=
1
g =1
g=1时,
y
=
x
y=x
y=x;
g
=
0
g =0
g=0时,
y
=
0
y=0
y=0
为了检验大M法的效果,用Gurobi求解下面的问题
m
i
n
x
y
≥
x
y
≥
−
M
g
y
≤
x
+
M
(
1
−
g
)
g
∈
{
0
,
1
}
−
10
≤
y
≤
0
−
10
≤
x
≤
0
min \quad x\\ y \geq x\\ y \geq -Mg\\ y \leq x + M(1-g)\\ g \in \{0,1\}\\ -10\leq y \leq 0\\ -10 \leq x \leq 0
minxy≥xy≥−Mgy≤x+M(1−g)g∈{0,1}−10≤y≤0−10≤x≤0
from gurobipy import *
m= Model()
M = GRB.INFINITY
x = m.addVar(lb = -10,ub=0,vtype=GRB.CONTINUOUS,name='miu')
y = m.addVar(lb = -10,ub=0,vtype=GRB.CONTINUOUS,name='xi')
g = m.addVar(vtype=GRB.BINARY,name='g')
m.setObjective(x,GRB.MINIMIZE)
m.addConstr(y >= x)
m.addConstr(y >= -M * g)
m.addConstr(y <= x + M * (1 - g))
m.optimize()
m.write('test.lp')
结果最优解居然是 x = − 10 , g = 1 , y = 0 x=-10,g=1, y=0 x=−10,g=1,y=0,而我们知道 g = 1 g =1 g=1时,肯定满足 y = x y=x y=x
错误根源
找了很久,发现是大M取值的问题,导致了数值计算中出现错误。 大M取GRB.INFINITY太大了。
解决方案:
M = GRB.INFINITY 改为 M = 10e6
结果就正确了
经测试,发现当满足 M ≤ 10 e 16 M\leq 10e16 M≤10e16,结果正确,当 M ≥ 10 e 17 M \geq 10e17 M≥10e17就会出现上面的错误了。
总结
1.综上
在和运筹优化群里大佬的讨论后总结如下:
大M不能太小,若太小则不能保证线性化后不等式的方向,因此无法起到线性化的作用;也不能太大,会导致数值计算上的问题。
大M如果有物理意义,根据物理意义来取值越小越好;否则一般取值上,比参数多一两个数量级就好。
2.大M的用法详细介绍
这个网站对大M的用法介绍比较详细:
https://yalmip.github.io/tutorial/bigmandconvexhulls
3.大M取值太小引发的错误
在另一篇中记录了大M取的太小引起的错误:
[两阶段鲁棒优化 | Biilinear 项的线性化]
(https://blog.csdn.net/m0_46357737/article/details/126117901?spm=1001.2014.3001.5501)
4.Gurobi求解时精度引起的错误
用gurobi求大M法线性化
B
i
n
a
r
y
∗
C
o
n
t
i
n
u
o
u
s
Binary*Continuous
Binary∗Continuous后的模型,发现结果不对。
检查了很久,后来发现加上
m.setParam('IntegralityFocus',1)
之后结果才正确。精度也会有影响。
5.偷懒的解决方法
直接把带 B i n a r y ∗ C o n t i n u o u s Binary*Continuous Binary∗Continuous项的约束扔给Gurobi,他会自动线性化,而且有时候效果比你手动线性化更好。