source: trunk/coopr/pyomo/base/numvalue.py @ 1438

Last change on this file since 1438 was 1438, checked in by wehart, 11 years ago

A variety of bug fixes and revised semantics, based on
feedback from JP:

. The value 'None' is accepted by all NumValue? objects, and this indicates that the
object has not been initialized.

. ParamValue? objects are print their name, rather than their value.

. Bug fix in _SumExpression.simplify()

. Updates for baselines and tests based on these changes.

File size: 8.5 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']
12
13import plugin
14import pyutilib.plugin
15import sys
16from set_types import Reals
17
18
19##------------------------------------------------------------------------
20##
21## Standard types of expressions
22##
23##------------------------------------------------------------------------
24
25def value(obj):
26    """
27    A utility function that returns the value of an expression
28    """
29    if obj is None:
30        return None
31    elif type(obj) in [bool,int,long,float]:
32        return obj
33    if not isinstance(obj, NumericValue):
34        raise ValueError, "Object "+str(obj)+" is not a NumericValue object"
35    tmp = obj()
36    if tmp is None:
37        raise ValueError, "No value for uninitialized NumericValue object "+obj.name
38    return tmp
39   
40
41def as_numeric(obj):
42    """Verify that this obj is a NumericValue or intrinsic value"""
43    if isinstance(obj,NumericValue):
44       return obj.as_numeric()
45    if type(obj) in [bool,int,long,float]:
46       return NumericConstant(value=obj)
47    raise ValueError, "This object is not a numeric value: "+str(obj)
48
49
50class NumericValue(object):
51    """An object that contains a numeric value"""
52
53    __hash__ = None
54
55    def __init__(self, **kwds):
56        if 'name' in kwds:
57            self.name=str(kwds['name'])
58        else:
59            self.name="unknown"
60        if 'domain' in kwds:
61            self.domain=kwds['domain']
62        elif 'within' in kwds:
63            self.domain=kwds['within']
64        else:
65            self.domain=None
66        if 'value' in kwds:
67            if pyutilib.is_nan(kwds['value']):
68                self.value=pyutilib.nan
69            else:
70                self.set_value(kwds['value'])
71        else:
72            self.value=None
73        self.model=None
74        #print "NUMVAL",self.name,self.domain,self.value
75
76    def fixed_value(self):
77        return False
78
79    def as_numeric(self):
80        return self
81
82    def pprint(self, ostream=None):
83        raise IOError, "NumericValue:pprint is not defined"     #pragma:nocover
84
85    def display(self, ostream=None):
86        self.pprint(ostream=ostream)
87
88    def reset(self):            #pragma:nocover
89        pass                    #pragma:nocover
90
91    def set_value(self, val):
92        if self._valid_value(val):
93            self.value=val
94
95    def __call__(self, exception=True):
96        return self.value
97
98    def __float__(self):
99        tmp = self.__call__()
100        if tmp is None:
101            raise ValueError, "Cannot coerce variable `"+self.name+"' to float because it is uninitialized."
102        return float(tmp)
103
104    def __int__(self):
105        tmp = self.__call__()
106        if tmp is None:
107            raise ValueError, "Cannot coerce variable `"+self.name+"' to integer because it is uninitialized."
108        return int(tmp)
109
110    def _valid_value(self,value,use_exception=True):
111        #print "HERE X", self.domain is None
112        ans = value is None or self.domain is None or value in self.domain
113        if not ans and use_exception:
114           raise ValueError, "Numeric value `"+str(value)+"` is not in domain "+str(self.domain)
115        return ans
116
117    def X__getattr__(self,name):
118        #print "GETATTR",name
119        #d = self.__dict__
120        try:
121            return self.__dict__[name]
122        except:
123            pass
124        try:
125            return self.__dict__["_attr_"+name]
126        except:
127            pass
128        raise AttributeError, "Unknown attribute `"+str(name)+"' for object with type "+str(type(self))
129
130    def X__setattr__(self,name,val):
131        ##print "SETATTR",name,val
132        if name == "__class__":
133           self.__class__ = val
134           return
135        if name[0] == "_":
136           self.__dict__[name] = val
137           return
138        if name in self._standard_attr:
139           self.__dict__["_attr_"+name] = val
140           return
141        raise AttributeError, "Unallowable attribute `"+name+"`"
142        #self._standard_attr[name] = val
143
144    def __lt__(self,other):
145        """Less than operator
146
147        (Called in response to 'self < other' or 'other > self'.)
148        """
149        return plugin.ExpressionFactory('<', [self,as_numeric(other)])
150
151    def __gt__(self,other):
152        """Greater than operator
153
154        (Called in response to 'self > other' or 'other < self'.)
155        """
156        return plugin.ExpressionFactory('>', [self,as_numeric(other)])
157
158    def __le__(self,other):
159        """Less than or equal operator
160
161        (Called in response to 'self <= other' or 'other >= self'.)
162        """
163        return plugin.ExpressionFactory('<=', [self,as_numeric(other)])
164
165    def __ge__(self,other):
166        """Greater than or equal operator
167
168        (Called in response to 'self >= other' or 'other <= self'.)
169        """
170        return plugin.ExpressionFactory('>=', [self,as_numeric(other)])
171
172    def __eq__(self,other):
173        """Equal to operator
174
175        (Called in response to 'self = other'.)
176        """
177        return plugin.ExpressionFactory('=', [self,as_numeric(other)])
178
179    def __add__(self,other):
180        """Binary addition
181
182        (Called in response to 'self + other'.)
183        """
184        return expr.generate_expression('add',self,other)
185
186    def __sub__(self,other):
187        """ Binary subtraction
188
189        (Called in response to 'self - other'.)
190        """
191        return expr.generate_expression('sub',self,other)
192
193    def __mul__(self,other):
194        """ Binary multiplication
195
196        (Called in response to 'self * other'.)
197        """
198        return expr.generate_expression('mul',self,other)
199
200    def __div__(self,other):
201        """ Binary division
202
203        (Called in response to 'self / other'.)
204        """
205        return expr.generate_expression('div',self,other)
206
207    def __pow__(self,other):
208        """ Binary power
209
210        (Called in response to 'self ** other'.)
211        """
212        return expr.generate_expression('pow',self,other)
213
214    def __radd__(self,other):
215        """Binary addition
216
217        (Called in response to 'other + self'.)
218        """
219        return expr.generate_expression('radd',self,other)
220
221    def __rsub__(self,other):
222        """ Binary subtraction
223
224        (Called in response to 'other - self'.)
225        """
226        return expr.generate_expression('rsub',self,other)
227
228    def __rmul__(self,other):
229        """ Binary multiplication
230
231        (Called in response to 'other * self'.)
232        """
233        return expr.generate_expression('rmul',self,other)
234       
235    def __rdiv__(self,other):
236        """ Binary division
237
238        (Called in response to 'other / self'.)
239        """
240        return expr.generate_expression('rdiv',self,other)
241
242    def __rpow__(self,other):
243        """ Binary power
244
245        (Called in response to 'other ** self'.)
246        """
247        return expr.generate_expression('rpow',self,other)
248
249    def __neg__(self):
250        """ Negation
251
252        (Called in response to '- self'.)
253        """
254        return expr.generate_expression('neg',self)
255
256    def __pos__(self):
257        """ Positive expression
258
259        (Called in response to '+ self'.)
260        """
261        return self
262
263    def __abs__(self):
264        """ Absolute value
265
266        (Called in response to 'abs(self)'.)
267        """
268        return expr.generate_expression('abs',self)
269
270
271class NumericConstant(NumericValue):
272    """An object that contains a constant numeric value"""
273
274    def __init__(self, **kwds):
275        if not 'domain' in kwds:
276            kwds['domain'] = Reals
277        NumericValue.__init__(self,**kwds)
278
279    def fixed_value(self):
280        return True
281
282    def __call__(self, exception=True):
283        return self.value
284
285    def __str__(self):
286        return str(self.value)
287
288    def __eq__(self,other):
289        """Equal to operator
290
291        (Called in response to 'self == other'.)
292        """
293        return self.value == other
294
295    def pprint(self, ostream=None):
296        if ostream is None:
297           ostream = sys.stdout
298        print >>ostream, str(self),
299
300    def simplify(self, model):
301        return self                 #pragma:nocover
302
303
304ZeroConstant = NumericConstant(value=0)
305OneConstant = NumericConstant(value=1)
306
307import expr
Note: See TracBrowser for help on using the repository browser.