You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Pyomo目标函数调用分段线性函数报非恒定表达式转布尔值错误求助

Pyomo调用分段线性插值函数触发布尔表达式报错问题

问题背景

我尝试在Pyomo的目标函数中使用其提供的分段线性函数,对名为macc的数组进行插值,该数组共包含401个元素(macc[i],i取值为0到400),macc取值如下图:
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组件即可解决问题,修改步骤如下:

  1. 声明额外变量存储分段插值结果
  2. 用pyo.Piecewise关联输入变量x和插值结果变量,传入断点和对应取值
  3. 目标函数和约束中直接使用插值结果变量即可,不需要再调用插值函数

核心修改代码示例:

# 原有变量声明
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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.29 12:45:03