Skip to content

Commit cab3440

Browse files
authored
[Bridges] add {SOS1,SOS2,Indicator}ToMILPBridge (#2318)
1 parent acab995 commit cab3440

File tree

17 files changed

+1507
-224
lines changed

17 files changed

+1507
-224
lines changed

docs/src/submodules/Bridges/list_of_bridges.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,9 @@ Bridges.Constraint.CountDistinctToMILPBridge
7979
Bridges.Constraint.ReifiedCountDistinctToMILPBridge
8080
Bridges.Constraint.CountGreaterThanToMILPBridge
8181
Bridges.Constraint.TableToMILPBridge
82+
Bridges.Constraint.SOS1ToMILPBridge
83+
Bridges.Constraint.SOS2ToMILPBridge
84+
Bridges.Constraint.IndicatorToMILPBridge
8285
```
8386

8487
## [Objective bridges](@id objective_bridges_ref)

src/Bridges/Bridges.jl

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,7 @@ function runtests(
256256
variable_start = 1.2,
257257
constraint_start = 1.2,
258258
eltype = Float64,
259+
print_inner_model::Bool = false,
259260
)
260261
# Load model and bridge it
261262
inner = MOI.Utilities.UniversalFallback(MOI.Utilities.Model{eltype}())
@@ -264,6 +265,9 @@ function runtests(
264265
final_touch(model)
265266
# Should be able to call final_touch multiple times.
266267
final_touch(model)
268+
if print_inner_model
269+
print(inner)
270+
end
267271
# Load a non-bridged input model, and check that getters are the same.
268272
test = MOI.Utilities.UniversalFallback(MOI.Utilities.Model{eltype}())
269273
MOI.Utilities.loadfromstring!(test, input)

src/Bridges/Constraint/Constraint.jl

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,9 @@ include("bridges/set_dot_scaling.jl")
6262
include("bridges/table.jl")
6363
include("bridges/vectorize.jl")
6464
include("bridges/zero_one.jl")
65+
include("bridges/sos1_to_milp.jl")
66+
include("bridges/sos2_to_milp.jl")
67+
include("bridges/indicator_to_milp.jl")
6568

6669
"""
6770
add_all_bridges(bridged_model, ::Type{T}) where {T}
@@ -142,6 +145,9 @@ function add_all_bridges(bridged_model, ::Type{T}) where {T}
142145
MOI.Bridges.add_bridge(bridged_model, ReifiedCountDistinctToMILPBridge{T})
143146
MOI.Bridges.add_bridge(bridged_model, CountGreaterThanToMILPBridge{T})
144147
MOI.Bridges.add_bridge(bridged_model, TableToMILPBridge{T})
148+
MOI.Bridges.add_bridge(bridged_model, SOS1ToMILPBridge{T})
149+
MOI.Bridges.add_bridge(bridged_model, SOS2ToMILPBridge{T})
150+
MOI.Bridges.add_bridge(bridged_model, IndicatorToMILPBridge{T})
145151
return
146152
end
147153

src/Bridges/Constraint/bridges/bin_packing.jl

Lines changed: 1 addition & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -194,43 +194,6 @@ end
194194

195195
MOI.Bridges.needs_final_touch(::BinPackingToMILPBridge) = true
196196

197-
# We use the bridge as the first argument to avoid type piracy of other methods.
198-
function _get_bounds(
199-
bridge::BinPackingToMILPBridge{T},
200-
model::MOI.ModelLike,
201-
bounds::Dict{MOI.VariableIndex,NTuple{2,T}},
202-
f::MOI.ScalarAffineFunction{T},
203-
) where {T}
204-
lb = ub = f.constant
205-
for term in f.terms
206-
ret = _get_bounds(bridge, model, bounds, term.variable)
207-
if ret === nothing
208-
return nothing
209-
end
210-
lb += term.coefficient * ret[1]
211-
ub += term.coefficient * ret[2]
212-
end
213-
return lb, ub
214-
end
215-
216-
# We use the bridge as the first argument to avoid type piracy of other methods.
217-
function _get_bounds(
218-
::BinPackingToMILPBridge{T},
219-
model::MOI.ModelLike,
220-
bounds::Dict{MOI.VariableIndex,NTuple{2,T}},
221-
x::MOI.VariableIndex,
222-
) where {T}
223-
if haskey(bounds, x)
224-
return bounds[x]
225-
end
226-
ret = MOI.Utilities.get_bounds(model, T, x)
227-
if ret == (typemin(T), typemax(T))
228-
return nothing
229-
end
230-
bounds[x] = ret
231-
return ret
232-
end
233-
234197
function MOI.Bridges.final_touch(
235198
bridge::BinPackingToMILPBridge{T,F},
236199
model::MOI.ModelLike,
@@ -240,7 +203,7 @@ function MOI.Bridges.final_touch(
240203
bounds = Dict{MOI.VariableIndex,NTuple{2,T}}()
241204
for i in 1:length(scalars)
242205
x = scalars[i]
243-
ret = _get_bounds(bridge, model, bounds, x)
206+
ret = MOI.Utilities.get_bounds(model, bounds, x)
244207
if ret === nothing
245208
error(
246209
"Unable to use $(typeof(bridge)) because an element in the " *

src/Bridges/Constraint/bridges/count_belongs.jl

Lines changed: 1 addition & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -189,41 +189,6 @@ end
189189

190190
MOI.Bridges.needs_final_touch(::CountBelongsToMILPBridge) = true
191191

192-
function _get_bounds(
193-
bridge::CountBelongsToMILPBridge{T},
194-
model::MOI.ModelLike,
195-
bounds::Dict{MOI.VariableIndex,Tuple{T,T}},
196-
f::MOI.ScalarAffineFunction{T},
197-
) where {T}
198-
lb = ub = f.constant
199-
for term in f.terms
200-
ret = _get_bounds(bridge, model, bounds, term.variable)
201-
if ret === nothing
202-
return nothing
203-
end
204-
lb += term.coefficient * ret[1]
205-
ub += term.coefficient * ret[2]
206-
end
207-
return lb, ub
208-
end
209-
210-
function _get_bounds(
211-
::CountBelongsToMILPBridge{T},
212-
model::MOI.ModelLike,
213-
bounds::Dict{MOI.VariableIndex,Tuple{T,T}},
214-
x::MOI.VariableIndex,
215-
) where {T}
216-
if haskey(bounds, x)
217-
return bounds[x]
218-
end
219-
ret = MOI.Utilities.get_bounds(model, T, x)
220-
if ret == (typemin(T), typemax(T))
221-
return nothing
222-
end
223-
bounds[x] = ret
224-
return ret
225-
end
226-
227192
"""
228193
_unit_expansion(
229194
::CountBelongsToMILPBridge{T},
@@ -243,7 +208,7 @@ function _unit_expansion(
243208
bounds = Dict{MOI.VariableIndex,Tuple{T,T}}()
244209
ci = MOI.ConstraintIndex{MOI.ScalarAffineFunction{T},MOI.EqualTo{T}}[]
245210
for i in 1:length(f)
246-
ret = _get_bounds(bridge, model, bounds, f[i])
211+
ret = MOI.Utilities.get_bounds(model, bounds, f[i])
247212
if ret === nothing
248213
BT = typeof(bridge)
249214
error(

src/Bridges/Constraint/bridges/count_distinct.jl

Lines changed: 1 addition & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -228,43 +228,6 @@ end
228228

229229
MOI.Bridges.needs_final_touch(::CountDistinctToMILPBridge) = true
230230

231-
# We use the bridge as the first argument to avoid type piracy of other methods.
232-
function _get_bounds(
233-
bridge::CountDistinctToMILPBridge{T},
234-
model::MOI.ModelLike,
235-
bounds::Dict{MOI.VariableIndex,NTuple{2,T}},
236-
f::MOI.ScalarAffineFunction{T},
237-
) where {T}
238-
lb = ub = f.constant
239-
for term in f.terms
240-
ret = _get_bounds(bridge, model, bounds, term.variable)
241-
if ret === nothing
242-
return nothing
243-
end
244-
lb += term.coefficient * ret[1]
245-
ub += term.coefficient * ret[2]
246-
end
247-
return lb, ub
248-
end
249-
250-
# We use the bridge as the first argument to avoid type piracy of other methods.
251-
function _get_bounds(
252-
::CountDistinctToMILPBridge{T},
253-
model::MOI.ModelLike,
254-
bounds::Dict{MOI.VariableIndex,NTuple{2,T}},
255-
x::MOI.VariableIndex,
256-
) where {T}
257-
if haskey(bounds, x)
258-
return bounds[x]
259-
end
260-
ret = MOI.Utilities.get_bounds(model, T, x)
261-
if ret == (typemin(T), typemax(T))
262-
return nothing
263-
end
264-
bounds[x] = ret
265-
return ret
266-
end
267-
268231
function MOI.Bridges.final_touch(
269232
bridge::CountDistinctToMILPBridge{T,F},
270233
model::MOI.ModelLike,
@@ -274,7 +237,7 @@ function MOI.Bridges.final_touch(
274237
bounds = Dict{MOI.VariableIndex,NTuple{2,T}}()
275238
for i in 2:length(scalars)
276239
x = scalars[i]
277-
ret = _get_bounds(bridge, model, bounds, x)
240+
ret = MOI.Utilities.get_bounds(model, bounds, x)
278241
if ret === nothing
279242
error(
280243
"Unable to use CountDistinctToMILPBridge because element $i " *

src/Bridges/Constraint/bridges/count_distinct_reif.jl

Lines changed: 1 addition & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -246,43 +246,6 @@ end
246246

247247
MOI.Bridges.needs_final_touch(::ReifiedCountDistinctToMILPBridge) = true
248248

249-
# We use the bridge as the first argument to avoid type piracy of other methods.
250-
function _get_bounds(
251-
bridge::ReifiedCountDistinctToMILPBridge{T},
252-
model::MOI.ModelLike,
253-
bounds::Dict{MOI.VariableIndex,NTuple{2,T}},
254-
f::MOI.ScalarAffineFunction{T},
255-
) where {T}
256-
lb = ub = f.constant
257-
for term in f.terms
258-
ret = _get_bounds(bridge, model, bounds, term.variable)
259-
if ret === nothing
260-
return nothing
261-
end
262-
lb += term.coefficient * ret[1]
263-
ub += term.coefficient * ret[2]
264-
end
265-
return lb, ub
266-
end
267-
268-
# We use the bridge as the first argument to avoid type piracy of other methods.
269-
function _get_bounds(
270-
::ReifiedCountDistinctToMILPBridge{T},
271-
model::MOI.ModelLike,
272-
bounds::Dict{MOI.VariableIndex,NTuple{2,T}},
273-
x::MOI.VariableIndex,
274-
) where {T}
275-
if haskey(bounds, x)
276-
return bounds[x]
277-
end
278-
ret = MOI.Utilities.get_bounds(model, T, x)
279-
if ret == (typemin(T), typemax(T))
280-
return nothing
281-
end
282-
bounds[x] = ret
283-
return ret
284-
end
285-
286249
function MOI.Bridges.final_touch(
287250
bridge::ReifiedCountDistinctToMILPBridge{T,F},
288251
model::MOI.ModelLike,
@@ -292,7 +255,7 @@ function MOI.Bridges.final_touch(
292255
bounds = Dict{MOI.VariableIndex,NTuple{2,T}}()
293256
for i in 3:length(scalars)
294257
x = scalars[i]
295-
ret = _get_bounds(bridge, model, bounds, x)
258+
ret = MOI.Utilities.get_bounds(model, bounds, x)
296259
if ret === nothing
297260
error(
298261
"Unable to use ReifiedCountDistinctToMILPBridge because " *

src/Bridges/Constraint/bridges/count_greater_than.jl

Lines changed: 1 addition & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -182,43 +182,6 @@ end
182182

183183
MOI.Bridges.needs_final_touch(::CountGreaterThanToMILPBridge) = true
184184

185-
# We use the bridge as the first argument to avoid type piracy of other methods.
186-
function _get_bounds(
187-
bridge::CountGreaterThanToMILPBridge{T},
188-
model::MOI.ModelLike,
189-
bounds::Dict{MOI.VariableIndex,NTuple{2,T}},
190-
f::MOI.ScalarAffineFunction{T},
191-
) where {T}
192-
lb = ub = f.constant
193-
for term in f.terms
194-
ret = _get_bounds(bridge, model, bounds, term.variable)
195-
if ret === nothing
196-
return nothing
197-
end
198-
lb += term.coefficient * ret[1]
199-
ub += term.coefficient * ret[2]
200-
end
201-
return lb, ub
202-
end
203-
204-
# We use the bridge as the first argument to avoid type piracy of other methods.
205-
function _get_bounds(
206-
::CountGreaterThanToMILPBridge{T},
207-
model::MOI.ModelLike,
208-
bounds::Dict{MOI.VariableIndex,NTuple{2,T}},
209-
x::MOI.VariableIndex,
210-
) where {T}
211-
if haskey(bounds, x)
212-
return bounds[x]
213-
end
214-
ret = MOI.Utilities.get_bounds(model, T, x)
215-
if ret == (typemin(T), typemax(T))
216-
return nothing
217-
end
218-
bounds[x] = ret
219-
return ret
220-
end
221-
222185
function _add_unit_expansion(
223186
bridge::CountGreaterThanToMILPBridge{T,F},
224187
model::MOI.ModelLike,
@@ -227,7 +190,7 @@ function _add_unit_expansion(
227190
x,
228191
i,
229192
) where {T,F}
230-
ret = _get_bounds(bridge, model, bounds, x)
193+
ret = MOI.Utilities.get_bounds(model, bounds, x)
231194
if ret === nothing
232195
error(
233196
"Unable to use $(typeof(bridge)) because an element in the " *

0 commit comments

Comments
 (0)