source: coopr.pyomo/stable/coopr/pyomo/base/numvalue.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.

........

File size: 10.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__all__ = ['value', 'NumericValue', 'as_numeric', 'NumericConstant', 'ZeroConstant', 'OneConstant', 'is_constant']
12
13import plugin
14import pyutilib.math
15import sys
16from set_types import Reals
17
18
19##------------------------------------------------------------------------
20##
21## Standard types of expressions
22##
23##------------------------------------------------------------------------
24
25def create_name(name, ndx):
26    if ndx is None:
27        return name
28    if type(ndx) is tuple:
29        tmp = str(ndx).replace(', ',',')
30        return name+"["+tmp[1:-1]+"]"
31    return name+"["+str(ndx)+"]"
32
33def value(obj):
34    """
35    A utility function that returns the value of a Pyomo object or expression.
36
37    If the argument is None, a numeric value or a string, then this function simply
38    returns the argument.  Otherwise, if the argument is a NumericValue then the
39    __call__ method is executed.
40    """
41    if obj is None:
42        return None
43    elif type(obj) in [bool,int,long,float,str]:
44        return obj
45    if not isinstance(obj, NumericValue):
46        raise ValueError, "Object "+str(obj)+" is not a NumericValue object"
47    tmp = obj()
48    if tmp is None:
49        raise ValueError, "No value for uninitialized NumericValue object "+obj.name
50    return tmp
51
52def is_constant(obj):
53    """
54    A utility function that returns a boolean that indicates whether the object is a constant
55    """
56    if obj is None:
57        return False   
58    elif type(obj) in [bool,int,long,float]:
59        return True
60    if not isinstance(obj, NumericValue):
61        return False
62    return obj.is_constant()
63
64def as_numeric(obj):
65    """Verify that this obj is a NumericValue or intrinsic value"""
66    if isinstance(obj,NumericValue):
67       return obj.as_numeric()
68    if type(obj) in [bool,int,long,float]:
69       return NumericConstant(value=obj)
70    raise ValueError, "This object is not a numeric value: "+str(obj)
71
72
73class NumericValue(object):
74    """An object that contains a numeric value"""
75
76    __hash__ = None
77
78    #
79    # kwargs are a nice programmer convenience, but their manipulation appears too expensive in a highly used base class.
80    #
81    # the validate_value argument only applies to the value supplied in the constructor, and does not prevent
82    # subsequent value assignments from being checked.
83    #
84    def __init__(self, name='unknown', value=None, domain=None, validate_value=True):
85
86        self.name = name
87        self.domain = domain
88
89        if (value and pyutilib.math.is_nan(value)):
90            value = pyutilib.math.nan
91
92        # a numeric value is only constrained by the domain,
93        # if specified. avoid invoking set_value() here to
94        # accelerate object construction, which takes
95        # significant time due to the typical number of
96        # occurrences. similarly, we are avoiding the
97        # invocation of _valid_value.
98        if (value is not None) and (validate_value is True) and (self.domain is not None) and (value not in self.domain):
99           raise ValueError, "Numeric value `"+str(value)+"` is not in domain "+str(self.domain)           
100
101        self.value = value
102       
103    def is_constant(self):
104        return True
105
106    def fixed_value(self):
107        return False
108
109    def as_numeric(self):
110        return self
111
112    def pprint(self, ostream=None):
113        raise IOError, "NumericValue:pprint is not defined"     #pragma:nocover
114
115    def display(self, ostream=None):
116        self.pprint(ostream=ostream)
117
118    def reset(self):            #pragma:nocover
119        pass                    #pragma:nocover
120
121    def set_value(self, val):
122        if self._valid_value(val):
123            self.value=val
124
125    def __call__(self, exception=True):
126        return self.value
127
128    def __float__(self):
129        tmp = self.__call__()
130        if tmp is None:
131            raise ValueError, "Cannot coerce numeric value `"+self.name+"' to float because it is uninitialized."
132        return float(tmp)
133
134    def __int__(self):
135        tmp = self.__call__()
136        if tmp is None:
137            raise ValueError, "Cannot coerce numeric value `"+self.name+"' to integer because it is uninitialized."
138        return int(tmp)
139
140    def _valid_value(self,value,use_exception=True):
141        #print "HERE X", self.domain is None
142        ans = value is None or self.domain is None or value in self.domain
143        if not ans and use_exception:
144           raise ValueError, "Numeric value `"+str(value)+"` is not in domain "+str(self.domain)
145        return ans
146
147    def X__getattr__(self,name):
148        #print "GETATTR",name
149        #d = self.__dict__
150        try:
151            return self.__dict__[name]
152        except:
153            pass
154        try:
155            return self.__dict__["_attr_"+name]
156        except:
157            pass
158        raise AttributeError, "Unknown attribute `"+str(name)+"' for object with type "+str(type(self))
159
160    def X__setattr__(self,name,val):
161        ##print "SETATTR",name,val
162        if name == "__class__":
163           self.__class__ = val
164           return
165        if name[0] == "_":
166           self.__dict__[name] = val
167           return
168        if name in self._standard_attr:
169           self.__dict__["_attr_"+name] = val
170           return
171        raise AttributeError, "Unallowable attribute `"+name+"`"
172        #self._standard_attr[name] = val
173
174    def __lt__(self,other):
175        """Less than operator
176
177        (Called in response to 'self < other' or 'other > self'.)
178        """
179        return plugin.ExpressionFactory('<', [self,as_numeric(other)])
180
181    def __gt__(self,other):
182        """Greater than operator
183
184        (Called in response to 'self > other' or 'other < self'.)
185        """
186        return plugin.ExpressionFactory('>', [self,as_numeric(other)])
187
188    def __le__(self,other):
189        """Less than or equal operator
190
191        (Called in response to 'self <= other' or 'other >= self'.)
192        """
193        return plugin.ExpressionFactory('<=', [self,as_numeric(other)])
194
195    def __ge__(self,other):
196        """Greater than or equal operator
197
198        (Called in response to 'self >= other' or 'other <= self'.)
199        """
200        return plugin.ExpressionFactory('>=', [self,as_numeric(other)])
201
202    def __eq__(self,other):
203        """Equal to operator
204
205        (Called in response to 'self = other'.)
206        """
207        return plugin.ExpressionFactory('=', [self,as_numeric(other)])
208
209    def __add__(self,other):
210        """Binary addition
211
212        (Called in response to 'self + other'.)
213        """
214        return expr.generate_expression('add',self,other)
215
216    def __sub__(self,other):
217        """ Binary subtraction
218
219        (Called in response to 'self - other'.)
220        """
221        return expr.generate_expression('sub',self,other)
222
223    def __mul__(self,other):
224        """ Binary multiplication
225
226        (Called in response to 'self * other'.)
227        """
228        return expr.generate_expression('mul',self,other)
229
230    def __div__(self,other):
231        """ Binary division
232
233        (Called in response to 'self / other'.)
234        """
235        return expr.generate_expression('div',self,other)
236
237    def __pow__(self,other):
238        """ Binary power
239
240        (Called in response to 'self ** other'.)
241        """
242        return expr.generate_expression('pow',self,other)
243
244    def __radd__(self,other):
245        """Binary addition
246
247        (Called in response to 'other + self'.)
248        """
249        return expr.generate_expression('radd',self,other)
250
251    def __rsub__(self,other):
252        """ Binary subtraction
253
254        (Called in response to 'other - self'.)
255        """
256        return expr.generate_expression('rsub',self,other)
257
258    def __rmul__(self,other):
259        """ Binary multiplication
260
261        (Called in response to 'other * self'.)
262        """
263        return expr.generate_expression('rmul',self,other)
264       
265    def __rdiv__(self,other):
266        """ Binary division
267
268        (Called in response to 'other / self'.)
269        """
270        return expr.generate_expression('rdiv',self,other)
271
272    def __rpow__(self,other):
273        """ Binary power
274
275        (Called in response to 'other ** self'.)
276        """
277        return expr.generate_expression('rpow',self,other)
278
279    def __neg__(self):
280        """ Negation
281
282        (Called in response to '- self'.)
283        """
284        return expr.generate_expression('neg',self)
285
286    def __pos__(self):
287        """ Positive expression
288
289        (Called in response to '+ self'.)
290        """
291        return self
292
293    def __abs__(self):
294        """ Absolute value
295
296        (Called in response to 'abs(self)'.)
297        """
298        return expr.generate_expression('abs',self)
299
300
301class NumericConstant(NumericValue):
302    """An object that contains a constant numeric value"""
303
304    def __init__(self, name='unknown', domain=None, value=None):
305        if domain is None:
306           domain = Reals
307        # NOTE: we in general don't perform domain validation of numeric constants,
308        #       especially because the user/caller has specified the value, and
309        #       typically does not specify the domain. the domain might be useful
310        #       with meta-level symbolic expression analysis, but even there the
311        #       above default of a real domain is questionable.
312        NumericValue.__init__(self, name=name, domain=domain, value=value, validate_value=False)
313
314    def fixed_value(self):
315        return True
316
317    def __call__(self, exception=True):
318        return self.value
319
320    def __str__(self):
321        return str(self.value)
322
323    def __eq__(self,other):
324        """Equal to operator
325
326        (Called in response to 'self == other'.)
327        """
328        return self.value == other
329
330    def pprint(self, ostream=None):
331        if ostream is None:
332           ostream = sys.stdout
333        print >>ostream, str(self),
334
335    def simplify(self, model):
336        return self                 #pragma:nocover
337
338
339ZeroConstant = NumericConstant(value=0)
340OneConstant = NumericConstant(value=1)
341
342import expr
Note: See TracBrowser for help on using the repository browser.