From 103aedee75611de4f8b9f9a5fb12c55d0e3c76cb Mon Sep 17 00:00:00 2001 From: Chris Coey Date: Fri, 6 Mar 2020 22:23:46 -0500 Subject: [PATCH 1/4] add norminf and normone tests --- src/Test/contconic.jl | 140 ++++++++++++++++++++++++++++++++++++++++- test/Test/contconic.jl | 38 +++++++++++ 2 files changed, 176 insertions(+), 2 deletions(-) diff --git a/src/Test/contconic.jl b/src/Test/contconic.jl index ea3bd140a1..5fe2de215e 100644 --- a/src/Test/contconic.jl +++ b/src/Test/contconic.jl @@ -432,9 +432,77 @@ function norminf2test(model::MOI.ModelLike, config::TestConfig) end end +function norminf3test(model::MOI.ModelLike, config::TestConfig) + atol = config.atol + rtol = config.rtol + # Problem NormInf3 + # min x + # st (-1 + x, 2 .+ y) in NormInf(1 + n) + # (1 .+ y) in Nonnegatives(n) + # let n = 3. optimal solution: y .= -1, x = 2 + + @test MOIU.supports_default_copy_to(model, #=copy_names=# false) + @test MOI.supports(model, MOI.ObjectiveFunction{MOI.SingleVariable}()) + @test MOI.supports(model, MOI.ObjectiveSense()) + @test MOI.supports_constraint(model, MOI.VectorAffineFunction{Float64}, MOI.NormInfinityCone) + + MOI.empty!(model) + @test MOI.is_empty(model) + + x = MOI.add_variable(model) + y = MOI.add_variables(model, 3) + + MOI.set(model, MOI.ObjectiveFunction{MOI.SingleVariable}(), MOI.SingleVariable(x)) + MOI.set(model, MOI.ObjectiveSense(), MOI.MIN_SENSE) + + norminf_vaf = MOI.VectorAffineFunction(MOI.VectorAffineTerm.(1:4, + MOI.ScalarAffineTerm.(1.0, vcat(x, y))), [-1.0, 2, 2, 2]) + norminf = MOI.add_constraint(model, norminf_vaf, MOI.NormInfinityCone(4)) + nonneg_vaf = MOI.VectorAffineFunction(MOI.VectorAffineTerm.(1:3, + MOI.ScalarAffineTerm.(1.0, y)), ones(3)) + nonneg = MOI.add_constraint(model, nonneg_vaf, MOI.Nonnegatives(3)) + + @test MOI.get(model, MOI.NumberOfConstraints{MOI.VectorAffineFunction{Float64}, MOI.NormInfinityCone}()) == 1 + @test MOI.get(model, MOI.NumberOfConstraints{MOI.VectorAffineFunction{Float64}, MOI.Nonnegatives}()) == 1 + loc = MOI.get(model, MOI.ListOfConstraints()) + @test length(loc) == 2 + @test (MOI.VectorAffineFunction{Float64}, MOI.NormInfinityCone) in loc + @test (MOI.VectorAffineFunction{Float64}, MOI.Nonnegatives) in loc + + if config.solve + @test MOI.get(model, MOI.TerminationStatus()) == MOI.OPTIMIZE_NOT_CALLED + + MOI.optimize!(model) + + @test MOI.get(model, MOI.TerminationStatus()) == config.optimal_status + + @test MOI.get(model, MOI.PrimalStatus()) == MOI.FEASIBLE_POINT + if config.duals + @test MOI.get(model, MOI.DualStatus()) == MOI.FEASIBLE_POINT + end + + @test MOI.get(model, MOI.ObjectiveValue()) ≈ 2 atol=atol rtol=rtol + if config.dual_objective_value + @test MOI.get(model, MOI.DualObjectiveValue()) ≈ 2 atol=atol rtol=rtol + end + + @test MOI.get(model, MOI.VariablePrimal(), x) ≈ 2 atol=atol rtol=rtol + @test MOI.get(model, MOI.VariablePrimal(), y) ≈ fill(-1.0, 3) atol=atol rtol=rtol + + @test MOI.get(model, MOI.ConstraintPrimal(), norminf) ≈ ones(4) atol=atol rtol=rtol + @test MOI.get(model, MOI.ConstraintPrimal(), nonneg) ≈ zeros(3) atol=atol rtol=rtol + + if config.duals + @test MOI.get(model, MOI.ConstraintDual(), norminf) ≈ vcat(1, fill(-inv(3), 3)) atol=atol rtol=rtol + @test MOI.get(model, MOI.ConstraintDual(), nonneg) ≈ fill(inv(3), 3) atol=atol rtol=rtol + end + end +end + const norminftests = Dict("norminf1v" => norminf1vtest, "norminf1f" => norminf1ftest, - "norminf2" => norminf2test) + "norminf2" => norminf2test, + "norminf3" => norminf3test) @moitestset norminf @@ -568,9 +636,77 @@ function normone2test(model::MOI.ModelLike, config::TestConfig) end end +function normone3test(model::MOI.ModelLike, config::TestConfig) + atol = config.atol + rtol = config.rtol + # Problem NormOne3 + # min x + # st (-1 + x, 2 .+ y) in NormOne(1 + n) + # (1 .+ y) in Nonnegatives(n) + # let n = 3. optimal solution: y .= -1, x = 4 + + @test MOIU.supports_default_copy_to(model, #=copy_names=# false) + @test MOI.supports(model, MOI.ObjectiveFunction{MOI.SingleVariable}()) + @test MOI.supports(model, MOI.ObjectiveSense()) + @test MOI.supports_constraint(model, MOI.VectorAffineFunction{Float64}, MOI.NormOneCone) + + MOI.empty!(model) + @test MOI.is_empty(model) + + x = MOI.add_variable(model) + y = MOI.add_variables(model, 3) + + MOI.set(model, MOI.ObjectiveFunction{MOI.SingleVariable}(), MOI.SingleVariable(x)) + MOI.set(model, MOI.ObjectiveSense(), MOI.MIN_SENSE) + + norminf_vaf = MOI.VectorAffineFunction(MOI.VectorAffineTerm.(1:4, + MOI.ScalarAffineTerm.(1.0, vcat(x, y))), [-1.0, 2, 2, 2]) + norminf = MOI.add_constraint(model, norminf_vaf, MOI.NormOneCone(4)) + nonneg_vaf = MOI.VectorAffineFunction(MOI.VectorAffineTerm.(1:3, + MOI.ScalarAffineTerm.(1.0, y)), ones(3)) + nonneg = MOI.add_constraint(model, nonneg_vaf, MOI.Nonnegatives(3)) + + @test MOI.get(model, MOI.NumberOfConstraints{MOI.VectorAffineFunction{Float64}, MOI.NormOneCone}()) == 1 + @test MOI.get(model, MOI.NumberOfConstraints{MOI.VectorAffineFunction{Float64}, MOI.Nonnegatives}()) == 1 + loc = MOI.get(model, MOI.ListOfConstraints()) + @test length(loc) == 2 + @test (MOI.VectorAffineFunction{Float64}, MOI.NormOneCone) in loc + @test (MOI.VectorAffineFunction{Float64}, MOI.Nonnegatives) in loc + + if config.solve + @test MOI.get(model, MOI.TerminationStatus()) == MOI.OPTIMIZE_NOT_CALLED + + MOI.optimize!(model) + + @test MOI.get(model, MOI.TerminationStatus()) == config.optimal_status + + @test MOI.get(model, MOI.PrimalStatus()) == MOI.FEASIBLE_POINT + if config.duals + @test MOI.get(model, MOI.DualStatus()) == MOI.FEASIBLE_POINT + end + + @test MOI.get(model, MOI.ObjectiveValue()) ≈ 4 atol=atol rtol=rtol + if config.dual_objective_value + @test MOI.get(model, MOI.DualObjectiveValue()) ≈ 4 atol=atol rtol=rtol + end + + @test MOI.get(model, MOI.VariablePrimal(), x) ≈ 4 atol=atol rtol=rtol + @test MOI.get(model, MOI.VariablePrimal(), y) ≈ fill(-1.0, 3) atol=atol rtol=rtol + + @test MOI.get(model, MOI.ConstraintPrimal(), norminf) ≈ vcat(3, ones(3)) atol=atol rtol=rtol + @test MOI.get(model, MOI.ConstraintPrimal(), nonneg) ≈ zeros(3) atol=atol rtol=rtol + + if config.duals + @test MOI.get(model, MOI.ConstraintDual(), norminf) ≈ vcat(1, fill(-1, 3)) atol=atol rtol=rtol + @test MOI.get(model, MOI.ConstraintDual(), nonneg) ≈ ones(3) atol=atol rtol=rtol + end + end +end + const normonetests = Dict("normone1v" => normone1vtest, "normone1f" => normone1ftest, - "normone2" => normone2test) + "normone2" => normone2test, + "normone3" => normone3test) @moitestset normone diff --git a/test/Test/contconic.jl b/test/Test/contconic.jl index a39e23b58e..d1628b1b2a 100644 --- a/test/Test/contconic.jl +++ b/test/Test/contconic.jl @@ -36,6 +36,44 @@ config = MOIT.TestConfig() mock.optimize! = (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, MOI.INFEASIBLE_OR_UNBOUNDED) MOIT.lin4test(mock, MOIT.TestConfig(infeas_certificates=false)) end +@testset "NormInf" begin + mock.optimize! = (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, + [1, 0.5, 1], + (MOI.VectorAffineFunction{Float64}, MOI.Zeros) => [[-1], [-1]], + (MOI.VectorOfVariables, MOI.NormInfinityCone) => [[1, 0, -1]]) + MOIT.norminf1vtest(mock, config) + mock.optimize! = (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, + [1, 0.5, 1], + (MOI.VectorAffineFunction{Float64}, MOI.Zeros) => [[-1], [-1]], + (MOI.VectorAffineFunction{Float64}, MOI.NormInfinityCone) => [[1, 0, -1]]) + MOIT.norminf1ftest(mock, config) + mock.optimize! = (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, MOI.INFEASIBLE, MOI.INFEASIBLE_POINT, MOI.INFEASIBILITY_CERTIFICATE) + MOIT.norminf2test(mock, config) + mock.optimize! = (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, + [2, -1, -1, -1], + (MOI.VectorAffineFunction{Float64}, MOI.NormInfinityCone) => [vcat(1, fill(-inv(3), 3))], + (MOI.VectorAffineFunction{Float64}, MOI.Nonnegatives) => [fill(inv(3), 3)]) + MOIT.norminf3test(mock, config) +end +@testset "NormOne" begin + mock.optimize! = (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, + [1, 0.5, 0.5], + (MOI.VectorAffineFunction{Float64}, MOI.Zeros) => [[-1], [0]], + (MOI.VectorOfVariables, MOI.NormOneCone) => [[1, -1, -1]]) + MOIT.normone1vtest(mock, config) + mock.optimize! = (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, + [1, 0.5, 0.5], + (MOI.VectorAffineFunction{Float64}, MOI.Zeros) => [[-1], [0]], + (MOI.VectorAffineFunction{Float64}, MOI.NormOneCone) => [[1, -1, -1]]) + MOIT.normone1ftest(mock, config) + mock.optimize! = (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, MOI.INFEASIBLE, MOI.INFEASIBLE_POINT, MOI.INFEASIBILITY_CERTIFICATE) + MOIT.normone2test(mock, config) + mock.optimize! = (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, + [4, -1, -1, -1], + (MOI.VectorAffineFunction{Float64}, MOI.NormOneCone) => [vcat(1, fill(-1, 3))], + (MOI.VectorAffineFunction{Float64}, MOI.Nonnegatives) => [ones(3)]) + MOIT.normone3test(mock, config) +end @testset "SOC" begin mock.optimize! = (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [1.0, 1/√2, 1/√2], (MOI.VectorAffineFunction{Float64}, MOI.Zeros) => [[-√2]]) From bdb9720b43a53be14d4dd6a6707b3d8502616d1b Mon Sep 17 00:00:00 2001 From: Chris Coey Date: Fri, 6 Mar 2020 22:58:54 -0500 Subject: [PATCH 2/4] fix bug in get primal for norminf to lp bridge --- src/Bridges/Constraint/norm_to_lp.jl | 66 ++++++++++++---------------- 1 file changed, 28 insertions(+), 38 deletions(-) diff --git a/src/Bridges/Constraint/norm_to_lp.jl b/src/Bridges/Constraint/norm_to_lp.jl index ca051095ba..416749ae5f 100644 --- a/src/Bridges/Constraint/norm_to_lp.jl +++ b/src/Bridges/Constraint/norm_to_lp.jl @@ -70,69 +70,61 @@ The `NormOneCone` is representable with LP constraints, since ``t \\ge \\sum_i \\lvert x_i \\rvert`` if and only if there exists a vector y such that ``t \\ge \\sum_i y_i`` and ``y_i \\ge x_i``, ``y_i \\ge -x_i`` for all ``i``. """ -struct NormOneBridge{T, F, G, H} <: AbstractBridge +struct NormOneBridge{T, F, G} <: AbstractBridge y::Vector{MOI.VariableIndex} - ge_index::CI{F, MOI.GreaterThan{T}} - nn_index::CI{G, MOI.Nonnegatives} + nn_index::CI{F, MOI.Nonnegatives} end -function bridge_constraint(::Type{NormOneBridge{T, F, G, H}}, model::MOI.ModelLike, f::H, s::MOI.NormOneCone) where {T, F, G, H} +function bridge_constraint(::Type{NormOneBridge{T, F, G}}, model::MOI.ModelLike, f::G, s::MOI.NormOneCone) where {T, F, G} f_scalars = MOIU.eachscalar(f) d = MOI.dimension(s) y = MOI.add_variables(model, d - 1) - ge_index = MOIU.normalize_and_add_constraint(model, MOIU.operate(-, T, f_scalars[1], MOIU.operate(sum, T, y)), MOI.GreaterThan(zero(T)), allow_modify_function=true) + ge = MOIU.operate(-, T, f_scalars[1], MOIU.operate(sum, T, y)) lb = f_scalars[2:d] ub = MOIU.operate(-, T, lb) lb = MOIU.operate!(+, T, lb, MOI.VectorOfVariables(y)) ub = MOIU.operate!(+, T, ub, MOI.VectorOfVariables(y)) - f_new = MOIU.operate(vcat, T, ub, lb) - nn_index = MOI.add_constraint(model, f_new, MOI.Nonnegatives(2d - 2)) - return NormOneBridge{T, F, G, H}(y, ge_index, nn_index) + f_new = MOIU.operate(vcat, T, ge, ub, lb) + nn_index = MOI.add_constraint(model, f_new, MOI.Nonnegatives(2d - 1)) + return NormOneBridge{T, F, G}(y, nn_index) end MOI.supports_constraint(::Type{NormOneBridge{T}}, ::Type{<:MOI.AbstractVectorFunction}, ::Type{MOI.NormOneCone}) where T = true MOIB.added_constrained_variable_types(::Type{<:NormOneBridge}) = Tuple{DataType}[] -MOIB.added_constraint_types(::Type{NormOneBridge{T, F, G, H}}) where {T, F, G, H} = [(F, MOI.GreaterThan{T}), (G, MOI.Nonnegatives)] -function concrete_bridge_type(::Type{<:NormOneBridge{T}}, H::Type{<:MOI.AbstractVectorFunction}, ::Type{MOI.NormOneCone}) where T - S = MOIU.scalar_type(H) - F = MOIU.promote_operation(+, T, S, S) - G = MOIU.promote_operation(+, T, H, H) - return NormOneBridge{T, F, G, H} +MOIB.added_constraint_types(::Type{NormOneBridge{T, F}}) where {T, F} = [(F, MOI.Nonnegatives)] +function concrete_bridge_type(::Type{<:NormOneBridge{T}}, G::Type{<:MOI.AbstractVectorFunction}, ::Type{MOI.NormOneCone}) where T + S = MOIU.scalar_type(G) + F = MOIU.promote_operation(vcat, T, MOIU.promote_operation(+, T, S, S), MOIU.promote_operation(-, T, S, S)) + return NormOneBridge{T, F, G} end # Attributes, Bridge acting as a model MOI.get(b::NormOneBridge, ::MOI.NumberOfVariables) = length(b.y) MOI.get(b::NormOneBridge, ::MOI.ListOfVariableIndices) = b.y -MOI.get(b::NormOneBridge{T, F, G, H}, ::MOI.NumberOfConstraints{F, MOI.GreaterThan{T}}) where {T, F, G, H} = 1 -MOI.get(b::NormOneBridge{T, F, G, H}, ::MOI.NumberOfConstraints{G, MOI.Nonnegatives}) where {T, F, G, H} = 1 -MOI.get(b::NormOneBridge{T, F, G, H}, ::MOI.ListOfConstraintIndices{F, MOI.GreaterThan{T}}) where {T, F, G, H} = [b.ge_index] -MOI.get(b::NormOneBridge{T, F, G, H}, ::MOI.ListOfConstraintIndices{G, MOI.Nonnegatives}) where {T, F, G, H} = [b.nn_index] +MOI.get(b::NormOneBridge{T, F}, ::MOI.NumberOfConstraints{F, MOI.Nonnegatives}) where {T, F} = 1 +MOI.get(b::NormOneBridge{T, F}, ::MOI.ListOfConstraintIndices{F, MOI.Nonnegatives}) where {T, F} = [b.nn_index] # References function MOI.delete(model::MOI.ModelLike, c::NormOneBridge) MOI.delete(model, c.nn_index) - MOI.delete(model, c.ge_index) MOI.delete(model, c.y) end # Attributes, Bridge acting as a constraint -function MOI.get(model::MOI.ModelLike, ::MOI.ConstraintFunction, c::NormOneBridge{T, F, G, H}) where {T, F, G, H} - ge_func = MOI.get(model, MOI.ConstraintFunction(), c.ge_index) +function MOI.get(model::MOI.ModelLike, ::MOI.ConstraintFunction, c::NormOneBridge{T, F, G}) where {T, F, G} nn_func = MOIU.eachscalar(MOI.get(model, MOI.ConstraintFunction(), c.nn_index)) - t = MOIU.operate!(+, T, ge_func, MOIU.operate!(/, T, sum(nn_func), T(2))) - d = div(length(nn_func), 2) - x = MOIU.operate!(/, T, MOIU.operate!(-, T, nn_func[(d + 1):end], nn_func[1:d]), T(2)) - return MOIU.convert_approx(H, MOIU.remove_variable(MOIU.operate(vcat, T, t, x), c.y)) + t = MOIU.operate!(/, T, nn_func[1] + sum(nn_func), T(2)) + d = div(length(nn_func) - 1, 2) + x = MOIU.operate!(/, T, MOIU.operate!(-, T, nn_func[(d + 2):end], nn_func[2:(d + 1)]), T(2)) + return MOIU.convert_approx(G, MOIU.remove_variable(MOIU.operate(vcat, T, t, x), c.y)) end function MOI.get(model::MOI.ModelLike, ::MOI.ConstraintSet, c::NormOneBridge) - dim = 1 + div(MOI.dimension(MOI.get(model, MOI.ConstraintSet(), c.nn_index)), 2) + dim = div(MOI.dimension(MOI.get(model, MOI.ConstraintSet(), c.nn_index)) + 1, 2) return MOI.NormOneCone(dim) end - function MOI.supports( ::MOI.ModelLike, ::Union{MOI.ConstraintPrimalStart, MOI.ConstraintDualStart}, ::Type{<:NormOneBridge}) - return true end function MOI.set(model::MOI.ModelLike, attr::MOI.ConstraintPrimalStart, @@ -142,18 +134,17 @@ function MOI.set(model::MOI.ModelLike, attr::MOI.ConstraintPrimalStart, for i in eachindex(bridge.y) MOI.set(model, MOI.VariablePrimalStart(), bridge.y[i], y_value[i]) end - MOI.set(model, attr, bridge.nn_index, [y_value - x_value; y_value + x_value]) - MOI.set(model, attr, bridge.ge_index, value[1] - reduce(+, y_value, init=zero(T))) + nn_value = vcat(value[1] - reduce(+, y_value, init=zero(T)), y_value - x_value, y_value + x_value) + MOI.set(model, attr, bridge.nn_index, nn_value) return end function MOI.get(model::MOI.ModelLike, attr::Union{MOI.ConstraintPrimal, MOI.ConstraintPrimalStart}, bridge::NormOneBridge) - ge_primal = MOI.get(model, attr, bridge.ge_index) nn_primal = MOI.get(model, attr, bridge.nn_index) - t = ge_primal + sum(nn_primal) / 2 + t = (nn_primal[1] + sum(nn_primal)) / 2 d = length(bridge.y) - x = (nn_primal[(d + 1):end] - nn_primal[1:d]) / 2 + x = (nn_primal[(d + 2):end] - nn_primal[2:(d + 1)]) / 2 return vcat(t, x) end # Given a_i is dual on y_i - x_i >= 0 and b_i is dual on y_i + x_i >= 0 and c is dual on t - sum(y) >= 0, @@ -162,11 +153,10 @@ end function MOI.get(model::MOI.ModelLike, attr::Union{MOI.ConstraintDual, MOI.ConstraintDualStart}, bridge::NormOneBridge) - t = MOI.get(model, attr, bridge.ge_index) nn_dual = MOI.get(model, attr, bridge.nn_index) d = length(bridge.y) - x = nn_dual[(d + 1):end] - nn_dual[1:d] - return vcat(t, x) + x = nn_dual[(d + 2):end] - nn_dual[2:(d + 1)] + return vcat(nn_dual[1], x) end # value[1 + i] = nn_dual[d + i] - nn_dual[i] # and `nn_dual` is nonnegative. By complementarity slackness, only one of each @@ -174,9 +164,9 @@ end # depending on the sense of `value[1 + i]`. function MOI.set(model::MOI.ModelLike, ::MOI.ConstraintDualStart, bridge::NormOneBridge, value) - t = MOI.set(model, MOI.ConstraintDualStart(), bridge.ge_index, value[1]) d = length(bridge.y) - nn_dual = zeros(eltype(value), 2d) + nn_dual = zeros(eltype(value), 2d + 1) + nn_dual[1] = value[1] for i in eachindex(bridge.y) v = value[1 + i] if v < 0 From 02b107c5ee1f90a6c979442b92d4e8462de83891 Mon Sep 17 00:00:00 2001 From: Chris Coey Date: Sat, 7 Mar 2020 01:59:27 -0500 Subject: [PATCH 3/4] add/fix bridge tests --- src/Bridges/Constraint/norm_to_lp.jl | 10 +- test/Bridges/Constraint/norm_to_lp.jl | 395 +++++++++++++++++--------- 2 files changed, 270 insertions(+), 135 deletions(-) diff --git a/src/Bridges/Constraint/norm_to_lp.jl b/src/Bridges/Constraint/norm_to_lp.jl index 416749ae5f..0245ce1549 100644 --- a/src/Bridges/Constraint/norm_to_lp.jl +++ b/src/Bridges/Constraint/norm_to_lp.jl @@ -88,9 +88,9 @@ function bridge_constraint(::Type{NormOneBridge{T, F, G}}, model::MOI.ModelLike, return NormOneBridge{T, F, G}(y, nn_index) end -MOI.supports_constraint(::Type{NormOneBridge{T}}, ::Type{<:MOI.AbstractVectorFunction}, ::Type{MOI.NormOneCone}) where T = true +MOI.supports_constraint(::Type{<:NormOneBridge{T}}, ::Type{<:MOI.AbstractVectorFunction}, ::Type{MOI.NormOneCone}) where T = true MOIB.added_constrained_variable_types(::Type{<:NormOneBridge}) = Tuple{DataType}[] -MOIB.added_constraint_types(::Type{NormOneBridge{T, F}}) where {T, F} = [(F, MOI.Nonnegatives)] +MOIB.added_constraint_types(::Type{<:NormOneBridge{T, F}}) where {T, F} = [(F, MOI.Nonnegatives)] function concrete_bridge_type(::Type{<:NormOneBridge{T}}, G::Type{<:MOI.AbstractVectorFunction}, ::Type{MOI.NormOneCone}) where T S = MOIU.scalar_type(G) F = MOIU.promote_operation(vcat, T, MOIU.promote_operation(+, T, S, S), MOIU.promote_operation(-, T, S, S)) @@ -158,7 +158,7 @@ function MOI.get(model::MOI.ModelLike, x = nn_dual[(d + 2):end] - nn_dual[2:(d + 1)] return vcat(nn_dual[1], x) end -# value[1 + i] = nn_dual[d + i] - nn_dual[i] +# value[1 + i] = nn_dual[1 + d + i] - nn_dual[1 + i] # and `nn_dual` is nonnegative. By complementarity slackness, only one of each # `nn_dual` can be nonzero (except if `x = 0`) so we can set # depending on the sense of `value[1 + i]`. @@ -170,9 +170,9 @@ function MOI.set(model::MOI.ModelLike, ::MOI.ConstraintDualStart, for i in eachindex(bridge.y) v = value[1 + i] if v < 0 - nn_dual[i] = -v + nn_dual[1 + i] = -v else - nn_dual[d + i] = v + nn_dual[1 + d + i] = v end end MOI.set(model, MOI.ConstraintDualStart(), bridge.nn_index, nn_dual) diff --git a/test/Bridges/Constraint/norm_to_lp.jl b/test/Bridges/Constraint/norm_to_lp.jl index 0e328e05fb..9bc4eab57b 100644 --- a/test/Bridges/Constraint/norm_to_lp.jl +++ b/test/Bridges/Constraint/norm_to_lp.jl @@ -19,69 +19,146 @@ config = MOIT.TestConfig() MOI.VectorOfVariables, MOI.VectorAffineFunction{Float64}, MOI.VectorQuadraticFunction{Float64} ]]) - mock.optimize! = (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [1.0, 0.5, 1.0], - (MOI.VectorAffineFunction{Float64}, MOI.Nonnegatives) => [[0.0, 1.0, 0.0, 0.0]], - (MOI.VectorAffineFunction{Float64}, MOI.Zeros) => [[-1], [-1]]) + @testset "norminf1test" begin + mock.optimize! = (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, + [1.0, 0.5, 1.0], + (MOI.VectorAffineFunction{Float64}, MOI.Nonnegatives) => [[0.0, 1.0, 0.0, 0.0]], + (MOI.VectorAffineFunction{Float64}, MOI.Zeros) => [[-1], [-1]]) - MOIT.norminf1vtest(bridged_mock, config) - MOIT.norminf1ftest(bridged_mock, config) + MOIT.norminf1vtest(bridged_mock, config) + MOIT.norminf1ftest(bridged_mock, config) - @testset "Test mock model" begin var_names = ["x", "y", "z"] - MOI.set(mock, MOI.VariableName(), MOI.get(mock, MOI.ListOfVariableIndices()), var_names) + + @testset "Test mock model" begin + MOI.set(mock, MOI.VariableName(), MOI.get(mock, MOI.ListOfVariableIndices()), var_names) + nonneg = MOI.get(mock, MOI.ListOfConstraintIndices{MOI.VectorAffineFunction{Float64}, MOI.Nonnegatives}()) + @test length(nonneg) == 1 + MOI.set(mock, MOI.ConstraintName(), nonneg[1], "nonneg") + zeros = MOI.get(mock, MOI.ListOfConstraintIndices{MOI.VectorAffineFunction{Float64}, MOI.Zeros}()) + @test length(zeros) == 2 + MOI.set(mock, MOI.ConstraintName(), zeros[1], "x_eq") + MOI.set(mock, MOI.ConstraintName(), zeros[2], "y_eq") + + s = """ + variables: x, y, z + nonneg: [x + -1.0y, x + -1.0z, x + y, x + z] in MathOptInterface.Nonnegatives(4) + x_eq: [-1.0 + x] in MathOptInterface.Zeros(1) + y_eq: [-0.5 + y] in MathOptInterface.Zeros(1) + maxobjective: y + z + """ + model = MOIU.Model{Float64}() + MOIU.loadfromstring!(model, s) + MOIU.test_models_equal(mock, model, var_names, ["nonneg", "x_eq", "y_eq"]) + end + + @testset "Test bridged model" begin + MOI.set(bridged_mock, MOI.VariableName(), MOI.get(bridged_mock, MOI.ListOfVariableIndices()), var_names) + norminf = MOI.get(bridged_mock, MOI.ListOfConstraintIndices{MOI.VectorAffineFunction{Float64}, MOI.NormInfinityCone}()) + @test length(norminf) == 1 + MOI.set(bridged_mock, MOI.ConstraintName(), norminf[1], "norminf") + zeros = MOI.get(bridged_mock, MOI.ListOfConstraintIndices{MOI.VectorAffineFunction{Float64}, MOI.Zeros}()) + @test length(zeros) == 2 + MOI.set(bridged_mock, MOI.ConstraintName(), zeros[1], "x_eq") + MOI.set(bridged_mock, MOI.ConstraintName(), zeros[2], "y_eq") + + s = """ + variables: x, y, z + norminf: [1.0x, y, z] in MathOptInterface.NormInfinityCone(3) + x_eq: [-1.0 + x] in MathOptInterface.Zeros(1) + y_eq: [-0.5 + y] in MathOptInterface.Zeros(1) + maxobjective: y + z + """ + model = MOIU.Model{Float64}() + MOIU.loadfromstring!(model, s) + MOIU.test_models_equal(bridged_mock, model, var_names, ["norminf", "x_eq", "y_eq"]) + end + + ci = first(MOI.get(bridged_mock, MOI.ListOfConstraintIndices{MOI.VectorAffineFunction{Float64}, MOI.NormInfinityCone}())) nonneg = MOI.get(mock, MOI.ListOfConstraintIndices{MOI.VectorAffineFunction{Float64}, MOI.Nonnegatives}()) - @test length(nonneg) == 1 - MOI.set(mock, MOI.ConstraintName(), nonneg[1], "nonneg") - zeros = MOI.get(mock, MOI.ListOfConstraintIndices{MOI.VectorAffineFunction{Float64}, MOI.Zeros}()) - @test length(zeros) == 2 - MOI.set(mock, MOI.ConstraintName(), zeros[1], "x_eq") - MOI.set(mock, MOI.ConstraintName(), zeros[2], "y_eq") - - s = """ - variables: x, y, z - nonneg: [x + -1.0y, x + -1.0z, x + y, x + z] in MathOptInterface.Nonnegatives(4) - x_eq: [-1.0 + x] in MathOptInterface.Zeros(1) - y_eq: [-0.5 + y] in MathOptInterface.Zeros(1) - maxobjective: y + z - """ - model = MOIU.Model{Float64}() - MOIU.loadfromstring!(model, s) - MOIU.test_models_equal(mock, model, var_names, ["nonneg", "x_eq", "y_eq"]) - end - @testset "Test bridged model" begin - var_names = ["x", "y", "z"] - MOI.set(bridged_mock, MOI.VariableName(), MOI.get(bridged_mock, MOI.ListOfVariableIndices()), var_names) - norminf = MOI.get(bridged_mock, MOI.ListOfConstraintIndices{MOI.VectorAffineFunction{Float64}, MOI.NormInfinityCone}()) - @test length(norminf) == 1 - MOI.set(bridged_mock, MOI.ConstraintName(), norminf[1], "norminf") - zeros = MOI.get(bridged_mock, MOI.ListOfConstraintIndices{MOI.VectorAffineFunction{Float64}, MOI.Zeros}()) - @test length(zeros) == 2 - MOI.set(bridged_mock, MOI.ConstraintName(), zeros[1], "x_eq") - MOI.set(bridged_mock, MOI.ConstraintName(), zeros[2], "y_eq") - - s = """ - variables: x, y, z - norminf: [1.0x, y, z] in MathOptInterface.NormInfinityCone(3) - x_eq: [-1.0 + x] in MathOptInterface.Zeros(1) - y_eq: [-0.5 + y] in MathOptInterface.Zeros(1) - maxobjective: y + z - """ - model = MOIU.Model{Float64}() - MOIU.loadfromstring!(model, s) - MOIU.test_models_equal(bridged_mock, model, var_names, ["norminf", "x_eq", "y_eq"]) + @testset "$attr" for attr in [MOI.ConstraintPrimalStart(), MOI.ConstraintDualStart()] + @test MOI.supports(bridged_mock, attr, typeof(ci)) + value = [4.0, 1.0, -2.0] + MOI.set(bridged_mock, attr, ci, value) + @test MOI.get(bridged_mock, attr, ci) ≈ value + if attr isa MOI.ConstraintPrimalStart + nonneg_value = Float64[3, 6, 5, 2] + else + nonneg_value = [0.25, 2.25, 1.25, 0.25] + end + @test MOI.get(mock, attr, nonneg[1]) ≈ nonneg_value + end + + test_delete_bridge(bridged_mock, ci, 3, ( + (MOI.VectorAffineFunction{Float64}, MOI.Nonnegatives, 0),)) end - ci = first(MOI.get(bridged_mock, MOI.ListOfConstraintIndices{MOI.VectorAffineFunction{Float64}, MOI.NormInfinityCone}())) + @testset "norminf3test" begin + mock.optimize! = (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, + [2, -1, -1, -1], + (MOI.VectorAffineFunction{Float64}, MOI.Nonnegatives) => [vcat(fill(inv(3), 3), zeros(3)), fill(inv(3), 3)]) + MOIT.norminf3test(bridged_mock, config) - @testset "$attr" for attr in [MOI.ConstraintPrimalStart(), MOI.ConstraintDualStart()] - @test MOI.supports(bridged_mock, attr, typeof(ci)) - value = [4.0, 1.0, -2.0] - MOI.set(bridged_mock, attr, ci, value) - @test MOI.get(bridged_mock, attr, ci) ≈ value - end + var_names = ["x", "y1", "y2", "y3"] - test_delete_bridge(bridged_mock, ci, 3, ((MOI.VectorAffineFunction{Float64}, MOI.Nonnegatives, 0),)) + @testset "Test mock model" begin + MOI.set(mock, MOI.VariableName(), MOI.get(mock, MOI.ListOfVariableIndices()), var_names) + nonneg = MOI.get(mock, MOI.ListOfConstraintIndices{MOI.VectorAffineFunction{Float64}, MOI.Nonnegatives}()) + @test length(nonneg) == 2 + MOI.set(mock, MOI.ConstraintName(), nonneg[1], "nonneg1") + MOI.set(mock, MOI.ConstraintName(), nonneg[2], "nonneg2") + + s = """ + variables: x, y1, y2, y3 + nonneg1: [x + -1.0y1 + -3.0, x + -1.0y2 + -3.0, x + -1.0y3 + -3.0, x + y1 + 1.0, x + y2 + 1.0, x + y3 + 1.0] in MathOptInterface.Nonnegatives(6) + nonneg2: [y1 + 1.0, y2 + 1.0, y3 + 1.0] in MathOptInterface.Nonnegatives(3) + minobjective: x + """ + model = MOIU.Model{Float64}() + MOIU.loadfromstring!(model, s) + MOIU.test_models_equal(mock, model, var_names, ["nonneg1", "nonneg2"]) + end + + @testset "Test bridged model" begin + MOI.set(bridged_mock, MOI.VariableName(), MOI.get(bridged_mock, MOI.ListOfVariableIndices()), var_names) + norminf = MOI.get(bridged_mock, MOI.ListOfConstraintIndices{MOI.VectorAffineFunction{Float64}, MOI.NormInfinityCone}()) + @test length(norminf) == 1 + MOI.set(bridged_mock, MOI.ConstraintName(), norminf[1], "norminf") + nonneg = MOI.get(bridged_mock, MOI.ListOfConstraintIndices{MOI.VectorAffineFunction{Float64}, MOI.Nonnegatives}()) + @test length(nonneg) == 1 + MOI.set(bridged_mock, MOI.ConstraintName(), nonneg[1], "nonneg") + + s = """ + variables: x, y1, y2, y3 + norminf: [x + -1.0, y1 + 2.0, y2 + 2.0, y3 + 2.0] in MathOptInterface.NormInfinityCone(4) + nonneg: [y1 + 1.0, y2 + 1.0, y3 + 1.0] in MathOptInterface.Nonnegatives(3) + minobjective: x + """ + model = MOIU.Model{Float64}() + MOIU.loadfromstring!(model, s) + MOIU.test_models_equal(bridged_mock, model, var_names, ["norminf", "nonneg"]) + end + + ci = first(MOI.get(bridged_mock, MOI.ListOfConstraintIndices{MOI.VectorAffineFunction{Float64}, MOI.NormInfinityCone}())) + nonneg = MOI.get(mock, MOI.ListOfConstraintIndices{MOI.VectorAffineFunction{Float64}, MOI.Nonnegatives}()) + + @testset "$attr" for attr in [MOI.ConstraintPrimalStart(), MOI.ConstraintDualStart()] + @test MOI.supports(bridged_mock, attr, typeof(ci)) + value = Float64[5, 1, -2, 3] + MOI.set(bridged_mock, attr, ci, value) + @test MOI.get(bridged_mock, attr, ci) ≈ value + if attr isa MOI.ConstraintPrimalStart + nonneg_value = Float64[4, 7, 2, 6, 3, 8] + else + nonneg_value = [-1, 11, -1, 5, -1, 17] / 6 + end + @test MOI.get(mock, attr, nonneg[1]) ≈ nonneg_value + end + + test_delete_bridge(bridged_mock, ci, 4, ( + (MOI.VectorAffineFunction{Float64}, MOI.Nonnegatives, 1),)) + end end @testset "NormOne" begin @@ -92,85 +169,143 @@ end MOI.VectorOfVariables, MOI.VectorAffineFunction{Float64}, MOI.VectorQuadraticFunction{Float64} ]]) - mock.optimize! = (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [1.0, 0.5, 0.5, 0.5, 0.5], - (MOI.VectorAffineFunction{Float64}, MOI.Nonnegatives) => [[1.0, 1.0, 0.0, 0.0]], - (MOI.ScalarAffineFunction{Float64}, MOI.GreaterThan{Float64}) => [[1.0]], - (MOI.VectorAffineFunction{Float64}, MOI.Zeros) => [[-1], [0]]) - - MOIT.normone1vtest(bridged_mock, config) - MOIT.normone1ftest(bridged_mock, config) - - var_names = ["x", "y", "z"] - MOI.set(bridged_mock, MOI.VariableName(), MOI.get(bridged_mock, MOI.ListOfVariableIndices()), var_names) - - nonneg = MOI.get(mock, MOI.ListOfConstraintIndices{MOI.VectorAffineFunction{Float64}, MOI.Nonnegatives}()) - greater = MOI.get(mock, MOI.ListOfConstraintIndices{MOI.ScalarAffineFunction{Float64}, MOI.GreaterThan{Float64}}()) - u, v = MOI.get(mock, MOI.ListOfVariableIndices())[4:5] - @testset "Test mock model" begin - MOI.set(mock, MOI.VariableName(), u, "u") - MOI.set(mock, MOI.VariableName(), v, "v") - @test length(nonneg) == 1 - MOI.set(mock, MOI.ConstraintName(), nonneg[1], "nonneg") - @test length(greater) == 1 - MOI.set(mock, MOI.ConstraintName(), greater[1], "greater") - zeros = MOI.get(mock, MOI.ListOfConstraintIndices{MOI.VectorAffineFunction{Float64}, MOI.Zeros}()) - @test length(zeros) == 2 - MOI.set(mock, MOI.ConstraintName(), zeros[1], "x_eq") - MOI.set(mock, MOI.ConstraintName(), zeros[2], "y_eq") - - s = """ - variables: x, y, z, u, v - nonneg: [u + -1.0y, v + -1.0z, u + y, v + z] in MathOptInterface.Nonnegatives(4) - greater: x + -1.0u + -1.0v >= 0.0 - x_eq: [-1.0 + x] in MathOptInterface.Zeros(1) - y_eq: [-0.5 + y] in MathOptInterface.Zeros(1) - maxobjective: y + z - """ - model = MOIU.Model{Float64}() - MOIU.loadfromstring!(model, s) - MOIU.test_models_equal(mock, model, [var_names; "u"; "v"], ["nonneg", "greater", "x_eq", "y_eq"]) - end + @testset "norminf1test" begin + mock.optimize! = (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, + [1.0, 0.5, 0.5, 0.5, 0.5], + (MOI.VectorAffineFunction{Float64}, MOI.Nonnegatives) => [[1.0, 1.0, 1.0, 0.0, 0.0]], + (MOI.VectorAffineFunction{Float64}, MOI.Zeros) => [[-1], [0]]) - @testset "Test bridged model" begin - normone = MOI.get(bridged_mock, MOI.ListOfConstraintIndices{MOI.VectorAffineFunction{Float64}, MOI.NormOneCone}()) - @test length(normone) == 1 - MOI.set(bridged_mock, MOI.ConstraintName(), normone[1], "normone") - zeros = MOI.get(bridged_mock, MOI.ListOfConstraintIndices{MOI.VectorAffineFunction{Float64}, MOI.Zeros}()) - @test length(zeros) == 2 - MOI.set(bridged_mock, MOI.ConstraintName(), zeros[1], "x_eq") - MOI.set(bridged_mock, MOI.ConstraintName(), zeros[2], "y_eq") - - s = """ - variables: x, y, z - normone: [1.0x, y, z] in MathOptInterface.NormOneCone(3) - x_eq: [-1.0 + x] in MathOptInterface.Zeros(1) - y_eq: [-0.5 + y] in MathOptInterface.Zeros(1) - maxobjective: y + z - """ - model = MOIU.Model{Float64}() - MOIU.loadfromstring!(model, s) - MOIU.test_models_equal(bridged_mock, model, var_names, ["normone", "x_eq", "y_eq"]) - end + MOIT.normone1vtest(bridged_mock, config) + MOIT.normone1ftest(bridged_mock, config) - ci = first(MOI.get(bridged_mock, MOI.ListOfConstraintIndices{MOI.VectorAffineFunction{Float64}, MOI.NormOneCone}())) - - @testset "$attr" for attr in [MOI.ConstraintPrimalStart(), MOI.ConstraintDualStart()] - @test MOI.supports(bridged_mock, attr, typeof(ci)) - value = [4.0, 1.0, -2.0] - MOI.set(bridged_mock, attr, ci, value) - @test MOI.get(bridged_mock, attr, ci) ≈ value - if attr isa MOI.ConstraintPrimalStart - @test MOI.get(mock, MOI.VariablePrimalStart(), u) == 1 - @test MOI.get(mock, MOI.VariablePrimalStart(), v) == 2 - @test MOI.get(mock, attr, nonneg[1]) == [0.0, 4.0, 2.0, 0.0] - @test MOI.get(mock, attr, greater[1]) == 1 - else - @test MOI.get(mock, attr, nonneg[1]) == [0.0, 2.0, 1.0, 0.0] - @test MOI.get(mock, attr, greater[1]) == 4 + var_names = ["x", "y", "z"] + MOI.set(bridged_mock, MOI.VariableName(), MOI.get(bridged_mock, MOI.ListOfVariableIndices()), var_names) + + nonneg = MOI.get(mock, MOI.ListOfConstraintIndices{MOI.VectorAffineFunction{Float64}, MOI.Nonnegatives}()) + u, v = MOI.get(mock, MOI.ListOfVariableIndices())[4:5] + @testset "Test mock model" begin + MOI.set(mock, MOI.VariableName(), u, "u") + MOI.set(mock, MOI.VariableName(), v, "v") + @test length(nonneg) == 1 + MOI.set(mock, MOI.ConstraintName(), nonneg[1], "nonneg") + zeros = MOI.get(mock, MOI.ListOfConstraintIndices{MOI.VectorAffineFunction{Float64}, MOI.Zeros}()) + @test length(zeros) == 2 + MOI.set(mock, MOI.ConstraintName(), zeros[1], "x_eq") + MOI.set(mock, MOI.ConstraintName(), zeros[2], "y_eq") + + s = """ + variables: x, y, z, u, v + nonneg: [x + -1.0u + -1.0v, u + -1.0y, v + -1.0z, u + y, v + z] in MathOptInterface.Nonnegatives(5) + x_eq: [-1.0 + x] in MathOptInterface.Zeros(1) + y_eq: [-0.5 + y] in MathOptInterface.Zeros(1) + maxobjective: y + z + """ + model = MOIU.Model{Float64}() + MOIU.loadfromstring!(model, s) + MOIU.test_models_equal(mock, model, [var_names; "u"; "v"], ["nonneg", "x_eq", "y_eq"]) end + + @testset "Test bridged model" begin + normone = MOI.get(bridged_mock, MOI.ListOfConstraintIndices{MOI.VectorAffineFunction{Float64}, MOI.NormOneCone}()) + @test length(normone) == 1 + MOI.set(bridged_mock, MOI.ConstraintName(), normone[1], "normone") + zeros = MOI.get(bridged_mock, MOI.ListOfConstraintIndices{MOI.VectorAffineFunction{Float64}, MOI.Zeros}()) + @test length(zeros) == 2 + MOI.set(bridged_mock, MOI.ConstraintName(), zeros[1], "x_eq") + MOI.set(bridged_mock, MOI.ConstraintName(), zeros[2], "y_eq") + + s = """ + variables: x, y, z + normone: [1.0x, y, z] in MathOptInterface.NormOneCone(3) + x_eq: [-1.0 + x] in MathOptInterface.Zeros(1) + y_eq: [-0.5 + y] in MathOptInterface.Zeros(1) + maxobjective: y + z + """ + model = MOIU.Model{Float64}() + MOIU.loadfromstring!(model, s) + MOIU.test_models_equal(bridged_mock, model, var_names, ["normone", "x_eq", "y_eq"]) + end + + ci = first(MOI.get(bridged_mock, MOI.ListOfConstraintIndices{MOI.VectorAffineFunction{Float64}, MOI.NormOneCone}())) + + @testset "$attr" for attr in [MOI.ConstraintPrimalStart(), MOI.ConstraintDualStart()] + @test MOI.supports(bridged_mock, attr, typeof(ci)) + value = [4.0, 1.0, -2.0] + MOI.set(bridged_mock, attr, ci, value) + @test MOI.get(bridged_mock, attr, ci) ≈ value + if attr isa MOI.ConstraintPrimalStart + @test MOI.get(mock, MOI.VariablePrimalStart(), u) == 1 + @test MOI.get(mock, MOI.VariablePrimalStart(), v) == 2 + @test MOI.get(mock, attr, nonneg[1]) == Float64[1, 0, 4, 2, 0] + else + @test MOI.get(mock, attr, nonneg[1]) == Float64[4, 0, 2, 1, 0] + end + end + + test_delete_bridge(bridged_mock, ci, 3, ( + (MOI.VectorAffineFunction{Float64}, MOI.Nonnegatives, 0),)) end - test_delete_bridge(bridged_mock, ci, 3, ( - (MOI.ScalarAffineFunction{Float64}, MOI.GreaterThan{Float64}, 0), - (MOI.VectorAffineFunction{Float64}, MOI.Nonnegatives, 0))) + @testset "normone3test" begin + mock.optimize! = (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, + [4, -1, -1, -1, 1, 1, 1], + (MOI.VectorAffineFunction{Float64}, MOI.Nonnegatives) => [vcat(ones(4), zeros(3)), ones(3)]) + MOIT.normone3test(bridged_mock, config) + + var_names = ["x", "y1", "y2", "y3"] + + @testset "Test mock model" begin + var_names_all = vcat(var_names, "z1", "z2", "z3") + MOI.set(mock, MOI.VariableName(), MOI.get(mock, MOI.ListOfVariableIndices()), var_names_all) + nonneg = MOI.get(mock, MOI.ListOfConstraintIndices{MOI.VectorAffineFunction{Float64}, MOI.Nonnegatives}()) + @test length(nonneg) == 2 + MOI.set(mock, MOI.ConstraintName(), nonneg[1], "nonneg1") + MOI.set(mock, MOI.ConstraintName(), nonneg[2], "nonneg2") + + s = """ + variables: x, y1, y2, y3, z1, z2, z3 + nonneg1: [x + -1.0 + -1.0z1 + -1.0z2 + -1.0z3, z1 + -1.0y1 + -2.0, z2 + -1.0y2 + -2.0, z3 + -1.0y3 + -2.0, z1 + y1 + 2.0, z2 + y2 + 2.0, z3 + y3 + 2.0] in MathOptInterface.Nonnegatives(7) + nonneg2: [y1 + 1.0, y2 + 1.0, y3 + 1.0] in MathOptInterface.Nonnegatives(3) + minobjective: x + """ + model = MOIU.Model{Float64}() + MOIU.loadfromstring!(model, s) + MOIU.test_models_equal(mock, model, var_names_all, ["nonneg1", "nonneg2"]) + end + + @testset "Test bridged model" begin + MOI.set(bridged_mock, MOI.VariableName(), MOI.get(bridged_mock, MOI.ListOfVariableIndices()), var_names) + normone = MOI.get(bridged_mock, MOI.ListOfConstraintIndices{MOI.VectorAffineFunction{Float64}, MOI.NormOneCone}()) + @test length(normone) == 1 + MOI.set(bridged_mock, MOI.ConstraintName(), normone[1], "normone") + nonneg = MOI.get(bridged_mock, MOI.ListOfConstraintIndices{MOI.VectorAffineFunction{Float64}, MOI.Nonnegatives}()) + @test length(nonneg) == 1 + MOI.set(bridged_mock, MOI.ConstraintName(), nonneg[1], "nonneg") + + s = """ + variables: x, y1, y2, y3 + normone: [x + -1.0, y1 + 2.0, y2 + 2.0, y3 + 2.0] in MathOptInterface.NormOneCone(4) + nonneg: [y1 + 1.0, y2 + 1.0, y3 + 1.0] in MathOptInterface.Nonnegatives(3) + minobjective: x + """ + model = MOIU.Model{Float64}() + MOIU.loadfromstring!(model, s) + MOIU.test_models_equal(bridged_mock, model, var_names, ["normone", "nonneg"]) + end + + ci = first(MOI.get(bridged_mock, MOI.ListOfConstraintIndices{MOI.VectorAffineFunction{Float64}, MOI.NormOneCone}())) + nonneg = MOI.get(mock, MOI.ListOfConstraintIndices{MOI.VectorAffineFunction{Float64}, MOI.Nonnegatives}()) + + @testset "$attr" for attr in [MOI.ConstraintPrimalStart(), MOI.ConstraintDualStart()] + @test MOI.supports(bridged_mock, attr, typeof(ci)) + value = (attr isa MOI.ConstraintPrimalStart ? vcat(3, ones(3)) : vcat(1, fill(-1, 3))) + MOI.set(bridged_mock, attr, ci, value) + @test MOI.get(bridged_mock, attr, ci) ≈ value + nonneg_value = (attr isa MOI.ConstraintPrimalStart ? vcat(zeros(4), fill(2.0, 3)) : vcat(ones(4), zeros(3))) + @test MOI.get(mock, attr, nonneg[1]) ≈ nonneg_value + end + + test_delete_bridge(bridged_mock, ci, 4, ( + (MOI.VectorAffineFunction{Float64}, MOI.Nonnegatives, 1),)) + end end From 1cb4f503c4993cfe076127cef9d93df7ef5d0c57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Legat?= Date: Mon, 11 May 2020 09:30:59 +0200 Subject: [PATCH 4/4] Remove <: --- src/Bridges/Constraint/norm_to_lp.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Bridges/Constraint/norm_to_lp.jl b/src/Bridges/Constraint/norm_to_lp.jl index 0245ce1549..158d1a2072 100644 --- a/src/Bridges/Constraint/norm_to_lp.jl +++ b/src/Bridges/Constraint/norm_to_lp.jl @@ -88,7 +88,7 @@ function bridge_constraint(::Type{NormOneBridge{T, F, G}}, model::MOI.ModelLike, return NormOneBridge{T, F, G}(y, nn_index) end -MOI.supports_constraint(::Type{<:NormOneBridge{T}}, ::Type{<:MOI.AbstractVectorFunction}, ::Type{MOI.NormOneCone}) where T = true +MOI.supports_constraint(::Type{NormOneBridge{T}}, ::Type{<:MOI.AbstractVectorFunction}, ::Type{MOI.NormOneCone}) where T = true MOIB.added_constrained_variable_types(::Type{<:NormOneBridge}) = Tuple{DataType}[] MOIB.added_constraint_types(::Type{<:NormOneBridge{T, F}}) where {T, F} = [(F, MOI.Nonnegatives)] function concrete_bridge_type(::Type{<:NormOneBridge{T}}, G::Type{<:MOI.AbstractVectorFunction}, ::Type{MOI.NormOneCone}) where T