求解器配方

访问求解器状态

解决后,结果对象有一个成员 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