参数值不会在PySP回调的Pyomo模型中更新

2024-04-28 06:27:39 发布

您现在位置:Python中文网/ 问答频道 /正文

我使用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值在初始化时对每个场景保持不变,即{123124118}。虽然如果我检查每个场景的实例值,即instance.Fault.value,那么这些值似乎正在更新(instance.Fault.value给出了与不同场景一致的不同值),但是在检查实际模型的输出lp文件时,约束没有按预期更新,最终解决方案与前面提到的每个场景相同。我不知道如何解决这个问题,我已经陷入这个问题好几天了。有人能帮我吗


Tags: instancename模型示例modelvaluecallback场景
2条回答

简而言之,您没有正确使用Param。可变参数用于保存表达式树中出现的标量值(用于目标或约束)。您将一个复杂的数据结构放入Param中,然后在创建原始模型时使用间接数据(作为另一个变量的索引)对其进行迭代。这不起作用的原因是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

在开始之前,我应该指出PySP不再处于积极的开发中。mpi公司正在进行新的开发

回到您的问题:PySP假设模型的“形状”对于每个场景都是相同的,因此您必须进行更多的编码以使该假设有效。mpi sppy的情况大致相同,尽管它有一些机制允许根据场景的不同,VAR的概率为零。mpi sspy的问题比PySP小一些,参数在不同场景之间会改变大小,但它确实有一些组件假设模型的形状可以由任意场景确定(PySP使用ReferenceModel,因此它强烈假设形状不会改变)

相关问题 更多 >