Pyomo接口
Pyomo 是基于Python编程语言的开源优化建模语言, 它提供了丰富的优化相关功能,并已被许多研究人员用于解决复杂的实际应用问题,感兴趣的用户可以查看 谁在使用Pyomo? 了解更多信息。本章介绍了如何在 Pyomo环境下使用杉数求解器。
安装说明
在Pyomo环境下调用杉数求解器进行求解之前,用户需要正确安装与配置Pyomo和杉数求解器。 Pyomo目前支持Python 2.7和3.6-3.10版本,用户可以从 Anaconda发行版 或者 Python官方发行版 下载并安装Python。我们推荐用户 安装Anaconda发行版,因为它对Python新手使用更加友好与方便。
使用conda安装
我们推荐安装了Anaconda发行版Python的用户使用它自带的 conda
工具安装Pyomo,
在Windows的命令行或者Linux和MacOS上的终端中执行下述命令即可:
conda install -c conda-forge pyomo
Pyomo也集成了一些可选的第三方Python包扩展其优化相关功能,可通过如下命令进行安装:
conda install -c conda-forge pyomo.extras
使用pip安装
用户也可以通过标准的 pip
工具安装Pyomo,在Windows的命令行或者Linux和MacOS的终端中
执行下述命令即可:
pip install pyomo
如果用户在安装Pyomo过程中遇到了任何问题,可以查阅 如何安装Pyomo 以了解更多信息。 关于安装与配置杉数求解器,请用户查看文档中的 如何安装杉数求解器 章节 了解详细步骤。
使用示例
我们将通过求解 AMPL接口-使用示例 章节中描述的例子来介绍 如何在Pyomo中调用杉数求解器进行优化求解。如果用户想了解更详细的Pyomo使用说明,可以参考 Pyomo官方文档 进行学习。
抽象模型
Pyomo主要提供了两种方式对其支持的各种问题类型进行建模,本部分将介绍使用抽象模型求解上述问题的方式。
使用Pyomo对上述问题进行建模与求解的源代码 pydiet_abstract.py
如下,
详见 代码 9 :
1# The code is adopted from:
2#
3# https://github.com/Pyomo/pyomo/blob/master/examples/pyomo/amplbook2/diet.py
4#
5# with some modification by developer of the Cardinal Optimizer
6
7from pyomo.core import *
8
9model = AbstractModel()
10
11model.NUTR = Set()
12model.FOOD = Set()
13
14model.cost = Param(model.FOOD, within=NonNegativeReals)
15model.f_min = Param(model.FOOD, within=NonNegativeReals)
16
17model.f_max = Param(model.FOOD)
18model.n_min = Param(model.NUTR, within=NonNegativeReals)
19model.n_max = Param(model.NUTR)
20model.amt = Param(model.NUTR, model.FOOD, within=NonNegativeReals)
21
22def Buy_bounds(model, i):
23 return (model.f_min[i], model.f_max[i])
24model.Buy = Var(model.FOOD, bounds=Buy_bounds)
25
26def Objective_rule(model):
27 return sum_product(model.cost, model.Buy)
28model.totalcost = Objective(rule=Objective_rule, sense=minimize)
29
30def Diet_rule(model, i):
31 expr = 0
32
33 for j in model.FOOD:
34 expr = expr + model.amt[i, j] * model.Buy[j]
35
36 return (model.n_min[i], expr, model.n_max[i])
37model.Diet = Constraint(model.NUTR, rule=Diet_rule)
该问题的数据文件 pydiet_abstract.dat
见 代码 10 :
1# The data is adopted from:
2#
3# https://github.com/Pyomo/pyomo/blob/master/examples/pyomo/amplbook2/diet.dat
4#
5# with some modification by developer of the Cardinal Optimizer
6
7data;
8
9set NUTR := A B1 B2 C ;
10set FOOD := BEEF CHK FISH HAM MCH MTL SPG TUR ;
11
12param: cost f_min f_max :=
13 BEEF 3.19 0 100
14 CHK 2.59 0 100
15 FISH 2.29 0 100
16 HAM 2.89 0 100
17 MCH 1.89 0 100
18 MTL 1.99 0 100
19 SPG 1.99 0 100
20 TUR 2.49 0 100 ;
21
22param: n_min n_max :=
23 A 700 10000
24 C 700 10000
25 B1 700 10000
26 B2 700 10000 ;
27
28param amt (tr):
29 A C B1 B2 :=
30 BEEF 60 20 10 15
31 CHK 8 0 20 20
32 FISH 8 10 15 10
33 HAM 40 40 35 10
34 MCH 15 35 15 15
35 MTL 70 30 15 15
36 SPG 25 50 25 15
37 TUR 60 20 15 10 ;
通过在Windows的命令行或者Linux和Mac的终端中输入下述命令即可实现在Pyomo中调用杉数求解器 进行求解:
pyomo solve --solver=coptampl pydiet_abstract.py pydiet_abstract.dat
求解过程中,Pyomo在屏幕中输出如下信息:
[ 0.00] Setting up Pyomo environment
[ 0.00] Applying Pyomo preprocessing actions
[ 0.00] Creating model
[ 0.01] Applying solver
[ 0.05] Processing results
Number of solutions: 1
Solution Information
Gap: None
Status: optimal
Function Value: 88.19999999999999
Solver results file: results.yml
[ 0.05] Applying Pyomo postprocessing actions
[ 0.05] Pyomo Finished
求解完成后,Pyomo将求解结果输出到如下 results.yml
中:
# ==========================================================
# = Solver Results =
# ==========================================================
# ----------------------------------------------------------
# Problem Information
# ----------------------------------------------------------
Problem:
- Lower bound: -inf
Upper bound: inf
Number of objectives: 1
Number of constraints: 4
Number of variables: 8
Sense: unknown
# ----------------------------------------------------------
# Solver Information
# ----------------------------------------------------------
Solver:
- Status: ok
Message: COPT-AMPL\x3a optimal solution; objective 88.2, iterations 1
Termination condition: optimal
Id: 0
Error rc: 0
Time: 0.03171110153198242
# ----------------------------------------------------------
# Solution Information
# ----------------------------------------------------------
Solution:
- number of solutions: 1
number of solutions displayed: 1
- Gap: None
Status: optimal
Message: COPT-AMPL\x3a optimal solution; objective 88.2, iterations 1
Objective:
totalcost:
Value: 88.19999999999999
Variable:
Buy[MCH]:
Value: 46.666666666666664
Constraint: No values
分析结果知,杉数求解器找到了最优解约为88.2个单位,此时应当购买约46.67个单位的食物MCH。
具象模型
除了使用抽象模型进行建模,Pyomo还支持具象模型建模方式,本部分将介绍使用具象模型对上述问题进行 建模并求解。
具象模型可以使用 "Direct"
和 "Persistent"
接口方式进行求解。该方式依赖杉数求解器的
Pyomo插件文件 copt_pyomo.py
,文件位于安装包的 "lib/pyomo"
子文件夹。使用该插件
需要将 copt_pyomo.py
文件复制到待求解Python程序的相同目录下,且已正确安装了相应
Python版本的杉数求解器Python接口。
使用Pyomo建模求解的源代码 pydiet_concrete.py
见
代码 11:
1# The code is adopted from:
2#
3# https://github.com/Pyomo/pyomo/blob/master/examples/pyomo/amplbook2/diet.py
4#
5# with some modification by developer of the Cardinal Optimizer
6
7from __future__ import print_function, division
8
9import pyomo.environ as pyo
10import pyomo.opt as pyopt
11
12from copt_pyomo import *
13
14# Nutrition set
15NUTR = ["A", "C", "B1", "B2"]
16# Food set
17FOOD = ["BEEF", "CHK", "FISH", "HAM", "MCH", "MTL", "SPG", "TUR"]
18
19# Price of foods
20cost = {"BEEF": 3.19, "CHK": 2.59, "FISH": 2.29, "HAM": 2.89, "MCH": 1.89,
21 "MTL": 1.99, "SPG": 1.99, "TUR": 2.49}
22# Nutrition of foods
23amt = {"BEEF": {"A": 60, "C": 20, "B1": 10, "B2": 15},
24 "CHK": {"A": 8, "C": 0, "B1": 20, "B2": 20},
25 "FISH": {"A": 8, "C": 10, "B1": 15, "B2": 10},
26 "HAM": {"A": 40, "C": 40, "B1": 35, "B2": 10},
27 "MCH": {"A": 15, "C": 35, "B1": 15, "B2": 15},
28 "MTL": {"A": 70, "C": 30, "B1": 15, "B2": 15},
29 "SPG": {"A": 25, "C": 50, "B1": 25, "B2": 15},
30 "TUR": {"A": 60, "C": 20, "B1": 15, "B2": 10}}
31
32# The "diet problem" using ConcreteModel
33model = pyo.ConcreteModel()
34
35model.NUTR = pyo.Set(initialize=NUTR)
36model.FOOD = pyo.Set(initialize=FOOD)
37
38model.cost = pyo.Param(model.FOOD, initialize=cost)
39
40def amt_rule(model, i, j):
41 return amt[i][j]
42model.amt = pyo.Param(model.FOOD, model.NUTR, initialize=amt_rule)
43
44model.f_min = pyo.Param(model.FOOD, default=0)
45model.f_max = pyo.Param(model.FOOD, default=100)
46
47model.n_min = pyo.Param(model.NUTR, default=700)
48model.n_max = pyo.Param(model.NUTR, default=10000)
49
50def Buy_bounds(model, i):
51 return (model.f_min[i], model.f_max[i])
52model.buy = pyo.Var(model.FOOD, bounds=Buy_bounds)
53
54def Objective_rule(model):
55 return pyo.sum_product(model.cost, model.buy)
56model.totalcost = pyo.Objective(rule=Objective_rule, sense=pyo.minimize)
57
58def Diet_rule(model, j):
59 expr = 0
60
61 for i in model.FOOD:
62 expr = expr + model.amt[i, j] * model.buy[i]
63
64 return (model.n_min[j], expr, model.n_max[j])
65model.Diet = pyo.Constraint(model.NUTR, rule=Diet_rule)
66
67# Reduced costs of variables
68model.rc = pyo.Suffix(direction=pyo.Suffix.IMPORT)
69
70# Activities and duals of constraints
71model.slack = pyo.Suffix(direction=pyo.Suffix.IMPORT)
72model.dual = pyo.Suffix(direction=pyo.Suffix.IMPORT)
73
74# Use 'copt_direct' solver to solve the problem
75solver = pyopt.SolverFactory('copt_direct')
76
77# Use 'copt_persistent' solver to solve the problem
78# solver = pyopt.SolverFactory('copt_persistent')
79# solver.set_instance(model)
80
81results = solver.solve(model, tee=True)
82
83# Check result
84print("")
85if results.solver.status == pyopt.SolverStatus.ok and \
86 results.solver.termination_condition == pyopt.TerminationCondition.optimal:
87 print("Optimal solution found")
88else:
89 print("Something unexpected happened: ", str(results.solver))
90
91print("")
92print("Optimal objective value:")
93print(" totalcost: {0:6f}".format(pyo.value(model.totalcost)))
94
95print("")
96print("Variables solution:")
97for i in FOOD:
98 print(" buy[{0:4s}] = {1:9.6f} (rc: {2:9.6f})".format(i, \
99 pyo.value(model.buy[i]), \
100 model.rc[model.buy[i]]))
101
102print("")
103print("Constraint solution:")
104for i in NUTR:
105 print(" diet[{0:2s}] = {1:12.6f} (dual: {2:9.6f})".format(i, \
106 model.slack[model.Diet[i]], \
107 model.dual[model.Diet[i]]))
然后,在Windows的命令行或者Linux和MacOS的终端中执行下述命令进行求解:
python pydiet_concrete.py
求解完成后,屏幕输出如下内容:
Optimal solution found
Objective:
totalcost: 88.200000
Variables:
buy[BEEF] = 0.000000
buy[CHK ] = 0.000000
buy[FISH] = 0.000000
buy[HAM ] = 0.000000
buy[MCH ] = 46.666667
buy[MTL ] = 0.000000
buy[SPG ] = 0.000000
buy[TUR ] = 0.000000
结果显示,杉数求解器找到了最优解约88.2个单位,此时应当购买约46.67个单位的食物MCH。