-
Notifications
You must be signed in to change notification settings - Fork 92
indicator to SOS bridge #877
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
Merged
Merged
Changes from all commits
Commits
Show all changes
40 commits
Select commit
Hold shift + click to select a range
7506209
indicator to SOS bridge
matbesancon bf829d9
fix type signatures
matbesancon f4a32ef
register bridge
matbesancon 11f5032
added tests
matbesancon b2be67d
ignore benchmarks
matbesancon 62ae22b
remove equalto constraint
matbesancon 94665e7
remove ambiguity
matbesancon 23fd06b
file reformatting
matbesancon 3e54c05
split files
matbesancon 32e2493
Merge branch 'master' into indicator-sos
matbesancon fc3102d
revisions
matbesancon 4fd52d6
remove redundant constraint from bridge
matbesancon c5b0b2f
add single bridge
matbesancon 2946115
convert to VariableIndex
matbesancon 3a6a676
add intermediate expression
matbesancon 32d7baa
replace VAF with abstract vector function
matbesancon cb78e29
fix VAF
matbesancon de49ca4
Merge branch 'master' into indicator-sos
matbesancon 89ff760
Merge branch 'master' into indicator-sos
matbesancon c753d2f
added get for set and func
matbesancon 91a4c0a
remove log
matbesancon 6813017
Merge branch 'master' into indicator-sos
matbesancon 2cf8729
added delete
matbesancon 8995b14
test model equals
matbesancon 08fc80f
does not need adding binary
matbesancon e35ffd1
failing delete test
matbesancon 7a8cd2f
add get for bridge
matbesancon f7c2e85
add primal start
matbesancon a01b091
add supports
matbesancon 2fb4b59
added get tests
matbesancon 3603585
more tests
matbesancon 007e23e
fix test types
matbesancon 970d801
added test for mock bridged
matbesancon 7938dd5
use attr
matbesancon 4d4a8f0
replace attr with N
matbesancon 9a7aaca
variable attr propagation
matbesancon dbe41e2
remove ConstraintPrimal
matbesancon 0c8ad66
reset test VariablePrimal
matbesancon ec89295
replace rebuilt attribute with attr to propage result number
matbesancon 5d3ab8c
no primal start N
matbesancon File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,3 +4,4 @@ | |
docs/build/ | ||
docs/site/ | ||
Manifest.toml | ||
test/Benchmarks/*.json |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,183 @@ | ||
""" | ||
IndicatorSOS1Bridge{T, BC <: MOI.AbstractScalarSet} | ||
|
||
The `IndicatorSOS1Bridge` replaces an indicator constraint of the following form: | ||
``z \\in \\mathbb{B}, z == 1 \\implies f(x) \\leq b`` with a SOS1 constraint: | ||
``z \\in \\mathbb{B}, w \\leq 0, f(x) + w \\leq b, SOS1(w, z)``. | ||
`GreaterThan` constraints are handled in a symmetric way: | ||
``z \\in \\mathbb{B}, z == 1 \\implies f(x) \\geq b`` is reformulated as: | ||
``z \\in \\mathbb{B}, w \\geq 0, f(x) + w \\geq b, SOS1(w, z)``. | ||
Other scalar sets are handled without a bound constraint: | ||
``z \\in \\mathbb{B}, z == 1 \\implies f(x) == b`` is reformulated as: | ||
``z \\in \\mathbb{B}, w \\text{ free}, f(x) + w == b, SOS1(w, z)``. | ||
|
||
If `BC !<: Union{LessThan, GreaterThan}`, `bound_constraint_index` is `nothing`. | ||
""" | ||
struct IndicatorSOS1Bridge{T, BC <: MOI.AbstractScalarSet, MaybeBC <: Union{MOI.ConstraintIndex{MOI.SingleVariable, BC}, Nothing}} <: AbstractBridge | ||
w_variable_index::MOI.VariableIndex | ||
z_variable_index::MOI.VariableIndex | ||
affine_func::MOI.ScalarAffineFunction{T} | ||
bound_constraint_index::MaybeBC | ||
sos_constraint_index::MOI.ConstraintIndex{MOI.VectorOfVariables, MOI.SOS1{T}} | ||
linear_constraint_index::MOI.ConstraintIndex{MOI.ScalarAffineFunction{T}, BC} | ||
end | ||
|
||
function bridge_constraint(::Type{IndicatorSOS1Bridge{T,BC,MaybeBC}}, model::MOI.ModelLike, f::MOI.VectorAffineFunction{T}, s::MOI.IndicatorSet{MOI.ACTIVATE_ON_ONE, BC}) where {T <: Real, BC, MaybeBC} | ||
f_scalars = MOIU.eachscalar(f) | ||
(w, bound_constraint) = _add_bound_constraint!(model, BC) | ||
z = convert(MOI.SingleVariable, f_scalars[1]).variable | ||
sos_vector = MOI.VectorOfVariables([w, z]) | ||
sos_constraint = MOI.add_constraint(model, sos_vector, MOI.SOS1{T}([0.4, 0.6])) | ||
affine_func = f_scalars[2] | ||
affine_expr = MOIU.operate(+, T, affine_func, MOI.SingleVariable(w)) | ||
linear_constraint = MOI.add_constraint(model, affine_expr, s.set) | ||
return IndicatorSOS1Bridge{T,BC,MaybeBC}(w, z, affine_func, bound_constraint, sos_constraint, linear_constraint) | ||
end | ||
|
||
function _add_bound_constraint!(model::MOI.ModelLike, ::Type{BC}) where {T <: Real, BC <: Union{MOI.LessThan{T}, MOI.GreaterThan{T}}} | ||
return MOI.add_constrained_variable(model, BC(zero(T))) | ||
end | ||
|
||
function _add_bound_constraint!(model::MOI.ModelLike, ::Type{<:MOI.AbstractScalarSet}) | ||
return (MOI.add_variable(model), nothing) | ||
end | ||
|
||
function MOI.supports_constraint(::Type{<:IndicatorSOS1Bridge}, | ||
::Type{<:MOI.AbstractVectorFunction}, | ||
::Type{<:MOI.IndicatorSet{MOI.ACTIVATE_ON_ONE, <:MOI.AbstractScalarSet}}) | ||
return true | ||
end | ||
|
||
function MOI.get(model::MOI.ModelLike, attr::MOI.ConstraintSet, | ||
b::IndicatorSOS1Bridge) | ||
return MOI.IndicatorSet{MOI.ACTIVATE_ON_ONE}( | ||
MOI.get(model, attr, b.linear_constraint_index), | ||
) | ||
end | ||
|
||
function MOI.get(model::MOI.ModelLike, attr::MOI.ConstraintFunction, | ||
b::IndicatorSOS1Bridge{T}) where {T} | ||
z = b.z_variable_index | ||
terms = [MOI.VectorAffineTerm(1, MOI.ScalarAffineTerm(one(T), z))] | ||
for affine_term in b.affine_func.terms | ||
push!(terms, MOI.VectorAffineTerm(2, affine_term)) | ||
end | ||
return MOI.VectorAffineFunction( | ||
terms, [zero(T), b.affine_func.constant] | ||
) | ||
end | ||
|
||
function MOI.delete(model::MOI.ModelLike, bridge::IndicatorSOS1Bridge) | ||
if bridge.bound_constraint_index !== nothing | ||
MOI.delete(model, bridge.bound_constraint_index) | ||
end | ||
MOI.delete(model, bridge.sos_constraint_index) | ||
MOI.delete(model, bridge.linear_constraint_index) | ||
MOI.delete(model, bridge.w_variable_index) | ||
return | ||
end | ||
|
||
function MOIB.added_constrained_variable_types(::Type{<:IndicatorSOS1Bridge{T, BC}}) where {T, BC <: Union{MOI.LessThan{T}, MOI.GreaterThan{T}}} | ||
return [(BC,)] | ||
end | ||
|
||
function MOIB.added_constrained_variable_types(::Type{<:IndicatorSOS1Bridge{T, BC}}) where {T, BC} | ||
return [] | ||
end | ||
|
||
function MOIB.added_constraint_types(::Type{<:IndicatorSOS1Bridge{T, BC}}) where {T, BC <: Union{MOI.LessThan{T}, MOI.GreaterThan{T}}} | ||
return [(MOI.VectorOfVariables, MOI.SOS1{T}), | ||
(MOI.ScalarAffineFunction{T}, BC), | ||
] | ||
end | ||
|
||
function MOIB.added_constraint_types(::Type{<:IndicatorSOS1Bridge{T, S}}) where {T, S <: MOI.AbstractScalarSet} | ||
return [(MOI.VectorOfVariables, MOI.SOS1{T}), | ||
(MOI.ScalarAffineFunction{T}, S), | ||
] | ||
end | ||
|
||
function concrete_bridge_type(::Type{<:IndicatorSOS1Bridge{T}}, | ||
::Type{<:MOI.AbstractVectorFunction}, | ||
::Type{MOI.IndicatorSet{MOI.ACTIVATE_ON_ONE, S}}) where {T, S<:Union{MOI.LessThan, MOI.GreaterThan}} | ||
return IndicatorSOS1Bridge{T, S, MOI.ConstraintIndex{MOI.SingleVariable, S}} | ||
end | ||
|
||
function concrete_bridge_type(::Type{<:IndicatorSOS1Bridge{T}}, | ||
::Type{<:MOI.AbstractVectorFunction}, | ||
::Type{MOI.IndicatorSet{MOI.ACTIVATE_ON_ONE, S}}) where {T, S <: MOI.AbstractScalarSet} | ||
return IndicatorSOS1Bridge{T, S, Nothing} | ||
end | ||
|
||
# Attributes, Bridge acting as a model | ||
|
||
function MOI.get(::IndicatorSOS1Bridge, ::MOI.NumberOfVariables) | ||
return 1 | ||
end | ||
|
||
function MOI.get(b::IndicatorSOS1Bridge, ::MOI.ListOfVariableIndices) | ||
return [b.w_variable_index] | ||
end | ||
|
||
function MOI.get(::IndicatorSOS1Bridge{T, BC, Nothing}, ::MOI.NumberOfConstraints{MOI.SingleVariable, BC}) where {T, BC} | ||
return 0 | ||
end | ||
|
||
function MOI.get(::IndicatorSOS1Bridge{T, BC, CI}, ::MOI.NumberOfConstraints{MOI.SingleVariable, BC}) where {T, BC, CI <: MOI.ConstraintIndex{MOI.SingleVariable, BC}} | ||
return 1 | ||
end | ||
|
||
function MOI.get(::IndicatorSOS1Bridge, ::MOI.NumberOfConstraints{MOI.VectorOfVariables, <:MOI.SOS1}) | ||
return 1 | ||
end | ||
|
||
function MOI.get(::IndicatorSOS1Bridge{T, BC}, ::MOI.NumberOfConstraints{MOI.ScalarAffineFunction{T}, BC}) where {T, BC, CI <: MOI.ConstraintIndex{MOI.SingleVariable, BC}} | ||
return 1 | ||
end | ||
|
||
function MOI.get(b::IndicatorSOS1Bridge{T, BC, CI}, ::MOI.ListOfConstraintIndices{MOI.SingleVariable, BC}) where {T, BC, CI <: MOI.ConstraintIndex} | ||
return [b.bound_constraint_index] | ||
end | ||
|
||
function MOI.get(::IndicatorSOS1Bridge{T, BC, Nothing}, ::MOI.ListOfConstraintIndices{MOI.SingleVariable, BC}) where {T, BC} | ||
return MOI.ConstraintIndex{MOI.SingleVariable, BC}[] | ||
end | ||
|
||
function MOI.get(b::IndicatorSOS1Bridge{T}, ::MOI.ListOfConstraintIndices{MOI.VectorOfVariables, <:MOI.SOS1}) where {T} | ||
return [b.sos_constraint_index] | ||
end | ||
|
||
function MOI.get(b::IndicatorSOS1Bridge{T, BC}, ::MOI.ListOfConstraintIndices{MOI.ScalarAffineFunction{T}, BC}) where {T, BC} | ||
return [b.linear_constraint_index] | ||
end | ||
|
||
function MOI.supports( | ||
::MOI.ModelLike, | ||
::MOI.ConstraintPrimalStart, | ||
::Type{<:IndicatorSOS1Bridge}) | ||
return true | ||
end | ||
|
||
function MOI.get(model::MOI.ModelLike, attr::MOI.ConstraintPrimal, bridge::IndicatorSOS1Bridge) | ||
zvalue = MOI.get(model, MOI.VariablePrimal(attr.N), bridge.z_variable_index) | ||
wvalue = MOI.get(model, MOI.VariablePrimal(attr.N), bridge.w_variable_index) | ||
lin_primal_start = MOI.get(model, attr, bridge.linear_constraint_index) | ||
return [zvalue, lin_primal_start - wvalue] | ||
end | ||
|
||
function MOI.get(model::MOI.ModelLike, attr::MOI.ConstraintPrimalStart, bridge::IndicatorSOS1Bridge) | ||
zstart = MOI.get(model, MOI.VariablePrimalStart(), bridge.z_variable_index) | ||
wstart = MOI.get(model, MOI.VariablePrimalStart(), bridge.w_variable_index) | ||
lin_primal_start = MOI.get(model, attr, bridge.linear_constraint_index) | ||
return [zstart, lin_primal_start - wstart] | ||
end | ||
|
||
function MOI.set(model::MOI.ModelLike, attr::MOI.ConstraintPrimalStart, | ||
bridge::IndicatorSOS1Bridge{T}, value) where {T} | ||
zvalue = value[1] | ||
lin_start = value[2] | ||
MOI.set(model, MOI.VariablePrimalStart(), bridge.z_variable_index, zvalue) | ||
wstart = MOI.get(model, MOI.VariablePrimalStart(), bridge.w_variable_index) | ||
wstart = wstart === nothing ? zero(T) : wstart | ||
MOI.set(model, attr, bridge.linear_constraint_index, lin_start + wstart) | ||
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.