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

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

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

........

r3051 | jwatson | 2010-09-28 14:58:10 -0500 (Tue, 28 Sep 2010) | 3 lines


Fixed error in implementation of last() method of SetContainer?.

........

r3052 | jwatson | 2010-09-29 09:09:07 -0500 (Wed, 29 Sep 2010) | 3 lines


Adding improved error diagnostics in the case where a non-hashable key is supplied as an index to a variable.

........

r3053 | jwatson | 2010-09-29 13:51:03 -0500 (Wed, 29 Sep 2010) | 3 lines


Fixing implementation of next() method, which never worked and wasn't actually exercised until Fernando just tried :(

........

r3066 | wehart | 2010-10-02 23:13:02 -0500 (Sat, 02 Oct 2010) | 3 lines


Adding logic to verify parameter values and indices when
initializing data.

........

r3067 | wehart | 2010-10-03 08:23:58 -0500 (Sun, 03 Oct 2010) | 2 lines


Adding the AbstractModel? class.

........

r3068 | wehart | 2010-10-03 10:56:20 -0500 (Sun, 03 Oct 2010) | 10 lines


Adding support for non-mutable parameters, which are now
the default. These are simply parameters that are stored as
dictionaries with float values rather than ParamValue? values.


There were many changes to the CUTE test examples to
use the value() function, which works with either mutable or
immutable Param objects. There were similar changes to other tests.
These changes allow us to make mutable or immutable the default
for Param objects without changing our tests.

........

r3069 | wehart | 2010-10-03 11:21:57 -0500 (Sun, 03 Oct 2010) | 3 lines


Adding core1 and hagar4 to the list of ignored tests. These two tests generate inconsistent
*.nl files on different platforms.

........

r3071 | wehart | 2010-10-04 11:13:16 -0500 (Mon, 04 Oct 2010) | 2 lines


Bug fixes to param management.

........

r3077 | jwatson | 2010-10-05 09:40:09 -0500 (Tue, 05 Oct 2010) | 3 lines


Minor improvement in error message associated with an exception.

........

r3081 | wehart | 2010-10-11 21:20:45 -0500 (Mon, 11 Oct 2010) | 6 lines


Adding logic to allow ASL solverss to be specified as:


--solver=asl:PICO


Misc bug fix in AMPL writer.

........

r3082 | jwatson | 2010-10-11 22:24:45 -0500 (Mon, 11 Oct 2010) | 3 lines


Restructured LP writer to print a single term per line, for two reasons. First, Gurobi does not like LP files that are broken based on an arbitrary column width (e.g., which might yield lines ending in a "+"). Second, the performance of the textwrap to enforce a particular column width was terrible; that performance bottleneck is now eliminated.

........

r3083 | jwatson | 2010-10-12 13:51:36 -0500 (Tue, 12 Oct 2010) | 1 line


Fixed typo in previous commit of cpxlp.py

........

r3094 | wehart | 2010-10-13 21:17:29 -0500 (Wed, 13 Oct 2010) | 2 lines


Adding a --help-solvers option to pyomo.

........

r3098 | wehart | 2010-10-13 21:44:34 -0500 (Wed, 13 Oct 2010) | 2 lines


Allow the output directory for the parse script to be specified.

........

r3099 | jwatson | 2010-10-14 10:16:07 -0500 (Thu, 14 Oct 2010) | 3 lines


Missed this file in a previous commit - adding "preprocess" keyword argument to the create() method of PyomoModel?, to allow for more control of preprocessing within PySP. Default is true, with no change in default behavior.

........

r3103 | wehart | 2010-10-14 23:26:20 -0500 (Thu, 14 Oct 2010) | 2 lines


Adding documentation.

........

r3108 | wehart | 2010-10-16 11:43:03 -0500 (Sat, 16 Oct 2010) | 3 lines


Adding logic to write the parse_table_datacmds.py file only when
it does not exist.

........

r3109 | wehart | 2010-10-16 12:39:43 -0500 (Sat, 16 Oct 2010) | 3 lines


Adding logic to allow parse table writing if the grammer file is
newer than the parse table file.

........

