@@ -7,6 +7,21 @@ function reformulate_disjunction(model::JuMP.AbstractModel,
7
7
method:: MBM
8
8
)
9
9
ref_cons = Vector {JuMP.AbstractConstraint} ()
10
+ for d in disj. indicators
11
+ constraints = copy (_indicator_to_constraints (model)[d]) # Make a copy to avoid modifying during iteration
12
+ for cref in constraints
13
+ con = JuMP. constraint_object (cref)
14
+ if con isa JuMP. ScalarConstraint{<: Any , <: MOI.Interval }
15
+ # Create lower and upper bound constraints
16
+ lower_con = JuMP. build_constraint (error, con. func, MOI. GreaterThan (con. set. lower))
17
+ upper_con = JuMP. build_constraint (error, con. func, MOI. LessThan (con. set. upper))
18
+ # Create new disjunct constraints
19
+ JuMP. add_constraint (model, _DisjunctConstraint (lower_con, d))
20
+ JuMP. add_constraint (model, _DisjunctConstraint (upper_con, d))
21
+ JuMP. delete (model, cref)
22
+ end
23
+ end
24
+ end
10
25
for d in disj. indicators
11
26
_reformulate_disjunct (model, ref_cons, d, LogicalVariableRef[x for x in disj. indicators if x != d], method)
12
27
end
@@ -21,29 +36,33 @@ function _reformulate_disjunct(
21
36
conlvref:: Vector{LogicalVariableRef} ,
22
37
method:: AbstractReformulationMethod
23
38
)
24
- bconref = VariableRef[binary_variable (i) for i in conlvref]
39
+
40
+ bconref = Dict (d => binary_variable (d) for d in conlvref)
25
41
! haskey (_indicator_to_constraints (model), lvref) && return
26
- M = Vector {Float64} (undef, length (conlvref))
27
- for (i,d) in enumerate (conlvref)
28
- M[i] = maximum (_maximize_M (model, constraint_object (cref),
29
- Vector {DisjunctConstraintRef} (_indicator_to_constraints (model)[d]), method)
30
- for cref in _indicator_to_constraints (model)[lvref])
42
+ constraints = _indicator_to_constraints (model)[lvref]
43
+ M = Dict {LogicalVariableRef,Float64} ()
44
+ sizehint! (M, length (conlvref))
45
+ for d in conlvref
46
+ M[d] = maximum (_maximize_M (model, JuMP. constraint_object (cref),
47
+ Vector {DisjunctConstraintRef} (_indicator_to_constraints (model)[d]), method) for cref in constraints)
31
48
end
32
- for cref in _indicator_to_constraints (model)[lvref]
49
+
50
+ isempty (constraints) || sizehint! (ref_cons, length (constraints))
51
+ for cref in constraints
33
52
con = JuMP. constraint_object (cref)
34
- append! (ref_cons, reformulate_disjunct_constraint (model, con, bconref, M, method))
53
+ append! (ref_cons, reformulate_disjunct_constraint (model, con, Dict {LogicalVariableRef,VariableRef} ( bconref) , M, method))
35
54
end
36
55
return ref_cons
37
56
end
38
57
39
58
function reformulate_disjunct_constraint (
40
59
model:: JuMP.AbstractModel ,
41
60
con:: JuMP.VectorConstraint{T, S, R} ,
42
- bconref:: Vector{ VariableRef} ,
43
- M:: Vector{ Float64} ,
61
+ bconref:: Dict{LogicalVariableRef, VariableRef} ,
62
+ M:: Dict{LogicalVariableRef, Float64} ,
44
63
method:: MBM
45
64
) where {T, S <: _MOI.Nonpositives , R}
46
- m_sum = sum (M[i] * bconref[i] for i in 1 : length (M))
65
+ m_sum = sum (M[i] * bconref[i] for i in keys (M))
47
66
new_func = JuMP. @expression (model, [i= 1 : con. set. dimension],
48
67
con. func[i] - m_sum
49
68
)
54
73
function reformulate_disjunct_constraint (
55
74
model:: JuMP.AbstractModel ,
56
75
con:: JuMP.VectorConstraint{T, S, R} ,
57
- bconref:: Vector{ VariableRef} ,
58
- M:: Vector{ Float64} ,
76
+ bconref:: Dict{LogicalVariableRef, VariableRef} ,
77
+ M:: Dict{LogicalVariableRef, Float64} ,
59
78
method:: MBM
60
79
) where {T, S <: _MOI.Nonnegatives , R}
61
- m_sum = sum (M[i] * bconref[i] for i in 1 : length (M))
80
+ m_sum = sum (M[i] * bconref[i] for i in keys (M))
62
81
new_func = JuMP. @expression (model, [i= 1 : con. set. dimension],
63
82
con. func[i] + m_sum
64
83
)
69
88
function reformulate_disjunct_constraint (
70
89
model:: JuMP.AbstractModel ,
71
90
con:: JuMP.VectorConstraint{T, S, R} ,
72
- bconref:: Vector{ VariableRef} ,
73
- M:: Vector{ Float64} ,
91
+ bconref:: Dict{LogicalVariableRef, VariableRef} ,
92
+ M:: Dict{LogicalVariableRef, Float64} ,
74
93
method:: MBM
75
94
) where {T, S <: _MOI.Zeros , R}
76
- m_sum = sum (M[i] * bconref[i] for i in 1 : length (M))
95
+ m_sum = sum (M[i] * bconref[i] for i in keys (M))
77
96
upper_expr = JuMP. @expression (model, [i= 1 : con. set. dimension],
78
97
con. func[i] + m_sum
79
98
)
89
108
function reformulate_disjunct_constraint (
90
109
model:: JuMP.AbstractModel ,
91
110
con:: JuMP.ScalarConstraint{T, S} ,
92
- bconref:: Vector{ VariableRef} ,
93
- M:: Vector{ Float64} ,
111
+ bconref:: Dict{LogicalVariableRef, VariableRef} ,
112
+ M:: Dict{LogicalVariableRef, Float64} ,
94
113
method:: MBM
95
114
) where {T, S <: _MOI.LessThan }
96
- new_func = JuMP. @expression (model, con. func - sum (M[i] * bconref[i] for i in 1 : length (M)))
115
+ new_func = JuMP. @expression (model, con. func - sum (M[i] * bconref[i] for i in keys (M)))
97
116
reform_con = JuMP. build_constraint (error, new_func, con. set)
98
117
return [reform_con]
99
118
end
100
119
101
120
function reformulate_disjunct_constraint (
102
121
model:: JuMP.AbstractModel ,
103
122
con:: JuMP.ScalarConstraint{T, S} ,
104
- bconref:: Vector{ VariableRef} ,
105
- M:: Vector{ Float64} ,
123
+ bconref:: Dict{LogicalVariableRef, VariableRef} ,
124
+ M:: Dict{LogicalVariableRef, Float64} ,
106
125
method:: MBM
107
126
) where {T, S <: _MOI.GreaterThan }
108
- new_func = JuMP. @expression (model, con. func + sum (M[i] * bconref[i] for i in 1 : length (M)))
127
+ new_func = JuMP. @expression (model, con. func + sum (M[i] * bconref[i] for i in keys (M)))
109
128
reform_con = JuMP. build_constraint (error, new_func, con. set)
110
129
return [reform_con]
111
130
end
112
131
113
132
function reformulate_disjunct_constraint (
114
133
model:: JuMP.AbstractModel ,
115
134
con:: JuMP.ScalarConstraint{T, S} ,
116
- bconref:: Vector{ VariableRef} ,
117
- M:: Vector{ Float64} ,
135
+ bconref:: Dict{LogicalVariableRef, VariableRef} ,
136
+ M:: Dict{LogicalVariableRef, Float64} ,
118
137
method:: MBM
119
- ) where {T, S <: _MOI.Interval }
120
- lower_func = JuMP. @expression (model, con. func - sum (M[i] * bconref[i] for i in 1 : length (M)))
121
- upper_func = JuMP. @expression (model, con. func + sum (M[i] * bconref[i] for i in 1 : length (M)))
138
+ ) where {T, S <: _MOI.EqualTo }
139
+ upper_func = JuMP. @expression (model, con. func - sum (M[i] * bconref[i] for i in keys (M)))
140
+ lower_func = JuMP. @expression (model, con. func + sum (M[i] * bconref[i] for i in keys (M)))
122
141
123
- lower_con = JuMP. build_constraint (error, lower_func , MOI. GreaterThan (con. set. lower ))
124
- upper_con = JuMP. build_constraint (error, upper_func , MOI. LessThan (con. set. upper ))
142
+ upper_con = JuMP. build_constraint (error, upper_func , MOI. LessThan (con. set. value ))
143
+ lower_con = JuMP. build_constraint (error, lower_func , MOI. GreaterThan (con. set. value ))
125
144
return [lower_con, upper_con]
126
145
end
127
-
128
146
function reformulate_disjunct_constraint (
129
147
model:: JuMP.AbstractModel ,
130
- con:: JuMP.ScalarConstraint{T, S} ,
131
- bconref:: Vector{ VariableRef} ,
132
- M:: Vector{ Float64} ,
148
+ con:: Any ,
149
+ bconref:: Dict{LogicalVariableRef, VariableRef} ,
150
+ M:: Dict{LogicalVariableRef, Float64} ,
133
151
method:: MBM
134
- ) where {T, S <: _MOI.EqualTo }
135
- upper_func = JuMP. @expression (model, con. func - sum (M[i] * bconref[i] for i in 1 : length (M)))
136
- lower_func = JuMP. @expression (model, con. func + sum (M[i] * bconref[i] for i in 1 : length (M)))
137
-
138
- upper_con = JuMP. build_constraint (error, upper_func, MOI. LessThan (con. set. value))
139
- lower_con = JuMP. build_constraint (error, lower_func, MOI. GreaterThan (con. set. value))
140
- return [lower_con, upper_con]
152
+ )
153
+ error (" Constraint type $(typeof (con)) is not supported by the Multiple Big-M reformulation method." )
141
154
end
142
155
143
156
# ###############################################################################
@@ -183,16 +196,6 @@ function _maximize_M(
183
196
return _mini_model (model, objective, constraints, method)
184
197
end
185
198
186
- function _maximize_M (
187
- model:: JuMP.AbstractModel ,
188
- objective:: ScalarConstraint{T, S} ,
189
- constraints:: Vector{DisjunctConstraintRef} ,
190
- method:: MBM
191
- ) where {T, S <: _MOI.Interval }
192
- return max (_mini_model (model, ScalarConstraint (objective. func, MOI. GreaterThan (objective. set. lower)), constraints, method),
193
- _mini_model (model, ScalarConstraint (objective. func, MOI. LessThan (objective. set. upper)), constraints, method))
194
- end
195
-
196
199
function _maximize_M (
197
200
model:: JuMP.AbstractModel ,
198
201
objective:: ScalarConstraint{T, S} ,
@@ -221,38 +224,38 @@ function _mini_model(
221
224
constraints:: Vector{DisjunctConstraintRef} ,
222
225
method:: MBM
223
226
) where {T,S <: Union{_MOI.LessThan, _MOI.GreaterThan} }
224
- sub_model = Model ()
225
- new_vars = Dict {VariableRef, VariableRef} ()
226
- for var in all_variables (model)
227
- new_vars[var] = @variable (sub_model, base_name= " sub_model_$(JuMP. name (var)) " )
228
- if is_fixed (var)
229
- JuMP. fix (new_vars[var], fix_value (var); force= true )
227
+ sub_model = JuMP . Model ()
228
+ new_vars = Dict {JuMP. VariableRef, JuMP. VariableRef} ()
229
+ for var in JuMP . all_variables (model)
230
+ new_vars[var] = JuMP . @variable (sub_model, base_name= " sub_model_$(JuMP. name (var)) " )
231
+ if JuMP . is_fixed (var)
232
+ JuMP. fix (new_vars[var], JuMP . fix_value (var); force= true )
230
233
end
231
- if is_integer (var)
234
+ if JuMP . is_integer (var)
232
235
JuMP. set_integer (new_vars[var])
233
236
end
234
- if has_upper_bound (var)
235
- set_upper_bound (new_vars[var], upper_bound (var))
237
+ if JuMP . has_upper_bound (var)
238
+ JuMP . set_upper_bound (new_vars[var], JuMP . upper_bound (var))
236
239
end
237
- if has_lower_bound (var)
238
- set_lower_bound (new_vars[var], lower_bound (var))
240
+ if JuMP . has_lower_bound (var)
241
+ JuMP . set_lower_bound (new_vars[var], JuMP . lower_bound (var))
239
242
end
240
- if has_start_value (var)
241
- JuMP. set_start_value (new_vars[var], start_value (var))
243
+ if JuMP . has_start_value (var)
244
+ JuMP. set_start_value (new_vars[var], JuMP . start_value (var))
242
245
end
243
246
end
244
- for con in [constraint_object (con) for con in constraints]
247
+ for con in [JuMP . constraint_object (con) for con in constraints]
245
248
expr = replace_variables_in_constraint (con. func, new_vars)
246
- @constraint (sub_model, expr * 1.0 in con. set)
249
+ JuMP . @constraint (sub_model, expr * 1.0 in con. set)
247
250
end
248
251
constraint_to_objective (sub_model, objective, new_vars)
249
- set_optimizer (sub_model, method. optimizer)
250
- set_silent (sub_model)
251
- optimize! (sub_model)
252
+ JuMP . set_optimizer (sub_model, method. optimizer)
253
+ JuMP . set_silent (sub_model)
254
+ JuMP . optimize! (sub_model)
252
255
if JuMP. termination_status (sub_model) != MOI. OPTIMAL || ! JuMP. has_values (sub_model) || JuMP. primal_status (sub_model) != MOI. FEASIBLE_POINT
253
- M = 200
256
+ M = 1e9
254
257
else
255
- M = objective_value (sub_model)
258
+ M = JuMP . objective_value (sub_model)
256
259
end
257
260
return M
258
261
end
@@ -270,14 +273,14 @@ end
270
273
# ###############################################################################
271
274
# CONSTRAINT TO OBJECTIVE
272
275
# ###############################################################################
273
- function constraint_to_objective (sub_model:: JuMP.AbstractModel ,obj:: ScalarConstraint{<:AbstractJuMPScalar, MOI.LessThan{Float64}} , new_vars:: Dict{VariableRef, VariableRef} )
274
- @objective (sub_model, Max, - obj. set. upper + replace_variables_in_constraint (obj. func, new_vars))
276
+ function constraint_to_objective (sub_model:: JuMP.AbstractModel ,obj:: JuMP. ScalarConstraint{<:JuMP. AbstractJuMPScalar, MOI.LessThan{Float64}} , new_vars:: Dict{JuMP. VariableRef, JuMP. VariableRef} )
277
+ JuMP . @objective (sub_model, Max, - obj. set. upper + replace_variables_in_constraint (obj. func, new_vars))
275
278
end
276
- function constraint_to_objective (sub_model:: JuMP.AbstractModel ,obj:: ScalarConstraint{<:AbstractJuMPScalar, MOI.GreaterThan{Float64}} , new_vars:: Dict{VariableRef, VariableRef} )
277
- @objective (sub_model, Max, - replace_variables_in_constraint (obj. func, new_vars) + obj. set. lower)
279
+ function constraint_to_objective (sub_model:: JuMP.AbstractModel ,obj:: JuMP. ScalarConstraint{<:JuMP. AbstractJuMPScalar, MOI.GreaterThan{Float64}} , new_vars:: Dict{JuMP. VariableRef, JuMP. VariableRef} )
280
+ JuMP . @objective (sub_model, Max, - replace_variables_in_constraint (obj. func, new_vars) + obj. set. lower)
278
281
end
279
282
280
- function constraint_to_objective (sub_model:: JuMP.AbstractModel ,obj:: ScalarConstraint , new_vars:: Dict{VariableRef, VariableRef} )
283
+ function constraint_to_objective (sub_model:: JuMP.AbstractModel ,obj:: JuMP. ScalarConstraint , new_vars:: Dict{JuMP. VariableRef, JuMP. VariableRef} )
281
284
error (" This type of constraint is not supported, only greater than and less than constraints are supported with intervals and equalities being converted." )
282
285
end
283
286
@@ -287,40 +290,40 @@ end
287
290
288
291
289
292
290
- function replace_variables_in_constraint (fun:: GenericVariableRef , var_map:: Dict{VariableRef, VariableRef} )
293
+ function replace_variables_in_constraint (fun:: JuMP. GenericVariableRef , var_map:: Dict{JuMP. VariableRef, JuMP. VariableRef} )
291
294
return var_map[fun]
292
295
end
293
296
294
- function replace_variables_in_constraint (fun:: AffExpr , var_map:: Dict{VariableRef, VariableRef} )
295
- new_aff = zero (AffExpr)
297
+ function replace_variables_in_constraint (fun:: JuMP. AffExpr , var_map:: Dict{JuMP. VariableRef, JuMP. VariableRef} )
298
+ new_aff = JuMP . zero (JuMP . AffExpr)
296
299
for (var, coef) in fun. terms
297
300
new_var = var_map[var]
298
- add_to_expression! (new_aff, coef, new_var)
301
+ JuMP . add_to_expression! (new_aff, coef, new_var)
299
302
end
300
303
new_aff. constant = fun. constant
301
304
return new_aff
302
305
end
303
306
304
- function replace_variables_in_constraint (fun:: QuadExpr , var_map:: Dict{VariableRef, VariableRef} )
305
- new_quad = zero (QuadExpr)
307
+ function replace_variables_in_constraint (fun:: JuMP. QuadExpr , var_map:: Dict{JuMP. VariableRef, JuMP. VariableRef} )
308
+ new_quad = JuMP . zero (JuMP . QuadExpr)
306
309
for (vars, coef) in fun. terms
307
- add_to_expression! (new_quad, coef, var_map[vars. a], var_map[vars. b])
310
+ JuMP . add_to_expression! (new_quad, coef, var_map[vars. a], var_map[vars. b])
308
311
end
309
312
new_aff = replace_variables_in_constraint (fun. aff, var_map)
310
- add_to_expression! (new_quad, new_aff)
313
+ JuMP . add_to_expression! (new_quad, new_aff)
311
314
return new_quad
312
315
end
313
316
314
- function replace_variables_in_constraint (fun:: Number , var_map:: Dict{VariableRef, VariableRef} )
317
+ function replace_variables_in_constraint (fun:: Number , var_map:: Dict{JuMP. VariableRef, JuMP. VariableRef} )
315
318
return fun
316
319
end
317
320
318
- function replace_variables_in_constraint (fun:: NonlinearExpr , var_map:: Dict{VariableRef, VariableRef} )
321
+ function replace_variables_in_constraint (fun:: JuMP. NonlinearExpr , var_map:: Dict{JuMP. VariableRef, JuMP. VariableRef} )
319
322
new_args = Any[replace_variables_in_constraint (arg, var_map) for arg in fun. args]
320
323
return JuMP. NonlinearExpr (fun. head, new_args)
321
324
end
322
325
323
- function replace_variables_in_constraint (fun:: Vector{T} , var_map:: Dict{VariableRef, VariableRef} ) where T
326
+ function replace_variables_in_constraint (fun:: Vector{T} , var_map:: Dict{JuMP. VariableRef, JuMP. VariableRef} ) where T
324
327
return [replace_variables_in_constraint (expr, var_map) for expr in fun]
325
328
end
326
329
0 commit comments