source: coopr.pyomo/stable/coopr/pyomo/base/block.py @ 3285

Last change on this file since 3285 was 3285, checked in by wehart, 10 years ago

Merged revisions 3184-3284 via svnmerge from
https://software.sandia.gov/svn/public/coopr/coopr.pyomo/trunk

........

r3188 | jwatson | 2010-10-29 08:09:35 -0600 (Fri, 29 Oct 2010) | 3 lines


Eliminating initial domain check when constructing numeric constants and the default domain (Reals) is specified.

........

r3203 | jwatson | 2010-10-29 14:46:18 -0600 (Fri, 29 Oct 2010) | 3 lines


Fixing bugs in has_discrete_variables() method of PyomoModel?.

........

r3211 | jdsiiro | 2010-11-01 14:49:11 -0600 (Mon, 01 Nov 2010) | 4 lines


bugfixes for Blocks:

  • avoid infinite loop when adding a block to a model
  • support pretty printing of user-defined components

........

r3212 | jdsiiro | 2010-11-02 15:17:13 -0600 (Tue, 02 Nov 2010) | 5 lines


  • cleaning up the management of Block._parent_block and Component.model attributes. Adding & removing blocks now updates the model attribute on all children
  • renaming Block._setattr_exec -> Block._add_component

........

r3213 | jdsiiro | 2010-11-03 10:47:06 -0600 (Wed, 03 Nov 2010) | 2 lines


Bugfix to the PyomoLogHandler? for python 2.4 compatibility

........

r3214 | jdsiiro | 2010-11-03 15:20:47 -0600 (Wed, 03 Nov 2010) | 3 lines


There is no point logging a warning when the problem is encountered
generating a logging.info message: log the warning at the info level.

........

r3215 | wehart | 2010-11-04 23:05:17 -0600 (Thu, 04 Nov 2010) | 3 lines


Adding a simple knapsack example to illustrate the difference between
a concrete and abstract model.

........

r3216 | jwatson | 2010-11-05 09:39:19 -0600 (Fri, 05 Nov 2010) | 3 lines


Fixing error diagnostic when indexing a variable with a bad index.

........

r3219 | jwatson | 2010-11-05 16:01:23 -0600 (Fri, 05 Nov 2010) | 3 lines


Supressing a validation test with NumericConstant?. If the user specifies a value, we are (now) assuming it is actually a numeric value - otherwise, the domain check significantly inflates the run-time associated with expression tree creation. This needs to be revisited in the Coopr 2.5 re-write.

........

r3226 | wehart | 2010-11-06 21:32:59 -0600 (Sat, 06 Nov 2010) | 2 lines


Setting up example, which was never converted.

........

r3233 | wehart | 2010-11-12 15:56:28 -0700 (Fri, 12 Nov 2010) | 4 lines


Migrating OS-specific functionality into coopr.os


Adding coopr.os to the dev.ini config file.

........

r3242 | wehart | 2010-11-13 01:28:57 -0700 (Sat, 13 Nov 2010) | 4 lines


Type fix.


Updating error message.

........

r3244 | wehart | 2010-11-13 10:44:26 -0700 (Sat, 13 Nov 2010) | 2 lines


Skipping OSiL writer when not defined.

........

r3246 | wehart | 2010-11-13 10:54:15 -0700 (Sat, 13 Nov 2010) | 2 lines


bug fix.

........

r3247 | wehart | 2010-11-13 11:14:01 -0700 (Sat, 13 Nov 2010) | 2 lines


Bug fix.

........

r3248 | jwatson | 2010-11-17 13:51:47 -0700 (Wed, 17 Nov 2010) | 3 lines


Interim fixes to output of quadratic terms in LP writer - more to do, but at least the basic examples now work.

........

r3254 | jwatson | 2010-11-19 13:19:19 -0700 (Fri, 19 Nov 2010) | 3 lines


Fixed bug in LP writer involving quadratic terms involving two distinct variables. Added two new quadratic examples.

........

r3257 | jwatson | 2010-11-19 13:59:35 -0700 (Fri, 19 Nov 2010) | 3 lines


