这篇文章是系列的第二篇,主要介绍 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/