1from pyomo.core import (Block, ConcreteModel, Constraint, Objective, Param, Set,
2                        Var, inequality, RangeSet, Any, Expression, maximize, TransformationFactory)
3from pyomo.gdp import Disjunct, Disjunction
4
5import pyomo.network as ntwk
6
7def oneVarDisj_2pts():
8    m = ConcreteModel()
9    m.x = Var(bounds=(0, 10))
10    m.disj1 = Disjunct()
11    m.disj1.xTrue = Constraint(expr=m.x==1)
12    m.disj2 = Disjunct()
13    m.disj2.xFalse = Constraint(expr=m.x==0)
14    m.disjunction = Disjunction(expr=[m.disj1, m.disj2])
15    m.obj = Objective(expr=m.x)
16    return m
17
18def twoSegments_SawayaGrossmann():
19    m = ConcreteModel()
20    m.x = Var(bounds=(0, 3))
21    m.disj1 = Disjunct()
22    m.disj1.c = Constraint(expr=inequality(0, m.x, 1))
23    m.disj2 = Disjunct()
24    m.disj2.c = Constraint(expr=inequality(2, m.x, 3))
25    m.disjunction = Disjunction(expr=[m.disj1, m.disj2])
26
27    # this is my objective because I want to make sure that when I am testing
28    # cutting planes, my first solution to rBigM is not on the convex hull.
29    m.obj = Objective(expr=m.x - m.disj2.indicator_var)
30
31    return m
32
33def makeTwoTermDisj():
34    """Single two-term disjunction which has all of ==, <=, and >= constraints
35    """
36    m = ConcreteModel()
37    m.a = Var(bounds=(2, 7))
38    m.x = Var(bounds=(4, 9))
39
40    def d_rule(disjunct, flag):
41        m = disjunct.model()
42        if flag:
43            disjunct.c1 = Constraint(expr=m.a == 0)
44            disjunct.c2 = Constraint(expr=m.x <= 7)
45        else:
46            disjunct.c = Constraint(expr=m.a >= 5)
47    m.d = Disjunct([0, 1], rule=d_rule)
48    m.disjunction = Disjunction(expr=[m.d[0], m.d[1]])
49    return m
50
51
52def makeTwoTermDisj_Nonlinear():
53    """Single two-term disjunction which has all of ==, <=, and >= and
54    one nonlinear constraint.
55    """
56    m = ConcreteModel()
57    m.w = Var(bounds=(2, 7))
58    m.x = Var(bounds=(1, 8))
59    m.y = Var(bounds=(-10, -3))
60
61    def d_rule(disjunct, flag):
62        m = disjunct.model()
63        if flag:
64            disjunct.c1 = Constraint(expr=m.x >= 2)
65            disjunct.c2 = Constraint(expr=m.w == 3)
66            disjunct.c3 = Constraint(expr=(1, m.x, 3))
67        else:
68            disjunct.c = Constraint(expr=m.x + m.y**2 <= 14)
69    m.d = Disjunct([0, 1], rule=d_rule)
70    m.disjunction = Disjunction(expr=[m.d[0], m.d[1]])
71    return m
72
73
74def makeTwoTermDisj_IndexedConstraints():
75    """Single two-term disjunction with IndexedConstraints on both disjuncts.
76    Does not bound the variables, so cannot be transformed by hull at all and
77    requires specifying m values in bigm.
78    """
79    m = ConcreteModel()
80    m.s = Set(initialize=[1, 2])
81    m.a = Var(m.s)
82    m.b = Block()
83
84    def disj1_rule(disjunct):
85        m = disjunct.model()
86
87        def c_rule(d, s):
88            return m.a[s] == 0
89        disjunct.c = Constraint(m.s, rule=c_rule)
90    m.b.simpledisj1 = Disjunct(rule=disj1_rule)
91
92    def disj2_rule(disjunct):
93        m = disjunct.model()
94
95        def c_rule(d, s):
96            return m.a[s] <= 3
97        disjunct.c = Constraint(m.s, rule=c_rule)
98    m.b.simpledisj2 = Disjunct(rule=disj2_rule)
99    m.b.disjunction = Disjunction(expr=[m.b.simpledisj1, m.b.simpledisj2])
100    return m
101
102
103def makeTwoTermDisj_IndexedConstraints_BoundedVars():
104    """Single two-term disjunction with IndexedConstraints on both disjuncts.
105    """
106    m = ConcreteModel()
107    m.s = Set(initialize=[1, 2])
108    m.lbs = Param(m.s, initialize={1: 2, 2: 4})
109    m.ubs = Param(m.s, initialize={1: 7, 2: 6})
110
111    def bounds_rule(m, s):
112        return (m.lbs[s], m.ubs[s])
113    m.a = Var(m.s, bounds=bounds_rule)
114
115    def d_rule(disjunct, flag):
116        m = disjunct.model()
117
118        def true_rule(d, s):
119            return m.a[s] == 0
120
121        def false_rule(d, s):
122            return m.a[s] >= 5
123        if flag:
124            disjunct.c = Constraint(m.s, rule=true_rule)
125        else:
126            disjunct.c = Constraint(m.s, rule=false_rule)
127    m.disjunct = Disjunct([0, 1], rule=d_rule)
128    m.disjunction = Disjunction(expr=[m.disjunct[0], m.disjunct[1]])
129    return m
130
131def localVar():
132    """Two-term disjunction which declares a local variable y on one of the
133    disjuncts, which is used in the objective function as well.
134
135    Used to test that we will treat y as global in the transformations,
136    despite where it is declared.
137    """
138    # y appears in a global constraint and a single disjunct.
139    m = ConcreteModel()
140    m.x = Var(bounds=(0,3))
141
142    m.disj1 = Disjunct()
143    m.disj1.cons = Constraint(expr=m.x >= 1)
144
145    m.disj2 = Disjunct()
146    m.disj2.y = Var(bounds=(1,3))
147    m.disj2.cons = Constraint(expr=m.x + m.disj2.y == 3)
148
149    m.disjunction = Disjunction(expr=[m.disj1, m.disj2])
150
151    # This makes y global actually... But in disguise.
152    m.objective = Objective(expr=m.x + m.disj2.y)
153    return m
154
155
156def makeThreeTermIndexedDisj():
157    """Three-term indexed disjunction"""
158    m = ConcreteModel()
159    m.s = Set(initialize=[1, 2])
160    m.a = Var(m.s, bounds=(2, 7))
161
162    def d_rule(disjunct, flag, s):
163        m = disjunct.model()
164        if flag == 0:
165            disjunct.c = Constraint(expr=m.a[s] == 0)
166        elif flag == 1:
167            disjunct.c = Constraint(expr=m.a[s] >= 5)
168        else:
169            disjunct.c = Constraint(expr=inequality(2, m.a[s], 4))
170    m.disjunct = Disjunct([0, 1, 2], m.s, rule=d_rule)
171
172    def disj_rule(m, s):
173        return [m.disjunct[0, s], m.disjunct[1, s], m.disjunct[2, s]]
174    m.disjunction = Disjunction(m.s, rule=disj_rule)
175    return m
176
177
178def makeTwoTermDisj_boxes():
179    m = ConcreteModel()
180    m.x = Var(bounds=(0,5))
181    m.y = Var(bounds=(0,5))
182    def d_rule(disjunct, flag):
183        m = disjunct.model()
184        if flag:
185            disjunct.c1 = Constraint(expr=inequality(1, m.x, 2))
186            disjunct.c2 = Constraint(expr=inequality(3, m.y, 4))
187        else:
188            disjunct.c1 = Constraint(expr=inequality(3, m.x, 4))
189            disjunct.c2 = Constraint(expr=inequality(1, m.y, 2))
190    m.d = Disjunct([0,1], rule=d_rule)
191    def disj_rule(m):
192        return [m.d[0], m.d[1]]
193    m.disjunction = Disjunction(rule=disj_rule)
194    m.obj = Objective(expr=m.x + 2*m.y)
195    return m
196
197
198def makeThreeTermDisj_IndexedConstraints():
199    """Three-term disjunction with indexed constraints on the disjuncts"""
200    m = ConcreteModel()
201    m.I = [1, 2, 3]
202    m.x = Var(m.I, bounds=(0, 10))
203
204    def c_rule(b, i):
205        m = b.model()
206        return m.x[i] >= i
207
208    def d_rule(d, j):
209        m = d.model()
210        d.c = Constraint(m.I[:j], rule=c_rule)
211    m.d = Disjunct(m.I, rule=d_rule)
212    m.disjunction = Disjunction(expr=[m.d[i] for i in m.I])
213    return m
214
215
216def makeTwoTermIndexedDisjunction():
217    """Two-term indexed disjunction"""
218    m = ConcreteModel()
219    m.A = Set(initialize=[1, 2, 3])
220    m.B = Set(initialize=['a', 'b'])
221    m.x = Var(m.A, bounds=(-10, 10))
222
223    def disjunct_rule(d, i, k):
224        m = d.model()
225        if k == 'a':
226            d.cons_a = Constraint(expr=m.x[i] >= 5)
227        if k == 'b':
228            d.cons_b = Constraint(expr=m.x[i] <= 0)
229    m.disjunct = Disjunct(m.A, m.B, rule=disjunct_rule)
230
231    def disj_rule(m, i):
232        return [m.disjunct[i, k] for k in m.B]
233    m.disjunction = Disjunction(m.A, rule=disj_rule)
234    return m
235
236
237def makeTwoTermIndexedDisjunction_BoundedVars():
238    """Two-term indexed disjunction.
239    Adds nothing to above--exists for historic reasons"""
240    m = ConcreteModel()
241    m.s = Set(initialize=[1, 2, 3])
242    m.a = Var(m.s, bounds=(-100, 100))
243
244    def disjunct_rule(d, s, flag):
245        m = d.model()
246        if flag:
247            d.c = Constraint(expr=m.a[s] >= 6)
248        else:
249            d.c = Constraint(expr=m.a[s] <= 3)
250    m.disjunct = Disjunct(m.s, [0, 1], rule=disjunct_rule)
251
252    def disjunction_rule(m, s):
253        return [m.disjunct[s, flag] for flag in [0, 1]]
254    m.disjunction = Disjunction(m.s, rule=disjunction_rule)
255    return m
256
257
258def makeIndexedDisjunction_SkipIndex():
259    """Two-term indexed disjunction where one of the two indices is skipped"""
260    m = ConcreteModel()
261    m.x = Var(bounds=(0, 10))
262    @m.Disjunct([0,1])
263    def disjuncts(d, i):
264        m = d.model()
265        d.cons = Constraint(expr=m.x == i)
266
267    @m.Disjunction([0,1])
268    def disjunctions(m, i):
269        if i == 0:
270            return Disjunction.Skip
271        return [m.disjuncts[i], m.disjuncts[0]]
272
273    return m
274
275def makeTwoTermMultiIndexedDisjunction():
276    """Two-term indexed disjunction with tuple indices"""
277    m = ConcreteModel()
278    m.s = Set(initialize=[1, 2])
279    m.t = Set(initialize=['A', 'B'])
280    m.a = Var(m.s, m.t, bounds=(2, 7))
281
282    def d_rule(disjunct, flag, s, t):
283        m = disjunct.model()
284        if flag:
285            disjunct.c = Constraint(expr=m.a[s, t] == 0)
286        else:
287            disjunct.c = Constraint(expr=m.a[s, t] >= 5)
288    m.disjunct = Disjunct([0, 1], m.s, m.t, rule=d_rule)
289
290    def disj_rule(m, s, t):
291        return [m.disjunct[0, s, t], m.disjunct[1, s, t]]
292    m.disjunction = Disjunction(m.s, m.t, rule=disj_rule)
293    return m
294
295
296def makeTwoTermDisjOnBlock():
297    """Two-term SimpleDisjunction on a block"""
298    m = ConcreteModel()
299    m.b = Block()
300    m.a = Var(bounds=(0, 5))
301
302    @m.b.Disjunct([0, 1])
303    def disjunct(disjunct, flag):
304        m = disjunct.model()
305        if flag:
306            disjunct.c = Constraint(expr=m.a <= 3)
307        else:
308            disjunct.c = Constraint(expr=m.a == 0)
309
310    @m.b.Disjunction()
311    def disjunction(m):
312        return [m.disjunct[0], m.disjunct[1]]
313
314    return m
315
316def add_disj_not_on_block(m):
317    def simpdisj_rule(disjunct):
318        m = disjunct.model()
319        disjunct.c = Constraint(expr=m.a >= 3)
320    m.simpledisj = Disjunct(rule=simpdisj_rule)
321    def simpledisj2_rule(disjunct):
322        m = disjunct.model()
323        disjunct.c = Constraint(expr=m.a <= 3.5)
324    m.simpledisj2 = Disjunct(rule=simpledisj2_rule)
325    m.disjunction2 = Disjunction(expr=[m.simpledisj, m.simpledisj2])
326    return m
327
328def makeDisjunctionsOnIndexedBlock():
329    """Two disjunctions (one indexed an one not), each on a separate
330    BlockData of an IndexedBlock of length 2
331    """
332    m = ConcreteModel()
333    m.s = Set(initialize=[1, 2])
334    m.a = Var(m.s, bounds=(0, 70))
335
336    @m.Disjunct(m.s, [0, 1])
337    def disjunct1(disjunct, s, flag):
338        m = disjunct.model()
339        if not flag:
340            disjunct.c = Constraint(expr=m.a[s] == 0)
341        else:
342            disjunct.c = Constraint(expr=m.a[s] >= 7)
343
344    def disjunction1_rule(m, s):
345        return [m.disjunct1[s, flag] for flag in [0, 1]]
346    m.disjunction1 = Disjunction(m.s, rule=disjunction1_rule)
347
348    m.b = Block([0, 1])
349    m.b[0].x = Var(bounds=(-2, 2))
350
351    def disjunct2_rule(disjunct, flag):
352        if not flag:
353            disjunct.c = Constraint(expr=m.b[0].x <= 0)
354        else:
355            disjunct.c = Constraint(expr=m.b[0].x >= 0)
356    m.b[0].disjunct = Disjunct([0, 1], rule=disjunct2_rule)
357
358    def disjunction(b, i):
359        return [b.disjunct[0], b.disjunct[1]]
360    m.b[0].disjunction = Disjunction([0], rule=disjunction)
361
362    m.b[1].y = Var(bounds=(-3, 3))
363    m.b[1].disjunct0 = Disjunct()
364    m.b[1].disjunct0.c = Constraint(expr=m.b[1].y <= 0)
365    m.b[1].disjunct1 = Disjunct()
366    m.b[1].disjunct1.c = Constraint(expr=m.b[1].y >= 0)
367    m.b[1].disjunction = Disjunction(
368        expr=[m.b[1].disjunct0, m.b[1].disjunct1])
369    return m
370
371
372def makeTwoTermDisj_BlockOnDisj():
373    """SimpleDisjunction where one of the Disjuncts contains three different
374    blocks: two simple and one indexed"""
375    m = ConcreteModel()
376    m.x = Var(bounds=(0, 1000))
377    m.y = Var(bounds=(0, 800))
378
379    def disj_rule(d, flag):
380        m = d.model()
381        if flag:
382            d.b = Block()
383            d.b.c = Constraint(expr=m.x == 0)
384            d.add_component('b.c', Constraint(expr=m.y >= 9))
385            d.b.anotherblock = Block()
386            d.b.anotherblock.c = Constraint(expr=m.y >= 11)
387            d.bb = Block([1])
388            d.bb[1].c = Constraint(expr=m.x == 0)
389        else:
390            d.c = Constraint(expr=m.x >= 80)
391    m.evil = Disjunct([0, 1], rule=disj_rule)
392    m.disjunction = Disjunction(expr=[m.evil[0], m.evil[1]])
393    return m
394
395
396def makeNestedDisjunctions():
397    """Three-term SimpleDisjunction built from two IndexedDisjuncts and one
398    SimpleDisjunct. The SimpleDisjunct and one of the DisjunctDatas each
399    contain a nested SimpleDisjunction (the disjuncts of which are declared
400    on the same disjunct as the disjunction).
401
402    (makeNestedDisjunctions_NestedDisjuncts is a much simpler model. All
403    this adds is that it has a nested disjunction on a DisjunctData as well
404    as on a SimpleDisjunct. So mostly it exists for historical reasons.)
405    """
406    m = ConcreteModel()
407    m.x = Var(bounds=(-9, 9))
408    m.z = Var(bounds=(0, 10))
409    m.a = Var(bounds=(0, 23))
410
411    def disjunct_rule(disjunct, flag):
412        m = disjunct.model()
413        if flag:
414            def innerdisj_rule(disjunct, flag):
415                m = disjunct.model()
416                if flag:
417                    disjunct.c = Constraint(expr=m.z >= 5)
418                else:
419                    disjunct.c = Constraint(expr=m.z == 0)
420            disjunct.innerdisjunct = Disjunct([0, 1], rule=innerdisj_rule)
421
422            @disjunct.Disjunction([0])
423            def innerdisjunction(b, i):
424                return [b.innerdisjunct[0], b.innerdisjunct[1]]
425            disjunct.c = Constraint(expr=m.a <= 2)
426        else:
427            disjunct.c = Constraint(expr=m.x == 2)
428    m.disjunct = Disjunct([0, 1], rule=disjunct_rule)
429    # I want a SimpleDisjunct with a disjunction in it too
430
431    def simpledisj_rule(disjunct):
432        m = disjunct.model()
433
434        @disjunct.Disjunct()
435        def innerdisjunct0(disjunct):
436            disjunct.c = Constraint(expr=m.x <= 2)
437
438        @disjunct.Disjunct()
439        def innerdisjunct1(disjunct):
440            disjunct.c = Constraint(expr=m.x >= 4)
441
442        disjunct.innerdisjunction = Disjunction(
443            expr=[disjunct.innerdisjunct0, disjunct.innerdisjunct1])
444    m.simpledisjunct = Disjunct(rule=simpledisj_rule)
445    m.disjunction = Disjunction(
446        expr=[m.simpledisjunct, m.disjunct[0], m.disjunct[1]])
447    return m
448
449
450def makeNestedDisjunctions_FlatDisjuncts():
451    """Two-term SimpleDisjunction where one of the disjuncts contains a nested
452    SimpleDisjunction, the disjuncts of which are declared on the model"""
453    m = ConcreteModel()
454    m.x = Var(bounds=(0, 2))
455    m.obj = Objective(expr=m.x)
456    m.d1 = Disjunct()
457    m.d1.c = Constraint(expr=m.x >= 1)
458    m.d2 = Disjunct()
459    m.d2.c = Constraint(expr=m.x >= 1.1)
460    m.d3 = Disjunct()
461    m.d3.c = Constraint(expr=m.x >= 1.2)
462    m.d4 = Disjunct()
463    m.d4.c = Constraint(expr=m.x >= 1.3)
464    m.disj = Disjunction(expr=[m.d1, m.d2])
465    m.d1.disj = Disjunction(expr=[m.d3, m.d4])
466    return m
467
468
469def makeNestedDisjunctions_NestedDisjuncts():
470    """Same as makeNestedDisjunctions_FlatDisjuncts except that the disjuncts
471    of the nested disjunction are declared on the parent disjunct."""
472    m = ConcreteModel()
473    m.x = Var(bounds=(0, 2))
474    m.obj = Objective(expr=m.x)
475    m.d1 = Disjunct()
476    m.d1.c = Constraint(expr=m.x >= 1)
477    m.d2 = Disjunct()
478    m.d2.c = Constraint(expr=m.x >= 1.1)
479    m.d1.d3 = Disjunct()
480    m.d1.d3.c = Constraint(expr=m.x >= 1.2)
481    m.d1.d4 = Disjunct()
482    m.d1.d4.c = Constraint(expr=m.x >= 1.3)
483    m.disj = Disjunction(expr=[m.d1, m.d2])
484    m.d1.disj2 = Disjunction(expr=[m.d1.d3, m.d1.d4])
485    return m
486
487
488def makeTwoSimpleDisjunctions():
489    """Two SimpleDisjunctions on the same model."""
490    m = ConcreteModel()
491    m.a = Var(bounds=(-10, 50))
492
493    def d1_rule(disjunct, flag):
494        m = disjunct.model()
495        if flag:
496            disjunct.c = Constraint(expr=m.a == 0)
497        else:
498            disjunct.c = Constraint(expr=m.a >= 5)
499    m.disjunct1 = Disjunct([0, 1], rule=d1_rule)
500
501    def d2_rule(disjunct, flag):
502        if not flag:
503            disjunct.c = Constraint(expr=m.a >= 30)
504        else:
505            disjunct.c = Constraint(expr=m.a == 100)
506    m.disjunct2 = Disjunct([0, 1], rule=d2_rule)
507
508    m.disjunction1 = Disjunction(expr=[m.disjunct1[0], m.disjunct1[1]])
509    m.disjunction2 = Disjunction(expr=[m.disjunct2[0], m.disjunct2[1]])
510    return m
511
512
513def makeDisjunctInMultipleDisjunctions():
514    """This is not a transformable model! Two SimpleDisjunctions which have
515    a shared disjunct.
516    """
517    m = ConcreteModel()
518    m.a = Var(bounds=(-10, 50))
519
520    def d1_rule(disjunct, flag):
521        m = disjunct.model()
522        if flag:
523            disjunct.c = Constraint(expr=m.a == 0)
524        else:
525            disjunct.c = Constraint(expr=m.a >= 5)
526    m.disjunct1 = Disjunct([0, 1], rule=d1_rule)
527
528    def d2_rule(disjunct, flag):
529        if not flag:
530            disjunct.c = Constraint(expr=m.a >= 30)
531        else:
532            disjunct.c = Constraint(expr=m.a == 100)
533    m.disjunct2 = Disjunct([0, 1], rule=d2_rule)
534
535    m.disjunction1 = Disjunction(expr=[m.disjunct1[0], m.disjunct1[1]])
536    m.disjunction2 = Disjunction(expr=[m.disjunct2[0], m.disjunct1[1]])
537    # Deactivate unused disjunct like we are supposed to
538    m.disjunct2[1].deactivate()
539    return m
540
541
542def makeDuplicatedNestedDisjunction():
543    """Not a transformable model (because of disjuncts shared between
544    disjunctions): A SimpleDisjunction where one of the disjuncts contains
545    two SimpleDisjunctions with the same Disjuncts.
546    """
547    m = ConcreteModel()
548    m.x = Var(bounds=(0, 8))
549
550    def outerdisj_rule(d, flag):
551        m = d.model()
552        if flag:
553            def innerdisj_rule(d, flag):
554                m = d.model()
555                if flag:
556                    d.c = Constraint(expr=m.x >= 2)
557                else:
558                    d.c = Constraint(expr=m.x == 0)
559            d.innerdisjunct = Disjunct([0, 1], rule=innerdisj_rule)
560            d.innerdisjunction = Disjunction(expr=[d.innerdisjunct[0],
561                                                   d.innerdisjunct[1]])
562            d.duplicateddisjunction = Disjunction(expr=[d.innerdisjunct[0],
563                                                        d.innerdisjunct[1]])
564        else:
565            d.c = Constraint(expr=m.x == 8)
566    m.outerdisjunct = Disjunct([0, 1], rule=outerdisj_rule)
567    m.disjunction = Disjunction(expr=[m.outerdisjunct[0],
568                                      m.outerdisjunct[1]])
569    return m
570
571def makeDisjunctWithRangeSet():
572    """Two-term SimpleDisjunction where one of the disjuncts contains a
573    RangeSet"""
574    m = ConcreteModel()
575    m.x = Var(bounds=(0, 1))
576    m.d1 = Disjunct()
577    m.d1.s = RangeSet(1)
578    m.d1.c = Constraint(rule=lambda _: m.x == 1)
579    m.d2 = Disjunct()
580    m.disj = Disjunction(expr=[m.d1, m.d2])
581    return m
582
583##########################
584# Grossmann lecture models
585##########################
586
587def grossmann_oneDisj():
588    m = ConcreteModel()
589    m.x = Var(bounds=(0,20))
590    m.y = Var(bounds=(0, 20))
591    m.disjunct1 = Disjunct()
592    m.disjunct1.constraintx = Constraint(expr=inequality(0, m.x, 2))
593    m.disjunct1.constrainty = Constraint(expr=inequality(7, m.y, 10))
594
595    m.disjunct2 = Disjunct()
596    m.disjunct2.constraintx = Constraint(expr=inequality(8, m.x, 10))
597    m.disjunct2.constrainty = Constraint(expr=inequality(0, m.y, 3))
598
599    m.disjunction = Disjunction(expr=[m.disjunct1, m.disjunct2])
600
601    m.objective = Objective(expr=m.x + 2*m.y, sense=maximize)
602
603    return m
604
605def to_break_constraint_tolerances():
606    m = ConcreteModel()
607    m.x = Var(bounds=(0, 130))
608    m.y = Var(bounds=(0, 130))
609    m.disjunct1 = Disjunct()
610    m.disjunct1.constraintx = Constraint(expr=inequality(0, m.x, 2))
611    m.disjunct1.constrainty = Constraint(expr=inequality(117, m.y, 127))
612
613    m.disjunct2 = Disjunct()
614    m.disjunct2.constraintx = Constraint(expr=inequality(118, m.x, 120))
615    m.disjunct2.constrainty = Constraint(expr=inequality(0, m.y, 3))
616
617    m.disjunction = Disjunction(expr=[m.disjunct1, m.disjunct2])
618
619    m.objective = Objective(expr=m.x + 2*m.y, sense=maximize)
620
621    return m
622
623def grossmann_twoDisj():
624    m = grossmann_oneDisj()
625
626    m.disjunct3 = Disjunct()
627    m.disjunct3.constraintx = Constraint(expr=inequality(1, m.x, 2.5))
628    m.disjunct3.constrainty = Constraint(expr=inequality(6.5, m.y, 8))
629
630    m.disjunct4 = Disjunct()
631    m.disjunct4.constraintx = Constraint(expr=inequality(9, m.x, 11))
632    m.disjunct4.constrainty = Constraint(expr=inequality(2, m.y, 3.5))
633
634    m.disjunction2 = Disjunction(expr=[m.disjunct3, m.disjunct4])
635
636    return m
637
638def twoDisj_twoCircles_easy():
639    m = ConcreteModel()
640    m.x = Var(bounds=(0,8))
641    m.y = Var(bounds=(0,10))
642
643    m.upper_circle = Disjunct()
644    m.upper_circle.cons = Constraint(expr=(m.x - 1)**2 + (m.y - 6)**2 <= 2)
645    m.lower_circle = Disjunct()
646    m.lower_circle.cons = Constraint(expr=(m.x - 4)**2 + (m.y - 2)**2 <= 2)
647
648    m.disjunction = Disjunction(expr=[m.upper_circle, m.lower_circle])
649
650    m.obj = Objective(expr=m.x + m.y, sense=maximize)
651    return m
652
653def fourCircles():
654    m = twoDisj_twoCircles_easy()
655
656    # and add two more overlapping circles, a la the Grossmann test case with
657    # the rectangles. (but not change my nice integral optimal solution...)
658    m.upper_circle2 = Disjunct()
659    m.upper_circle2.cons = Constraint(expr=(m.x - 2)**2 + (m.y - 7)**2 <= 1)
660
661    m.lower_circle2 = Disjunct()
662    m.lower_circle2.cons = Constraint(expr=(m.x - 5)**2 + (m.y - 3)**2 <= 2)
663
664    m.disjunction2 = Disjunction(expr=[m.upper_circle2, m.lower_circle2])
665
666    return m
667
668def makeDisjunctWithExpression():
669    """Two-term SimpleDisjunction where one of the disjuncts contains an
670    Expression. This is used to make sure that we correctly handle types we
671    hit in disjunct.component_objects(active=True)"""
672    m = ConcreteModel()
673    m.x = Var(bounds=(0, 1))
674    m.d1 = Disjunct()
675    m.d1.e = Expression(expr=m.x**2)
676    m.d1.c = Constraint(rule=lambda _: m.x == 1)
677    m.d2 = Disjunct()
678    m.disj = Disjunction(expr=[m.d1, m.d2])
679    return m
680
681def makeDisjunctionOfDisjunctDatas():
682    """Two SimpleDisjunctions, where each are disjunctions of DisjunctDatas.
683    This adds nothing to makeTwoSimpleDisjunctions but exists for convenience
684    because it has the same mathematical meaning as
685    makeAnyIndexedDisjunctionOfDisjunctDatas
686    """
687    m = ConcreteModel()
688    m.x = Var(bounds=(-100, 100))
689
690    m.obj = Objective(expr=m.x)
691
692    m.idx = Set(initialize=[1,2])
693    m.firstTerm = Disjunct(m.idx)
694    m.firstTerm[1].cons = Constraint(expr=m.x == 0)
695    m.firstTerm[2].cons = Constraint(expr=m.x == 2)
696    m.secondTerm = Disjunct(m.idx)
697    m.secondTerm[1].cons = Constraint(expr=m.x >= 2)
698    m.secondTerm[2].cons = Constraint(expr=m.x >= 3)
699
700    m.disjunction = Disjunction(expr=[m.firstTerm[1], m.secondTerm[1]])
701    m.disjunction2 = Disjunction(expr=[m.firstTerm[2], m.secondTerm[2]])
702    return m
703
704def makeAnyIndexedDisjunctionOfDisjunctDatas():
705    """An IndexedDisjunction indexed by Any, with two two-term DisjunctionDatas
706    build from DisjunctDatas. Identical mathematically to
707    makeDisjunctionOfDisjunctDatas.
708
709    Used to test that the right things happen for a case where soemone
710    implements an algorithm which iteratively generates disjuncts and
711    retransforms"""
712    m = ConcreteModel()
713    m.x = Var(bounds=(-100, 100))
714
715    m.obj = Objective(expr=m.x)
716
717    m.idx = Set(initialize=[1,2])
718    m.firstTerm = Disjunct(m.idx)
719    m.firstTerm[1].cons = Constraint(expr=m.x == 0)
720    m.firstTerm[2].cons = Constraint(expr=m.x == 2)
721    m.secondTerm = Disjunct(m.idx)
722    m.secondTerm[1].cons = Constraint(expr=m.x >= 2)
723    m.secondTerm[2].cons = Constraint(expr=m.x >= 3)
724
725    m.disjunction = Disjunction(Any)
726    m.disjunction[1] = [m.firstTerm[1], m.secondTerm[1]]
727    m.disjunction[2] = [m.firstTerm[2], m.secondTerm[2]]
728    return m
729
730def makeNetworkDisjunction(minimize=True):
731    """ creates a GDP model with pyomo.network components """
732    m = ConcreteModel()
733
734    m.feed = feed = Block()
735    m.wkbx = wkbx = Block()
736    m.dest = dest = Block()
737
738    m.orange = orange = Disjunct()
739    m.blue = blue = Disjunct()
740
741    m.orange_or_blue = Disjunction(expr=[orange,blue])
742
743    blue.blue_box = blue_box = Block()
744
745    feed.x = Var(bounds=(0,1))
746    wkbx.x = Var(bounds=(0,1))
747    dest.x = Var(bounds=(0,1))
748
749    wkbx.inlet = ntwk.Port(initialize={"x":wkbx.x})
750    wkbx.outlet = ntwk.Port(initialize={"x":wkbx.x})
751
752    feed.outlet = ntwk.Port(initialize={"x":feed.x})
753    dest.inlet = ntwk.Port(initialize={"x":dest.x})
754
755    blue_box.x = Var(bounds=(0,1))
756    blue_box.x_wkbx = Var(bounds=(0,1))
757    blue_box.x_dest = Var(bounds=(0,1))
758
759
760    blue_box.inlet_feed = ntwk.Port(initialize={"x":blue_box.x})
761    blue_box.outlet_wkbx = ntwk.Port(initialize={"x":blue_box.x})
762
763    blue_box.inlet_wkbx = ntwk.Port(initialize={"x":blue_box.x_wkbx})
764    blue_box.outlet_dest = ntwk.Port(initialize={"x":blue_box.x_dest})
765
766    blue_box.multiplier_constr = Constraint(expr=blue_box.x_dest == 2*blue_box.x_wkbx)
767
768    # orange arcs
769    orange.a1 = ntwk.Arc(source=feed.outlet, destination=wkbx.inlet)
770    orange.a2 = ntwk.Arc(source=wkbx.outlet, destination=dest.inlet)
771
772    # blue arcs
773    blue.a1 = ntwk.Arc(source=feed.outlet, destination=blue_box.inlet_feed)
774    blue.a2 = ntwk.Arc(source=blue_box.outlet_wkbx, destination=wkbx.inlet)
775    blue.a3 = ntwk.Arc(source=wkbx.outlet, destination=blue_box.inlet_wkbx)
776    blue.a4 = ntwk.Arc(source=blue_box.outlet_dest, destination=dest.inlet)
777
778    # maximize/minimize "production"
779    if minimize:
780        m.obj = Objective(expr=m.dest.x)
781    else:
782        m.obj = Objective(expr=m.dest.x, sense=maximize)
783
784    # create a completely fixed model
785    feed.x.fix(0.42)
786
787    return m
788
789def makeExpandedNetworkDisjunction(minimize=True):
790    m = makeNetworkDisjunction(minimize)
791    TransformationFactory('network.expand_arcs').apply_to(m)
792    return m
793
794def makeThreeTermDisjunctionWithOneVarInOneDisjunct():
795    """This is to make sure hull doesn't create more disaggregated variables
796    than it needs to: Here, x only appears in the first Disjunct, so we only
797    need two copies: one as usual for that disjunct and then one other that is
798    free if either of the second two Disjuncts is active and 0 otherwise.
799    """
800    m = ConcreteModel()
801    m.x = Var(bounds=(-2,8))
802    m.y = Var(bounds=(3,4))
803    m.d1 = Disjunct()
804    m.d1.c1 = Constraint(expr=m.x <= 3)
805    m.d1.c2 = Constraint(expr=m.y >= 3.5)
806    m.d2 = Disjunct()
807    m.d2.c1 = Constraint(expr=m.y >= 3.7)
808    m.d3 = Disjunct()
809    m.d3.c1 = Constraint(expr=m.y >= 3.9)
810
811    m.disjunction = Disjunction(expr=[m.d1, m.d2, m.d3])
812
813    return m
814