使用 PySP 回调的 Pyomo 模型中的参数值未更新

The parameter values are not updating in the Pyomo model with PySP callback

我正在使用 PySP (Pyomo) 解决一个随机优化问题。我为我的问题创建了一个具体模型,并根据

中给出的农民示例定义了场景

https://github.com/Pyomo/pysp/blob/main/examples/farmer/concrete/ReferenceModel.py

在上面的示例中,为每个场景调用了一个 pysp_instance_creation_callback() 函数。在函数中,为每个场景克隆一个模型实例,以便使用 instance.Yield.store_values(Yield[scenario_name]).

为每个场景更新场景变量(在本例中为 Yield)

我对我的问题采用了类似的方法。然而,在我的例子中,对于每种情景,未知数的大小都不同,这与农民的例子不同,在农民的例子中,情景只针对三种作物(小麦、糖、玉米)。例如,我的场景是这样的,

Scenario1 = {123, 124, 118}
Scenario2 = {117, 10}
Scenario3 = {118, 120, 125, 126}
Scenario4 = {0, 125}
...

我的代码片段类似于下面的代码片段(为了简单起见,我只提到了有用的约束和变量)

# Variable:
model.nEdges = 129
model.x_ij = range(0, model.nEdges)  # line switching variable range
model.xij = Var(model.x_ij, bounds=(0, 1), within=Binary)

# Scenario parameter:
model.Fault = Param(mutable=True, initialize={123,124,118}, within=Any)

# Constraint:
for key, ite in model.Fault.items():
    for faulty in ite.value:
        model.c.add(model.xij[faulty] == 0)

# Scenarios:
Fault = {}
Fault['Scenario1'] = {123, 124, 118}
Fault['Scenario2'] = {120, 124, 118}
Fault['Scenario3'] = {1, 125}

# callback function to update the model parameter
def pysp_instance_creation_callback(scenario_name, node_names):
    instance = model.clone()
    instance.Fault.store_values(Fault[scenario_name])
    return instance

但是,这个方法对我不起作用。每个场景的 model.Fault 值在初始化时保持不变,即 {123,124,118}。虽然如果我检查每个场景的实例值,即 instance.Fault.value,那么这些值似乎正在更新(instance.Fault.value 给出与不同场景一致的不同值)但是在检查输出 lp 文件时对于实际模型,约束不会根据需要更新,最终解决方案对于前面提到的每个场景都是相同的。我不确定如何解决这个问题,而且我已经被困在这个问题上好几天了。有人可以帮我吗?

在开始之前,我应该指出 PySP 不再处于积极开发状态。 mpi-sppy https://github.com/Pyomo/mpi-sppy

正在进行新的开发

回到您的问题:PySP 假设模型的“形状”对于每个场景都是相同的,因此您将不得不进行更多编码以使该假设有效。 mpi-sppy 或多或少也是如此,尽管它有机制允许 Var 的概率为零,具体取决于场景。 mpi-sspy 比 PySP 的麻烦要少一些,参数会在场景之间改变大小,但它确实有一些组件假设模型的形状可以由任意场景确定(PySP 使用 ReferenceModel 所以它强烈假定形状不变)。

简短的回答是您没有正确使用 Param。可变参数旨在保存 标量 值,这些值出现在 表达式树(用于目标或约束)。您将一个复杂的数据结构放入 Param 中,然后在创建原始模型时迭代它,使用间接数据(作为另一个变量的 index)。这不起作用的原因是 model.clone() 复制了当前存在的模型 ,它复制了原始约束。您添加到 model.c 的约束实际上独立于可变参数 Fault,因此当您更改其中的值时,Pyomo 无法知道什么/如何更新约束。

针对这种特定情况的更好方法是修复 变量而不是创建额外的约束:

model.xij = Var(model.x_ij, bounds=(0, 1), within=Binary)

# Scenarios:
Fault = {}
Fault['Scenario1'] = {123, 124, 118}
Fault['Scenario2'] = {120, 124, 118}
Fault['Scenario3'] = {1, 125}

# callback function to update the model parameter
def pysp_instance_creation_callback(scenario_name, node_names):
    instance = model.clone()
    for faulty in Fault[scenario_name]:
        instance.xij[faulty].fix(0)
    return instance