Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Bridges] add {SOS1,SOS2,Indicator}ToMILPBridge #2318

Merged
merged 11 commits into from
Oct 29, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@
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 @@
final_touch(model)
# Should be able to call final_touch multiple times.
final_touch(model)
if print_inner_model
print(inner)

Check warning on line 269 in src/Bridges/Bridges.jl

View check run for this annotation

Codecov / codecov/patch

src/Bridges/Bridges.jl#L269

Added line #L269 was not covered by tests
odow marked this conversation as resolved.
Show resolved Hide resolved
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
Loading