求解器配方
访问求解器状态
解决后,结果对象有一个成员 Solution.Status,它包含求解器的状态。以下代码片段展示了通过 print 语句访问的示例:
results = opt.solve(instance)
#print ("The solver returned a status of:"+str(results.solver.status))
使用Python的str函数将值转换为字符串,使得测试变得容易。特别是,值'optimal'表示求解器成功。还可以访问可以与求解器状态进行比较的Pyomo数据,如下面的代码片段所示:
from pyomo.opt import SolverStatus, TerminationCondition
#...
if (results.solver.status == SolverStatus.ok) and (results.solver.termination_condition == TerminationCondition.optimal):
print ("this is feasible and optimal")
elif results.solver.termination_condition == TerminationCondition.infeasible:
print ("do something about it? or exit?")
else:
# something else is wrong
print (str(results.solver))
或者,
from pyomo.opt import TerminationCondition
...
results = opt.solve(model, load_solutions=False)
if results.solver.termination_condition == TerminationCondition.optimal:
model.solutions.load_from(results)
else:
print ("Solution is not optimal")
# now do something about it? or exit? ...
求解器输出显示
要查看求解器的输出,请使用选项 tee=True,如下所示:
results = opt.solve(instance, tee=True)
这对于解决求解器困难可能很有用。
向求解器发送选项
大多数求解器接受选项,Pyomo 可以将选项传递给求解器。在脚本或回调中,可以通过向求解器对象的选项字典添加选项来附加选项,如下面的代码片段所示:
optimizer = pyo.SolverFactory['cbc']
optimizer.options["threads"] = 4
如果需要多个选项,则应添加多个字典条目。
有时希望将选项作为调用solve函数的一部分传递,如下面的代码片段所示:
results = optimizer.solve(instance, options={'threads' : 4}, tee=True)
引用的字符串直接传递给求解器。如果需要以这种方式传递多个选项给求解器,它们应该在引用的字符串中用空格分隔。请注意,tee 是 Pyomo 的一个选项,并且与求解器无关,而传递给 options 的字符串参数在 Pyomo 中几乎没有处理就直接传递给求解器。如果求解器没有“threads”选项,它可能会报错,但 Pyomo 不会。
SolverFactory 对象上的选项没有默认值。如果你直接修改其选项字典,如上所述,这些选项将在每次调用 optimizer.solve(…) 时持续存在,除非你从选项字典中删除它们。你也可以使用 options 关键字将选项字典传递给 opt.solve(…) 方法。这些选项仅在该求解过程中持续存在,并临时覆盖求解器对象上选项字典中的任何匹配选项。
指定求解器的路径
通常,求解器的可执行文件在路径中;然而,对于它们不在路径中的情况,SolverFactory函数接受关键字executable,您可以使用它来设置求解器可执行文件的绝对或相对路径。例如,
opt = pyo.SolverFactory("ipopt", executable="../ipopt")
热启动
一些求解器支持基于变量当前值的热启动。要使用此功能,请在实例中设置变量的值,并将warmstart=True传递给solve()方法。例如,
instance = model.create()
instance.y[0] = 1
instance.y[1] = 0
opt = pyo.SolverFactory("cplex")
results = opt.solve(instance, warmstart=True)
注意
Cplex和Gurobi的LP文件(以及Python)接口将生成一个包含变量数据的MST文件,并将其与LP文件一起传递给求解器。
警告
使用NL文件接口的求解器(例如,“gurobi_ampl”,“cplexamp”)不接受warmstart作为solve()方法的关键字,因为默认情况下,NL文件格式包含变量初始化数据(从所有变量的当前值中提取)。
并行解决多个实例
并行构建和解决Pyomo模型是许多应用的常见需求。我们推荐使用Python的MPI(mpi4py)来实现这一目的。有关mpi4py的更多信息,请参阅mpi4py文档(https://mpi4py.readthedocs.io/en/stable/)。下面的示例展示了如何使用mpi4py并行解决两个pyomo模型。可以使用以下命令运行该示例:
mpirun -np 2 python -m mpi4py parallel.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.
# ___________________________________________________________________________
# parallel.py
# run with mpirun -np 2 python -m mpi4py parallel.py
import pyomo.environ as pyo
from mpi4py import MPI
rank = MPI.COMM_WORLD.Get_rank()
size = MPI.COMM_WORLD.Get_size()
assert (
size == 2
), 'This example only works with 2 processes; please us mpirun -np 2 python -m mpi4py parallel.py'
# Create a solver
opt = pyo.SolverFactory('cplex_direct')
#
# A simple model with binary variables
#
model = pyo.ConcreteModel()
model.n = pyo.Param(initialize=4)
model.x = pyo.Var(pyo.RangeSet(model.n), within=pyo.Binary)
model.obj = pyo.Objective(expr=sum(model.x.values()))
if rank == 1:
model.x[1].fix(1)
results = opt.solve(model)
print('rank: ', rank, ' objective: ', pyo.value(model.obj.expr))
更改临时目录
“临时”目录用于许多中间文件。通常,临时文件的目录名称由操作系统提供,但用户可以指定自己的目录名称。pyomo 命令行 --tempdir 选项会传播到 TempFileManager 服务。可以通过脚本中的以下几行代码实现相同的效果:
from pyomo.common.tempfiles import TempfileManager
TempfileManager.tempdir = YourDirectoryNameGoesHere