Pyomo目标函数调用分段线性函数报非恒定表达式转布尔值错误求助
Pyomo调用分段线性插值函数触发布尔表达式报错问题
问题背景
我尝试在Pyomo的目标函数中使用其提供的分段线性函数,对名为macc的数组进行插值,该数组共包含401个元素(macc[i],i取值为0到400),macc取值如下图:
我的目标是求解满足约束条件的i值,使对应macc[i]符合要求。为此我对macc数组进行插值得到连续函数f,相关代码如下:
c = np.arange(401) f = pyopiecewise.piecewise(c,macc,validate=False) model = pyo.ConcreteModel() #Declare variable model.x = pyo.Var(domain=pyo.NonNegativeReals, bounds=(5,395), initialize = cp0) #Declare parameters model.s = pyo.Param(domain=pyo.NonNegativeReals,initialize=s0) model.b = pyo.Param(domain=pyo.NonNegativeReals,initialize=b0) model.tnac = pyo.Param(domain=pyo.NonNegativeReals,initialize=tnac0) #Objective function def objective_(m): ab = f(m.x) e = m.b - ab return (e * m.x) #Constraints def constraint1(m): ab = f(m.x) e = m.b - ab return e <= (m.tnac + m.s)
报错信息
当我在上述目标函数中调用函数f时,执行目标函数中的ab = f(m.x)语句触发如下报错:
ERROR: Rule failed when generating expression for Objective Obj with index None: PyomoException: Cannot convert non-constant expression to bool. This error is usually caused by using an expression in a boolean context such as an if statement. For example, m.x = Var() if m.x <= 0: ... would cause this exception. ERROR: Constructing component 'Obj' from data=None failed: PyomoException: Cannot convert non-constant expression to bool. This error is usually caused by using an expression in a boolean context such as an if statement. For example, m.x = Var() if m.x <= 0: ... would cause this exception.
完整复现代码
本示例中macc通过logistic函数生成,实际场景中macc为内部业务数据,不依赖外部函数生成:
import numpy as np import pyomo.environ as pyo import pyomo.core.kernel.piecewise_library.transforms as pyopiecewise #Create macc # logistic sigmoid function def logistic(x, L=1, x_0=0, k=1): return L / (1 + np.exp(-k * (x - x_0))) c = np.arange(401) macc = 2000*logistic(c,L=0.5,x_0 = 60,k=0.02) macc = macc -macc[0] f = pyopiecewise.piecewise(c,macc,validate=False) s0 = 800 b0 = 1000 tnac0 = 100 cp0 = 10 ab0 = 100 model = pyo.ConcreteModel() #Declare variable model.x = pyo.Var(domain=pyo.NonNegativeReals, bounds=(5,395), initialize = cp0) #Declare parameters model.s = pyo.Param(domain=pyo.NonNegativeReals,initialize=s0) model.b = pyo.Param(domain=pyo.NonNegativeReals,initialize=b0) model.tnac = pyo.Param(domain=pyo.NonNegativeReals,initialize=tnac0) #Objective function def objective_(m): ab = f(m.x) e = m.b - ab return (e * m.x) model.Obj = pyo.Objective(rule=objective_) #Constraints def constraint1(m): ab = f(m.x) e = m.b - ab return e <= (m.tnac + m.s) def constraint2(m): ab = f(m.x) e = m.b - ab return e >= 1 def constraint3(m): ab = f(m.x) return ab >= 0 model.con1 = pyo.Constraint(rule = constraint1) model.con2 = pyo.Constraint(rule = constraint2) model.con3 = pyo.Constraint(rule = constraint3)
目标函数可视化见下图:
解决思路
报错核心原因是你使用的pyomo.core.kernel.piecewise_library.transforms.piecewise是Pyomo Kernel模型专属API,不支持在常规ConcreteModel的规则中直接传入Pyomo变量构造表达式。
改用Pyomo标准pyo.Piecewise组件即可解决问题,修改步骤如下:
- 声明额外变量存储分段插值结果
- 用
pyo.Piecewise关联输入变量x和插值结果变量,传入断点和对应取值 - 目标函数和约束中直接使用插值结果变量即可,不需要再调用插值函数
核心修改代码示例:
# 原有变量声明 model.x = pyo.Var(domain=pyo.NonNegativeReals, bounds=(5,395), initialize = cp0) # 新增存储插值结果的变量 model.ab = pyo.Var() # 定义分段线性映射 model.piecewise = pyo.Piecewise(model.ab, model.x, pw_pts=c, pw_constr_type='EQ', f_rule=macc, validate=False) # 目标函数修改后写法 def objective_(m): e = m.b - m.ab return (e * m.x)
所有约束中的f(m.x)都替换为m.ab即可正常运行。
内容的提问来源于stack exchange,提问作者RonB
相关产品推荐
相关产品推荐

