Pyomo Interface
Pyomo is a Python based, open source optimization modeling language with a diverse set of optimization capabilities. It is used by researchers to solve complex real-world applications, see Who uses Pyomo? for more introduction. The following documentation explains how to use the Cardinal Optimizer.
Installation Guide
To use the Cardinal Optimizer in Pyomo, you should setup Pyomo and Cardinal Optimizer correctly first. Pyomo currently supports Python 2.7, 3.6-3.9, you can install Python from Anaconda Distribution of Python or from Official Python. We recommend install Python from Anaconda since it is much more friendly and convenient for fresh users.
Using conda
The recommended way to install Pyomo in Anaconda Distribution of Python is
to use conda
which is built-in supported. Just execute the following
commands in command prompt on Windows or shell on Linux and MacOS:
conda install -c conda-forge pyomo
Pyomo also has conditional dependencies on a variety of third-party Python
packages, they can be installed using conda
with commands:
conda install -c conda-forge pyomo.extras
Using pip
The alternative way to install Pyomo is to use the standard pip
utitility,
just execute the following commands in command prompt on Windows or shell
on Linux and MacOS:
pip install pyomo
If you encounter any problems when installing Pyomo, please refer to How to install Pyomo for details. To install Cardinal Optimizer and setup its license properly, please refer to How to install Cardinal Optimizer for details.
Example Usage
We are going to make a simple introduction on how to use the Cardinal Optimizer in Pyomo by solving the example described in AMPL Interface - Example Usage. Users who want to learn more information about Pyomo may refer to Pyomo documentation for details.
Abstract Model
Pyomo provides two major approaches to construct any supported model types, here we show the Abstract Model approach to solve the above problem.
The source code pydiet_abstract.py
is shown below, see
Listing 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)
And the data file pydiet_abstract.dat
in Listing 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 ;
To solve the problem using Pyomo and the Cardinal Optimizer, just type commands below in command prompt on Windows or Bash shell on Linux and MacOS.
pyomo solve --solver=coptampl pydiet_abstract.py pydiet_abstract.dat
When solving the problem, Pyomo write log information to the screen:
[ 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
Upon completion, you can check the solution summary in 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
So the minimal total cost is about 88.2 units when buying 46.67 units of MCH.
Concrete Model
The other approach to construct model in Pyomo is to use Concrete Model, we will show how to model and solve the above problem in this way.
Concrete models can be solved using the "Direct"
and "Persistent"
interface methods. This method relies on the Pyomo plugin file "copt_pyomo.py"
of COPT, which is located in the "lib/pyomo"
subfolder of the installation package.
To use this plugin, you need to copy the "copt_pyomo.py"
file to the same directory of your program, and have correctly installed the corresponding version of the Python interface of COPT(coptpy
).
The source code pydiet_concrete.py
is shown in
Listing 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]]))
To solve the problem using Pyomo and the Cardinal Optimizer, just execute commands below:
python pydiet_concrete.py
Up completion, you should see solution summary on screen as below:
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
So the Cardinal Optimizer found the optimal solution, which is about 88.2 units when buying about 46.67 units of MCH.