模型查询

访问变量值

原始变量值

通常,优化的目的是获取变量的最优值。一些用户可能希望在脚本中处理这些值。我们将描述如何从Python脚本中访问特定变量,以及如何从Python脚本和回调中访问所有变量。这应该使读者能够理解如何获得他们所需的访问权限。上面给出的迭代示例也说明了如何访问变量值。

从Python脚本中获取一个变量

假设模型已经实例化并解决,并且结果已经加载回实例对象中,那么我们可以利用变量是实例对象的成员这一事实,并且可以使用其value成员访问其值。例如,假设模型包含一个名为quant的变量,该变量是单例的(没有索引),并且进一步假设实例对象的名称是instance。那么可以使用pyo.value(instance.quant)访问此变量的值。可以通过提供索引来引用带有索引的变量。

考虑以下非常简单的例子,它与迭代例子类似。这是一个具体的模型。在这个例子中,访问了x[2]的值。

#  ___________________________________________________________________________
#
#  Pyomo: Python Optimization Modeling Objects
#  Copyright (c) 2008-2024
#  National Technology and Engineering Solutions of Sandia, LLC
#  Under the terms of Contract DE-NA0003525 with National Technology and
#  Engineering Solutions of Sandia, LLC, the U.S. Government retains certain
#  rights in this software.
#  This software is distributed under the 3-clause BSD License.
#  ___________________________________________________________________________

# noiteration1.py

import pyomo.environ as pyo
from pyomo.opt import SolverFactory

# Create a solver
opt = SolverFactory('glpk')

#
# A simple model with binary variables and
# an empty constraint list.
#
model = pyo.ConcreteModel()
model.n = pyo.Param(default=4)
model.x = pyo.Var(pyo.RangeSet(model.n), within=pyo.Binary)


def o_rule(model):
    return pyo.summation(model.x)


model.o = pyo.Objective(rule=o_rule)
model.c = pyo.ConstraintList()

results = opt.solve(model)

if pyo.value(model.x[2]) == 0:
    print("The second index has a zero")
else:
    print("x[2]=", pyo.value(model.x[2]))

注意

如果此脚本未经修改运行,Pyomo 可能会发出警告,因为没有约束条件。该警告是因为某些求解器在接收到没有任何约束条件的问题实例时可能会失败。

从Python脚本中获取所有变量

与单变量一样,我们假设模型已被实例化并解决。假设实例对象的名称为instance,以下代码片段显示所有变量及其值:

>>> for v in instance.component_objects(pyo.Var, active=True):
...     print("Variable",v)  
...     for index in v:
...         print ("   ",index, pyo.value(v[index]))  

或者,

>>> for v in instance.component_data_objects(pyo.Var, active=True):
...     print(v, pyo.value(v))  

这段代码可以通过检查变量是否未被索引(即唯一的索引值是None)来改进,然后代码可以打印值而不带旁边的None这个词。

再次假设模型已经实例化并解决,并且结果已经加载回实例对象中。以下是一个将所有整数固定在其当前值的代码片段:

>>> for var in instance.component_data_objects(pyo.Var, active=True):
...     if not var.is_continuous():
...         print ("fixing "+str(v))  
...         var.fixed = True # fix the current value

另一种访问所有变量的方法(特别是在有块的情况下)如下(这个特定的代码片段假设使用了from pyo.environ import *而不是import pyomo.environ as pyo):

for v in model.component_objects(Var, descend_into=True):
    print("FOUND VAR:" + v.name)
    v.pprint()

for v_data in model.component_data_objects(Var, descend_into=True):
    print("Found: " + v_data.name + ", value = " + str(value(v_data)))

访问参数值

访问参数值与访问变量值完全类似。例如,以下是一个代码片段,用于打印模型中每个参数的名称和值:

>>> for parmobject in instance.component_objects(pyo.Param, active=True):
...     nametoprint = str(str(parmobject.name))
...     print ("Parameter ", nametoprint)  
...     for index in parmobject:
...         vtoprint = pyo.value(parmobject[index])
...         print ("   ",index, vtoprint)  

访问对偶

在脚本中访问对偶值与访问原始变量值类似,不同之处在于对偶值默认不会被捕获,因此在优化之前需要额外的指令来表明需要获取对偶值。

