source: coopr.pyomo/stable/coopr/pyomo/base/numvalue.py @ 3182

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

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

........

r3116 | jwatson | 2010-10-18 14:08:00 -0600 (Mon, 18 Oct 2010) | 3 lines


First of a few commits involving an experimental linear compaction of the expression tree associated with a constraint, in order to save both memory and time.

........

r3117 | jwatson | 2010-10-18 14:09:13 -0600 (Mon, 18 Oct 2010) | 3 lines


Renaming linear representation module.

........

r3119 | jwatson | 2010-10-18 21:06:55 -0600 (Mon, 18 Oct 2010) | 3 lines


More exhaustive additions relating to linear expression encodings. No functional change to pyomo unless the --linearize-expressions options is specified. All tests are passing.

........

r3121 | jwatson | 2010-10-20 12:02:31 -0600 (Wed, 20 Oct 2010) | 3 lines


Fixing white-space issue when writing quadratic terms in LP files. Gurobi 4.0 beta wants more white-space than CPLEX, which is easy enough to accomodate.

........

r3123 | jwatson | 2010-10-20 13:02:06 -0600 (Wed, 20 Oct 2010) | 3 lines


Changing "integer" section label with the more technically correct "general" in the LP file writer. The former is not recognized by Gurobi, and actually does not appear in the CPLEX documentation either. I'm not sure where we got this, but the fix corrects/bypasses the issue entirely.

........

r3130 | wehart | 2010-10-20 20:44:17 -0600 (Wed, 20 Oct 2010) | 2 lines


Update of coopr.pyomo CHANGELOG for the 2.4 release.

........

r3132 | prsteel | 2010-10-21 15:30:40 -0600 (Thu, 21 Oct 2010) | 2 lines


Adding myself as a developer.

........

r3133 | jwatson | 2010-10-21 15:41:58 -0600 (Thu, 21 Oct 2010) | 5 lines


Various updates, mostly relating to linear expression representations debugging. Initial tests indicate very significant speed and memory reductions (at least for PH), with regression testing performed against a few initial benchmarks. No functional change if linear expressions are not enabled, which is the default


On the variable front, I have added output of variable Status in the pprint(), to facilitate debugging.

........

r3136 | khunter | 2010-10-22 10:19:32 -0600 (Fri, 22 Oct 2010) | 2 lines


Add name as a developer.

........

r3140 | jwatson | 2010-10-22 15:47:33 -0600 (Fri, 22 Oct 2010) | 3 lines


When constructing a linear representation, dump the canonical representation on the ConstraintData? class if it exists - these take up a large amount of space as well.

........

r3141 | jwatson | 2010-10-22 16:54:49 -0600 (Fri, 22 Oct 2010) | 3 lines


Added a "nochecking" keyword argument to Params. Intended strictly for use by algorithm developers, it by-passes the call to _valid_indexed_component, which was taking a huge amount of time in various PySP algorithms. Use sparingly and judiciously! May also apply in the near future to other aspects of setitem.

........

r3142 | jwatson | 2010-10-22 17:07:45 -0600 (Fri, 22 Oct 2010) | 3 lines


Suppression of index validation in Param::setitem when nochecking is enabled.

........

r3144 | jwatson | 2010-10-22 22:15:52 -0600 (Fri, 22 Oct 2010) | 3 lines


Update of test output baseline to reflect addition of variable status output in pretty-print.

........

r3149 | wehart | 2010-10-23 22:59:06 -0600 (Sat, 23 Oct 2010) | 3 lines


Changes to allow RangeSet? instances to be defined with
floating point start, stop and step arguments.

........

r3150 | wehart | 2010-10-23 22:59:31 -0600 (Sat, 23 Oct 2010) | 2 lines


Allowing string values to be elements of a Boolean set.

........

r3151 | wehart | 2010-10-23 23:00:47 -0600 (Sat, 23 Oct 2010) | 2 lines


Removing the name_str() method, which I didn't mean to commit.

........

r3153 | jwatson | 2010-10-24 22:14:15 -0600 (Sun, 24 Oct 2010) | 5 lines


Adding logic for LP writer when dealing with linearized expressions involving fixed variables.


