13
13
14
14
import logging
15
15
16
+ from pyomo .common .autoslots import AutoSlots
16
17
from pyomo .common .collections import ComponentMap
17
18
from pyomo .common .config import ConfigDict , ConfigValue
18
19
from pyomo .common .gc_manager import PauseGC
58
59
logger = logging .getLogger ('pyomo.gdp.bigm' )
59
60
60
61
62
+ class _BigMData (AutoSlots .Mixin ):
63
+ __slots__ = ('bigm_src' ,)
64
+
65
+ def __init__ (self ):
66
+ # we will keep a map of constraints (hashable, ha!) to a tuple to
67
+ # indicate what their M value is and where it came from, of the form:
68
+ # ((lower_value, lower_source, lower_key), (upper_value, upper_source,
69
+ # upper_key)), where the first tuple is the information for the lower M,
70
+ # the second tuple is the info for the upper M, source is the Suffix or
71
+ # argument dictionary and None if the value was calculated, and key is
72
+ # the key in the Suffix or argument dictionary, and None if it was
73
+ # calculated. (Note that it is possible the lower or upper is
74
+ # user-specified and the other is not, hence the need to store
75
+ # information for both.)
76
+ self .bigm_src = {}
77
+
78
+
79
+ Block .register_private_data_initializer (_BigMData )
80
+
81
+
61
82
@TransformationFactory .register (
62
83
'gdp.bigm' , doc = "Relax disjunctive model using big-M terms."
63
84
)
@@ -94,15 +115,8 @@ class BigM_Transformation(GDP_to_MIP_Transformation, _BigM_MixIn):
94
115
name beginning "_pyomo_gdp_bigm_reformulation". That Block will
95
116
contain an indexed Block named "relaxedDisjuncts", which will hold
96
117
the relaxed disjuncts. This block is indexed by an integer
97
- indicating the order in which the disjuncts were relaxed.
98
- Each block has a dictionary "_constraintMap":
99
-
100
- 'srcConstraints': ComponentMap(<transformed constraint>:
101
- <src constraint>)
102
- 'transformedConstraints': ComponentMap(<src constraint>:
103
- <transformed constraint>)
104
-
105
- All transformed Disjuncts will have a pointer to the block their transformed
118
+ indicating the order in which the disjuncts were relaxed. All
119
+ transformed Disjuncts will have a pointer to the block their transformed
106
120
constraints are on, and all transformed Disjunctions will have a
107
121
pointer to the corresponding 'Or' or 'ExactlyOne' constraint.
108
122
@@ -247,18 +261,6 @@ def _transform_disjunct(self, obj, bigM, transBlock):
247
261
248
262
relaxationBlock = self ._get_disjunct_transformation_block (obj , transBlock )
249
263
250
- # we will keep a map of constraints (hashable, ha!) to a tuple to
251
- # indicate what their M value is and where it came from, of the form:
252
- # ((lower_value, lower_source, lower_key), (upper_value, upper_source,
253
- # upper_key)), where the first tuple is the information for the lower M,
254
- # the second tuple is the info for the upper M, source is the Suffix or
255
- # argument dictionary and None if the value was calculated, and key is
256
- # the key in the Suffix or argument dictionary, and None if it was
257
- # calculated. (Note that it is possible the lower or upper is
258
- # user-specified and the other is not, hence the need to store
259
- # information for both.)
260
- relaxationBlock .bigm_src = {}
261
-
262
264
# This is crazy, but if the disjunction has been previously
263
265
# relaxed, the disjunct *could* be deactivated. This is a big
264
266
# deal for Hull, as it uses the component_objects /
@@ -278,8 +280,8 @@ def _transform_constraint(
278
280
):
279
281
# add constraint to the transformation block, we'll transform it there.
280
282
transBlock = disjunct ._transformation_block ()
281
- bigm_src = transBlock .bigm_src
282
- constraintMap = transBlock ._constraintMap
283
+ bigm_src = transBlock .private_data (). bigm_src
284
+ constraint_map = transBlock .private_data ( 'pyomo.gdp' )
283
285
284
286
disjunctionRelaxationBlock = transBlock .parent_block ()
285
287
@@ -346,7 +348,7 @@ def _transform_constraint(
346
348
bigm_src [c ] = (lower , upper )
347
349
348
350
self ._add_constraint_expressions (
349
- c , i , M , disjunct .binary_indicator_var , newConstraint , constraintMap
351
+ c , i , M , disjunct .binary_indicator_var , newConstraint , constraint_map
350
352
)
351
353
352
354
# deactivate because we relaxed
@@ -409,7 +411,7 @@ def _update_M_from_suffixes(self, constraint, suffix_list, lower, upper):
409
411
def get_m_value_src (self , constraint ):
410
412
transBlock = _get_constraint_transBlock (constraint )
411
413
((lower_val , lower_source , lower_key ), (upper_val , upper_source , upper_key )) = (
412
- transBlock .bigm_src [constraint ]
414
+ transBlock .private_data (). bigm_src [constraint ]
413
415
)
414
416
415
417
if (
@@ -464,7 +466,7 @@ def get_M_value_src(self, constraint):
464
466
transBlock = _get_constraint_transBlock (constraint )
465
467
# This is a KeyError if it fails, but it is also my fault if it
466
468
# fails... (That is, it's a bug in the mapping.)
467
- return transBlock .bigm_src [constraint ]
469
+ return transBlock .private_data (). bigm_src [constraint ]
468
470
469
471
def get_M_value (self , constraint ):
470
472
"""Returns the M values used to transform constraint. Return is a tuple:
@@ -479,7 +481,7 @@ def get_M_value(self, constraint):
479
481
transBlock = _get_constraint_transBlock (constraint )
480
482
# This is a KeyError if it fails, but it is also my fault if it
481
483
# fails... (That is, it's a bug in the mapping.)
482
- lower , upper = transBlock .bigm_src [constraint ]
484
+ lower , upper = transBlock .private_data (). bigm_src [constraint ]
483
485
return (lower [0 ], upper [0 ])
484
486
485
487
def get_all_M_values_by_constraint (self , model ):
@@ -499,9 +501,8 @@ def get_all_M_values_by_constraint(self, model):
499
501
# First check if it was transformed at all.
500
502
if transBlock is not None :
501
503
# If it was transformed with BigM, we get the M values.
502
- if hasattr (transBlock , 'bigm_src' ):
503
- for cons in transBlock .bigm_src :
504
- m_values [cons ] = self .get_M_value (cons )
504
+ for cons in transBlock .private_data ().bigm_src :
505
+ m_values [cons ] = self .get_M_value (cons )
505
506
return m_values
506
507
507
508
def get_largest_M_value (self , model ):
0 commit comments