source: trunk/coopr/pyomo/base/PyomoModel.py @ 1755

Last change on this file since 1755 was 1755, checked in by jwatson, 11 years ago

Removing the "problem_writer" attribute from the PyomoModel? class. It is assigned every time write() is invoked, and isn't used anywhere else within pyomo or coopr. Further, it is causing pickle to crash, as the problem writers are not pickleable.

  • Property svn:executable set to *
File size: 14.4 KB
Line 
1#  _________________________________________________________________________
2#
3#  Coopr: A COmmon Optimization Python Repository
4#  Copyright (c) 2008 Sandia Corporation.
5#  This software is distributed under the BSD License.
6#  Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
7#  the U.S. Government retains certain rights in this software.
8#  For more information, see the Coopr README.txt file.
9#  _________________________________________________________________________
10
11import copy
12import re
13import sys
14
15from plugin import *
16from numvalue import *
17
18import pyutilib
19from pyutilib.numtypes import *
20from pyutilib import quote_split, tuplize
21
22from coopr.opt import ProblemFormat, ResultsFormat
23from coopr.pyomo.base.var import _VarValue
24import coopr.opt
25from PyomoModelData import ModelData
26import pyomo
27
28from sets import Set, _ProductSet, _SetContainer, _BaseSet
29from rangeset import RangeSet
30from var import _VarBase
31from constraint import Objective, Constraint
32from param import _ParamBase
33
34
35class Model(object):
36    """
37    The MINLP model that will be analyzed by the user.
38    """
39
40    presolver_ep = pyutilib.plugin.ExtensionPoint(IPyomoPresolver)
41
42
43    def __init__(self):
44        """Constructor"""
45        #
46        # Define component dictionary: component type -> instance
47        #
48        self._component={}
49        for item in pyutilib.plugin.ExtensionPoint(IModelComponent):
50            self._component[ item.cls() ] = {}
51        #
52        # A list of the declarations, in the order that they are
53        # specified.
54        #
55        self._declarations=[]
56        # the _name_varmap is assigned when the problem definition
57        # file is written, i.e., via the write() command. intent
58        # is to map names that will be coming back from a solver
59        # into Pyomo variables. Values are of type _VarValue.
60        self._name_varmap={}
61        self.name="unknown"
62        self.tmpctr=0
63        self._varctr=0
64        #self._varmap={}
65        self._presolvers = ["simple_presolver"]
66        #
67        # Dictionaries that map from id to Variable/Constraints
68        #
69        self._var = {}
70        self._con = {}
71        self._obj = {}
72
73
74    def num_used_variables(self):
75        return len(self._var)
76
77
78    #def variable_map(self):
79        #return self._varmap
80
81
82    def valid_problem_types(self):
83        return [ProblemFormat.pyomo]
84
85
86    def _add_temporary_set(self,val):
87        if val._index_set is not None:
88           ##print "HERE Y1"
89           val._index = self._construct_temporary_set(val._index_set,val.name+"_index")
90        if isinstance(val._index,_SetContainer) and \
91           val._index.name == "_unknown_":
92           ##print "HERE Y2"
93           self._construct_temporary_set(val._index,val.name+"_index")
94        if val.domain is not None and val.domain.name == "_unknown_":
95           ##print "HERE Y3"
96           self._construct_temporary_set(val.domain,val.name+"_domain")
97
98
99    def _construct_temporary_set(self, obj, name):
100        if type(obj) is tuple:
101           if len(obj) == 1:                #pragma:nocover
102                  raise Exception, "Unexpected temporary set construction"
103           else:
104                  tobj=_ProductSet(*obj)
105                  setattr(self,name,tobj)
106                  tobj.virtual=True
107                  return tobj
108        if isinstance(obj,_BaseSet):
109           setattr(self,name,obj)
110           return obj
111
112
113    def _clear_attribute(self,name):
114        #
115        # Cleanup Old Model Declaration First
116        #
117        i=0
118        for decl in self._declarations:
119            if decl.name == name:
120                self.__dict__[name]=None
121                del self._declarations[i]
122                for item in self._component:
123                    if name in self._component[item]:
124                        del self._component[item][name]
125                        break
126                break
127            i += 1
128
129    def _setattr_exec(self,name,val,item):
130        self._clear_attribute(name)
131        val.name=name
132        self._add_temporary_set(val)
133        val.model=self
134        self._component[item][name]=val
135        self._declarations.append(val)
136        self.__dict__[name]=val
137
138    def __setattr__(self,name,val):
139        """Set attributes"""
140        #
141        # Set Model Declaration
142        #
143        if name != "_component":
144            #
145            # If this is a component type, then simply set it
146            #
147            if type(val) in self._component:
148                self._setattr_exec(name,val, type(val))
149                return
150            #
151            # Otherwise, see if this is an instance of a component type
152            #
153            for item in self._component:
154                #print "HERE z",name,val,item,isinstance(val,item)
155                if isinstance(val,item):
156                    self._setattr_exec(name,val, item)
157                    return
158
159        #if name in self.__dict__.keys() and isinstance(self.__dict__[name],NumericValue):
160            #tmpval = value(val)
161            #if tmpval is None:
162                #raise ValueError, "Bad numeric value"
163            #self.__dict__[name].value = tmpval
164        #else:
165            #self.__dict__[name]=val
166
167        #
168        # Try to set the value.  This may fail if the attribute does not already
169        # exist in this model, if the set_value function is not defined, or if
170        # a bad value is provided.  In the latter case, a ValueError will be thrown, which
171        # we raise.  Otherwise, this is an object that we need to set directly.
172        #
173        #print "HERE X",name
174        try:
175            #print "HERE",self.__dict__[name].name,type(self.__dict__[name]),type(val)
176            self.__dict__[name].set_value(val)
177        except ValueError, e:
178            raise
179        except Exception, e:
180            self.__dict__[name]=val
181
182
183    def create(self,filename=None):
184        """
185        Create a concrete instance of this Model, possibly using data
186        read in from a file.
187        """
188        instance = self.clone()
189        instance.load(filename)
190        instance.presolve()
191        return instance
192
193
194    def clone(self):
195        """Create a copy of this model"""
196        for declaration in self._declarations:
197          declaration.model = None
198        instance = copy.deepcopy(self)
199        for declaration in self._declarations:
200          declaration.model = self
201        for declaration in instance._declarations:
202          declaration.model = instance
203        return instance
204
205
206    def reset(self):
207        for declaration in self._declarations:
208            declaration.reset()
209
210
211    def presolve(self):
212        """Apply the presolvers defined by the user"""
213        for item in self._presolvers:
214            self = Model.presolver_ep.service(item).presolve(self)
215       
216
217    def solution(self):
218        """Return the solution"""
219        pass                            #pragma:nocover
220
221
222    def load(self,arg):
223        """ Load the model with data from a file or a Solution object """
224        if arg is None or type(arg) is str:
225           self._load_model_data(ModelData(filename=arg,model=self))
226           return True
227        elif type(arg) is ModelData:
228           self._load_model_data(arg)
229           return True
230        elif type(arg) is coopr.opt.SolverResults:
231           if arg.solver.status != coopr.opt.SolverStatus.ok:
232              raise ValueError, "Cannot load a SolverResults object with bad status: "+str(arg.solver.status)
233           if len(arg.solution) > 0:
234              self._load_solution(arg.solution(0))
235              return True
236           else:
237              return False
238        elif type(arg) is coopr.opt.Solution:
239           self._load_solution(arg)
240           return True
241        else:
242           raise ValueError, "Cannot load model with object of type "+str(type(arg))
243
244
245    def _tuplize(self, data, setobj):
246        if data is None:            #pragma:nocover
247           return None
248        if setobj.dimen == 1:
249           return data
250        ans = {}
251        for key in data:
252          if type(data[key][0]) is tuple:
253             return data
254          ans[key] = tuplize(data[key], setobj.dimen, setobj.name)
255        return ans
256
257
258    def _load_model_data(self,modeldata):
259        """
260        Load declarations from a ModelData object.
261        """
262        #print "HERE _load_model_data",self._declarations
263        for declaration in self._declarations:
264          tmp = declaration.name
265          if tmp in modeldata._default.keys():
266             if isinstance(declaration,_BaseSet):
267                declaration.default = self._tuplize(modeldata._default[tmp],declaration)
268             else:
269                declaration.default = modeldata._default[tmp]
270          if tmp in modeldata._data.keys():
271             #print "HERE", declaration.name, str(declaration.dimen),modeldata._data[tmp]
272             if isinstance(declaration,_BaseSet):
273                data = self._tuplize(modeldata._data[tmp],declaration)
274             else:
275                data = modeldata._data[tmp]
276          else:
277             data = None
278          if pyomo.debug("generate"):           #pragma:nocover
279             print "About to generate '"+declaration.name+"' with data: "+str(data)
280             self.pprint()
281          declaration._construct(self,data)
282          try:
283            ##declaration._construct(self,data)
284            pass
285          except Exception, err:
286            print "Error constructing declaration "+str(declaration.name)+" from data="+str(data)
287            print "ERROR: "+str(err)
288            raise err
289
290    def _load_solution(self,soln):
291        """
292        Load a solution.
293        """
294        for (name,value) in soln.variable:
295          #
296          # NOTE: the following is a hack, to handle the ONE_VAR_CONSTANT variable
297          #       that is necessary for the objective constant-offset terms.
298          #       probably should create a dummy variable in the model map at the same
299          #       time the objective expression is being constructed.
300          #
301          if name != "ONE_VAR_CONSTANT":
302             if name not in self._name_varmap:
303                names=""
304                raise KeyError, "Variable name '"+name+"' is not in model "+self.name+".  Valid variable names: "+str(self._name_varmap.keys())
305             if not isinstance(self._name_varmap[name],_VarValue):
306                raise TypeError, "Variable '"+name+"' in model '"+self.name+"' is type "+str(type(self._name_varmap[name]))
307             if self._name_varmap[name].fixed is True:
308                raise TypeError, "Variable '"+name+"' in model '"+self.name+"' is currently fixed - new value is not expected in solution"
309             self._name_varmap[name].value = value
310
311
312    def write(self,filename=None,format=ProblemFormat.cpxlp):
313        """
314        Write the model to a file, with a given format.
315        """
316        if format is None and not filename is None:
317            #
318            # Guess the format
319            #
320            for fmt in coopr.opt.ProblemFormat:
321                if filename.endswith('.'+str(fmt)):
322                    format=fmt
323                    break
324        problem_writer = coopr.opt.WriterFactory(format)
325        if problem_writer is None:
326           raise ValueError, "Cannot write model in format \"" + str(format) + "\": no model writer registered for that format"
327        fname = problem_writer(self, filename)
328        if pyomo.debug("verbose"):
329           print "Writing model "+self.name+" to file '"+str(fname)+"'  with format "+str(format)
330        return fname
331
332
333    def pprint(self, filename=None, ostream=None):
334        """
335        Print a summary of the model info
336        """
337        if ostream is None:
338           ostream = sys.stdout
339        if filename is not None:
340           OUTPUT=open(filename,"w")
341           self.pprint(ostream=OUTPUT)
342           OUTPUT.close()
343           return
344        if ostream is None:
345           ostream = sys.stdout
346        #
347        # We hard-code the order of the core Pyomo modeling
348        # components, to ensure that the output follows the logical
349        # expected by a user.
350        #
351        items = [_BaseSet, RangeSet, _ParamBase, _VarBase, Objective, Constraint]
352        for item in pyutilib.plugin.ExtensionPoint(IModelComponent):
353            if not item in items:
354                items.append(item)
355        for item in items:
356            if not item in self._component:
357                continue
358            keys = self._component[item].keys()
359            keys.sort()
360            #
361            # NOTE: these conditional checks should not be hard-coded.
362            #
363            if item.__name__ == "_BaseSet":
364                print >>ostream, len(keys), "Set Declarations"
365            elif item.__name__ == "_ParamBase":
366                print >>ostream, len(keys), "Param Declarations"
367            elif item.__name__ == "_VarBase":
368                print >>ostream, len(keys), "Var Declarations"
369            else:
370                print >>ostream, len(keys), item.__name__+" Declarations"
371            for key in keys:
372                self._component[item][key].pprint(ostream)
373            print >>ostream, ""
374        #
375        # Model Order
376        #
377        print >>ostream, len(self._declarations),"Declarations:",
378        for i in range(0,len(self._declarations)):
379          print >>ostream, self._declarations[i].name,
380        print >>ostream, ""
381
382
383    def display(self,filename=None, ostream=None):
384        """
385        Print the Pyomo model in a verbose format.
386        """
387        if filename is not None:
388           OUTPUT=open(filename,"w")
389           self.display(ostream=OUTPUT)
390           OUTPUT.close()
391           return
392        if ostream is None:
393           ostream = sys.stdout
394        print >>ostream, "Model "+self.name
395        print >>ostream, ""
396        print >>ostream, "  Variables:"
397        if len(self._component[_VarBase]) == 0:
398           print >>ostream, "    None"
399        else:
400           for ndx in self._component[_VarBase]:
401             self._component[_VarBase][ndx].display(prefix="    ",ostream=ostream)
402        print >>ostream, ""
403        print >>ostream, "  Objectives:"
404        if len(self._component[Objective]) == 0:
405           print >>ostream, "    None"
406        else:
407           for ndx in self._component[Objective]:
408             self._component[Objective][ndx].display(prefix="    ",ostream=ostream)
409        print >>ostream, ""
410        print >>ostream, "  Constraints:"
411        if len(self._component[Constraint]) == 0:
412           print >>ostream, "    None"
413        else:
414           for ndx in self._component[Constraint]:
415             self._component[Constraint][ndx].display(prefix="    ",ostream=ostream)
416
Note: See TracBrowser for help on using the repository browser.