Fixing diagnostic error message when attempting to solve quadratic programs with GLPK - code for generating message was not syntatically legal.

........

r3268 | jwatson | 2010-12-01 15:08:28 -0700 (Wed, 01 Dec 2010) | 3 lines


Fixing issues with the Piecewise construct when breakpoints and slopes are generated via rules. Works now (on a sample of size 1 - the newly added example5.py) for non-indexed rules, likely broken for indexed breakpoint/slope rules.

........

r3272 | jwatson | 2010-12-02 13:53:51 -0700 (Thu, 02 Dec 2010) | 3 lines


Adding omitted pprint() method for SOS constraints - identified while debugging a piecewise issue.

........

r3274 | jwatson | 2010-12-02 16:32:29 -0700 (Thu, 02 Dec 2010) | 3 lines


Adding example of Piecewise construct using breakpoint and slope rules, as opposed to explicit/direct lists.

........

r3276 | jwatson | 2010-12-03 14:06:40 -0700 (Fri, 03 Dec 2010) | 3 lines


Some progress toward functional indexed Piecewise components.

........

  • Property svn:executable set to *
File size: 12.2 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
11"""
12Block Properties:
13
141. Blocks are indexed components that contain other components (including blocks)
15
162. Blocks have a global attribute that defines whether construction is deferred.  This
17applies to all components that they contain except blocks.  Blocks contained by other blocks
18use their local attribute to determine whether construction is deferred.
19
20NOTE: Blocks do not currently maintain statistics about the sets, parameters, constraints, etc that
21they contain, including these components from subblocks.
22"""
23
24__all__ = ['Block']
25
26import sys
27
28from plugin import *
29
30from pyutilib.component.core import alias, ExtensionPoint
31from pyutilib.misc import Container
32
33from component import Component
34from sets import Set, _ProductSet, _SetContainer, _BaseSet
35from rangeset import RangeSet
36from var import Var
37from constraint import Objective, Constraint
38from param import Param
39
40from indexed_component import IndexedComponent
41try:
42    from components import OrderedDict
43except ImportError:
44    from ordereddict import OrderedDict
45
46
47class Block(IndexedComponent):
48    """
49    A block in an optimization model.  By default, this defers construction of
50    components until data is loaded.
51    """
52
53    alias("Block", "Blocks are indexed components that contain one or more " + \
54          "other model components.")
55
56    def __init__(self, *args, **kwargs):
57        """Constructor"""
58        if 'ctype' in kwargs:
59            tkwargs = {'ctype':kwargs['ctype']}
60        else:
61            tkwargs = {'ctype':Block}
62        IndexedComponent.__init__(self, *args, **tkwargs)
63        #
64        self.name=kwargs.get('name', 'unknown')
65        self._defer_construction=True
66        # By default, a Block is a top-level (i.e. Model) block
67        self.model = self
68        self._parent_block = None
69        #
70        # Define component dictionary: component type -> instance
71        #
72        self._component={}
73        for item in ModelComponentFactory.services():
74            self._component[  ModelComponentFactory.get_class(item) ] = {}
75        #
76        # A list of the declarations, in the order that they are
77        # specified.
78        #
79        self._declarations=OrderedDict()
80
81        # Hack. Right now Block objects assume all attributes derived from
82        # Component eventually inherit from NumValue, and so have a domain
83        # attribute.
84        self.domain = None
85
86    def concrete_mode(self):
87        """Configure block to immediately construct components"""
88        self._defer_construction=False
89
90    def symbolic_mode(self):
91        """Configure block to defer construction of components"""
92        self._defer_construction=True
93
94    def components(self, ctype=None):
95        """
96        Return information about the block components.  If ctype is None, return the dictionary
97        that maps {component type -> {name -> instance}}.  Otherwise, return the dictionary
98        that maps {name -> instance} for the specified component type.
99        """
100        if ctype is None:
101            return self._component
102        if ctype in self._component:
103             return self._component[ctype]
104        raise KeyError, "Unknown component type: %s" % str(ctype)
105
106    def active_components(self, _ctype=None):
107        """
108        Returns the active components in this block.  If _ctype is None, return the
109        dictionary that maps {component type -> {name -> instance}}.  Otherwise, return
110        the dictionary that maps {name -> instance} for the specified component type.
111        """
112        tmp = {}
113        if _ctype is None:
114            for ctype in self._component:
115                tmp[ctype]={}
116        elif _ctype in self._component:
117            tmp[_ctype]={}
118        else:
119            raise KeyError, "Unknown component type: %s" % str(_ctype)
120        for ctype in tmp:
121            for name in self._component[ctype]:
122                comp = self._component[ctype][name]
123                if comp.active:
124                    tmp[ctype][name] = comp
125        if not _ctype is None:
126            return tmp[_ctype]
127        return tmp
128
129    def _add_temporary_set(self,val):
130        if val._index_set is not None:
131            ctr=0
132            for tset in val._index_set:
133                if tset.name == "_unknown_":
134                    self._construct_temporary_set(
135                      tset,
136                      val.name+"_index_"+str(ctr)
137                    )
138                ctr += 1
139            val._index = self._construct_temporary_set(
140              val._index_set,
141              val.name+"_index"
142            )
143        if isinstance(val._index,_SetContainer) and \
144            val._index.name == "_unknown_":
145            self._construct_temporary_set(val._index,val.name+"_index")
146        if val.domain is not None and val.domain.name == "_unknown_":
147            self._construct_temporary_set(val.domain,val.name+"_domain")
148
149    def _construct_temporary_set(self, obj, name):
150        if type(obj) is tuple:
151           if len(obj) == 1:                #pragma:nocover
152                  raise Exception, "Unexpected temporary set construction"
153           else:
154                  tobj=_ProductSet(*obj)
155                  setattr(self,name,tobj)
156                  tobj.virtual=True
157                  return tobj
158        if isinstance(obj,_BaseSet):
159           setattr(self,name,obj)
160           return obj
161
162    def _clear_attribute(self,name):
163        """
164        Cleanup the pre-existing model attribute
165        """
166        val = self._declarations.get(name, None)
167        if val is None:
168            return
169
170        if isinstance(val, Block):
171            val.__dict__['_parent_block'] = None
172            val.model = val
173        else:
174            val.model = None
175           
176        self.__dict__[name]=None # Any idea why we don't DEL here?
177        del self._component[ val.type() ][name]
178        del self._declarations[name]
179
180    def _add_component(self, name, val):
181        self._clear_attribute(name)
182        val.name=name
183        self._add_temporary_set(val)
184        self._component[val.type()][name]=val
185        self._declarations[name] = val
186        self.__dict__[name]=val
187
188        # Presumably self.model refers to the 'root' Block that will
189        # eventually be solved, whereas '_parent_block' refers to the
190        # immediate parent.
191
192        # Update the (new) child block's _parent_block. 
193        if isinstance(val, Block):
194            if val._parent_block is not None:
195                # Nothing really wrong here, but until we are more
196                # careful about checking that this actually works,
197                # complain loudly.
198                raise Exception, "Reassigning a block attached to a model"
199            # NB: use __dict__ directly to prevent infinite recursion
200            val.__dict__['_parent_block'] = self
201
202        # Update the new component's model pointer
203        val.model = self.model
204       
205        frame = sys._getframe(2)
206        locals_ = frame.f_locals
207        if getattr(val,'rule',None) is None and val.name+'_rule' in locals_:
208            val.rule = locals_[val.name+'_rule']
209        if not self._defer_construction:
210            val.construct(None)
211
212    def __setattr__(self,name,val):
213        """Set attributes"""
214        #
215        # Set Model Declaration
216        #
217        if name == "model":
218            if val is not None and not isinstance(val, Block):
219                raise ValueError, "Cannot set Block.model to a non-Block " \
220                      "object (%s)" % ( val )
221            self.__dict__["model"] = val
222            # Update all child components.  NB: use __dict__.get because
223            # Component.__init__() assigns "self.model = None" before
224            # Block.__init__ defines the _declarations map.
225            for subcomp in self.__dict__.get("_declarations", {}).itervalues():
226                subcomp.model = val
227        elif name != "_component" and isinstance(val, Component):
228            #
229            # If this is a component type, then simply set it
230            #
231            self._add_component(name,val)
232        else:
233            #
234            # Try to set the value. This may fail if the attribute
235            # does not already exist in this model, if the set_value
236            # function is not defined, or if a bad value is
237            # provided. In the latter case, a ValueError will be
238            # thrown, which # we raise. Otherwise, this is an object
239            # that we need to set directly.
240            #
241            try:
242                self.__dict__[name].set_value(val)
243            except ValueError, e:
244                raise
245            except Exception, e:
246                self.__dict__[name]=val
247
248    def pprint(self, filename=None, ostream=None):
249        """
250        Print a summary of the model info
251        """
252        if ostream is None:
253           ostream = sys.stdout
254        if filename is not None:
255           OUTPUT=open(filename,"w")
256           self.pprint(ostream=OUTPUT)
257           OUTPUT.close()
258           return
259        if ostream is None:
260           ostream = sys.stdout
261        #
262        # We hard-code the order of the core Pyomo modeling
263        # components, to ensure that the output follows the logical order
264        # that expected by a user.
265        #
266        items = [Set, RangeSet, Param, Var, Objective, Constraint, Block]
267        for item in ExtensionPoint(IModelComponent):
268            if not item in items:
269                items.append(item)
270
271        # Currently, model components are not actually being registered
272        # with the IModelComponent extension point (1 Nov 2010), so as a
273        # workaround, we will loop through the components and add any
274        # new components that actually have defined members.
275        extra_items = []
276        for item, members in self._component.iteritems():
277            if item not in items and len(members):
278                extra_items.append(item)
279        # extra items get added alphabetically (so output is consistent)
280        items.extend(sorted(extra_items))
281
282        for item in items:
283            if not item in self._component:
284                continue
285            keys = self._component[item].keys()
286            keys.sort()
287            #
288            # NOTE: these conditional checks should not be hard-coded.
289            #
290            print >>ostream, len(keys), item.__name__+" Declarations"
291            for key in keys:
292                self._component[item][key].pprint(ostream=ostream)
293            print >>ostream, ""
294        #
295        # Model Order
296        #
297        print >>ostream, len(self._declarations),"Declarations:",
298        for name in self._declarations:
299          print >>ostream, name,
300        print >>ostream, ""
301
302    def display(self, filename=None, ostream=None):
303        """
304        Print the Pyomo model in a verbose format.
305        """
306        if filename is not None:
307           OUTPUT=open(filename,"w")
308           self.display(ostream=OUTPUT)
309           OUTPUT.close()
310           return
311        if ostream is None:
312           ostream = sys.stdout
313        if self.type() is Block:
314            print >>ostream, "Block "+self.name
315        else:
316            print >>ostream, "Model "+self.name
317        #
318        print >>ostream, ""
319        print >>ostream, "  Variables:"
320        VAR = self.active_components(Var)
321        if len(VAR) == 0:
322            print >>ostream, "    None"
323        else:
324            for ndx in VAR:
325                VAR[ndx].display(prefix="    ",ostream=ostream)
326        #
327        print >>ostream, ""
328        print >>ostream, "  Objectives:"
329        OBJ = self.active_components(Objective)
330        if len(OBJ) == 0:
331            print >>ostream, "    None"
332        else:
333            for ndx in OBJ:
334                OBJ[ndx].display(prefix="    ",ostream=ostream)
335        print >>ostream, ""
336        #
337        CON = self.active_components(Constraint)
338        print >>ostream, "  Constraints:"
339        if len(CON) == 0:
340            print >>ostream, "    None"
341        else:
342            for ndx in CON:
343                CON[ndx].display(prefix="    ",ostream=ostream)
344
Note: See TracBrowser for help on using the repository browser.