Skip to content

Commit 45c7b48

Browse files
committed
Bugfix so that mbm can accept bigm-style bigM arguments for the constraints that will be transformed with bigm
1 parent 3d5500f commit 45c7b48

File tree

2 files changed

+71
-38
lines changed

2 files changed

+71
-38
lines changed

pyomo/gdp/plugins/multiple_bigm.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -432,6 +432,7 @@ def _transform_constraint(self, obj, disjunct, active_disjuncts, Ms):
432432
bigm = TransformationFactory('gdp.bigm')
433433
bigm.assume_fixed_vars_permanent = self._config.\
434434
assume_fixed_vars_permanent
435+
bigm.used_args = self.used_args
435436

436437
for i in sorted(obj.keys()):
437438
c = obj[i]

pyomo/gdp/tests/test_mbigm.py

Lines changed: 70 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -645,33 +645,13 @@ def test_logical_constraints_on_disjuncts(self):
645645
check_linear_coef(self, repn, m.d2.binary_indicator_var, -1)
646646
check_linear_coef(self, repn, m.d3.binary_indicator_var, -1)
647647

648-
def test_only_multiple_bigm_bound_constraints(self):
649-
m = self.make_model()
650-
mbm = TransformationFactory('gdp.mbigm')
651-
mbm.apply_to(m, only_mbigm_bound_constraints=True)
652-
653-
cons = mbm.get_transformed_constraints(m.d1.x1_bounds)
654-
self.assertEqual(len(cons), 2)
655-
self.check_pretty_bound_constraints(cons[0], m.x1, {m.d1: 0.5, m.d2:
656-
0.65, m.d3: 2},
657-
lb=True)
658-
self.check_pretty_bound_constraints(cons[1], m.x1, {m.d1: 2, m.d2: 3,
659-
m.d3: 10}, lb=False)
660-
661-
cons = mbm.get_transformed_constraints(m.d1.x2_bounds)
662-
self.assertEqual(len(cons), 2)
663-
self.check_pretty_bound_constraints(cons[0], m.x2, {m.d1: 0.75, m.d2: 3,
664-
m.d3: 0.55},
665-
lb=True)
666-
self.check_pretty_bound_constraints(cons[1], m.x2, {m.d1: 3, m.d2: 10,
667-
m.d3: 1}, lb=False)
668-
648+
def check_traditionally_bigmed_constraints(self, m, mbm, Ms):
669649
cons = mbm.get_transformed_constraints(m.d1.func)
670650
self.assertEqual(len(cons), 2)
671651
lb = cons[0]
672652
ub = cons[1]
673653
assertExpressionsEqual(self, lb.expr, 0.0 <= m.x1 + m.x2 - m.d -
674-
(-1030.0)*(1 - m.d1.binary_indicator_var))
654+
Ms[m.d1][0]*(1 - m.d1.binary_indicator_var))
675655
# [ESJ 11/23/22]: It's really hard to use assertExpressionsEqual on the
676656
# ub constraints because SumExpressions are sharing args, I think. So
677657
# when they get constructed in the transformation (because they come
@@ -685,45 +665,97 @@ def test_only_multiple_bigm_bound_constraints(self):
685665
simplified = repn.constant + sum(
686666
repn.linear_coefs[i]*repn.linear_vars[i]
687667
for i in range(len(repn.linear_vars)))
688-
assertExpressionsEqual(
689-
self,
690-
simplified,
691-
m.x1 + m.x2 - m.d + 1030.0*m.d1.binary_indicator_var - 1030.0)
668+
assertExpressionsEqual(self, simplified, m.x1 + m.x2 - m.d +
669+
Ms[m.d1][1]*m.d1.binary_indicator_var -
670+
Ms[m.d1][1])
692671

693672
cons = mbm.get_transformed_constraints(m.d2.func)
694673
self.assertEqual(len(cons), 2)
695674
lb = cons[0]
696675
ub = cons[1]
697-
print(lb.expr)
698676
assertExpressionsEqual(self, lb.expr, 0.0 <= 2*m.x1 + 4*m.x2 + 7 - m.d -
699-
(-1093.0)*(1 - m.d2.binary_indicator_var))
677+
Ms[m.d2][0]*(1 - m.d2.binary_indicator_var))
700678
self.assertIsNone(ub.lower)
701679
self.assertEqual(ub.upper, 0)
702680
repn = generate_standard_repn(ub.body)
703681
self.assertTrue(repn.is_linear())
704682
simplified = repn.constant + sum(
705683
repn.linear_coefs[i]*repn.linear_vars[i]
706684
for i in range(len(repn.linear_vars)))
707-
assertExpressionsEqual(
708-
self,
709-
simplified,
710-
2*m.x1 + 4*m.x2 - m.d + 1107.0*m.d2.binary_indicator_var - 1100.0)
685+
assertExpressionsEqual(self, simplified, 2*m.x1 + 4*m.x2 - m.d +
686+
Ms[m.d2][1]*m.d2.binary_indicator_var -
687+
(Ms[m.d2][1] - 7))
711688

