Expression 对象与 pyomo 中的布尔值相乘

问题描述 投票:0回答:1

我目前正在尝试将 pyomo 从 6.5.0 升级到 6.6.2

但是,当我尝试将布尔值与表达式对象相乘时,我遇到了 * 运算符的问题。它对于二进制变量可以正常工作,但对于返回这些错误的本机布尔值则失败:

- TypeError: unsupported operand type(s) for *: '_GeneralExpressionData' and 'bool'
- TypeError: unsupported operand type(s) for *: 'bool' and 'SumExpression'
- TypeError: unsupported operand type(s) for *: 'ScalarExpression' and 'bool'
- TypeError: unsupported operand type(s) for *: 'bool' and 'NPV_SumExpression'

所有这些操作在 6.5.0 中都运行良好,我总是可以通过在乘法之前将布尔值转换为整数来解决它,但这意味着对项目进行大量更改。
为什么不再支持此操作以及如何有效解决此问题?
谢谢

配置:

  • Windows 11
  • Python 3.11
  • Pyomo 6.6.2

工作示例:

import pyomo.environ as pyo
from pyomo.repn.standard_repn import generate_standard_repn
from pyomo.opt import SolverFactory

model = pyo.ConcreteModel()

model.x = pyo.Var([1,2], domain=pyo.NonNegativeReals)
model.exp = pyo.Expression(rule= lambda m: 3*m.x[1] + 4*m.x[2])

model.OBJ = pyo.Objective(expr = 2*model.x[1] + 3*model.x[2])

model.Constraint1 = pyo.Constraint(expr = model.exp >= 1)


def update_expression(attribute, update, add_expression: bool = False):
     original_index = attribute.index_set()

     update_values = (update[index] for index in original_index)

     for index, update_value in zip(original_index, update_values, strict=True):
         attribute[index] = generate_standard_repn(update_value + attribute[index] * add_expression).to_expression()

 model.new_expression = pyo.Expression(rule= lambda _ :-1)

 update_expression(model.exp, model.new_expression, add_expression=True)

 opt = SolverFactory('cbc')
 result = opt.solve(model, tee=True)
 model.display()

用于动态更新表达式的函数示例

python-3.x optimization pyomo
1个回答
0
投票

这种行为是故意的,您看到的异常是为了捕获建模错误而添加的。问题的关键在于,逻辑运算和代数运算在概念上属于不同的表达系统,不应该混合在一起。例如,“

5 * True
”应该是代数运算(乘法)并返回
5
(假设逻辑状态
True
应映射到数字状态
1
),还是应该是逻辑运算(和)并返回
True
(将
5
映射到
True
后)? Python 使用前者,这似乎是正确的。不幸的是,在构建表达系统时这会变得更加混乱。考虑:

(m.p >= 5) * 10

如果

m.p
是一个值为 6 的不可变
Param
,那么根据 Python 规则,这个表达式将为 10。不幸的是,如果
m.p
是一个
Var
,你会得到一个表达式,并且该表达式无法写出到任何求解器 [*1]。

随着我们在 Pyomo 中开发和扩展对逻辑表达式的支持(例如,通过 GDP 中的工作以及新的草案约束编程接口),代数和逻辑表达式系统之间的区别变得更加明显。从 Pyomo 6.6 开始,我们在代数表达式(由于历史原因位于

NumericExpression
层次结构中)、逻辑表达式(在
BooleanExpression
层次结构中)和关系表达式(源自
RelationalExpression
)之间进行了强烈区分。两者(关系表达式是具有代数表达式参数的逻辑表达式)。

至于您的用例,而不是:

for index, update_value in zip(original_index, update_values, strict=True):
    attribute[index] = generate_standard_repn(update_value + attribute[index] * add_expression).to_expression()

我会推荐类似的东西:

if add_expression:
    for index, update_value in zip(original_index, update_values, strict=True):
        attribute[index] += update_value
else:
    for index, update_value in zip(original_index, update_values, strict=True):
        attribute[index] = update_value

[*1] 从技术上讲,您可以将该表达式写入 NL 文件中,但需要将其转换为

Expr_if(IF_=m.p >= 5, THEN_=10, ELSE_=0)
。虽然您可以发出该表达式,但
m.p == 5
处的不连续性可能会给许多求解器带来问题。

© www.soinside.com 2019 - 2024. All rights reserved.