Created
December 5, 2011 22:44
-
-
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
'''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