Python Xpress优化器使用where类非线性函数报无效约束的解决方法
问题解答
1. 直接使用的可行性结论
numpy.where 这类Numpy提供的面向数值运算的条件/非线性函数,不能在Xpress求解器的建模流程中直接使用。
原因很简单:Xpress建模阶段操作的是符号化的变量、表达式对象,最终要传给求解器的是结构化的约束矩阵;而numpy.where是针对普通数值数组设计的执行即时判断的函数,处理Xpress的符号对象时无法生成求解器可识别的约束结构,必然触发Invalid constraint(无效约束)报错。
2. 等价替代实现方法
numpy.where(condition, res_true, res_false)的本质是二分段条件取值逻辑,完全可以通过Xpress原生支持的二进制辅助变量+大M法实现等价建模,不需要依赖Numpy函数。
以最常见的numpy.where(expr >= 0, val1, val2)逻辑为例(即表达式expr大于等于0时返回val1,否则返回val2),实现步骤如下:
- 第一步:定义1个0-1二进制辅助变量
delta,约定delta=1代表条件成立,delta=0代表条件不成立 - 第二步:根据模型中表达式的数值范围,选取一个足够大的常数
M(注意M只要大于expr可能取到的最大绝对值即可,不要盲目取1e12这类过大的值,避免引发数值精度问题) - 第三步:添加约束完成逻辑的等价绑定,参考代码如下:
import xpress as xp # 初始化模型、定义原有决策变量和expr表达式的代码省略 delta = xp.var(vartype=xp.binary) z = xp.var() # z用来存储where逻辑的返回值 prob.addVariable(delta, z) M = 10000 # 按实际模型数值范围调整 # delta=1时强制expr >= 0 prob.addConstraint(expr >= -M * (1 - delta)) # delta=0时强制expr < 0,1e-6为浮点精度容忍值 prob.addConstraint(expr <= M * delta - 1e-6) # 绑定z的取值:delta=1时z=val1,delta=0时z=val2 prob.addConstraint(z >= val1 - M*(1-delta)) prob.addConstraint(z <= val1 + M*(1-delta)) prob.addConstraint(z >= val2 - M*delta) prob.addConstraint(z <= val2 + M*delta)
如果是多分支的条件判断,只需要对应增加二进制辅助变量的数量,沿用上述大M逻辑做等价转换即可。所有建模过程中涉及决策变量、表达式的运算,都要使用Xpress原生提供的运算方法,不要混用Numpy的条件判断、非线性函数处理符号对象。
相关报错截图


内容的提问来源于stack exchange,提问作者Gheouany Saad
相关产品推荐
相关产品推荐

