Present Azi One
Present Azi One
Present Azi One
0. Installing Pyomo
John D. Siirola
<VENUE>
<DATE>
Sandia National Laboratories is a multi-program laboratory managed and operated by Sandia Corporation, a wholly owned subsidiary of Lockheed Martin
Corporation, for the U.S. Department of Energy’s National Nuclear Security Administration under contract DE-AC04-94AL85000. SAND NO. 2011-XXXXP
Use Anaconda3 [all platforms]
Install Anaconda3
https://www.continuum.io/downloads
Windows/Mac OS X/Linux
Install the Python 3.5 version for your OS
Includes several packages for scientific computing already
Supports easy installation of pyomo and solvers
Installing Pyomo 2
Install with pip [all platforms]
Install Python
Linux & Mac OS/X typically have Python pre-installed
Scientific Python distributions have many utilities pre-installed
http://www.scipy.org/install.html
Install Pyomo
Install in your system
pip install Pyomo
Install in a user directory
pip install --user Pyomo
Installing Pyomo 3
Install with Download Scripts [Windows]
Install Python
Linux & Mac OS/X typically have Python pre-installed
Scientific Python distributions have many utilities pre-installed
http://www.scipy.org/install.html
Install pip
https://bootstrap.pypa.io/get-pip.py
Installing Pyomo 4
Install Trunk / Offline [All platforms]
Install Python
Linux & Mac OS/X typically have Python pre-installed
Scientific Python distributions have many utilities pre-installed
http://www.scipy.org/install.htm
Installing Pyomo 5
Install Solvers
Open Source Solvers
Installing Pyomo 6
License
Pyomo released under 3-clause BSD license
No restrictions on deployment or commercial use
Installing Pyomo 7
Getting help
Homepage:
www.pyomo.org
Developer site:
https://software.sandia.gov/pyomo
Mailing lists
pyomo-forum@googlegroups.com
pyomo-developers@googlegroups.com
Installing Pyomo 8
Acknowledgements
William Hart
Carl Laird
John Siirola
Jean-Paul Watson
David Woodruff
Installing Pyomo 9
1. Overview of Pyomo
John D. Siirola
<VENUE>
<DATE>
Sandia National Laboratories is a multi-program laboratory managed and operated by Sandia Corporation, a wholly owned subsidiary of Lockheed Martin
Corporation, for the U.S. Department of Energy’s National Nuclear Security Administration under contract DE-AC04-94AL85000. SAND NO. 2011-XXXXP
Pyomo Overview
Idea: a Pythonic framework for formulating optimization models
Provide a natural syntax to describe mathematical models
Formulate large models with a concise syntax
Separate modeling and data declarations
Enable data import and export in commonly used formats
# simple.py
Highlights: from pyomo.environ import *
Python provides a
M = ConcreteModel()
clean, intuitive syntax M.x1 = Var()
M.x2 = Var(bounds=(-1,1))
M.x3 = Var(bounds=(1,2))
Python scripts provide M.o = Objective(
a flexible context for expr=M.x1**2 + (M.x2*M.x3)**4 + \
exploring the structure M.x1*M.x3 + \
M.x2*sin(M.x1+M.x3) + M.x2)
of Pyomo models
model = M
Overview of Pyomo 2
Overview
What happened to Coopr?
Overview of Pyomo 3
What Happened to Coopr?
Overview of Pyomo 4
Optimization Modeling
Goal:
Provide a natural syntax to describe mathematical models
Formulate large models with a concise syntax
Separate modeling and data declarations
Enable data import and export in commonly used formats
Impact:
Robustly model large constraint matrices (e.g. for MILPs)
Integrated support of automatic differentiation for complex nonlinear
models
Examples:
AMPL, GAMS, AIMMS, …
OptimJ, FlopCPP, PuLP, JuMP, …
Overview of Pyomo 5
Why Model in Python?
Full-Featured Library
Language features includes functions, classes, looping, namespaces, etc
Introspection facilitates the development of generic algorithms
Python’s clean syntax facilitates rapid prototyping
Open Source License
No licensing issues w.r.t. the language itself
Extensibility and Robustness
Highly stable and well-supported
Support and Documentation
Extensive online documentation and several excellent books
Long-term support for the language is not a factor
Standard Library
Includes a large number of useful modules
Portability
Widely available on many platforms
Overview of Pyomo 6
Why Open Source?
Transparency and reliability
Flexible licensing
Pyomo released under 3-clause BSD license
No restrictions on deployment or commercial use
Overview of Pyomo 7
Pyomo at a Glance
CPLEX
Solver Interfaces Gurobi
Xpress
GLPK
Core Optimization
Objects CBC
BARON
OpenOpt
Core Modeling
Objects NEOS
AMPL Solver Library
Ipopt
KNITRO
Bonmin
Couenne
DAKOTA
Overview of Pyomo 8
Pyomo at a Glance
CPLEX
Solver Interfaces Gurobi
Xpress
Meta-Solvers
• Generalized Benders GLPK
Core Optimization
• Progressive Hedging CBC
• Linear bilevel
Objects
• Linear MPEC BARON
OpenOpt
Core Modeling
Objects NEOS
Modeling Extensions AMPL Solver Library
• Disjunctive programming
Ipopt
• Stochastic programming Model
• Bilevel programming Transformations KNITRO
• Differential equations Bonmin
• Equilibrium constraints Couenne
DAKOTA
Overview of Pyomo 9
Survey of Python Modeling Tools
Pyomo
Supports concrete/abstract modeling for LP/MILP/NLP models
Modeling extensions for stochastic programming, bilevel, MPEC, etc
Separate model objects
PuLP
Supports concrete modeling for LP/MILP models
Separate model objects
Simple object model
APLEpy
Supports concrete modeling for LP/MILP models
Single global model object
PyMathProg, pyglpk, cplex, gurobi
Python interfaces for specific solver tools
Overview of Pyomo 10
More than just mathematical modeling
Scripting
Construct models using native Python data
Iterative analysis of models leveraging Python functionality
Data analysis and visualization of optimization results
Meta-solvers
Integrate scripting and/or transformations into optimization solver
Leverage Python’s introspective nature to build “generic” capabilities
E.g.: progressive hedging, SP extensive form -> MIP
Overview of Pyomo 11
Who Uses Pyomo?
Students
Rose-Hulman, UC Davis, U Texas, Iowa State, NPS
Researchers
Government laboratories
Sandia National Labs, Lawrence Livermore National Lab, Los Alamos
National Lab, National Energy Technology Lab, Federal Energy Regulation
Commission
Universities
UC Davis, TAMU, Rose-Hulman, UT, USC, GMU, Iowa State, NCSU, U
Washington, NPS, U de Santiago de Chile, U Pisa, …
Companies
Overview of Pyomo 12
Who Uses Pyomo?
Software Projects
TEMOA – Energy economy optimization models
Minpower – Power systems toolkit
Water Security Toolkit – Planning/Response for water contamination
SolverStudio – Excel plugin for optimization modeling
Overview of Pyomo 13
For More Information
See the Pyomo homepage
www.pyomo.org
Coming soon:
A gallery of simple
examples
Overview of Pyomo 14
Development, Community Activity
Pyomo Forum
Active discussion list
Overview of Pyomo 15
Acknowledgements
Sandia National Laboratories
William Hart
Jean-Paul Watson
John Siirola
Francisco Munoz
University of California, Davis
Prof. David L. Woodruff
Prof. Roger Wets
Purdue University
Prof. Carl D. Laird
Oregon State University
Gabe Hackebeil
Carnegie Mellon University
Bethany Nicholson
Overview of Pyomo 16
2. A Python Tutorial
John D. Siirola
<VENUE>
<DATE>
Sandia National Laboratories is a multi-program laboratory managed and operated by Sandia Corporation, a wholly owned subsidiary of Lockheed Martin
Corporation, for the U.S. Department of Energy’s National Nuclear Security Administration under contract DE-AC04-94AL85000. SAND NO. 2011-XXXXP
Why Python?
Interpreted language
Intuitive syntax
Dynamic typing
Lots of built-in libraries and third-party extensions
Shallow learning curve
Integration with C/Java
Object-oriented
Simple, but extremely powerful
A Python Tutorial 2
Python Implementations
Cpython
C Python interpreter
https://www.python.org/downloads/
Full Pyomo Support
SciPy Stack
http://www.scipy.org/install.html
Anaconda: Linux/MacOS/MS Windows
PyPy
A Python interpreter written in Python Beta Pyomo Support
http://pypy.org/
Jython
Java Python interpreter
http://www.jython.org/
Pyomo Not Supported (yet)
IronPython
.NET Python interpreter
http://ironpython.net/
A Python Tutorial 3
Python Versions: 2.x vs 3.x
Python 3.0 was released in 2008
Included significant backward incompatibilities
Status
We try to stick to
Python 2.7.11 “universal” syntax
Very stable; patches have included package that will work in
updates to support Python 3.x compatibility both 2.x and 3.x
Python 3.5.1
Very stable
A Python Tutorial 4
Overview
interactive "shell"
basic types: numbers, strings
container types: lists, dictionaries, tuples
variables
control structures
functions & procedures
classes & instances
modules
exceptions
files & standard library
A Python Tutorial 5
Interactive Shell
Great for learning the language
Great for experimenting with the library
Great for testing your own modules
Two variations:
IDLE (GUI)
python (command line)
Type statements or expressions at prompt:
>>> print( "Hello, world" )
Hello, world
>>> x = 12**2
>>> x/2
72
>>> # this is a comment
A Python Tutorial 6
Python Program
To write a program, put commands in a file
# hello.py
print( "Hello, world" )
x = 12**2
print( x )
python hello.py
Hello, world
144
A Python Tutorial 7
Python Variables
No need to declare
Need to assign (initialize)
use of uninitialized variable raises exception
Not typed
greeting = 34.2
if friendly:
greeting = "hello world"
else:
greeting = 12**2
print( greeting )
Everything is a "variable":
Even functions, classes, modules
A Python Tutorial 8
Control Structures
if condition: while condition:
statements statements
[elif condition:
statements] ... for var in sequence:
else: statements
statements
break
continue
A Python Tutorial 9
Grouping Indentation
In Python: In C:
A Python Tutorial 10
Numbers
The usual suspects
12, 3.14, 0xFF, 0377, (-1+2)*3/4**5, abs(x), 0<x<=5
C-style shifting & masking
1<<16, x&0xff, x|1, ~x, x^y
Integer division truncates
Python 2.x
– 1/2 0, 1./2. 0.5, float(1)/2 0.5
– from __future__ import division
» 1/2 0.5
Python 3.x
– 1/2 0.5
Long (arbitrary precision), complex
2L**100 1267650600228229401496703205376L
– In Python 2.2 and beyond, 2**100 does the same thing
1j**2 (-1+0j)
A Python Tutorial 11
Strings
"hello"+"world” "helloworld” # concatenation
"hello"*3 "hellohellohello" # repetition
"hello"[0] "h" # indexing
"hello"[-1] "o" # (from end)
"hello"[1:4] "ell" # slicing
len("hello") 5 # size
"hello" < "jello” True # comparison
"e" in "hello” True # search
A Python Tutorial 12
Lists
Flexible arrays, not linked lists
a = [99, "bottles of beer", ["on", "the", "wall"]]
A Python Tutorial 13
List Operations
>>> a = range(5) # [0,1,2,3,4]
>>> a.append(5) # [0,1,2,3,4,5]
>>> a.pop() # [0,1,2,3,4]
5
>>> a.insert(0, 42) # [42,0,1,2,3,4]
>>> a.pop(0) # [0,1,2,3,4]
42
>>> a.reverse() # [4,3,2,1,0]
>>> a.sort() # [0,1,2,3,4]
A Python Tutorial 14
Dictionaries
Hash tables, "associative arrays"
d = {"duck": "eend", "water": "water"}
Lookup:
d["duck"] # -> "eend"
d["back"] # raises KeyError exception
A Python Tutorial 15
Dictionary Operations
Keys, values, items:
d.keys() -> ["duck", "back"]
d.values() -> ["duik", "rug"]
d.items() -> [("duck","duik"), ("back","rug")]
A Python Tutorial 16
Dictionary Details
Keys must be immutable:
numbers, strings, tuples of immutables
these cannot be changed after creation
keys are hashed (to ensure fast lookup)
lists or dictionaries cannot be used as keys
these objects can be changed "in place"
no restrictions on values
A Python Tutorial 17
Tuples
key = (lastname, firstname)
point = x, y, z # parentheses optional
x, y, z = point # unpack
lastname = key[0] # index tuple values
singleton = (1,) # trailing comma!!!
# (1) integer!
empty = () # parentheses!
A Python Tutorial 18
Reference Semantics
Assignment manipulates references
x = y does not make a copy of y
x = y makes x reference the object y references
Reference values can be modified!
>>> a = [1, 2, 3]
>>> b = a
>>> a.append(4)
>>> print(b)
[1, 2, 3, 4]
Copied objects are distinct
>>> import copy
>>> c = copy.copy(a)
>>> a.pop()
>>> print(c)
[1, 2, 3, 4]
A Python Tutorial 19
Changing a Shared List
a = [1, 2, 3] a 1 2 3
a
b = a 1 2 3
b
a
a.append(4) 1 2 3 4
b
A Python Tutorial 20
Changing an Integer
a = 1 a 1
a
b = a 1
b new int object created
by add operator (1+1)
a 2
a = a+1 old reference deleted
by assignment (a=...)
b 1
A Python Tutorial 21
Functions / Procedures
def name(arg1, arg2, ...):
"""documentation""" # optional doc string
statements
A Python Tutorial 22
Example
def gcd(a, b):
"""greatest common divisor"""
while a != 0:
a, b = b%a, a # parallel assignment
return b
>>> gcd.__doc__
'greatest common divisor'
A Python Tutorial 23
Classes
class name(object):
"""documentation"""
statements
A Python Tutorial 24
Example
class Stack(object):
"""A well-known data structure..."""
def __init__(self): # constructor
self.items = []
def push(self, x):
self.items.append(x) # the sky is the limit
def pop(self):
x = self.items[-1] # what if it’s empty?
del self.items[-1]
return x
def empty(self):
return len(self.items) == 0 # Boolean result
A Python Tutorial 25
Example (cont’d)
To create an instance, simply call the class object:
x = Stack() # no 'new' operator!
A Python Tutorial 26
Class/Instance Variables
class Connection(object):
verbose = 0 # class variable
def connect(self):
if self.verbose: # class or instance variable?
print("connecting to %s" % (self.host,))
A Python Tutorial 27
Instance Variable Rules
On use via instance (self.x), search order:
(1) instance, (2) class, (3) base classes
this also works for method lookup
But...!
mutable class variable: one copy shared by all
mutable instance variable: each instance its own
A Python Tutorial 28
Modules
Collection of stuff in foo.py file
functions, classes, variables
Importing modules:
import re
print( re.match("[a-z]+", s) )
from re import match
print( match("[a-z]+", s) )
A Python Tutorial 29
Catching Exceptions
def foo(x):
return 1/x
def bar(x):
try:
print( foo(x) )
except ZeroDivisionError as message:
print("Can’t divide by zero: %s" % message)
bar(0)
A Python Tutorial 30
Try-Finally: Cleanup
f = open(file)
try:
process_file(f)
finally:
f.close() # always executed
print("OK") # executed on success only
A Python Tutorial 31
Raising Exceptions
raise IndexError
try:
something
except: # catch everything
print( "Oops" )
raise # reraise
A Python Tutorial 32
More on Exceptions
User-defined exceptions
subclass Exception or any other standard exception
A Python Tutorial 33
Major Python Packages
SciPy
Scientific Python for mathematics and engineering
http://www.scipy.org
Numpy
Numeric array package
http://www.numpy.org/
Matplotlib
2D plotting library
http://matplotlib.org/
Pandas
Data structures and analysis
http://pandas.pydata.org/
Ipython
Interactive Python shell
http://ipython.org/
A Python Tutorial 36
Resources
Software Carpentry
http://software-carpentry.org/
Python webpage
http://www.python.org
Books
Python Essential Reference (4th Edition), David Beazley, 2009
Python in a Nutshell, Alex Martelli, 2003
Python Pocket Reference, 4th Edition, Mark Lutz, 2009
…
A Python Tutorial 37
Acknowledgements
William Hart
Ted Ralphs
John Siirola
Dave Woodruff
Guido van Rossum
A Python Tutorial 38
3. Pyomo Fundamentals
John D. Siirola
<VENUE>
<DATE>
Sandia National Laboratories is a multi-program laboratory managed and operated by Sandia Corporation, a wholly owned subsidiary of Lockheed Martin
Corporation, for the U.S. Department of Energy’s National Nuclear Security Administration under contract DE-AC04-94AL85000. SAND NO. 2011-XXXXP
3. Fundamental Pyomo Components
Pyomo is an object model for describing optimization problems
The fundamental objects used to build models are Components
Set
Set
Param domain
domain
Var
Model bounds
domain
Var
bounds
Constraint bounds
expression
…
Pyomo Fundamentals 2
Cutting to the chase: a simple Pyomo model
rosenbrock.py:
model = ConcreteModel()
model.obj = Objective(
expr= (1-model.x)**2 + 100*(model.y-model.x**2)**2,
sense= minimize )
Pyomo Fundamentals 3
Cutting to the chase: a simple Pyomo model
Solve the model: % pyomo solve rosenbrock.py --solver=ipopt --summary
[ 0.00] Setting up Pyomo environment
The pyomo command [
[
0.00] Applying Pyomo preprocessing actions
0.00] Creating model
[ 0.00] Applying solver
[ 0.03] Processing results
Number of solutions: 1
Solution Information
Gap: <undefined>
Status: optimal
Function Value: 2.98956421871e-17
Solver results file: results.json
=====================================================
Solution Summary
=====================================================
Model unknown
Variables:
Variable x : Size=1 Domain=Reals
Value=0.999999994543
Variable y : Size=1 Domain=Reals
Value=0.999999989052
Objectives:
Objective obj : Size=1
Value=2.98956421871e-17
Constraints:
None
[ 0.03] Applying Pyomo postprocessing actions
[ 0.03] Pyomo Finished
Pyomo Fundamentals 4
Regarding namespaces
Pyomo objects exist within the pyomo.environ namespace:
import pyomo.environ
model = pyomo.environ.ConcreteModel()
Pyomo Fundamentals 5
Getting Started: the Model
from pyomo.environ import * Every Pyomo model starts
with this; it tells Python to
load the Pyomo Modeling
model = ConcreteModel() Environment
Pyomo Fundamentals 6
Populating the Model: Variables
Pyomo Fundamentals 7
Defining the Objective
model.x = Var( initialize=-1.2, bounds=(-2, 2) )
model.y = Var( initialize= 1.0, bounds=(-2, 2) )
model.obj = Objective(
expr= (1-model.x)**2 + 100*(model.y-model.x**2)**2,
sense= minimize )
Pyomo Fundamentals 8
Defining the Problem: Constraints
model.a = Var()
model.b = Var()
model.c = Var()
model.c1 = Constraint(
expr = model.b + 5 * model.c <= model.a )
Pyomo Fundamentals 9
Lists of Constraints
model.a = Var()
model.b = Var()
model.c = Var()
model.limits = ConstraintList()
Pyomo Fundamentals 10
Higher-dimensional components
(Almost) All Pyomo components can be indexed
All non-keyword arguments are assumed to be indices
Individual indices may be multi-dimensional (e.g., a list of pairs)
Pyomo Fundamentals 11
Manipulating indices: list comprehensions
model.IDX = range(10)
model.a = Var()
model.b = Var(model.IDX)
model.c1 = Constraint(
expr = sum(model.b[i] for i in model.IDX) <= model.a )
Pyomo Fundamentals 12
Concrete Modeling
Pyomo Fundamentals 13
Putting It All Together: Concrete p-Median
𝑦𝑛 = 𝑃 select 𝑃 warehouses
𝑛∈𝑁
0≤𝑥≤1 𝑦 ∈ 0,1 𝑁
Pyomo Fundamentals 14
Concrete p-Median (1)
from pyomo.environ import *
N = 3
M = 4
P = 3
d = {(1, 1): 1.7, (1, 2): 7.2, (1, 3): 9.0, (1, 4): 8.3,
(2, 1): 2.9, (2, 2): 6.3, (2, 3): 9.8, (2, 4): 0.7,
(3, 1): 4.5, (3, 2): 4.8, (3, 3): 4.2, (3, 4): 9.3}
model = ConcreteModel()
model.Locations = range(N)
model.Customers = range(M)
model.x = Var( model.Locations, model.Customers,
bounds=(0.0,1.0) )
Pyomo Fundamentals 15
Concrete p-Median (2)
model.obj = Objective( expr = sum( d[n,m]*model.x[n,m]
for n in model.Locations for m in model.Customers ) )
model.single_x = ConstraintList()
for m in model.Customers:
model.single_x.add(
sum( model.x[n,m] for n in model.Locations ) == 1.0 )
model.bound_y = ConstraintList()
for n in model.Locations:
for m in model.Customers:
model.bound_y.add( model.x[n,m] <= model.y[n] )
model.num_facilities = Constraint(
expr=sum( model.y[n] for n in model.Locations ) == P )
Pyomo Fundamentals 16
Solving models: the pyomo command
pyomo (pyomo.exe on Windows):
Constructs model and passes it to an (external) solver
pyomo solve <model_file> [<data_file> …] [options]
Installed to:
[PYTHONHOME]\Scripts [Windows; C:\Python27\Scripts]
[PYTHONHOME]/bin [Linux; /usr/bin]
Pyomo Fundamentals 17
In Class Exercise: Concrete Knapsack
N
max v x
i 1
i i
Item
hammer
Weight
5
Value
8
N
w x
wrench 7 3
s.t. i i Wmax screwdriver 4 6
i 1
towel
xi {0,1} 3 11
Max weight: 14
Syntax reminders:
from pyomo.environ import *
ConcreteModel()
Var( [index, …], [within=domain], [bounds=(lower,upper)] )
ConstraintList()
c.add( expression )
Objective( sense={maximize|minimize},
expr=expression )
Pyomo Fundamentals 18
Concrete Knapsack: Solution
from pyomo.environ import *
model = ConcreteModel()
model.ITEMS = v.keys()
model.x = Var( model.ITEMS, within=Binary )
model.value = Objective(
expr = sum( v[i]*model.x[i] for i in model.ITEMS ),
sense = maximize )
model.weight = Constraint(
expr = sum( w[i]*model.x[i] for i in model.ITEMS ) <= W_max )
Pyomo Fundamentals 19
Abstract Modeling
Pyomo Fundamentals 20
Concrete vs. Abstract Models
Concrete Models: data first, then model
1-pass construction
All data must be present before Python starts processing the model
Pyomo will construct each component in order at the time it is declared
Straightforward logical process; easy to script.
Familiar to modelers with experience with GAMS
Pyomo Fundamentals 21
Generating and Managing Indices: Sets
Any iterable object can be an index, e.g., lists:
IDX_a = [1,2,5]
DATA = {1: 10, 2: 21, 5:42};
IDX_b = DATA.keys()
Pyomo Fundamentals 22
Sequential Indices: RangeSet
Sets of sequential integers are common
model.IDX = Set( initialize=range(5) )
model.IDX = RangeSet( 5 )
This gives [ 0, 1, 2, 3, 4 ]
Pyomo Fundamentals 23
Manipulating Sets
Sets support efficient higher-dimensional indices
model.IDX = Set( initialize=[1,2,5] )
model.IDX2 = model.IDX * model.IDX
This creates a virtual Sets also support union (&), intersection (|),
2-D “matrix” Set difference (-), symmetric difference (^)
The filter should return True if the element is in the set; False otherwise.
Pyomo Fundamentals 24
Deferred construction: Rules
Abstract modeling constructs the model in two passes:
Python parses the model declaration
creating “empty” Pyomo components in the model
Pyomo loads and parses external data
Naming conventions
the component name prepended with “_” (c4 _c4)
the component name with “_rule” appended (c4 c4_rule)
each rule is called “rule” (Python implicitly overrides each declaration)
Pyomo Fundamentals 25
Indexed Constraints
model.IDX = Set( initialize=range(5) )
model.a = Var( model.IDX )
model.b = Var()
def c4_rule(model, i):
return model.a[i] + model.b <= 1
model.c4 = Constraint( model.IDX, rule=c4_rule )
Pyomo Fundamentals 26
Importing Data: Parameters
Pyomo Fundamentals 27
Data Sources
Data can be imported from “.dat” file
Format similar to AMPL style
Explicit data from “param” declarations
External data through “load” declarations:
Excel
load ABCD.xls range=ABCD : Z=[A, B, C] Y=D ;
Databases
load “DBQ=diet.mdb” using=pyodbc query=“SELECT FOOD, cost,
f_min, f_max from Food” : [FOOD] cost f_min f_max ;
Pyomo Fundamentals 28
Abstract p-Median (pmedian.py, 1)
from pyomo.environ import *
model = AbstractModel()
Pyomo Fundamentals 29
Abstract p-Median (pmedian.py, 2)
def obj_rule(model):
return sum( model.d[n,m]*model.x[n,m]
for n in model.Locations for m in model.Customers )
model.obj = Objective( rule=obj_rule )
def num_facilities_rule(model):
return sum( model.y[n] for n in model.Locations ) == model.P
model.num_facilities = Constraint( rule=num_facilities_rule )
Pyomo Fundamentals 30
Abstract p-Median (pmedian.dat)
param N := 3;
param M := 4;
param P := 2;
param d: 1 2 3 4 :=
1 1.7 7.2 9.0 8.3
2 2.9 6.3 9.8 0.7
3 4.5 4.8 4.2 9.3 ;
Pyomo Fundamentals 31
In Class Exercise: Abstract Knapsack
N
max vi xi
i 1
Item
hammer
Weight
5
Value
8
N
w x
wrench 7 3
s.t. i i Wmax screwdriver 4 6
i 1
towel
xi {0,1} 3 11
Max weight: 14
Syntax reminders:
AbstractModel()
Set( [index, …], [initialize=list/function] )
Param( [index, …], [within=domain], [initialize=dict/function] )
Var( [index, …], [within=domain], [bounds=(lower,upper)] )
Constraint( [index, …], [expr=expression|rule=function] )
Objective( sense={maximize|minimize},
expr=expression|rule=function )
Pyomo Fundamentals 32
Abstract Knapsack: Solution
from pyomo.environ import *
model = AbstractModel()
model.ITEMS = Set()
model.v = Param( model.ITEMS, within=PositiveReals )
model.w = Param( model.ITEMS, within=PositiveReals )
model.W_max = Param( within=PositiveReals )
model.x = Var( model.ITEMS, within=Binary )
def value_rule(model):
return sum( model.v[i]*model.x[i] for i in model.ITEMS )
model.value = Objective( rule=value_rule, sense=maximize )
def weight_rule(model):
return sum( model.w[i]*model.x[i] for i in model.ITEMS ) \
<= model.W_max
model.weight = Constraint( rule=weight_rule )
Pyomo Fundamentals 33
Abstract Knapsack: Solution Data
param: v w :=
hammer 8 5
wrench 3 7
screwdriver 6 4
towel 11 3;
Pyomo Fundamentals 34
4. Pyomo Idioms
John D. Siirola
<VENUE>
<DATE>
Sandia National Laboratories is a multi-program laboratory managed and operated by Sandia Corporation, a wholly owned subsidiary of Lockheed Martin
Corporation, for the U.S. Department of Energy’s National Nuclear Security Administration under contract DE-AC04-94AL85000. SAND NO. 2011-XXXXP
Pyomo and Python: Idioms and Efficiency
Pyomo Idioms 2
What are reasonable performance expectations?
Pyomo Idioms 3
Managing edge cases (special sets vs rule logic)
def rule2(model):
if t == 0:
return Constraint.Skip
return model.x[t] = model.c * model.x[t-1]
model.link = Constraint( model.T, rule=rule2)
Pyomo Idioms 4
Managing edge cases (special sets vs rule logic)
model.Tnot0 = model.T – [ 0 ]
def rule1(model, t):
return model.x[t] == model.c * model.x[t-1]
model.link = Constraint( model.Tnot0, rule=rule1)
def rule2(model):
if t == 0:
return Constraint.Skip
return model.x[t] = model.c * model.x[t-1]
model.link = Constraint( model.T, rule=rule2)
Pyomo Idioms 5
Managing edge cases (special sets vs rule logic)
model.Tnot0 = model.T – [ 0 ]
def rule1(model, t):
return model.x[t] = model.c * model.x[t-1]
model.link = Constraint( model.Tnot0, rule=rule1)
Pyomo Idioms 6
Managing edge cases (special sets vs rule logic)
model.Tnot0 = model.T – [ 0 ]
def rule1(model, t):
return model.x[t] == model.c * model.x[t-1]
model.link = Constraint( model.Tnot0, rule=rule1)
Pyomo Idioms 7
Managing edge cases (special sets vs rule logic)
Pyomo Idioms 8
Managing performance (how not to shoot yourself)
Expression generation; consider:
min d n ,m xn.m , n Locations , m Customers
n m
Pyomo Idioms 9
Managing performance (how not to shoot yourself)
Expression generation; consider:
min d n ,m xn.m , n Locations , m Customers
def rule1(model): n m
ans = 0
for n in model.Locations:
for m in model.Customers:
ans = ans + model.d[n,m]*model.x[n,m]
return ans
def rule2(model):
ans = 0
for n in model.Locations:
for m in model.Customers:
ans += model.d[n,m]*model.x[n,m]
return ans
def rule3(model):
return sum( [ model.d[n,m]*model.x[n,m]
for n in model.Locations for m in model.Customers ] )
def rule4(model):
return sum( model.d[n,m]*model.x[n,m]
for n in model.Locations for m in model.Customers )
Pyomo Idioms 10
Managing performance (how not to shoot yourself)
Expression generation; consider:
min d n ,m xn.m , n Locations , m Customers
def rule1(model): n m
ans = 0
for n in model.Locations:
for m in model.Customers:
ans = ans + model.d[n,m]*model.x[n,m]
return ans
def rule2(model):
ans = 0
for n in model.Locations:
for m in model.Customers:
ans += model.d[n,m]*model.x[n,m]
return ans
def rule3(model):
return sum( [ model.d[n,m]*model.x[n,m]
for n in model.Locations for m in model.Customers ] )
def rule4(model):
return sum( model.d[n,m]*model.x[n,m]
for n in model.Locations for m in model.Customers )
Pyomo Idioms 11
Managing performance (how not to shoot yourself)
Expression generation; consider:
min d n ,m xn.m , n Locations , m Customers
def rule1(model): n m
ans = 0
for n in model.Locations:
for m in model.Customers:
ans = ans + model.d[n,m]*model.x[n,m]
return ans
def rule2(model):
ans = 0
for n in model.Locations:
for m in model.Customers:
ans += model.d[n,m]*model.x[n,m]
return ans
def rule3(model):
return sum( [ model.d[n,m]*model.x[n,m]
for n in model.Locations for m in model.Customers ] )
def rule4(model):
return sum( model.d[n,m]*model.x[n,m]
for n in model.Locations for m in model.Customers )
Pyomo Idioms 12
Managing performance (how not to shoot yourself)
Expression generation; consider:
min d n ,m xn.m , n Locations , m Customers
def rule1(model): n m
ans = 0
for n in model.Locations:
for m in model.Customers:
ans = ans + model.d[n,m]*model.x[n,m]
return ans
def rule2(model):
ans = 0
for n in model.Locations:
for m in model.Customers:
ans += model.d[n,m]*model.x[n,m]
return ans
def rule3(model):
return sum( [ model.d[n,m]*model.x[n,m]
for n in model.Locations for m in model.Customers ] )
def rule4(model):
return sum( model.d[n,m]*model.x[n,m]
for n in model.Locations for m in model.Customers )
Pyomo Idioms 13
Managing performance (how not to shoot yourself)
Expression generation; consider:
min d n ,m xn.m , n Locations , m Customers
def rule1(model): n m
ans = 0
for n in model.Locations:
for m in model.Customers:
ans = ans + model.d[n,m]*model.x[n,m]
return ans [ n = m = 1..640 ]
def rule2(model):
ans = 0
rule1: >>10000 sec
for n in model.Locations: rule2: 5.0 sec
for m in model.Customers:
ans += model.d[n,m]*model.x[n,m] rule3: 7.4 sec
return ans rule4: 5.0 sec
def rule3(model):
return sum( [ model.d[n,m]*model.x[n,m]
for n in model.Locations for m in model.Customers ] )
def rule4(model):
return sum( model.d[n,m]*model.x[n,m]
for n in model.Locations for m in model.Customers )
Pyomo Idioms 14
Managing performance (how not to shoot yourself)
Sparse data; consider:
a
mM
x bn
n,m m n N
def rule1(model,n):
return sum( model.a[n,m] * model.x[m] for m in model.M) <= model.b[n] )
def rule2(model,n):
return sum( model.a[n,m] * model.x[m] for m in model.M) <= model.b[n]
if model.a[n,m] != 0 )
def rule3(model,n):
For n = 1..10, m = 1..1e5, 4% nonzero,
return sum( model.a[n,m] * model.x[m] for m in model.M) <= model.b[n]
if value(model.a[n,m]) != 0 )
1.9 seconds to generate the constraint
def rule4(model,n):1e5 terms in the constraint (dense!!)
return sum( model.a[n,m] * model.x[m] for m in model.M) <= model.b[n]
if model.a[n,m].value != 0 )
Pyomo Idioms 15
Managing performance (how not to shoot yourself)
Sparse data; consider:
a
mM
x bn
n,m m n N
def rule1(model,n):
return sum( model.a[n,m] * model.x[m] for m in model.M) <= model.b[n] )
def rule2(model,n):
return sum( model.a[n,m] * model.x[m] for m in model.M
if model.a[n,m] != 0 ) <= model.b[n]
def rule3(model,n):
return sum( model.a[n,m] * model.x[m] for m in model.M) <= model.b[n]
if value(model.a[n,m]) != 0 )
For n = 1..10, m = 1..1e5, 4% nonzero,
def rule4(model,n):
0.1 seconds slower, and still dense!
return sum( model.a[n,m] * model.x[m] for m in model.M) <= model.b[n]
if model.a[n,m].value != 0 )
Pyomo Idioms 16
Managing performance (how not to shoot yourself)
Sparse data; consider:
a
mM
x bn
n,m m n N
def rule1(model,n):
return sum( model.a[n,m] * model.x[m] for m in model.M) <= model.b[n] )
def rule2(model,n):
return sum( model.a[n,m] * model.x[m] for m in model.M) <= model.b[n]
if model.a[n,m] != 0 )
def rule3(model,n):
return sum( model.a[n,m] * model.x[m] for m in model.M
if value(model.a[n,m]) != 0 ) <= model.b[n]
def rule4(model,n):
return sum( model.a[n,m] * model.x[m] for m in model.M
if model.a[n,m].value != 0 ) <= model.b[n]
Pyomo Idioms 17
Managing performance (how not to shoot yourself)
Sparse data; consider:
a
mM
x bn
n,m m n N
def rule1(model,n):
return sum( model.a[n,m] * model.x[m] for m in model.M) <= model.b[n] )
def rule2(model,n):
return sum( model.a[n,m] * model.x[m] for m in model.M
if model.a[n,m] != 0 ) <= model.b[n]
Pyomo Idioms 18
Managing performance (how not to shoot yourself)
Mutable vs Immutable Params
Given a promise parameter value will never change, we can optimize
Immutable Params are now the default!
model.a = Param( model.N, model.M, default=0, mutable=False )
def rule1(model,n):
return sum( model.a[n,m] * model.x[m] for m in model.M) <= model.b[n] )
def rule2(model,n):
return sum( model.a[n,m] * model.x[m] for m in model.M
if model.a[n,m] != 0 ) <= model.b[n]
[ n = 1..10, m = 1..1e5,
def rule3(model,n):
return sum( model.a[n,m] * model.x[m] for m in model.M
4% fill ]
if value(model.a[n,m]) != 0 ) <= model.b[n]
rule1: 1.2 sec
def rule4(model,n): rule2: 0.5 sec
return sum( model.a[n,m] * model.x[m] for m in model.M
if model.a[n,m].value != 0 ) <= model.b[n] rule3: 0.5 sec
model.C = Constraint( model.N, rule=ruleN )
rule4: Exception!
Pyomo Idioms 19
Managing performance (how not to shoot yourself)
Sparse constraints; consider:
storaget , p ,d storaget 1, p ,d productiont , p ,d
t [dStartd , dEnd d ], p Products, d Disruptions
Pyomo Idioms 20
Managing performance (how not to shoot yourself)
Sparse constraints; consider:
storaget , p ,d storaget 1, p ,d productiont , p ,d
t [dStartd , dEnd d ], p Products, d Disruptions
def rule1(model,t,d,p):
if t < model.dStart[d] or t > model.dEnd[d]:
return Constraint.Skip
return model.storage[t,p,d] == model.storage[t-1,p,d] + model.production[t,p,d]
model.C1 = Constraint( model.TIME, model.DISRUPTIONS, model.PRODUCTS, rule=rule1 )
def rule2(model,t,d,p):
return model.storage[t,p,d] == model.storage[t-1,p,d] + model.production[t,p,d]
def _filter2(model,t,d,p):
return t >= model.dStart[d] and t <= model.dEnd[d]
model.ACTIVE_DISRUPTIONS = Set( model.TIME * model.DISRUPTIONS * model.PRODUCTS,
filter=_filter2 )
model.C2 = Constraint( model.ACTIVE_DISRUPTIONS, rule=rule2 )
def _filter3(model,t,d):
return t >= model.dStart[d] and t <= model.dEnd[d]
model.ACTIVE_DISRUPTIONS = Set( model.TIME * model.DISRUPTIONS, filter=_filter3 )
model.C3 = Constraint( model.ACTIVE_DISRUPTIONS, model.PRODUCTS, rule=rule2 )
Pyomo Idioms 21
Managing performance (how not to shoot yourself)
Sparse constraints; consider:
storaget , p ,d storaget 1, p ,d productiont , p ,d
t [dStartd , dEnd d ], p Products, d Disruptions
def rule1(model,t,d,p):
if t < model.dStart[d] or t > model.dEnd[d]:
return Constraint.Skip
return model.storage[t,p,d] == model.storage[t-1,p,d] + model.production[t,p,d]
model.C1 = Constraint( model.TIME, model.DISRUPTIONS, model.PRODUCTS, rule=rule1 )
def rule2(model,t,d,p):
return model.storage[t,p,d] == model.storage[t-1,p,d] + model.production[t,p,d]
def _filter2(model,t,d,p):
return t >= model.dStart[d] and t <= model.dEnd[d]
model.ACTIVE_DISRUPTIONS = Set( within=model.TIME * model.DISRUPTIONS * model.PRODUCTS,
filter=_filter2 )
model.C2 = Constraint( model.ACTIVE_DISRUPTIONS, rule=rule2 )
def _filter3(model,t,d):
return t >= model.dStart[d] and t <= model.dEnd[d]
model.ACTIVE_DISRUPTIONS = Set( model.TIME * model.DISRUPTIONS, filter=_filter3 )
model.C3 = Constraint( model.ACTIVE_DISRUPTIONS, model.PRODUCTS, rule=rule2 )
Pyomo Idioms 22
Managing performance (how not to shoot yourself)
Sparse constraints; consider:
storaget , p ,d storaget 1, p ,d productiont , p ,d
t [dStartd , dEnd d ], p Products, d Disruptions
def rule1(model,t,d,p):
if t < model.dStart[d] or t > model.dEnd[d]:
return Constraint.Skip
return model.storage[t,p,d] == model.storage[t-1,p,d] + model.production[t,p,d]
model.C1 = Constraint( model.TIME, model.DISRUPTIONS, model.PRODUCTS, rule=rule1 )
def rule2(model,t,d,p):
return model.storage[t,p,d] == model.storage[t-1,p,d] + model.production[t,p,d]
def _filter2(model,t,d,p):
return t >= model.dStart[d] and t <= model.dEnd[d]
model.ACTIVE_DISRUPTIONS = Set( model.TIME * model.DISRUPTIONS * model.PRODUCTS,
filter=_filter2 )
model.C2 = Constraint( model.ACTIVE_DISRUPTIONS, rule=rule2 )
def _filter3(model,t,d):
return t >= model.dStart[d] and t <= model.dEnd[d]
model.ACTIVE_DISRUPTIONS = Set( within=model.TIME * model.DISRUPTIONS, filter=_filter3 )
model.C3 = Constraint( model.ACTIVE_DISRUPTIONS, model.PRODUCTS, rule=rule2 )
Pyomo Idioms 23
Managing performance (how not to shoot yourself)
Sparse constraints; consider: [ t = d = 1..250,
storaget , p ,d storaget 1, p ,d productiont , p ,d p =1..10,
t*d = 2% fill ]
t [dStartd , dEnd d ], p Products, d Disruptions
def rule1(model,t,d,p): C1: 2.2 sec
if t < model.dStart[d] or t > model.dEnd[d]:
return Constraint.Skip C2: 2e-4 sec
return model.storage[t,p,d] == model.storage[t-1,p,d] + model.production[t,p,d]
C3: 2e-4 sec
model.C1 = Constraint( model.TIME, model.DISRUPTIONS, model.PRODUCTS, rule=rule1 )
def rule2(model,t,d,p):
return model.storage[t,p,d] == model.storage[t-1,p,d] + model.production[t,p,d]
def _filter2(model,t,d,p):
return t >= model.dStart[d] and t <= model.dEnd[d]
model.ACTIVE_DISRUPTIONS = Set( within=model.TIME * model.DISRUPTIONS * model.PRODUCTS,
filter=_filter2 )
model.C2 = Constraint( model.ACTIVE_DISRUPTIONS, rule=rule2 )
def _filter3(model,t,d):
return t >= model.dStart[d] and t <= model.dEnd[d]
model.ACTIVE_DISRUPTIONS = Set( within=model.TIME * model.DISRUPTIONS, filter=_filter3 )
model.C3 = Constraint( model.ACTIVE_DISRUPTIONS, model.PRODUCTS, rule=rule2 )
Pyomo Idioms 24
Managing performance (how not to shoot yourself)
Using Pyomo convenience functions
min d n ,m xn.m , n Locations , m Customers
n m
def rule1(model):
return sum( model.d1[n,m]*model.x[n,m]
for n in model.Locations for m in model.Customers ) [ n = m = 1..640 ]
def rule2(model): rule1: 5.0 sec
return summation( model.d1, model.x )
rule2: 7.9 sec
model.d2 = Param( model.Locations, model.Customers, mutable=False ) rule3: 3.5 sec
rule4: 5.6 sec
def rule3(model):
return sum( model.d2[n,m]*model.x[n,m]
for n in model.Locations for m in model.Customers )
def rule4(model):
return sumation( model.d2, model.x )
Pyomo Idioms 25
The Performance “Elephant”: Memory
Known issue …
Python uses a fairly heavy-weight object model
“Significant” recent improvements in low-level core components
Coopr 3.3 uses <50% of the memory of Coopr 3.0
But…
640 x 640 p-median problem still consumes ~1 GB.
Pyomo Idioms 26
5. Nonlinear Problems
John D. Siirola
<VENUE>
<DATE>
Sandia National Laboratories is a multi-program laboratory managed and operated by Sandia Corporation, a wholly owned subsidiary of Lockheed Martin
Corporation, for the U.S. Department of Energy’s National Nuclear Security Administration under contract DE-AC04-94AL85000. SAND NO. 2011-XXXXP
Nonlinear problems are easy…
Pyomo Fundamentals 2
Nonlinear problems are easy…
… to write in Pyomo (correct formulation and solution is another story)
Pyomo Fundamentals 3
Nonlinear problems are easy…
… to write in Pyomo (correct formulation and solution is another story)
Agenda:
Introduction
Rosenbrock Example
Introduction to Scripting
Introduction to IPOPT
Recommendations for Nonlinear Problems
Formulation Matters Example
Exercises
Pyomo Fundamentals 4
Nonlinear: Supported expressions
model = ConcreteModel()
model.r = Var()
model.h = Var()
def surf_area_obj_rule(m):
return 2 * pi * m.r * (m.r + m.h)
model.surf_area_obj = Objective(rule=surf_area_obj_rule)
def vol_con_rule(m):
return pi * m.h * m.r**2 == 355
model.vol_con = Constraint(rule=vol_con_rule)
Pyomo Fundamentals 5
Nonlinear: Supported expressions
Caution: Always use the intrinsic functions that are part of the Pyomo package.
from pyomo.environ import * # imports, e.g., pyomo versions of exp, log, etc.)
from math import * # overrides the pyomo versions with math versions
Pyomo Fundamentals 6
Example: Rosenbrock function
Pyomo Fundamentals 7
Example: Rosenbrock function
model = ConcreteModel()
model.x = Var()
model.y = Var()
def rosenbrock(m):
return (1.0-m.x)**2 + 100.0*(m.y - m.x**2)**2
model.obj = Objective(rule=rosenbrock, sense=minimize)
Pyomo Fundamentals 8
Example: Rosenbrock function
# rosenbrock.py: A Pyomo model for the Rosenbrock problem
from pyomo.environ import *
model = ConcreteModel()
model.x = Var()
model.y = Var()
def rosenbrock(m):
return (1.0-m.x)**2 + 100.0*(m.y - m.x**2)**2
model.obj = Objective(rule=rosenbrock, sense=minimize)
…
Variables:
x : Size=1, Index=None, Domain=Reals
Key : Lower : Value : Upper : Fixed : Stale
None : None : 1.0 : None : False : False
y : Size=1, Index=None, Domain=Reals
Key : Lower : Value : Upper : Fixed : Stale
None : None : 1.0 : None : False : False
…
Pyomo Fundamentals 9
Example: Rosenbrock function
…
Variables:
x : Size=1, Index=None, Domain=Reals
Key : Lower : Value : Upper : Fixed : Stale
None : None : 1.0 : None : False : False
y : Size=1, Index=None, Domain=Reals
Key : Lower : Value : Upper : Fixed : Stale
None : None : 1.0 : None : False : False
…
Pyomo Fundamentals 10
Example: Scripting (Rosenbrock)
# rosenbrock_script.py: A Pyomo model for the Rosenbrock problem
from pyomo.environ import *
model = ConcreteModel()
model.x = Var()
model.y = Var()
def rosenbrock(m):
return (1.0-m.x)**2 + 100.0*(m.y - m.x**2)**2
model.obj = Objective(rule=rosenbrock, sense=minimize)
solver = SolverFactory('ipopt')
solver.solve(model, tee=True)
print()
print('*** Solution *** :')
print('x:', value(model.x))
print('y:', value(model.y))
Pyomo Fundamentals 11
Example: Scripting (Rosenbrock)
# rosenbrock_script.py: A Pyomo model for the Rosenbrock problem
from pyomo.environ import *
model = ConcreteModel()
model.x = Var()
model.y = Var()
def rosenbrock(m):
return (1.0-m.x)**2 + 100.0*(m.y - m.x**2)**2
model.obj = Objective(rule=rosenbrock, sense=minimize)
solver = SolverFactory('ipopt')
solver.solve(model, tee=True)
print()
print('*** Solution *** :')
print('x:', value(model.x))
print('y:', value(model.y))
Pyomo Fundamentals 12
Example: Scripting (Rosenbrock)
# rosenbrock_script.py: A Pyomo model for the Rosenbrock problem
from pyomo.environ import *
model = ConcreteModel()
model.x = Var()
model.y = Var()
def rosenbrock(m):
return (1.0-m.x)**2 + 100.0*(m.y - m.x**2)**2
model.obj = Objective(rule=rosenbrock, sense=minimize)
solver = SolverFactory('ipopt')
solver.solve(model, tee=True)
print()
print('*** Solution *** :')
print('x:', value(model.x))
print('y:', value(model.y))
Pyomo Fundamentals 13
Example: Scripting (Rosenbrock)
# rosenbrock_script.py: A Pyomo model for the Rosenbrock problem
from pyomo.environ import *
model = ConcreteModel()
model.x = Var()
model.y = Var()
def rosenbrock(m):
return (1.0-m.x)**2 + 100.0*(m.y - m.x**2)**2
model.obj = Objective(rule=rosenbrock, sense=minimize)
solver = SolverFactory('ipopt')
solver.solve(model, tee=True)
print()
print('*** Solution *** :')
print('x:', value(model.x))
print('y:', value(model.y))
Pyomo Fundamentals 14
Example: Scripting (Rosenbrock)
# rosenbrock_script.py: A Pyomo model for the Rosenbrock problem
from pyomo.environ import *
model = ConcreteModel()
model.x = Var()
model.y = Var()
def rosenbrock(m):
return (1.0-m.x)**2 + 100.0*(m.y - m.x**2)**2
model.obj = Objective(rule=rosenbrock, sense=minimize)
solver = SolverFactory('ipopt')
solver.solve(model, tee=True)
print()
print('*** Solution *** :')
print('x:', value(model.x))
print('y:', value(model.y))
python rosenbrock_script.py
Pyomo Fundamentals 15
Exercise: Scripting (looping over initial value)
Pyomo Fundamentals 16
Example: Scripting (loop over initial value)
# rosenbrock_script_loop.py: A Pyomo model for the Rosenbrock problem
from pyomo.environ import *
model = ConcreteModel()
model.x = Var()
model.y = Var()
def rosenbrock(m):
return (1.0-m.x)**2 + 100.0*(m.y - m.x**2)**2
model.obj = Objective(rule=rosenbrock, sense=minimize)
solver = SolverFactory('ipopt')
solver.solve(model)
Pyomo Fundamentals 17
Introduction to IPOPT
Objective Function
Equality Constraints
Inequality Constraints
Variable Bounds
Pyomo Fundamentals 18
Introduction to IPOPT
Cost/Profit, Measure of fit
Physics of the system
Physical, Performance,
Safety Constraints
Pyomo Fundamentals 19
Large Scale Optimization
Gradient Based Solution Techniques
Newton Step
Active-set Strategy
20/67
Interior Point Methods
Original NLP
Initialize
21/67
Effect of Barrier Term
Pyomo Fundamentals 22
Effect of Barrier Term
Pyomo Fundamentals 23
Effect of Barrier Term
Pyomo Fundamentals 24
Effect of Barrier Term
Pyomo Fundamentals 25
Effect of Barrier Term
Pyomo Fundamentals 26
Interior Point Methods
Original NLP
Initialize
Pyomo Fundamentals 28
IPOPT: Other Considerations
Regularization:
If certain convexity criteria are not satisfied at a current point, IPOPT
may need to regularize. (This can be seen in the output.)
We do NOT want to see regularization at the final iteration (solution).
Can be an indicator of poor conditioning.
Globalization:
IPOPT uses a filter-based line-search approach
Accepts the step if sufficient reduction is seen in objective or
constraint violation
Restoration Phase:
Minimize constraint violation
Regularized with distance from current point
Similar structure to original problem (reuse symbolic factorization)
Pyomo Fundamentals 29
IPOPT Algorithm Flowsheet
Initialize
NO
Calculate Step
Barrier NLP YES
Reduce µ Factor LS
Converged?
NO
YES
Inertia OK? Backsolve
Calculate Step
Direction NO
Iterative
Filter Adjust Refinement
Line Search
Pyomo Fundamentals 30
IPOPT Output
Pyomo Fundamentals 31
IPOPT Output
Pyomo Fundamentals 32
Exit Conditions
Successful Exit
Successful Exit with regularization at solution
Infeasible
Unbounded
Pyomo Fundamentals 33
Exit Conditions: Successful
x2
Decreasing
objective
x1
Pyomo Fundamentals 34
Exit Conditions: Successful
iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls
0 5.0000000e-01 2.50e-01 5.00e-01 -1.0 0.00e+00 - 0.00e+00 0.00e+00 0
1 2.4298076e-01 2.33e-01 7.67e-01 -1.0 5.20e-01 - 7.73e-01 9.52e-01h 1
2 2.6898113e-02 7.23e-05 4.09e-04 -1.7 2.16e-01 - 1.00e+00 1.00e+00h 1
3 1.8655807e-04 1.83e-04 7.86e-05 -3.8 2.68e-02 - 1.00e+00 9.97e-01f 1
4 1.8250072e-06 1.23e-12 2.22e-16 -5.7 1.85e-04 - 1.00e+00 1.00e+00h 1
5 -1.7494097e-08 8.48e-13 0.00e+00 -8.6 1.84e-06 - 1.00e+00 1.00e+00h 1
Number of Iterations....: 5
(scaled) (unscaled)
Objective...............: -1.7494096510367012e-08 -1.7494096510367012e-08
Dual infeasibility......: 0.0000000000000000e+00 0.0000000000000000e+00
Constraint violation....: 8.4843243541854463e-13 8.4843243541854463e-13
Complementarity.........: 2.5050549017950606e-09 2.5050549017950606e-09
Overall NLP error.......: 2.5050549017950606e-09 2.5050549017950606e-09
...
*** soln
x1 = 1.0
x2 = -1.7494096510367012e-08
Pyomo Fundamentals 35
Exit Conditions: Successful w/ Regularization
x2
Decreasing
objective
x1
Pyomo Fundamentals 36
Exit Conditions: Successful w/ Regularization
iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls
0 2.0000000e+00 1.00e+00 0.00e+00 -1.0 0.00e+00 - 0.00e+00 0.00e+00 0
1 1.0000000e+00 0.00e+00 1.00e-04 -1.7 1.00e+00 -4.0 1.00e+00 1.00e+00h 1
2 1.0000000e+00 0.00e+00 0.00e+00 -3.8 0.00e+00 0.9 1.00e+00 1.00e+00 0
3 1.0000000e+00 0.00e+00 0.00e+00 -5.7 0.00e+00 0.5 1.00e+00 1.00e+00T 0
4 1.0000000e+00 0.00e+00 0.00e+00 -8.6 0.00e+00 0.9 1.00e+00 1.00e+00T 0
Number of Iterations....: 4
(scaled) (unscaled)
Objective...............: 1.0000000000000000e+00 1.0000000000000000e+00
Dual infeasibility......: 0.0000000000000000e+00 0.0000000000000000e+00
Constraint violation....: 0.0000000000000000e+00 0.0000000000000000e+00
Complementarity.........: 2.5059035596800808e-09 2.5059035596800808e-09
Overall NLP error.......: 2.5059035596800808e-09 2.5059035596800808e-09
...
*** soln
x1 = 0.0
x2 = 1.0
Pyomo Fundamentals 37
Exit Conditions: Infeasible
x2
Decreasing
objective
x1
Pyomo Fundamentals 38
Exit Conditions: Infeasible
iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls
...
5 2.0000016e+00 1.00e+00 4.74e+03 -1.0 3.47e+01 - 2.79e-02 4.16e-04h 7
6r 2.0000016e+00 1.00e+00 1.00e+03 0.0 0.00e+00 - 0.00e+00 4.44e-07R 3
7r 2.0010000e+00 1.01e+00 1.74e+02 0.0 8.73e-02 - 1.00e+00 1.00e+00f 1
8r 2.0010010e+00 1.00e+00 1.32e-03 0.0 8.73e-02 - 1.00e+00 1.00e+00f 1
9r 2.0000080e+00 1.00e+00 5.18e-03 -2.1 6.12e-03 - 9.94e-01 9.99e-01h 1
iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls
10r 2.0000000e+00 1.00e+00 3.73e-06 -4.7 7.99e-06 - 1.00e+00 1.00e+00f 1
11r 2.0000000e+00 1.00e+00 1.79e-07 -7.1 2.85e-08 - 1.00e+00 1.00e+00f 1
Number of Iterations....: 11
(scaled) (unscaled)
Objective...............: 1.9999999800009090e+00 1.9999999800009090e+00
Dual infeasibility......: 1.0000000002321485e+00 1.0000000002321485e+00
Constraint violation....: 9.9999998000090895e-01 9.9999998000090895e-01
Complementarity.........: 9.0909091652062654e-10 9.0909091652062654e-10
Overall NLP error.......: 9.9999998000090895e-01 1.0000000002321485e+00
...
*** soln
x1 = -6.353194883662875e-12
x2 = 2.0
Pyomo Fundamentals 39
Exit Conditions: Unbounded
Decreasing
objective
x1
Pyomo Fundamentals 40
Exit Conditions: Unbounded
iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls
...
45 -2.2420218e+11 1.00e+04 1.00e+00 -1.7 1.25e+19 -19.1 3.55e-08 7.11e-15f 48
46 -2.2420225e+11 1.00e+04 1.00e+00 -1.7 3.75e+19 -19.6 1.20e-08 1.78e-15f 50
47 -2.2420229e+11 1.00e+04 1.00e+00 -1.7 1.25e+19 -19.1 1.00e+00 3.55e-15f 49
48 -3.7503956e+19 1.57e+27 8.36e+09 -1.7 3.75e+19 -19.6 1.18e-08 1.00e+00w 1
49 -1.3750923e+20 3.92e+26 2.09e+09 -1.7 1.00e+20 -20.0 1.00e+00 1.00e+00w 1
Number of Iterations....: 49
(scaled) (unscaled)
Objective...............: -1.3750923074037683e+20 -1.3750923074037683e+20
Dual infeasibility......: 2.0888873315629249e+09 2.0888873315629249e+09
Constraint violation....: 3.9209747283936173e+26 3.9209747283936173e+26
Complementarity.........: 3.1115099971882619e+03 3.1115099971882619e+03
Overall NLP error.......: 3.9209747283936173e+26 3.9209747283936173e+26
*** soln
x1 = 0.5
x2 = 0.5
Pyomo Fundamentals 41
IPOPT Options
Solver options can be set through scripts (and the pyomo command line)
print_options_documentation yes
Outputs the complete set of IPOPT options (with documentation and their defaults)
mu_init
Sets the initial value of the barrier parameter
Can be helpful to make this smaller when initial guesses are known to be good
bounds_push
By default, IPOPT pushes the bounds a little further out.
This can be set to remove this behavior
E.g., sqrt(x), x>= 0
linear_solver
Set the linear solver that will be used for the KKT system
Significantly better performance with HSL (MA27) over default MUMPS
print_user_options
Print options set and whether or not they were used
Helpful to detect mismatched options
Pyomo Fundamentals 42
IPOPT Options
# rosenbrock_options.py: A Pyomo model for the Rosenbrock problem
from pyomo.environ import *
model = ConcreteModel()
model.x = Var()
model.y = Var()
def rosenbrock(m):
return (1.0-m.x)**2 + 100.0*(m.y - m.x**2)**2
model.obj = Objective(rule=rosenbrock, sense=minimize)
solver = SolverFactory('ipopt')
solver.options['mu_init'] = 1e-4
solver.options['print_user_options'] = 'yes'
solver.options['ma27_pivtol'] = 1e-4
solver.solve(model, tee=True)
print()
print('*** Solution *** :')
print('x:', value(model.x))
print('y:', value(model.y))
Pyomo Fundamentals 43
IPOPT Options
ma27_pivtol=0.0001
print_user_options=yes
mu_init=0.0001
ma27_pivtol=0.0001
print_user_options=yes
mu_init=0.0001
******************************************************************************
This program contains Ipopt, a library for large-scale nonlinear optimization.
Ipopt is released as open source code under the Eclipse Public License (EPL).
For more information visit http://projects.coin-or.org/Ipopt
******************************************************************************
NOTE: You are using Ipopt by default with the MUMPS linear solver.
Other linear solvers might be more efficient (see Ipopt documentation).
Pyomo Fundamentals 44
Modeling Tips
Variable Initialization
Proper initialization of nonlinear problems can be critical for effective
solution.
Strategies include:
Using understood physics or past successful solutions
Solving simpler problem(s) first, progressing to more difficult
Undefined Evaluations
Many mathematical functions have a valid domain, and evaluation outside
that domain causes errors
Add appropriate bounds to variables to keep them inside valid domain
Note that solvers use first and second derivatives. While sqrt(x) is valid at x=0,
1/sqrt(x) is not
Problem Scaling
Scale model to avoid variables, constraints, derivatives with different scales.
Formulation Matters!
Pyomo Fundamentals 45
6. Structured Modeling &
Transformations
John D. Siirola
<VENUE>
<DATE>
Sandia National Laboratories is a multi-program laboratory managed and operated by Sandia Corporation, a wholly owned subsidiary of Lockheed Martin
Corporation, for the U.S. Department of Energy’s National Nuclear Security Administration under contract DE-AC04-94AL85000. SAND NO. 2011-XXXXP
Is this an optimization model?
min cT x
s.t. Ax b
x n
max abs( x 3)
s.t. [...]
Model Transformations
Project from one problem space to another
Standardize common reformulations or approximations
Convert “unoptimizable” modeling constructs into equivalent
optimizable forms
Transform
Solve
Yik Yki
t t t t t t t t
i mJ (i ) im k mJ ( k ) km k mJ ( k ) km i mJ (i ) im
m j m j m j m j
j Cik , i, k I , i k
Yik Yki
t t t t t t t t t t
i mJ (i ) im ij k mJ ( k ) km k mJ ( k ) km kj i mJ (i ) im
m j m j m j m j
j Cik , i, k I , i k
Structured Modeling & Transformations 17
Solving disjunctive models
Few solvers “understand” disjunctive models
Transform model into standard math program
Big-M relaxation:
Convert logic variables to binary
Split equality constraints in disjuncts into pairs of inequality constraints
Relax all constraints in the disjuncts with “appropriate” M values
Algorithmic approaches
e.g., Trespalacios and Grossmann (submitted 2013)
Prematurely choosing one relaxation makes trying others difficult
Equilibrium Constraints
Variational inequalities
Complementarity conditions
Optimality conditions (for bilevel problems)
min 𝑓 𝑥
s.t. ℎ 𝑥 =0
𝑎𝑖 ≤ 𝜔𝑖 ≤ 𝑏𝑖 𝑖 = 1…𝑚
𝜔𝑖 = 𝑤𝑖 𝑥 𝑖 = 1…𝑚
𝜔𝑖 − 𝑎𝑖 𝑣𝑖 𝑥 ≤ 0 𝑖 = 1…𝑚
𝜔𝑖 − 𝑏𝑖 𝑣𝑖 𝑥 ≤ 0 𝑖 = 1…𝑚
NOTE: There are serious difficulties with solving this
formulation as standard stability assumptions are not met.
But other nonlinear transformations exist!
min 𝑓 𝑥
s.t. ℎ 𝑥 =0
𝑦1,𝑖 𝑦2,𝑖 𝑦3,𝑖
𝑤𝑖 𝑥 = 𝑎𝑖 ∨ 𝑤𝑖 𝑥 = 𝑏𝑖 ∨ 𝑎𝑖 < 𝑤𝑖 𝑥 < 𝑏𝑖 𝑖 = 1…𝑚
𝑣𝑖 𝑥 ≥ 0 𝑣𝑖 𝑥 ≤ 0 𝑣𝑖 𝑥 = 0
𝑦1,𝑖 + 𝑦2,𝑖 + 𝑦3,𝑖 = 1 𝑖 = 1…𝑚
𝑦1,𝑖 , 𝑦2,𝑖 , 𝑦3,𝑖 ∈ 0,1 𝑖 = 1…𝑚
Chaining transformations
f x x f x x
f x x x x x x x x
f abs( x) x x x Y Y x
My
x 0 x 0
x 0 x 0 x M (1 y )
x 0, x 0 x 0, x 0
Stochastic programming
Deterministic Scenario
Scenario Data
Data Stochastic
Model + Scenario
ScenarioData
ScenarioData
ScenarioData
Data
Model
Scenario
ScenarioData
Data
Bilevel models
Upper-level Model Standard Math
Programming Model
Lower-level Model
DAE models
Discretized
DAE Model Algebraic Model
<VENUE>
<DATE>
Sandia National Laboratories is a multi-program laboratory managed and operated by Sandia Corporation, a wholly owned subsidiary of Lockheed Martin
Corporation, for the U.S. Department of Energy’s National Nuclear Security Administration under contract DE-AC04-94AL85000. SAND NO. 2011-XXXXP
Extending the Pyomo environment
What about models that are not strictly math programs?
Dynamic systems
Dynamic Systems 2
Examples of Dynamic Optimization
Parameter Estimation
Nonlinear model predictive control
Batch process operation
Reactor design
min ( x(t ), y (t ), u (t ))
x (t ) f ( x(t ), y (t ), u (t ), t , p )
DAE 0 g ( x(t ), y (t ), u (t ), t , p )
model x(t ) n
y (t ) n
u (t ) m
x: State (differential) variables
u: Control (input) variables
y: Algebraic variables
Dynamic Systems 3
Solution Approaches
[Figure from L.T. Biegler (2007)]
Pontryagin(1962)
Dynamic Systems 4
Sequential Approach
[Figure from M. Diehl]
Dynamic Systems 5
Simultaneous Approach
[Figure from L.T. Biegler (2007)]
Dynamic Systems 6
Full Discretization
Finite Difference Methods
Forward Difference 𝑑𝑓 𝑓 𝑡 + ℎ − 𝑓(𝑡)
(𝑡) =
𝑑𝑓 𝑓 𝑡 + ℎ − 𝑓(𝑡) 𝑑𝑡 ℎ
(𝑡) = lim
𝑑𝑡 ℎ→0 ℎ Backward Difference 𝑑𝑓 𝑓 𝑡 − 𝑓(𝑡 − ℎ)
(𝑡) =
𝑑𝑡 ℎ
Collocation over finite elements
Dynamic Systems 7
Simple Example
𝑑𝑧
= 𝑧 2 − 2𝑧 + 1, 𝑧 0 = −3
𝑑𝑡
𝑑𝑓 𝑓 𝑡 − 𝑓(𝑡 − ℎ)
Backward Difference (𝑡) =
𝑑𝑡 ℎ
Dynamic Systems 8
Simple Example – Exercise Solution
Solve the differential equation using a backward finite
difference scheme
from pyomo.environ import *
numpoints = 10
model = m = ConcreteModel()
m.points = RangeSet(0,numpoints)
m.h = Param(initialize=1.0/numpoints)
m.z = Var(m.points)
m.dzdt = Var(m.points)
m.obj = Objective(expr=1) # Dummy Objective
def _zdot(m, i):
return m.dzdt[i] == m.z[i]**2 - 2*m.z[i] + 1
m.zdot = Constraint(m.points, rule=_zdot)
def _back_diff(m,i):
if i == 0:
return Constraint.Skip
return m.dzdt[i] == (m.z[i]-m.z[i-1])/m.h
m.back_diff = Constraint(m.points, rule=_back_diff)
def _init_con(m):
return m.z[0] == -3
m.init_con = Constraint(rule=_init_con)
Dynamic Systems 9
Collocation over finite elements
x x x x x x
element n k=2 x
x x k=1 x
x x
K
y(t) = å (t )yik K
u(t) = å (t )uik
ik
K
z(t) = å ik (t )zik
k=1 ik
k=1
k=0
Algebraic and
Differential variables Control variables
Continuous Dynamic Systems Discontinuous 10
Collocation over finite elements
Given:
Dynamic Systems 11
Collocation points
Dynamic Systems 12
Simple Example - Collocation
Dynamic Systems 13
Simple Example - Collocation
(τ − 𝜏1 )(𝜏 − 𝜏2 )(𝜏 − 𝜏3 )
ℓ0 τ = = 𝑎3 𝜏 3 + 𝑎2 𝜏 2 + 𝑎1 𝜏 + 𝑎0
(𝜏0 − 𝜏1 )(𝜏0 − 𝜏2 )(𝜏0 − 𝜏3 )
ℓ0 𝜏 = −10𝜏 3 + 18𝜏 2 − 9𝜏 + 1
ℓሶ 0 𝜏 = −30𝜏 2 + 36𝜏 − 9
Dynamic Systems 14
Simple Example - Collocation
Dynamic Systems 15
Collocation Matrix
Constant
Dynamic Systems 16
Python code for generating collocation matrix
import numpy
# Specify collocation points
cp = [0, 0.155051, 0.644949, 1]
a = []
for i in range(len(cp)):
ptmp = []
tmp = 0
for j in range(len(cp)):
if j != i:
row = []
row.insert(0,1/(cp[i]-cp[j]))
row.insert(1,-cp[j]/(cp[i]-cp[j]))
ptmp.insert(tmp,row)
tmp += 1
p=[1]
for j in range(len(cp)-1):
p = numpy.convolve(p,ptmp[j])
pder = numpy.polyder(p,1)
arow = []
for j in range(len(cp)):
arow.append(numpy.polyval(pder,cp[j]))
a.append(arow)
print(arow)
Dynamic Systems 17
Simple Example - Collocation
𝑑𝑧
= 𝑧 2 − 2𝑧 + 1, 𝑧 0 = −3
𝑑𝑡
Exercise: Solve the differential equation using collocation over
a single finite element with 𝑡 ∈ [0,1]
Collocation
Equations
Dynamic Systems 18
Implementation is challenging!
Common theme: significant effort to rework formulation
Time: first ~6 months of a grad student’s research
Error prone: many ways to make subtle mistakes
Inflexible: formulation specific to selected solution approach
Dynamic Systems 19
Expressing dynamical systems
[with J. Siirola, V. Zavala]
Model dynamical systems in a natural form
Systems of Differential Algebraic Equations (DAE)
Extend the Pyomo component model
ContinuousSet: A virtual set over which you can take a derivative
DerivativeVar: The derivative of a Var with respect to a ContinuousSet
min ( x(t ), y (t ), u (t ))
x (t ) f ( x(t ), y (t ), u (t ), t , p )
DAE 0 g ( x(t ), y (t ), u (t ), t , p )
model x(t ) n
y (t ) n
u (t ) m
Dynamic Systems 20
Simple Example – pyomo.dae
Dynamic Systems 21
Solving dynamical systems
Given that we have a DAE model in Pyomo… now what?
How to optimize?
Simulation-based / Multiple shooting methods / Simultaneous
Common theme: significant effort to rework formulation
Time / Error prone / Inflexible
Our approach: separate the declaration of dynamical models from the
solution approach using (nearly) automatic transformations
Dynamic Systems 22
Simple Example – pyomo.dae
from pyomo.environ import *
from pyomo.dae import *
model = m = ConcreteModel()
m.t = ContinuousSet(bounds=(0, 1))
m.z = Var(m.t)
m.dzdt = DerivativeVar(m.z, wrt=m.t)
m.obj = Objective(expr=1) # Dummy Objective
def _zdot(m, t):
return m.dzdt[t] == m.z[t]**2 - 2*m.z[t] + 1
m.zdot = Constraint(m.t, rule=_zdot)
def _init_con(m):
return m.z[0] == -3
m.init_con = Constraint(rule=_init_con)
Dynamic Systems 23
Small example: optimal control (1/8)
from pyomo.environ import *
from pyomo.dae import *
model = m = ConcreteModel()
m.tf = Param(initialize = 1)
m.t = ContinuousSet(bounds=(0, m.tf))
m.u = Var(m.t, initialize=0)
m.x1 = Var(m.t)
m.x2 = Var(m.t)
m.x3 = Var(m.t)
m.dx1dt = DerivativeVar(m.x1, wrt=m.t)
m.dx2dt = DerivativeVar(m.x2, wrt=m.t)
m.dx3dt = DerivativeVar(m.x3, wrt=m.t)
m.obj = Objective(expr=m.x3[m.tf])
def _x1dot(m, t):
return m.dx1dt[t] == m.x2[t]
m.x1dot = Constraint(m.t, rule=_x1dot)
def _x2dot(m, t):
return m.dx2dt[t] == -m.x2[t] + m.u[t]
m.x2dot = Constraint(m.t, rule=_x2dot)
def _x3dot(m, t):
return m.dx3dt[t] == m.x1[t]**2 + \
m.x2[t]**2 + 0.005*m.u[t]**2
m.x3dot = Constraint(m.t, rule=_x3dot)
def _con(m, t):
return m.x2[t] - 8*(t-0.5)**2 + 0.5 <= 0
m.con = Constraint(m.t, rule=_con)
[Jacobson and Lele (1969)]
def _init(m):
yield m.x1[0] == 0
yield m.x2[0] == -1
yield m.x3[0] == 0
m.init_conditions = ConstraintList(rule=_init)
Dynamic Systems 24
Small example: optimal control (2/8)
from pyomo.environ import *
from pyomo.dae import *
model = m = ConcreteModel()
m.tf = Param(initialize = 1)
m.t = ContinuousSet(bounds=(0, m.tf))
m.u = Var(m.t, initialize=0)
m.x1 = Var(m.t)
m.x2 = Var(m.t)
m.x3 = Var(m.t)
from pyomo.environ import *
from pyomo.dae import * wrt=m.t)
m.dx1dt = DerivativeVar(m.x1, wrt=m.t)
m.dx2dt = DerivativeVar(m.x2,
m.dx3dt = DerivativeVar(m.x3, wrt=m.t)
m.obj = Objective(expr=m.x3[m.tf])
def _x1dot(m, t):
return m.dx1dt[t] == m.x2[t]
m.x1dot = Constraint(m.t, rule=_x1dot)
def _x2dot(m, t):
return m.dx2dt[t] == -m.x2[t] + m.u[t]
m.x2dot = Constraint(m.t, rule=_x2dot)
def _x3dot(m, t):
return m.dx3dt[t] == m.x1[t]**2 + \
m.x2[t]**2 + 0.005*m.u[t]**2
m.x3dot = Constraint(m.t, rule=_x3dot)
def _con(m, t):
return m.x2[t] - 8*(t-0.5)**2 + 0.5 <= 0
m.con = Constraint(m.t, rule=_con)
[Jacobson and Lele (1969)]
def _init(m):
yield m.x1[0] == 0
yield m.x2[0] == -1
yield m.x3[0] == 0
m.init_conditions = ConstraintList(rule=_init)
Dynamic Systems 25
Small example: optimal control (3/8)
from pyomo.environ import *
from pyomo.dae import *
model = m = ConcreteModel()
m.tf = Param(initialize = 1)
m.t = ContinuousSet(bounds=(0, m.tf))
m.u = Var(m.t, initialize=0)
m.x1 = Var(m.t)
m.x2 = Var(m.t)
m.x3 = Var(m.t)
model = m = ConcreteModel()
m.dx1dt = DerivativeVar(m.x1, wrt=m.t)
m.tf = Param(initialize = 1)
m.dx2dt = DerivativeVar(m.x2, wrt=m.t)
m.dx3dt = DerivativeVar(m.x3, wrt=m.t)
m.t = ContinuousSet(bounds=(0, m.tf))
m.obj = Objective(expr=m.x3[m.tf])
def _x1dot(m, t):
return m.dx1dt[t] == m.x2[t]
m.x1dot = Constraint(m.t, rule=_x1dot)
def _x2dot(m, t):
return m.dx2dt[t] == -m.x2[t] + m.u[t]
m.x2dot = Constraint(m.t, rule=_x2dot)
def _x3dot(m, t):
return m.dx3dt[t] == m.x1[t]**2 + \
m.x2[t]**2 + 0.005*m.u[t]**2
m.x3dot = Constraint(m.t, rule=_x3dot)
def _con(m, t):
return m.x2[t] - 8*(t-0.5)**2 + 0.5 <= 0
m.con = Constraint(m.t, rule=_con)
[Jacobson and Lele (1969)]
def _init(m):
yield m.x1[0] == 0
yield m.x2[0] == -1
yield m.x3[0] == 0
m.init_conditions = ConstraintList(rule=_init)
Dynamic Systems 26
Small example: optimal control (4/8)
from pyomo.environ import *
from pyomo.dae import *
model = m = ConcreteModel()
m.tf = Param(initialize = 1)
m.t = ContinuousSet(bounds=(0, m.tf))
m.u = Var(m.t, initialize=0)
m.x1 = Var(m.t)
m.x2 = Var(m.t)
m.x3 = Var(m.t)
m.dx1dt = DerivativeVar(m.x1, wrt=m.t)
m.dx2dt = DerivativeVar(m.x2, wrt=m.t)
m.dx3dt = DerivativeVar(m.x3, wrt=m.t)
m.obj = Objective(expr=m.x3[m.tf])
def _x1dot(m, t):
return m.dx1dt[t] == m.x2[t]
m.x1dot = Constraint(m.t, rule=_x1dot)
m.u = Var(m.t, initialize=0)
def _x2dot(m, t):
m.x1 = Var(m.t) return m.dx2dt[t] == -m.x2[t] + m.u[t]
m.x2dot = Constraint(m.t, rule=_x2dot)
m.x2 = Var(m.t)
def _x3dot(m, t):
m.x3 = Var(m.t) return m.dx3dt[t] == m.x1[t]**2 + \
m.x2[t]**2 + 0.005*m.u[t]**2
m.x3dot = Constraint(m.t, rule=_x3dot)
m.dx1dt = DerivativeVar(m.x1,
def _con(m, t): wrt=m.t)
m.dx2dt = DerivativeVar(m.x2, wrt=m.t)
return m.x2[t] - 8*(t-0.5)**2 + 0.5 <= 0
m.con = Constraint(m.t, rule=_con)
m.dx3dt
[Jacobson and Lele (1969)] = DerivativeVar(m.x3, wrt=m.t)
def _init(m):
yield m.x1[0] == 0
yield m.x2[0] == -1
yield m.x3[0] == 0
m.init_conditions = ConstraintList(rule=_init)
Dynamic Systems 27
Small example: optimal control (5/8)
from pyomo.environ import *
from pyomo.dae import *
model = m = ConcreteModel()
m.tf = Param(initialize = 1)
m.t = ContinuousSet(bounds=(0, m.tf))
m.u = Var(m.t, initialize=0)
m.x1 = Var(m.t)
m.x2 = Var(m.t)
m.x3 = Var(m.t)
m.dx1dt = DerivativeVar(m.x1, wrt=m.t)
m.dx2dt = DerivativeVar(m.x2, wrt=m.t)
m.dx3dt = DerivativeVar(m.x3, wrt=m.t)
m.obj = Objective(expr=m.x3[m.tf])
def _x1dot(m, t):
return m.dx1dt[t] == m.x2[t]
m.x1dot = Constraint(m.t, rule=_x1dot)
m.obj = Objective(expr=m.x3[m.tf])
def _x2dot(m, t):
return m.dx2dt[t] == -m.x2[t] + m.u[t]
m.x2dot = Constraint(m.t, rule=_x2dot)
def _x3dot(m, t):
return m.dx3dt[t] == m.x1[t]**2 + \
m.x2[t]**2 + 0.005*m.u[t]**2
m.x3dot = Constraint(m.t, rule=_x3dot)
def _con(m, t):
return m.x2[t] - 8*(t-0.5)**2 + 0.5 <= 0
m.con = Constraint(m.t, rule=_con)
[Jacobson and Lele (1969)]
def _init(m):
yield m.x1[0] == 0
yield m.x2[0] == -1
yield m.x3[0] == 0
m.init_conditions = ConstraintList(rule=_init)
Dynamic Systems 28
Small example: optimal control (6/8)
from pyomo.environ import *
from pyomo.dae import *
def _x3dot(m, t): model = m = ConcreteModel()
return m.dx3dt[t]m.tf
m.t
= Param(initialize = 1)
== m.x1[t]**2 + \ m.tf))
= ContinuousSet(bounds=(0,
m.x2[t]**2 + 0.005*m.u[t]**2
m.u = Var(m.t, initialize=0)
m.x3dot = Constraint(m.t,
m.x1
m.x2
= rule=_x3dot)
Var(m.t)
= Var(m.t)
m.x3 = Var(m.t)
m.dx1dt = DerivativeVar(m.x1, wrt=m.t)
m.dx2dt = DerivativeVar(m.x2, wrt=m.t)
m.dx3dt = DerivativeVar(m.x3, wrt=m.t)
m.obj = Objective(expr=m.x3[m.tf])
def _x1dot(m, t):
return m.dx1dt[t] == m.x2[t]
m.x1dot = Constraint(m.t, rule=_x1dot)
def _x2dot(m, t):
return m.dx2dt[t] == -m.x2[t] + m.u[t]
m.x2dot = Constraint(m.t, rule=_x2dot)
def _x3dot(m, t):
return m.dx3dt[t] == m.x1[t]**2 + \
m.x2[t]**2 + 0.005*m.u[t]**2
m.x3dot = Constraint(m.t, rule=_x3dot)
def _con(m, t):
return m.x2[t] - 8*(t-0.5)**2 + 0.5 <= 0
m.con = Constraint(m.t, rule=_con)
[Jacobson and Lele (1969)]
def _init(m):
yield m.x1[0] == 0
yield m.x2[0] == -1
yield m.x3[0] == 0
m.init_conditions = ConstraintList(rule=_init)
Dynamic Systems 29
Small example: optimal control (7/8)
from pyomo.environ import *
from pyomo.dae import *
model = m = ConcreteModel()
m.tf = Param(initialize = 1)
m.t = ContinuousSet(bounds=(0, m.tf))
def _con(m,t):
return m.x2[t] - 8*(t-0.5)**2
m.u
m.x1 + 0.5 <= 0
= Var(m.t, initialize=0)
= Var(m.t)
m.con = Constraint(m.t,
m.x2 rule=_con)
m.x3
= Var(m.t)
= Var(m.t)
m.dx1dt = DerivativeVar(m.x1, wrt=m.t)
m.dx2dt = DerivativeVar(m.x2, wrt=m.t)
m.dx3dt = DerivativeVar(m.x3, wrt=m.t)
m.obj = Objective(expr=m.x3[m.tf])
def _x1dot(m, t):
return m.dx1dt[t] == m.x2[t]
m.x1dot = Constraint(m.t, rule=_x1dot)
def _x2dot(m, t):
return m.dx2dt[t] == -m.x2[t] + m.u[t]
m.x2dot = Constraint(m.t, rule=_x2dot)
def _x3dot(m, t):
return m.dx3dt[t] == m.x1[t]**2 + \
m.x2[t]**2 + 0.005*m.u[t]**2
m.x3dot = Constraint(m.t, rule=_x3dot)
def _con(m, t):
return m.x2[t] - 8*(t-0.5)**2 + 0.5 <= 0
m.con = Constraint(m.t, rule=_con)
[Jacobson and Lele (1969)]
def _init(m):
yield m.x1[0] == 0
yield m.x2[0] == -1
yield m.x3[0] == 0
m.init_conditions = ConstraintList(rule=_init)
Dynamic Systems 30
Small example: optimal control (8/8)
from pyomo.environ import *
from pyomo.dae import *
model = m = ConcreteModel()
m.tf = Param(initialize = 1)
def _init(m): m.t = ContinuousSet(bounds=(0, m.tf))
Dynamic Systems 31
Optimal Control Example - Script
from pyomo.environ import *
# Import dynamic model
from optimalControl import m
Dynamic Systems 32
Optimal Control Example - Results
Dynamic Systems 33
Optimal Control Example - Script
from pyomo.environ import *
# Import dynamic model
from optimalControl import m
Dynamic Systems 34
Optimal Control Example - Results 2
Dynamic Systems 35
Parameter Estimation Example 1
2
min 𝑥1 𝑡𝑖 − 𝑥1 𝑚𝑒𝑎𝑠 𝑡𝑖
𝑡𝑖
𝑑𝑥1
𝑠. 𝑡. = 𝑥2
𝑑𝑡
𝑑𝑥2
= 1 − 2𝑥2 − 𝑥1
𝑑𝑡
−1.5 ≤ 𝑝1 , 𝑝2 ≤ 1.5
𝑥1 0 = 𝑝1 , 𝑥2 0 = 𝑝2
Time 1 2 3 5
𝑥1 𝑚𝑒𝑎𝑠 0.264 0.594 0.801 0.959
Dynamic Systems 36
Parameter Estimation Example 1
data file
set t := 0 1 2 3 5 6 ;
set MEAS_t := 1 2 3 5 ;
param x1_meas :=
1 0.264
2 0.594
3 0.801
5 0.959
;
Dynamic Systems 37
Parameter Estimation Example 2
𝑘1 𝑘2
𝐴 →𝐵→𝐶
𝑑𝐴
= −𝑘1 𝐴
𝑑𝑡
𝑑𝐵
= 𝑘1 𝐴 − 𝑘2 𝐵
𝑑𝑡
𝐴 0 = 1, 𝐵 0 =0
Time 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1.0
A 0.606 0.368 0.223 0.135 0.082 0.050 0.030 0.018 0.011 0.007
B 0.373 0.564 0.647 0.669 0.656 0.624 0.583 0.539 0.494 0.451
Dynamic Systems 38
Disease Transmission Example
Parameter estimation of a S-I-R disease transmission model[*]
Discretized problem:
- 3 differential equations
- 520 finite elements
- 3 collocation points
~ 10,500 variables
~ 10,000 constraints
Dynamic Systems 39
Performance impact
Comparing the automated discretization to a manually
discretized model implemented (and tuned) by a person
Manual Using pyomo.dae
Discretization (Radau Collocation)
Model Creation Time
1.79 5.29
(CPU secs)
Solve Time
1.35 0.86
(CPU secs)
IPOPT Iterations 27 26
Objective (x10-5) 1.4716 1.4716
Dynamic Systems 40
Distillation Example
model.S_TRAYS = Set()
model.S_RECTIFICATION = Set(within = model.S_TRAYS)
model.S_STRIPPING = Set(within = model.S_TRAYS)
model.t = ContinuousSet(initialize=range(1,52))
model.x = Var(model.S_TRAYS, model.t, initialize=x_init_rule)
model.dx = DerivativeVar(model.x)
def _diffeq(m,n,t):
if t == 1:
return Constraint.Skip
if n == 1:
return m.dx[n,t] == 1/m.acond*m.V[t]*(m.y[n+1,t]-m.x[n,t])
elif n in m.S_RECTIFICATION:
return m.dx[n,t] == 1/m.atray*(m.L[t]*(m.x[n-1,t]-m.x[n,t])-m.V[t]*(m.y[n,t]-m.y[n+1,t]))
elif n == 17:
return m.dx[n,t] == 1/m.atray*(m.Feed*m.x_Feed+m.L[t]*m.x[n-1,t]-m.FL[t]*m.x[n,t]- \
m.V[t]*(m.y[n,t]-m.y[n+1,t]))
elif n in m.S_STRIPPING:
return m.dx[n,t] == 1/m.atray*(m.FL[t]*(m.x[n-1,t]-m.x[n,t])-m.V[t]*(m.y[n,t]-m.y[n+1,t]))
else :
return m.dx[n,t] == 1/m.areb*(m.FL[t]*m.x[n-1,t]-(m.Feed-m.D)*m.x[n,t]-m.V[t]*m.y[n,t])
model.diffeq = Constraint(model.S_TRAYS, model.t, rule=_diffeq)
Dynamic Systems 41
PDE Example
Illustrative example[1]
PDE
2
2
𝜕𝑢 𝜕 𝑢
𝜋 =
𝜕𝑡 𝜕𝑥 2
Initial Condition
𝑢 𝑥, 0 = sin(𝜋𝑥)
Boundary Conditions
𝑢 0, 𝑡 = 0
−𝑡
𝜕𝑢
𝜋𝑒 + 1, 𝑡 = 0
𝜕𝑥
[1] Example 1 from http://www.mathworks.com/help/matlab/ref/pdepe.html
Dynamic Systems 42
PDE Example
𝜕𝑢 𝜕2𝑢 𝜕𝑢
𝜋2 = 𝑢 𝑥, 0 = sin(𝜋𝑥) 𝑢 0, 𝑡 = 0 𝜋𝑒 −𝑡 + 1, 𝑡 = 0
𝜕𝑡 𝜕𝑥 2 𝜕𝑥
Dynamic Systems 43
PDE Example
𝜕𝑢 𝜕 𝜕𝑢
𝜋2 =
𝜕𝑡 𝜕𝑥 𝜕𝑥
𝑢 𝑥, 0 = sin(𝜋𝑥)
𝑢 0, 𝑡 = 0
−𝑡
𝜕𝑢
𝜋𝑒 + 1, 𝑡 = 0
𝜕𝑥
Dynamic Systems 44
PDE Example
Dynamic Systems 45
Upcoming Features
Interface to integrator/DAE solver for:
Model simulation
Model initialization
Implementation of multiple shooting
Interpolation tools for:
Model initialization
Dynamic Systems 46
Building Expert Frameworks with pyomo.dae
Dynamic Systems 47
Nonlinear Model Predictive Control
[Control frameworks developed by Federico Lozano Santamaría Universidad de los Andes, Bogotá, Colombia]
Dynamic Systems
Reaction Kinetics
𝑘1 𝑘2
Chemical reaction kinetics: 2𝐴 → 𝐵; 𝐵 → 𝐶
𝐸𝑎
Reaction rate: 𝑟1 = 𝑘1 𝑐𝐴2 𝑘1 = 𝐴1 𝑒 𝑅⋅𝑇
𝐸𝑎
𝑟2 = 𝑘2 𝑐𝐵 𝑘2 = 𝐴 2 𝑒 𝑅⋅𝑇
Stoichiometry 𝑑𝑐𝐴
= −2𝑟1 𝑘1
𝑑𝑥
𝑑𝑐𝐵
= 𝑟1 𝑘1 − 𝑟2 𝑘2
𝑑𝑥
𝑑𝑐𝐶
= 𝑟2 𝑘2
𝑑𝑥
Example from: http://www.comsol.com/blogs/general-introduction-chemical-kinetics-arrhenius-law/
Dynamic Systems 49
General purpose kinetic model
def create_kinetic_model(rxnNet, time):
model = ConcreteModel()
model.SPECIES = Set( initialize=rxnNet.species() )
model.REACTIONS = Set( initialize=rxnNet.reactions.keys() )
model.TIME = ContinuousSet( bounds=(0,max(time)), initialize=time )
model.c = Var( model.TIME, model.SPECIES, bounds=(0,None) )
model.dcdt = DerivativeVar( model.c, wrt=model.TIME )
model.k = Var( model.REACTIONS, bounds=(0,None) )
model.rate = Var( model.TIME, model.REACTIONS )
def reaction_rate(m, t, r):
rhs = m.k[r]
for s, coef in iteritems(m.rxnNetwork.reactions[r].reactants):
rhs *= m.c[t,s]**coef
return m.rate[t,r] == rhs
model.reaction_rate = Constraint( model.TIME, model.REACTIONS, rule=reaction_rate )
def stoichiometry(m, t, s):
rhs = 0
for r in m.REACTIONS:
if s in m.rxnNetwork.reactions[r].reactants:
rhs -= m.rate[t,r] * m.rxnNetwork.reactions[r].reactants[s]
if s in m.rxnNetwork.reactions[r].products:
rhs += m.rate[t,r] * m.rxnNetwork.reactions[r].products[s]
return m.dcdt[t,s] == rhs
model.stoichiometry = Constraint( model.TIME, model.SPECIES, rule=stoichiometry )
return model
Dynamic Systems 50
Step 1: simulation
fdiff = TransformationFactory("dae.finite_difference")
rxns = ReactionNetwork()
rxns.add( Reaction("AtoB", reactants=['2*A'], products=['B']) )
rxns.add( Reaction("BtoC", reactants=['B'], products=['C']) )
A1 = 1.32e19 # L / mol*s
A2 = 1.09e13 # 1/s
Ea1 = 140000 # J/mol
Ea2 = 100000 # J/mol
R = 8.314 # J / K*mol
T = 330 # K
model.k['AtoB'].fix( A1 * exp( -Ea1 / (R*T) ) )
model.k['BtoC'].fix( A2 * exp( -Ea2 / (R*T) ) )
Dynamic Systems 51
Step 1: results
Dynamic Systems 52
Step 2: maximize the production of “B”
fdiff = TransformationFactory("dae.finite_difference")
rxns = ReactionNetwork()
rxns.add( Reaction("AtoB", reactants=['2*A'], products=['B']) )
rxns.add( Reaction("BtoC", reactants=['B'], products=['C']) )
model = create_kinetic_model(rxns, 60*60)
A1 = 1.32e19 # L / mol*s
A2 = 1.09e13 # 1/s
Ea1 = 140000 # J/mol
Ea2 = 100000 # J/mol
R = 8.314 # J / K*mol
Dynamic Systems 53
Step 2: maximize the production of “B”
Dynamic Systems 54
Kinetic parameter regression
(Assumed) Chemical reaction kinetics:
𝑘1
TG + MeOH ՞ DG + FAME
𝑘2
DG + MeOH ՞ MG + FAME
𝑘3
MG + MeOH ՞ Glycerol + FAME
Dynamic Systems 55
Generate (sub)model for each experiment…
def create_regression_model(b, t):
rxns = ReactionNetwork()
rxns.add_reversible(
Reaction( "k_1", reactants=['TG','MeOH'], products=['DG','FAME'] ) )
rxns.add_reversible(
Reaction( "k_2", reactants=['DG','MeOH'], products=['MG','FAME'] ) )
rxns.add_reversible(
Reaction( "k_3", reactants=['MG','MeOH'], products=['Glycerol','FAME'] ) )
data = b.model().data[t]
key = b.model().key
model.error = Var(bounds=(0,None))
model.compute_error = Constraint(
expr= model.error == sum(
(( model.c[t,key[i]] - x ) / max(data[_t][i] for _t in data) )**2
for t in data for i,x in enumerate(data[t]) ) )
return model
Dynamic Systems 56
Assemble the regression model and solve
model = ConcreteModel()
model.key = key = ('MeOH','TG','DG','MG','FAME','Glycerol')
model.data = data = { 150: { 0: (2.833,6.84E-02,0.00,0.00,0.00,0.00,),
256: (2.807,4.75E-02,1.51E-02,3.71E-03,2.60E-02,8.18E-04,), # ...
} 210: { # ...
} }
Dynamic Systems 57
Regression results
T=150 T=210
Dynamic Systems 58
8. Solving Stochastic
Programs
Sandia National Laboratories is a multi-program laboratory managed and operated by Sandia Corporation, a wholly owned subsidiary of Lockheed
Martin Corporation, for the U.S. Department of Energy’s National Nuclear Security Administration under contract DE-AC04-94AL85000.
Progressive Hedging Algorithm
Scenario MIPs
Initialize Ws wx ( x x)
Global Convergence
“Done”
Criterion Achieved? Fix Variables That | ( x x) | ?
Have Converged
PH Iteration i:
Solve Weighted min f ( x) wx x / 2 || x x ||2
Scenario MIPs
Update Ws wx wx ( x x)
We can formulate a two-stage stochastic program where the first stage has
zero cost and the second stage has cost t.
model = AbstractModel()
model.d = Param()
model.t = Var()
model.x = Var(within=NonNegativeReals, bounds=(0,100))
def c1_rule(model):
return model.t >= (c-b)*model.x + b*model.d
model.c1 = Constraint(rule=c1_rule)
def c2_rule(model):
return model.t >= (c+h)*model.x - h*model.d
model.c2 = Constraint(rule=c2_rule)
# 0*model.x
model.stage1 = Constraint(expr=model.FirstStageCost==0)
model.stage2 = Constraint(expr=model.SecondStageCost==model.t)
In the node-based approach, a single .dat file is specified for each node in
the scenario tree
Maximally compact, but requires some book-keeping
This example uses scenario-based data, with data files that simply define d.
In PySP, the runef script is provided to both write and solve the extensive
form of a stochastic programming model
Questions?
2
First stage variables:
4 • Unit On / Off
Generator Number
10
12
Nature resolves uncertainty
14
16
• Load
0 5 10
Hour of day
15 20 25
• Renewables output
• Forced outages
p1 p2 … pN
• Jean-Paul Watson
• Roger Wets
• David Woodruff
Sandia National Laboratories is a multi-program laboratory managed and operated by Sandia Corporation, a wholly owned subsidiary of Lockheed
Martin Corporation, for the U.S. Department of Energy’s National Nuclear Security Administration under contract DE-AC04-94AL85000.
Overview of Bilevel Programming
General formulation:
Upper-level problem
where
Lower-level problem
Extremely complex
• Impossible to enumerate the set of all states in the game
solvebilevel(CO,OO,CI,OI,[y])
Modeling extensions
Modeling components (pyomo.bilevel)
Model transformations
Can be applied automatically
Custom solvers
Solvers tailored for specific classes of bilevel problems
Process:
• Model problem with SubModel components
• Transform the problem to a standard form
LP, MIP, etc
• Apply a suitable solver
Problem:
Example:
Use a custom solver that considers complementarity conditions
(Bard, 1998)
Example:
Chain reformulations: BLP -> MPEC -> GDP -> MIP
Provide “BigM” values for unbounded variables
Apply standard MIP solver
(Fortuny-Amat and McCarl, 1981)
Example:
Reformulate the complementarity conditions with nonlinear
constraints
(Ferris and Dirkse, 2005)
Problem:
Upper level constraints do not constrain y
Case 1:
The reformulation is a simple LP (or a MIP if x are binary)
Case 2:
The upper-level decision variables x are binary
Reformulate the bilinear objective terms as disjunctions:
Python Script:
Formulate the model
Apply desired model reformulations
Apply a suitable optimizer
OR
Directly analyze the model within Python
(e.g. using Pyomo’s algebraic structure)
Pyomo Command:
Execute a command that executes a Pyomo meta-solvers
Performs suitable reformulations
Applies a suitable optimizer
Maps the solution to the original problem
pyomo solve --solver=bilevel_ld model.py
• Parameterizing transformations
How can we flexibly specify transformation options?
E.g. Specifying big-M values for specific complementarity conditions
• Additional meta-solvers
E.g. bilevel_blp
• Richard L. Chen
• William E. Hart
• John D. Siirola
• Jean-Paul Watson
Problem:
Reformulation: This is the MPEC model that eliminates the v variable in the
reformulation on the earlier slide.