@@ -59,6 +59,7 @@ struct BinPackingToMILPBridge{
5959 equal_to:: Vector {
6060 MOI. ConstraintIndex{MOI. ScalarAffineFunction{T},MOI. EqualTo{T}},
6161 }
62+ bounds:: Vector{NTuple{2,T}}
6263end
6364
6465const BinPackingToMILP{T,OT<: MOI.ModelLike } =
@@ -76,6 +77,7 @@ function bridge_constraint(
7677 MOI. VariableIndex[],
7778 MOI. ConstraintIndex{MOI. ScalarAffineFunction{T},MOI. LessThan{T}}[],
7879 MOI. ConstraintIndex{MOI. ScalarAffineFunction{T},MOI. EqualTo{T}}[],
80+ NTuple{2 ,T}[],
7981 )
8082end
8183
@@ -133,6 +135,7 @@ function MOI.delete(model::MOI.ModelLike, bridge::BinPackingToMILPBridge)
133135 empty! (bridge. equal_to)
134136 MOI. delete .(model, bridge. variables)
135137 empty! (bridge. variables)
138+ empty! (bridge. bounds)
136139 return
137140end
138141
@@ -232,9 +235,7 @@ function MOI.Bridges.final_touch(
232235 bridge:: BinPackingToMILPBridge{T,F} ,
233236 model:: MOI.ModelLike ,
234237) where {T,F}
235- # Clear any existing reformulations!
236- MOI. delete (model, bridge)
237- S = Dict {T,Vector{Tuple{Float64,MOI.VariableIndex}}} ()
238+ S = Dict {T,Vector{Tuple{T,MOI.VariableIndex}}} ()
238239 scalars = collect (MOI. Utilities. eachscalar (bridge. f))
239240 bounds = Dict {MOI.VariableIndex,NTuple{2,T}} ()
240241 for i in 1 : length (scalars)
@@ -246,41 +247,56 @@ function MOI.Bridges.final_touch(
246247 " function has a non-finite domain: $x " ,
247248 )
248249 end
250+ if length (bridge. bounds) < i
251+ # This is the first time calling final_touch
252+ push! (bridge. bounds, ret)
253+ elseif bridge. bounds[i] == ret
254+ # We've called final_touch before, and the bounds match. No need to
255+ # reformulate a second time.
256+ continue
257+ elseif bridge. bounds[i] != ret
258+ # There is a stored bound, and the current bounds do not match. This
259+ # means the model has been modified since the previous call to
260+ # final_touch. We need to delete the bridge and start again.
261+ MOI. delete (model, bridge)
262+ MOI. Bridges. final_touch (bridge, model)
263+ return
264+ end
249265 unit_f = MOI. ScalarAffineFunction (MOI. ScalarAffineTerm{T}[], zero (T))
250266 convex_f = MOI. ScalarAffineFunction (MOI. ScalarAffineTerm{T}[], zero (T))
251267 for xi in ret[1 ]:: T : ret[2 ]:: T
252268 new_var, _ = MOI. add_constrained_variable (model, MOI. ZeroOne ())
253269 push! (bridge. variables, new_var)
254270 if ! haskey (S, xi)
255- S[xi] = Tuple{Float64 ,MOI. VariableIndex}[]
271+ S[xi] = Tuple{T ,MOI. VariableIndex}[]
256272 end
257273 push! (S[xi], (bridge. s. weights[i], new_var))
258- push! (unit_f. terms, MOI. ScalarAffineTerm (T (- xi), new_var))
259- push! (convex_f. terms, MOI. ScalarAffineTerm (one (T), new_var))
274+ push! (unit_f. terms, MOI. ScalarAffineTerm {T} (T (- xi), new_var))
275+ push! (convex_f. terms, MOI. ScalarAffineTerm {T} (one (T), new_var))
260276 end
261277 push! (
262278 bridge. equal_to,
263279 MOI. Utilities. normalize_and_add_constraint (
264280 model,
265281 MOI. Utilities. operate (+ , T, x, unit_f),
266- MOI. EqualTo (zero (T));
282+ MOI. EqualTo {T} (zero (T));
267283 allow_modify_function = true ,
268284 ),
269285 )
270286 push! (
271287 bridge. equal_to,
272- MOI. add_constraint (model, convex_f, MOI. EqualTo (one (T))),
288+ MOI. add_constraint (model, convex_f, MOI. EqualTo {T} (one (T))),
273289 )
274290 end
275291 # We use a sort so that the model order is deterministic.
276292 for s in sort! (collect (keys (S)))
277293 ci = MOI. add_constraint (
278294 model,
279- MOI. ScalarAffineFunction (
280- [MOI. ScalarAffineTerm (w, z) for (w, z) in S[s]],
295+ MOI. ScalarAffineFunction {T} (
296+ [MOI. ScalarAffineTerm {T} (w, z) for (w, z) in S[s]],
281297 zero (T),
282298 ),
283- MOI. LessThan (bridge. s. capacity),
299+ MOI. LessThan {T} (bridge. s. capacity),
284300 )
285301 push! (bridge. less_than, ci)
286302 end
0 commit comments