要在没有脚本的情况下获取对偶值,请使用pyomo选项 --solver-suffixes='dual',这将导致对偶值包含在输出中。注意:除了对偶值(dual),还可以请求减少成本(rc)和松弛值(slack)。所有后缀都可以通过pyomo选项--solver-suffixes='.*'请求。

警告

一些对偶值可能具有None值,而不是0

在Python脚本中访问Duals

为了表示需要双重变量,可以在模型或实例上声明一个名为“dual”的Suffix组件,并使用IMPORT或IMPORT_EXPORT方向。

# Create a 'dual' suffix component on the instance
# so the solver plugin will know which suffixes to collect
instance.dual = pyo.Suffix(direction=pyo.Suffix.IMPORT)

有关Pyomo的Suffix组件的更多信息,请参阅Suffixes部分。在获得结果并将其加载到实例中后,可以按以下方式访问对偶值。

# display all duals
print("Duals")
for c in instance.component_objects(pyo.Constraint, active=True):
    print("   Constraint", c)
    for index in c:
        print("      ", index, instance.dual[c[index]])

当然,以下代码片段只有在存在名为 AxbConstraint 的约束并且具有索引(即字符串 Film)时才会起作用。

# access one dual
print("Dual for Film=", instance.dual[instance.AxbConstraint['Film']])

这是一个完整的示例,依赖于文件 abstract2.py 提供模型,以及文件 abstract2.dat 提供数据。请注意,abstract2.py 中的模型确实包含一个名为 AxbConstraint 的约束,并且 abstract2.dat 确实为其指定了一个名为 Film 的索引。

#  ___________________________________________________________________________
#
#  Pyomo: Python Optimization Modeling Objects
#  Copyright (c) 2008-2024
#  National Technology and Engineering Solutions of Sandia, LLC
#  Under the terms of Contract DE-NA0003525 with National Technology and
#  Engineering Solutions of Sandia, LLC, the U.S. Government retains certain
#  rights in this software.
#  This software is distributed under the 3-clause BSD License.
#  ___________________________________________________________________________

# driveabs2.py

import pyomo.environ as pyo
from pyomo.opt import SolverFactory

# Create a solver
opt = SolverFactory('cplex')

# get the model from another file
from abstract2 import model

# Create a model instance and optimize
instance = model.create_instance('abstract2.dat')

# Create a 'dual' suffix component on the instance
# so the solver plugin will know which suffixes to collect
instance.dual = pyo.Suffix(direction=pyo.Suffix.IMPORT)

results = opt.solve(instance)
# also puts the results back into the instance for easy access

# display all duals
print("Duals")
for c in instance.component_objects(pyo.Constraint, active=True):
    print("   Constraint", c)
    for index in c:
        print("      ", index, instance.dual[c[index]])

# access one dual
print("Dual for Film=", instance.dual[instance.AxbConstraint['Film']])

具体模型略有不同,因为模型本身就是实例。这里是一个完整的示例,它依赖于文件 concrete1.py 来提供模型并实例化它。

#  ___________________________________________________________________________
#
#  Pyomo: Python Optimization Modeling Objects
#  Copyright (c) 2008-2024
#  National Technology and Engineering Solutions of Sandia, LLC
#  Under the terms of Contract DE-NA0003525 with National Technology and
#  Engineering Solutions of Sandia, LLC, the U.S. Government retains certain
#  rights in this software.
#  This software is distributed under the 3-clause BSD License.
#  ___________________________________________________________________________

# driveconc1.py

import pyomo.environ as pyo
from pyomo.opt import SolverFactory

# Create a solver
opt = SolverFactory('cplex')

# get the model from another file
from concrete1 import model

# Create a 'dual' suffix component on the instance
# so the solver plugin will know which suffixes to collect
model.dual = pyo.Suffix(direction=pyo.Suffix.IMPORT)

results = opt.solve(model)  # also load results to model

# display all duals
print("Duals")
for c in model.component_objects(pyo.Constraint, active=True):
    print("   Constraint", c)
    for index in c:
        print("      ", index, model.dual[c[index]])

访问Slacks

函数 lslack()uslack() 分别返回约束的上下松弛量。