1#  ___________________________________________________________________________
2#
3#  Pyomo: Python Optimization Modeling Objects
4#  Copyright 2017 National Technology and Engineering Solutions of Sandia, LLC
5#  Under the terms of Contract DE-NA0003525 with National Technology and
6#  Engineering Solutions of Sandia, LLC, the U.S. Government retains certain
7#  rights in this software.
8#  This software is distributed under the 3-clause BSD License.
9#  ___________________________________________________________________________
10#
11# Unit Tests for Python numeric values
12#
13
14import os
15from os.path import abspath, dirname
16currdir = dirname(abspath(__file__))+os.sep
17
18from math import nan, inf
19import pyomo.common.unittest as unittest
20
21from pyomo.environ import (value, ConcreteModel, Param, Var,
22                           polynomial_degree, is_constant, is_fixed,
23                           is_potentially_variable, is_variable_type)
24from pyomo.core.expr.numvalue import (NumericConstant,
25                                      as_numeric,
26                                      is_numeric_data)
27
28try:
29    import numpy
30    numpy_available=True
31except:
32    numpy_available=False
33
34class MyBogusType(object):
35    def __init__(self, val=0):
36        self.val = float(val)
37
38class MyBogusNumericType(MyBogusType):
39    def __add__(self, other):
40        return MyBogusNumericType(self.val + float(other))
41
42
43class Test_value(unittest.TestCase):
44
45    def test_none(self):
46        val = None
47        try:
48            value(val)
49            self.fail("Expected ValueError")
50        except ValueError:
51            pass
52
53    def test_bool(self):
54        val = False
55        self.assertEqual(val, value(val))
56        val = True
57        self.assertEqual(val, value(val))
58
59    def test_float(self):
60        val = 1.1
61        self.assertEqual(val, value(val))
62
63    def test_int(self):
64        val = 1
65        self.assertEqual(val, value(val))
66
67    def test_long(self):
68        val = int(1e10)
69        self.assertEqual(val, value(val))
70
71    def test_string(self):
72        val = 'foo'
73        try:
74            value(val)
75            self.fail("Expected ValueError")
76        except ValueError:
77            pass
78
79    def test_const1(self):
80        val = NumericConstant(1.0)
81        self.assertEqual(1.0, value(val))
82
83    def test_error1(self):
84        class A(object): pass
85        val = A()
86        try:
87            value(val)
88            self.fail("Expected TypeError")
89        except TypeError:
90            pass
91
92    def test_unknownType(self):
93        ref = MyBogusType(42)
94        try:
95            val = value(ref)
96            self.fail("Expected TypeError")
97        except TypeError:
98            pass
99
100    def test_unknownNumericType(self):
101        ref = MyBogusNumericType(42)
102        val = value(ref)
103        self.assertEqual(val().val, 42)
104        from pyomo.core.base.numvalue import native_numeric_types, native_types
105        self.assertIn(MyBogusNumericType, native_numeric_types)
106        self.assertIn(MyBogusNumericType, native_types)
107        native_numeric_types.remove(MyBogusNumericType)
108        native_types.remove(MyBogusNumericType)
109
110
111class Test_is_numeric_data(unittest.TestCase):
112
113    def test_string(self):
114        self.assertEqual(is_numeric_data("a"), False)
115        self.assertEqual(is_numeric_data(b"a"), False)
116
117    def test_float(self):
118        self.assertEqual(is_numeric_data(0.0), True)
119
120    def test_int(self):
121        self.assertEqual(is_numeric_data(0), True)
122
123    def test_NumericValue(self):
124        self.assertEqual(is_numeric_data(NumericConstant(1.0)), True)
125
126    def test_error(self):
127        class A(object): pass
128        val = A()
129        self.assertEqual(False, is_numeric_data(val))
130
131    def test_unknownNumericType(self):
132        ref = MyBogusNumericType(42)
133        self.assertTrue(is_numeric_data(ref))
134        from pyomo.core.base.numvalue import native_numeric_types, native_types
135        self.assertIn(MyBogusNumericType, native_numeric_types)
136        self.assertIn(MyBogusNumericType, native_types)
137        native_numeric_types.remove(MyBogusNumericType)
138        native_types.remove(MyBogusNumericType)
139
140
141class Test_value(unittest.TestCase):
142
143    def test_none(self):
144        val = None
145        self.assertEqual(val, value(val))
146
147    def test_bool(self):
148        val = False
149        self.assertEqual(val, value(val))
150
151    def test_float(self):
152        val = 1.1
153        self.assertEqual(val, value(val))
154
155    def test_int(self):
156        val = 1
157        self.assertEqual(val, value(val))
158
159    def test_long(self):
160        val = int(1e10)
161        self.assertEqual(val, value(val))
162
163    def test_nan(self):
164        val = nan
165        self.assertEqual(id(val), id(value(val)))
166
167    def test_inf(self):
168        val = inf
169        self.assertEqual(id(val), id(value(val)))
170
171    def test_string(self):
172        val = 'foo'
173        self.assertEqual(val, value(val))
174
175    def test_const1(self):
176        val = NumericConstant(1.0)
177        self.assertEqual(1.0, value(val))
178
179    def test_const3(self):
180        val = NumericConstant(nan)
181        self.assertEqual(id(nan), id(value(val)))
182
183    def test_const4(self):
184        val = NumericConstant(inf)
185        self.assertEqual(id(inf), id(value(val)))
186
187    def test_param1(self):
188        m = ConcreteModel()
189        m.p = Param(mutable=True, initialize=2)
190        self.assertEqual(2, value(m.p))
191
192    def test_param2(self):
193        m = ConcreteModel()
194        m.p = Param(mutable=True)
195        self.assertRaises(ValueError, value, m.p, exception=True)
196
197    def test_param3(self):
198        m = ConcreteModel()
199        m.p = Param(mutable=True)
200        self.assertEqual(None, value(m.p, exception=False))
201
202    def test_var1(self):
203        m = ConcreteModel()
204        m.x = Var()
205        self.assertRaises(ValueError, value, m.x, exception=True)
206
207    def test_var2(self):
208        m = ConcreteModel()
209        m.x = Var()
210        self.assertEqual(None, value(m.x, exception=False))
211
212    def test_error1(self):
213        class A(object): pass
214        val = A()
215        try:
216            value(val)
217            self.fail("Expected TypeError")
218        except TypeError:
219            pass
220
221    def test_unknownNumericType(self):
222        ref = MyBogusNumericType(42)
223        val = value(ref)
224        self.assertEqual(val.val, 42.0)
225        #self.assertEqual(val().val, 42)
226        from pyomo.core.base.numvalue import native_numeric_types, native_types
227        self.assertIn(MyBogusNumericType, native_numeric_types)
228        self.assertIn(MyBogusNumericType, native_types)
229        native_numeric_types.remove(MyBogusNumericType)
230        native_types.remove(MyBogusNumericType)
231
232
233class Test_polydegree(unittest.TestCase):
234
235    def test_none(self):
236        val = None
237        self.assertRaises(TypeError, polynomial_degree, val)
238
239    def test_bool(self):
240        val = False
241        self.assertEqual(0, polynomial_degree(val))
242
243    def test_float(self):
244        val = 1.1
245        self.assertEqual(0, polynomial_degree(val))
246
247    def test_int(self):
248        val = 1
249        self.assertEqual(0, polynomial_degree(val))
250
251    def test_long(self):
252        val = int(1e10)
253        self.assertEqual(0, polynomial_degree(val))
254
255    def test_nan(self):
256        val = nan
257        self.assertEqual(0, polynomial_degree(val))
258
259    def test_inf(self):
260        val = inf
261        self.assertEqual(0, polynomial_degree(val))
262
263    def test_string(self):
264        val = 'foo'
265        self.assertRaises(TypeError, polynomial_degree, val)
266
267    def test_const1(self):
268        val = NumericConstant(1.0)
269        self.assertEqual(0, polynomial_degree(val))
270
271    def test_const3(self):
272        val = NumericConstant(nan)
273        self.assertEqual(0, polynomial_degree(val))
274
275    def test_const4(self):
276        val = NumericConstant(inf)
277        self.assertEqual(0, polynomial_degree(val))
278
279    def test_param1(self):
280        m = ConcreteModel()
281        m.p = Param(mutable=True, initialize=2)
282        self.assertEqual(0, polynomial_degree(m.p))
283
284    def test_param2(self):
285        m = ConcreteModel()
286        m.p = Param(mutable=True)
287        self.assertEqual(0, polynomial_degree(m.p))
288
289    def test_var1(self):
290        m = ConcreteModel()
291        m.x = Var()
292        self.assertTrue(1, polynomial_degree(m.x))
293
294    def test_error1(self):
295        class A(object): pass
296        val = A()
297        try:
298            polynomial_degree(val)
299            self.fail("Expected TypeError")
300        except TypeError:
301            pass
302
303    def test_unknownNumericType(self):
304        ref = MyBogusNumericType(42)
305        val = polynomial_degree(ref)
306        self.assertEqual(val, 0)
307        #self.assertEqual(val().val, 42)
308        from pyomo.core.base.numvalue import native_numeric_types, native_types
309        self.assertIn(MyBogusNumericType, native_numeric_types)
310        self.assertIn(MyBogusNumericType, native_types)
311        native_numeric_types.remove(MyBogusNumericType)
312        native_types.remove(MyBogusNumericType)
313
314
315class Test_is_constant(unittest.TestCase):
316
317    def test_none(self):
318        self.assertTrue(is_constant(None))
319
320    def test_bool(self):
321        self.assertTrue(is_constant(True))
322
323    def test_float(self):
324        self.assertTrue(is_constant(1.1))
325
326    def test_int(self):
327        self.assertTrue(is_constant(1))
328
329    def test_long(self):
330        val = int(1e10)
331        self.assertTrue(is_constant(val))
332
333    def test_string(self):
334        self.assertTrue(is_constant('foo'))
335
336    def test_const1(self):
337        val = NumericConstant(1.0)
338        self.assertTrue(is_constant(val))
339
340    def test_const2(self):
341        val = NumericConstant('foo')
342        self.assertTrue(is_constant(val))
343
344    def test_error(self):
345        class A(object): pass
346        val = A()
347        try:
348            is_constant(val)
349            self.fail("Expected TypeError")
350        except TypeError:
351            pass
352
353    def test_unknownNumericType(self):
354        ref = MyBogusNumericType(42)
355        self.assertTrue(is_constant(ref))
356        from pyomo.core.base.numvalue import native_numeric_types, native_types
357        self.assertIn(MyBogusNumericType, native_numeric_types)
358        self.assertIn(MyBogusNumericType, native_types)
359        native_numeric_types.remove(MyBogusNumericType)
360        native_types.remove(MyBogusNumericType)
361
362
363class Test_is_fixed(unittest.TestCase):
364
365    def test_none(self):
366        self.assertTrue(is_fixed(None))
367
368    def test_bool(self):
369        self.assertTrue(is_fixed(True))
370
371    def test_float(self):
372        self.assertTrue(is_fixed(1.1))
373
374    def test_int(self):
375        self.assertTrue(is_fixed(1))
376
377    def test_long(self):
378        val = int(1e10)
379        self.assertTrue(is_fixed(val))
380
381    def test_string(self):
382        self.assertTrue(is_fixed('foo'))
383
384    def test_const1(self):
385        val = NumericConstant(1.0)
386        self.assertTrue(is_fixed(val))
387
388    def test_error(self):
389        class A(object): pass
390        val = A()
391        try:
392            is_fixed(val)
393            self.fail("Expected TypeError")
394        except TypeError:
395            pass
396
397    def test_unknownNumericType(self):
398        ref = MyBogusNumericType(42)
399        self.assertTrue(is_fixed(ref))
400        from pyomo.core.base.numvalue import native_numeric_types, native_types
401        self.assertIn(MyBogusNumericType, native_numeric_types)
402        self.assertIn(MyBogusNumericType, native_types)
403        native_numeric_types.remove(MyBogusNumericType)
404        native_types.remove(MyBogusNumericType)
405
406
407class Test_is_variable_type(unittest.TestCase):
408
409    def test_none(self):
410        self.assertFalse(is_variable_type(None))
411
412    def test_bool(self):
413        self.assertFalse(is_variable_type(True))
414
415    def test_float(self):
416        self.assertFalse(is_variable_type(1.1))
417
418    def test_int(self):
419        self.assertFalse(is_variable_type(1))
420
421    def test_long(self):
422        val = int(1e10)
423        self.assertFalse(is_variable_type(val))
424
425    def test_string(self):
426        self.assertFalse(is_variable_type('foo'))
427
428    def test_const1(self):
429        val = NumericConstant(1.0)
430        self.assertFalse(is_variable_type(val))
431
432    def test_error(self):
433        class A(object): pass
434        val = A()
435        self.assertFalse(is_variable_type(val))
436
437    def test_unknownNumericType(self):
438        ref = MyBogusNumericType(42)
439        self.assertFalse(is_variable_type(ref))
440
441
442class Test_is_potentially_variable(unittest.TestCase):
443
444    def test_none(self):
445        self.assertFalse(is_potentially_variable(None))
446
447    def test_bool(self):
448        self.assertFalse(is_potentially_variable(True))
449
450    def test_float(self):
451        self.assertFalse(is_potentially_variable(1.1))
452
453    def test_int(self):
454        self.assertFalse(is_potentially_variable(1))
455
456    def test_long(self):
457        val = int(1e10)
458        self.assertFalse(is_potentially_variable(val))
459
460    def test_string(self):
461        self.assertFalse(is_potentially_variable('foo'))
462
463    def test_const1(self):
464        val = NumericConstant(1.0)
465        self.assertFalse(is_potentially_variable(val))
466
467    def test_error(self):
468        class A(object): pass
469        val = A()
470        self.assertFalse(is_potentially_variable(val))
471
472    def test_unknownNumericType(self):
473        ref = MyBogusNumericType(42)
474        self.assertFalse(is_potentially_variable(ref))
475
476
477class Test_as_numeric(unittest.TestCase):
478
479    def test_none(self):
480        val = None
481        try:
482            as_numeric(val)
483            self.fail("Expected ValueError")
484        except:
485            pass
486
487    def test_bool(self):
488        val = False
489        try:
490            as_numeric(val)
491            self.fail("Expected ValueError")
492        except:
493            pass
494        val = True
495        try:
496            as_numeric(val)
497            self.fail("Expected ValueError")
498        except:
499            pass
500
501    def test_float(self):
502        val = 1.1
503        nval = as_numeric(val)
504        self.assertEqual(val, nval)
505        self.assertEqual(nval/2, 0.55)
506
507    def test_int(self):
508        val = 1
509        nval = as_numeric(val)
510        self.assertEqual(1.0, nval)
511        #self.assertEqual(val, nval)
512        self.assertEqual(nval/2, 0.5)
513
514    def test_long(self):
515        val = int(1e10)
516        nval = as_numeric(val)
517        self.assertEqual(1.0e10, nval)
518        #self.assertEqual(val, as_numeric(val))
519        self.assertEqual(nval/2, 5.0e9)
520
521    def test_string(self):
522        val = 'foo'
523        try:
524            as_numeric(val)
525            self.fail("Expected ValueError")
526        except:
527            pass
528
529    def test_const1(self):
530        val = NumericConstant(1.0)
531        self.assertEqual(1.0, as_numeric(val))
532
533    def test_error1(self):
534        class A(object): pass
535        val = A()
536        try:
537            as_numeric(val)
538            self.fail("Expected TypeError")
539        except TypeError:
540            pass
541
542    def test_unknownType(self):
543        ref = MyBogusType(42)
544        try:
545            val = as_numeric(ref)
546            self.fail("Expected TypeError")
547        except TypeError:
548            pass
549
550    def test_unknownNumericType(self):
551        ref = MyBogusNumericType(42)
552        val = as_numeric(ref)
553        self.assertEqual(val().val, 42.0)
554        #self.assertEqual(val().val, 42)
555        from pyomo.core.base.numvalue import native_numeric_types, native_types
556        self.assertIn(MyBogusNumericType, native_numeric_types)
557        self.assertIn(MyBogusNumericType, native_types)
558        native_numeric_types.remove(MyBogusNumericType)
559        native_types.remove(MyBogusNumericType)
560
561    def test_numpy_basic_float_registration(self):
562        if not numpy_available:
563            self.skipTest("This test requires NumPy")
564        from pyomo.core.base.numvalue import native_numeric_types, native_integer_types, native_boolean_types, native_types
565        self.assertIn(numpy.float_, native_numeric_types)
566        self.assertNotIn(numpy.float_, native_integer_types)
567        self.assertIn(numpy.float_, native_boolean_types)
568        self.assertIn(numpy.float_, native_types)
569
570    def test_numpy_basic_int_registration(self):
571        if not numpy_available:
572            self.skipTest("This test requires NumPy")
573        from pyomo.core.base.numvalue import native_numeric_types, native_integer_types, native_boolean_types, native_types
574        self.assertIn(numpy.int_, native_numeric_types)
575        self.assertIn(numpy.int_, native_integer_types)
576        self.assertIn(numpy.int_, native_boolean_types)
577        self.assertIn(numpy.int_, native_types)
578
579    def test_numpy_basic_bool_registration(self):
580        if not numpy_available:
581            self.skipTest("This test requires NumPy")
582        from pyomo.core.base.numvalue import native_numeric_types, native_integer_types, native_boolean_types, native_types
583        self.assertNotIn(numpy.bool_, native_numeric_types)
584        self.assertNotIn(numpy.bool_, native_integer_types)
585        self.assertIn(numpy.bool_, native_boolean_types)
586        self.assertIn(numpy.bool_, native_types)
587
588
589if __name__ == "__main__":
590    unittest.main()
591
592