优化求解器之Pyomo建模工具简介

这篇文章是系列的第二篇,主要介绍 Pyomo 的基本使用方法。目前,MindOpt 支持在 Windows/Linux/OSX 系统中,通过 Pyomo 建立线性规划模型并调用 MindOpt 来求解。


一、概述

Pyomo 是基于 Python 开发的第三方开源建模语言,Pyomo 的建模对象嵌入在 Python 中,它支持对线性规划、混合整数规划、非线性规划等问题的建模和分析,创建具体的问题实例,并调用求解器进行求解。


二、支持问题类型

Pyomo 支持多种求解器(如 MindOpt)接入。Pyomo 具有通用接口,支持调用任何可以读取 AMPL ".nl" 和写入 ".sol" 文件的求解器,以及生成 GAMS 格式模型和检索结果的能力。您可以在安装 Pyomo 后使用 Pyomo 命令 pyomo help --solvers 来获取当前支持的求解器列表。


Pyomo 支持多种问题类型,包括:

  • 线性规划
  • 二次规划
  • 非线性规划
  • 整数线性规划
  • 混合整数非线性规划
  • 混合整数二次规划
  • 微分代数方程
  • 整数随机规划
  • 广义析取规划
  • 带平衡约束的数学规划


Pyomo支持在功能齐全的编程语言中进行分析和编写脚本。

此外,Pyomo 还是用于开发高级优化和分析工具的有效框架。例如,PySP 包为随机编程提供了通用求解器。由于 Pyomo 的建模对象是嵌入在 Python 中的,所以其允许使用 Python 并行通信库对子问题进行透明并行化。


三、Pyomo 建模方法

可通过两种方式使用 Pyomo 创建优化模型:抽象(Abstract)和具体(Concrete)。这两种方式的关键区别在于是否将模型与数据分开引入:

  • 在抽象模型中,模型与数据是分开的,支持在模型建立后再引入数据赋值。
  • 在具体模型中,数据在模型本身中被定义。例如,在使用具体模型的 Pyomo 脚本中,所有内容都是在单个脚本文件中定义的。对于简单的问题,这可能是一种很高效的方法。但另一方面,对于规模比较大的问题(更大的数据集),这使得将数据和处理该数据所需的代码嵌入同一个Python脚本中变得不易实现且难以维护。


总体上讲,Pyomo 模型由变量(Variables)、参数(Parameters)、约束(Constraints)和目标(Objectives)组成。

(1)变量(Variables):

变量代表模型中待优化的决策变量,它是在优化求解中待计算的对象。求解优化模型后得到的变量的值通常称为解,它是优化求解过程的输出。

(2)参数(Parameters):

参数通常指优化问题中提供的数据(系数),以便为决策变量找到最佳(或良好)的值分配。参数值也可以通过定义验证函数进行检查。

(3)约束(Constraints):

约束是定义等式、不等式或其他数学表达式来指定变量的限制的一种方式。大多数约束是使用表达式规则创建的,这些规则往往是一个 Python 函数。

(4)优化目标(Objective):

优化目标是指被建模系统的目标的函数,一般有最大化或最小化两种定义。


优化模型示例

以 MindOpt (https://solver.damo.alibaba-inc.com/doc/html/index.html) 中的 线性规划问题示例 为例,我们使用 Pyomo API 来建立优化模型。

# Define variables and constraints.
variable_names = ['x0', 'x1', 'x2', 'x3']    #变量名称
var_lb = {'x0':0, 'x1':0, 'x2':0, 'x3':0}
var_ub = {'x0':10, 'x1':None, 'x2':None, 'x3':None}
objective_coeff = {'x0': 1, 'x1': 1, 'x2': 1, 'x3': 1}
constraint_names = ['c0', 'c1']
constraint_bound = {'c0': 1, 'c1': 1}
constraint_coeff = {('x0', 'c0'): 1, ('x1', 'c0'): 1, ('x2', 'c0'): 2, ('x3', 'c0'): 3,
                               ('x0', 'c1'): 1, ('x1', 'c1'): -1, ('x2', 'c1'): 0, ('x3', 'c1'): 6}
 
# Create model.
model = ConcreteModel(name="ex1")

# Build decision variables.
model.Set = Set(initialize=variable_names)
model.Variable = Var(model.Set, within=NonNegativeReals, bounds=fb)

# Objective. #目标
model.obj = Objective(expr=sum(objective_coeff[var_name] * model.Variable[var_name] for var_name in variable_names), sense=minimize)

# Constraints.  #约束
model.dual = Suffix(direction=Suffix.IMPORT)
model.cons1 = Constraint(expr = ConstraintsRule(model, 'c0') >= constraint_bound['c0'])
model.cons2 = Constraint(expr = ConstraintsRule(model, 'c1') == constraint_bound['c1'])

并指定使用 MindOpt 求解器,以及对求解的相关参数进行设置(注意:为了使用 MindOpt,请参考 MindOpt-Pyomo 的建模与优化 中描述的方法先将接口文件引入):

# Solve problem by MindOpt solver.
opt = SolverFactory("mindo_direct")

# Set options.
opt.options['Method'] = -1
opt.options['IPM/PrimalTolerance'] = 1e-10

最后,调用 Pyomo 的求解函数 solve() 进行求解,并获取相关的结果:

# Solve.
results = opt.solve(model)

# Summary of result.
results.write()

if (results.solver.status == SolverStatus.ok) and (results.solver.termination_condition == TerminationCondition.optimal):
    print("The solution is optimal and feasible.")
    model.Variable.display()
    model.dual.display()
    model.obj.display()
elif (results.solver.termination_condition == TerminationCondition.infeasible):
    print("The model is infeasible.")
    print("Solver Status: ",  results.solver.status)
else:
    print("Something else is wrong.")
    print("Solver Status: ",  results.solver.status)

更多的关于 Pyomo 的介绍请见:https://pyomo.readthedocs.io/


上一篇:成功解决ERROR: Command errored out with exit status 1: command: 'f:\program files\python\python36\pyt


下一篇:DDD分层架构最佳实践