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 Elements of a Model
12#
13# Test             Class to test the Model class
14#
15
16import json
17import os
18from os.path import abspath, dirname, join
19currdir = dirname(abspath(__file__))
20import pickle
21
22from filecmp import cmp
23import pyomo.common.unittest as unittest
24
25from pyomo.common.dependencies import yaml_available
26from pyomo.common.tempfiles import TempfileManager
27from pyomo.core.expr import current as EXPR
28from pyomo.environ import RangeSet, ConcreteModel, Var, Param, Block, AbstractModel, Set, Constraint, Objective, value, sum_product, SolverFactory, VarList, ObjectiveList, ConstraintList
29from pyomo.opt import check_available_solvers
30from pyomo.opt.parallel.local import SolverManager_Serial
31
32if yaml_available:
33    import yaml
34
35solvers = check_available_solvers('glpk')
36
37class Test(unittest.TestCase):
38
39    def tearDown(self):
40        if os.path.exists("unknown.lp"):
41            os.unlink("unknown.lp")
42        TempfileManager.clear_tempfiles()
43
44
45    def test_clone_concrete_model(self):
46        def _populate(b, *args):
47            b.A = RangeSet(1,3)
48            b.v = Var()
49            b.vv = Var(m.A)
50            b.p = Param()
51
52        m = ConcreteModel()
53        _populate(m)
54        m.b = Block()
55        _populate(m.b)
56        m.b.c = Block()
57        _populate(m.b.c)
58        m.bb = Block(m.A, rule=_populate)
59
60        n = m.clone()
61        self.assertNotEqual(id(m), id(n))
62
63        self.assertEqual(id(m), id(m.b.parent_block()))
64        self.assertEqual(id(m), id(m.bb.parent_block()))
65        self.assertEqual(id(m), id(m.bb[1].parent_block()))
66        self.assertEqual(id(m), id(m.bb[2].parent_block()))
67        self.assertEqual(id(m), id(m.bb[3].parent_block()))
68
69        self.assertEqual(id(n), id(n.b.parent_block()))
70        self.assertEqual(id(n), id(n.bb.parent_block()))
71        self.assertEqual(id(n), id(n.bb[1].parent_block()))
72        self.assertEqual(id(n), id(n.bb[2].parent_block()))
73        self.assertEqual(id(n), id(n.bb[3].parent_block()))
74
75        for x,y in ((m, n), (m.b, n.b), (m.b.c, n.b.c), (m.bb[2], n.bb[2])):
76            self.assertNotEqual(id(x), id(y))
77            self.assertNotEqual(id(x.parent_block()), id(x))
78            self.assertNotEqual(id(y.parent_block()), id(y))
79
80            self.assertEqual(id(x.A.parent_block()), id(x))
81            self.assertEqual(id(x.v.parent_block()), id(x))
82            self.assertEqual(id(x.vv.parent_block()), id(x))
83            self.assertEqual(id(x.vv[1].parent_block()), id(x))
84            self.assertEqual(id(x.p.parent_block()), id(x))
85
86            self.assertEqual(id(y.A.parent_block()), id(y))
87            self.assertEqual(id(y.v.parent_block()), id(y))
88            self.assertEqual(id(y.vv.parent_block()), id(y))
89            self.assertEqual(id(y.vv[1].parent_block()), id(y))
90            self.assertEqual(id(y.p.parent_block()), id(y))
91
92    def test_clone_abstract_model(self):
93        def _populate(b, *args):
94            b.A = RangeSet(1,3)
95            b.v = Var()
96            b.vv = Var(m.A)
97            b.p = Param()
98
99        m = AbstractModel()
100        _populate(m)
101        m.b = Block()
102        _populate(m.b)
103        m.b.c = Block()
104        _populate(m.b.c)
105        m.bb = Block(m.A, rule=_populate)
106
107        n = m.clone()
108        self.assertNotEqual(id(m), id(n))
109
110        self.assertEqual(id(m), id(m.b.parent_block()))
111        self.assertEqual(id(m), id(m.bb.parent_block()))
112
113        self.assertEqual(id(n), id(n.b.parent_block()))
114        self.assertEqual(id(n), id(n.bb.parent_block()))
115
116        for x,y in ((m, n), (m.b, n.b), (m.b.c, n.b.c)):
117            self.assertNotEqual(id(x), id(y))
118            self.assertNotEqual(id(x.parent_block()), id(x))
119            self.assertNotEqual(id(y.parent_block()), id(y))
120
121            self.assertEqual(id(x.A.parent_block()), id(x))
122            self.assertEqual(id(x.v.parent_block()), id(x))
123            self.assertEqual(id(x.vv.parent_block()), id(x))
124            self.assertEqual(id(x.p.parent_block()), id(x))
125
126            self.assertEqual(id(y.A.parent_block()), id(y))
127            self.assertEqual(id(y.v.parent_block()), id(y))
128            self.assertEqual(id(y.vv.parent_block()), id(y))
129            self.assertEqual(id(y.p.parent_block()), id(y))
130
131    def test_clear_attribute(self):
132        # Test coverage of the _clear_attribute method
133        model = ConcreteModel()
134        obj = Set()
135        model.A = obj
136        self.assertEqual(model.A.local_name, "A")
137        self.assertEqual(obj.local_name, "A")
138        self.assertIs(obj, model.A)
139
140        obj = Var()
141        model.A = obj
142        self.assertEqual(model.A.local_name, "A")
143        self.assertEqual(obj.local_name, "A")
144        self.assertIs(obj, model.A)
145
146        obj = Param()
147        model.A = obj
148        self.assertEqual(model.A.local_name, "A")
149        self.assertEqual(obj.local_name, "A")
150        self.assertIs(obj, model.A)
151
152        obj = Objective()
153        model.A = obj
154        self.assertEqual(model.A.local_name, "A")
155        self.assertEqual(obj.local_name, "A")
156        self.assertIs(obj, model.A)
157
158        obj = Constraint()
159        model.A = obj
160        self.assertEqual(model.A.local_name, "A")
161        self.assertEqual(obj.local_name, "A")
162        self.assertIs(obj, model.A)
163
164        obj = Set()
165        model.A = obj
166        self.assertEqual(model.A.local_name, "A")
167        self.assertEqual(obj.local_name, "A")
168        self.assertIs(obj, model.A)
169
170    def test_set_attr(self):
171        model = ConcreteModel()
172        model.x = Param(mutable=True)
173        model.x = 5
174        self.assertEqual(value(model.x), 5)
175        model.x = 6
176        self.assertEqual(value(model.x), 6)
177        model.x = None
178        self.assertEqual(model.x._value, None)
179
180    def test_write(self):
181        model = ConcreteModel()
182        model.A = RangeSet(1,4)
183        model.x = Var(model.A, bounds=(-1,1))
184        def obj_rule(model):
185            return sum_product(model.x)
186        model.obj = Objective(rule=obj_rule)
187        model.write()
188
189    def test_write2(self):
190        model = ConcreteModel()
191        model.A = RangeSet(1,4)
192        model.x = Var(model.A, bounds=(-1,1))
193        def obj_rule(model):
194            return sum_product(model.x)
195        model.obj = Objective(rule=obj_rule)
196        def c_rule(model):
197            return (1, model.x[1]+model.x[2], 2)
198        model.c = Constraint(rule=c_rule)
199        model.write()
200
201    def test_write3(self):
202        # Test that the summation works correctly, even though param 'w' has a default value
203        model = ConcreteModel()
204        model.J = RangeSet(1,4)
205        model.w=Param(model.J, default=4)
206        model.x=Var(model.J, initialize=3)
207        def obj_rule(instance):
208            return sum_product(instance.w, instance.x)
209        model.obj = Objective(rule=obj_rule)
210        self.assertEqual( value(model.obj), 48 )
211
212    @unittest.skipIf('glpk' not in solvers, "glpk solver is not available")
213    def test_solve1(self):
214        model = ConcreteModel()
215        model.A = RangeSet(1,4)
216        model.x = Var(model.A, bounds=(-1,1))
217        def obj_rule(model):
218            return sum_product(model.x)
219        model.obj = Objective(rule=obj_rule)
220        def c_rule(model):
221            expr = 0
222            for i in model.A:
223                expr += i*model.x[i]
224            return expr == 0
225        model.c = Constraint(rule=c_rule)
226        opt = SolverFactory('glpk')
227        results = opt.solve(model, symbolic_solver_labels=True)
228        model.solutions.store_to(results)
229        results.write(filename=join(currdir,"solve1.out"), format='json')
230        with open(join(currdir,"solve1.out"), 'r') as out, \
231            open(join(currdir,"solve1.txt"), 'r') as txt:
232            self.assertStructuredAlmostEqual(json.load(txt), json.load(out),
233                                             abstol=1e-4,
234                                             allow_second_superset=True)
235        #
236        def d_rule(model):
237            return model.x[1] >= 0
238        model.d = Constraint(rule=d_rule)
239        model.d.deactivate()
240        results = opt.solve(model)
241        model.solutions.store_to(results)
242        results.write(filename=join(currdir,"solve1x.out"), format='json')
243        with open(join(currdir,"solve1x.out"), 'r') as out, \
244            open(join(currdir,"solve1.txt"), 'r') as txt:
245            self.assertStructuredAlmostEqual(json.load(txt), json.load(out),
246                                             abstol=1e-4,
247                                             allow_second_superset=True)
248        #
249        model.d.activate()
250        results = opt.solve(model)
251        model.solutions.store_to(results)
252        results.write(filename=join(currdir,"solve1a.out"), format='json')
253        with open(join(currdir,"solve1a.out"), 'r') as out, \
254            open(join(currdir,"solve1a.txt"), 'r') as txt:
255            self.assertStructuredAlmostEqual(json.load(txt), json.load(out),
256                                             abstol=1e-4,
257                                             allow_second_superset=True)
258        #
259        model.d.deactivate()
260        def e_rule(model, i):
261            return model.x[i] >= 0
262        model.e = Constraint(model.A, rule=e_rule)
263        for i in model.A:
264            model.e[i].deactivate()
265        results = opt.solve(model)
266        model.solutions.store_to(results)
267        results.write(filename=join(currdir,"solve1y.out"), format='json')
268        with open(join(currdir,"solve1y.out"), 'r') as out, \
269            open(join(currdir,"solve1.txt"), 'r') as txt:
270            self.assertStructuredAlmostEqual(json.load(txt), json.load(out),
271                                             abstol=1e-4,
272                                             allow_second_superset=True)
273        #
274        model.e.activate()
275        results = opt.solve(model)
276        model.solutions.store_to(results)
277        results.write(filename=join(currdir,"solve1b.out"), format='json')
278        with open(join(currdir,"solve1b.out"), 'r') as out, \
279            open(join(currdir,"solve1b.txt"), 'r') as txt:
280            self.assertStructuredAlmostEqual(json.load(txt), json.load(out),
281                                             abstol=1e-4,
282                                             allow_second_superset=True)
283
284    @unittest.skipIf('glpk' not in solvers, "glpk solver is not available")
285    def test_store_to_skip_stale_vars(self):
286        # test store_to() function with skip_stale_vars=True
287        model = ConcreteModel()
288        model.A = RangeSet(1,4)
289        model.x = Var(model.A, bounds=(-1,1))
290        def obj_rule(model):
291            return sum_product(model.x)
292        model.obj = Objective(rule=obj_rule)
293        def c_rule(model):
294            expr = 0
295            for i in model.A:
296                expr += i*model.x[i]
297            return expr == 0
298        model.c = Constraint(rule=c_rule)
299        opt = SolverFactory('glpk')
300        results = opt.solve(model, symbolic_solver_labels=True)
301        model.x[1].fix()
302        results = opt.solve(model, symbolic_solver_labels=True)
303        model.solutions.store_to(results,skip_stale_vars=False)
304        for index in model.A:
305            self.assertIn(model.x[index].getname(), results.solution.variable.keys())
306        model.solutions.store_to(results,skip_stale_vars=True)
307        for index in model.A:
308            if index == 1:
309                self.assertNotIn(model.x[index].getname(), results.solution.variable.keys())
310            else:
311                self.assertIn(model.x[index].getname(), results.solution.variable.keys())
312
313
314    def test_display(self):
315        model = ConcreteModel()
316        model.A = RangeSet(1,4)
317        model.x = Var(model.A, bounds=(-1,1))
318        def obj_rule(model):
319            expr = 0
320            for i in model.A:
321                expr += model.x[i]
322            return expr
323        model.obj = Objective(rule=obj_rule)
324        model.display(join(currdir,"solve3.out"))
325        _out, _txt = join(currdir,"solve3.out"), join(currdir,"solve3.txt")
326        self.assertTrue(cmp(_out, _txt),
327                        msg="Files %s and %s differ" % (_txt, _out))
328
329    @unittest.skipIf('glpk' not in solvers, "glpk solver is not available")
330    def test_solve4(self):
331        model = ConcreteModel()
332        model.A = RangeSet(1,4)
333        model.x = Var(model.A, bounds=(-1,1))
334        def obj_rule(model):
335            return sum_product(model.x)
336        model.obj = Objective(rule=obj_rule)
337        def c_rule(model):
338            expr = 0
339            for i in model.A:
340                expr += i*model.x[i]
341            return expr == 0
342        model.c = Constraint(rule=c_rule)
343        opt = SolverFactory('glpk')
344        results = opt.solve(model, symbolic_solver_labels=True)
345        model.solutions.store_to(results)
346        results.write(filename=join(currdir,'solve4.out'), format='json')
347        with open(join(currdir,"solve4.out"), 'r') as out, \
348            open(join(currdir,"solve1.txt"), 'r') as txt:
349            self.assertStructuredAlmostEqual(json.load(txt), json.load(out),
350                                             abstol=1e-4,
351                                             allow_second_superset=True)
352
353    @unittest.skipIf('glpk' not in solvers, "glpk solver is not available")
354    def test_solve6(self):
355        #
356        # Test that solution values have complete block names:
357        #   b.obj
358        #   b.x
359        #
360        model = ConcreteModel()
361        model.y = Var(bounds=(-1,1))
362        model.b = Block()
363        model.b.A = RangeSet(1,4)
364        model.b.x = Var(model.b.A, bounds=(-1,1))
365        def obj_rule(block):
366            return sum_product(block.x)
367        model.b.obj = Objective(rule=obj_rule)
368        def c_rule(model):
369            expr = model.y
370            for i in model.b.A:
371                expr += i*model.b.x[i]
372            return expr == 0
373        model.c = Constraint(rule=c_rule)
374        opt = SolverFactory('glpk')
375        results = opt.solve(model, symbolic_solver_labels=True)
376        model.solutions.store_to(results)
377        results.write(filename=join(currdir,'solve6.out'), format='json')
378        with open(join(currdir,"solve6.out"), 'r') as out, \
379            open(join(currdir,"solve6.txt"), 'r') as txt:
380            self.assertStructuredAlmostEqual(json.load(txt), json.load(out),
381                                             abstol=1e-4,
382                                             allow_second_superset=True)
383
384    @unittest.skipIf('glpk' not in solvers, "glpk solver is not available")
385    def test_solve7(self):
386        #
387        # Test that solution values are writen with appropriate
388        # quotations in results
389        #
390        model = ConcreteModel()
391        model.y = Var(bounds=(-1,1))
392        model.A = RangeSet(1,4)
393        model.B = Set(initialize=['A B', 'C,D', 'E'])
394        model.x = Var(model.A, model.B, bounds=(-1,1))
395        def obj_rule(model):
396            return sum_product(model.x)
397        model.obj = Objective(rule=obj_rule)
398        def c_rule(model):
399            expr = model.y
400            for i in model.A:
401                for j in model.B:
402                    expr += i*model.x[i,j]
403            return expr == 0
404        model.c = Constraint(rule=c_rule)
405        opt = SolverFactory('glpk')
406        results = opt.solve(model, symbolic_solver_labels=True)
407        #model.display()
408        model.solutions.store_to(results)
409        results.write(filename=join(currdir,'solve7.out'), format='json')
410        with open(join(currdir,"solve7.out"), 'r') as out, \
411            open(join(currdir,"solve7.txt"), 'r') as txt:
412            self.assertStructuredAlmostEqual(json.load(txt), json.load(out),
413                                             abstol=1e-4,
414                                             allow_second_superset=True)
415
416    def test_stats1(self):
417        model = ConcreteModel()
418        model.x = Var([1,2])
419        def obj_rule(model, i):
420            return sum_product(model.x)
421        model.obj = Objective([1,2], rule=obj_rule)
422        def c_rule(model, i):
423            expr = 0
424            for j in [1,2]:
425                expr += j*model.x[j]
426            return expr == 0
427        model.c = Constraint([1,2], rule=c_rule)
428        self.assertEqual(model.nvariables(), 2)
429        self.assertEqual(model.nobjectives(), 2)
430        self.assertEqual(model.nconstraints(), 2)
431
432    def test_stats2(self):
433        model = ConcreteModel()
434        #
435        model.x = Var([1,2])
436        def obj_rule(model, i):
437            return sum_product(model.x)
438        model.y = VarList()
439        model.y.add()
440        model.y.add()
441        #
442        model.obj = Objective([1,2], rule=obj_rule)
443        model.o = ObjectiveList()
444        model.o.add(model.y[1])
445        model.o.add(model.y[2])
446        #
447        def c_rule(model, i):
448            expr = 0
449            for j in [1,2]:
450                expr += j*model.x[j]
451            return expr == 0
452        model.c = Constraint([1,2], rule=c_rule)
453        model.C = ConstraintList()
454        model.C.add(model.y[1] == 0)
455        model.C.add(model.y[2] == 0)
456        #
457        self.assertEqual(model.nvariables(), 4)
458        self.assertEqual(model.nobjectives(), 4)
459        self.assertEqual(model.nconstraints(), 4)
460
461    def test_stats3(self):
462        model = ConcreteModel()
463        model.x = Var([1,2])
464        def obj_rule(model, i):
465            return sum_product(model.x)
466        model.obj = Objective([1,2], rule=obj_rule)
467        def c_rule(model, i):
468            expr = 0
469            for j in [1,2]:
470                expr += j*model.x[j]
471            return expr == 0
472        model.c = Constraint([1,2], rule=c_rule)
473        #
474        model.B = Block()
475        model.B.x = Var([1,2])
476        model.B.o = ObjectiveList()
477        model.B.o.add(model.B.x[1])
478        model.B.o.add(model.B.x[2])
479        model.B.c = ConstraintList()
480        model.B.c.add(model.x[1] == 0)
481        model.B.c.add(model.x[2] == 0)
482        self.assertEqual(model.nvariables(), 4)
483        self.assertEqual(model.nobjectives(), 4)
484        self.assertEqual(model.nconstraints(), 4)
485
486    def test_stats4(self):
487        model = ConcreteModel()
488        model.x = Var([1])
489
490        model.B = Block()
491        model.B.x = Var([1, 2, 3])
492        model.B.o = ObjectiveList()
493        model.B.o.add(model.B.x[1])
494        model.B.c = ConstraintList()
495        model.B.c.add(model.B.x[1] == 0)
496        model.B.c.add(model.B.x[2] == 0)
497        model.B.c.add(model.B.x[3] == 0)
498        self.assertEqual(model.nvariables(), 4)
499        self.assertEqual(model.nobjectives(), 1)
500        self.assertEqual(model.nconstraints(), 3)
501        model.clear()
502        self.assertEqual(model.nvariables(), 0)
503        self.assertEqual(model.nobjectives(), 0)
504        self.assertEqual(model.nconstraints(), 0)
505
506    @unittest.skipIf('glpk' not in solvers, "glpk solver is not available")
507    def test_solve_with_pickle(self):
508        model = ConcreteModel()
509        model.A = RangeSet(1,4)
510        model.b = Block()
511        model.b.x = Var(model.A, bounds=(-1,1))
512        model.b.obj = Objective(expr=sum_product(model.b.x))
513        model.c = Constraint(expr=model.b.x[1] >= 0)
514        opt = SolverFactory('glpk')
515        self.assertEqual(len(model.solutions), 0)
516        results = opt.solve(model, symbolic_solver_labels=True)
517        self.assertEqual(len(model.solutions), 1)
518        #
519        self.assertEqual(model.solutions[0].gap, 0.0)
520        #self.assertEqual(model.solutions[0].status, SolutionStatus.feasible)
521        self.assertEqual(model.solutions[0].message, None)
522        #
523        buf = pickle.dumps(model)
524        tmodel = pickle.loads(buf)
525        self.assertEqual(len(tmodel.solutions), 1)
526        self.assertEqual(tmodel.solutions[0].gap, 0.0)
527        #self.assertEqual(tmodel.solutions[0].status, SolutionStatus.feasible)
528        self.assertEqual(tmodel.solutions[0].message, None)
529
530    @unittest.skipIf('glpk' not in solvers, "glpk solver is not available")
531    def test_solve_with_pickle_then_clone(self):
532        # This tests github issue Pyomo-#65
533        model = ConcreteModel()
534        model.A = RangeSet(1,4)
535        model.b = Block()
536        model.b.x = Var(model.A, bounds=(-1,1))
537        model.b.obj = Objective(expr=sum_product(model.b.x))
538        model.c = Constraint(expr=model.b.x[1] >= 0)
539        opt = SolverFactory('glpk')
540        self.assertEqual(len(model.solutions), 0)
541        results = opt.solve(model, symbolic_solver_labels=True)
542        self.assertEqual(len(model.solutions), 1)
543        #
544        self.assertEqual(model.solutions[0].gap, 0.0)
545        #self.assertEqual(model.solutions[0].status, SolutionStatus.feasible)
546        self.assertEqual(model.solutions[0].message, None)
547        #
548        buf = pickle.dumps(model)
549        tmodel = pickle.loads(buf)
550        self.assertEqual(len(tmodel.solutions), 1)
551        self.assertEqual(tmodel.solutions[0].gap, 0.0)
552        #self.assertEqual(tmodel.solutions[0].status, SolutionStatus.feasible)
553        self.assertEqual(tmodel.solutions[0].message, None)
554        self.assertIn(id(tmodel.b.obj), tmodel.solutions[0]._entry['objective'])
555        self.assertIs(
556            tmodel.b.obj,
557            tmodel.solutions[0]._entry['objective'][id(tmodel.b.obj)][0]() )
558
559        inst = tmodel.clone()
560
561        # make sure the clone has all the attributes
562        self.assertTrue(hasattr(inst,'A'))
563        self.assertTrue(hasattr(inst,'b'))
564        self.assertTrue(hasattr(inst.b,'x'))
565        self.assertTrue(hasattr(inst.b,'obj'))
566        self.assertTrue(hasattr(inst,'c'))
567        # and that they were all copied
568        self.assertIsNot(inst.A, tmodel.A)
569        self.assertIsNot(inst.b, tmodel.b)
570        self.assertIsNot(inst.b.x, tmodel.b.x)
571        self.assertIsNot(inst.b.obj, tmodel.b.obj)
572        self.assertIsNot(inst.c, tmodel.c)
573
574        # Make sure the solution is on the new model
575        self.assertTrue(hasattr(inst,'solutions'))
576        self.assertEqual(len(inst.solutions), 1)
577        self.assertEqual(inst.solutions[0].gap, 0.0)
578        #self.assertEqual(inst.solutions[0].status, SolutionStatus.feasible)
579        self.assertEqual(inst.solutions[0].message, None)
580
581        # Spot-check some components and make sure all the weakrefs in
582        # the ModelSOlution got updated
583        self.assertIn(id(inst.b.obj), inst.solutions[0]._entry['objective'])
584        _obj = inst.solutions[0]._entry['objective'][id(inst.b.obj)]
585        self.assertIs(_obj[0](), inst.b.obj)
586
587        for v in [1,2,3,4]:
588            self.assertIn(id(inst.b.x[v]), inst.solutions[0]._entry['variable'])
589            _v = inst.solutions[0]._entry['variable'][id(inst.b.x[v])]
590            self.assertIs(_v[0](), inst.b.x[v])
591
592    @unittest.skipIf('glpk' not in solvers, "glpk solver is not available")
593    @unittest.skipIf(not yaml_available, "YAML not available available")
594    def test_solve_with_store1(self):
595        # With symbolic solver labels
596        model = ConcreteModel()
597        model.A = RangeSet(1,4)
598        model.b = Block()
599        model.b.x = Var(model.A, bounds=(-1,1))
600        model.b.obj = Objective(expr=sum_product(model.b.x))
601        model.c = Constraint(expr=model.b.x[1] >= 0)
602        opt = SolverFactory('glpk')
603        results = opt.solve(model, symbolic_solver_labels=True)
604        #
605        results.write(filename=join(currdir,'solve_with_store1.out'),
606                      format='yaml')
607        with open(join(currdir,"solve_with_store1.out"), 'r') as out, \
608            open(join(currdir,"solve_with_store1.txt"), 'r') as txt:
609            self.assertStructuredAlmostEqual(yaml.full_load(txt),
610                                             yaml.full_load(out),
611                                             allow_second_superset=True)
612        model.solutions.store_to(results)
613        #
614        results.write(filename=join(currdir,'solve_with_store2.out'),
615                      format='yaml')
616        with open(join(currdir,"solve_with_store2.out"), 'r') as out, \
617            open(join(currdir,"solve_with_store2.txt"), 'r') as txt:
618            self.assertStructuredAlmostEqual(yaml.full_load(txt),
619                                             yaml.full_load(out),
620                                             allow_second_superset=True)
621        #
622        # Load results with string indices
623        #
624        tmodel = ConcreteModel()
625        tmodel.A = RangeSet(1,4)
626        tmodel.b = Block()
627        tmodel.b.x = Var(tmodel.A, bounds=(-1,1))
628        tmodel.b.obj = Objective(expr=sum_product(tmodel.b.x))
629        tmodel.c = Constraint(expr=tmodel.b.x[1] >= 0)
630        self.assertEqual(len(tmodel.solutions), 0)
631        tmodel.solutions.load_from(results)
632        self.assertEqual(len(tmodel.solutions), 1)
633
634    @unittest.skipIf('glpk' not in solvers, "glpk solver is not available")
635    @unittest.skipIf(not yaml_available, "YAML not available available")
636    def test_solve_with_store2(self):
637        # Without symbolic solver labels
638        model = ConcreteModel()
639        model.A = RangeSet(1,4)
640        model.b = Block()
641        model.b.x = Var(model.A, bounds=(-1,1))
642        model.b.obj = Objective(expr=sum_product(model.b.x))
643        model.c = Constraint(expr=model.b.x[1] >= 0)
644        opt = SolverFactory('glpk')
645        results = opt.solve(model, symbolic_solver_labels=False)
646        #
647        results.write(filename=join(currdir,'solve_with_store1.out'),
648                      format='yaml')
649        with open(join(currdir,"solve_with_store1.out"), 'r') as out, \
650            open(join(currdir,"solve_with_store1.txt"), 'r') as txt:
651            self.assertStructuredAlmostEqual(yaml.full_load(txt),
652                                             yaml.full_load(out),
653                                             allow_second_superset=True)
654        model.solutions.store_to(results)
655        #
656        results.write(filename=join(currdir,'solve_with_store2.out'),
657                      format='yaml')
658        with open(join(currdir,"solve_with_store2.out"), 'r') as out, \
659            open(join(currdir,"solve_with_store2.txt"), 'r') as txt:
660            self.assertStructuredAlmostEqual(yaml.full_load(txt),
661                                             yaml.full_load(out),
662                                             allow_second_superset=True)
663        #
664        # Load results with string indices
665        #
666        tmodel = ConcreteModel()
667        tmodel.A = RangeSet(1,4)
668        tmodel.b = Block()
669        tmodel.b.x = Var(tmodel.A, bounds=(-1,1))
670        tmodel.b.obj = Objective(expr=sum_product(tmodel.b.x))
671        tmodel.c = Constraint(expr=tmodel.b.x[1] >= 0)
672        self.assertEqual(len(tmodel.solutions), 0)
673        tmodel.solutions.load_from(results)
674        self.assertEqual(len(tmodel.solutions), 1)
675
676    @unittest.skipIf('glpk' not in solvers, "glpk solver is not available")
677    @unittest.skipIf(not yaml_available, "YAML not available available")
678    def test_solve_with_store2(self):
679        model = ConcreteModel()
680        model.A = RangeSet(1,4)
681        model.b = Block()
682        model.b.x = Var(model.A, bounds=(-1,1))
683        model.b.obj = Objective(expr=sum_product(model.b.x))
684        model.c = Constraint(expr=model.b.x[1] >= 0)
685        opt = SolverFactory('glpk')
686        results = opt.solve(model)
687        #
688        results.write(filename=join(currdir,'solve_with_store3.out'),
689                      format='json')
690        with open(join(currdir,"solve_with_store3.out"), 'r') as out, \
691            open(join(currdir,"solve_with_store3.txt"), 'r') as txt:
692            self.assertStructuredAlmostEqual(yaml.full_load(txt),
693                                             yaml.full_load(out),
694                                             allow_second_superset=True)
695        #
696        model.solutions.store_to(results)
697        results.write(filename=join(currdir,'solve_with_store4.out'),
698                      format='json')
699        with open(join(currdir,"solve_with_store4.out"), 'r') as out, \
700            open(join(currdir,"solve_with_store4.txt"), 'r') as txt:
701            self.assertStructuredAlmostEqual(yaml.full_load(txt),
702                                             yaml.full_load(out),
703                                             allow_second_superset=True)
704        #
705        # Test that we can pickle the results object
706        #
707        buf = pickle.dumps(results)
708        results_ = pickle.loads(buf)
709        results.write(filename=join(currdir,'solve_with_store4.out'),
710                      format='json')
711        with open(join(currdir,"solve_with_store4.out"), 'r') as out, \
712            open(join(currdir,"solve_with_store4.txt"), 'r') as txt:
713            self.assertStructuredAlmostEqual(yaml.full_load(txt),
714                                             yaml.full_load(out),
715                                             allow_second_superset=True)
716        #
717        # Load results with string indices
718        #
719        tmodel = ConcreteModel()
720        tmodel.A = RangeSet(1,3)
721        tmodel.b = Block()
722        tmodel.b.x = Var(tmodel.A, bounds=(-1,1))
723        tmodel.b.obj = Objective(expr=sum_product(tmodel.b.x))
724        tmodel.c = Constraint(expr=tmodel.b.x[1] >= 0)
725        self.assertEqual(len(tmodel.solutions), 0)
726        tmodel.solutions.load_from(results, ignore_invalid_labels=True)
727        self.assertEqual(len(tmodel.solutions), 1)
728
729    @unittest.skipIf('glpk' not in solvers, "glpk solver is not available")
730    @unittest.skipIf(not yaml_available, "YAML not available available")
731    def test_solve_with_store3(self):
732        model = ConcreteModel()
733        model.A = RangeSet(1,4)
734        model.b = Block()
735        model.b.x = Var(model.A, bounds=(-1,1))
736        model.b.obj = Objective(expr=sum_product(model.b.x))
737        model.c = Constraint(expr=model.b.x[1] >= 0)
738        opt = SolverFactory('glpk')
739        results = opt.solve(model)
740        #
741        model.solutions.store_to(results)
742        results.write(filename=join(currdir,'solve_with_store5.out'),
743                      format='json')
744        with open(join(currdir,"solve_with_store5.out"), 'r') as out, \
745            open(join(currdir,"solve_with_store4.txt"), 'r') as txt:
746            self.assertStructuredAlmostEqual(yaml.full_load(txt),
747                                             yaml.full_load(out),
748                                             allow_second_superset=True)
749        #
750        model.solutions.store_to(results, cuid=True)
751        buf = pickle.dumps(results)
752        results_ = pickle.loads(buf)
753        model.solutions.load_from(results_)
754        model.solutions.store_to(results_)
755        results_.write(filename=join(currdir,'solve_with_store6.out'),
756                       format='json')
757        with open(join(currdir,"solve_with_store6.out"), 'r') as out, \
758            open(join(currdir,"solve_with_store4.txt"), 'r') as txt:
759            self.assertStructuredAlmostEqual(yaml.full_load(txt),
760                                             yaml.full_load(out),
761                                             allow_second_superset=True)
762        #
763        # Load results with string indices
764        #
765        tmodel = ConcreteModel()
766        tmodel.A = RangeSet(1,4)
767        tmodel.b = Block()
768        tmodel.b.x = Var(tmodel.A, bounds=(-1,1))
769        tmodel.b.obj = Objective(expr=sum_product(tmodel.b.x))
770        tmodel.c = Constraint(expr=tmodel.b.x[1] >= 0)
771        self.assertEqual(len(tmodel.solutions), 0)
772        tmodel.solutions.load_from(results)
773        self.assertEqual(len(tmodel.solutions), 1)
774        tmodel.solutions.store_to(results)
775        results.write(filename=join(currdir,'solve_with_store7.out'),
776                      format='json')
777        with open(join(currdir,"solve_with_store7.out"), 'r') as out, \
778            open(join(currdir,"solve_with_store4.txt"), 'r') as txt:
779            self.assertStructuredAlmostEqual(yaml.full_load(txt),
780                                             yaml.full_load(out),
781                                             allow_second_superset=True)
782
783    @unittest.skipIf('glpk' not in solvers, "glpk solver is not available")
784    @unittest.skipIf(not yaml_available, "YAML not available available")
785    def test_solve_with_store4(self):
786        model = ConcreteModel()
787        model.A = RangeSet(1,4)
788        model.b = Block()
789        model.b.x = Var(model.A, bounds=(-1,1))
790        model.b.obj = Objective(expr=sum_product(model.b.x))
791        model.c = Constraint(expr=model.b.x[1] >= 0)
792        opt = SolverFactory('glpk')
793        results = opt.solve(model, load_solutions=False)
794        self.assertEqual(len(model.solutions), 0)
795        self.assertEqual(len(results.solution), 1)
796        model.solutions.load_from(results)
797        self.assertEqual(len(model.solutions), 1)
798        self.assertEqual(len(results.solution), 1)
799        #
800        model.solutions.store_to(results)
801        results.write(filename=join(currdir,'solve_with_store8.out'),
802                      format='json')
803        with open(join(currdir,"solve_with_store8.out"), 'r') as out, \
804            open(join(currdir,"solve_with_store4.txt"), 'r') as txt:
805            self.assertStructuredAlmostEqual(yaml.full_load(txt),
806                                             yaml.full_load(out),
807                                             allow_second_superset=True)
808
809    @unittest.skipIf('glpk' not in solvers, "glpk solver is not available")
810    @unittest.skipIf(not yaml_available, "YAML not available available")
811    def test_solve_with_store5(self):
812        model = ConcreteModel()
813        model.A = RangeSet(1,4)
814        model.b = Block()
815        model.b.x = Var(model.A, bounds=(-1,1))
816        model.b.obj = Objective(expr=sum_product(model.b.x))
817        model.c = Constraint(expr=model.b.x[1] >= 0)
818
819        smanager = SolverManager_Serial()
820        ah = smanager.queue(model, solver='glpk', load_solutions=False)
821        results = smanager.wait_for(ah)
822        self.assertEqual(len(model.solutions), 0)
823        self.assertEqual(len(results.solution), 1)
824        model.solutions.load_from(results)
825        self.assertEqual(len(model.solutions), 1)
826        self.assertEqual(len(results.solution), 1)
827        #
828        model.solutions.store_to(results)
829        results.write(filename=join(currdir,'solve_with_store8.out'),
830                      format='json')
831        with open(join(currdir,"solve_with_store8.out"), 'r') as out, \
832            open(join(currdir,"solve_with_store4.txt"), 'r') as txt:
833            self.assertStructuredAlmostEqual(yaml.full_load(txt),
834                                             yaml.full_load(out),
835                                             allow_second_superset=True)
836
837
838    def test_create_concrete_from_rule(self):
839        def make(m):
840            m.I = RangeSet(3)
841            m.x = Var(m.I)
842            m.c = Constraint( expr=sum(m.x[i] for i in m.I) >= 0 )
843        model = ConcreteModel(rule=make)
844        self.assertEqual( [x.local_name for x in model.component_objects()],
845                          ['I','x','c'] )
846        self.assertEqual( len(list(EXPR.identify_variables(model.c.body))), 3 )
847
848
849    def test_create_abstract_from_rule(self):
850        def make_invalid(m):
851            m.I = RangeSet(3)
852            m.x = Var(m.I)
853            m.c = Constraint( expr=sum(m.x[i] for i in m.I) >= 0 )
854
855        def make(m):
856            m.I = RangeSet(3)
857            m.x = Var(m.I)
858            def c(b):
859                return sum(m.x[i] for i in m.I) >= 0
860            m.c = Constraint( rule=c )
861
862        with self.assertRaisesRegex(
863                ValueError, r'x\[1\]: The component has not been constructed.'):
864            model = AbstractModel(rule=make_invalid)
865            instance = model.create_instance()
866
867        model = AbstractModel(rule=make)
868        instance = model.create_instance()
869        self.assertEqual( [x.local_name for x in model.component_objects()],
870                          [] )
871        self.assertEqual( [x.local_name for x in instance.component_objects()],
872                          ['I','x','c'] )
873        self.assertEqual( len(list(EXPR.identify_variables(instance.c.body))), 3 )
874
875        model = AbstractModel(rule=make)
876        model.y = Var()
877        instance = model.create_instance()
878        self.assertEqual( [x.local_name for x in instance.component_objects()],
879                          ['y','I','x','c'] )
880        self.assertEqual( len(list(EXPR.identify_variables(instance.c.body))), 3 )
881
882    def test_error1(self):
883        model = ConcreteModel()
884        model.x = Var()
885        instance = model.create_instance()
886
887if __name__ == "__main__":
888    unittest.main()
889
890