Skip to content

Commit

Permalink
[Bridges] add {SOS1,SOS2,Indicator}ToMILPBridge (#2318)
Browse files Browse the repository at this point in the history
  • Loading branch information
odow authored Oct 29, 2023
1 parent acab995 commit cab3440
Show file tree
Hide file tree
Showing 17 changed files with 1,507 additions and 224 deletions.
3 changes: 3 additions & 0 deletions docs/src/submodules/Bridges/list_of_bridges.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,9 @@ Bridges.Constraint.CountDistinctToMILPBridge
Bridges.Constraint.ReifiedCountDistinctToMILPBridge
Bridges.Constraint.CountGreaterThanToMILPBridge
Bridges.Constraint.TableToMILPBridge
Bridges.Constraint.SOS1ToMILPBridge
Bridges.Constraint.SOS2ToMILPBridge
Bridges.Constraint.IndicatorToMILPBridge
```

## [Objective bridges](@id objective_bridges_ref)
Expand Down
4 changes: 4 additions & 0 deletions src/Bridges/Bridges.jl
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,7 @@ function runtests(
variable_start = 1.2,
constraint_start = 1.2,
eltype = Float64,
print_inner_model::Bool = false,
)
# Load model and bridge it
inner = MOI.Utilities.UniversalFallback(MOI.Utilities.Model{eltype}())
Expand All @@ -264,6 +265,9 @@ function runtests(
final_touch(model)
# Should be able to call final_touch multiple times.
final_touch(model)
if print_inner_model
print(inner)
end
# Load a non-bridged input model, and check that getters are the same.
test = MOI.Utilities.UniversalFallback(MOI.Utilities.Model{eltype}())
MOI.Utilities.loadfromstring!(test, input)
Expand Down
6 changes: 6 additions & 0 deletions src/Bridges/Constraint/Constraint.jl
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,9 @@ include("bridges/set_dot_scaling.jl")
include("bridges/table.jl")
include("bridges/vectorize.jl")
include("bridges/zero_one.jl")
include("bridges/sos1_to_milp.jl")
include("bridges/sos2_to_milp.jl")
include("bridges/indicator_to_milp.jl")

"""
add_all_bridges(bridged_model, ::Type{T}) where {T}
Expand Down Expand Up @@ -142,6 +145,9 @@ function add_all_bridges(bridged_model, ::Type{T}) where {T}
MOI.Bridges.add_bridge(bridged_model, ReifiedCountDistinctToMILPBridge{T})
MOI.Bridges.add_bridge(bridged_model, CountGreaterThanToMILPBridge{T})
MOI.Bridges.add_bridge(bridged_model, TableToMILPBridge{T})
MOI.Bridges.add_bridge(bridged_model, SOS1ToMILPBridge{T})
MOI.Bridges.add_bridge(bridged_model, SOS2ToMILPBridge{T})
MOI.Bridges.add_bridge(bridged_model, IndicatorToMILPBridge{T})
return
end

Expand Down
39 changes: 1 addition & 38 deletions src/Bridges/Constraint/bridges/bin_packing.jl
Original file line number Diff line number Diff line change
Expand Up @@ -194,43 +194,6 @@ end

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

# We use the bridge as the first argument to avoid type piracy of other methods.
function _get_bounds(
bridge::BinPackingToMILPBridge{T},
model::MOI.ModelLike,
bounds::Dict{MOI.VariableIndex,NTuple{2,T}},
f::MOI.ScalarAffineFunction{T},
) where {T}
lb = ub = f.constant
for term in f.terms
ret = _get_bounds(bridge, model, bounds, term.variable)
if ret === nothing
return nothing
end
lb += term.coefficient * ret[1]
ub += term.coefficient * ret[2]
end
return lb, ub
end

# We use the bridge as the first argument to avoid type piracy of other methods.
function _get_bounds(
::BinPackingToMILPBridge{T},
model::MOI.ModelLike,
bounds::Dict{MOI.VariableIndex,NTuple{2,T}},
x::MOI.VariableIndex,
) where {T}
if haskey(bounds, x)
return bounds[x]
end
ret = MOI.Utilities.get_bounds(model, T, x)
if ret == (typemin(T), typemax(T))
return nothing
end
bounds[x] = ret
return ret
end

function MOI.Bridges.final_touch(
bridge::BinPackingToMILPBridge{T,F},
model::MOI.ModelLike,
Expand All @@ -240,7 +203,7 @@ function MOI.Bridges.final_touch(
bounds = Dict{MOI.VariableIndex,NTuple{2,T}}()
for i in 1:length(scalars)
x = scalars[i]
ret = _get_bounds(bridge, model, bounds, x)
ret = MOI.Utilities.get_bounds(model, bounds, x)
if ret === nothing
error(
"Unable to use $(typeof(bridge)) because an element in the " *
Expand Down
37 changes: 1 addition & 36 deletions src/Bridges/Constraint/bridges/count_belongs.jl
Original file line number Diff line number Diff line change
Expand Up @@ -189,41 +189,6 @@ end

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

function _get_bounds(
bridge::CountBelongsToMILPBridge{T},
model::MOI.ModelLike,
bounds::Dict{MOI.VariableIndex,Tuple{T,T}},
f::MOI.ScalarAffineFunction{T},
) where {T}
lb = ub = f.constant
for term in f.terms
ret = _get_bounds(bridge, model, bounds, term.variable)
if ret === nothing
return nothing
end
lb += term.coefficient * ret[1]
ub += term.coefficient * ret[2]
end
return lb, ub
end

function _get_bounds(
::CountBelongsToMILPBridge{T},
model::MOI.ModelLike,
bounds::Dict{MOI.VariableIndex,Tuple{T,T}},
x::MOI.VariableIndex,
) where {T}
if haskey(bounds, x)
return bounds[x]
end
ret = MOI.Utilities.get_bounds(model, T, x)
if ret == (typemin(T), typemax(T))
return nothing
end
bounds[x] = ret
return ret
end

"""
_unit_expansion(
::CountBelongsToMILPBridge{T},
Expand All @@ -243,7 +208,7 @@ function _unit_expansion(
bounds = Dict{MOI.VariableIndex,Tuple{T,T}}()
ci = MOI.ConstraintIndex{MOI.ScalarAffineFunction{T},MOI.EqualTo{T}}[]
for i in 1:length(f)
ret = _get_bounds(bridge, model, bounds, f[i])
ret = MOI.Utilities.get_bounds(model, bounds, f[i])
if ret === nothing
BT = typeof(bridge)
error(
Expand Down
39 changes: 1 addition & 38 deletions src/Bridges/Constraint/bridges/count_distinct.jl
Original file line number Diff line number Diff line change
Expand Up @@ -228,43 +228,6 @@ end

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

# We use the bridge as the first argument to avoid type piracy of other methods.
function _get_bounds(
bridge::CountDistinctToMILPBridge{T},
model::MOI.ModelLike,
bounds::Dict{MOI.VariableIndex,NTuple{2,T}},
f::MOI.ScalarAffineFunction{T},
) where {T}
lb = ub = f.constant
for term in f.terms
ret = _get_bounds(bridge, model, bounds, term.variable)
if ret === nothing
return nothing
end
lb += term.coefficient * ret[1]
ub += term.coefficient * ret[2]
end
return lb, ub
end

# We use the bridge as the first argument to avoid type piracy of other methods.
function _get_bounds(
::CountDistinctToMILPBridge{T},
model::MOI.ModelLike,
bounds::Dict{MOI.VariableIndex,NTuple{2,T}},
x::MOI.VariableIndex,
) where {T}
if haskey(bounds, x)
return bounds[x]
end
ret = MOI.Utilities.get_bounds(model, T, x)
if ret == (typemin(T), typemax(T))
return nothing
end
bounds[x] = ret
return ret
end

function MOI.Bridges.final_touch(
bridge::CountDistinctToMILPBridge{T,F},
model::MOI.ModelLike,
Expand All @@ -274,7 +237,7 @@ function MOI.Bridges.final_touch(
bounds = Dict{MOI.VariableIndex,NTuple{2,T}}()
for i in 2:length(scalars)
x = scalars[i]
ret = _get_bounds(bridge, model, bounds, x)
ret = MOI.Utilities.get_bounds(model, bounds, x)
if ret === nothing
error(
"Unable to use CountDistinctToMILPBridge because element $i " *
Expand Down
39 changes: 1 addition & 38 deletions src/Bridges/Constraint/bridges/count_distinct_reif.jl
Original file line number Diff line number Diff line change
Expand Up @@ -246,43 +246,6 @@ end

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

# We use the bridge as the first argument to avoid type piracy of other methods.
function _get_bounds(
bridge::ReifiedCountDistinctToMILPBridge{T},
model::MOI.ModelLike,
bounds::Dict{MOI.VariableIndex,NTuple{2,T}},
f::MOI.ScalarAffineFunction{T},
) where {T}
lb = ub = f.constant
for term in f.terms
ret = _get_bounds(bridge, model, bounds, term.variable)
if ret === nothing
return nothing
end
lb += term.coefficient * ret[1]
ub += term.coefficient * ret[2]
end
return lb, ub
end

# We use the bridge as the first argument to avoid type piracy of other methods.
function _get_bounds(
::ReifiedCountDistinctToMILPBridge{T},
model::MOI.ModelLike,
bounds::Dict{MOI.VariableIndex,NTuple{2,T}},
x::MOI.VariableIndex,
) where {T}
if haskey(bounds, x)
return bounds[x]
end
ret = MOI.Utilities.get_bounds(model, T, x)
if ret == (typemin(T), typemax(T))
return nothing
end
bounds[x] = ret
return ret
end

function MOI.Bridges.final_touch(
bridge::ReifiedCountDistinctToMILPBridge{T,F},
model::MOI.ModelLike,
Expand All @@ -292,7 +255,7 @@ function MOI.Bridges.final_touch(
bounds = Dict{MOI.VariableIndex,NTuple{2,T}}()
for i in 3:length(scalars)
x = scalars[i]
ret = _get_bounds(bridge, model, bounds, x)
ret = MOI.Utilities.get_bounds(model, bounds, x)
if ret === nothing
error(
"Unable to use ReifiedCountDistinctToMILPBridge because " *
Expand Down
39 changes: 1 addition & 38 deletions src/Bridges/Constraint/bridges/count_greater_than.jl
Original file line number Diff line number Diff line change
Expand Up @@ -182,43 +182,6 @@ end

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

# We use the bridge as the first argument to avoid type piracy of other methods.
function _get_bounds(
bridge::CountGreaterThanToMILPBridge{T},
model::MOI.ModelLike,
bounds::Dict{MOI.VariableIndex,NTuple{2,T}},
f::MOI.ScalarAffineFunction{T},
) where {T}
lb = ub = f.constant
for term in f.terms
ret = _get_bounds(bridge, model, bounds, term.variable)
if ret === nothing
return nothing
end
lb += term.coefficient * ret[1]
ub += term.coefficient * ret[2]
end
return lb, ub
end

# We use the bridge as the first argument to avoid type piracy of other methods.
function _get_bounds(
::CountGreaterThanToMILPBridge{T},
model::MOI.ModelLike,
bounds::Dict{MOI.VariableIndex,NTuple{2,T}},
x::MOI.VariableIndex,
) where {T}
if haskey(bounds, x)
return bounds[x]
end
ret = MOI.Utilities.get_bounds(model, T, x)
if ret == (typemin(T), typemax(T))
return nothing
end
bounds[x] = ret
return ret
end

function _add_unit_expansion(
bridge::CountGreaterThanToMILPBridge{T,F},
model::MOI.ModelLike,
Expand All @@ -227,7 +190,7 @@ function _add_unit_expansion(
x,
i,
) where {T,F}
ret = _get_bounds(bridge, model, bounds, x)
ret = MOI.Utilities.get_bounds(model, bounds, x)
if ret === nothing
error(
"Unable to use $(typeof(bridge)) because an element in the " *
Expand Down
Loading

0 comments on commit cab3440

Please sign in to comment.