From dc0c420a085bc749b9e3d0e07657b96d91d71c79 Mon Sep 17 00:00:00 2001 From: joaquimg Date: Fri, 7 Dec 2018 00:14:32 -0200 Subject: [PATCH 01/21] add slack bridge file --- src/Bridges/slackbridge.jl | 71 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 src/Bridges/slackbridge.jl diff --git a/src/Bridges/slackbridge.jl b/src/Bridges/slackbridge.jl new file mode 100644 index 0000000000..3ce6e43bbe --- /dev/null +++ b/src/Bridges/slackbridge.jl @@ -0,0 +1,71 @@ +""" + SlackBridge{T} + +The `SplackBridge` converts a constraint ``Function in Set`` where `F` is a function different + from `SingleVariable` and to `VectorOfVariables` into the constraints ``F + F2 in Zeros`` of ``F + F2 in EqualTo{T}`` + and ``F2 in Set\``. +""" +struct ScalarSlackBridge{T, F<:MOI.AbstractScalarFunction, S<:MOI.AbstractScalarSet} <: AbstractBridge + slack::MOI.VariableIndex + slack_in_set::CI{MOI.SingleVariable, S} + equality::CI{F, MOI.EqualTo{T}} +end +function ScalarSlackBridge{T, F, S}(model, f::F, s::S) where {T, F<:MOI.ScalarAffineFunction{T}, S<:MOI.AbstractScalarSet} + slack = MOI.add_variable(model) + new_f = copy(f) + push!(new_f.terms, MOI.ScalarAffineTerm{T}(-one(T), slack)) + slack_in_set = MOI.add_constraint(model, SingleVariable(slack), s) + equality = MOI.add_constraint(model, new_f, MOI.EqualTo(0.0)) + return ScalarSlackBridge{T, F, S}(slack, equality, slack_in_set) +end + +MOI.supports_constraint(::Type{ScalarSlackBridge{T, F, S}}, ::Type{<:MOI.AbstractScalarFunction}, ::Type{MOI.Interval{T}}) where T = true +MOI.supports_constraint(::Type{ScalarSlackBridge{T, F, S}}, ::Type{<:MOI.AbstractScalarFunction}, ::Type{MOI.GreaterThan{T}}) where T = true +MOI.supports_constraint(::Type{ScalarSlackBridge{T, F, S}}, ::Type{<:MOI.AbstractScalarFunction}, ::Type{MOI.LessThan{T}}) where T = true +function added_constraint_types(::Type{ScalarSlackBridge{T, F, S}}) where {T, F<:MOI.AbstractScalarFunction, S} + return [(F, MOI.EqualTo{T}), (MOI.SingleVariable, S)] +end +function concrete_bridge_type(::Type{<:ScalarSlackBridge}, + F::Type{<:MOI.AbstractScalarFunction}, + S::Type{<:MOI.AbstractScalarSet}) where T + return ScalarSlackBridge{T, F, S} +end + +# Attributes, Bridge acting as an model +MOI.get(b::ScalarSlackBridge{T, F, S}, ::MOI.NumberOfConstraints{F, MOI.EqualTo{T}}) where {T, F<:MOI.ScalarAffineFunction{T}, S} = 1 +MOI.get(b::ScalarSlackBridge{T, F, S}, ::MOI.NumberOfConstraints{MOI.SingleVariable, S}) where {T, F<:MOI.ScalarAffineFunction{T}, S} = 1 +MOI.get(b::ScalarSlackBridge{T, F, S}, ::MOI.ListOfConstraintIndices{F, MOI.EqualTo{T}}) where {T, F<:MOI.ScalarAffineFunction{T}, S} = [b.equality] +MOI.get(b::ScalarSlackBridge{T, F, S}, ::MOI.ListOfConstraintIndices{MOI.SingleVariable, S}) where {T, F<:MOI.ScalarAffineFunction{T}, S} = [b.slack_in_set] + +# Indices +function MOI.delete(model::MOI.ModelLike, c::ScalarSlackBridge) + MOI.delete(model, c.equality) + MOI.delete(model, c.slack_in_set) + MOI.delete(model, c.slack) + return +end + +# Attributes, Bridge acting as a constraint +function MOI.get(model::MOI.ModelLike, attr::MOI.ConstraintPrimal, c::ScalarSlackBridge) + # ldue to equality, slack should have the same value as original affine function + return MOI.get(model, attr, c.slack_in_set) +end +function MOI.get(model::MOI.ModelLike, a::MOI.ConstraintDual, c::ScalarSlackBridge) + error("") +end + +# Constraints +function MOI.modify(model::MOI.ModelLike, c::ScalarSlackBridge, change::MOI.AbstractFunctionModification) + MOI.modify(model, c.equality, change) +end + +function MOI.set(model::MOI.ModelLike, ::MOI.ConstraintFunction, + c::ScalarSlackBridge{T, F, S}, func::F) where {T, F, S} + new_func = copy(func) + push!(new_func.terms, MOI.ScalarAffineTerm{T}(-one(T), c.slack)) + MOI.set(model, MOI.ConstraintFunction(), c.equality, new_func) +end + +function MOI.set(model::MOI.ModelLike, ::MOI.ConstraintSet, c::ScalarSlackBridge, change::MOI.Interval) + MOI.set(model, MOI.ConstraintSet(), c.slack_in_set, change) +end From b35e15f0c537ee2ac12a8005d7bfad1c04929b0c Mon Sep 17 00:00:00 2001 From: joaquimgarcia_psr Date: Thu, 27 Dec 2018 20:14:30 -0200 Subject: [PATCH 02/21] fixes for slack bridge --- src/Bridges/slackbridge.jl | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/src/Bridges/slackbridge.jl b/src/Bridges/slackbridge.jl index 3ce6e43bbe..ea8a579174 100644 --- a/src/Bridges/slackbridge.jl +++ b/src/Bridges/slackbridge.jl @@ -1,33 +1,32 @@ + +const ScalarSlackSet{T} = Union{MOI.Interval{T}, MOI.GreaterThan{T}, MOI.LessThan{T}} + """ - SlackBridge{T} + ScalarSlackBridge{T, F, S} -The `SplackBridge` converts a constraint ``Function in Set`` where `F` is a function different - from `SingleVariable` and to `VectorOfVariables` into the constraints ``F + F2 in Zeros`` of ``F + F2 in EqualTo{T}`` - and ``F2 in Set\``. +The `ScalarSlackBridge` converts a constraint `F`-in-`S` where `F` is a function different + from `SingleVariable` into the constraints ``F in EqualTo{T}`` and `SingleVariable`-in-`S`. """ -struct ScalarSlackBridge{T, F<:MOI.AbstractScalarFunction, S<:MOI.AbstractScalarSet} <: AbstractBridge +struct ScalarSlackBridge{T, F<:MOI.AbstractScalarFunction, S<:ScalarSlackSet{T}} <: AbstractBridge slack::MOI.VariableIndex slack_in_set::CI{MOI.SingleVariable, S} equality::CI{F, MOI.EqualTo{T}} end -function ScalarSlackBridge{T, F, S}(model, f::F, s::S) where {T, F<:MOI.ScalarAffineFunction{T}, S<:MOI.AbstractScalarSet} +function ScalarSlackBridge{T, F, S}(model, f::F, s::S) where {T, F<:MOI.ScalarAffineFunction{T}, S<:ScalarSlackSet{T}} slack = MOI.add_variable(model) - new_f = copy(f) - push!(new_f.terms, MOI.ScalarAffineTerm{T}(-one(T), slack)) + new_f = MOIU.operate(-, T, f, slack) slack_in_set = MOI.add_constraint(model, SingleVariable(slack), s) equality = MOI.add_constraint(model, new_f, MOI.EqualTo(0.0)) return ScalarSlackBridge{T, F, S}(slack, equality, slack_in_set) end -MOI.supports_constraint(::Type{ScalarSlackBridge{T, F, S}}, ::Type{<:MOI.AbstractScalarFunction}, ::Type{MOI.Interval{T}}) where T = true -MOI.supports_constraint(::Type{ScalarSlackBridge{T, F, S}}, ::Type{<:MOI.AbstractScalarFunction}, ::Type{MOI.GreaterThan{T}}) where T = true -MOI.supports_constraint(::Type{ScalarSlackBridge{T, F, S}}, ::Type{<:MOI.AbstractScalarFunction}, ::Type{MOI.LessThan{T}}) where T = true +MOI.supports_constraint(::Type{ScalarSlackBridge{T, F, S}}, ::Type{<:MOI.AbstractScalarFunction}, ::Type{<:ScalarSlackSet{T}}) where {T, F, S} = true function added_constraint_types(::Type{ScalarSlackBridge{T, F, S}}) where {T, F<:MOI.AbstractScalarFunction, S} return [(F, MOI.EqualTo{T}), (MOI.SingleVariable, S)] end function concrete_bridge_type(::Type{<:ScalarSlackBridge}, F::Type{<:MOI.AbstractScalarFunction}, - S::Type{<:MOI.AbstractScalarSet}) where T + S::Type{<:ScalarSlackSet{T}}) where T return ScalarSlackBridge{T, F, S} end @@ -47,11 +46,11 @@ end # Attributes, Bridge acting as a constraint function MOI.get(model::MOI.ModelLike, attr::MOI.ConstraintPrimal, c::ScalarSlackBridge) - # ldue to equality, slack should have the same value as original affine function + # due to equality, slack should have the same value as original affine function return MOI.get(model, attr, c.slack_in_set) end function MOI.get(model::MOI.ModelLike, a::MOI.ConstraintDual, c::ScalarSlackBridge) - error("") + error("ScalarSlackBridge is not returning duals for now") end # Constraints @@ -61,8 +60,7 @@ end function MOI.set(model::MOI.ModelLike, ::MOI.ConstraintFunction, c::ScalarSlackBridge{T, F, S}, func::F) where {T, F, S} - new_func = copy(func) - push!(new_func.terms, MOI.ScalarAffineTerm{T}(-one(T), c.slack)) + new_func = MOIU.operate(-, T, func, c.slack) MOI.set(model, MOI.ConstraintFunction(), c.equality, new_func) end From 89be811a9f53c30e895209988415c52222ac80db Mon Sep 17 00:00:00 2001 From: joaquimgarcia_psr Date: Thu, 27 Dec 2018 20:14:50 -0200 Subject: [PATCH 03/21] Add slack to main file --- src/Bridges/Bridges.jl | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Bridges/Bridges.jl b/src/Bridges/Bridges.jl index c22a5822ef..667c3b3091 100644 --- a/src/Bridges/Bridges.jl +++ b/src/Bridges/Bridges.jl @@ -45,6 +45,7 @@ function full_bridge_optimizer(model::MOI.ModelLike, ::Type{T}) where T cache = MOIU.UniversalFallback(AllBridgedConstraints{T}()) bridgedmodel = MOIB.LazyBridgeOptimizer(model, cache) add_bridge(bridgedmodel, MOIB.VectorizeBridge{T}) + # add_bridge(bridgedmodel, MOIB.ScalarSlackBridge{T}) add_bridge(bridgedmodel, MOIB.SplitIntervalBridge{T}) add_bridge(bridgedmodel, MOIB.QuadtoSOCBridge{T}) add_bridge(bridgedmodel, MOIB.GeoMeanBridge{T}) @@ -59,6 +60,8 @@ end include("vectorizebridge.jl") @bridge Vectorize VectorizeBridge () (MOI.EqualTo, MOI.LessThan, MOI.GreaterThan,) () () (MOI.SingleVariable,) (MOI.ScalarAffineFunction, MOI.ScalarQuadraticFunction) () () +include("slackbridge.jl") +@bridge ScalarSlack ScalarSlackBridge () (MOI.Interval, MOI.LessThan, MOI.GreaterThan) () () () (MOI.ScalarAffineFunction, MOI.ScalarQuadraticFunction) () () include("intervalbridge.jl") @bridge SplitInterval SplitIntervalBridge () (MOI.Interval,) () () (MOI.SingleVariable,) (MOI.ScalarAffineFunction, MOI.ScalarQuadraticFunction) () () include("rsocbridge.jl") From f319839064864dec3c140aab71f7436dcdfa1a54 Mon Sep 17 00:00:00 2001 From: joaquimg Date: Thu, 27 Dec 2018 21:32:42 -0200 Subject: [PATCH 04/21] add to full b opt --- src/Bridges/Bridges.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Bridges/Bridges.jl b/src/Bridges/Bridges.jl index 667c3b3091..a52baa782f 100644 --- a/src/Bridges/Bridges.jl +++ b/src/Bridges/Bridges.jl @@ -45,7 +45,7 @@ function full_bridge_optimizer(model::MOI.ModelLike, ::Type{T}) where T cache = MOIU.UniversalFallback(AllBridgedConstraints{T}()) bridgedmodel = MOIB.LazyBridgeOptimizer(model, cache) add_bridge(bridgedmodel, MOIB.VectorizeBridge{T}) - # add_bridge(bridgedmodel, MOIB.ScalarSlackBridge{T}) + add_bridge(bridgedmodel, MOIB.ScalarSlackBridge{T}) add_bridge(bridgedmodel, MOIB.SplitIntervalBridge{T}) add_bridge(bridgedmodel, MOIB.QuadtoSOCBridge{T}) add_bridge(bridgedmodel, MOIB.GeoMeanBridge{T}) From edc720a0f98292990a8dd2b4a5a2959503dd8850 Mon Sep 17 00:00:00 2001 From: joaquimg Date: Thu, 27 Dec 2018 21:33:08 -0200 Subject: [PATCH 05/21] list acceptes function --- src/Bridges/slackbridge.jl | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/src/Bridges/slackbridge.jl b/src/Bridges/slackbridge.jl index ea8a579174..b0cc596282 100644 --- a/src/Bridges/slackbridge.jl +++ b/src/Bridges/slackbridge.jl @@ -1,5 +1,6 @@ const ScalarSlackSet{T} = Union{MOI.Interval{T}, MOI.GreaterThan{T}, MOI.LessThan{T}} +const NonSingleVariable{T} = Union{MOI.ScalarAffineFunction{T}, MOI.ScalarQuadraticFunction{T}} """ ScalarSlackBridge{T, F, S} @@ -7,34 +8,34 @@ const ScalarSlackSet{T} = Union{MOI.Interval{T}, MOI.GreaterThan{T}, MOI.LessTha The `ScalarSlackBridge` converts a constraint `F`-in-`S` where `F` is a function different from `SingleVariable` into the constraints ``F in EqualTo{T}`` and `SingleVariable`-in-`S`. """ -struct ScalarSlackBridge{T, F<:MOI.AbstractScalarFunction, S<:ScalarSlackSet{T}} <: AbstractBridge +struct ScalarSlackBridge{T, F<:NonSingleVariable{T}, S<:ScalarSlackSet{T}} <: AbstractBridge slack::MOI.VariableIndex slack_in_set::CI{MOI.SingleVariable, S} equality::CI{F, MOI.EqualTo{T}} end -function ScalarSlackBridge{T, F, S}(model, f::F, s::S) where {T, F<:MOI.ScalarAffineFunction{T}, S<:ScalarSlackSet{T}} +function ScalarSlackBridge{T, F, S}(model, f::F, s::S) where {T, F<:NonSingleVariable{T}, S<:ScalarSlackSet{T}} slack = MOI.add_variable(model) - new_f = MOIU.operate(-, T, f, slack) - slack_in_set = MOI.add_constraint(model, SingleVariable(slack), s) + new_f = MOIU.operate(-, T, f, MOI.SingleVariable(slack)) + slack_in_set = MOI.add_constraint(model, MOI.SingleVariable(slack), s) equality = MOI.add_constraint(model, new_f, MOI.EqualTo(0.0)) - return ScalarSlackBridge{T, F, S}(slack, equality, slack_in_set) + return ScalarSlackBridge{T, F, S}(slack, slack_in_set, equality) end -MOI.supports_constraint(::Type{ScalarSlackBridge{T, F, S}}, ::Type{<:MOI.AbstractScalarFunction}, ::Type{<:ScalarSlackSet{T}}) where {T, F, S} = true -function added_constraint_types(::Type{ScalarSlackBridge{T, F, S}}) where {T, F<:MOI.AbstractScalarFunction, S} +MOI.supports_constraint(::Type{ScalarSlackBridge{T, F, S}}, ::Type{<:NonSingleVariable{T}}, ::Type{<:ScalarSlackSet{T}}) where {T, F, S} = true +function added_constraint_types(::Type{ScalarSlackBridge{T, F, S}}) where {T, F<:NonSingleVariable{T}, S} return [(F, MOI.EqualTo{T}), (MOI.SingleVariable, S)] end function concrete_bridge_type(::Type{<:ScalarSlackBridge}, - F::Type{<:MOI.AbstractScalarFunction}, + F::Type{<:NonSingleVariable{T}}, S::Type{<:ScalarSlackSet{T}}) where T return ScalarSlackBridge{T, F, S} end # Attributes, Bridge acting as an model -MOI.get(b::ScalarSlackBridge{T, F, S}, ::MOI.NumberOfConstraints{F, MOI.EqualTo{T}}) where {T, F<:MOI.ScalarAffineFunction{T}, S} = 1 -MOI.get(b::ScalarSlackBridge{T, F, S}, ::MOI.NumberOfConstraints{MOI.SingleVariable, S}) where {T, F<:MOI.ScalarAffineFunction{T}, S} = 1 -MOI.get(b::ScalarSlackBridge{T, F, S}, ::MOI.ListOfConstraintIndices{F, MOI.EqualTo{T}}) where {T, F<:MOI.ScalarAffineFunction{T}, S} = [b.equality] -MOI.get(b::ScalarSlackBridge{T, F, S}, ::MOI.ListOfConstraintIndices{MOI.SingleVariable, S}) where {T, F<:MOI.ScalarAffineFunction{T}, S} = [b.slack_in_set] +MOI.get(b::ScalarSlackBridge{T, F, S}, ::MOI.NumberOfConstraints{F, MOI.EqualTo{T}}) where {T, F<:NonSingleVariable{T}, S} = 1 +MOI.get(b::ScalarSlackBridge{T, F, S}, ::MOI.NumberOfConstraints{MOI.SingleVariable, S}) where {T, F<:NonSingleVariable{T}, S} = 1 +MOI.get(b::ScalarSlackBridge{T, F, S}, ::MOI.ListOfConstraintIndices{F, MOI.EqualTo{T}}) where {T, F<:NonSingleVariable{T}, S} = [b.equality] +MOI.get(b::ScalarSlackBridge{T, F, S}, ::MOI.ListOfConstraintIndices{MOI.SingleVariable, S}) where {T, F<:NonSingleVariable{T}, S} = [b.slack_in_set] # Indices function MOI.delete(model::MOI.ModelLike, c::ScalarSlackBridge) @@ -60,7 +61,7 @@ end function MOI.set(model::MOI.ModelLike, ::MOI.ConstraintFunction, c::ScalarSlackBridge{T, F, S}, func::F) where {T, F, S} - new_func = MOIU.operate(-, T, func, c.slack) + new_func = MOIU.operate(-, T, func, MOI.SingleVariable(c.slack)) MOI.set(model, MOI.ConstraintFunction(), c.equality, new_func) end From a90ed344117ff4fb567be17718a8c3b6dd3f6528 Mon Sep 17 00:00:00 2001 From: joaquimg Date: Thu, 27 Dec 2018 21:33:49 -0200 Subject: [PATCH 06/21] add basic bridge tests --- test/bridge.jl | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/test/bridge.jl b/test/bridge.jl index c8a484830d..1dfc924e3d 100644 --- a/test/bridge.jl +++ b/test/bridge.jl @@ -342,6 +342,27 @@ end test_delete_bridge(bridged_mock, ci, 2, ((MOI.ScalarAffineFunction{Float64}, MOI.GreaterThan{Float64}, 0), (MOI.ScalarAffineFunction{Float64}, MOI.LessThan{Float64}, 0))) end + @testset "Scalar slack" begin + bridgedmock = MOIB.ScalarSlack{Float64}(mock) + MOIT.basic_constraint_tests(bridgedmock, config, + include=[(F, S) for + F in [MOI.ScalarAffineFunction{Float64}, + MOI.ScalarQuadraticFunction{Float64}], + S in [MOI.GreaterThan{Float64}, + MOI.LessThan{Float64}] + ]) + end + @testset "Scalar slack then Interval" begin + bridgedmock = MOIB.ScalarSlack{Float64}(MOIB.SplitInterval{Float64}(mock)) + MOIT.basic_constraint_tests(bridgedmock, config, + include=[(F, S) for + F in [MOI.ScalarAffineFunction{Float64}, + MOI.ScalarQuadraticFunction{Float64}], + S in [MOI.Interval{Float64}, + MOI.GreaterThan{Float64}, + MOI.LessThan{Float64}] + ]) + end @testset "RSOC" begin bridged_mock = MOIB.RSOC{Float64}(mock) From 9defdeff2d2d68067857ec3fc3c4cdd35951825c Mon Sep 17 00:00:00 2001 From: joaquimg Date: Thu, 27 Dec 2018 22:25:13 -0200 Subject: [PATCH 07/21] add vector slack --- src/Bridges/Bridges.jl | 21 +++++++++++ src/Bridges/slackbridge.jl | 75 ++++++++++++++++++++++++++++++++++++++ test/bridge.jl | 14 ++++++- 3 files changed, 109 insertions(+), 1 deletion(-) diff --git a/src/Bridges/Bridges.jl b/src/Bridges/Bridges.jl index a52baa782f..e8880acb0a 100644 --- a/src/Bridges/Bridges.jl +++ b/src/Bridges/Bridges.jl @@ -46,6 +46,7 @@ function full_bridge_optimizer(model::MOI.ModelLike, ::Type{T}) where T bridgedmodel = MOIB.LazyBridgeOptimizer(model, cache) add_bridge(bridgedmodel, MOIB.VectorizeBridge{T}) add_bridge(bridgedmodel, MOIB.ScalarSlackBridge{T}) + add_bridge(bridgedmodel, MOIB.VectorSlackBridge{T}) add_bridge(bridgedmodel, MOIB.SplitIntervalBridge{T}) add_bridge(bridgedmodel, MOIB.QuadtoSOCBridge{T}) add_bridge(bridgedmodel, MOIB.GeoMeanBridge{T}) @@ -62,6 +63,26 @@ include("vectorizebridge.jl") @bridge Vectorize VectorizeBridge () (MOI.EqualTo, MOI.LessThan, MOI.GreaterThan,) () () (MOI.SingleVariable,) (MOI.ScalarAffineFunction, MOI.ScalarQuadraticFunction) () () include("slackbridge.jl") @bridge ScalarSlack ScalarSlackBridge () (MOI.Interval, MOI.LessThan, MOI.GreaterThan) () () () (MOI.ScalarAffineFunction, MOI.ScalarQuadraticFunction) () () +@bridge(VectorSlack, VectorSlackBridge, +(), +(), +(MOI.Zeros, +MOI.Nonnegatives, +MOI.Nonpositives, +MOI.SecondOrderCone, +MOI.RotatedSecondOrderCone, +MOI.GeometricMeanCone, +MOI.PositiveSemidefiniteConeSquare, +MOI.LogDetConeTriangle, +MOI.RootDetConeTriangle), +(), +(), +(), +(), +(MOI.VectorAffineFunction, +#MOI.VectorQuadraticFunction +) +) include("intervalbridge.jl") @bridge SplitInterval SplitIntervalBridge () (MOI.Interval,) () () (MOI.SingleVariable,) (MOI.ScalarAffineFunction, MOI.ScalarQuadraticFunction) () () include("rsocbridge.jl") diff --git a/src/Bridges/slackbridge.jl b/src/Bridges/slackbridge.jl index b0cc596282..56e0ce4b8d 100644 --- a/src/Bridges/slackbridge.jl +++ b/src/Bridges/slackbridge.jl @@ -1,3 +1,4 @@ +# scalar version const ScalarSlackSet{T} = Union{MOI.Interval{T}, MOI.GreaterThan{T}, MOI.LessThan{T}} const NonSingleVariable{T} = Union{MOI.ScalarAffineFunction{T}, MOI.ScalarQuadraticFunction{T}} @@ -68,3 +69,77 @@ end function MOI.set(model::MOI.ModelLike, ::MOI.ConstraintSet, c::ScalarSlackBridge, change::MOI.Interval) MOI.set(model, MOI.ConstraintSet(), c.slack_in_set, change) end + +# vector version + +# const MOI.AbstractVectorSet = Union{MOI.Interval{T}, MOI.GreaterThan{T}, MOI.LessThan{T}} +const NonVectorOfVariables{T} = Union{MOI.VectorAffineFunction{T}}#, MOI.VectorQuadraticFunction{T}} + +""" + VectorSlackBridge{T, F, S} + +The `VectorSlackBridge` converts a constraint `F`-in-`S` where `F` is a function different + from `VectorOfVariables` into the constraints ``F in Zeros`` and `VectorOfVariables`-in-`S`. +""" +struct VectorSlackBridge{T, F<:NonVectorOfVariables{T}, S<:MOI.AbstractVectorSet} <: AbstractBridge + slacks::Vector{MOI.VariableIndex} + slacks_in_set::CI{MOI.VectorOfVariables, S} + equality::CI{F, MOI.Zeros} +end +function VectorSlackBridge{T, F, S}(model, f::F, s::S) where {T, F<:NonVectorOfVariables{T}, S<:MOI.AbstractVectorSet} + d = MOI.dimension(s) + slacks = MOI.add_variables(model, d) + new_f = MOIU.operate(-, T, f, MOI.VectorAffineFunction{T}(MOI.VectorOfVariables(slacks))) + slacks_in_set = MOI.add_constraint(model, MOI.VectorOfVariables(slacks), s) + equality = MOI.add_constraint(model, new_f, MOI.Zeros) + return VectorSlackBridge{T, F, S}(slacks, slacks_in_set, equality) +end + +MOI.supports_constraint(::Type{VectorSlackBridge{T, F, S}}, ::Type{<:NonVectorOfVariables{T}}, ::Type{<:MOI.Zeros}) where {T, F, S} = false +MOI.supports_constraint(::Type{VectorSlackBridge{T, F, S}}, ::Type{<:NonVectorOfVariables{T}}, ::Type{<:MOI.AbstractVectorSet}) where {T, F, S} = true +function added_constraint_types(::Type{VectorSlackBridge{T, F, S}}) where {T, F<:NonVectorOfVariables{T}, S} + return [(F, MOI.Zeros), (MOI.VectorOfVariables, S)] +end +function concrete_bridge_type(::Type{<:VectorSlackBridge}, + F::Type{<:NonVectorOfVariables{T}}, + S::Type{<:MOI.AbstractVectorSet}) where T + return VectorSlackBridge{T, F, S} +end + +# Attributes, Bridge acting as an model +MOI.get(b::VectorSlackBridge{T, F, S}, ::MOI.NumberOfConstraints{F, MOI.Zeros}) where {T, F<:NonVectorOfVariables{T}, S} = 1 +MOI.get(b::VectorSlackBridge{T, F, S}, ::MOI.NumberOfConstraints{MOI.VectorOfVariables, S}) where {T, F<:NonVectorOfVariables{T}, S} = 1 +MOI.get(b::VectorSlackBridge{T, F, S}, ::MOI.ListOfConstraintIndices{F, MOI.Zeros}) where {T, F<:NonVectorOfVariables{T}, S} = [b.equality] +MOI.get(b::VectorSlackBridge{T, F, S}, ::MOI.ListOfConstraintIndices{MOI.VectorOfVariables, S}) where {T, F<:NonVectorOfVariables{T}, S} = [b.slacks_in_set] + +# Indices +function MOI.delete(model::MOI.ModelLike, c::VectorSlackBridge) + MOI.delete(model, c.equality) + MOI.delete(model, c.slacks_in_set) + MOI.delete(model, c.slacks) + return +end + +# Attributes, Bridge acting as a constraint +function MOI.get(model::MOI.ModelLike, attr::MOI.ConstraintPrimal, c::VectorSlackBridge) + # due to equality, slacks should have the same value as original affine function + return MOI.get(model, attr, c.slacks_in_set) +end +function MOI.get(model::MOI.ModelLike, a::MOI.ConstraintDual, c::VectorSlackBridge) + error("VectorSlackBridge is not returning duals for now") +end + +# Constraints +function MOI.modify(model::MOI.ModelLike, c::VectorSlackBridge, change::MOI.AbstractFunctionModification) + MOI.modify(model, c.equality, change) +end + +function MOI.set(model::MOI.ModelLike, ::MOI.ConstraintFunction, + c::VectorSlackBridge{T, F, S}, func::F) where {T, F, S} + new_func = MOIU.operate(-, T, func, MOI.VectorAffineFunction{T}(MOI.VectorOfVariables(c.slacks))) + MOI.set(model, MOI.ConstraintFunction(), c.equality, new_func) +end + +function MOI.set(model::MOI.ModelLike, ::MOI.ConstraintSet, c::VectorSlackBridge, change::MOI.Interval) + MOI.set(model, MOI.ConstraintSet(), c.slacks_in_set, change) +end diff --git a/test/bridge.jl b/test/bridge.jl index 1dfc924e3d..7888dea6f5 100644 --- a/test/bridge.jl +++ b/test/bridge.jl @@ -341,7 +341,7 @@ end @test MOI.get(bridged_mock, MOI.ConstraintFunction(), ci) ≈ newf test_delete_bridge(bridged_mock, ci, 2, ((MOI.ScalarAffineFunction{Float64}, MOI.GreaterThan{Float64}, 0), (MOI.ScalarAffineFunction{Float64}, MOI.LessThan{Float64}, 0))) - end + end @testset "Scalar slack" begin bridgedmock = MOIB.ScalarSlack{Float64}(mock) MOIT.basic_constraint_tests(bridgedmock, config, @@ -364,6 +364,18 @@ end ]) end + # @testset "Vector slack" begin + # bridgedmock = MOIB.VectorSlack{Float64}(mock) + # MOIT.basic_constraint_tests(bridgedmock, config, + # include=[(F, S) for + # F in [MOI.VectorAffineFunction{Float64}, + # #MOI.VectorQuadraticFunction{Float64} + # ], + # S in [MOI.Nonnegatives, + # MOI.Nonpositives] + # ]) + # end + @testset "RSOC" begin bridged_mock = MOIB.RSOC{Float64}(mock) mock.optimize! = (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [1/√2, 1/√2, 0.5, 1.0], From 861806e93b4763a0b4bf3d1dbb95e276101182c6 Mon Sep 17 00:00:00 2001 From: joaquimg Date: Fri, 28 Dec 2018 15:37:54 -0200 Subject: [PATCH 08/21] add operate methods for vector functions --- src/Utilities/functions.jl | 217 ++++++++++++++++++++++++++++++++++++- 1 file changed, 215 insertions(+), 2 deletions(-) diff --git a/src/Utilities/functions.jl b/src/Utilities/functions.jl index c8091464b4..d545e0f7a8 100644 --- a/src/Utilities/functions.jl +++ b/src/Utilities/functions.jl @@ -594,6 +594,12 @@ function operate_term(::typeof(-), term::MOI.ScalarQuadraticTerm) term.variable_index_1, term.variable_index_2) end +function operate_term(::typeof(-), term::MOI.VectorAffineTerm) + return MOI.VectorAffineTerm(term.output_index, operate_term(-, term.scalar_term)) +end +function operate_term(::typeof(-), term::MOI.VectorQuadraticTerm) + return MOI.VectorQuadraticTerm(term.output_index, operate_term(-, term.scalar_term)) +end function operate_term(::typeof(*), α::T, t::MOI.ScalarAffineTerm{T}) where T MOI.ScalarAffineTerm(α * t.coefficient, t.variable_index) @@ -607,10 +613,24 @@ function operate_term(::typeof(*), t1::MOI.ScalarAffineTerm, MOI.ScalarQuadraticTerm(t1.coefficient * t2.coefficient, t1.variable_index, t2.variable_index) end +function operate_term(::typeof(*), α::T, t::MOI.VectorAffineTerm{T}) where T + MOI.VectorAffineTerm(t.output_index, operate_term(*, α, t.scalar_term)) +end +function operate_term(::typeof(*), α::T, t::MOI.VectorQuadraticTerm{T}) where T + MOI.VectorQuadraticTerm(t.output_index, operate_term(*, α, t.scalar_term)) +end +function operate_term(::typeof(*), t1::MOI.VectorAffineTerm, + t2::MOI.VectorAffineTerm) + @assert t1.output_index == t2.output_index + MOI.VectorQuadraticTerm(t1.output_index, operate_term(*, t1.scalar_term, t2.scalar_term)) +end function operate_term(::typeof(/), t::MOI.ScalarAffineTerm{T}, α::T) where T MOI.ScalarAffineTerm(t.coefficient / α, t.variable_index) end +function operate_term(::typeof(/), t::MOI.VectorAffineTerm{T}, α::T) where T + MOI.VectorAffineTerm(t.output_index, operate_term(/, t.scalar_term, α)) +end # Avoid a copy in the case of + function operate_terms(::typeof(+), @@ -618,16 +638,26 @@ function operate_terms(::typeof(+), MOI.ScalarQuadraticTerm}}) return terms end +function operate_terms(::typeof(+), + terms::Vector{<:Union{MOI.VectorAffineTerm, + MOI.VectorQuadraticTerm}}) + return terms +end function operate_terms(::typeof(-), terms::Vector{<:Union{MOI.ScalarAffineTerm, MOI.ScalarQuadraticTerm}}) return map(term -> operate_term(-, term), terms) end +function operate_terms(::typeof(-), + terms::Vector{<:Union{MOI.VectorAffineTerm, + MOI.VectorQuadraticTerm}}) + return map(term -> operate_term(-, term), terms) +end -function map_terms!(op, func::MOI.ScalarAffineFunction) +function map_terms!(op, func::Union{MOI.ScalarAffineFunction, MOI.VectorAffineFunction}) map!(op, func.terms, func.terms) end -function map_terms!(op, func::MOI.ScalarQuadraticFunction) +function map_terms!(op, func::Union{MOI.ScalarQuadraticFunction, MOI.VectorQuadraticFunction}) map!(op, func.affine_terms, func.affine_terms) map!(op, func.quadratic_terms, func.quadratic_terms) end @@ -642,6 +672,16 @@ const ScalarQuadraticLike{T} = Union{ScalarAffineLike{T}, MOI.ScalarQuadraticFun const ScalarLike{T} = Union{MOI.SingleVariable, MOI.ScalarAffineFunction{T}, MOI.ScalarQuadraticFunction{T}} +# Functions convertible to a VectorAffineFunction +const VectorAffineLike{T} = Union{Vector{T}, MOI.VectorOfVariables, MOI.VectorAffineFunction{T}} +# Functions convertible to a VectorQuadraticFunction +const VectorQuadraticLike{T} = Union{VectorAffineLike{T}, MOI.VectorQuadraticFunction{T}} + +# Used for overloading Base operator functions so `T` is not in the union to +# avoid overloading e.g. `+(::Float64, ::Float64)` +const VectorLike{T} = Union{MOI.VectorOfVariables, MOI.VectorAffineFunction{T}, + MOI.VectorQuadraticFunction{T}} + ###################################### +/- ##################################### ## promote_operation function promote_operation(::Union{typeof(+), typeof(-)}, ::Type{T}, @@ -807,6 +847,179 @@ function Base.:-(α::T, f::ScalarLike{T}) where T return operate(-, T, α, f) end +# Vector +/- + +function promote_operation(::Union{typeof(+), typeof(-)}, ::Type{T}, + ::Type{<:VectorAffineLike{T}}, + ::Type{<:VectorAffineLike{T}}) where T + return MOI.VectorAffineFunction{T} +end +function promote_operation(::Union{typeof(+), typeof(-)}, ::Type{T}, + ::Type{<:VectorQuadraticLike{T}}, + ::Type{<:VectorQuadraticLike{T}}) where T + return MOI.VectorQuadraticFunction{T} +end + +# Vector Variable +/- ... +function operate!(op::Union{typeof(+), typeof(-)}, ::Type{T}, + f::MOI.VectorOfVariables, + g::VectorQuadraticLike) where T + return operate(op, T, f, g) +end +# Vector Affine +/-! ... +function operate!(op::Union{typeof(+), typeof(-)}, ::Type{T}, + f::MOI.VectorAffineFunction{T}, + g::Vector{T}) where T + @assert output_dimension(f) == length(g) + f.constant .= op.(f.constant, g) + return f +end +function operate!(op::Union{typeof(+), typeof(-)}, ::Type{T}, + f::MOI.VectorAffineFunction{T}, + g::MOI.VectorOfVariables) where T + d = output_dimension(g) + @assert output_dimension(f) == d + push!(f.terms, MOI.VectorAffineTerm.(collect(1:d), MOI.ScalarAffineTerm.(op(one(T)), g.variables))) + return f +end +function operate!(op::Union{typeof(+), typeof(-)}, ::Type{T}, + f::MOI.VectorAffineFunction{T}, + g::MOI.VectorAffineFunction{T}) where T + append!(f.terms, operate_terms(op, g.terms)) + f.constant .= op.(f.constants, g.constants) + return f +end +function operate!(op::Union{typeof(+), typeof(-)}, ::Type{T}, + f::MOI.VectorAffineFunction{T}, + g::MOI.VectorQuadraticFunction{T}) where T + return operate(op, T, f, g) +end +# Vector Quadratic +/-! ... +function operate!(op::Union{typeof(+), typeof(-)}, ::Type{T}, + f::MOI.VectorQuadraticFunction{T}, + g::Vector{T}) where T + @assert output_dimension(f) == length(g) + f.constant .= op.(f.constant, g) + return f +end +function operate!(op::Union{typeof(+), typeof(-)}, ::Type{T}, + f::MOI.VectorQuadraticFunction{T}, + g::MOI.VectorOfVariables) where T + d = output_dimension(g) + @assert output_dimension(f) == d + push!(f.affine_terms, MOI.VectorAffineTerm.(collect(1:d), MOI.ScalarAffineTerm.(op(one(T)), g.variables))) + return f +end +function operate!(op::Union{typeof(+), typeof(-)}, ::Type{T}, + f::MOI.VectorQuadraticFunction{T}, + g::MOI.VectorAffineFunction{T}) where T + append!(f.affine_terms, operate_terms(op, g.terms)) + f.constant .= op.(f.constants, g.constants) + return f +end +function operate!(op::Union{typeof(+), typeof(-)}, ::Type{T}, + f::MOI.VectorQuadraticFunction{T}, + g::MOI.VectorQuadraticFunction{T}) where T + append!(f.affine_terms, operate_terms(op, g.affine_terms)) + append!(f.quadratic_terms, operate_terms(op, g.quadratic_terms)) + f.constants .= op.(f.constants, g.constants) + return f +end + +## operate +# + with at least 3 arguments, can use in-place as the user cannot use +# intermediate results +# overload +# function operate(op::typeof(+), ::Type{T}, f, g, h, args...) where T +# return operate!(+, T, operate(+, T, f, g), h, args...) +# end + +# Vector number +/- ... +function operate(op::typeof(+), ::Type{T}, α::Vector{T}, f::VectorLike{T}) where T + return operate(op, T, f, α) +end +function operate(op::typeof(-), ::Type{T}, α::Vector{T}, f::VectorLike{T}) where T + return operate!(+, T, operate(-, T, f), α) +end + +# Vector Variable +/- ... +function operate(op::Union{typeof(+), typeof(-)}, ::Type{T}, + f::MOI.VectorOfVariables, α::Vector{T}) where T + d = output_dimension(f) + @assert length(α) == d + return MOI.VectorAffineFunction{T}( + [MOI.VectorAffineTerm.(collect(1:d), + MOI.ScalarAffineTerm.(one(T), f.variables))], + op.(α)) +end +function operate(op::Union{typeof(+), typeof(-)}, ::Type{T}, + f::MOI.VectorOfVariables, + g::MOI.VectorOfVariables) where T + d = output_dimension(f) + @assert output_dimension(g) == d + return MOI.VectorAffineFunction{T}([ + MOI.VectorAffineTerm.(collect(1:d), MOI.ScalarAffineTerm.(one(T), f.variables)), + MOI.VectorAffineTerm.(collect(1:d), MOI.ScalarAffineTerm.(op(one(T)), g.variables)) + ], + fill(zero(T),d)) +end +function operate(op::typeof(+), ::Type{T}, + f::MOI.VectorOfVariables, + g::Union{MOI.VectorAffineFunction{T}, + MOI.VectorQuadraticFunction{T}}) where T + return operate(op, T, g, f) +end +function operate(op::typeof(-), ::Type{T}, + f::MOI.VectorOfVariables, + g::Union{MOI.VectorAffineFunction{T}, + MOI.VectorQuadraticFunction{T}}) where T + return operate!(+, T, operate(-, T, g), f) +end +# Vector Affine +/- ... +function operate(op::Union{typeof(-)}, ::Type{T}, + f::MOI.VectorAffineFunction{T}) where T + return MOI.VectorAffineFunction(operate_terms(op, f.terms), + op.(f.constants)) +end +function operate(op::Union{typeof(+), typeof(-)}, ::Type{T}, + f::MOI.VectorAffineFunction{T}, + g::VectorAffineLike{T}) where T + return operate!(op, T, copy(f), g) +end +function operate(op::Union{typeof(+), typeof(-)}, ::Type{T}, + f::MOI.VectorAffineFunction{T}, + g::MOI.VectorQuadraticFunction{T}) where T + MOI.VectorQuadraticFunction([f.terms; operate_terms(op, g.affine_terms)], + operate_terms(op, g.quadratic_terms), + op.(f.constants, g.constants)) +end + +# Vector Quadratic +/- ... +function operate(op::Union{typeof(+), typeof(-)}, ::Type{T}, + f::MOI.VectorQuadraticFunction{T}, + g::VectorQuadraticLike{T}) where T + operate!(op, T, copy(f), g) +end + +function Base.:+(args::VectorLike{T}...) where T + return operate(+, T, args...) +end +function Base.:+(α::Vector{T}, f::VectorLike{T}...) where T + return operate(+, T, α, f...) +end +function Base.:+(f::VectorLike{T}, α::Vector{T}) where T + return operate(+, T, f, α) +end +function Base.:-(args::VectorLike{T}...) where T + return operate(-, T, args...) +end +function Base.:-(f::VectorLike{T}, α::Vector{T}) where T + return operate(-, T, f, α) +end +function Base.:-(α::Vector{T}, f::VectorLike{T}) where T + return operate(-, T, α, f) +end + ####################################### * ###################################### function promote_operation(::typeof(*), ::Type{T}, ::Type{T}, ::Type{<:Union{MOI.SingleVariable, From 8972a33c4538e9deed276106669e6b0b06da572d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Legat?= Date: Fri, 18 Jan 2019 15:28:05 +0100 Subject: [PATCH 09/21] =?UTF-8?q?=F0=9F=8E=A8=20Remove=20whitespace?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Utilities/functions.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Utilities/functions.jl b/src/Utilities/functions.jl index d545e0f7a8..e4043ff096 100644 --- a/src/Utilities/functions.jl +++ b/src/Utilities/functions.jl @@ -948,7 +948,7 @@ function operate(op::Union{typeof(+), typeof(-)}, ::Type{T}, d = output_dimension(f) @assert length(α) == d return MOI.VectorAffineFunction{T}( - [MOI.VectorAffineTerm.(collect(1:d), + [MOI.VectorAffineTerm.(collect(1:d), MOI.ScalarAffineTerm.(one(T), f.variables))], op.(α)) end From e17f9dbed58aee29b692d6c4b6d82890937c11e4 Mon Sep 17 00:00:00 2001 From: joaquimgarcia_psr Date: Fri, 18 Jan 2019 20:37:22 -0200 Subject: [PATCH 10/21] Fix bridges and add tests --- src/Bridges/Bridges.jl | 6 +-- src/Bridges/bridgeoptimizer.jl | 2 + src/Bridges/slackbridge.jl | 82 +++++++++++++++++----------- src/Utilities/functions.jl | 8 +-- test/bridge.jl | 98 ++++++++++++++++++++++++++-------- 5 files changed, 135 insertions(+), 61 deletions(-) diff --git a/src/Bridges/Bridges.jl b/src/Bridges/Bridges.jl index e8880acb0a..c7e5460877 100644 --- a/src/Bridges/Bridges.jl +++ b/src/Bridges/Bridges.jl @@ -66,8 +66,7 @@ include("slackbridge.jl") @bridge(VectorSlack, VectorSlackBridge, (), (), -(MOI.Zeros, -MOI.Nonnegatives, +(MOI.Nonnegatives, MOI.Nonpositives, MOI.SecondOrderCone, MOI.RotatedSecondOrderCone, @@ -80,8 +79,7 @@ MOI.RootDetConeTriangle), (), (), (MOI.VectorAffineFunction, -#MOI.VectorQuadraticFunction -) +MOI.VectorQuadraticFunction) ) include("intervalbridge.jl") @bridge SplitInterval SplitIntervalBridge () (MOI.Interval,) () () (MOI.SingleVariable,) (MOI.ScalarAffineFunction, MOI.ScalarQuadraticFunction) () () diff --git a/src/Bridges/bridgeoptimizer.jl b/src/Bridges/bridgeoptimizer.jl index 39aa630d07..95dcc57627 100644 --- a/src/Bridges/bridgeoptimizer.jl +++ b/src/Bridges/bridgeoptimizer.jl @@ -342,3 +342,5 @@ end # Variables MOI.add_variable(b::AbstractBridgeOptimizer) = MOI.add_variable(b.model) MOI.add_variables(b::AbstractBridgeOptimizer, n) = MOI.add_variables(b.model, n) + +# TODO add transform \ No newline at end of file diff --git a/src/Bridges/slackbridge.jl b/src/Bridges/slackbridge.jl index 56e0ce4b8d..fae417ac93 100644 --- a/src/Bridges/slackbridge.jl +++ b/src/Bridges/slackbridge.jl @@ -1,20 +1,17 @@ # scalar version -const ScalarSlackSet{T} = Union{MOI.Interval{T}, MOI.GreaterThan{T}, MOI.LessThan{T}} -const NonSingleVariable{T} = Union{MOI.ScalarAffineFunction{T}, MOI.ScalarQuadraticFunction{T}} - """ ScalarSlackBridge{T, F, S} The `ScalarSlackBridge` converts a constraint `F`-in-`S` where `F` is a function different from `SingleVariable` into the constraints ``F in EqualTo{T}`` and `SingleVariable`-in-`S`. """ -struct ScalarSlackBridge{T, F<:NonSingleVariable{T}, S<:ScalarSlackSet{T}} <: AbstractBridge +struct ScalarSlackBridge{T, F<:MOI.AbstractScalarFunction, S<:MOI.AbstractScalarSet} <: AbstractBridge slack::MOI.VariableIndex slack_in_set::CI{MOI.SingleVariable, S} equality::CI{F, MOI.EqualTo{T}} end -function ScalarSlackBridge{T, F, S}(model, f::F, s::S) where {T, F<:NonSingleVariable{T}, S<:ScalarSlackSet{T}} +function ScalarSlackBridge{T, F, S}(model, f::F, s::S) where {T, F<:MOI.AbstractScalarFunction, S<:MOI.AbstractScalarSet} slack = MOI.add_variable(model) new_f = MOIU.operate(-, T, f, MOI.SingleVariable(slack)) slack_in_set = MOI.add_constraint(model, MOI.SingleVariable(slack), s) @@ -22,21 +19,34 @@ function ScalarSlackBridge{T, F, S}(model, f::F, s::S) where {T, F<:NonSingleVar return ScalarSlackBridge{T, F, S}(slack, slack_in_set, equality) end -MOI.supports_constraint(::Type{ScalarSlackBridge{T, F, S}}, ::Type{<:NonSingleVariable{T}}, ::Type{<:ScalarSlackSet{T}}) where {T, F, S} = true -function added_constraint_types(::Type{ScalarSlackBridge{T, F, S}}) where {T, F<:NonSingleVariable{T}, S} +# start allowing everything (scalar) +MOI.supports_constraint(::Type{ScalarSlackBridge{T, F, S}}, + ::Type{<:MOI.AbstractScalarFunction}, + ::Type{<:MOI.AbstractScalarSet}) where {T, F, S} = true +# then restrict (careful with ambiguity) +MOI.supports_constraint(::Type{ScalarSlackBridge{T, F, S}}, + ::Type{<:MOI.SingleVariable}, + ::Type{<:MOI.EqualTo}) where {T, F, S} = false +MOI.supports_constraint(::Type{ScalarSlackBridge{T, F, S}}, + ::Type{<:MOI.SingleVariable}, + ::Type{<:MOI.AbstractScalarSet}) where {T, F, S} = false +MOI.supports_constraint(::Type{ScalarSlackBridge{T, F, S}}, + ::Type{<:MOI.AbstractScalarFunction}, + ::Type{<:MOI.EqualTo}) where {T, F, S} = false +function added_constraint_types(::Type{ScalarSlackBridge{T, F, S}}) where {T, F, S} return [(F, MOI.EqualTo{T}), (MOI.SingleVariable, S)] end -function concrete_bridge_type(::Type{<:ScalarSlackBridge}, - F::Type{<:NonSingleVariable{T}}, - S::Type{<:ScalarSlackSet{T}}) where T +function concrete_bridge_type(::Type{<:ScalarSlackBridge{T}}, + F::Type{<:MOI.AbstractScalarFunction}, + S::Type{<:MOI.AbstractScalarSet}) where T return ScalarSlackBridge{T, F, S} end # Attributes, Bridge acting as an model -MOI.get(b::ScalarSlackBridge{T, F, S}, ::MOI.NumberOfConstraints{F, MOI.EqualTo{T}}) where {T, F<:NonSingleVariable{T}, S} = 1 -MOI.get(b::ScalarSlackBridge{T, F, S}, ::MOI.NumberOfConstraints{MOI.SingleVariable, S}) where {T, F<:NonSingleVariable{T}, S} = 1 -MOI.get(b::ScalarSlackBridge{T, F, S}, ::MOI.ListOfConstraintIndices{F, MOI.EqualTo{T}}) where {T, F<:NonSingleVariable{T}, S} = [b.equality] -MOI.get(b::ScalarSlackBridge{T, F, S}, ::MOI.ListOfConstraintIndices{MOI.SingleVariable, S}) where {T, F<:NonSingleVariable{T}, S} = [b.slack_in_set] +MOI.get(b::ScalarSlackBridge{T, F, S}, ::MOI.NumberOfConstraints{F, MOI.EqualTo{T}}) where {T, F<:MOI.AbstractScalarFunction, S} = 1 +MOI.get(b::ScalarSlackBridge{T, F, S}, ::MOI.NumberOfConstraints{MOI.SingleVariable, S}) where {T, F<:MOI.AbstractScalarFunction, S} = 1 +MOI.get(b::ScalarSlackBridge{T, F, S}, ::MOI.ListOfConstraintIndices{F, MOI.EqualTo{T}}) where {T, F<:MOI.AbstractScalarFunction, S} = [b.equality] +MOI.get(b::ScalarSlackBridge{T, F, S}, ::MOI.ListOfConstraintIndices{MOI.SingleVariable, S}) where {T, F<:MOI.AbstractScalarFunction, S} = [b.slack_in_set] # Indices function MOI.delete(model::MOI.ModelLike, c::ScalarSlackBridge) @@ -66,51 +76,61 @@ function MOI.set(model::MOI.ModelLike, ::MOI.ConstraintFunction, MOI.set(model, MOI.ConstraintFunction(), c.equality, new_func) end -function MOI.set(model::MOI.ModelLike, ::MOI.ConstraintSet, c::ScalarSlackBridge, change::MOI.Interval) +function MOI.set(model::MOI.ModelLike, ::MOI.ConstraintSet, c::ScalarSlackBridge{T, F, S}, change::S) where {T, F, S} MOI.set(model, MOI.ConstraintSet(), c.slack_in_set, change) end # vector version -# const MOI.AbstractVectorSet = Union{MOI.Interval{T}, MOI.GreaterThan{T}, MOI.LessThan{T}} -const NonVectorOfVariables{T} = Union{MOI.VectorAffineFunction{T}}#, MOI.VectorQuadraticFunction{T}} - """ VectorSlackBridge{T, F, S} The `VectorSlackBridge` converts a constraint `F`-in-`S` where `F` is a function different from `VectorOfVariables` into the constraints ``F in Zeros`` and `VectorOfVariables`-in-`S`. """ -struct VectorSlackBridge{T, F<:NonVectorOfVariables{T}, S<:MOI.AbstractVectorSet} <: AbstractBridge +struct VectorSlackBridge{T, F<:MOI.AbstractVectorFunction, S<:MOI.AbstractVectorSet} <: AbstractBridge slacks::Vector{MOI.VariableIndex} slacks_in_set::CI{MOI.VectorOfVariables, S} equality::CI{F, MOI.Zeros} end -function VectorSlackBridge{T, F, S}(model, f::F, s::S) where {T, F<:NonVectorOfVariables{T}, S<:MOI.AbstractVectorSet} +function VectorSlackBridge{T, F, S}(model, f::F, s::S) where {T, F<:MOI.AbstractVectorFunction, S<:MOI.AbstractVectorSet} + if S <: MOI.Zeros + error("type no allowed") + end d = MOI.dimension(s) slacks = MOI.add_variables(model, d) new_f = MOIU.operate(-, T, f, MOI.VectorAffineFunction{T}(MOI.VectorOfVariables(slacks))) slacks_in_set = MOI.add_constraint(model, MOI.VectorOfVariables(slacks), s) - equality = MOI.add_constraint(model, new_f, MOI.Zeros) + equality = MOI.add_constraint(model, new_f, MOI.Zeros(d)) return VectorSlackBridge{T, F, S}(slacks, slacks_in_set, equality) end -MOI.supports_constraint(::Type{VectorSlackBridge{T, F, S}}, ::Type{<:NonVectorOfVariables{T}}, ::Type{<:MOI.Zeros}) where {T, F, S} = false -MOI.supports_constraint(::Type{VectorSlackBridge{T, F, S}}, ::Type{<:NonVectorOfVariables{T}}, ::Type{<:MOI.AbstractVectorSet}) where {T, F, S} = true -function added_constraint_types(::Type{VectorSlackBridge{T, F, S}}) where {T, F<:NonVectorOfVariables{T}, S} +MOI.supports_constraint(::Type{VectorSlackBridge{T, F, S}}, + ::Type{<:MOI.AbstractVectorFunction}, + ::Type{<:MOI.AbstractVectorSet}) where {T, F, S} = true +MOI.supports_constraint(::Type{VectorSlackBridge{T, F, S}}, + ::Type{<:MOI.VectorOfVariables}, + ::Type{<:MOI.Zeros}) where {T, F, S} = false +MOI.supports_constraint(::Type{VectorSlackBridge{T, F, S}}, + ::Type{<:MOI.AbstractVectorFunction}, + ::Type{<:MOI.Zeros}) where {T, F, S} = false +MOI.supports_constraint(::Type{VectorSlackBridge{T, F, S}}, + ::Type{<:MOI.VectorOfVariables}, + ::Type{<:MOI.AbstractVectorSet}) where {T, F, S} = false +function added_constraint_types(::Type{VectorSlackBridge{T, F, S}}) where {T, F<:MOI.AbstractVectorFunction, S} return [(F, MOI.Zeros), (MOI.VectorOfVariables, S)] end -function concrete_bridge_type(::Type{<:VectorSlackBridge}, - F::Type{<:NonVectorOfVariables{T}}, +function concrete_bridge_type(::Type{<:VectorSlackBridge{T}}, + F::Type{<:MOI.AbstractVectorFunction}, S::Type{<:MOI.AbstractVectorSet}) where T return VectorSlackBridge{T, F, S} end # Attributes, Bridge acting as an model -MOI.get(b::VectorSlackBridge{T, F, S}, ::MOI.NumberOfConstraints{F, MOI.Zeros}) where {T, F<:NonVectorOfVariables{T}, S} = 1 -MOI.get(b::VectorSlackBridge{T, F, S}, ::MOI.NumberOfConstraints{MOI.VectorOfVariables, S}) where {T, F<:NonVectorOfVariables{T}, S} = 1 -MOI.get(b::VectorSlackBridge{T, F, S}, ::MOI.ListOfConstraintIndices{F, MOI.Zeros}) where {T, F<:NonVectorOfVariables{T}, S} = [b.equality] -MOI.get(b::VectorSlackBridge{T, F, S}, ::MOI.ListOfConstraintIndices{MOI.VectorOfVariables, S}) where {T, F<:NonVectorOfVariables{T}, S} = [b.slacks_in_set] +MOI.get(b::VectorSlackBridge{T, F, S}, ::MOI.NumberOfConstraints{F, MOI.Zeros}) where {T, F<:MOI.AbstractVectorFunction, S} = 1 +MOI.get(b::VectorSlackBridge{T, F, S}, ::MOI.NumberOfConstraints{MOI.VectorOfVariables, S}) where {T, F<:MOI.AbstractVectorFunction, S} = 1 +MOI.get(b::VectorSlackBridge{T, F, S}, ::MOI.ListOfConstraintIndices{F, MOI.Zeros}) where {T, F<:MOI.AbstractVectorFunction, S} = [b.equality] +MOI.get(b::VectorSlackBridge{T, F, S}, ::MOI.ListOfConstraintIndices{MOI.VectorOfVariables, S}) where {T, F<:MOI.AbstractVectorFunction, S} = [b.slacks_in_set] # Indices function MOI.delete(model::MOI.ModelLike, c::VectorSlackBridge) @@ -140,6 +160,6 @@ function MOI.set(model::MOI.ModelLike, ::MOI.ConstraintFunction, MOI.set(model, MOI.ConstraintFunction(), c.equality, new_func) end -function MOI.set(model::MOI.ModelLike, ::MOI.ConstraintSet, c::VectorSlackBridge, change::MOI.Interval) +function MOI.set(model::MOI.ModelLike, ::MOI.ConstraintSet, c::VectorSlackBridge{T,F,S}, change::S) where {T, F, S} MOI.set(model, MOI.ConstraintSet(), c.slacks_in_set, change) end diff --git a/src/Utilities/functions.jl b/src/Utilities/functions.jl index e4043ff096..b7c51f7da9 100644 --- a/src/Utilities/functions.jl +++ b/src/Utilities/functions.jl @@ -871,7 +871,7 @@ function operate!(op::Union{typeof(+), typeof(-)}, ::Type{T}, f::MOI.VectorAffineFunction{T}, g::Vector{T}) where T @assert output_dimension(f) == length(g) - f.constant .= op.(f.constant, g) + f.constants .= op.(f.constants, g) return f end function operate!(op::Union{typeof(+), typeof(-)}, ::Type{T}, @@ -886,7 +886,7 @@ function operate!(op::Union{typeof(+), typeof(-)}, ::Type{T}, f::MOI.VectorAffineFunction{T}, g::MOI.VectorAffineFunction{T}) where T append!(f.terms, operate_terms(op, g.terms)) - f.constant .= op.(f.constants, g.constants) + f.constants .= op.(f.constants, g.constants) return f end function operate!(op::Union{typeof(+), typeof(-)}, ::Type{T}, @@ -899,7 +899,7 @@ function operate!(op::Union{typeof(+), typeof(-)}, ::Type{T}, f::MOI.VectorQuadraticFunction{T}, g::Vector{T}) where T @assert output_dimension(f) == length(g) - f.constant .= op.(f.constant, g) + f.constants .= op.(f.constants, g) return f end function operate!(op::Union{typeof(+), typeof(-)}, ::Type{T}, @@ -914,7 +914,7 @@ function operate!(op::Union{typeof(+), typeof(-)}, ::Type{T}, f::MOI.VectorQuadraticFunction{T}, g::MOI.VectorAffineFunction{T}) where T append!(f.affine_terms, operate_terms(op, g.terms)) - f.constant .= op.(f.constants, g.constants) + f.constants .= op.(f.constants, g.constants) return f end function operate!(op::Union{typeof(+), typeof(-)}, ::Type{T}, diff --git a/test/bridge.jl b/test/bridge.jl index 7888dea6f5..e3fb68f554 100644 --- a/test/bridge.jl +++ b/test/bridge.jl @@ -1,7 +1,7 @@ # Model not supporting Interval MOIU.@model(SimpleModel, (), - (MOI.EqualTo, MOI.GreaterThan, MOI.LessThan), + (MOI.EqualTo, MOI.GreaterThan, MOI.LessThan, MOI.Interval), (MOI.Zeros, MOI.Nonnegatives, MOI.Nonpositives, MOI.SecondOrderCone, MOI.RotatedSecondOrderCone, MOI.GeometricMeanCone, MOI.PositiveSemidefiniteConeTriangle, MOI.ExponentialCone), @@ -9,7 +9,7 @@ MOIU.@model(SimpleModel, (MOI.SingleVariable,), (MOI.ScalarAffineFunction, MOI.ScalarQuadraticFunction), (MOI.VectorOfVariables,), - (MOI.VectorAffineFunction,)) + (MOI.VectorAffineFunction, MOI.VectorQuadraticFunction)) function test_noc(bridged_mock, F, S, n) @test MOI.get(bridged_mock, MOI.NumberOfConstraints{F, S}()) == n @@ -344,6 +344,21 @@ end end @testset "Scalar slack" begin bridgedmock = MOIB.ScalarSlack{Float64}(mock) + x = MOI.add_variable(bridgedmock) + y = MOI.add_variable(bridgedmock) + f = MOI.ScalarAffineFunction(MOI.ScalarAffineTerm{Float64}.([1.0, 2.0], [x, y]), 0.0) + ci = MOI.add_constraint(bridgedmock, f, MOI.GreaterThan(0.0)) + @test MOI.get(bridgedmock, MOI.ConstraintFunction(), ci) ≈ f + newf = MOI.ScalarAffineFunction(MOI.ScalarAffineTerm{Float64}.([2.0, 1.0], [x, y]), 0.0) + MOI.set(bridgedmock, MOI.ConstraintFunction(), ci, newf) + @test MOI.get(bridgedmock, MOI.ConstraintFunction(), ci) ≈ newf + @test MOI.get(bridgedmock, MOI.ConstraintSet(), ci) == MOI.GreaterThan(0.0) + MOI.set(bridgedmock, MOI.ConstraintSet(), ci, MOI.GreaterThan(1.0)) + @test MOI.get(bridgedmock, MOI.ConstraintSet(), ci) == MOI.GreaterThan(1.0) + MOI.modify(bridgedmock, ci, MOI.ScalarConstantChange{Float64}(1.0)) + @test MOI.get(bridgedmock, MOI.ConstraintFunction(), ci) ≈ + MOI.ScalarAffineFunction(MOI.ScalarAffineTerm{Float64}.([2.0, 1.0], [x, y]), 1.0) + MOIT.basic_constraint_tests(bridgedmock, config, include=[(F, S) for F in [MOI.ScalarAffineFunction{Float64}, @@ -351,30 +366,69 @@ end S in [MOI.GreaterThan{Float64}, MOI.LessThan{Float64}] ]) + + # There are extra variables due to the bridge + MOIU.set_mock_optimize!(mock, + (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [1.0, 1.0, 2.0, 2.0]), + (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [0.5, 0.5, 1.0, 1.0])) + MOIT.linear11test(bridgedmock, MOIT.TestConfig(duals = false)) + loc = MOI.get(bridgedmock, MOI.ListOfConstraints()) + @test length(loc) == 2 + @test (MOI.ScalarAffineFunction{Float64}, MOI.LessThan{Float64}) in loc + @test (MOI.ScalarAffineFunction{Float64}, MOI.GreaterThan{Float64}) in loc + loc = MOI.get(mock, MOI.ListOfConstraints()) + @test length(loc) == 3 + @test (MOI.ScalarAffineFunction{Float64}, MOI.EqualTo{Float64}) in loc + @test (MOI.SingleVariable, MOI.LessThan{Float64}) in loc + @test (MOI.SingleVariable, MOI.GreaterThan{Float64}) in loc + # ci = first(MOI.get(bridgedmock, MOI.ListOfConstraintIndices{MOI.ScalarAffineFunction{Float64}, MOI.Interval{Float64}}())) + # newf = MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([1.0, -1.0], MOI.get(bridgedmock, MOI.ListOfVariableIndices())), 0.0) + # MOI.set(bridgedmock, MOI.ConstraintFunction(), ci, newf) + # @test MOI.get(bridgedmock, MOI.ConstraintFunction(), ci) ≈ newf + # deletion test wont work due to deleted variable + # test_delete_bridge(bridgedmock, ci, 2, ((MOI.ScalarAffineFunction{Float64}, MOI.GreaterThan{Float64}, 0), + # (MOI.ScalarAffineFunction{Float64}, MOI.LessThan{Float64}, 0))) end - @testset "Scalar slack then Interval" begin - bridgedmock = MOIB.ScalarSlack{Float64}(MOIB.SplitInterval{Float64}(mock)) + + @testset "Vector slack" begin + bridgedmock = MOIB.VectorSlack{Float64}(mock) + x = MOI.add_variable(bridgedmock) + y = MOI.add_variable(bridgedmock) + f = MOI.VectorAffineFunction(MOI.VectorAffineTerm.(1, MOI.ScalarAffineTerm.([1.0, 2.0], [x, y])), [0.0]) + ci = MOI.add_constraint(bridgedmock, f, MOI.Nonpositives(1)) + @test MOI.get(bridgedmock, MOI.ConstraintFunction(), ci) ≈ f + newf = MOI.VectorAffineFunction(MOI.VectorAffineTerm.(1, MOI.ScalarAffineTerm.([2.0, 1.0], [x, y])), [0.0]) + MOI.set(bridgedmock, MOI.ConstraintFunction(), ci, newf) + @test MOI.get(bridgedmock, MOI.ConstraintFunction(), ci) ≈ newf + @test MOI.get(bridgedmock, MOI.ConstraintSet(), ci) == MOI.Nonpositives(1) + MOI.modify(bridgedmock, ci, MOI.VectorConstantChange([1.0])) + @test MOI.get(bridgedmock, MOI.ConstraintFunction(), ci) ≈ + MOI.VectorAffineFunction(MOI.VectorAffineTerm.(1, MOI.ScalarAffineTerm.([2.0, 1.0], [x, y])), [1.0]) + MOIT.basic_constraint_tests(bridgedmock, config, include=[(F, S) for - F in [MOI.ScalarAffineFunction{Float64}, - MOI.ScalarQuadraticFunction{Float64}], - S in [MOI.Interval{Float64}, - MOI.GreaterThan{Float64}, - MOI.LessThan{Float64}] - ]) - end + F in [MOI.VectorAffineFunction{Float64}, + MOI.VectorQuadraticFunction{Float64}], + S in [MOI.Nonnegatives, + MOI.Nonpositives] + ]) - # @testset "Vector slack" begin - # bridgedmock = MOIB.VectorSlack{Float64}(mock) - # MOIT.basic_constraint_tests(bridgedmock, config, - # include=[(F, S) for - # F in [MOI.VectorAffineFunction{Float64}, - # #MOI.VectorQuadraticFunction{Float64} - # ], - # S in [MOI.Nonnegatives, - # MOI.Nonpositives] - # ]) - # end + # There are extra variables due to the bridge + MOIU.set_mock_optimize!(mock, + (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [0, 0, 0, 0]), + (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [100, 0, 100, 0]), + (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [100, -100, 100, -100])) + MOIT.linear7test(bridgedmock, config) + loc = MOI.get(bridgedmock, MOI.ListOfConstraints()) + @test length(loc) == 2 + @test (MOI.VectorAffineFunction{Float64}, MOI.Nonnegatives) in loc + @test (MOI.VectorAffineFunction{Float64}, MOI.Nonpositives) in loc + loc = MOI.get(mock, MOI.ListOfConstraints()) + @test length(loc) == 3 + @test (MOI.VectorAffineFunction{Float64}, MOI.Zeros) in loc + @test (MOI.VectorOfVariables, MOI.Nonnegatives) in loc + @test (MOI.VectorOfVariables, MOI.Nonpositives) in loc + end @testset "RSOC" begin bridged_mock = MOIB.RSOC{Float64}(mock) From 0880c9e179a6dc137998fc5f7f7925c99f13b185 Mon Sep 17 00:00:00 2001 From: joaquimgarcia_psr Date: Fri, 18 Jan 2019 21:06:34 -0200 Subject: [PATCH 11/21] remove debug check --- src/Bridges/slackbridge.jl | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/Bridges/slackbridge.jl b/src/Bridges/slackbridge.jl index fae417ac93..300a23290b 100644 --- a/src/Bridges/slackbridge.jl +++ b/src/Bridges/slackbridge.jl @@ -94,9 +94,6 @@ struct VectorSlackBridge{T, F<:MOI.AbstractVectorFunction, S<:MOI.AbstractVector equality::CI{F, MOI.Zeros} end function VectorSlackBridge{T, F, S}(model, f::F, s::S) where {T, F<:MOI.AbstractVectorFunction, S<:MOI.AbstractVectorSet} - if S <: MOI.Zeros - error("type no allowed") - end d = MOI.dimension(s) slacks = MOI.add_variables(model, d) new_f = MOIU.operate(-, T, f, MOI.VectorAffineFunction{T}(MOI.VectorOfVariables(slacks))) From dd32f7ab32b0a1f3b54fbadf9366c3f13faeac3a Mon Sep 17 00:00:00 2001 From: joaquimgarcia_psr Date: Sat, 19 Jan 2019 16:10:16 -0200 Subject: [PATCH 12/21] fixes and tests for operate --- src/Utilities/functions.jl | 50 ++++++++++++++++++++++------------ test/Utilities/functions.jl | 53 +++++++++++++++++++++++++++++++++++++ 2 files changed, 86 insertions(+), 17 deletions(-) diff --git a/src/Utilities/functions.jl b/src/Utilities/functions.jl index b7c51f7da9..46a9a7f051 100644 --- a/src/Utilities/functions.jl +++ b/src/Utilities/functions.jl @@ -684,6 +684,7 @@ const VectorLike{T} = Union{MOI.VectorOfVariables, MOI.VectorAffineFunction{T}, ###################################### +/- ##################################### ## promote_operation + function promote_operation(::Union{typeof(+), typeof(-)}, ::Type{T}, ::Type{<:ScalarAffineLike{T}}, ::Type{<:ScalarAffineLike{T}}) where T @@ -848,7 +849,10 @@ function Base.:-(α::T, f::ScalarLike{T}) where T end # Vector +/- - +function promote_operation(::Union{typeof(+), typeof(-)}, ::Type{T}, + ::Type{<:VectorAffineLike{T}}) where T +return MOI.VectorAffineFunction{T} +end function promote_operation(::Union{typeof(+), typeof(-)}, ::Type{T}, ::Type{<:VectorAffineLike{T}}, ::Type{<:VectorAffineLike{T}}) where T @@ -870,16 +874,16 @@ end function operate!(op::Union{typeof(+), typeof(-)}, ::Type{T}, f::MOI.VectorAffineFunction{T}, g::Vector{T}) where T - @assert output_dimension(f) == length(g) + @assert MOI.output_dimension(f) == length(g) f.constants .= op.(f.constants, g) return f end function operate!(op::Union{typeof(+), typeof(-)}, ::Type{T}, f::MOI.VectorAffineFunction{T}, g::MOI.VectorOfVariables) where T - d = output_dimension(g) - @assert output_dimension(f) == d - push!(f.terms, MOI.VectorAffineTerm.(collect(1:d), MOI.ScalarAffineTerm.(op(one(T)), g.variables))) + d = MOI.output_dimension(g) + @assert MOI.output_dimension(f) == d + append!(f.terms, MOI.VectorAffineTerm.(collect(1:d), MOI.ScalarAffineTerm.(op(one(T)), g.variables))) return f end function operate!(op::Union{typeof(+), typeof(-)}, ::Type{T}, @@ -898,16 +902,16 @@ end function operate!(op::Union{typeof(+), typeof(-)}, ::Type{T}, f::MOI.VectorQuadraticFunction{T}, g::Vector{T}) where T - @assert output_dimension(f) == length(g) + @assert MOI.output_dimension(f) == length(g) f.constants .= op.(f.constants, g) return f end function operate!(op::Union{typeof(+), typeof(-)}, ::Type{T}, f::MOI.VectorQuadraticFunction{T}, g::MOI.VectorOfVariables) where T - d = output_dimension(g) - @assert output_dimension(f) == d - push!(f.affine_terms, MOI.VectorAffineTerm.(collect(1:d), MOI.ScalarAffineTerm.(op(one(T)), g.variables))) + d = MOI.output_dimension(g) + @assert MOI.output_dimension(f) == d + append!(f.affine_terms, MOI.VectorAffineTerm.(collect(1:d), MOI.ScalarAffineTerm.(op(one(T)), g.variables))) return f end function operate!(op::Union{typeof(+), typeof(-)}, ::Type{T}, @@ -934,6 +938,18 @@ end # return operate!(+, T, operate(+, T, f, g), h, args...) # end +# function operate(op::typeof(+), ::Type{T}, f::VectorOfVariables) where T +# return f +# end + +function operate(op::typeof(-), ::Type{T}, f::MOI.VectorOfVariables) where T + d = MOI.output_dimension(f) + return MOI.VectorAffineFunction{T}( + MOI.VectorAffineTerm.(collect(1:d), + MOI.ScalarAffineTerm.(-one(T), f.variables)), + fill(zero(T),d)) +end + # Vector number +/- ... function operate(op::typeof(+), ::Type{T}, α::Vector{T}, f::VectorLike{T}) where T return operate(op, T, f, α) @@ -945,22 +961,22 @@ end # Vector Variable +/- ... function operate(op::Union{typeof(+), typeof(-)}, ::Type{T}, f::MOI.VectorOfVariables, α::Vector{T}) where T - d = output_dimension(f) + d = MOI.output_dimension(f) @assert length(α) == d return MOI.VectorAffineFunction{T}( - [MOI.VectorAffineTerm.(collect(1:d), - MOI.ScalarAffineTerm.(one(T), f.variables))], + MOI.VectorAffineTerm.(collect(1:d), + MOI.ScalarAffineTerm.(one(T), f.variables)), op.(α)) end function operate(op::Union{typeof(+), typeof(-)}, ::Type{T}, f::MOI.VectorOfVariables, g::MOI.VectorOfVariables) where T - d = output_dimension(f) - @assert output_dimension(g) == d - return MOI.VectorAffineFunction{T}([ - MOI.VectorAffineTerm.(collect(1:d), MOI.ScalarAffineTerm.(one(T), f.variables)), + d = MOI.output_dimension(f) + @assert MOI.output_dimension(g) == d + return MOI.VectorAffineFunction{T}( + vcat(MOI.VectorAffineTerm.(collect(1:d), MOI.ScalarAffineTerm.(one(T), f.variables)), MOI.VectorAffineTerm.(collect(1:d), MOI.ScalarAffineTerm.(op(one(T)), g.variables)) - ], + ), fill(zero(T),d)) end function operate(op::typeof(+), ::Type{T}, diff --git a/test/Utilities/functions.jl b/test/Utilities/functions.jl index bf71cb4bf1..2014f14046 100644 --- a/test/Utilities/functions.jl +++ b/test/Utilities/functions.jl @@ -492,3 +492,56 @@ end end end + +@testset "Vector operate tests" begin + w = MOI.VariableIndex(0) + x = MOI.VariableIndex(1) + y = MOI.VariableIndex(2) + + T = Float64 + @test MOIU.promote_operation(+, T, MOI.VectorAffineFunction{T}, MOI.VectorAffineFunction{T}) == MOI.VectorAffineFunction{T} + @test MOIU.promote_operation(+, T, Vector{T}, MOI.VectorAffineFunction{T}) == MOI.VectorAffineFunction{T} + @test MOIU.promote_operation(+, T, Vector{T}, MOI.VectorQuadraticFunction{T}) == MOI.VectorQuadraticFunction{T} + @test MOIU.promote_operation(+, T, MOI.VectorAffineFunction{T}, MOI.VectorQuadraticFunction{T}) == MOI.VectorQuadraticFunction{T} + + α = [1, 2, 3] + v = MOI.VectorOfVariables([y, w, y]) + g = MOI.VectorAffineFunction(MOI.VectorAffineTerm.([3, 1], + MOI.ScalarAffineTerm.([5, 2], + [y, x])), + [3, 1, 4]) + f = MOI.VectorQuadraticFunction(MOI.VectorAffineTerm.([1, 2, 2], + MOI.ScalarAffineTerm.([3, 1, 2], [x, x, y])), + MOI.VectorQuadraticTerm.([1, 1, 2], + MOI.ScalarQuadraticTerm.([1, 2, 3], [x, y, x], [x, y, y])), [7, 3, 4]) + v_plus_g = MOI.VectorAffineFunction(MOI.VectorAffineTerm.([3, 1, 1, 2, 3], + MOI.ScalarAffineTerm.([5, 2, 1, 1, 1], + [y, x, y, w, y])), + [3, 1, 4]) + g_plus_α = MOI.VectorAffineFunction(MOI.VectorAffineTerm.([3, 1], + MOI.ScalarAffineTerm.([5, 2], + [y, x])), + [4, 3, 7]) + α_minus_v = MOI.VectorAffineFunction(MOI.VectorAffineTerm.([1, 2, 3], + MOI.ScalarAffineTerm.([-1, -1, -1], + [y, w, y])), + [1, 2, 3]) + v_minus_v_plus_v = MOI.VectorAffineFunction(MOI.VectorAffineTerm.([1, 2, 3, 1, 2, 3, 1, 2, 3], + MOI.ScalarAffineTerm.([1, 1, 1, -1, -1, -1, 1, 1, 1], + [y, w, y, y, w, y, y, w, y])), + [0, 0, 0]) + f_plus_α = MOI.VectorQuadraticFunction(MOI.VectorAffineTerm.([1, 2, 2], + MOI.ScalarAffineTerm.([3, 1, 2], [x, x, y])), + MOI.VectorQuadraticTerm.([1, 1, 2], + MOI.ScalarQuadraticTerm.([1, 2, 3], [x, y, x], [x, y, y])), [8, 5, 7]) + f_minus_g = MOI.VectorQuadraticFunction(MOI.VectorAffineTerm.([1, 2, 2, 3, 1], + MOI.ScalarAffineTerm.([3, 1, 2, -5, -2], [x, x, y, y, x])), + MOI.VectorQuadraticTerm.([1, 1, 2], + MOI.ScalarQuadraticTerm.([1, 2, 3], [x, y, x], [x, y, y])), [4, 2, 0]) + @test v + g ≈ v_plus_g + @test g + α ≈ g_plus_α + @test α - v ≈ α_minus_v + @test MOIU.operate(+, T, MOIU.operate(-, T, v, v), v) ≈ v_minus_v_plus_v + @test f + α ≈ f_plus_α + @test f - g ≈ f_minus_g +end From ccf8e1326ef14945b65fb34bdb57797aadc0533b Mon Sep 17 00:00:00 2001 From: joaquimgarcia_psr Date: Sat, 19 Jan 2019 21:06:53 -0200 Subject: [PATCH 13/21] add tests and small fixes --- src/Bridges/Bridges.jl | 26 ++++------- src/Bridges/slackbridge.jl | 18 ++++---- src/Utilities/functions.jl | 78 ++++++++++++++++++------------- test/Utilities/functions.jl | 92 ++++++++++++++++++++++--------------- test/bridge.jl | 19 ++++++++ 5 files changed, 140 insertions(+), 93 deletions(-) diff --git a/src/Bridges/Bridges.jl b/src/Bridges/Bridges.jl index c7e5460877..ec31e2d7cf 100644 --- a/src/Bridges/Bridges.jl +++ b/src/Bridges/Bridges.jl @@ -63,24 +63,14 @@ include("vectorizebridge.jl") @bridge Vectorize VectorizeBridge () (MOI.EqualTo, MOI.LessThan, MOI.GreaterThan,) () () (MOI.SingleVariable,) (MOI.ScalarAffineFunction, MOI.ScalarQuadraticFunction) () () include("slackbridge.jl") @bridge ScalarSlack ScalarSlackBridge () (MOI.Interval, MOI.LessThan, MOI.GreaterThan) () () () (MOI.ScalarAffineFunction, MOI.ScalarQuadraticFunction) () () -@bridge(VectorSlack, VectorSlackBridge, -(), -(), -(MOI.Nonnegatives, -MOI.Nonpositives, -MOI.SecondOrderCone, -MOI.RotatedSecondOrderCone, -MOI.GeometricMeanCone, -MOI.PositiveSemidefiniteConeSquare, -MOI.LogDetConeTriangle, -MOI.RootDetConeTriangle), -(), -(), -(), -(), -(MOI.VectorAffineFunction, -MOI.VectorQuadraticFunction) -) +@bridge(VectorSlack, VectorSlackBridge, (), (), + (MOI.Nonnegatives, MOI.Nonpositives, MOI.SecondOrderCone, + MOI.RotatedSecondOrderCone, MOI.GeometricMeanCone, + MOI.PositiveSemidefiniteConeSquare, MOI.LogDetConeTriangle, + MOI.RootDetConeTriangle, MOI.PowerCone, MOI.DualPowerCone), + (), (), (), (), + (MOI.VectorAffineFunction, MOI.VectorQuadraticFunction) + ) include("intervalbridge.jl") @bridge SplitInterval SplitIntervalBridge () (MOI.Interval,) () () (MOI.SingleVariable,) (MOI.ScalarAffineFunction, MOI.ScalarQuadraticFunction) () () include("rsocbridge.jl") diff --git a/src/Bridges/slackbridge.jl b/src/Bridges/slackbridge.jl index 300a23290b..ba821a8e42 100644 --- a/src/Bridges/slackbridge.jl +++ b/src/Bridges/slackbridge.jl @@ -6,12 +6,12 @@ The `ScalarSlackBridge` converts a constraint `F`-in-`S` where `F` is a function different from `SingleVariable` into the constraints ``F in EqualTo{T}`` and `SingleVariable`-in-`S`. """ -struct ScalarSlackBridge{T, F<:MOI.AbstractScalarFunction, S<:MOI.AbstractScalarSet} <: AbstractBridge +struct ScalarSlackBridge{T, F, S} <: AbstractBridge slack::MOI.VariableIndex slack_in_set::CI{MOI.SingleVariable, S} equality::CI{F, MOI.EqualTo{T}} end -function ScalarSlackBridge{T, F, S}(model, f::F, s::S) where {T, F<:MOI.AbstractScalarFunction, S<:MOI.AbstractScalarSet} +function ScalarSlackBridge{T, F, S}(model, f::MOI.AbstractScalarFunction, s::S) where {T, F, S} slack = MOI.add_variable(model) new_f = MOIU.operate(-, T, f, MOI.SingleVariable(slack)) slack_in_set = MOI.add_constraint(model, MOI.SingleVariable(slack), s) @@ -39,7 +39,8 @@ end function concrete_bridge_type(::Type{<:ScalarSlackBridge{T}}, F::Type{<:MOI.AbstractScalarFunction}, S::Type{<:MOI.AbstractScalarSet}) where T - return ScalarSlackBridge{T, F, S} + F2 = MOIU.promote_operation(-, T, F, MOI.SingleVariable) + return ScalarSlackBridge{T, F2, S} end # Attributes, Bridge acting as an model @@ -62,7 +63,7 @@ function MOI.get(model::MOI.ModelLike, attr::MOI.ConstraintPrimal, c::ScalarSlac return MOI.get(model, attr, c.slack_in_set) end function MOI.get(model::MOI.ModelLike, a::MOI.ConstraintDual, c::ScalarSlackBridge) - error("ScalarSlackBridge is not returning duals for now") + return MOI.get(model, a, c.slack_in_set) end # Constraints @@ -88,12 +89,12 @@ end The `VectorSlackBridge` converts a constraint `F`-in-`S` where `F` is a function different from `VectorOfVariables` into the constraints ``F in Zeros`` and `VectorOfVariables`-in-`S`. """ -struct VectorSlackBridge{T, F<:MOI.AbstractVectorFunction, S<:MOI.AbstractVectorSet} <: AbstractBridge +struct VectorSlackBridge{T, F, S} <: AbstractBridge slacks::Vector{MOI.VariableIndex} slacks_in_set::CI{MOI.VectorOfVariables, S} equality::CI{F, MOI.Zeros} end -function VectorSlackBridge{T, F, S}(model, f::F, s::S) where {T, F<:MOI.AbstractVectorFunction, S<:MOI.AbstractVectorSet} +function VectorSlackBridge{T, F, S}(model, f::MOI.AbstractVectorFunction, s::S) where {T, F, S} d = MOI.dimension(s) slacks = MOI.add_variables(model, d) new_f = MOIU.operate(-, T, f, MOI.VectorAffineFunction{T}(MOI.VectorOfVariables(slacks))) @@ -120,7 +121,8 @@ end function concrete_bridge_type(::Type{<:VectorSlackBridge{T}}, F::Type{<:MOI.AbstractVectorFunction}, S::Type{<:MOI.AbstractVectorSet}) where T - return VectorSlackBridge{T, F, S} + F2 = MOIU.promote_operation(-, T, F, MOI.VectorOfVariables) + return VectorSlackBridge{T, F2, S} end # Attributes, Bridge acting as an model @@ -143,7 +145,7 @@ function MOI.get(model::MOI.ModelLike, attr::MOI.ConstraintPrimal, c::VectorSlac return MOI.get(model, attr, c.slacks_in_set) end function MOI.get(model::MOI.ModelLike, a::MOI.ConstraintDual, c::VectorSlackBridge) - error("VectorSlackBridge is not returning duals for now") + return MOI.get(model, a, c.slacks_in_set) end # Constraints diff --git a/src/Utilities/functions.jl b/src/Utilities/functions.jl index 46a9a7f051..9b94599239 100644 --- a/src/Utilities/functions.jl +++ b/src/Utilities/functions.jl @@ -849,10 +849,11 @@ function Base.:-(α::T, f::ScalarLike{T}) where T end # Vector +/- -function promote_operation(::Union{typeof(+), typeof(-)}, ::Type{T}, - ::Type{<:VectorAffineLike{T}}) where T -return MOI.VectorAffineFunction{T} -end +############################################################################### +# function promote_operation(::Union{typeof(+), typeof(-)}, ::Type{T}, +# ::Type{<:VectorAffineLike{T}}) where T +# return MOI.VectorAffineFunction{T} +# end function promote_operation(::Union{typeof(+), typeof(-)}, ::Type{T}, ::Type{<:VectorAffineLike{T}}, ::Type{<:VectorAffineLike{T}}) where T @@ -866,42 +867,44 @@ end # Vector Variable +/- ... function operate!(op::Union{typeof(+), typeof(-)}, ::Type{T}, - f::MOI.VectorOfVariables, - g::VectorQuadraticLike) where T + f::MOI.VectorOfVariables, + g::VectorQuadraticLike) where T return operate(op, T, f, g) end # Vector Affine +/-! ... function operate!(op::Union{typeof(+), typeof(-)}, ::Type{T}, - f::MOI.VectorAffineFunction{T}, - g::Vector{T}) where T + f::MOI.VectorAffineFunction{T}, + g::Vector{T}) where T @assert MOI.output_dimension(f) == length(g) f.constants .= op.(f.constants, g) return f end function operate!(op::Union{typeof(+), typeof(-)}, ::Type{T}, - f::MOI.VectorAffineFunction{T}, - g::MOI.VectorOfVariables) where T + f::MOI.VectorAffineFunction{T}, + g::MOI.VectorOfVariables) where T d = MOI.output_dimension(g) @assert MOI.output_dimension(f) == d - append!(f.terms, MOI.VectorAffineTerm.(collect(1:d), MOI.ScalarAffineTerm.(op(one(T)), g.variables))) + append!(f.terms, MOI.VectorAffineTerm.( + collect(1:d), + MOI.ScalarAffineTerm.(op(one(T)), g.variables))) return f end function operate!(op::Union{typeof(+), typeof(-)}, ::Type{T}, - f::MOI.VectorAffineFunction{T}, - g::MOI.VectorAffineFunction{T}) where T + f::MOI.VectorAffineFunction{T}, + g::MOI.VectorAffineFunction{T}) where T append!(f.terms, operate_terms(op, g.terms)) f.constants .= op.(f.constants, g.constants) return f end function operate!(op::Union{typeof(+), typeof(-)}, ::Type{T}, - f::MOI.VectorAffineFunction{T}, - g::MOI.VectorQuadraticFunction{T}) where T + f::MOI.VectorAffineFunction{T}, + g::MOI.VectorQuadraticFunction{T}) where T return operate(op, T, f, g) end # Vector Quadratic +/-! ... function operate!(op::Union{typeof(+), typeof(-)}, ::Type{T}, - f::MOI.VectorQuadraticFunction{T}, - g::Vector{T}) where T + f::MOI.VectorQuadraticFunction{T}, + g::Vector{T}) where T @assert MOI.output_dimension(f) == length(g) f.constants .= op.(f.constants, g) return f @@ -915,15 +918,15 @@ function operate!(op::Union{typeof(+), typeof(-)}, ::Type{T}, return f end function operate!(op::Union{typeof(+), typeof(-)}, ::Type{T}, - f::MOI.VectorQuadraticFunction{T}, - g::MOI.VectorAffineFunction{T}) where T + f::MOI.VectorQuadraticFunction{T}, + g::MOI.VectorAffineFunction{T}) where T append!(f.affine_terms, operate_terms(op, g.terms)) f.constants .= op.(f.constants, g.constants) return f end function operate!(op::Union{typeof(+), typeof(-)}, ::Type{T}, - f::MOI.VectorQuadraticFunction{T}, - g::MOI.VectorQuadraticFunction{T}) where T + f::MOI.VectorQuadraticFunction{T}, + g::MOI.VectorQuadraticFunction{T}) where T append!(f.affine_terms, operate_terms(op, g.affine_terms)) append!(f.quadratic_terms, operate_terms(op, g.quadratic_terms)) f.constants .= op.(f.constants, g.constants) @@ -945,9 +948,10 @@ end function operate(op::typeof(-), ::Type{T}, f::MOI.VectorOfVariables) where T d = MOI.output_dimension(f) return MOI.VectorAffineFunction{T}( - MOI.VectorAffineTerm.(collect(1:d), - MOI.ScalarAffineTerm.(-one(T), f.variables)), - fill(zero(T),d)) + MOI.VectorAffineTerm.( + collect(1:d), + MOI.ScalarAffineTerm.(-one(T), f.variables)), + fill(zero(T),d)) end # Vector number +/- ... @@ -964,9 +968,10 @@ function operate(op::Union{typeof(+), typeof(-)}, ::Type{T}, d = MOI.output_dimension(f) @assert length(α) == d return MOI.VectorAffineFunction{T}( - MOI.VectorAffineTerm.(collect(1:d), - MOI.ScalarAffineTerm.(one(T), f.variables)), - op.(α)) + MOI.VectorAffineTerm.( + collect(1:d), + MOI.ScalarAffineTerm.(one(T), f.variables)), + op.(α)) end function operate(op::Union{typeof(+), typeof(-)}, ::Type{T}, f::MOI.VectorOfVariables, @@ -974,10 +979,14 @@ function operate(op::Union{typeof(+), typeof(-)}, ::Type{T}, d = MOI.output_dimension(f) @assert MOI.output_dimension(g) == d return MOI.VectorAffineFunction{T}( - vcat(MOI.VectorAffineTerm.(collect(1:d), MOI.ScalarAffineTerm.(one(T), f.variables)), - MOI.VectorAffineTerm.(collect(1:d), MOI.ScalarAffineTerm.(op(one(T)), g.variables)) - ), - fill(zero(T),d)) + vcat( + MOI.VectorAffineTerm.( + collect(1:d), + MOI.ScalarAffineTerm.(one(T), f.variables)), + MOI.VectorAffineTerm.( + collect(1:d), + MOI.ScalarAffineTerm.(op(one(T)), g.variables))), + fill(zero(T),d)) end function operate(op::typeof(+), ::Type{T}, f::MOI.VectorOfVariables, @@ -997,6 +1006,13 @@ function operate(op::Union{typeof(-)}, ::Type{T}, return MOI.VectorAffineFunction(operate_terms(op, f.terms), op.(f.constants)) end +function operate(op::Union{typeof(-)}, ::Type{T}, + f::MOI.VectorQuadraticFunction{T}) where T + return MOI.VectorQuadraticFunction( + operate_terms(op, f.affine_terms), + operate_terms(op, f.quadratic_terms), + op.(f.constants)) +end function operate(op::Union{typeof(+), typeof(-)}, ::Type{T}, f::MOI.VectorAffineFunction{T}, g::VectorAffineLike{T}) where T diff --git a/test/Utilities/functions.jl b/test/Utilities/functions.jl index 2014f14046..8f6dc12a30 100644 --- a/test/Utilities/functions.jl +++ b/test/Utilities/functions.jl @@ -499,49 +499,69 @@ end y = MOI.VariableIndex(2) T = Float64 - @test MOIU.promote_operation(+, T, MOI.VectorAffineFunction{T}, MOI.VectorAffineFunction{T}) == MOI.VectorAffineFunction{T} - @test MOIU.promote_operation(+, T, Vector{T}, MOI.VectorAffineFunction{T}) == MOI.VectorAffineFunction{T} - @test MOIU.promote_operation(+, T, Vector{T}, MOI.VectorQuadraticFunction{T}) == MOI.VectorQuadraticFunction{T} - @test MOIU.promote_operation(+, T, MOI.VectorAffineFunction{T}, MOI.VectorQuadraticFunction{T}) == MOI.VectorQuadraticFunction{T} + for t1 in [MOI.VectorAffineFunction{T}, MOI.VectorOfVariables, Vector{T}] + for t2 in [MOI.VectorAffineFunction{T}, MOI.VectorOfVariables] + @test MOIU.promote_operation(+, T, t1, t2) == MOI.VectorAffineFunction{T} + @test MOIU.promote_operation(-, T, t1, t2) == MOI.VectorAffineFunction{T} + end + end + for t1 in [MOI.VectorQuadraticFunction{T}, MOI.VectorAffineFunction{T}, + MOI.VectorOfVariables, Vector{T}] + for t2 in [MOI.VectorQuadraticFunction{T}] + @test MOIU.promote_operation(+, T, t1, t2) == MOI.VectorQuadraticFunction{T} + @test MOIU.promote_operation(-, T, t1, t2) == MOI.VectorQuadraticFunction{T} + end + end α = [1, 2, 3] v = MOI.VectorOfVariables([y, w, y]) - g = MOI.VectorAffineFunction(MOI.VectorAffineTerm.([3, 1], - MOI.ScalarAffineTerm.([5, 2], - [y, x])), - [3, 1, 4]) - f = MOI.VectorQuadraticFunction(MOI.VectorAffineTerm.([1, 2, 2], - MOI.ScalarAffineTerm.([3, 1, 2], [x, x, y])), - MOI.VectorQuadraticTerm.([1, 1, 2], - MOI.ScalarQuadraticTerm.([1, 2, 3], [x, y, x], [x, y, y])), [7, 3, 4]) - v_plus_g = MOI.VectorAffineFunction(MOI.VectorAffineTerm.([3, 1, 1, 2, 3], - MOI.ScalarAffineTerm.([5, 2, 1, 1, 1], - [y, x, y, w, y])), - [3, 1, 4]) - g_plus_α = MOI.VectorAffineFunction(MOI.VectorAffineTerm.([3, 1], - MOI.ScalarAffineTerm.([5, 2], - [y, x])), - [4, 3, 7]) - α_minus_v = MOI.VectorAffineFunction(MOI.VectorAffineTerm.([1, 2, 3], - MOI.ScalarAffineTerm.([-1, -1, -1], - [y, w, y])), - [1, 2, 3]) - v_minus_v_plus_v = MOI.VectorAffineFunction(MOI.VectorAffineTerm.([1, 2, 3, 1, 2, 3, 1, 2, 3], - MOI.ScalarAffineTerm.([1, 1, 1, -1, -1, -1, 1, 1, 1], - [y, w, y, y, w, y, y, w, y])), - [0, 0, 0]) - f_plus_α = MOI.VectorQuadraticFunction(MOI.VectorAffineTerm.([1, 2, 2], - MOI.ScalarAffineTerm.([3, 1, 2], [x, x, y])), - MOI.VectorQuadraticTerm.([1, 1, 2], - MOI.ScalarQuadraticTerm.([1, 2, 3], [x, y, x], [x, y, y])), [8, 5, 7]) - f_minus_g = MOI.VectorQuadraticFunction(MOI.VectorAffineTerm.([1, 2, 2, 3, 1], - MOI.ScalarAffineTerm.([3, 1, 2, -5, -2], [x, x, y, y, x])), - MOI.VectorQuadraticTerm.([1, 1, 2], - MOI.ScalarQuadraticTerm.([1, 2, 3], [x, y, x], [x, y, y])), [4, 2, 0]) + g = MOI.VectorAffineFunction( + MOI.VectorAffineTerm.([3, 1], + MOI.ScalarAffineTerm.([5, 2], [y, x])), + [3, 1, 4]) + f = MOI.VectorQuadraticFunction( + MOI.VectorAffineTerm.([1, 2, 2], + MOI.ScalarAffineTerm.([3, 1, 2], [x, x, y])), + MOI.VectorQuadraticTerm.([1, 1, 2], + MOI.ScalarQuadraticTerm.([1, 2, 3], [x, y, x], [x, y, y])), + [7, 3, 4]) + v_plus_g = MOI.VectorAffineFunction( + MOI.VectorAffineTerm.([3, 1, 1, 2, 3], + MOI.ScalarAffineTerm.([5, 2, 1, 1, 1], [y, x, y, w, y])), + [3, 1, 4]) + g_plus_α = MOI.VectorAffineFunction( + MOI.VectorAffineTerm.([3, 1], + MOI.ScalarAffineTerm.([5, 2], [y, x])), + [4, 3, 7]) + α_minus_v = MOI.VectorAffineFunction( + MOI.VectorAffineTerm.([1, 2, 3], + MOI.ScalarAffineTerm.([-1, -1, -1], [y, w, y])), + [1, 2, 3]) + v_minus_v_plus_v = MOI.VectorAffineFunction( + MOI.VectorAffineTerm.([1, 2, 3, 1, 2, 3, 1, 2, 3], + MOI.ScalarAffineTerm.([1, 1, 1, -1, -1, -1, 1, 1, 1], + [y, w, y, y, w, y, y, w, y])), + [0, 0, 0]) + f_plus_α = MOI.VectorQuadraticFunction( + MOI.VectorAffineTerm.([1, 2, 2], + MOI.ScalarAffineTerm.([3, 1, 2], [x, x, y])), + MOI.VectorQuadraticTerm.([1, 1, 2], + MOI.ScalarQuadraticTerm.([1, 2, 3], [x, y, x], [x, y, y])), + [8, 5, 7]) + f_minus_g = MOI.VectorQuadraticFunction( + MOI.VectorAffineTerm.([1, 2, 2, 3, 1], + MOI.ScalarAffineTerm.([3, 1, 2, -5, -2], [x, x, y, y, x])), + MOI.VectorQuadraticTerm.([1, 1, 2], + MOI.ScalarQuadraticTerm.([1, 2, 3], [x, y, x], [x, y, y])), + [4, 2, 0]) @test v + g ≈ v_plus_g @test g + α ≈ g_plus_α @test α - v ≈ α_minus_v @test MOIU.operate(+, T, MOIU.operate(-, T, v, v), v) ≈ v_minus_v_plus_v @test f + α ≈ f_plus_α @test f - g ≈ f_minus_g + @test f - f + f - g ≈ f_minus_g + + @test v - α ≈ - α_minus_v + @test g - f ≈ - f_minus_g end diff --git a/test/bridge.jl b/test/bridge.jl index e3fb68f554..31ee8b51f1 100644 --- a/test/bridge.jl +++ b/test/bridge.jl @@ -388,6 +388,12 @@ end # deletion test wont work due to deleted variable # test_delete_bridge(bridgedmock, ci, 2, ((MOI.ScalarAffineFunction{Float64}, MOI.GreaterThan{Float64}, 0), # (MOI.ScalarAffineFunction{Float64}, MOI.LessThan{Float64}, 0))) + + for T in [Int, Float64], S in [MOI.GreaterThan{T}, MOI.GreaterThan{T}] + for F in [MOI.ScalarAffineFunction{T}, MOI.ScalarQuadraticFunction{T}] + @test MOIB.added_constraint_types(MOIB.ScalarSlackBridge{T, F, S}) == [(F, MOI.EqualTo{T}), (MOI.SingleVariable, S)] + end + end end @testset "Vector slack" begin @@ -404,6 +410,12 @@ end MOI.modify(bridgedmock, ci, MOI.VectorConstantChange([1.0])) @test MOI.get(bridgedmock, MOI.ConstraintFunction(), ci) ≈ MOI.VectorAffineFunction(MOI.VectorAffineTerm.(1, MOI.ScalarAffineTerm.([2.0, 1.0], [x, y])), [1.0]) + # This power cone test is failing + # fp = MOI.VectorAffineFunction(MOI.VectorAffineTerm.([1,2,3], MOI.ScalarAffineTerm.([1.0, 2.0, 3.0], [x, y, y])), [0.0]) + # cp = MOI.add_constraint(bridgedmock, fp, MOI.PowerCone(0.1)) + # @test MOI.get(bridgedmock, MOI.ConstraintSet(), cp) == MOI.PowerCone(0.1) + # MOI.set(bridgedmock, MOI.ConstraintSet(), cp, MOI.PowerCone(0.2)) + # @test MOI.get(bridgedmock, MOI.ConstraintSet(), cp) == MOI.PowerCone(0.2) MOIT.basic_constraint_tests(bridgedmock, config, include=[(F, S) for @@ -419,6 +431,7 @@ end (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [100, 0, 100, 0]), (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [100, -100, 100, -100])) MOIT.linear7test(bridgedmock, config) + loc = MOI.get(bridgedmock, MOI.ListOfConstraints()) @test length(loc) == 2 @test (MOI.VectorAffineFunction{Float64}, MOI.Nonnegatives) in loc @@ -428,6 +441,12 @@ end @test (MOI.VectorAffineFunction{Float64}, MOI.Zeros) in loc @test (MOI.VectorOfVariables, MOI.Nonnegatives) in loc @test (MOI.VectorOfVariables, MOI.Nonpositives) in loc + + for T in [Int, Float64], S in [MOI.Nonnegatives, MOI.Nonpositives] + for F in [MOI.VectorAffineFunction{T}, MOI.VectorQuadraticFunction{T}] + @test MOIB.added_constraint_types(MOIB.VectorSlackBridge{T, F, S}) == [(F, MOI.Zeros), (MOI.VectorOfVariables, S)] + end + end end @testset "RSOC" begin From f4c124a049dcead74c1f9889929964f956dd0617 Mon Sep 17 00:00:00 2001 From: joaquimgarcia_psr Date: Sun, 20 Jan 2019 21:04:59 -0200 Subject: [PATCH 14/21] add more function tests --- test/Utilities/functions.jl | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/Utilities/functions.jl b/test/Utilities/functions.jl index 8f6dc12a30..a6771e686f 100644 --- a/test/Utilities/functions.jl +++ b/test/Utilities/functions.jl @@ -556,11 +556,14 @@ end [4, 2, 0]) @test v + g ≈ v_plus_g @test g + α ≈ g_plus_α + @test α + g ≈ g_plus_α @test α - v ≈ α_minus_v @test MOIU.operate(+, T, MOIU.operate(-, T, v, v), v) ≈ v_minus_v_plus_v @test f + α ≈ f_plus_α @test f - g ≈ f_minus_g @test f - f + f - g ≈ f_minus_g + @test v + f + α - v ≈ f_plus_α + @test v - f - α - v ≈ - f_plus_α @test v - α ≈ - α_minus_v @test g - f ≈ - f_minus_g From fdb8b7d010d1deecda9e3e121e6614a17bf2e20a Mon Sep 17 00:00:00 2001 From: joaquimgarcia_psr Date: Sun, 20 Jan 2019 21:05:16 -0200 Subject: [PATCH 15/21] fix function identation --- src/Utilities/functions.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Utilities/functions.jl b/src/Utilities/functions.jl index 9b94599239..03bfad0e91 100644 --- a/src/Utilities/functions.jl +++ b/src/Utilities/functions.jl @@ -640,7 +640,7 @@ function operate_terms(::typeof(+), end function operate_terms(::typeof(+), terms::Vector{<:Union{MOI.VectorAffineTerm, - MOI.VectorQuadraticTerm}}) + MOI.VectorQuadraticTerm}}) return terms end function operate_terms(::typeof(-), From 6accda6091decbaadfb91dd154fa388376b91652 Mon Sep 17 00:00:00 2001 From: joaquimgarcia_psr Date: Sun, 20 Jan 2019 21:05:41 -0200 Subject: [PATCH 16/21] fix powercone --- src/Bridges/Bridges.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Bridges/Bridges.jl b/src/Bridges/Bridges.jl index ec31e2d7cf..001290278d 100644 --- a/src/Bridges/Bridges.jl +++ b/src/Bridges/Bridges.jl @@ -67,8 +67,8 @@ include("slackbridge.jl") (MOI.Nonnegatives, MOI.Nonpositives, MOI.SecondOrderCone, MOI.RotatedSecondOrderCone, MOI.GeometricMeanCone, MOI.PositiveSemidefiniteConeSquare, MOI.LogDetConeTriangle, - MOI.RootDetConeTriangle, MOI.PowerCone, MOI.DualPowerCone), - (), (), (), (), + MOI.RootDetConeTriangle), + (MOI.PowerCone, MOI.DualPowerCone, MOI.SOS1, MOI.SOS2), (), (), (), (MOI.VectorAffineFunction, MOI.VectorQuadraticFunction) ) include("intervalbridge.jl") From 27b95cfb7b109df3edc3c179a1275aee3c1f4efe Mon Sep 17 00:00:00 2001 From: joaquimgarcia_psr Date: Sun, 20 Jan 2019 21:07:47 -0200 Subject: [PATCH 17/21] improve comments in slack bridge --- src/Bridges/slackbridge.jl | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/src/Bridges/slackbridge.jl b/src/Bridges/slackbridge.jl index ba821a8e42..f187adf364 100644 --- a/src/Bridges/slackbridge.jl +++ b/src/Bridges/slackbridge.jl @@ -3,8 +3,10 @@ """ ScalarSlackBridge{T, F, S} -The `ScalarSlackBridge` converts a constraint `F`-in-`S` where `F` is a function different - from `SingleVariable` into the constraints ``F in EqualTo{T}`` and `SingleVariable`-in-`S`. +The `ScalarSlackBridge` converts a constraint `G`-in-`S` where `G` is a function different +from `SingleVariable` into the constraints `F`-in-`EqualTo{T}` and `SingleVariable`-in-`S`. +`F` is the result of subtracting a `SingleVariable` from `G`. +Tipically `G` is the same as `F`, but that is not mandatory. """ struct ScalarSlackBridge{T, F, S} <: AbstractBridge slack::MOI.VariableIndex @@ -22,7 +24,7 @@ end # start allowing everything (scalar) MOI.supports_constraint(::Type{ScalarSlackBridge{T, F, S}}, ::Type{<:MOI.AbstractScalarFunction}, - ::Type{<:MOI.AbstractScalarSet}) where {T, F, S} = true + ::Type{<:MOI.AbstractScalarSet}) where {T, F, S} = true # then restrict (careful with ambiguity) MOI.supports_constraint(::Type{ScalarSlackBridge{T, F, S}}, ::Type{<:MOI.SingleVariable}, @@ -63,6 +65,9 @@ function MOI.get(model::MOI.ModelLike, attr::MOI.ConstraintPrimal, c::ScalarSlac return MOI.get(model, attr, c.slack_in_set) end function MOI.get(model::MOI.ModelLike, a::MOI.ConstraintDual, c::ScalarSlackBridge) + # The dual constraint on slack (since it is free) is + # -dual_slack_in_set + dual_equality = 0 so the two duals are + # equal and we can return either one of them. return MOI.get(model, a, c.slack_in_set) end @@ -72,7 +77,7 @@ function MOI.modify(model::MOI.ModelLike, c::ScalarSlackBridge, change::MOI.Abst end function MOI.set(model::MOI.ModelLike, ::MOI.ConstraintFunction, - c::ScalarSlackBridge{T, F, S}, func::F) where {T, F, S} + c::ScalarSlackBridge{T, F, S}, func::F) where {T, F, S} new_func = MOIU.operate(-, T, func, MOI.SingleVariable(c.slack)) MOI.set(model, MOI.ConstraintFunction(), c.equality, new_func) end @@ -86,8 +91,10 @@ end """ VectorSlackBridge{T, F, S} -The `VectorSlackBridge` converts a constraint `F`-in-`S` where `F` is a function different - from `VectorOfVariables` into the constraints ``F in Zeros`` and `VectorOfVariables`-in-`S`. +The `VectorSlackBridge` converts a constraint `G`-in-`S` where `G` is a function different +from `VectorOfVariables` into the constraints `F`in-`Zeros` and `VectorOfVariables`-in-`S`. +`F` is the result of subtracting a `VectorOfVariables` from `G`. +Tipically `G` is the same as `F`, but that is not mandatory. """ struct VectorSlackBridge{T, F, S} <: AbstractBridge slacks::Vector{MOI.VariableIndex} @@ -145,6 +152,9 @@ function MOI.get(model::MOI.ModelLike, attr::MOI.ConstraintPrimal, c::VectorSlac return MOI.get(model, attr, c.slacks_in_set) end function MOI.get(model::MOI.ModelLike, a::MOI.ConstraintDual, c::VectorSlackBridge) + # The dual constraint on slack (since it is free) is + # -dual_slack_in_set + dual_equality = 0 so the two duals are + # equal and we can return either one of them. return MOI.get(model, a, c.slacks_in_set) end @@ -154,7 +164,7 @@ function MOI.modify(model::MOI.ModelLike, c::VectorSlackBridge, change::MOI.Abst end function MOI.set(model::MOI.ModelLike, ::MOI.ConstraintFunction, - c::VectorSlackBridge{T, F, S}, func::F) where {T, F, S} + c::VectorSlackBridge{T, F, S}, func::F) where {T, F, S} new_func = MOIU.operate(-, T, func, MOI.VectorAffineFunction{T}(MOI.VectorOfVariables(c.slacks))) MOI.set(model, MOI.ConstraintFunction(), c.equality, new_func) end From e25a306932e5f7281919fb8252bc6900a774cb16 Mon Sep 17 00:00:00 2001 From: joaquimgarcia_psr Date: Sun, 20 Jan 2019 21:08:09 -0200 Subject: [PATCH 18/21] improve comments in conlinear --- src/Test/contlinear.jl | 44 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/src/Test/contlinear.jl b/src/Test/contlinear.jl index 99c7c0d4d4..e311068055 100644 --- a/src/Test/contlinear.jl +++ b/src/Test/contlinear.jl @@ -783,6 +783,23 @@ function linear7test(model::MOI.ModelLike, config::TestConfig) atol = config.atol rtol = config.rtol + # Min x - y + # s.t. bx <= x (c1) + # y <= by (c2) + # + # or, in more detail, + # + # Min 1 x - 1 y + # s.t. - 1 x <= - bx (z) (c1) + # 1 y <= by (w) (c2) + # + # with generic dual + # + # Max - bx z + by w + # s.t. - z == - 1 (c1) + # w == 1 (c2) + # i.e. z == w == 1 + @test MOIU.supports_default_copy_to(model, #=copy_names=# false) @test MOI.supports(model, MOI.ObjectiveFunction{MOI.ScalarAffineFunction{Float64}}()) @test MOI.supports(model, MOI.ObjectiveSense()) @@ -1171,9 +1188,36 @@ function linear11test(model::MOI.ModelLike, config::TestConfig) atol = config.atol rtol = config.rtol # simple 2 variable, 1 constraint problem + # + # starts with + # # min x + y # st x + y >= 1 # x + y >= 2 + # sol: x+y = 2 (degenerate) + # + # with dual + # + # max w + 2z + # st w + z == 1 + # w + z == 1 + # w, z >= 0 + # sol: z = 1, w = 0 + # + # tranforms problem into: + # + # min x + y + # st x + y >= 1 + # x + y <= 2 + # sol: x+y = 1 (degenerate) + # + # with dual + # + # max w + 2z + # st w + z == 1 + # w + z == 1 + # w >= 0, z <= 0 + # sol: w = 1, z = 0 @test MOIU.supports_default_copy_to(model, #=copy_names=# false) @test MOI.supports(model, MOI.ObjectiveFunction{MOI.ScalarAffineFunction{Float64}}()) From e9af2bde16057a10ada867664ed49020bcb95cd6 Mon Sep 17 00:00:00 2001 From: joaquimgarcia_psr Date: Sun, 20 Jan 2019 21:21:26 -0200 Subject: [PATCH 19/21] fix slack bridge tests and add more tests --- test/bridge.jl | 44 +++++++++++++++++++++++++++++++++++--------- 1 file changed, 35 insertions(+), 9 deletions(-) diff --git a/test/bridge.jl b/test/bridge.jl index 31ee8b51f1..f0e9dc163f 100644 --- a/test/bridge.jl +++ b/test/bridge.jl @@ -5,7 +5,7 @@ MOIU.@model(SimpleModel, (MOI.Zeros, MOI.Nonnegatives, MOI.Nonpositives, MOI.SecondOrderCone, MOI.RotatedSecondOrderCone, MOI.GeometricMeanCone, MOI.PositiveSemidefiniteConeTriangle, MOI.ExponentialCone), - (), + (MOI.PowerCone, MOI.DualPowerCone), (MOI.SingleVariable,), (MOI.ScalarAffineFunction, MOI.ScalarQuadraticFunction), (MOI.VectorOfVariables,), @@ -370,8 +370,21 @@ end # There are extra variables due to the bridge MOIU.set_mock_optimize!(mock, (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [1.0, 1.0, 2.0, 2.0]), - (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [0.5, 0.5, 1.0, 1.0])) + (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [0.5, 0.5, 1.0, 1.0], + (MOI.ScalarAffineFunction{Float64}, MOI.EqualTo{Float64}) => [1, 0], + (MOI.SingleVariable, MOI.GreaterThan{Float64}) => [1], + (MOI.SingleVariable, MOI.LessThan{Float64}) => [0])) MOIT.linear11test(bridgedmock, MOIT.TestConfig(duals = false)) + + c1 = MOI.get(bridgedmock, MOI.ListOfConstraintIndices{MOI.ScalarAffineFunction{Float64}, MOI.GreaterThan{Float64}}()) + @test length(c1) == 1 + @test MOI.get(bridgedmock, MOI.ConstraintPrimal(), c1[]) ≈ 1.0 + @test MOI.get(bridgedmock, MOI.ConstraintDual(), c1[]) ≈ 1.0 + c2 = MOI.get(bridgedmock, MOI.ListOfConstraintIndices{MOI.ScalarAffineFunction{Float64}, MOI.LessThan{Float64}}()) + @test length(c2) == 1 + @test MOI.get(bridgedmock, MOI.ConstraintPrimal(), c2[]) ≈ 1.0 + @test MOI.get(bridgedmock, MOI.ConstraintDual(), c2[]) ≈ 0.0 + loc = MOI.get(bridgedmock, MOI.ListOfConstraints()) @test length(loc) == 2 @test (MOI.ScalarAffineFunction{Float64}, MOI.LessThan{Float64}) in loc @@ -381,6 +394,7 @@ end @test (MOI.ScalarAffineFunction{Float64}, MOI.EqualTo{Float64}) in loc @test (MOI.SingleVariable, MOI.LessThan{Float64}) in loc @test (MOI.SingleVariable, MOI.GreaterThan{Float64}) in loc + # ci = first(MOI.get(bridgedmock, MOI.ListOfConstraintIndices{MOI.ScalarAffineFunction{Float64}, MOI.Interval{Float64}}())) # newf = MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([1.0, -1.0], MOI.get(bridgedmock, MOI.ListOfVariableIndices())), 0.0) # MOI.set(bridgedmock, MOI.ConstraintFunction(), ci, newf) @@ -395,7 +409,7 @@ end end end end - + @testset "Vector slack" begin bridgedmock = MOIB.VectorSlack{Float64}(mock) x = MOI.add_variable(bridgedmock) @@ -411,11 +425,11 @@ end @test MOI.get(bridgedmock, MOI.ConstraintFunction(), ci) ≈ MOI.VectorAffineFunction(MOI.VectorAffineTerm.(1, MOI.ScalarAffineTerm.([2.0, 1.0], [x, y])), [1.0]) # This power cone test is failing - # fp = MOI.VectorAffineFunction(MOI.VectorAffineTerm.([1,2,3], MOI.ScalarAffineTerm.([1.0, 2.0, 3.0], [x, y, y])), [0.0]) - # cp = MOI.add_constraint(bridgedmock, fp, MOI.PowerCone(0.1)) - # @test MOI.get(bridgedmock, MOI.ConstraintSet(), cp) == MOI.PowerCone(0.1) - # MOI.set(bridgedmock, MOI.ConstraintSet(), cp, MOI.PowerCone(0.2)) - # @test MOI.get(bridgedmock, MOI.ConstraintSet(), cp) == MOI.PowerCone(0.2) + fp = MOI.VectorAffineFunction(MOI.VectorAffineTerm.([1,2,3], MOI.ScalarAffineTerm.([1.0, 2.0, 3.0], [x, y, y])), [0.0, 0.0, 0.0]) + cp = MOI.add_constraint(bridgedmock, fp, MOI.PowerCone(0.1)) + @test MOI.get(bridgedmock, MOI.ConstraintSet(), cp) == MOI.PowerCone(0.1) + MOI.set(bridgedmock, MOI.ConstraintSet(), cp, MOI.PowerCone(0.2)) + @test MOI.get(bridgedmock, MOI.ConstraintSet(), cp) == MOI.PowerCone(0.2) MOIT.basic_constraint_tests(bridgedmock, config, include=[(F, S) for @@ -429,9 +443,21 @@ end MOIU.set_mock_optimize!(mock, (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [0, 0, 0, 0]), (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [100, 0, 100, 0]), - (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [100, -100, 100, -100])) + (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [100, -100, 100, -100], + (MOI.VectorAffineFunction{Float64}, MOI.Zeros) => [[1.], [1.]], + (MOI.VectorOfVariables, MOI.Nonnegatives) => [[1.]], + (MOI.VectorOfVariables, MOI.Nonpositives) => [[1.]])) MOIT.linear7test(bridgedmock, config) + c1 = MOI.get(bridgedmock, MOI.ListOfConstraintIndices{MOI.VectorAffineFunction{Float64}, MOI.Nonnegatives}()) + @test length(c1) == 1 + @test MOI.get(bridgedmock, MOI.ConstraintPrimal(), c1[]) ≈ [100.0] + @test MOI.get(bridgedmock, MOI.ConstraintDual(), c1[]) ≈ [1.0] + c2 = MOI.get(bridgedmock, MOI.ListOfConstraintIndices{MOI.VectorAffineFunction{Float64}, MOI.Nonpositives}()) + @test length(c2) == 1 + @test MOI.get(bridgedmock, MOI.ConstraintPrimal(), c2[]) ≈ [-100.0] + @test MOI.get(bridgedmock, MOI.ConstraintDual(), c2[]) ≈ [1.0] + loc = MOI.get(bridgedmock, MOI.ListOfConstraints()) @test length(loc) == 2 @test (MOI.VectorAffineFunction{Float64}, MOI.Nonnegatives) in loc From 6895aa105504596b70ea350bab2e0fc7483c8f04 Mon Sep 17 00:00:00 2001 From: joaquimgarcia_psr Date: Mon, 21 Jan 2019 11:13:11 -0200 Subject: [PATCH 20/21] add more vector function tests and fix operations --- src/Utilities/functions.jl | 8 ++ test/Utilities/functions.jl | 158 ++++++++++++++++++++---------------- 2 files changed, 96 insertions(+), 70 deletions(-) diff --git a/src/Utilities/functions.jl b/src/Utilities/functions.jl index 03bfad0e91..f31bb17a52 100644 --- a/src/Utilities/functions.jl +++ b/src/Utilities/functions.jl @@ -613,6 +613,7 @@ function operate_term(::typeof(*), t1::MOI.ScalarAffineTerm, MOI.ScalarQuadraticTerm(t1.coefficient * t2.coefficient, t1.variable_index, t2.variable_index) end + function operate_term(::typeof(*), α::T, t::MOI.VectorAffineTerm{T}) where T MOI.VectorAffineTerm(t.output_index, operate_term(*, α, t.scalar_term)) end @@ -628,9 +629,16 @@ end function operate_term(::typeof(/), t::MOI.ScalarAffineTerm{T}, α::T) where T MOI.ScalarAffineTerm(t.coefficient / α, t.variable_index) end +function operate_term(::typeof(/), t::MOI.ScalarQuadraticTerm{T}, α::T) where T + MOI.ScalarQuadraticTerm(t.coefficient / α, t.variable_index_1, + t.variable_index_2) +end function operate_term(::typeof(/), t::MOI.VectorAffineTerm{T}, α::T) where T MOI.VectorAffineTerm(t.output_index, operate_term(/, t.scalar_term, α)) end +function operate_term(::typeof(/), t::MOI.VectorQuadraticTerm{T}, α::T) where T + MOI.VectorQuadraticTerm(t.output_index, operate_term(/, t.scalar_term, α)) +end # Avoid a copy in the case of + function operate_terms(::typeof(+), diff --git a/test/Utilities/functions.jl b/test/Utilities/functions.jl index a6771e686f..2821d32d19 100644 --- a/test/Utilities/functions.jl +++ b/test/Utilities/functions.jl @@ -491,80 +491,98 @@ ) end end -end -@testset "Vector operate tests" begin - w = MOI.VariableIndex(0) - x = MOI.VariableIndex(1) - y = MOI.VariableIndex(2) + @testset "Vector operate tests" begin + w = MOI.VariableIndex(0) + x = MOI.VariableIndex(1) + y = MOI.VariableIndex(2) - T = Float64 - for t1 in [MOI.VectorAffineFunction{T}, MOI.VectorOfVariables, Vector{T}] - for t2 in [MOI.VectorAffineFunction{T}, MOI.VectorOfVariables] - @test MOIU.promote_operation(+, T, t1, t2) == MOI.VectorAffineFunction{T} - @test MOIU.promote_operation(-, T, t1, t2) == MOI.VectorAffineFunction{T} + @testset "Vector terms tests" begin + at = MOI.VectorAffineTerm(3, MOI.ScalarAffineTerm(10.0, x)) + qt = MOI.VectorQuadraticTerm(3, MOI.ScalarQuadraticTerm(6.0, x, y)) + @test MOIU.operate_term(*, 3.0, at) == + MOI.VectorAffineTerm(3, MOI.ScalarAffineTerm(30.0, x)) + @test MOIU.operate_term(*, at, at) == + MOI.VectorQuadraticTerm(3, MOI.ScalarQuadraticTerm(100.0, x, x)) + @test MOIU.operate_term(*, 3.0, qt) == + MOI.VectorQuadraticTerm(3, MOI.ScalarQuadraticTerm(18.0, x, y)) + @test MOIU.operate_term(/, at, 2.0) == + MOI.VectorAffineTerm(3, MOI.ScalarAffineTerm(5.0, x)) + @test MOIU.operate_term(/, qt, 3.0) == + MOI.VectorQuadraticTerm(3, MOI.ScalarQuadraticTerm(2.0, x, y)) end - end - for t1 in [MOI.VectorQuadraticFunction{T}, MOI.VectorAffineFunction{T}, - MOI.VectorOfVariables, Vector{T}] - for t2 in [MOI.VectorQuadraticFunction{T}] - @test MOIU.promote_operation(+, T, t1, t2) == MOI.VectorQuadraticFunction{T} - @test MOIU.promote_operation(-, T, t1, t2) == MOI.VectorQuadraticFunction{T} + + @testset "Vector promote tests" begin + T = Float64 + for t1 in [MOI.VectorAffineFunction{T}, MOI.VectorOfVariables, Vector{T}] + for t2 in [MOI.VectorAffineFunction{T}, MOI.VectorOfVariables] + @test MOIU.promote_operation(+, T, t1, t2) == MOI.VectorAffineFunction{T} + @test MOIU.promote_operation(-, T, t1, t2) == MOI.VectorAffineFunction{T} + end + end + for t1 in [MOI.VectorQuadraticFunction{T}, MOI.VectorAffineFunction{T}, + MOI.VectorOfVariables, Vector{T}] + for t2 in [MOI.VectorQuadraticFunction{T}] + @test MOIU.promote_operation(+, T, t1, t2) == MOI.VectorQuadraticFunction{T} + @test MOIU.promote_operation(-, T, t1, t2) == MOI.VectorQuadraticFunction{T} + end + end end - end - α = [1, 2, 3] - v = MOI.VectorOfVariables([y, w, y]) - g = MOI.VectorAffineFunction( - MOI.VectorAffineTerm.([3, 1], - MOI.ScalarAffineTerm.([5, 2], [y, x])), - [3, 1, 4]) - f = MOI.VectorQuadraticFunction( - MOI.VectorAffineTerm.([1, 2, 2], - MOI.ScalarAffineTerm.([3, 1, 2], [x, x, y])), - MOI.VectorQuadraticTerm.([1, 1, 2], - MOI.ScalarQuadraticTerm.([1, 2, 3], [x, y, x], [x, y, y])), - [7, 3, 4]) - v_plus_g = MOI.VectorAffineFunction( - MOI.VectorAffineTerm.([3, 1, 1, 2, 3], - MOI.ScalarAffineTerm.([5, 2, 1, 1, 1], [y, x, y, w, y])), - [3, 1, 4]) - g_plus_α = MOI.VectorAffineFunction( - MOI.VectorAffineTerm.([3, 1], - MOI.ScalarAffineTerm.([5, 2], [y, x])), - [4, 3, 7]) - α_minus_v = MOI.VectorAffineFunction( - MOI.VectorAffineTerm.([1, 2, 3], - MOI.ScalarAffineTerm.([-1, -1, -1], [y, w, y])), - [1, 2, 3]) - v_minus_v_plus_v = MOI.VectorAffineFunction( - MOI.VectorAffineTerm.([1, 2, 3, 1, 2, 3, 1, 2, 3], - MOI.ScalarAffineTerm.([1, 1, 1, -1, -1, -1, 1, 1, 1], - [y, w, y, y, w, y, y, w, y])), - [0, 0, 0]) - f_plus_α = MOI.VectorQuadraticFunction( - MOI.VectorAffineTerm.([1, 2, 2], - MOI.ScalarAffineTerm.([3, 1, 2], [x, x, y])), - MOI.VectorQuadraticTerm.([1, 1, 2], - MOI.ScalarQuadraticTerm.([1, 2, 3], [x, y, x], [x, y, y])), - [8, 5, 7]) - f_minus_g = MOI.VectorQuadraticFunction( - MOI.VectorAffineTerm.([1, 2, 2, 3, 1], - MOI.ScalarAffineTerm.([3, 1, 2, -5, -2], [x, x, y, y, x])), + α = [1, 2, 3] + v = MOI.VectorOfVariables([y, w, y]) + g = MOI.VectorAffineFunction( + MOI.VectorAffineTerm.([3, 1], + MOI.ScalarAffineTerm.([5, 2], [y, x])), + [3, 1, 4]) + f = MOI.VectorQuadraticFunction( + MOI.VectorAffineTerm.([1, 2, 2], + MOI.ScalarAffineTerm.([3, 1, 2], [x, x, y])), + MOI.VectorQuadraticTerm.([1, 1, 2], + MOI.ScalarQuadraticTerm.([1, 2, 3], [x, y, x], [x, y, y])), + [7, 3, 4]) + v_plus_g = MOI.VectorAffineFunction( + MOI.VectorAffineTerm.([3, 1, 1, 2, 3], + MOI.ScalarAffineTerm.([5, 2, 1, 1, 1], [y, x, y, w, y])), + [3, 1, 4]) + g_plus_α = MOI.VectorAffineFunction( + MOI.VectorAffineTerm.([3, 1], + MOI.ScalarAffineTerm.([5, 2], [y, x])), + [4, 3, 7]) + α_minus_v = MOI.VectorAffineFunction( + MOI.VectorAffineTerm.([1, 2, 3], + MOI.ScalarAffineTerm.([-1, -1, -1], [y, w, y])), + [1, 2, 3]) + v_minus_v_plus_v = MOI.VectorAffineFunction( + MOI.VectorAffineTerm.([1, 2, 3, 1, 2, 3, 1, 2, 3], + MOI.ScalarAffineTerm.([1, 1, 1, -1, -1, -1, 1, 1, 1], + [y, w, y, y, w, y, y, w, y])), + [0, 0, 0]) + f_plus_α = MOI.VectorQuadraticFunction( + MOI.VectorAffineTerm.([1, 2, 2], + MOI.ScalarAffineTerm.([3, 1, 2], [x, x, y])), MOI.VectorQuadraticTerm.([1, 1, 2], MOI.ScalarQuadraticTerm.([1, 2, 3], [x, y, x], [x, y, y])), - [4, 2, 0]) - @test v + g ≈ v_plus_g - @test g + α ≈ g_plus_α - @test α + g ≈ g_plus_α - @test α - v ≈ α_minus_v - @test MOIU.operate(+, T, MOIU.operate(-, T, v, v), v) ≈ v_minus_v_plus_v - @test f + α ≈ f_plus_α - @test f - g ≈ f_minus_g - @test f - f + f - g ≈ f_minus_g - @test v + f + α - v ≈ f_plus_α - @test v - f - α - v ≈ - f_plus_α - - @test v - α ≈ - α_minus_v - @test g - f ≈ - f_minus_g -end + [8, 5, 7]) + f_minus_g = MOI.VectorQuadraticFunction( + MOI.VectorAffineTerm.([1, 2, 2, 3, 1], + MOI.ScalarAffineTerm.([3, 1, 2, -5, -2], [x, x, y, y, x])), + MOI.VectorQuadraticTerm.([1, 1, 2], + MOI.ScalarQuadraticTerm.([1, 2, 3], [x, y, x], [x, y, y])), + [4, 2, 0]) + @test v + g ≈ v_plus_g + @test g + α ≈ g_plus_α + @test α + g ≈ g_plus_α + @test α - v ≈ α_minus_v + @test MOIU.operate(+, Int, MOIU.operate(-, Int, v, v), v) ≈ v_minus_v_plus_v + @test f + α ≈ f_plus_α + @test f - g ≈ f_minus_g + @test f - f + f - g ≈ f_minus_g + @test v + f + α - v ≈ f_plus_α + @test v - f - α - v ≈ - f_plus_α + @test MOIU.operate!(-, Int, v, f) - v ≈ - f + @test (g + v + g + v + f) - (v + g + v + g) ≈ f + @test v - α ≈ - α_minus_v + @test g - f ≈ - f_minus_g + end +end \ No newline at end of file From d6788e4f699ec7f496c506e6c4880c3d85206bad Mon Sep 17 00:00:00 2001 From: joaquimgarcia_psr Date: Mon, 21 Jan 2019 22:15:56 -0200 Subject: [PATCH 21/21] add number of variables and bridge tests --- src/Bridges/slackbridge.jl | 18 ++++++++++-------- test/bridge.jl | 14 +++++--------- 2 files changed, 15 insertions(+), 17 deletions(-) diff --git a/src/Bridges/slackbridge.jl b/src/Bridges/slackbridge.jl index f187adf364..9a290dee73 100644 --- a/src/Bridges/slackbridge.jl +++ b/src/Bridges/slackbridge.jl @@ -46,10 +46,11 @@ function concrete_bridge_type(::Type{<:ScalarSlackBridge{T}}, end # Attributes, Bridge acting as an model -MOI.get(b::ScalarSlackBridge{T, F, S}, ::MOI.NumberOfConstraints{F, MOI.EqualTo{T}}) where {T, F<:MOI.AbstractScalarFunction, S} = 1 -MOI.get(b::ScalarSlackBridge{T, F, S}, ::MOI.NumberOfConstraints{MOI.SingleVariable, S}) where {T, F<:MOI.AbstractScalarFunction, S} = 1 -MOI.get(b::ScalarSlackBridge{T, F, S}, ::MOI.ListOfConstraintIndices{F, MOI.EqualTo{T}}) where {T, F<:MOI.AbstractScalarFunction, S} = [b.equality] -MOI.get(b::ScalarSlackBridge{T, F, S}, ::MOI.ListOfConstraintIndices{MOI.SingleVariable, S}) where {T, F<:MOI.AbstractScalarFunction, S} = [b.slack_in_set] +MOI.get(b::ScalarSlackBridge{T, F, S}, ::MOI.NumberOfVariables) where {T, F, S} = 1 +MOI.get(b::ScalarSlackBridge{T, F, S}, ::MOI.NumberOfConstraints{F, MOI.EqualTo{T}}) where {T, F, S} = 1 +MOI.get(b::ScalarSlackBridge{T, F, S}, ::MOI.NumberOfConstraints{MOI.SingleVariable, S}) where {T, F, S} = 1 +MOI.get(b::ScalarSlackBridge{T, F, S}, ::MOI.ListOfConstraintIndices{F, MOI.EqualTo{T}}) where {T, F, S} = [b.equality] +MOI.get(b::ScalarSlackBridge{T, F, S}, ::MOI.ListOfConstraintIndices{MOI.SingleVariable, S}) where {T, F, S} = [b.slack_in_set] # Indices function MOI.delete(model::MOI.ModelLike, c::ScalarSlackBridge) @@ -133,10 +134,11 @@ function concrete_bridge_type(::Type{<:VectorSlackBridge{T}}, end # Attributes, Bridge acting as an model -MOI.get(b::VectorSlackBridge{T, F, S}, ::MOI.NumberOfConstraints{F, MOI.Zeros}) where {T, F<:MOI.AbstractVectorFunction, S} = 1 -MOI.get(b::VectorSlackBridge{T, F, S}, ::MOI.NumberOfConstraints{MOI.VectorOfVariables, S}) where {T, F<:MOI.AbstractVectorFunction, S} = 1 -MOI.get(b::VectorSlackBridge{T, F, S}, ::MOI.ListOfConstraintIndices{F, MOI.Zeros}) where {T, F<:MOI.AbstractVectorFunction, S} = [b.equality] -MOI.get(b::VectorSlackBridge{T, F, S}, ::MOI.ListOfConstraintIndices{MOI.VectorOfVariables, S}) where {T, F<:MOI.AbstractVectorFunction, S} = [b.slacks_in_set] +MOI.get(b::VectorSlackBridge{T, F, S}, ::MOI.NumberOfVariables) where {T, F, S} = length(b.slacks) +MOI.get(b::VectorSlackBridge{T, F, S}, ::MOI.NumberOfConstraints{F, MOI.Zeros}) where {T, F, S} = 1 +MOI.get(b::VectorSlackBridge{T, F, S}, ::MOI.NumberOfConstraints{MOI.VectorOfVariables, S}) where {T, F, S} = 1 +MOI.get(b::VectorSlackBridge{T, F, S}, ::MOI.ListOfConstraintIndices{F, MOI.Zeros}) where {T, F, S} = [b.equality] +MOI.get(b::VectorSlackBridge{T, F, S}, ::MOI.ListOfConstraintIndices{MOI.VectorOfVariables, S}) where {T, F, S} = [b.slacks_in_set] # Indices function MOI.delete(model::MOI.ModelLike, c::VectorSlackBridge) diff --git a/test/bridge.jl b/test/bridge.jl index f0e9dc163f..ba654d7b5f 100644 --- a/test/bridge.jl +++ b/test/bridge.jl @@ -343,6 +343,7 @@ end (MOI.ScalarAffineFunction{Float64}, MOI.LessThan{Float64}, 0))) end @testset "Scalar slack" begin + MOI.empty!(mock) bridgedmock = MOIB.ScalarSlack{Float64}(mock) x = MOI.add_variable(bridgedmock) y = MOI.add_variable(bridgedmock) @@ -358,6 +359,7 @@ end MOI.modify(bridgedmock, ci, MOI.ScalarConstantChange{Float64}(1.0)) @test MOI.get(bridgedmock, MOI.ConstraintFunction(), ci) ≈ MOI.ScalarAffineFunction(MOI.ScalarAffineTerm{Float64}.([2.0, 1.0], [x, y]), 1.0) + test_delete_bridge(bridgedmock, ci, 2, ((MOI.ScalarAffineFunction{Float64}, MOI.Interval{Float64}, 0),)) MOIT.basic_constraint_tests(bridgedmock, config, include=[(F, S) for @@ -395,14 +397,6 @@ end @test (MOI.SingleVariable, MOI.LessThan{Float64}) in loc @test (MOI.SingleVariable, MOI.GreaterThan{Float64}) in loc - # ci = first(MOI.get(bridgedmock, MOI.ListOfConstraintIndices{MOI.ScalarAffineFunction{Float64}, MOI.Interval{Float64}}())) - # newf = MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([1.0, -1.0], MOI.get(bridgedmock, MOI.ListOfVariableIndices())), 0.0) - # MOI.set(bridgedmock, MOI.ConstraintFunction(), ci, newf) - # @test MOI.get(bridgedmock, MOI.ConstraintFunction(), ci) ≈ newf - # deletion test wont work due to deleted variable - # test_delete_bridge(bridgedmock, ci, 2, ((MOI.ScalarAffineFunction{Float64}, MOI.GreaterThan{Float64}, 0), - # (MOI.ScalarAffineFunction{Float64}, MOI.LessThan{Float64}, 0))) - for T in [Int, Float64], S in [MOI.GreaterThan{T}, MOI.GreaterThan{T}] for F in [MOI.ScalarAffineFunction{T}, MOI.ScalarQuadraticFunction{T}] @test MOIB.added_constraint_types(MOIB.ScalarSlackBridge{T, F, S}) == [(F, MOI.EqualTo{T}), (MOI.SingleVariable, S)] @@ -411,6 +405,7 @@ end end @testset "Vector slack" begin + MOI.empty!(mock) bridgedmock = MOIB.VectorSlack{Float64}(mock) x = MOI.add_variable(bridgedmock) y = MOI.add_variable(bridgedmock) @@ -424,7 +419,8 @@ end MOI.modify(bridgedmock, ci, MOI.VectorConstantChange([1.0])) @test MOI.get(bridgedmock, MOI.ConstraintFunction(), ci) ≈ MOI.VectorAffineFunction(MOI.VectorAffineTerm.(1, MOI.ScalarAffineTerm.([2.0, 1.0], [x, y])), [1.0]) - # This power cone test is failing + test_delete_bridge(bridgedmock, ci, 2, ((MOI.VectorAffineFunction{Float64}, MOI.Zeros, 0),)) + fp = MOI.VectorAffineFunction(MOI.VectorAffineTerm.([1,2,3], MOI.ScalarAffineTerm.([1.0, 2.0, 3.0], [x, y, y])), [0.0, 0.0, 0.0]) cp = MOI.add_constraint(bridgedmock, fp, MOI.PowerCone(0.1)) @test MOI.get(bridgedmock, MOI.ConstraintSet(), cp) == MOI.PowerCone(0.1)