在 pyomo 中定义一组约束的结果是错误的

The outcome of defining a set of constraints in pyomo is wrong

我在 pyomo 中创建了一个优化模型,我有一个元组列表作为参数“par”。

import pyomo.environ as pe
model = pe.ConcreteModel()
p_set = [(1,2), (2,3), (4,5)]
model.par = pe.Param(initialize=p_set, mutable= True)
def var_fix(model, i, j ):
    if (i,j) in model.par:
        constraint = (model.v[i,j] == 1)      # v is a binary variable
    else:
        constraint = (model.v[i,j] == 0) 
    return constraint
model.var_fix = pe.Constraint(model.edges, rule=var_fix)  

但是,在打印“var_fix”约束后,它们都等于零:

Key       : Lower : Body     : Upper : Active
(1, 2)   :   0.0     :   v[1,2] :   0.0     :   True
(2, 3)   :   0.0     :   v[2,3] :   0.0     :   True
(4, 5)   :   0.0     :   v[4,5] :   0.0     :   True

我以这种方式定义参数和约束,因为我想用一个可能有不同数量元组的新参数迭代地更改这个参数“par”,然后解决问题。在每次迭代中我会做:

# generating par_new based on some random processes 
par_new = [(5,10), (2,3), (4,5), (11,8), (10,6)]
model.par = par_new
# solve the problem again

问题的症结在于您正在定义一个包含元组列表的 ScalarParam。 Pyomo 中的标量对象是使用隐式索引 None 的索引对象的特例。这样做是为了使使用 Pyomo 模型的代码可以将所有组件视为已被索引(这可以防止代码被 if comp.is_indexed(): 测试弄得乱七八糟)。您正在执行的 __contains__ 测试 (if (i,j) in model.par) 正在测试元组是否在参数的 索引集 中,而不是在参数的 中值.

最简单的更改是更改测试以检查参数的值:

>>> from pyomo.environ import *
>>> m = ConcreteModel()
>>> m.p = Param(initialize=[(1,2),(3,4)], mutable=True, domain=Any)
>>> (1,2) in m.p
False
>>> (1,2) in m.p.value
True

但是,如果您打算迭代更新模型(不重建它),我建议让参数保持约束的 RHS。也就是说,更像是:

model = pe.ConcreteModel()

p_set = [(1,2), (2,3), (4,5)]
def par(m, i, j):
    return 1 if (i,j) in p_set else 0
model.par = pe.Param(model.edges, initialize=par, mutable=True)

def var_fix(model, i, j ):
    return model.v[i,j] == model.par[i,j]
model.var_fix = pe.Constraint(model.edges, rule=var_fix)  

这是因为构建规则不是回调:它们仅在最初构建组件时被调用,而不是在求解期间被调用。更新参数看起来更像:

model.par.set_values(0)
for i,j in par_new:
    model.par[i,j] = 1