712689
cons = mbm.get_transformed_constraints(m.d3.func)
713690
self.assertEqual(len(cons), 2)
714691
lb = cons[0]
715692
ub = cons[1]
716-
print(lb.expr)
717693
assertExpressionsEqual(self, lb.expr, 0.0 <= m.x1 - 5*m.x2 - 3 - m.d -
718-
(-1113.0)*(1 - m.d3.binary_indicator_var))
694+
Ms[m.d3][0]*(1 - m.d3.binary_indicator_var))
719695
self.assertIsNone(ub.lower)
720696
self.assertEqual(ub.upper, 0)
721697
repn = generate_standard_repn(ub.body)
722698
self.assertTrue(repn.is_linear())
723699
simplified = repn.constant + sum(
724700
repn.linear_coefs[i]*repn.linear_vars[i]
725701
for i in range(len(repn.linear_vars)))
726-
assertExpressionsEqual(
727-
self,
728-
simplified,
729-
m.x1 - 5*m.x2 - m.d + 1107.0*m.d3.binary_indicator_var - 1110.0)
702+
assertExpressionsEqual(self, simplified, m.x1 - 5*m.x2 - m.d +
703+
Ms[m.d3][1]*m.d3.binary_indicator_var -
704+
(Ms[m.d3][1] + 3))
705+
706+
def test_only_multiple_bigm_bound_constraints(self):
707+
m = self.make_model()
708+
mbm = TransformationFactory('gdp.mbigm')
709+
mbm.apply_to(m, only_mbigm_bound_constraints=True)
710+
711+
cons = mbm.get_transformed_constraints(m.d1.x1_bounds)
712+
self.assertEqual(len(cons), 2)
713+
self.check_pretty_bound_constraints(cons[0], m.x1, {m.d1: 0.5, m.d2:
714+
0.65, m.d3: 2},
715+
lb=True)
716+
self.check_pretty_bound_constraints(cons[1], m.x1, {m.d1: 2, m.d2: 3,
717+
m.d3: 10}, lb=False)
718+
719+
cons = mbm.get_transformed_constraints(m.d1.x2_bounds)
720+
self.assertEqual(len(cons), 2)
721+
self.check_pretty_bound_constraints(cons[0], m.x2, {m.d1: 0.75, m.d2: 3,
722+
m.d3: 0.55},
723+
lb=True)
724+
self.check_pretty_bound_constraints(cons[1], m.x2, {m.d1: 3, m.d2: 10,
725+
m.d3: 1}, lb=False)
726+
727+
self.check_traditionally_bigmed_constraints(
728+
m,
729+
mbm,
730+
{m.d1: (-1030.0, 1030.0),
731+
m.d2: (-1093.0, 1107.0),
732+
m.d3: (-1113.0, 1107.0)})
733+
734+
def test_only_multiple_bigm_bound_constraints_arg_Ms(self):
735+
m = self.make_model()
736+
mbm = TransformationFactory('gdp.mbigm')
737+
Ms = {m.d1: 1050, m.d2.func: (-2000, 1200), None: 4000}
738+
mbm.apply_to(m, only_mbigm_bound_constraints=True, bigM=Ms)
739+
740+
cons = mbm.get_transformed_constraints(m.d1.x1_bounds)
741+
self.assertEqual(len(cons), 2)
742+
self.check_pretty_bound_constraints(cons[0], m.x1, {m.d1: 0.5, m.d2:
743+
0.65, m.d3: 2},
744+
lb=True)
745+
self.check_pretty_bound_constraints(cons[1], m.x1, {m.d1: 2, m.d2: 3,
746+
m.d3: 10}, lb=False)
747+
748+
cons = mbm.get_transformed_constraints(m.d1.x2_bounds)
749+
self.assertEqual(len(cons), 2)
750+
self.check_pretty_bound_constraints(cons[0], m.x2, {m.d1: 0.75, m.d2: 3,
751+
m.d3: 0.55},
752+
lb=True)
753+
self.check_pretty_bound_constraints(cons[1], m.x2, {m.d1: 3, m.d2: 10,
754+
m.d3: 1}, lb=False)
755+
756+
self.check_traditionally_bigmed_constraints(
757+
m,
758+
mbm,
759+
{m.d1: (-1050, 1050),
760+
m.d2: (-2000, 1200),
761+
m.d3: (-4000, 4000)})

0 commit comments

Comments
 (0)