Added "has_discrete_variables" method to PyomoModel?, to support query by MIP plugins - which often need this method to determine the type of solution information (e.g., duals) to extract.

........

r3158 | claird | 2010-10-25 12:01:21 -0600 (Mon, 25 Oct 2010) | 1 line


Added exception for multiple objectives - not currently handled by the NL writier

........

r3159 | claird | 2010-10-25 12:03:18 -0600 (Mon, 25 Oct 2010) | 1 line


Commented out second objective function so there are not multiple objectives in the example

........

r3166 | jwatson | 2010-10-26 19:42:59 -0600 (Tue, 26 Oct 2010) | 3 lines


Various performance-related enhancements, including a rework of NumericValue? and NumericConstant? internals.

........

r3167 | jwatson | 2010-10-26 20:05:25 -0600 (Tue, 26 Oct 2010) | 3 lines


Restoring older version of rangeset.py - the latest commit caused all kinds of test failures, for reasons I haven't had time to explore.

........

r3171 | jwatson | 2010-10-28 21:02:40 -0600 (Thu, 28 Oct 2010) | 3 lines


Fixing bug observed by John regarding passing of keyword arguments to the Constraint base class initializer.

........

r3181 | wehart | 2010-10-28 21:45:53 -0600 (Thu, 28 Oct 2010) | 2 lines


Updating changelog

........

