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

如何在Pyomo中处理布尔逻辑?适配GLPK的线性规划替代方案

问题:Pyomo线性规划中嵌入价格逻辑触发布尔表达式报错

需要在Pyomo优化模型中加入价格计算逻辑,但触发布尔逻辑相关报错,当前使用GLPK求解器(仅支持线性规划),寻求可行的替代方案。

原代码

spread_min_150  =  0.01
spread_150_max  =  0.05

SPOT = 600
avg = 10
h = 730


def price(SPOT, POSITION, spread_min_150, spread_150_max):
    if SPOT < 150:
        spread_price  =  SPOT * (1 + spread_min_150) if POSITION >= 0 else SPOT * (1 - spread_min_150)
    else:
        spread_price  =  SPOT * (1 + spread_150_max) if POSITION >= 0 else SPOT * (1 - spread_150_max)
    return spread_price

model = pyo.ConcreteModel()
model.a = pyo.Var(domain=pyo.NonNegativeReals)
model.b = pyo.Var(domain=pyo.NonNegativeReals)

mcp = avg * 730 - (model.a*730 + model.b*730)

B = mcp * price(SPOT, mcp, spread_min_150, spread_150_max)

model.obj = pyo.Objective(expr=B, sense=pyo.minimize)

model.obj.pprint()

opt = pyo.SolverFactory('glpk') # ('glpk', executable='/usr/bin/glpsol')
result = opt.solve(model)
print(result)
model.display()

报错信息

---------------------------------------------------------------------------
PyomoException                            Traceback (most recent call last)
<ipython-input-5-c3d5ce23abb2> in <cell line: 22>()
     20 mcp = avg * 730 - (model.a*730 + model.b*730)
     21 
---> 22 B = mcp * price(SPOT, mcp, spread_min_150, spread_150_max)
     23 
     24 model.obj = pyo.Objective(expr=B, sense=pyo.minimize)

1 frames
/usr/local/lib/python3.10/dist-packages/pyomo/core/expr/relational_expr.py in __bool__(self)
     46         if self.is_constant():
     47             return bool(self())
---> 48         raise PyomoException(
     49             """
     50 Cannot convert non-constant Pyomo expression (%s) to bool.

PyomoException: Cannot convert non-constant Pyomo expression (0  <=  7300 - (730*a + 730*b)) to bool.
This error is usually caused by using a Var, unit, or mutable Param in a
Boolean context such as an "if" statement, or when checking container
membership or equality. For example,
    >>> m.x = Var()
    >>> if m.x >= 1:
    ...     pass
and
    >>> m.y = Var()
    >>> if m.y in [m.x, m.y]:
    ...     pass
would both cause this exception.

原因分析

报错核心是不能将Pyomo变量/表达式用于Python原生的if判断:

  1. 原代码中price函数里的POSITION >= 0是对Pyomo表达式mcp的判断,Python会尝试将其转为布尔值,但Pyomo的非恒定表达式不支持这种隐式转换。
  2. 原逻辑中的分支判断属于非线性分段函数,直接用Python条件语句无法被GLPK识别为线性约束或目标。

解决方案

由于当前案例中SPOT=600是固定值(大于150),可以简化分支逻辑,通过辅助变量线性化处理mcp的正负分支,适配GLPK的线性规划求解能力:

修改后的代码

import pyomo.environ as pyo

spread_min_150 = 0.01
spread_150_max = 0.05

SPOT = 600
avg = 10
h = 730

model = pyo.ConcreteModel()
model.a = pyo.Var(domain=pyo.NonNegativeReals)
model.b = pyo.Var(domain=pyo.NonNegativeReals)

# 定义mcp表达式
mcp = avg * 730 - (model.a*730 + model.b*730)

# 引入辅助变量,分别表示mcp的正部和负部
model.mcp_pos = pyo.Var(domain=pyo.NonNegativeReals)
model.mcp_neg = pyo.Var(domain=pyo.NonNegativeReals)

# 添加约束:mcp = 正部 - 负部,确保仅其中一个变量非零
model.mcp_decompose = pyo.Constraint(expr=mcp == model.mcp_pos - model.mcp_neg)

# SPOT=600>150,直接使用对应spread系数
price_pos = SPOT * (1 + spread_150_max)  # mcp>=0时的价格
price_neg = SPOT * (1 - spread_150_max)  # mcp<0时的价格

# 线性化目标函数:将mcp*price拆分为正部和负部的线性组合
model.obj = pyo.Objective(expr=model.mcp_pos*price_pos - model.mcp_neg*price_neg, sense=pyo.minimize)

model.obj.pprint()

opt = pyo.SolverFactory('glpk')
result = opt.solve(model)
print(result)
model.display()

扩展说明(若SPOT为变量)

如果后续SPOT变为优化变量,需要引入二进制变量实现分支逻辑(模型转为混合整数线性规划MILP,GLPK支持该类型):

  1. 定义二进制变量y(取值0或1),表示SPOT < 150的状态:
    • y=1:SPOT < 150,使用spread_min_150
    • y=0:SPOT >=150,使用spread_150_max
  2. 添加约束限制SPOT的范围:
    M = 1e6  # 足够大的常数
    model.y = pyo.Var(domain=pyo.Binary)
    model.spot_low = pyo.Constraint(expr=SPOT >= 0 - M*(1 - model.y))
    model.spot_high = pyo.Constraint(expr=SPOT <= 150 + M*model.y)
    
  3. 基于y切换价格系数,构建线性目标函数。

内容的提问来源于stack exchange,提问作者cirogalvao

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 11:27:47