r3110 | wehart | 2010-10-16 13:03:50 -0500 (Sat, 16 Oct 2010) | 6 lines


Rework to set the sys.path environment. PLY relies on this in a way that I didn't
expect.


This commit should resolve the issue that users have observed where the parse table is
frequently written.

........

  • Property svn:executable set to *
File size: 11.1 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        self._parent_block = None
67        #
68        # Define component dictionary: component type -> instance
69        #
70        self._component={}
71        for item in ModelComponentFactory.services():
72            self._component[  ModelComponentFactory.get_class(item) ] = {}
73        #
74        # A list of the declarations, in the order that they are
75        # specified.
76        #
77        self._declarations=OrderedDict()
78
79        # Hack. Right now Block objects assume all attributes derived from
80        # Component eventually inherit from NumValue, and so have a domain
81        # attribute.
82        self.domain = None
83
84    def concrete_mode(self):
85        """Configure block to immediately construct components"""
86        self._defer_construction=False
87
88    def symbolic_mode(self):
89        """Configure block to defer construction of components"""
90        self._defer_construction=True
91
92    def components(self, ctype=None):
93        """
94        Return information about the block components.  If ctype is None, return the dictionary
95        that maps {component type -> {name -> instance}}.  Otherwise, return the dictionary
96        that maps {name -> instance} for the specified component type.
97        """
98        if ctype is None:
99            return self._component
100        if ctype in self._component:
101             return self._component[ctype]
102        raise KeyError, "Unknown component type: %s" % str(ctype)
103
104    def active_components(self, _ctype=None):
105        """
106        Returns the active components in this block.  If _ctype is None, return the
107        dictionary that maps {component type -> {name -> instance}}.  Otherwise, return
108        the dictionary that maps {name -> instance} for the specified component type.
109        """
110        tmp = {}
111        if _ctype is None:
112            for ctype in self._component:
113                tmp[ctype]={}
114        elif _ctype in self._component:
115            tmp[_ctype]={}
116        else:
117            raise KeyError, "Unknown component type: %s" % str(_ctype)
118        for ctype in tmp:
119            for name in self._component[ctype]:
120                comp = self._component[ctype][name]
121                if comp.active:
122                    tmp[ctype][name] = comp
123        if not _ctype is None:
124            return tmp[_ctype]
125        return tmp
126
127    def _add_temporary_set(self,val):
128        if val._index_set is not None:
129            ctr=0
130            for tset in val._index_set:
131                if tset.name == "_unknown_":
132                    self._construct_temporary_set(
133                      tset,
134                      val.name+"_index_"+str(ctr)
135                    )
136                ctr += 1
137            val._index = self._construct_temporary_set(
138              val._index_set,
139              val.name+"_index"
140            )
141        if isinstance(val._index,_SetContainer) and \
142            val._index.name == "_unknown_":
143            self._construct_temporary_set(val._index,val.name+"_index")
144        if val.domain is not None and val.domain.name == "_unknown_":
145            self._construct_temporary_set(val.domain,val.name+"_domain")
146
147    def _construct_temporary_set(self, obj, name):
148        if type(obj) is tuple:
149           if len(obj) == 1:                #pragma:nocover
150                  raise Exception, "Unexpected temporary set construction"
151           else:
152                  tobj=_ProductSet(*obj)
153                  setattr(self,name,tobj)
154                  tobj.virtual=True
155                  return tobj
156        if isinstance(obj,_BaseSet):
157           setattr(self,name,obj)
158           return obj
159
160    def _clear_attribute(self,name):
161        """
162        Cleanup the pre-existing model attribute
163        """
164        if name in self._declarations:
165            self.__dict__[name]=None
166            del self._component[ self._declarations[name].type() ][name]
167            del self._declarations[name]
168
169    def _setattr_exec(self, name, val):
170        self._clear_attribute(name)
171        val.name=name
172        self._add_temporary_set(val)
173        self._component[val.type()][name]=val
174        self._declarations[name] = val
175        self.__dict__[name]=val
176
177        # Presumably self.model refers to the 'root' Block that will
178        # eventually be solved, whereas '_parent_block' refers to the
179        # immediate parent.
180
181        # Don't let '_parent_block' attributes trigger recursion
182        if isinstance(val, Block):
183            self.__dict__["_parent_block"] = self
184        else:
185            curr = self
186            while curr is not None:
187                val.model = curr
188                curr = self._parent_block
189        # self is the top level model if self.model is None; otherwise,
190        # self.model is the top level model
191        if self.model is not None:
192            self.__dict__["model"] = self.model
193        else:
194            self.__dict__["model"] = self
195
196#         # Need to break infinite loop of attribute setting
197#         if isinstance(val, Block) and name != "_parent_block":
198#             val._parent_block = self
199#         else:
200#             curr = self
201#             while not curr is None:
202#                val.model=curr
203#                curr = self._parent_block
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 != "_component" and isinstance(val, Component):
218            #
219            # If this is a component type, then simply set it
220            #
221            self._setattr_exec(name,val)
222        else:
223            #
224            # Try to set the value. This may fail if the attribute
225            # does not already exist in this model, if the set_value
226            # function is not defined, or if a bad value is
227            # provided. In the latter case, a ValueError will be
228            # thrown, which # we raise. Otherwise, this is an object
229            # that we need to set directly.
230            #
231            try:
232                self.__dict__[name].set_value(val)
233            except ValueError, e:
234                raise
235            except Exception, e:
236                self.__dict__[name]=val
237
238    def pprint(self, filename=None, ostream=None):
239        """
240        Print a summary of the model info
241        """
242        if ostream is None:
243           ostream = sys.stdout
244        if filename is not None:
245           OUTPUT=open(filename,"w")
246           self.pprint(ostream=OUTPUT)
247           OUTPUT.close()
248           return
249        if ostream is None:
250           ostream = sys.stdout
251        #
252        # We hard-code the order of the core Pyomo modeling
253        # components, to ensure that the output follows the logical order
254        # that expected by a user.
255        #
256        items = [Set, RangeSet, Param, Var, Objective, Constraint, Block]
257        for item in ExtensionPoint(IModelComponent):
258            if not item in items:
259                items.append(item)
260        for item in items:
261            if not item in self._component:
262                continue
263            keys = self._component[item].keys()
264            keys.sort()
265            #
266            # NOTE: these conditional checks should not be hard-coded.
267            #
268            print >>ostream, len(keys), item.__name__+" Declarations"
269            for key in keys:
270                self._component[item][key].pprint(ostream)
271            print >>ostream, ""
272        #
273        # Model Order
274        #
275        print >>ostream, len(self._declarations),"Declarations:",
276        for name in self._declarations:
277          print >>ostream, name,
278        print >>ostream, ""
279
280    def display(self, filename=None, ostream=None):
281        """
282        Print the Pyomo model in a verbose format.
283        """
284        if filename is not None:
285           OUTPUT=open(filename,"w")
286           self.display(ostream=OUTPUT)
287           OUTPUT.close()
288           return
289        if ostream is None:
290           ostream = sys.stdout
291        if self.type() is Block:
292            print >>ostream, "Block "+self.name
293        else:
294            print >>ostream, "Model "+self.name
295        #
296        print >>ostream, ""
297        print >>ostream, "  Variables:"
298        VAR = self.active_components(Var)
299        if len(VAR) == 0:
300            print >>ostream, "    None"
301        else:
302            for ndx in VAR:
303                VAR[ndx].display(prefix="    ",ostream=ostream)
304        #
305        print >>ostream, ""
306        print >>ostream, "  Objectives:"
307        OBJ = self.active_components(Objective)
308        if len(OBJ) == 0:
309            print >>ostream, "    None"
310        else:
311            for ndx in OBJ:
312                OBJ[ndx].display(prefix="    ",ostream=ostream)
313        print >>ostream, ""
314        #
315        CON = self.active_components(Constraint)
316        print >>ostream, "  Constraints:"
317        if len(CON) == 0:
318            print >>ostream, "    None"
319        else:
320            for ndx in CON:
321                CON[ndx].display(prefix="    ",ostream=ostream)
322
Note: See TracBrowser for help on using the repository browser.