File size: 9.6 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 is very expensive in a highly used base class.
80    #
81    def __init__(self, name='unknown', value=None, domain=None):
82
83        self.name = name
84        self.domain = domain
85
86        if (value and pyutilib.math.is_nan(value)):
87            value = pyutilib.math.nan
88
89        # a numeric value is only constrained by the domain,
90        # if specified. avoid invoking set_value() here to
91        # accelerate object construction, which takes
92        # significant time due to the typical number of
93        # occurrences. similarly, we are avoiding the
94        # invocation of _valid_value.
95        if (value is not None) and (self.domain is not None) and (value not in self.domain):
96           raise ValueError, "Numeric value `"+str(value)+"` is not in domain "+str(self.domain)           
97
98        self.value = value
99       
100    def is_constant(self):
101        return True
102
103    def fixed_value(self):
104        return False
105
106    def as_numeric(self):
107        return self
108
109    def pprint(self, ostream=None):
110        raise IOError, "NumericValue:pprint is not defined"     #pragma:nocover
111
112    def display(self, ostream=None):
113        self.pprint(ostream=ostream)
114
115    def reset(self):            #pragma:nocover
116        pass                    #pragma:nocover
117
118    def set_value(self, val):
119        if self._valid_value(val):
120            self.value=val
121
122    def __call__(self, exception=True):
123        return self.value
124
125    def __float__(self):
126        tmp = self.__call__()
127        if tmp is None:
128            raise ValueError, "Cannot coerce numeric value `"+self.name+"' to float because it is uninitialized."
129        return float(tmp)
130
131    def __int__(self):
132        tmp = self.__call__()
133        if tmp is None:
134            raise ValueError, "Cannot coerce numeric value `"+self.name+"' to integer because it is uninitialized."
135        return int(tmp)
136
137    def _valid_value(self,value,use_exception=True):
138        #print "HERE X", self.domain is None
139        ans = value is None or self.domain is None or value in self.domain
140        if not ans and use_exception:
141           raise ValueError, "Numeric value `"+str(value)+"` is not in domain "+str(self.domain)
142        return ans
143
144    def X__getattr__(self,name):
145        #print "GETATTR",name
146        #d = self.__dict__
147        try:
148            return self.__dict__[name]
149        except:
150            pass
151        try:
152            return self.__dict__["_attr_"+name]
153        except:
154            pass
155        raise AttributeError, "Unknown attribute `"+str(name)+"' for object with type "+str(type(self))
156
157    def X__setattr__(self,name,val):
158        ##print "SETATTR",name,val
159        if name == "__class__":
160           self.__class__ = val
161           return
162        if name[0] == "_":
163           self.__dict__[name] = val
164           return
165        if name in self._standard_attr:
166           self.__dict__["_attr_"+name] = val
167           return
168        raise AttributeError, "Unallowable attribute `"+name+"`"
169        #self._standard_attr[name] = val
170
171    def __lt__(self,other):
172        """Less than operator
173
174        (Called in response to 'self < other' or 'other > self'.)
175        """
176        return plugin.ExpressionFactory('<', [self,as_numeric(other)])
177
178    def __gt__(self,other):
179        """Greater than operator
180
181        (Called in response to 'self > other' or 'other < self'.)
182        """
183        return plugin.ExpressionFactory('>', [self,as_numeric(other)])
184
185    def __le__(self,other):
186        """Less than or equal operator
187
188        (Called in response to 'self <= other' or 'other >= self'.)
189        """
190        return plugin.ExpressionFactory('<=', [self,as_numeric(other)])
191
192    def __ge__(self,other):
193        """Greater than or equal operator
194
195        (Called in response to 'self >= other' or 'other <= self'.)
196        """
197        return plugin.ExpressionFactory('>=', [self,as_numeric(other)])
198
199    def __eq__(self,other):
200        """Equal to operator
201
202        (Called in response to 'self = other'.)
203        """
204        return plugin.ExpressionFactory('=', [self,as_numeric(other)])
205
206    def __add__(self,other):
207        """Binary addition
208
209        (Called in response to 'self + other'.)
210        """
211        return expr.generate_expression('add',self,other)
212
213    def __sub__(self,other):
214        """ Binary subtraction
215
216        (Called in response to 'self - other'.)
217        """
218        return expr.generate_expression('sub',self,other)
219
220    def __mul__(self,other):
221        """ Binary multiplication
222
223        (Called in response to 'self * other'.)
224        """
225        return expr.generate_expression('mul',self,other)
226
227    def __div__(self,other):
228        """ Binary division
229
230        (Called in response to 'self / other'.)
231        """
232        return expr.generate_expression('div',self,other)
233
234    def __pow__(self,other):
235        """ Binary power
236
237        (Called in response to 'self ** other'.)
238        """
239        return expr.generate_expression('pow',self,other)
240
241    def __radd__(self,other):
242        """Binary addition
243
244        (Called in response to 'other + self'.)
245        """
246        return expr.generate_expression('radd',self,other)
247
248    def __rsub__(self,other):
249        """ Binary subtraction
250
251        (Called in response to 'other - self'.)
252        """
253        return expr.generate_expression('rsub',self,other)
254
255    def __rmul__(self,other):
256        """ Binary multiplication
257
258        (Called in response to 'other * self'.)
259        """
260        return expr.generate_expression('rmul',self,other)
261       
262    def __rdiv__(self,other):
263        """ Binary division
264
265        (Called in response to 'other / self'.)
266        """
267        return expr.generate_expression('rdiv',self,other)
268
269    def __rpow__(self,other):
270        """ Binary power
271
272        (Called in response to 'other ** self'.)
273        """
274        return expr.generate_expression('rpow',self,other)
275
276    def __neg__(self):
277        """ Negation
278
279        (Called in response to '- self'.)
280        """
281        return expr.generate_expression('neg',self)
282
283    def __pos__(self):
284        """ Positive expression
285
286        (Called in response to '+ self'.)
287        """
288        return self
289
290    def __abs__(self):
291        """ Absolute value
292
293        (Called in response to 'abs(self)'.)
294        """
295        return expr.generate_expression('abs',self)
296
297
298class NumericConstant(NumericValue):
299    """An object that contains a constant numeric value"""
300
301    def __init__(self, name='unknown', domain=None, value=None):
302        if domain is None:
303           domain = Reals
304        NumericValue.__init__(self, name=name, domain=domain, value=value)
305
306    def fixed_value(self):
307        return True
308
309    def __call__(self, exception=True):
310        return self.value
311
312    def __str__(self):
313        return str(self.value)
314
315    def __eq__(self,other):
316        """Equal to operator
317
318        (Called in response to 'self == other'.)
319        """
320        return self.value == other
321
322    def pprint(self, ostream=None):
323        if ostream is None:
324           ostream = sys.stdout
325        print >>ostream, str(self),
326
327    def simplify(self, model):
328        return self                 #pragma:nocover
329
330
331ZeroConstant = NumericConstant(value=0)
332OneConstant = NumericConstant(value=1)
333
334import expr
Note: See TracBrowser for help on using the repository browser.