Skip to content

Instantly share code, notes, and snippets.

@adamgreenhall
Created December 5, 2011 22:44
Show Gist options
  • Save adamgreenhall/1435751 to your computer and use it in GitHub Desktop.
Save adamgreenhall/1435751 to your computer and use it in GitHub Desktop.
a memory leak test for pyomo using pympler and objgraph -- I think the ConcreteModel leak was cleared up by https://software.sandia.gov/trac/coopr/changeset/5449
"""
An optimization command library.
"""
import coopr.pyomo as pyomo
from coopr.opt.base import solvers as cooprsolvers
variable_kinds = dict(Continuous=pyomo.Reals, Binary=pyomo.Boolean, Boolean=pyomo.Boolean)
import logging,time
class Problem(object):
'''an optimization problem/model based on pyomo'''
def __init__(self):
self.model=pyomo.ConcreteModel('power system problem')
self.solved=False
def add_objective(self,expression,sense=pyomo.minimize):
'''add an objective to the problem'''
self.model.objective=pyomo.Objective(name='objective',rule=expression,sense=sense)
def add_variable(self,variable):
'''add a single variable to the problem'''
try: self._add_component(variable.name,variable)
except AttributeError: pass #just a number, don't add to vars
def add_constraint(self,constraint):
'''add a single constraint to the problem'''
self._add_component(constraint.name,constraint)
def solve(self,solver='glpk',problem_filename=False,get_duals=True,tracker=None):
'''
Solve the optimization problem.
:param solver: name of solver (lowercase string).
:param problem_filename: write MIP problem formulation to a file, if a file name is specified
:param get_duals: get the duals, or prices, of the optimization problem
'''
# current_log_level = logging.getLogger().getEffectiveLevel()
opt_solver = cooprsolvers.SolverFactory(solver)
if opt_solver is None:
msg='solver "{}" not found. available solvers are {}'.format(solver,[k for k in cooprsolvers.IOptSolver._factory_active.keys() if not k.startswith('_')])
raise OptimizationError(msg)
if tracker is not None:
tracker.create_snapshot('solver set up.')
def cooprsolve(instance,suffixes=['dual'],keepFiles=False):
if not keepFiles: logging.getLogger().setLevel(logging.WARNING)
start = time.time()
results= opt_solver.solve(instance,suffixes=suffixes) #,keepFiles=keepFiles
elapsed = (time.time() - start)
# logging.getLogger().setLevel(current_log_level)
return results,elapsed
instance=self.model.create()
results,elapsed=cooprsolve(instance)
self.statusText = str(results.solver[0]['Termination condition'])
if not self.statusText =='optimal':
logging.critical('problem not solved. Solver terminated with status: "{}"'.format(self.statusText))
self.status=self.solved=False
else:
self.status=self.solved=True
self.solutionTime =elapsed #results.Solver[0]['Wallclock time']
logging.info('Problem solved in {}s.'.format(self.solutionTime))
if problem_filename:
# logging.disable(logging.CRITICAL) #disable coopr's funny loggings when writing lp files.
self.write(problem_filename)
# logging.disable(current_log_level)
if not self.status: return
instance.load(results)
def resolvefixvariables(instance,results):
active_vars= instance.active_components(pyomo.Var)
need_to_resolve=False
for _,var in active_vars.items():
if isinstance(var.domain, pyomo.base.IntegerSet) or isinstance(var.domain, pyomo.base.BooleanSet):
var.fixed=True
need_to_resolve=True
if not need_to_resolve: return instance,results
logging.info('resolving fixed-integer LP for duals')
instance.preprocess()
try:
results,elapsed=cooprsolve(instance)
self.solutionTime+=elapsed
except RuntimeError:
logging.error('coopr raised an error in solving. keep the files for debugging.')
results= cooprsolve(instance, keepFiles=True)
instance.load(results)
return instance,results
if get_duals:
try: instance,results = resolvefixvariables(instance,results)
except RuntimeError:
logging.error('in re-solving for the duals. the duals will be set to default value.')
try: self.objective = results.Solution.objective['objective'].value #instance.active_components(pyomo.Objective)['objective']
except AttributeError:
self.objective = results.Solution.objective['__default_objective__'].value
self.constraints = instance.active_components(pyomo.Constraint)
self.variables = instance.active_components(pyomo.Var)
return
def __getattr__(self,name):
try: return getattr(self.model,name)
except AttributeError:
msg='the model has no variable/constraint/attribute named "{n}"'.format(n=name)
raise AttributeError(msg)
def value(variable):
'''
Value of an optimization variable after the problem is solved.
If passed a numeric value, will return the number.
'''
try: return variable.value
except AttributeError: return variable #just a number
def dual(constraint,index=None):
'''Dual of optimization constraint, after the problem is solved.'''
return constraint[index].dual
def new_variable(name='',kind='Continuous',low=-1000000,high=1000000):
'''
Create an optimization variable.
:param name: name of optimization variable.
:param kind: type of variable, specified by string. {Continuous or Binary/Boolean}
:param low: low limit of variable
:param high: high limit of variable
'''
return pyomo.Var(name=name,bounds=(low,high),domain=variable_kinds[kind])
def new_constraint(name,expression):
'''Create an optimization constraint.'''
return pyomo.Constraint(name=name,rule=expression)
class OptimizationError(Exception):
'''Error that occurs within solving an optimization problem.'''
def __init__(self, ivalue):
if ivalue: self.value=ivalue
else: self.value="Optimization Error: there was a problem"
Exception.__init__( self, self.value)
def __str__(self): return self.value
'''Simple test see why ConcreteModel instances aren't being garbage collected'''
from pympler.classtracker import ClassTracker
from pympler.classtracker_stats import HtmlStats
import objgraph
import random,inspect,gc
import optimization #this is a minpower module, copied out here for
from coopr import pyomo
from coopr.opt.base.solvers import IOptSolver,OptSolver
import pyutilib
import coopr
import logging
logging.basicConfig( level=logging.DEBUG, format='%(levelname)s: %(message)s')
tracker=ClassTracker()
for cls in [pyomo.ConcreteModel,pyomo.Var,pyomo.base.var._VarElement,
pyomo.Constraint,optimization.Problem,
IOptSolver,OptSolver,pyutilib.component.core.core.PluginMeta,
]:
tracker.track_class(cls)
def simple_problem():
prob=optimization.Problem()
tracker.create_snapshot('prob. init')
x= optimization.new_variable('x',low=0,high=3)
y= optimization.new_variable('y',low=0,high=1)
prob.add_variable(x)
prob.add_variable(y)
prob.add_objective(y-4*x)
prob.add_constraint(optimization.new_constraint('',x+y<=2))
tracker.create_snapshot('prob. created')
return prob
prob=simple_problem()
prob.solve(solver='cplex',tracker=tracker)
tracker.create_snapshot('prob. solved')
prob.variables={}
prob.constraints={}
prob.objective=0
del prob
gc.collect()
tracker.create_snapshot('prob. deleted')
tracker.stats.print_summary()
HtmlStats(tracker=tracker).create_html('profile-simple-problem.html')
def show_backref_chain(name):
try: objgraph.show_chain(objgraph.find_backref_chain( random.choice(objgraph.by_type(name)),inspect.ismodule),filename='{}-chain.png'.format(name))
except: print 'couldnt find a reference to {} -- skip plotting'.format(name)
objgraph.show_backrefs(objgraph.by_type('ConcreteModel'),filename='ConcreteModel-backrefs.png')
objgraph.show_backrefs(objgraph.by_type('SymbolMap'),filename='SymbolMap-backrefs.png')
objgraph.show_backrefs(objgraph.by_type('PluginEnvironment'),filename='PluginEnvironment-backrefs.png')
objgraph.show_backrefs(objgraph.by_type('_VarElement'),filename='VarElement-backrefs.png')
show_backref_chain('ConcreteModel')
show_backref_chain('SymbolMap')
show_backref_chain('PluginEnvironment')
show_backref_chain('ExtensionPoint')
show_backref_chain('_VarElement')
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment