Scipy linprog添加Upper Bounds后线性优化失效问题求助
首先咱们得理清楚核心问题:你三次调用linprog用的是完全不同的约束集合,所以得到不同的目标函数值是完全正常的,你的误解在于觉得第一个调用应该和第三个结果一致,但两者的约束逻辑差得很远,咱们拆解来看:
三个调用的约束差异
先把你的三个调用的约束条件明确下来:
第一个调用(同时带不等式+等式约束)
res=linprog(c,A_ub=AUB,b_ub=BUB,A_eq=AEQ,b_eq=BEQ,options={"disp":True})要求解必须同时满足:
- 等式约束:
AEQ @ x = BEQ(也就是严格等于[2.9,1.5,0.0,100]这四个值) - 不等式约束:
AUB @ x ≤ BUB(也就是不超过[3.2,1.85,0.5,100]这四个上限)
- 等式约束:
第二个调用(仅原等式约束)
res=linprog(c,A_eq=AEQ,b_eq=BEQ,options={"disp":True})只要求满足
AEQ @ x = BEQ,没有额外的不等式限制,可行域比第一个调用更大。第三个调用(等式约束换成BUB)
res=linprog(c,A_eq=AEQ,b_eq=BUB,options={"disp":True})这里你把等式约束的右端换成了
BUB,也就是要求AEQ @ x = [3.2,1.85,0.5,100]——这是一个完全不同的可行域,和前两个调用的约束没有任何包含关系。
为什么第三个结果最小?
第三个调用的可行域是AEQ @ x = BUB,这个集合里的点刚好更贴合你目标函数c=[0.9,0.25,0.,1.25,4.5,0]的优化方向(比如x3的系数是0,优先让x3取大值来降低其他高系数变量的取值),所以得到了更小的目标值。但这个可行域和第一个调用的可行域是完全分开的——第一个调用要求严格满足AEQ @ x = BEQ,根本碰不到第三个调用的可行域里的点,自然不可能得到相同的结果。
第一个调用可能存在的问题
你说加了Upper Bounds后“失效”,首先要确认第一个调用的约束是否相容(也就是有没有解同时满足所有等式和不等式约束)。可以用可行性检查来验证:
from scipy.optimize import linprog c = [0.9,0.25,0.,1.25,4.5,0] AUB = [[0.99,0.001,0.043,0,0,0.031],[0,0.001,0.01,0.7,0,0.0185], [0,0,0,0,0.99,0.0045],[1,1,1,1,1,1]] AEQ = [[0.99,0.001,0.043,0,0,0.031],[0,0.001,0.001,0.7,0,0.0185], [0,0,0,0,0.99,0.0045],[1,1,1,1,1,1]] BUB = [3.2,1.85,0.5,100] BEQ = [2.9,1.5,0.0,100] # 检查约束是否可行(目标函数设为全0,只找可行解) res_feas = linprog([0]*6, A_ub=AUB, b_ub=BUB, A_eq=AEQ, b_eq=BEQ, options={"disp":True}) print("约束是否可行:", res_feas.success)
如果输出res_feas.success是False,说明你的等式约束和不等式约束存在冲突,根本没有可行解,这时候linprog返回的结果是不可靠的,你需要重新检查约束的定义是否正确(比如是不是把不等式约束的方向搞反了?或者等式约束的右端值写错了?)。
关键结论
- 三个调用的可行域完全不同,所以最优值不同是正常现象;
- 第一个调用的约束是在原等式约束基础上加了限制,可行域更小,不可能达到第三个调用的最优值(因为第三个调用的可行域不在第一个的范围内);
- 先通过可行性检查确认第一个调用的约束是否合理,再根据你的实际优化需求调整约束条件(比如是不是应该把某些等式改成不等式?或者调整右端值?)。
内容的提问来源于stack exchange,提问作者Yalcin

