From 52f379f3b65b4f0569bddeb625dfabf3ef20766b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Legat?= Date: Fri, 19 Apr 2019 12:23:10 +0200 Subject: [PATCH 1/2] Refactor tests --- test/Bridges/Bridges.jl | 19 + test/Bridges/external.jl | 53 ++ test/Bridges/flip_sign_bridge.jl | 105 +++ test/Test/Test.jl | 21 + test/Test/config.jl | 8 + test/Test/contconic.jl | 368 ++++---- test/Test/contlinear.jl | 316 +++---- test/Test/contquadratic.jl | 86 +- test/Test/intconic.jl | 20 +- test/Test/intlinear.jl | 52 +- test/Test/modellike.jl | 8 +- test/Test/unit.jl | 8 + test/Utilities/Utilities.jl | 29 + test/Utilities/cachingoptimizer.jl | 25 +- test/Utilities/constraints.jl | 8 +- test/Utilities/copy.jl | 66 +- test/Utilities/functions.jl | 1248 +++++++++++++-------------- test/Utilities/mockoptimizer.jl | 18 +- test/Utilities/model.jl | 5 + test/Utilities/sets.jl | 6 +- test/Utilities/universalfallback.jl | 203 +++-- test/bridge.jl | 160 ---- test/dummy.jl | 5 + test/model.jl | 17 + test/model_for_mock.jl | 9 + test/runtests.jl | 38 +- 26 files changed, 1529 insertions(+), 1372 deletions(-) create mode 100644 test/Bridges/Bridges.jl create mode 100644 test/Bridges/external.jl create mode 100644 test/Bridges/flip_sign_bridge.jl create mode 100644 test/Test/Test.jl create mode 100644 test/Utilities/Utilities.jl create mode 100644 test/model.jl create mode 100644 test/model_for_mock.jl diff --git a/test/Bridges/Bridges.jl b/test/Bridges/Bridges.jl new file mode 100644 index 0000000000..b4dde39b23 --- /dev/null +++ b/test/Bridges/Bridges.jl @@ -0,0 +1,19 @@ +include("bridge.jl") +include("bridgeoptimizer.jl") +include("singlebridgeoptimizer.jl") +include("lazybridgeoptimizer.jl") +@testset "Separate bridges" begin + include("flip_sign_bridge.jl") + include("vectorizebridge.jl") + include("scalarizebridge.jl") + include("slackbridge.jl") + include("functionize_bridge.jl") + include("intervalbridge.jl") + include("rsocbridge.jl") + include("quadtosocbridge.jl") + include("geomeanbridge.jl") + include("squarepsdbridge.jl") + include("detbridge.jl") + include("soctopsdbridge.jl") +end +include("external.jl") diff --git a/test/Bridges/external.jl b/test/Bridges/external.jl new file mode 100644 index 0000000000..e2d56b3b9b --- /dev/null +++ b/test/Bridges/external.jl @@ -0,0 +1,53 @@ +# We need to test this in a module at the top level because it can't be defined +# in a testset. If it runs without error, then we're okay. +module TestExternalBridge + using MathOptInterface + + struct StrictlyGreaterThan <: MathOptInterface.AbstractScalarSet end + struct StrictlyGreaterBridge{T} <: MathOptInterface.Bridges.AbstractBridge end + + function StrictlyGreaterBridge( + model, + func::MathOptInterface.SingleVariable, + set::StrictlyGreaterThan) + return StrictlyGreaterBridge{Float64}() + end + + function MathOptInterface.supports_constraint( + ::Type{StrictlyGreaterBridge{T}}, + ::Type{MathOptInterface.SingleVariable}, + ::Type{StrictlyGreaterThan}) where {T} + return true + end + + function MathOptInterface.Bridges.added_constraint_types( + ::Type{StrictlyGreaterBridge{T}}, + ::Type{MathOptInterface.SingleVariable}, + ::Type{StrictlyGreaterThan}) where {T} + return [( + MathOptInterface.SingleVariable, + MathOptInterface.GreaterThan{T} + )] + end + + MathOptInterface.Bridges.@bridge(StrictlyGreater, StrictlyGreaterBridge, + (StrictlyGreaterThan, ), + (), + (), + (), + (MathOptInterface.SingleVariable, ), + (), + (), + () + ) +end + +@testset "@bridge with external components" begin + model = SimpleModel{Float64}(); + @test MOI.supports_constraint(model, MOI.SingleVariable, MOI.GreaterThan{Float64}) + @test !MOI.supports_constraint(model, MOI.SingleVariable, TestExternalBridge.StrictlyGreaterThan) + + bridge = TestExternalBridge.StrictlyGreater{Float64}(model); + @test MOI.supports_constraint(bridge, MOI.SingleVariable, MOI.GreaterThan{Float64}) + @test MOI.supports_constraint(bridge, MOI.SingleVariable, TestExternalBridge.StrictlyGreaterThan) +end diff --git a/test/Bridges/flip_sign_bridge.jl b/test/Bridges/flip_sign_bridge.jl new file mode 100644 index 0000000000..a1e3f49646 --- /dev/null +++ b/test/Bridges/flip_sign_bridge.jl @@ -0,0 +1,105 @@ +mock = MOIU.MockOptimizer(SimpleModel{Float64}()) +config = MOIT.TestConfig() +config_with_basis = MOIT.TestConfig(basis = true) + +@testset "GreaterToLess" begin + bridged_mock = MOIB.GreaterToLess{Float64}(mock) + + MOIU.set_mock_optimize!(mock, + (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [0, 0]), + (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [100, 0]), + (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [100, -100])) + MOIT.linear6test(bridged_mock, config) + + ci = first(MOI.get(bridged_mock, MOI.ListOfConstraintIndices{MOI.ScalarAffineFunction{Float64}, MOI.GreaterThan{Float64}}())) + test_delete_bridge(bridged_mock, ci, 2, + ((MOI.ScalarAffineFunction{Float64}, + MOI.LessThan{Float64}, 1),)) +end + +@testset "LessToGreater" begin + bridged_mock = MOIB.LessToGreater{Float64}(mock) + + MOIU.set_mock_optimize!(mock, + (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, + MOI.OPTIMAL, (MOI.FEASIBLE_POINT, [1.0]), + MOI.FEASIBLE_POINT, + (MOI.ScalarAffineFunction{Float64}, MOI.GreaterThan{Float64}) => [1.0] + ), + (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, + MOI.OPTIMAL, (MOI.FEASIBLE_POINT, [2.0]), + MOI.FEASIBLE_POINT, + (MOI.ScalarAffineFunction{Float64}, MOI.GreaterThan{Float64}) => [1.0] + ) + ) + MOIT.solve_set_scalaraffine_lessthan(bridged_mock, config) + + MOIU.set_mock_optimize!(mock, + (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, + MOI.OPTIMAL, (MOI.FEASIBLE_POINT, [1.0]), + MOI.FEASIBLE_POINT, + (MOI.ScalarAffineFunction{Float64}, MOI.GreaterThan{Float64}) => [1.0] + ), + (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, + MOI.OPTIMAL, (MOI.FEASIBLE_POINT, [0.5]), + MOI.FEASIBLE_POINT, + (MOI.ScalarAffineFunction{Float64}, MOI.GreaterThan{Float64}) => [0.5] + ) + ) + MOIT.solve_coef_scalaraffine_lessthan(bridged_mock, config) + + ci = first(MOI.get(bridged_mock, MOI.ListOfConstraintIndices{MOI.ScalarAffineFunction{Float64}, MOI.LessThan{Float64}}())) + test_delete_bridge(bridged_mock, ci, 1, + ((MOI.ScalarAffineFunction{Float64}, + MOI.GreaterThan{Float64}, 0),)) +end + +@testset "NonnegToNonpos" begin + bridged_mock = MOIB.NonnegToNonpos{Float64}(mock) + + MOIU.set_mock_optimize!(mock, + (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [0, 0]), + (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [100, 0]), + (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [100, -100])) + MOIT.linear7test(bridged_mock, config) + + ci = first(MOI.get(bridged_mock, MOI.ListOfConstraintIndices{MOI.VectorAffineFunction{Float64}, MOI.Nonnegatives}())) + test_delete_bridge(bridged_mock, ci, 2, + ((MOI.VectorAffineFunction{Float64}, + MOI.Nonpositives, 1),)) +end + +@testset "NonposToNonneg" begin + bridged_mock = MOIB.NonposToNonneg{Float64}(mock) + + MOIU.set_mock_optimize!(mock, + (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [0, 0]), + (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [100, 0]), + (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [100, -100])) + MOIT.linear7test(bridged_mock, config) + + MOIU.set_mock_optimize!(mock, + (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, + MOI.OPTIMAL, (MOI.FEASIBLE_POINT, [0.0, 0.0]) + ), + (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, + MOI.OPTIMAL, (MOI.FEASIBLE_POINT, [1.0, 0.75]) + ) + ) + MOIT.solve_const_vectoraffine_nonpos(bridged_mock, config) + + MOIU.set_mock_optimize!(mock, + (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!( + mock, MOI.OPTIMAL, (MOI.FEASIBLE_POINT, [0.5]) + ), + (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!( + mock, MOI.OPTIMAL, (MOI.FEASIBLE_POINT, [0.25]) + ) + ) + MOIT.solve_multirow_vectoraffine_nonpos(bridged_mock, config) + + ci = first(MOI.get(bridged_mock, MOI.ListOfConstraintIndices{MOI.VectorAffineFunction{Float64}, MOI.Nonpositives}())) + test_delete_bridge(bridged_mock, ci, 1, + ((MOI.VectorAffineFunction{Float64}, + MOI.Nonnegatives, 0),)) +end diff --git a/test/Test/Test.jl b/test/Test/Test.jl new file mode 100644 index 0000000000..98c0e387da --- /dev/null +++ b/test/Test/Test.jl @@ -0,0 +1,21 @@ +@testset "Config" begin + include("config.jl") +end +@testset "Unit" begin + include("unit.jl") +end +@testset "Continuous Linear" begin + include("contlinear.jl") +end +@testset "Continuous Conic" begin + include("contconic.jl") +end +@testset "Continuous Quadratic" begin + include("contquadratic.jl") +end +@testset "Integer Linear" begin + include("intlinear.jl") +end +@testset "Integer Conic" begin + include("intconic.jl") +end diff --git a/test/Test/config.jl b/test/Test/config.jl index 95d26afb26..c1b949ea85 100644 --- a/test/Test/config.jl +++ b/test/Test/config.jl @@ -1,3 +1,11 @@ +using Test +import MathOptInterface +const MOI = MathOptInterface +const MOIT = MOI.Test +const MOIU = MOI.Utilities + +include("../model_for_mock.jl") + function atest(model::MOI.ModelLike, config::MOIT.TestConfig) @test config.atol == 1e-8 @test config.rtol == 1e-8 diff --git a/test/Test/contconic.jl b/test/Test/contconic.jl index 5942db1ce1..1a45a44b74 100644 --- a/test/Test/contconic.jl +++ b/test/Test/contconic.jl @@ -1,184 +1,190 @@ -@testset "Continuous Conic" begin - mock = MOIU.MockOptimizer(Model{Float64}()) - config = MOIT.TestConfig() +using Test +import MathOptInterface +const MOI = MathOptInterface +const MOIT = MOI.Test +const MOIU = MOI.Utilities - @testset "Linear" begin - mock.optimize! = (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [1.0, 0.0, 2.0], - (MOI.VectorAffineFunction{Float64}, MOI.Zeros) => [[-3, -1]]) - MOIT.lin1vtest(mock, config) - mock.optimize! = (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [1.0, 0.0, 2.0], - (MOI.VectorAffineFunction{Float64}, MOI.Nonnegatives) => [[0, 2, 0]], - (MOI.VectorAffineFunction{Float64}, MOI.Zeros) => [[-3, -1]]) - MOIT.lin1ftest(mock, config) - mock.optimize! = (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [-4, -3, 16, 0], - (MOI.VectorAffineFunction{Float64}, MOI.Zeros) => [[7, 2, -4]]) - MOIT.lin2vtest(mock, config) - mock.optimize! = (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [-4, -3, 16, 0], - (MOI.VectorAffineFunction{Float64}, MOI.Nonnegatives) => [[0]], - (MOI.VectorAffineFunction{Float64}, MOI.Nonpositives) => [[0]], - (MOI.VectorAffineFunction{Float64}, MOI.Zeros) => [[7, 2, -4], [7]]) - MOIT.lin2ftest(mock, config) - mock.optimize! = (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, MOI.INFEASIBLE, MOI.INFEASIBLE_POINT, MOI.INFEASIBILITY_CERTIFICATE) - MOIT.lin3test(mock, config) - mock.optimize! = (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, MOI.INFEASIBLE) - MOIT.lin3test(mock, MOIT.TestConfig(infeas_certificates=false)) - mock.optimize! = (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, MOI.INFEASIBLE_OR_UNBOUNDED) - MOIT.lin3test(mock, MOIT.TestConfig(infeas_certificates=false)) - mock.optimize! = (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, MOI.INFEASIBLE, MOI.INFEASIBLE_POINT, MOI.INFEASIBILITY_CERTIFICATE) - MOIT.lin4test(mock, config) - mock.optimize! = (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, MOI.INFEASIBLE) - MOIT.lin4test(mock, MOIT.TestConfig(infeas_certificates=false)) - mock.optimize! = (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, MOI.INFEASIBLE_OR_UNBOUNDED) - MOIT.lin4test(mock, MOIT.TestConfig(infeas_certificates=false)) - 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]]) - MOIT.soc1vtest(mock, config) - mock.optimize! = (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [1.0, 1/√2, 1/√2], - (MOI.VectorAffineFunction{Float64}, MOI.SecondOrderCone) => [[√2, -1, -1]], - (MOI.VectorAffineFunction{Float64}, MOI.Zeros) => [[-√2]]) - MOIT.soc1ftest(mock, config) - mock.optimize! = (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [-1/√2, 1/√2, 1.], - (MOI.VectorAffineFunction{Float64}, MOI.SecondOrderCone) => [[√2, 1, -1]], - (MOI.VectorAffineFunction{Float64}, MOI.Zeros) => [[√2]], - (MOI.VectorAffineFunction{Float64}, MOI.Nonnegatives) => [[1.0]]) - MOIT.soc2ntest(mock, config) - mock.optimize! = (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [-1/√2, 1/√2, 1.], - (MOI.VectorAffineFunction{Float64}, MOI.SecondOrderCone) => [[√2, 1, -1]], - (MOI.VectorAffineFunction{Float64}, MOI.Zeros) => [[√2]], - (MOI.VectorAffineFunction{Float64}, MOI.Nonpositives) => [[-1.0]]) - MOIT.soc2ptest(mock, config) - mock.optimize! = (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, MOI.INFEASIBLE, MOI.INFEASIBLE_POINT, MOI.INFEASIBILITY_CERTIFICATE) - MOIT.soc3test(mock, config) - mock.optimize! = (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [1.0, 2/√5, 1/√5, 2/√5, 1/√5], - (MOI.VectorAffineFunction{Float64}, MOI.Zeros) => [[-√5, -2.0, -1.0]]) - MOIT.soc4test(mock, config) - end - @testset "RSOC" begin - mock.optimize! = (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [1/√2, 1/√2, 0.5, 1.0], - (MOI.SingleVariable, MOI.EqualTo{Float64}) => [-√2, -1/√2], - (MOI.VectorOfVariables, MOI.RotatedSecondOrderCone) => [[√2, 1/√2, -1.0, -1.0]]) - # double variable bounds on a and b variables - mock.eval_variable_constraint_dual = false - MOIT.rotatedsoc1vtest(mock, config) - mock.eval_variable_constraint_dual = true - mock.optimize! = (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [1/√2, 1/√2], - (MOI.VectorAffineFunction{Float64}, MOI.RotatedSecondOrderCone) => [[√2, 1/√2, -1.0, -1.0]]) - MOIT.rotatedsoc1ftest(mock, config) - mock.optimize! = (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, MOI.INFEASIBLE, tuple(), - (MOI.SingleVariable, MOI.LessThan{Float64}) => [-1], - (MOI.SingleVariable, MOI.EqualTo{Float64}) => [-1], - (MOI.SingleVariable, MOI.GreaterThan{Float64}) => [1], - (MOI.VectorOfVariables , MOI.RotatedSecondOrderCone) => [[1, 1, -1]]) - # double variable bounds on x, y, z variables - mock.eval_variable_constraint_dual = false - MOIT.rotatedsoc2test(mock, config) - mock.eval_variable_constraint_dual = true - n = 2 - ub = 3.0 - mock.optimize! = (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [1.0; zeros(n-1); ub; √ub; ones(2)], - (MOI.SingleVariable, MOI.EqualTo{Float64}) => [-√ub/4, -√ub/4], - (MOI.VectorOfVariables, MOI.Nonnegatives) => [zeros(n)], - (MOI.SingleVariable, MOI.GreaterThan{Float64}) => [0.0], - (MOI.SingleVariable, MOI.LessThan{Float64}) => [-1/(2*√ub)], - (MOI.VectorAffineFunction{Float64}, MOI.RotatedSecondOrderCone) => [[√ub/(2*√2); √ub/(2*√2); -√ub/2; zeros(n-1)], [√ub/√2, 1/√(2*ub), -1.0]]) - # double variable bounds on u - mock.eval_variable_constraint_dual = false - MOIT.rotatedsoc3test(mock, config) - mock.eval_variable_constraint_dual = true - end - @testset "GeoMean" begin - mock.optimize! = (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, ones(4)) - MOIT.geomeantest(mock, config) - end - @testset "Exponential" begin - mock.optimize! = (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [1., 2., 2exp(1/2)], - (MOI.ScalarAffineFunction{Float64}, MOI.EqualTo{Float64}) => [1 + exp(1/2), 1 + exp(1/2)/2]) - MOIT.exp1vtest(mock, config) - mock.optimize! = (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [1., 2., 2exp(1/2)], - (MOI.VectorAffineFunction{Float64}, MOI.ExponentialCone) => [[-exp(1/2), -exp(1/2)/2, 1.]], - (MOI.ScalarAffineFunction{Float64}, MOI.EqualTo{Float64}) => [1 + exp(1/2), 1 + exp(1/2)/2]) - MOIT.exp1ftest(mock, config) - mock.optimize! = (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [0., -0.3, 0., exp(-0.3), exp(-0.3), exp(-0.3), 0., 1.0, 0.], - (MOI.VectorAffineFunction{Float64}, MOI.ExponentialCone) => [[-exp(-0.3)/2, -1.3exp(-0.3)/2, 0.5], [-exp(-0.3)/2, -1.3exp(-0.3)/2, 0.5]], - (MOI.ScalarAffineFunction{Float64}, MOI.EqualTo{Float64}) => [-1.0, exp(-0.3)*0.3], - (MOI.ScalarAffineFunction{Float64}, MOI.LessThan{Float64}) => [-exp(-0.3)*0.3], - (MOI.VectorAffineFunction{Float64}, MOI.Nonnegatives) => [[0.0, exp(-0.3), exp(-0.3)/2], [0.0, 0.0, exp(-0.3)/2]]) - MOIT.exp2test(mock, config) - mock.optimize! = (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [log(5), 5.], - (MOI.ScalarAffineFunction{Float64}, MOI.LessThan{Float64}) => [0.], - (MOI.VectorAffineFunction{Float64}, MOI.ExponentialCone) => [[-1., log(5)-1, 1/5]]) - MOIT.exp3test(mock, config) - end - @testset "PSD" begin - # PSD0 - mock.optimize! = (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, ones(3), - (MOI.ScalarAffineFunction{Float64}, MOI.EqualTo{Float64}) => [2]) - MOIT.psdt0vtest(mock, config) - mock.optimize! = (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, ones(3), - (MOI.VectorAffineFunction{Float64}, MOI.PositiveSemidefiniteConeTriangle) => [[1, -1, 1]], - (MOI.ScalarAffineFunction{Float64}, MOI.EqualTo{Float64}) => [2]) - MOIT.psdt0ftest(mock, config) - mock.optimize! = (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, ones(4), - (MOI.ScalarAffineFunction{Float64}, MOI.EqualTo{Float64}) => [2]) - MOIT.psds0vtest(mock, config) - mock.optimize! = (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, ones(4), - (MOI.VectorAffineFunction{Float64}, MOI.PositiveSemidefiniteConeSquare) => [[1, -2, 0, 1]], - (MOI.ScalarAffineFunction{Float64}, MOI.EqualTo{Float64}) => [2]) - MOIT.psds0ftest(mock, config) - # PSD1 - δ = √(1 + (3*√2+2)*√(-116*√2+166) / 14) / 2 - ε = √((1 - 2*(√2-1)*δ^2) / (2-√2)) - y2 = 1 - ε*δ - y1 = 1 - √2*y2 - obj = y1 + y2/2 - k = -2*δ/ε - x2 = ((3-2obj)*(2+k^2)-4) / (4*(2+k^2)-4*√2) - α = √(3-2obj-4x2)/2 - β = k*α - Xv = [α^2, α*β, β^2, α^2, α*β, α^2] - xv = [√2*x2, x2, x2] - cX0 = 1+(√2-1)*y2 - cX1 = 1-y2 - cX2 = -y2 - cXv = [cX0, cX1, cX0, cX2, cX1, cX0] - mock.optimize! = (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [Xv; xv], - (MOI.ScalarAffineFunction{Float64}, MOI.EqualTo{Float64}) => [y1, y2]) - MOIT.psdt1vtest(mock, config) - mock.optimize! = (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [Xv; xv], - (MOI.VectorAffineFunction{Float64}, MOI.PositiveSemidefiniteConeTriangle) => [cXv], - (MOI.ScalarAffineFunction{Float64}, MOI.EqualTo{Float64}) => [y1, y2]) - MOIT.psdt1ftest(mock, config) - Xv = [α^2, α*β, α^2, α*β, β^2, α*β, α^2, α*β, α^2] - cXv = [cX0, cX1, cX2, cX1, cX0, cX1, cX2, cX1, cX0] - mock.optimize! = (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [Xv; xv], - (MOI.ScalarAffineFunction{Float64}, MOI.EqualTo{Float64}) => [y1, y2]) - MOIT.psds1vtest(mock, config) - mock.optimize! = (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [Xv; xv], - (MOI.VectorAffineFunction{Float64}, MOI.PositiveSemidefiniteConeSquare) => [cXv], - (MOI.ScalarAffineFunction{Float64}, MOI.EqualTo{Float64}) => [y1, y2]) - MOIT.psds1ftest(mock, config) - # PSD2 - η = 10.0 - α = 0.8 - δ = 0.9 - mock.optimize! = (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [2η/3, 0, η/3, 0, 0, 0, η*δ*(1 - 1/√3)/2], - (MOI.ScalarAffineFunction{Float64}, MOI.GreaterThan{Float64}) => [δ*(1-1/√3)/2], - (MOI.VectorAffineFunction{Float64}, MOI.Nonpositives) => [[0, -α/√3+δ/(2*√6)*(2*√2-1), 0, -3δ*(1-1/√3)/8, -3δ*(1-1/√3)/8, -δ*(3 - 2*√3 + 1/√3)/8]], - (MOI.VectorAffineFunction{Float64}, MOI.PositiveSemidefiniteConeTriangle) => [[(1-1/√3)/2, 1/√6, (1+1/√3)/2]], - (MOI.ScalarAffineFunction{Float64}, MOI.EqualTo{Float64}) => [0]) - MOIT.psdt2test(mock, config) - end - @testset "LogDet and RootDet" begin - mock.optimize! = (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [0, 1, 0, 1, 1]) - MOIT.logdetttest(mock, config) - mock.optimize! = (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [0, 1, 0, 0, 1, 1]) - MOIT.logdetstest(mock, config) +include("../model.jl") - mock.optimize! = (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [1, 1, 0, 1]) - MOIT.rootdetttest(mock, config) - mock.optimize! = (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [1, 1, 0, 0, 1]) - MOIT.rootdetstest(mock, config) - end +mock = MOIU.MockOptimizer(Model{Float64}()) +config = MOIT.TestConfig() + +@testset "Linear" begin + mock.optimize! = (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [1.0, 0.0, 2.0], + (MOI.VectorAffineFunction{Float64}, MOI.Zeros) => [[-3, -1]]) + MOIT.lin1vtest(mock, config) + mock.optimize! = (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [1.0, 0.0, 2.0], + (MOI.VectorAffineFunction{Float64}, MOI.Nonnegatives) => [[0, 2, 0]], + (MOI.VectorAffineFunction{Float64}, MOI.Zeros) => [[-3, -1]]) + MOIT.lin1ftest(mock, config) + mock.optimize! = (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [-4, -3, 16, 0], + (MOI.VectorAffineFunction{Float64}, MOI.Zeros) => [[7, 2, -4]]) + MOIT.lin2vtest(mock, config) + mock.optimize! = (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [-4, -3, 16, 0], + (MOI.VectorAffineFunction{Float64}, MOI.Nonnegatives) => [[0]], + (MOI.VectorAffineFunction{Float64}, MOI.Nonpositives) => [[0]], + (MOI.VectorAffineFunction{Float64}, MOI.Zeros) => [[7, 2, -4], [7]]) + MOIT.lin2ftest(mock, config) + mock.optimize! = (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, MOI.INFEASIBLE, MOI.INFEASIBLE_POINT, MOI.INFEASIBILITY_CERTIFICATE) + MOIT.lin3test(mock, config) + mock.optimize! = (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, MOI.INFEASIBLE) + MOIT.lin3test(mock, MOIT.TestConfig(infeas_certificates=false)) + mock.optimize! = (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, MOI.INFEASIBLE_OR_UNBOUNDED) + MOIT.lin3test(mock, MOIT.TestConfig(infeas_certificates=false)) + mock.optimize! = (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, MOI.INFEASIBLE, MOI.INFEASIBLE_POINT, MOI.INFEASIBILITY_CERTIFICATE) + MOIT.lin4test(mock, config) + mock.optimize! = (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, MOI.INFEASIBLE) + MOIT.lin4test(mock, MOIT.TestConfig(infeas_certificates=false)) + mock.optimize! = (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, MOI.INFEASIBLE_OR_UNBOUNDED) + MOIT.lin4test(mock, MOIT.TestConfig(infeas_certificates=false)) +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]]) + MOIT.soc1vtest(mock, config) + mock.optimize! = (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [1.0, 1/√2, 1/√2], + (MOI.VectorAffineFunction{Float64}, MOI.SecondOrderCone) => [[√2, -1, -1]], + (MOI.VectorAffineFunction{Float64}, MOI.Zeros) => [[-√2]]) + MOIT.soc1ftest(mock, config) + mock.optimize! = (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [-1/√2, 1/√2, 1.], + (MOI.VectorAffineFunction{Float64}, MOI.SecondOrderCone) => [[√2, 1, -1]], + (MOI.VectorAffineFunction{Float64}, MOI.Zeros) => [[√2]], + (MOI.VectorAffineFunction{Float64}, MOI.Nonnegatives) => [[1.0]]) + MOIT.soc2ntest(mock, config) + mock.optimize! = (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [-1/√2, 1/√2, 1.], + (MOI.VectorAffineFunction{Float64}, MOI.SecondOrderCone) => [[√2, 1, -1]], + (MOI.VectorAffineFunction{Float64}, MOI.Zeros) => [[√2]], + (MOI.VectorAffineFunction{Float64}, MOI.Nonpositives) => [[-1.0]]) + MOIT.soc2ptest(mock, config) + mock.optimize! = (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, MOI.INFEASIBLE, MOI.INFEASIBLE_POINT, MOI.INFEASIBILITY_CERTIFICATE) + MOIT.soc3test(mock, config) + mock.optimize! = (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [1.0, 2/√5, 1/√5, 2/√5, 1/√5], + (MOI.VectorAffineFunction{Float64}, MOI.Zeros) => [[-√5, -2.0, -1.0]]) + MOIT.soc4test(mock, config) +end +@testset "RSOC" begin + mock.optimize! = (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [1/√2, 1/√2, 0.5, 1.0], + (MOI.SingleVariable, MOI.EqualTo{Float64}) => [-√2, -1/√2], + (MOI.VectorOfVariables, MOI.RotatedSecondOrderCone) => [[√2, 1/√2, -1.0, -1.0]]) + # double variable bounds on a and b variables + mock.eval_variable_constraint_dual = false + MOIT.rotatedsoc1vtest(mock, config) + mock.eval_variable_constraint_dual = true + mock.optimize! = (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [1/√2, 1/√2], + (MOI.VectorAffineFunction{Float64}, MOI.RotatedSecondOrderCone) => [[√2, 1/√2, -1.0, -1.0]]) + MOIT.rotatedsoc1ftest(mock, config) + mock.optimize! = (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, MOI.INFEASIBLE, tuple(), + (MOI.SingleVariable, MOI.LessThan{Float64}) => [-1], + (MOI.SingleVariable, MOI.EqualTo{Float64}) => [-1], + (MOI.SingleVariable, MOI.GreaterThan{Float64}) => [1], + (MOI.VectorOfVariables , MOI.RotatedSecondOrderCone) => [[1, 1, -1]]) + # double variable bounds on x, y, z variables + mock.eval_variable_constraint_dual = false + MOIT.rotatedsoc2test(mock, config) + mock.eval_variable_constraint_dual = true + n = 2 + ub = 3.0 + mock.optimize! = (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [1.0; zeros(n-1); ub; √ub; ones(2)], + (MOI.SingleVariable, MOI.EqualTo{Float64}) => [-√ub/4, -√ub/4], + (MOI.VectorOfVariables, MOI.Nonnegatives) => [zeros(n)], + (MOI.SingleVariable, MOI.GreaterThan{Float64}) => [0.0], + (MOI.SingleVariable, MOI.LessThan{Float64}) => [-1/(2*√ub)], + (MOI.VectorAffineFunction{Float64}, MOI.RotatedSecondOrderCone) => [[√ub/(2*√2); √ub/(2*√2); -√ub/2; zeros(n-1)], [√ub/√2, 1/√(2*ub), -1.0]]) + # double variable bounds on u + mock.eval_variable_constraint_dual = false + MOIT.rotatedsoc3test(mock, config) + mock.eval_variable_constraint_dual = true +end +@testset "GeoMean" begin + mock.optimize! = (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, ones(4)) + MOIT.geomeantest(mock, config) +end +@testset "Exponential" begin + mock.optimize! = (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [1., 2., 2exp(1/2)], + (MOI.ScalarAffineFunction{Float64}, MOI.EqualTo{Float64}) => [1 + exp(1/2), 1 + exp(1/2)/2]) + MOIT.exp1vtest(mock, config) + mock.optimize! = (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [1., 2., 2exp(1/2)], + (MOI.VectorAffineFunction{Float64}, MOI.ExponentialCone) => [[-exp(1/2), -exp(1/2)/2, 1.]], + (MOI.ScalarAffineFunction{Float64}, MOI.EqualTo{Float64}) => [1 + exp(1/2), 1 + exp(1/2)/2]) + MOIT.exp1ftest(mock, config) + mock.optimize! = (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [0., -0.3, 0., exp(-0.3), exp(-0.3), exp(-0.3), 0., 1.0, 0.], + (MOI.VectorAffineFunction{Float64}, MOI.ExponentialCone) => [[-exp(-0.3)/2, -1.3exp(-0.3)/2, 0.5], [-exp(-0.3)/2, -1.3exp(-0.3)/2, 0.5]], + (MOI.ScalarAffineFunction{Float64}, MOI.EqualTo{Float64}) => [-1.0, exp(-0.3)*0.3], + (MOI.ScalarAffineFunction{Float64}, MOI.LessThan{Float64}) => [-exp(-0.3)*0.3], + (MOI.VectorAffineFunction{Float64}, MOI.Nonnegatives) => [[0.0, exp(-0.3), exp(-0.3)/2], [0.0, 0.0, exp(-0.3)/2]]) + MOIT.exp2test(mock, config) + mock.optimize! = (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [log(5), 5.], + (MOI.ScalarAffineFunction{Float64}, MOI.LessThan{Float64}) => [0.], + (MOI.VectorAffineFunction{Float64}, MOI.ExponentialCone) => [[-1., log(5)-1, 1/5]]) + MOIT.exp3test(mock, config) +end +@testset "PSD" begin + # PSD0 + mock.optimize! = (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, ones(3), + (MOI.ScalarAffineFunction{Float64}, MOI.EqualTo{Float64}) => [2]) + MOIT.psdt0vtest(mock, config) + mock.optimize! = (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, ones(3), + (MOI.VectorAffineFunction{Float64}, MOI.PositiveSemidefiniteConeTriangle) => [[1, -1, 1]], + (MOI.ScalarAffineFunction{Float64}, MOI.EqualTo{Float64}) => [2]) + MOIT.psdt0ftest(mock, config) + mock.optimize! = (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, ones(4), + (MOI.ScalarAffineFunction{Float64}, MOI.EqualTo{Float64}) => [2]) + MOIT.psds0vtest(mock, config) + mock.optimize! = (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, ones(4), + (MOI.VectorAffineFunction{Float64}, MOI.PositiveSemidefiniteConeSquare) => [[1, -2, 0, 1]], + (MOI.ScalarAffineFunction{Float64}, MOI.EqualTo{Float64}) => [2]) + MOIT.psds0ftest(mock, config) + # PSD1 + δ = √(1 + (3*√2+2)*√(-116*√2+166) / 14) / 2 + ε = √((1 - 2*(√2-1)*δ^2) / (2-√2)) + y2 = 1 - ε*δ + y1 = 1 - √2*y2 + obj = y1 + y2/2 + k = -2*δ/ε + x2 = ((3-2obj)*(2+k^2)-4) / (4*(2+k^2)-4*√2) + α = √(3-2obj-4x2)/2 + β = k*α + Xv = [α^2, α*β, β^2, α^2, α*β, α^2] + xv = [√2*x2, x2, x2] + cX0 = 1+(√2-1)*y2 + cX1 = 1-y2 + cX2 = -y2 + cXv = [cX0, cX1, cX0, cX2, cX1, cX0] + mock.optimize! = (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [Xv; xv], + (MOI.ScalarAffineFunction{Float64}, MOI.EqualTo{Float64}) => [y1, y2]) + MOIT.psdt1vtest(mock, config) + mock.optimize! = (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [Xv; xv], + (MOI.VectorAffineFunction{Float64}, MOI.PositiveSemidefiniteConeTriangle) => [cXv], + (MOI.ScalarAffineFunction{Float64}, MOI.EqualTo{Float64}) => [y1, y2]) + MOIT.psdt1ftest(mock, config) + Xv = [α^2, α*β, α^2, α*β, β^2, α*β, α^2, α*β, α^2] + cXv = [cX0, cX1, cX2, cX1, cX0, cX1, cX2, cX1, cX0] + mock.optimize! = (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [Xv; xv], + (MOI.ScalarAffineFunction{Float64}, MOI.EqualTo{Float64}) => [y1, y2]) + MOIT.psds1vtest(mock, config) + mock.optimize! = (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [Xv; xv], + (MOI.VectorAffineFunction{Float64}, MOI.PositiveSemidefiniteConeSquare) => [cXv], + (MOI.ScalarAffineFunction{Float64}, MOI.EqualTo{Float64}) => [y1, y2]) + MOIT.psds1ftest(mock, config) + # PSD2 + η = 10.0 + α = 0.8 + δ = 0.9 + mock.optimize! = (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [2η/3, 0, η/3, 0, 0, 0, η*δ*(1 - 1/√3)/2], + (MOI.ScalarAffineFunction{Float64}, MOI.GreaterThan{Float64}) => [δ*(1-1/√3)/2], + (MOI.VectorAffineFunction{Float64}, MOI.Nonpositives) => [[0, -α/√3+δ/(2*√6)*(2*√2-1), 0, -3δ*(1-1/√3)/8, -3δ*(1-1/√3)/8, -δ*(3 - 2*√3 + 1/√3)/8]], + (MOI.VectorAffineFunction{Float64}, MOI.PositiveSemidefiniteConeTriangle) => [[(1-1/√3)/2, 1/√6, (1+1/√3)/2]], + (MOI.ScalarAffineFunction{Float64}, MOI.EqualTo{Float64}) => [0]) + MOIT.psdt2test(mock, config) +end +@testset "LogDet and RootDet" begin + mock.optimize! = (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [0, 1, 0, 1, 1]) + MOIT.logdetttest(mock, config) + mock.optimize! = (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [0, 1, 0, 0, 1, 1]) + MOIT.logdetstest(mock, config) + + mock.optimize! = (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [1, 1, 0, 1]) + MOIT.rootdetttest(mock, config) + mock.optimize! = (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [1, 1, 0, 0, 1]) + MOIT.rootdetstest(mock, config) end diff --git a/test/Test/contlinear.jl b/test/Test/contlinear.jl index 4597cf9c56..e7d8a6a188 100644 --- a/test/Test/contlinear.jl +++ b/test/Test/contlinear.jl @@ -1,162 +1,168 @@ -@testset "Continuous Linear" begin - mock = MOIU.MockOptimizer(MOIU.UniversalFallback(ModelForMock{Float64}())) - config = MOIT.TestConfig(basis = true) - config_no_lhs_modif = MOIT.TestConfig(modify_lhs = false) +using Test +import MathOptInterface +const MOI = MathOptInterface +const MOIT = MOI.Test +const MOIU = MOI.Utilities - function set_mock_optimize_linear1Test!(mock) - MOIU.set_mock_optimize!(mock, - (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [1, 0], - (MOI.ScalarAffineFunction{Float64}, MOI.LessThan{Float64}) => [-1]), - (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [1, 0], - (MOI.ScalarAffineFunction{Float64}, MOI.LessThan{Float64}) => [-1]), - (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [0, 0, 1], - (MOI.ScalarAffineFunction{Float64}, MOI.LessThan{Float64}) => [-2]), - (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [-1, 0, 2]), - (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [1, 0, 0]), - (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [2, 0, 0]), - (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [0, 2, 0]), - (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [1, 1, 0], - (MOI.ScalarAffineFunction{Float64}, MOI.EqualTo{Float64}) => [-1.5], - (MOI.ScalarAffineFunction{Float64}, MOI.GreaterThan{Float64}) => [0.5])) - end - set_mock_optimize_linear1Test!(mock) - MOIT.linear1test(mock, config) - set_mock_optimize_linear1Test!(mock) - MOIT.linear1test(mock, config_no_lhs_modif) - MOIU.set_mock_optimize!(mock, - (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [1, 0], - (MOI.ScalarAffineFunction{Float64}, MOI.LessThan{Float64}) => [-1], - con_basis = - [(MOI.ScalarAffineFunction{Float64}, MOI.LessThan{Float64}) => [MOI.NONBASIC], - (MOI.SingleVariable, MOI.GreaterThan{Float64}) => [MOI.BASIC, MOI.NONBASIC]])) - MOIT.linear2test(mock, config) - MOIU.set_mock_optimize!(mock, - (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [3], con_basis = - [(MOI.ScalarAffineFunction{Float64}, MOI.GreaterThan{Float64}) => [MOI.NONBASIC], - (MOI.SingleVariable, MOI.GreaterThan{Float64}) => [MOI.BASIC]]), - (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [0], con_basis = - [(MOI.ScalarAffineFunction{Float64}, MOI.LessThan{Float64}) => [MOI.BASIC], - (MOI.SingleVariable, MOI.LessThan{Float64}) => [MOI.NONBASIC]])) - MOIT.linear3test(mock, config) - MOIU.set_mock_optimize!(mock, - (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [0, 0]), - (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [100, 0]), - (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [100, -100])) - MOIT.linear4test(mock, config) - function set_mock_optimize_linear5Test!(mock) - MOIU.set_mock_optimize!(mock, - (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [4/3, 4/3]), - (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [2, 0]), - (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [4, 0]), - (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [2])) - end - set_mock_optimize_linear5Test!(mock) - MOIT.linear5test(mock, config) - set_mock_optimize_linear5Test!(mock) - MOIT.linear5test(mock, config_no_lhs_modif) +include("../model_for_mock.jl") + +mock = MOIU.MockOptimizer(MOIU.UniversalFallback(ModelForMock{Float64}())) +config = MOIT.TestConfig(basis = true) +config_no_lhs_modif = MOIT.TestConfig(modify_lhs = false) + +function set_mock_optimize_linear1Test!(mock) + MOIU.set_mock_optimize!(mock, + (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [1, 0], + (MOI.ScalarAffineFunction{Float64}, MOI.LessThan{Float64}) => [-1]), + (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [1, 0], + (MOI.ScalarAffineFunction{Float64}, MOI.LessThan{Float64}) => [-1]), + (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [0, 0, 1], + (MOI.ScalarAffineFunction{Float64}, MOI.LessThan{Float64}) => [-2]), + (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [-1, 0, 2]), + (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [1, 0, 0]), + (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [2, 0, 0]), + (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [0, 2, 0]), + (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [1, 1, 0], + (MOI.ScalarAffineFunction{Float64}, MOI.EqualTo{Float64}) => [-1.5], + (MOI.ScalarAffineFunction{Float64}, MOI.GreaterThan{Float64}) => [0.5])) +end +set_mock_optimize_linear1Test!(mock) +MOIT.linear1test(mock, config) +set_mock_optimize_linear1Test!(mock) +MOIT.linear1test(mock, config_no_lhs_modif) +MOIU.set_mock_optimize!(mock, + (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [1, 0], + (MOI.ScalarAffineFunction{Float64}, MOI.LessThan{Float64}) => [-1], + con_basis = + [(MOI.ScalarAffineFunction{Float64}, MOI.LessThan{Float64}) => [MOI.NONBASIC], + (MOI.SingleVariable, MOI.GreaterThan{Float64}) => [MOI.BASIC, MOI.NONBASIC]])) +MOIT.linear2test(mock, config) +MOIU.set_mock_optimize!(mock, + (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [3], con_basis = + [(MOI.ScalarAffineFunction{Float64}, MOI.GreaterThan{Float64}) => [MOI.NONBASIC], + (MOI.SingleVariable, MOI.GreaterThan{Float64}) => [MOI.BASIC]]), + (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [0], con_basis = + [(MOI.ScalarAffineFunction{Float64}, MOI.LessThan{Float64}) => [MOI.BASIC], + (MOI.SingleVariable, MOI.LessThan{Float64}) => [MOI.NONBASIC]])) +MOIT.linear3test(mock, config) +MOIU.set_mock_optimize!(mock, + (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [0, 0]), + (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [100, 0]), + (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [100, -100])) +MOIT.linear4test(mock, config) +function set_mock_optimize_linear5Test!(mock) + MOIU.set_mock_optimize!(mock, + (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [4/3, 4/3]), + (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [2, 0]), + (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [4, 0]), + (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [2])) +end +set_mock_optimize_linear5Test!(mock) +MOIT.linear5test(mock, config) +set_mock_optimize_linear5Test!(mock) +MOIT.linear5test(mock, config_no_lhs_modif) +MOIU.set_mock_optimize!(mock, + (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [0, 0]), + (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [100, 0]), + (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [100, -100])) +MOIT.linear6test(mock, config) +function set_mock_optimize_linear7Test!(mock) MOIU.set_mock_optimize!(mock, (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [0, 0]), (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [100, 0]), (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [100, -100])) - MOIT.linear6test(mock, config) - function set_mock_optimize_linear7Test!(mock) - MOIU.set_mock_optimize!(mock, - (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [0, 0]), - (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [100, 0]), - (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [100, -100])) - end - set_mock_optimize_linear7Test!(mock) - MOIT.linear7test(mock, config) - set_mock_optimize_linear7Test!(mock) - MOIT.linear7test(mock, config_no_lhs_modif) - MOIU.set_mock_optimize!(mock, - (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, MOI.INFEASIBLE, - tuple(), - (MOI.ScalarAffineFunction{Float64}, MOI.LessThan{Float64}) => [-1])) - MOIT.linear8atest(mock, config) - MOIU.set_mock_optimize!(mock, - (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, MOI.INFEASIBLE)) - MOIT.linear8atest(mock, MOIT.TestConfig(infeas_certificates=false)) - MOIU.set_mock_optimize!(mock, - (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, MOI.DUAL_INFEASIBLE, - MOI.INFEASIBILITY_CERTIFICATE)) - MOIT.linear8btest(mock, config) - MOIU.set_mock_optimize!(mock, - (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, MOI.DUAL_INFEASIBLE)) - MOIT.linear8btest(mock, MOIT.TestConfig(infeas_certificates=false)) - MOIU.set_mock_optimize!(mock, - (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, MOI.DUAL_INFEASIBLE, (MOI.INFEASIBILITY_CERTIFICATE, [1, 1]))) - MOIT.linear8ctest(mock, config) - MOIU.set_mock_optimize!(mock, - (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, MOI.DUAL_INFEASIBLE)) - MOIT.linear8ctest(mock, MOIT.TestConfig(infeas_certificates=false)) - MOIU.set_mock_optimize!(mock, - (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [650/11, 400/11], con_basis = - [(MOI.ScalarAffineFunction{Float64}, MOI.LessThan{Float64}) => [MOI.NONBASIC, MOI.NONBASIC], - (MOI.ScalarAffineFunction{Float64}, MOI.GreaterThan{Float64}) => [MOI.BASIC], - (MOI.SingleVariable, MOI.GreaterThan{Float64}) => [MOI.BASIC, MOI.BASIC]])) - MOIT.linear9test(mock, config) - MOIU.set_mock_optimize!(mock, - (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [5.0, 5.0], con_basis = - [(MOI.ScalarAffineFunction{Float64}, MOI.Interval{Float64}) => [MOI.NONBASIC_AT_UPPER], - (MOI.SingleVariable, MOI.GreaterThan{Float64}) => [MOI.BASIC, MOI.BASIC]], - (MOI.ScalarAffineFunction{Float64}, MOI.Interval{Float64}) => [-1]), - (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [2.5, 2.5], con_basis = - [(MOI.ScalarAffineFunction{Float64}, MOI.Interval{Float64}) => [MOI.NONBASIC_AT_LOWER], - (MOI.SingleVariable, MOI.GreaterThan{Float64}) => [MOI.BASIC, MOI.BASIC]], - (MOI.ScalarAffineFunction{Float64}, MOI.Interval{Float64}) => [1]), - (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [1.0, 1.0], con_basis = - [(MOI.ScalarAffineFunction{Float64}, MOI.Interval{Float64}) => [MOI.NONBASIC_AT_LOWER], - (MOI.SingleVariable, MOI.GreaterThan{Float64}) => [MOI.BASIC, MOI.BASIC]]), - (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [6.0, 6.0], con_basis = - [(MOI.ScalarAffineFunction{Float64}, MOI.Interval{Float64}) => [MOI.NONBASIC_AT_UPPER], - (MOI.SingleVariable, MOI.GreaterThan{Float64}) => [MOI.BASIC, MOI.BASIC]])) - MOIT.linear10test(mock, config) - MOIU.set_mock_optimize!(mock, - (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [0.0, 0.0], con_basis = - [(MOI.ScalarAffineFunction{Float64}, MOI.Interval{Float64}) => [MOI.BASIC], - (MOI.SingleVariable, MOI.GreaterThan{Float64}) => [MOI.NONBASIC, MOI.NONBASIC]], - (MOI.ScalarAffineFunction{Float64}, MOI.Interval{Float64}) => [0])) - MOIT.linear10btest(mock, config) +end +set_mock_optimize_linear7Test!(mock) +MOIT.linear7test(mock, config) +set_mock_optimize_linear7Test!(mock) +MOIT.linear7test(mock, config_no_lhs_modif) +MOIU.set_mock_optimize!(mock, + (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, MOI.INFEASIBLE, + tuple(), + (MOI.ScalarAffineFunction{Float64}, MOI.LessThan{Float64}) => [-1])) +MOIT.linear8atest(mock, config) +MOIU.set_mock_optimize!(mock, + (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, MOI.INFEASIBLE)) +MOIT.linear8atest(mock, MOIT.TestConfig(infeas_certificates=false)) +MOIU.set_mock_optimize!(mock, + (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, MOI.DUAL_INFEASIBLE, + MOI.INFEASIBILITY_CERTIFICATE)) +MOIT.linear8btest(mock, config) +MOIU.set_mock_optimize!(mock, + (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, MOI.DUAL_INFEASIBLE)) +MOIT.linear8btest(mock, MOIT.TestConfig(infeas_certificates=false)) +MOIU.set_mock_optimize!(mock, + (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, MOI.DUAL_INFEASIBLE, (MOI.INFEASIBILITY_CERTIFICATE, [1, 1]))) +MOIT.linear8ctest(mock, config) +MOIU.set_mock_optimize!(mock, + (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, MOI.DUAL_INFEASIBLE)) +MOIT.linear8ctest(mock, MOIT.TestConfig(infeas_certificates=false)) +MOIU.set_mock_optimize!(mock, + (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [650/11, 400/11], con_basis = + [(MOI.ScalarAffineFunction{Float64}, MOI.LessThan{Float64}) => [MOI.NONBASIC, MOI.NONBASIC], + (MOI.ScalarAffineFunction{Float64}, MOI.GreaterThan{Float64}) => [MOI.BASIC], + (MOI.SingleVariable, MOI.GreaterThan{Float64}) => [MOI.BASIC, MOI.BASIC]])) +MOIT.linear9test(mock, config) +MOIU.set_mock_optimize!(mock, + (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [5.0, 5.0], con_basis = + [(MOI.ScalarAffineFunction{Float64}, MOI.Interval{Float64}) => [MOI.NONBASIC_AT_UPPER], + (MOI.SingleVariable, MOI.GreaterThan{Float64}) => [MOI.BASIC, MOI.BASIC]], + (MOI.ScalarAffineFunction{Float64}, MOI.Interval{Float64}) => [-1]), + (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [2.5, 2.5], con_basis = + [(MOI.ScalarAffineFunction{Float64}, MOI.Interval{Float64}) => [MOI.NONBASIC_AT_LOWER], + (MOI.SingleVariable, MOI.GreaterThan{Float64}) => [MOI.BASIC, MOI.BASIC]], + (MOI.ScalarAffineFunction{Float64}, MOI.Interval{Float64}) => [1]), + (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [1.0, 1.0], con_basis = + [(MOI.ScalarAffineFunction{Float64}, MOI.Interval{Float64}) => [MOI.NONBASIC_AT_LOWER], + (MOI.SingleVariable, MOI.GreaterThan{Float64}) => [MOI.BASIC, MOI.BASIC]]), + (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [6.0, 6.0], con_basis = + [(MOI.ScalarAffineFunction{Float64}, MOI.Interval{Float64}) => [MOI.NONBASIC_AT_UPPER], + (MOI.SingleVariable, MOI.GreaterThan{Float64}) => [MOI.BASIC, MOI.BASIC]])) +MOIT.linear10test(mock, config) +MOIU.set_mock_optimize!(mock, + (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [0.0, 0.0], con_basis = + [(MOI.ScalarAffineFunction{Float64}, MOI.Interval{Float64}) => [MOI.BASIC], + (MOI.SingleVariable, MOI.GreaterThan{Float64}) => [MOI.NONBASIC, MOI.NONBASIC]], + (MOI.ScalarAffineFunction{Float64}, MOI.Interval{Float64}) => [0])) +MOIT.linear10btest(mock, config) - MOIU.set_mock_optimize!(mock, - (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [1.0, 1.0]), - (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [0.5, 0.5])) - MOIT.linear11test(mock, config) - MOIU.set_mock_optimize!(mock, - (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, MOI.INFEASIBLE, - tuple(), - (MOI.ScalarAffineFunction{Float64}, MOI.LessThan{Float64}) => [-1, -1])) - MOIT.linear12test(mock, config) - MOIU.set_mock_optimize!(mock, - (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, MOI.INFEASIBLE)) - MOIT.linear12test(mock, MOIT.TestConfig(infeas_certificates=false)) - MOIU.set_mock_optimize!(mock, - (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [1/5, 1/5], - (MOI.ScalarAffineFunction{Float64}, MOI.GreaterThan{Float64}) => [0], - (MOI.ScalarAffineFunction{Float64}, MOI.EqualTo{Float64}) => [0])) - MOIT.linear13test(mock, config) - MOIU.set_mock_optimize!(mock, - (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [0, 1/2, 1], con_basis = - [(MOI.ScalarAffineFunction{Float64}, MOI.LessThan{Float64}) => [MOI.NONBASIC], - (MOI.SingleVariable, MOI.GreaterThan{Float64}) => [MOI.NONBASIC, MOI.BASIC, MOI.BASIC], - (MOI.SingleVariable, MOI.LessThan{Float64}) => [MOI.NONBASIC]], - (MOI.ScalarAffineFunction{Float64}, MOI.LessThan{Float64}) => [-1], - (MOI.SingleVariable, MOI.GreaterThan{Float64}) => [2, 0, 0], - (MOI.SingleVariable, MOI.LessThan{Float64}) => [-2]), - (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [1], - (MOI.ScalarAffineFunction{Float64}, MOI.LessThan{Float64}) => [-1], - (MOI.SingleVariable, MOI.GreaterThan{Float64}) => [0])) - # linear14 has double variable bounds for the z variable - mock.eval_variable_constraint_dual = false - MOIT.linear14test(mock, config) - mock.eval_variable_constraint_dual = true - MOIU.set_mock_optimize!(mock, - (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [0.0], - (MOI.VectorAffineFunction{Float64}, MOI.Zeros) => [0.0, 0.0])) - MOIT.linear15test(mock, config) +MOIU.set_mock_optimize!(mock, + (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [1.0, 1.0]), + (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [0.5, 0.5])) +MOIT.linear11test(mock, config) +MOIU.set_mock_optimize!(mock, + (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, MOI.INFEASIBLE, + tuple(), + (MOI.ScalarAffineFunction{Float64}, MOI.LessThan{Float64}) => [-1, -1])) +MOIT.linear12test(mock, config) +MOIU.set_mock_optimize!(mock, + (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, MOI.INFEASIBLE)) +MOIT.linear12test(mock, MOIT.TestConfig(infeas_certificates=false)) +MOIU.set_mock_optimize!(mock, + (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [1/5, 1/5], + (MOI.ScalarAffineFunction{Float64}, MOI.GreaterThan{Float64}) => [0], + (MOI.ScalarAffineFunction{Float64}, MOI.EqualTo{Float64}) => [0])) +MOIT.linear13test(mock, config) +MOIU.set_mock_optimize!(mock, + (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [0, 1/2, 1], con_basis = + [(MOI.ScalarAffineFunction{Float64}, MOI.LessThan{Float64}) => [MOI.NONBASIC], + (MOI.SingleVariable, MOI.GreaterThan{Float64}) => [MOI.NONBASIC, MOI.BASIC, MOI.BASIC], + (MOI.SingleVariable, MOI.LessThan{Float64}) => [MOI.NONBASIC]], + (MOI.ScalarAffineFunction{Float64}, MOI.LessThan{Float64}) => [-1], + (MOI.SingleVariable, MOI.GreaterThan{Float64}) => [2, 0, 0], + (MOI.SingleVariable, MOI.LessThan{Float64}) => [-2]), + (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [1], + (MOI.ScalarAffineFunction{Float64}, MOI.LessThan{Float64}) => [-1], + (MOI.SingleVariable, MOI.GreaterThan{Float64}) => [0])) +# linear14 has double variable bounds for the z variable +mock.eval_variable_constraint_dual = false +MOIT.linear14test(mock, config) +mock.eval_variable_constraint_dual = true +MOIU.set_mock_optimize!(mock, + (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [0.0], + (MOI.VectorAffineFunction{Float64}, MOI.Zeros) => [0.0, 0.0])) +MOIT.linear15test(mock, config) - MOIU.set_mock_optimize!(mock, - (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [1.0, 0.0])) - MOIT.partial_start_test(mock, config) -end +MOIU.set_mock_optimize!(mock, + (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [1.0, 0.0])) +MOIT.partial_start_test(mock, config) diff --git a/test/Test/contquadratic.jl b/test/Test/contquadratic.jl index 3e7771fc54..010113d078 100644 --- a/test/Test/contquadratic.jl +++ b/test/Test/contquadratic.jl @@ -1,42 +1,48 @@ -@testset "Continuous Quadratic" begin - mock = MOIU.MockOptimizer(Model{Float64}()) - config = MOIT.TestConfig() +using Test +import MathOptInterface +const MOI = MathOptInterface +const MOIT = MOI.Test +const MOIU = MOI.Utilities - @testset "QP" begin - MOIU.set_mock_optimize!(mock, - (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [4/7, 3/7, 6/7])) - MOIT.qp1test(mock, config) - MOIT.qp2test(mock, config) - MOIU.set_mock_optimize!(mock, - (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [1/4, 3/4]), - (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [1.0, 0.0])) - MOIT.qp3test(mock, config) - end - @testset "QCP" begin - MOIU.set_mock_optimize!(mock, - (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [1/2, 7/4], MOI.FEASIBLE_POINT)) - MOIT.qcp1test(mock, config) - MOIU.set_mock_optimize!(mock, - (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [√2], MOI.FEASIBLE_POINT)) - MOIT.qcp2test(mock, config) - MOIU.set_mock_optimize!(mock, - (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [√2], MOI.FEASIBLE_POINT)) - MOIT.qcp3test(mock, config) - MOIU.set_mock_optimize!(mock, - (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [1.0, 1.0], MOI.FEASIBLE_POINT)) - MOIT.qcp4test(mock, config) - end - @testset "Non-convex QCP" begin - MOIU.set_mock_optimize!(mock, - (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [4.0, 1.0], MOI.FEASIBLE_POINT)) - MOIT.ncqcp1test(mock, config) - MOIU.set_mock_optimize!(mock, - (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [2.0, 2.0], MOI.FEASIBLE_POINT)) - MOIT.ncqcp2test(mock, config) - end - @testset "SOCP" begin - MOIU.set_mock_optimize!(mock, - (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [1/2, 1/2, 1/√2])) - MOIT.socp1test(mock, config) - end +include("../model.jl") + +mock = MOIU.MockOptimizer(Model{Float64}()) +config = MOIT.TestConfig() + +@testset "QP" begin + MOIU.set_mock_optimize!(mock, + (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [4/7, 3/7, 6/7])) + MOIT.qp1test(mock, config) + MOIT.qp2test(mock, config) + MOIU.set_mock_optimize!(mock, + (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [1/4, 3/4]), + (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [1.0, 0.0])) + MOIT.qp3test(mock, config) +end +@testset "QCP" begin + MOIU.set_mock_optimize!(mock, + (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [1/2, 7/4], MOI.FEASIBLE_POINT)) + MOIT.qcp1test(mock, config) + MOIU.set_mock_optimize!(mock, + (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [√2], MOI.FEASIBLE_POINT)) + MOIT.qcp2test(mock, config) + MOIU.set_mock_optimize!(mock, + (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [√2], MOI.FEASIBLE_POINT)) + MOIT.qcp3test(mock, config) + MOIU.set_mock_optimize!(mock, + (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [1.0, 1.0], MOI.FEASIBLE_POINT)) + MOIT.qcp4test(mock, config) +end +@testset "Non-convex QCP" begin + MOIU.set_mock_optimize!(mock, + (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [4.0, 1.0], MOI.FEASIBLE_POINT)) + MOIT.ncqcp1test(mock, config) + MOIU.set_mock_optimize!(mock, + (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [2.0, 2.0], MOI.FEASIBLE_POINT)) + MOIT.ncqcp2test(mock, config) +end +@testset "SOCP" begin + MOIU.set_mock_optimize!(mock, + (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [1/2, 1/2, 1/√2])) + MOIT.socp1test(mock, config) end diff --git a/test/Test/intconic.jl b/test/Test/intconic.jl index 3987bde800..1a735a879a 100644 --- a/test/Test/intconic.jl +++ b/test/Test/intconic.jl @@ -1,9 +1,15 @@ -@testset "Integer Conic" begin - mock = MOIU.MockOptimizer(Model{Float64}()) - config = MOIT.TestConfig() +using Test +import MathOptInterface +const MOI = MathOptInterface +const MOIT = MOI.Test +const MOIU = MOI.Utilities - @testset "SOC" begin - mock.optimize! = (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [1.0, 1.0, 0.0]) - MOIT.intsoc1test(mock, config) - end +include("../model.jl") + +mock = MOIU.MockOptimizer(Model{Float64}()) +config = MOIT.TestConfig() + +@testset "SOC" begin + mock.optimize! = (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [1.0, 1.0, 0.0]) + MOIT.intsoc1test(mock, config) end diff --git a/test/Test/intlinear.jl b/test/Test/intlinear.jl index 38abca3efb..0bcbea02b7 100644 --- a/test/Test/intlinear.jl +++ b/test/Test/intlinear.jl @@ -1,24 +1,30 @@ -@testset "Integer Linear" begin - mock = MOIU.MockOptimizer(Model{Float64}()) - config = MOIT.TestConfig() +using Test +import MathOptInterface +const MOI = MathOptInterface +const MOIT = MOI.Test +const MOIU = MOI.Utilities - MOIU.set_mock_optimize!(mock, - (mock::MOIU.MockOptimizer) -> begin - MOI.set(mock, MOI.ObjectiveBound(), 20.0) - MOIU.mock_optimize!(mock, [4, 5, 1]) - end) - MOIT.int1test(mock, config) - MOIU.set_mock_optimize!(mock, - (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [0, 1, 2]), - (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [1, 1, 2]), - (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [0.0, 0.0, 1.0, 1.0, 0.0, 1.0, 0.0, 0.0, 3.0, 12.0]), - (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [0.0, 0.0, 2.0, 2.0, 0.0, 2.0, 0.0, 0.0, 6.0, 24.0])) - MOIT.int2test(mock, config) - # FIXME [1, 0...] is not the correct optimal solution but it passes the test - MOIU.set_mock_optimize!(mock, - (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [1.0; zeros(10)])) - MOIT.int3test(mock, config) - MOIU.set_mock_optimize!(mock, - (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [1, 0, 0, 1, 1])) - MOIT.knapsacktest(mock, config) -end +include("../model.jl") + +mock = MOIU.MockOptimizer(Model{Float64}()) +config = MOIT.TestConfig() + +MOIU.set_mock_optimize!(mock, + (mock::MOIU.MockOptimizer) -> begin + MOI.set(mock, MOI.ObjectiveBound(), 20.0) + MOIU.mock_optimize!(mock, [4, 5, 1]) + end) +MOIT.int1test(mock, config) +MOIU.set_mock_optimize!(mock, + (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [0, 1, 2]), + (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [1, 1, 2]), + (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [0.0, 0.0, 1.0, 1.0, 0.0, 1.0, 0.0, 0.0, 3.0, 12.0]), + (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [0.0, 0.0, 2.0, 2.0, 0.0, 2.0, 0.0, 0.0, 6.0, 24.0])) +MOIT.int2test(mock, config) +# FIXME [1, 0...] is not the correct optimal solution but it passes the test +MOIU.set_mock_optimize!(mock, + (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [1.0; zeros(10)])) +MOIT.int3test(mock, config) +MOIU.set_mock_optimize!(mock, + (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [1, 0, 0, 1, 1])) +MOIT.knapsacktest(mock, config) diff --git a/test/Test/modellike.jl b/test/Test/modellike.jl index 561483a797..f08cc09536 100644 --- a/test/Test/modellike.jl +++ b/test/Test/modellike.jl @@ -1,4 +1,10 @@ -@testset "ModelLike" begin +using Test +import MathOptInterface +const MOI = MathOptInterface +const MOIT = MOI.Test + +@testset "Failed copy" begin + include("../dummy.jl") model = DummyModelWithAdd() MOIT.failcopytestc(model) MOIT.failcopytestia(model) diff --git a/test/Test/unit.jl b/test/Test/unit.jl index ec638bbd1e..8402a4b184 100644 --- a/test/Test/unit.jl +++ b/test/Test/unit.jl @@ -1,3 +1,11 @@ +using Test +import MathOptInterface +const MOI = MathOptInterface +const MOIT = MOI.Test +const MOIU = MOI.Utilities + +include("../model.jl") + @testset "Basic Constraint Tests" begin mock = MOIU.MockOptimizer(Model{Float64}()) config = MOIT.TestConfig() diff --git a/test/Utilities/Utilities.jl b/test/Utilities/Utilities.jl new file mode 100644 index 0000000000..9e8a905f92 --- /dev/null +++ b/test/Utilities/Utilities.jl @@ -0,0 +1,29 @@ +using Test + +@testset "Functions" begin + include("functions.jl") +end +@testset "Sets" begin + include("sets.jl") +end +@testset "Constraints" begin + include("constraints.jl") +end +@testset "Model" begin + include("model.jl") +end +@testset "Universal Fallback" begin + include("universalfallback.jl") +end +@testset "Parser" begin + include("parser.jl") +end +@testset "Mock Optimizer" begin + include("mockoptimizer.jl") +end +@testset "Caching Optimizer" begin + include("cachingoptimizer.jl") +end +@testset "Copy" begin + include("copy.jl") +end diff --git a/test/Utilities/cachingoptimizer.jl b/test/Utilities/cachingoptimizer.jl index 44dcf6f2f9..6bd93f5aee 100644 --- a/test/Utilities/cachingoptimizer.jl +++ b/test/Utilities/cachingoptimizer.jl @@ -1,4 +1,25 @@ -@MOIU.model ModelForCachingOptimizer (MOI.ZeroOne, MOI.Integer) (MOI.EqualTo, MOI.GreaterThan, MOI.LessThan, MOI.Interval) (MOI.Zeros, MOI.Nonnegatives, MOI.Nonpositives, MOI.SecondOrderCone, MOI.RotatedSecondOrderCone, MOI.GeometricMeanCone, MOI.ExponentialCone, MOI.DualExponentialCone, MOI.PositiveSemidefiniteConeTriangle, MOI.RootDetConeTriangle, MOI.LogDetConeTriangle) () (MOI.SingleVariable,) (MOI.ScalarAffineFunction, MOI.ScalarQuadraticFunction) (MOI.VectorOfVariables,) (MOI.VectorAffineFunction,) +using Test +import MathOptInterface +const MOI = MathOptInterface +const MOIT = MOI.Test +const MOIU = MOI.Utilities + +include("../model.jl") +include("../model_for_mock.jl") + +MOIU.@model(ModelForCachingOptimizer, + (MOI.ZeroOne, MOI.Integer), + (MOI.EqualTo, MOI.GreaterThan, MOI.LessThan, MOI.Interval), + (MOI.Zeros, MOI.Nonnegatives, MOI.Nonpositives, MOI.SecondOrderCone, + MOI.RotatedSecondOrderCone, MOI.GeometricMeanCone, + MOI.ExponentialCone, MOI.DualExponentialCone, + MOI.PositiveSemidefiniteConeTriangle, MOI.RootDetConeTriangle, + MOI.LogDetConeTriangle), + (), + (MOI.SingleVariable,), + (MOI.ScalarAffineFunction, MOI.ScalarQuadraticFunction), + (MOI.VectorOfVariables,), + (MOI.VectorAffineFunction,)) @testset "Test default attributes" begin # Without an optimizer attached (i.e., `MOI.state(model) == NO_OPTIMIZER`) we @@ -241,7 +262,7 @@ end end -@testset "CachingOptimizer constructor with optimizer" begin +@testset "Constructor with optimizer" begin @testset "Empty model and optimizer" begin s = MOIU.MockOptimizer(ModelForMock{Float64}(), supports_names=false) model = ModelForCachingOptimizer{Float64}() diff --git a/test/Utilities/constraints.jl b/test/Utilities/constraints.jl index 4f4c6e4ac4..6216a92b39 100644 --- a/test/Utilities/constraints.jl +++ b/test/Utilities/constraints.jl @@ -1,4 +1,10 @@ -@testset "Scalar constraints" begin +using Test +import MathOptInterface +const MOI = MathOptInterface + +include("../model.jl") + +@testset "Scalar" begin model = Model{Float64}() x = MOI.add_variable(model) @testset "SingleVariable" begin diff --git a/test/Utilities/copy.jl b/test/Utilities/copy.jl index bf80adc551..397aaf9849 100644 --- a/test/Utilities/copy.jl +++ b/test/Utilities/copy.jl @@ -1,33 +1,39 @@ -@testset "Copy test" begin - @testset "AUTOMATIC copy" begin - src = DummyModel() - dest = DummyModel() +using Test +import MathOptInterface +const MOI = MathOptInterface +const MOIT = MOI.Test +const MOIU = MOI.Utilities + +include("../dummy.jl") + +@testset "AUTOMATIC" begin + src = DummyModel() + dest = DummyModel() + @test_throws ErrorException MOIU.automatic_copy_to(dest, src) + try @test_throws ErrorException MOIU.automatic_copy_to(dest, src) - try - @test_throws ErrorException MOIU.automatic_copy_to(dest, src) - catch err - @test sprint(showerror, err) == "Model DummyModel does not" * - " support copy with names." - end - end - @testset "Default copy" begin - @test !MOIU.supports_default_copy_to(DummyModel(), false) - @test !MOIU.supports_default_copy_to(DummyModel(), true) - model = Model{Float64}() - MOIT.failcopytestc(model) - MOIT.failcopytestia(model) - MOIT.failcopytestva(model) - MOIT.failcopytestca(model) - MOIT.copytest(model, Model{Float64}()) - end - @testset "Allocate-Load copy" begin - @test !MOIU.supports_allocate_load(DummyModel(), false) - @test !MOIU.supports_allocate_load(DummyModel(), true) - mock = MOIU.MockOptimizer(Model{Float64}(), needs_allocate_load=true) - MOIT.failcopytestc(mock) - MOIT.failcopytestia(mock) - MOIT.failcopytestva(mock) - MOIT.failcopytestca(mock) - MOIT.copytest(mock, Model{Float64}()) + catch err + @test sprint(showerror, err) == "Model DummyModel does not" * + " support copy with names." end end +@testset "Default" begin + @test !MOIU.supports_default_copy_to(DummyModel(), false) + @test !MOIU.supports_default_copy_to(DummyModel(), true) + model = Model{Float64}() + MOIT.failcopytestc(model) + MOIT.failcopytestia(model) + MOIT.failcopytestva(model) + MOIT.failcopytestca(model) + MOIT.copytest(model, Model{Float64}()) +end +@testset "Allocate-Load" begin + @test !MOIU.supports_allocate_load(DummyModel(), false) + @test !MOIU.supports_allocate_load(DummyModel(), true) + mock = MOIU.MockOptimizer(Model{Float64}(), needs_allocate_load=true) + MOIT.failcopytestc(mock) + MOIT.failcopytestia(mock) + MOIT.failcopytestva(mock) + MOIT.failcopytestca(mock) + MOIT.copytest(mock, Model{Float64}()) +end diff --git a/test/Utilities/functions.jl b/test/Utilities/functions.jl index 0e91cca91a..05bbf35828 100644 --- a/test/Utilities/functions.jl +++ b/test/Utilities/functions.jl @@ -3,668 +3,666 @@ using MathOptInterface const MOI = MathOptInterface const MOIU = MOI.Utilities -@testset "Function tests" begin - w = MOI.VariableIndex(0) - x = MOI.VariableIndex(1) - y = MOI.VariableIndex(2) - z = MOI.VariableIndex(3) - @testset "Vectorization" begin - g = MOI.VectorAffineFunction(MOI.VectorAffineTerm.([3, 1], - MOI.ScalarAffineTerm.([5, 2], - [y, x])), - [3, 1, 4]) - @testset "vectorize" begin - g1 = MOI.ScalarAffineFunction([MOI.ScalarAffineTerm(2, x)], 3) - g2 = MOI.ScalarAffineFunction(MOI.ScalarAffineTerm{Int}[], 1) - g3 = MOI.ScalarAffineFunction([MOI.ScalarAffineTerm(5, y)], 4) - @test g ≈ MOIU.vectorize([g1, g2, g3]) +w = MOI.VariableIndex(0) +x = MOI.VariableIndex(1) +y = MOI.VariableIndex(2) +z = MOI.VariableIndex(3) +@testset "Vectorization" begin + g = MOI.VectorAffineFunction(MOI.VectorAffineTerm.([3, 1], + MOI.ScalarAffineTerm.([5, 2], + [y, x])), + [3, 1, 4]) + @testset "vectorize" begin + g1 = MOI.ScalarAffineFunction([MOI.ScalarAffineTerm(2, x)], 3) + g2 = MOI.ScalarAffineFunction(MOI.ScalarAffineTerm{Int}[], 1) + g3 = MOI.ScalarAffineFunction([MOI.ScalarAffineTerm(5, y)], 4) + @test g ≈ MOIU.vectorize([g1, g2, g3]) + end + @testset "operate vcat" begin + v = MOI.VectorOfVariables([y, w]) + wf = MOI.SingleVariable(w) + xf = MOI.SingleVariable(x) + @testset "Variable" begin + # TODO #616 end - @testset "operate vcat" begin - v = MOI.VectorOfVariables([y, w]) - wf = MOI.SingleVariable(w) - xf = MOI.SingleVariable(x) - @testset "Variable" begin - # TODO #616 - end - f = MOI.ScalarAffineFunction( - MOI.ScalarAffineTerm.([2, 4], [x, z]), 5) - g = MOI.VectorAffineFunction( - MOI.VectorAffineTerm.([3, 1], MOI.ScalarAffineTerm.([5, 2], [y, x])), - [3, 1, 4]) - @testset "Affine" begin - @test MOIU.promote_operation(vcat, Int, typeof(wf), typeof(f), - typeof(v), Int, typeof(g), typeof(xf), - Int) == MOI.VectorAffineFunction{Int} - F = MOIU.operate(vcat, Int, wf, f, v, 3, g, xf, -4) - expected_terms = MOI.VectorAffineTerm.( - [1, 2, 2, 3, 4, 8, 6, 9], - MOI.ScalarAffineTerm.([1, 2, 4, 1, 1, 5, 2, 1], - [w, x, z, y, w, y, x, x])) - expected_constants = [0, 5, 0, 0, 3, 3, 1, 4, 0, -4] - F = MOIU.operate(vcat, Int, wf, f, v, 3, g, xf, -4) - @test F.terms == expected_terms - @test F.constants == expected_constants - end - @testset "Quadratic" begin - @test MOIU.promote_operation( - vcat, Int, MOI.VectorQuadraticFunction{Int}, typeof(wf), - typeof(f), typeof(v), Int, MOI.ScalarQuadraticFunction{Int}, - typeof(g), typeof(xf), Int) == MOI.VectorQuadraticFunction{Int} - # TODO - end + f = MOI.ScalarAffineFunction( + MOI.ScalarAffineTerm.([2, 4], [x, z]), 5) + g = MOI.VectorAffineFunction( + MOI.VectorAffineTerm.([3, 1], MOI.ScalarAffineTerm.([5, 2], [y, x])), + [3, 1, 4]) + @testset "Affine" begin + @test MOIU.promote_operation(vcat, Int, typeof(wf), typeof(f), + typeof(v), Int, typeof(g), typeof(xf), + Int) == MOI.VectorAffineFunction{Int} + F = MOIU.operate(vcat, Int, wf, f, v, 3, g, xf, -4) + expected_terms = MOI.VectorAffineTerm.( + [1, 2, 2, 3, 4, 8, 6, 9], + MOI.ScalarAffineTerm.([1, 2, 4, 1, 1, 5, 2, 1], + [w, x, z, y, w, y, x, x])) + expected_constants = [0, 5, 0, 0, 3, 3, 1, 4, 0, -4] + F = MOIU.operate(vcat, Int, wf, f, v, 3, g, xf, -4) + @test F.terms == expected_terms + @test F.constants == expected_constants + end + @testset "Quadratic" begin + @test MOIU.promote_operation( + vcat, Int, MOI.VectorQuadraticFunction{Int}, typeof(wf), + typeof(f), typeof(v), Int, MOI.ScalarQuadraticFunction{Int}, + typeof(g), typeof(xf), Int) == MOI.VectorQuadraticFunction{Int} + # TODO end end - @testset "MultirowChange construction" begin - chg1 = MOI.MultirowChange(w, [(Int32(2), 2.0), (Int32(1), 3.0)]) - chg2 = MOI.MultirowChange(w, [(Int64(2), 2.0), (Int64(1), 3.0)]) - @test chg1.variable == chg2.variable - @test chg1.new_coefficients == chg2.new_coefficients - end - @testset "VectorAffineTerm/VectorQuadraticTerm construction" begin - scalaraffine = MOI.ScalarAffineTerm(2.0, z) - @test MOI.VectorAffineTerm(Int32(3), scalaraffine) === MOI.VectorAffineTerm(Int64(3), scalaraffine) - @test MOI.VectorAffineTerm{Float64}(Int32(3), scalaraffine) === MOI.VectorAffineTerm(Int64(3), scalaraffine) - scalarquad = MOI.ScalarQuadraticTerm(2.0, y, z) - @test MOI.VectorQuadraticTerm(Int32(3), scalarquad) === MOI.VectorQuadraticTerm(Int64(3), scalarquad) - @test MOI.VectorQuadraticTerm{Float64}(Int32(3), scalarquad) === MOI.VectorQuadraticTerm(Int64(3), scalarquad) - end - @testset "evalvariables" begin - # We do tests twice to make sure the function is not modified - vals = Dict(w=>0, x=>3, y=>1, z=>5) - fsv = MOI.SingleVariable(z) - @test MOI.output_dimension(fsv) == 1 - @test MOIU.evalvariables(vi -> vals[vi], fsv) ≈ 5 - @test MOIU.evalvariables(vi -> vals[vi], fsv) ≈ 5 - fvv = MOI.VectorOfVariables([x, z, y]) - @test MOI.output_dimension(fvv) == 3 - @test MOIU.evalvariables(vi -> vals[vi], fvv) ≈ [3, 5, 1] - @test MOIU.evalvariables(vi -> vals[vi], fvv) ≈ [3, 5, 1] - fsa = MOI.ScalarAffineFunction([MOI.ScalarAffineTerm(1.0, x), MOI.ScalarAffineTerm(3.0, z), MOI.ScalarAffineTerm(2.0, y)], 2.0) - @test MOI.output_dimension(fsa) == 1 - @test MOIU.evalvariables(vi -> vals[vi], fsa) ≈ 22 - @test MOIU.evalvariables(vi -> vals[vi], fsa) ≈ 22 - fva = MOI.VectorAffineFunction(MOI.VectorAffineTerm.([2, 1, 2], MOI.ScalarAffineTerm.([1.0, 3.0, 2.0], [x, z, y])), [-3.0, 2.0]) - @test MOI.output_dimension(fva) == 2 - @test MOIU.evalvariables(vi -> vals[vi], fva) ≈ [12, 7] - @test MOIU.evalvariables(vi -> vals[vi], fva) ≈ [12, 7] - fsq = MOI.ScalarQuadraticFunction(MOI.ScalarAffineTerm.(1.0, [x, y]), - MOI.ScalarQuadraticTerm.(1.0, [x, w, w], [z, z, y]), -3.0) - @test MOI.output_dimension(fsq) == 1 - @test MOIU.evalvariables(vi -> vals[vi], fsq) ≈ 16 - @test MOIU.evalvariables(vi -> vals[vi], fsq) ≈ 16 - fvq = MOI.VectorQuadraticFunction(MOI.VectorAffineTerm.([2, 1], MOI.ScalarAffineTerm.(1.0, [x, y])), - MOI.VectorQuadraticTerm.([1, 2, 2], MOI.ScalarQuadraticTerm.(1.0, [x, w, w], [z, z, y])), [-3.0, -2.0]) - @test MOI.output_dimension(fvq) == 2 - @test MOIU.evalvariables(vi -> vals[vi], fvq) ≈ [13, 1] - @test MOIU.evalvariables(vi -> vals[vi], fvq) ≈ [13, 1] - end - @testset "mapvariables" begin - fsq = MOI.ScalarQuadraticFunction(MOI.ScalarAffineTerm.(1.0, [x, y]), - MOI.ScalarQuadraticTerm.(1.0, [x, w, w], [z, z, y]), -3.0) - gsq = MOIU.mapvariables(Dict(x => y, y => z, w => w, z => x), fsq) - sats = MOI.ScalarAffineTerm.(1.0, [y, z]) - sqts = MOI.ScalarQuadraticTerm.(1.0, [y, w, w], [x, x, z]) - @test gsq.affine_terms == sats - @test gsq.quadratic_terms == sqts - @test gsq.constant == -3. - fvq = MOI.VectorQuadraticFunction(MOI.VectorAffineTerm.([2, 1], MOI.ScalarAffineTerm.(1.0, [x, y])), - MOI.VectorQuadraticTerm.([1, 2, 2], MOI.ScalarQuadraticTerm.(1.0, [x, w, w], [z, z, y])), [-3.0, -2.0]) - gvq = MOIU.mapvariables(Dict(x => y, y => z, w => w, z => x), fvq) - @test gvq.affine_terms == MOI.VectorAffineTerm.([2, 1], sats) - @test gvq.quadratic_terms == MOI.VectorQuadraticTerm.([1, 2, 2], sqts) - @test MOIU.constant(gvq) == [-3., -2.] - end - @testset "Conversion VectorOfVariables -> VectorAffineFunction" begin - f = MOI.VectorAffineFunction{Int}(MOI.VectorOfVariables([z, x, y])) - @test f isa MOI.VectorAffineFunction{Int} - @test f.terms == MOI.VectorAffineTerm.(1:3, MOI.ScalarAffineTerm.(ones(Int, 3), [z, x, y])) - @test all(iszero.(MOIU.constant(f))) - f = MOI.VectorAffineFunction{Float64}(MOI.VectorOfVariables([x, w])) - @test f isa MOI.VectorAffineFunction{Float64} - @test f.terms == MOI.VectorAffineTerm.(1:2, MOI.ScalarAffineTerm.(1.0, [x, w])) - @test all(iszero.(MOIU.constant(f))) - end - @testset "Iteration and indexing on VectorOfVariables" begin - f = MOI.VectorOfVariables([z, w, x, y]) - it = MOIU.eachscalar(f) - @test length(it) == 4 - @test eltype(it) == MOI.SingleVariable - @test collect(it) == [MOI.SingleVariable(z), MOI.SingleVariable(w), MOI.SingleVariable(x), MOI.SingleVariable(y)] - @test it[2] == MOI.SingleVariable(w) - @test it[end] == MOI.SingleVariable(y) - end - @testset "Indexing on VectorAffineFunction" begin - f = MOI.VectorAffineFunction(MOI.VectorAffineTerm.([2, 1, 3, 2, 2, 1, 3, 1, 2], - MOI.ScalarAffineTerm.([1, 7, 2, 9, 3, 1, 6, 4, 1], - [x, y, z, z, y, z, x, x, y])), - [2, 7, 5]) - it = MOIU.eachscalar(f) - @test length(it) == 3 - @test eltype(it) == MOI.ScalarAffineFunction{Int} - g = it[2] - @test g isa MOI.ScalarAffineFunction - @test g.terms == MOI.ScalarAffineTerm.([1, 9, 3, 1], [x, z, y, y]) - @test g.constant == 7 - g = it[1] - @test g isa MOI.ScalarAffineFunction - @test g.terms == MOI.ScalarAffineTerm.([7, 1, 4], [y, z, x]) - @test g.constant == 2 - g = it[end] - @test g isa MOI.ScalarAffineFunction - @test g.terms == MOI.ScalarAffineTerm.([2, 6], [z, x]) - @test g.constant == 5 - h = it[[3, 1]] - @test h isa MOI.VectorAffineFunction - @test h.terms == MOI.VectorAffineTerm.([1, 1, 2, 2, 2], MOI.ScalarAffineTerm.([2, 6, 7, 1, 4], [z, x, y, z, x])) - @test MOIU.constant(h) == [5, 2] - F = MOIU.operate(vcat, Int, it[[1, 2]], it[3]) - @test F isa MOI.VectorAffineFunction{Int} - @test F.terms == MOI.VectorAffineTerm.([1, 1, 1, 2, 2, 2, 2, 3, 3], MOI.ScalarAffineTerm.([7, 1, 4, 1, 9, 3, 1, 2, 6], [y, z, x, x, z, y, y, z, x])) - @test MOIU.constant(F) == MOIU.constant(f) - end - @testset "Indexing on VectorQuadraticFunction" begin - f = MOI.VectorQuadraticFunction(MOI.VectorAffineTerm.([2, 1, 3, 2, 2], - MOI.ScalarAffineTerm.([1, 7, 2, 9, 3], - [x, y, z, z, y])), - MOI.VectorQuadraticTerm.([2, 3, 1, 2], - MOI.ScalarQuadraticTerm.([1, 6, 4, 3], - [z, x, x, y], - [y, z, z, y])), - [2, 7, 5]) - it = MOIU.eachscalar(f) - @test length(it) == 3 - @test eltype(it) == MOI.ScalarQuadraticFunction{Int} - g = it[2] - @test g isa MOI.ScalarQuadraticFunction - @test g.affine_terms == MOI.ScalarAffineTerm.([1, 9, 3], [x, z, y]) - @test g.quadratic_terms == MOI.ScalarQuadraticTerm.([1, 3], [z, y], [y, y]) - @test g.constant == 7 - g = it[end] - @test g isa MOI.ScalarQuadraticFunction - @test g.affine_terms == MOI.ScalarAffineTerm.([2], [z]) - @test g.quadratic_terms == MOI.ScalarQuadraticTerm.([6], [x], [z]) - @test g.constant == 5 +end +@testset "MultirowChange construction" begin + chg1 = MOI.MultirowChange(w, [(Int32(2), 2.0), (Int32(1), 3.0)]) + chg2 = MOI.MultirowChange(w, [(Int64(2), 2.0), (Int64(1), 3.0)]) + @test chg1.variable == chg2.variable + @test chg1.new_coefficients == chg2.new_coefficients +end +@testset "VectorAffineTerm/VectorQuadraticTerm construction" begin + scalaraffine = MOI.ScalarAffineTerm(2.0, z) + @test MOI.VectorAffineTerm(Int32(3), scalaraffine) === MOI.VectorAffineTerm(Int64(3), scalaraffine) + @test MOI.VectorAffineTerm{Float64}(Int32(3), scalaraffine) === MOI.VectorAffineTerm(Int64(3), scalaraffine) + scalarquad = MOI.ScalarQuadraticTerm(2.0, y, z) + @test MOI.VectorQuadraticTerm(Int32(3), scalarquad) === MOI.VectorQuadraticTerm(Int64(3), scalarquad) + @test MOI.VectorQuadraticTerm{Float64}(Int32(3), scalarquad) === MOI.VectorQuadraticTerm(Int64(3), scalarquad) +end +@testset "evalvariables" begin + # We do tests twice to make sure the function is not modified + vals = Dict(w=>0, x=>3, y=>1, z=>5) + fsv = MOI.SingleVariable(z) + @test MOI.output_dimension(fsv) == 1 + @test MOIU.evalvariables(vi -> vals[vi], fsv) ≈ 5 + @test MOIU.evalvariables(vi -> vals[vi], fsv) ≈ 5 + fvv = MOI.VectorOfVariables([x, z, y]) + @test MOI.output_dimension(fvv) == 3 + @test MOIU.evalvariables(vi -> vals[vi], fvv) ≈ [3, 5, 1] + @test MOIU.evalvariables(vi -> vals[vi], fvv) ≈ [3, 5, 1] + fsa = MOI.ScalarAffineFunction([MOI.ScalarAffineTerm(1.0, x), MOI.ScalarAffineTerm(3.0, z), MOI.ScalarAffineTerm(2.0, y)], 2.0) + @test MOI.output_dimension(fsa) == 1 + @test MOIU.evalvariables(vi -> vals[vi], fsa) ≈ 22 + @test MOIU.evalvariables(vi -> vals[vi], fsa) ≈ 22 + fva = MOI.VectorAffineFunction(MOI.VectorAffineTerm.([2, 1, 2], MOI.ScalarAffineTerm.([1.0, 3.0, 2.0], [x, z, y])), [-3.0, 2.0]) + @test MOI.output_dimension(fva) == 2 + @test MOIU.evalvariables(vi -> vals[vi], fva) ≈ [12, 7] + @test MOIU.evalvariables(vi -> vals[vi], fva) ≈ [12, 7] + fsq = MOI.ScalarQuadraticFunction(MOI.ScalarAffineTerm.(1.0, [x, y]), + MOI.ScalarQuadraticTerm.(1.0, [x, w, w], [z, z, y]), -3.0) + @test MOI.output_dimension(fsq) == 1 + @test MOIU.evalvariables(vi -> vals[vi], fsq) ≈ 16 + @test MOIU.evalvariables(vi -> vals[vi], fsq) ≈ 16 + fvq = MOI.VectorQuadraticFunction(MOI.VectorAffineTerm.([2, 1], MOI.ScalarAffineTerm.(1.0, [x, y])), + MOI.VectorQuadraticTerm.([1, 2, 2], MOI.ScalarQuadraticTerm.(1.0, [x, w, w], [z, z, y])), [-3.0, -2.0]) + @test MOI.output_dimension(fvq) == 2 + @test MOIU.evalvariables(vi -> vals[vi], fvq) ≈ [13, 1] + @test MOIU.evalvariables(vi -> vals[vi], fvq) ≈ [13, 1] +end +@testset "mapvariables" begin + fsq = MOI.ScalarQuadraticFunction(MOI.ScalarAffineTerm.(1.0, [x, y]), + MOI.ScalarQuadraticTerm.(1.0, [x, w, w], [z, z, y]), -3.0) + gsq = MOIU.mapvariables(Dict(x => y, y => z, w => w, z => x), fsq) + sats = MOI.ScalarAffineTerm.(1.0, [y, z]) + sqts = MOI.ScalarQuadraticTerm.(1.0, [y, w, w], [x, x, z]) + @test gsq.affine_terms == sats + @test gsq.quadratic_terms == sqts + @test gsq.constant == -3. + fvq = MOI.VectorQuadraticFunction(MOI.VectorAffineTerm.([2, 1], MOI.ScalarAffineTerm.(1.0, [x, y])), + MOI.VectorQuadraticTerm.([1, 2, 2], MOI.ScalarQuadraticTerm.(1.0, [x, w, w], [z, z, y])), [-3.0, -2.0]) + gvq = MOIU.mapvariables(Dict(x => y, y => z, w => w, z => x), fvq) + @test gvq.affine_terms == MOI.VectorAffineTerm.([2, 1], sats) + @test gvq.quadratic_terms == MOI.VectorQuadraticTerm.([1, 2, 2], sqts) + @test MOIU.constant(gvq) == [-3., -2.] +end +@testset "Conversion VectorOfVariables -> VectorAffineFunction" begin + f = MOI.VectorAffineFunction{Int}(MOI.VectorOfVariables([z, x, y])) + @test f isa MOI.VectorAffineFunction{Int} + @test f.terms == MOI.VectorAffineTerm.(1:3, MOI.ScalarAffineTerm.(ones(Int, 3), [z, x, y])) + @test all(iszero.(MOIU.constant(f))) + f = MOI.VectorAffineFunction{Float64}(MOI.VectorOfVariables([x, w])) + @test f isa MOI.VectorAffineFunction{Float64} + @test f.terms == MOI.VectorAffineTerm.(1:2, MOI.ScalarAffineTerm.(1.0, [x, w])) + @test all(iszero.(MOIU.constant(f))) +end +@testset "Iteration and indexing on VectorOfVariables" begin + f = MOI.VectorOfVariables([z, w, x, y]) + it = MOIU.eachscalar(f) + @test length(it) == 4 + @test eltype(it) == MOI.SingleVariable + @test collect(it) == [MOI.SingleVariable(z), MOI.SingleVariable(w), MOI.SingleVariable(x), MOI.SingleVariable(y)] + @test it[2] == MOI.SingleVariable(w) + @test it[end] == MOI.SingleVariable(y) +end +@testset "Indexing on VectorAffineFunction" begin + f = MOI.VectorAffineFunction(MOI.VectorAffineTerm.([2, 1, 3, 2, 2, 1, 3, 1, 2], + MOI.ScalarAffineTerm.([1, 7, 2, 9, 3, 1, 6, 4, 1], + [x, y, z, z, y, z, x, x, y])), + [2, 7, 5]) + it = MOIU.eachscalar(f) + @test length(it) == 3 + @test eltype(it) == MOI.ScalarAffineFunction{Int} + g = it[2] + @test g isa MOI.ScalarAffineFunction + @test g.terms == MOI.ScalarAffineTerm.([1, 9, 3, 1], [x, z, y, y]) + @test g.constant == 7 + g = it[1] + @test g isa MOI.ScalarAffineFunction + @test g.terms == MOI.ScalarAffineTerm.([7, 1, 4], [y, z, x]) + @test g.constant == 2 + g = it[end] + @test g isa MOI.ScalarAffineFunction + @test g.terms == MOI.ScalarAffineTerm.([2, 6], [z, x]) + @test g.constant == 5 + h = it[[3, 1]] + @test h isa MOI.VectorAffineFunction + @test h.terms == MOI.VectorAffineTerm.([1, 1, 2, 2, 2], MOI.ScalarAffineTerm.([2, 6, 7, 1, 4], [z, x, y, z, x])) + @test MOIU.constant(h) == [5, 2] + F = MOIU.operate(vcat, Int, it[[1, 2]], it[3]) + @test F isa MOI.VectorAffineFunction{Int} + @test F.terms == MOI.VectorAffineTerm.([1, 1, 1, 2, 2, 2, 2, 3, 3], MOI.ScalarAffineTerm.([7, 1, 4, 1, 9, 3, 1, 2, 6], [y, z, x, x, z, y, y, z, x])) + @test MOIU.constant(F) == MOIU.constant(f) +end +@testset "Indexing on VectorQuadraticFunction" begin + f = MOI.VectorQuadraticFunction(MOI.VectorAffineTerm.([2, 1, 3, 2, 2], + MOI.ScalarAffineTerm.([1, 7, 2, 9, 3], + [x, y, z, z, y])), + MOI.VectorQuadraticTerm.([2, 3, 1, 2], + MOI.ScalarQuadraticTerm.([1, 6, 4, 3], + [z, x, x, y], + [y, z, z, y])), + [2, 7, 5]) + it = MOIU.eachscalar(f) + @test length(it) == 3 + @test eltype(it) == MOI.ScalarQuadraticFunction{Int} + g = it[2] + @test g isa MOI.ScalarQuadraticFunction + @test g.affine_terms == MOI.ScalarAffineTerm.([1, 9, 3], [x, z, y]) + @test g.quadratic_terms == MOI.ScalarQuadraticTerm.([1, 3], [z, y], [y, y]) + @test g.constant == 7 + g = it[end] + @test g isa MOI.ScalarQuadraticFunction + @test g.affine_terms == MOI.ScalarAffineTerm.([2], [z]) + @test g.quadratic_terms == MOI.ScalarQuadraticTerm.([6], [x], [z]) + @test g.constant == 5 +end +@testset "Scalar" begin + @testset "Variable" begin + @testset "zero" begin + f = MOI.SingleVariable(MOI.VariableIndex(0)) + g = MOI.SingleVariable(MOI.VariableIndex(1)) + @test !iszero(f) + @test !iszero(g) + end end - @testset "Scalar" begin - @testset "Variable" begin - @testset "zero" begin - f = MOI.SingleVariable(MOI.VariableIndex(0)) - g = MOI.SingleVariable(MOI.VariableIndex(1)) - @test !iszero(f) - @test !iszero(g) - end + @testset "Affine" begin + @testset "zero" begin + f = @inferred MOIU.zero(MOI.ScalarAffineFunction{Float64}) + @test iszero(f) + @test MOIU.isapprox_zero(f, 1e-16) end - @testset "Affine" begin - @testset "zero" begin - f = @inferred MOIU.zero(MOI.ScalarAffineFunction{Float64}) - @test iszero(f) - @test MOIU.isapprox_zero(f, 1e-16) - end - @testset "promote_operation" begin - @test MOIU.promote_operation( - -, Int, MOI.SingleVariable - ) == MOI.ScalarAffineFunction{Int} - @test MOIU.promote_operation( - -, Int, MOI.ScalarAffineFunction{Int} - ) == MOI.ScalarAffineFunction{Int} - @test MOIU.promote_operation(+, Float64, MOI.SingleVariable, - MOI.SingleVariable) == MOI.ScalarAffineFunction{Float64} - @test MOIU.promote_operation(+, Float64, - MOI.ScalarAffineFunction{Float64}, - Float64) == MOI.ScalarAffineFunction{Float64} - @test MOIU.promote_operation(+, Int, - MOI.ScalarAffineFunction{Int}, - MOI.ScalarAffineFunction{Int}) == MOI.ScalarAffineFunction{Int} - end - @testset "Comparison" begin - @test MOIU.operate(+, Float64, MOI.SingleVariable(x), - MOI.SingleVariable(z)) + 1.0 ≈ - MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([1, 1e-7, 1], [x, y, z]), 1.0) atol=1e-6 - f1 = MOI.ScalarAffineFunction([MOI.ScalarAffineTerm(1.0, x), MOI.ScalarAffineTerm(1e-7, y)], 1.0) - f2 = MOI.ScalarAffineFunction([MOI.ScalarAffineTerm(1.0, x)], 1.0) - @test f1 ≈ f2 atol=1e-6 - fdiff = f1 - f2 - @testset "With iszero" begin - @test !iszero(fdiff) - @test iszero(f1 - f1) - @test iszero(f2 - f2) - end - @testset "With tolerance" begin - MOIU.canonicalize!(fdiff) - @test !MOIU.isapprox_zero(fdiff, 1e-8) - @test MOIU.isapprox_zero(fdiff, 1e-6) - end - end - @testset "canonical" begin - f = MOIU.canonical(MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([2, 1, 3, -2, -3], [y, x, z, x, z]), 5)) - @test MOI.output_dimension(f) == 1 - @test f.terms == MOI.ScalarAffineTerm.([-1, 2], [x, y]) - @test f.constant == 5 - f = MOIU.canonical(MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([1, 3, 1, 2, -3, 2], - [w, y, w, x, x, z]), 2) + - MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([-1, -2, -2, 3, 2], - [ y, z, w, x, y]), 3)) - @test f.terms == MOI.ScalarAffineTerm.([2, 4], [x, y]) - @test f.constant == 5 - end - f = MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([2, 4], [x, y]), - 5) - @testset "convert" begin - @test_throws InexactError convert(MOI.SingleVariable, f) - quad_f = MOI.ScalarQuadraticFunction(f.terms, - MOI.ScalarQuadraticTerm{Int}[], - f.constant) - @test convert(MOI.ScalarQuadraticFunction{Int}, f) ≈ quad_f - g = convert(MOI.ScalarAffineFunction{Float64}, MOI.SingleVariable(x)) - @test convert(MOI.SingleVariable, g) == MOI.SingleVariable(x) + @testset "promote_operation" begin + @test MOIU.promote_operation( + -, Int, MOI.SingleVariable + ) == MOI.ScalarAffineFunction{Int} + @test MOIU.promote_operation( + -, Int, MOI.ScalarAffineFunction{Int} + ) == MOI.ScalarAffineFunction{Int} + @test MOIU.promote_operation(+, Float64, MOI.SingleVariable, + MOI.SingleVariable) == MOI.ScalarAffineFunction{Float64} + @test MOIU.promote_operation(+, Float64, + MOI.ScalarAffineFunction{Float64}, + Float64) == MOI.ScalarAffineFunction{Float64} + @test MOIU.promote_operation(+, Int, + MOI.ScalarAffineFunction{Int}, + MOI.ScalarAffineFunction{Int}) == MOI.ScalarAffineFunction{Int} + end + @testset "Comparison" begin + @test MOIU.operate(+, Float64, MOI.SingleVariable(x), + MOI.SingleVariable(z)) + 1.0 ≈ + MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([1, 1e-7, 1], [x, y, z]), 1.0) atol=1e-6 + f1 = MOI.ScalarAffineFunction([MOI.ScalarAffineTerm(1.0, x), MOI.ScalarAffineTerm(1e-7, y)], 1.0) + f2 = MOI.ScalarAffineFunction([MOI.ScalarAffineTerm(1.0, x)], 1.0) + @test f1 ≈ f2 atol=1e-6 + fdiff = f1 - f2 + @testset "With iszero" begin + @test !iszero(fdiff) + @test iszero(f1 - f1) + @test iszero(f2 - f2) end - @testset "operate with Float64 coefficient type" begin - f = MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([1.0, 4.0], - [x, y]), - 5.0) - @test f ≈ 2.0f / 2.0 + @testset "With tolerance" begin + MOIU.canonicalize!(fdiff) + @test !MOIU.isapprox_zero(fdiff, 1e-8) + @test MOIU.isapprox_zero(fdiff, 1e-6) end - @testset "operate with Int coefficient type" begin - f = MOIU.canonical(MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([1, 3, 1, 2, -3, 2], - [w, y, w, x, x, z]), 2) + - MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([-1, -2, -2, 3, 2], - [ y, z, w, x, y]), 3)) - @test f === +f - @test f ≈ MOI.SingleVariable(x) + MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([1, 4], - [x, y]), 5) - @test f ≈ f * 1 - @test f ≈ MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([1, 2], [x, y]), 2) * 2 + 1 - @test f ≈ MOI.SingleVariable(x) - MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([-1, -4], [x, y]), -5) - @test f ≈ MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([3, 4], [x, y]), 5) - MOI.SingleVariable(x) + end + @testset "canonical" begin + f = MOIU.canonical(MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([2, 1, 3, -2, -3], [y, x, z, x, z]), 5)) + @test MOI.output_dimension(f) == 1 + @test f.terms == MOI.ScalarAffineTerm.([-1, 2], [x, y]) + @test f.constant == 5 + f = MOIU.canonical(MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([1, 3, 1, 2, -3, 2], + [w, y, w, x, x, z]), 2) + + MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([-1, -2, -2, 3, 2], + [ y, z, w, x, y]), 3)) + @test f.terms == MOI.ScalarAffineTerm.([2, 4], [x, y]) + @test f.constant == 5 + end + f = MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([2, 4], [x, y]), + 5) + @testset "convert" begin + @test_throws InexactError convert(MOI.SingleVariable, f) + quad_f = MOI.ScalarQuadraticFunction(f.terms, + MOI.ScalarQuadraticTerm{Int}[], + f.constant) + @test convert(MOI.ScalarQuadraticFunction{Int}, f) ≈ quad_f + g = convert(MOI.ScalarAffineFunction{Float64}, MOI.SingleVariable(x)) + @test convert(MOI.SingleVariable, g) == MOI.SingleVariable(x) + end + @testset "operate with Float64 coefficient type" begin + f = MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([1.0, 4.0], + [x, y]), + 5.0) + @test f ≈ 2.0f / 2.0 + end + @testset "operate with Int coefficient type" begin + f = MOIU.canonical(MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([1, 3, 1, 2, -3, 2], + [w, y, w, x, x, z]), 2) + + MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([-1, -2, -2, 3, 2], + [ y, z, w, x, y]), 3)) + @test f === +f + @test f ≈ MOI.SingleVariable(x) + MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([1, 4], + [x, y]), 5) + @test f ≈ f * 1 + @test f ≈ MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([1, 2], [x, y]), 2) * 2 + 1 + @test f ≈ MOI.SingleVariable(x) - MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([-1, -4], [x, y]), -5) + @test f ≈ MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([3, 4], [x, y]), 5) - MOI.SingleVariable(x) + end + @testset "modification" begin + f = MOIU.modifyfunction(f, MOI.ScalarConstantChange(6)) + @test f.constant == 6 + g = deepcopy(f) + @test g ≈ f + f = MOIU.modifyfunction(f, MOI.ScalarCoefficientChange(y, 3)) + @test !(g ≈ f) + @test g.terms == MOI.ScalarAffineTerm.([2, 4], [x, y]) + @test f.terms == MOI.ScalarAffineTerm.([2, 3], [x, y]) + f = MOIU.modifyfunction(f, MOI.ScalarCoefficientChange(x, 0)) + @test f.terms == MOI.ScalarAffineTerm.([3], [y]) + end + end + @testset "Quadratic" begin + @testset "zero" begin + f = @inferred MOIU.zero(MOI.ScalarQuadraticFunction{Float64}) + @test MOIU.isapprox_zero(f, 1e-16) + end + @testset "promote_operation" begin + @test MOIU.promote_operation( + -, Int, MOI.ScalarQuadraticFunction{Int} + ) == MOI.ScalarQuadraticFunction{Int} + @test MOIU.promote_operation(+, Int, + MOI.ScalarQuadraticFunction{Int}, + MOI.ScalarQuadraticFunction{Int}) == MOI.ScalarQuadraticFunction{Int} + @test MOIU.promote_operation(+, Int, + MOI.ScalarQuadraticFunction{Int}, + MOI.ScalarAffineFunction{Int}) == MOI.ScalarQuadraticFunction{Int} + @test MOIU.promote_operation(+, Int, + MOI.ScalarAffineFunction{Int}, + MOI.ScalarQuadraticFunction{Int}) == MOI.ScalarQuadraticFunction{Int} + @test MOIU.promote_operation(*, Int, + MOI.SingleVariable, + MOI.SingleVariable) == MOI.ScalarQuadraticFunction{Int} + @test MOIU.promote_operation(*, Float64, + MOI.SingleVariable, + MOI.ScalarAffineFunction{Float64}) == MOI.ScalarQuadraticFunction{Float64} + @test MOIU.promote_operation(*, Int, + MOI.ScalarAffineFunction{Int}, + MOI.SingleVariable) == MOI.ScalarQuadraticFunction{Int} + @test MOIU.promote_operation(*, Float64, + MOI.ScalarAffineFunction{Float64}, + MOI.ScalarAffineFunction{Float64}) == MOI.ScalarQuadraticFunction{Float64} + @test MOIU.promote_operation(/, Float64, + MOI.ScalarQuadraticFunction{Float64}, + Float64) == MOI.ScalarQuadraticFunction{Float64} + end + fx = MOI.SingleVariable(x) + fy = MOI.SingleVariable(y) + f = 7 + 3fx + 1fx * fx + 2fy * fy + 3fx * fy + MOIU.canonicalize!(f) + @test MOI.output_dimension(f) == 1 + @testset "Comparison" begin + @testset "With iszero" begin + @test !iszero(f) + @test iszero(0 * f) + @test iszero(f - f) end - @testset "modification" begin - f = MOIU.modifyfunction(f, MOI.ScalarConstantChange(6)) - @test f.constant == 6 - g = deepcopy(f) - @test g ≈ f - f = MOIU.modifyfunction(f, MOI.ScalarCoefficientChange(y, 3)) - @test !(g ≈ f) - @test g.terms == MOI.ScalarAffineTerm.([2, 4], [x, y]) - @test f.terms == MOI.ScalarAffineTerm.([2, 3], [x, y]) - f = MOIU.modifyfunction(f, MOI.ScalarCoefficientChange(x, 0)) - @test f.terms == MOI.ScalarAffineTerm.([3], [y]) + @testset "With tolerance" begin + @test !MOIU.isapprox_zero(f, 1e-8) + # Test isapprox_zero with zero terms + @test MOIU.isapprox_zero(0 * f, 1e-8) + g = 1.0fx * fy - (1 + 1e-6) * fy * fx + MOIU.canonicalize!(g) + @test MOIU.isapprox_zero(g, 1e-5) + @test !MOIU.isapprox_zero(g, 1e-7) end end - @testset "Quadratic" begin - @testset "zero" begin - f = @inferred MOIU.zero(MOI.ScalarQuadraticFunction{Float64}) - @test MOIU.isapprox_zero(f, 1e-16) + @testset "convert" begin + @test_throws InexactError convert(MOI.SingleVariable, f) + @test_throws InexactError convert(MOI.ScalarAffineFunction{Int}, + f) + g = convert(MOI.ScalarQuadraticFunction{Float64}, fx) + @test convert(MOI.SingleVariable, g) == fx + end + @testset "operate" begin + @test f ≈ 7 + (fx + 2fy) * (1fx + fy) + 3fx + @test f ≈ -(-7 - 3fx) + (fx + 2fy) * (1fx + fy) + @test f ≈ -((fx + 2fy) * (MOIU.operate(-, Int, fx) - fy)) + 3fx + 7 + @test f ≈ 7 + MOIU.operate(*, Int, fx, fx) + 3fx * (fy + 1) + 2fy * fy + @test f ≈ (fx + 2) * (fx + 1) + (fy + 1) * (2fy + 3fx) + (5 - 3fx - 2fy) + @test f ≈ begin + MOI.ScalarQuadraticFunction([MOI.ScalarAffineTerm(3, x)], + MOI.ScalarQuadraticTerm.([1], [x], [x]), 4) + + MOI.ScalarQuadraticFunction(MOI.ScalarAffineTerm{Int}[], + MOI.ScalarQuadraticTerm.([2, 3], [y, x], [y, y]), 3) end - @testset "promote_operation" begin - @test MOIU.promote_operation( - -, Int, MOI.ScalarQuadraticFunction{Int} - ) == MOI.ScalarQuadraticFunction{Int} - @test MOIU.promote_operation(+, Int, - MOI.ScalarQuadraticFunction{Int}, - MOI.ScalarQuadraticFunction{Int}) == MOI.ScalarQuadraticFunction{Int} - @test MOIU.promote_operation(+, Int, - MOI.ScalarQuadraticFunction{Int}, - MOI.ScalarAffineFunction{Int}) == MOI.ScalarQuadraticFunction{Int} - @test MOIU.promote_operation(+, Int, - MOI.ScalarAffineFunction{Int}, - MOI.ScalarQuadraticFunction{Int}) == MOI.ScalarQuadraticFunction{Int} - @test MOIU.promote_operation(*, Int, - MOI.SingleVariable, - MOI.SingleVariable) == MOI.ScalarQuadraticFunction{Int} - @test MOIU.promote_operation(*, Float64, - MOI.SingleVariable, - MOI.ScalarAffineFunction{Float64}) == MOI.ScalarQuadraticFunction{Float64} - @test MOIU.promote_operation(*, Int, - MOI.ScalarAffineFunction{Int}, - MOI.SingleVariable) == MOI.ScalarQuadraticFunction{Int} - @test MOIU.promote_operation(*, Float64, - MOI.ScalarAffineFunction{Float64}, - MOI.ScalarAffineFunction{Float64}) == MOI.ScalarQuadraticFunction{Float64} - @test MOIU.promote_operation(/, Float64, - MOI.ScalarQuadraticFunction{Float64}, - Float64) == MOI.ScalarQuadraticFunction{Float64} + @test f ≈ begin + MOI.ScalarQuadraticFunction([MOI.ScalarAffineTerm(3, x)], + MOI.ScalarQuadraticTerm.([1], [x], [x]), 10) - + MOI.ScalarQuadraticFunction(MOI.ScalarAffineTerm{Int}[], + MOI.ScalarQuadraticTerm.([-2, -3], [y, x], [y, y]), 3) end - fx = MOI.SingleVariable(x) - fy = MOI.SingleVariable(y) - f = 7 + 3fx + 1fx * fx + 2fy * fy + 3fx * fy - MOIU.canonicalize!(f) - @test MOI.output_dimension(f) == 1 - @testset "Comparison" begin - @testset "With iszero" begin - @test !iszero(f) - @test iszero(0 * f) - @test iszero(f - f) - end - @testset "With tolerance" begin - @test !MOIU.isapprox_zero(f, 1e-8) - # Test isapprox_zero with zero terms - @test MOIU.isapprox_zero(0 * f, 1e-8) - g = 1.0fx * fy - (1 + 1e-6) * fy * fx - MOIU.canonicalize!(g) - @test MOIU.isapprox_zero(g, 1e-5) - @test !MOIU.isapprox_zero(g, 1e-7) - end + @test f ≈ begin + MOI.ScalarAffineFunction([MOI.ScalarAffineTerm(3, x)], 5) + + MOI.ScalarQuadraticFunction(MOI.ScalarAffineTerm{Int}[], + MOI.ScalarQuadraticTerm.([1, 2, 3], [x, y, x], [x, y, y]), 2) end - @testset "convert" begin - @test_throws InexactError convert(MOI.SingleVariable, f) - @test_throws InexactError convert(MOI.ScalarAffineFunction{Int}, - f) - g = convert(MOI.ScalarQuadraticFunction{Float64}, fx) - @test convert(MOI.SingleVariable, g) == fx + @test f ≈ begin + MOI.ScalarAffineFunction([MOI.ScalarAffineTerm(3, x)], 5) - + MOI.ScalarQuadraticFunction(MOI.ScalarAffineTerm{Int}[], + MOI.ScalarQuadraticTerm.([-1, -2, -3], [x, y, x], [x, y, y]), -2) end - @testset "operate" begin - @test f ≈ 7 + (fx + 2fy) * (1fx + fy) + 3fx - @test f ≈ -(-7 - 3fx) + (fx + 2fy) * (1fx + fy) - @test f ≈ -((fx + 2fy) * (MOIU.operate(-, Int, fx) - fy)) + 3fx + 7 - @test f ≈ 7 + MOIU.operate(*, Int, fx, fx) + 3fx * (fy + 1) + 2fy * fy - @test f ≈ (fx + 2) * (fx + 1) + (fy + 1) * (2fy + 3fx) + (5 - 3fx - 2fy) - @test f ≈ begin - MOI.ScalarQuadraticFunction([MOI.ScalarAffineTerm(3, x)], - MOI.ScalarQuadraticTerm.([1], [x], [x]), 4) + - MOI.ScalarQuadraticFunction(MOI.ScalarAffineTerm{Int}[], - MOI.ScalarQuadraticTerm.([2, 3], [y, x], [y, y]), 3) - end - @test f ≈ begin - MOI.ScalarQuadraticFunction([MOI.ScalarAffineTerm(3, x)], - MOI.ScalarQuadraticTerm.([1], [x], [x]), 10) - - MOI.ScalarQuadraticFunction(MOI.ScalarAffineTerm{Int}[], - MOI.ScalarQuadraticTerm.([-2, -3], [y, x], [y, y]), 3) - end - @test f ≈ begin - MOI.ScalarAffineFunction([MOI.ScalarAffineTerm(3, x)], 5) + - MOI.ScalarQuadraticFunction(MOI.ScalarAffineTerm{Int}[], - MOI.ScalarQuadraticTerm.([1, 2, 3], [x, y, x], [x, y, y]), 2) - end - @test f ≈ begin - MOI.ScalarAffineFunction([MOI.ScalarAffineTerm(3, x)], 5) - - MOI.ScalarQuadraticFunction(MOI.ScalarAffineTerm{Int}[], - MOI.ScalarQuadraticTerm.([-1, -2, -3], [x, y, x], [x, y, y]), -2) - end - @test f ≈ begin - MOI.ScalarQuadraticFunction(MOI.ScalarAffineTerm{Int}[], - MOI.ScalarQuadraticTerm.([1, 2, 3], [x, y, x], [x, y, y]), 2) + - MOI.ScalarAffineFunction([MOI.ScalarAffineTerm(3, x)], 5) - end - @test f ≈ begin - MOI.ScalarQuadraticFunction(MOI.ScalarAffineTerm{Int}[], - MOI.ScalarQuadraticTerm.([1, 2, 3], [x, y, x], [x, y, y]), 12) - - MOI.ScalarAffineFunction([MOI.ScalarAffineTerm(-3, x)], 5) - end - @test f ≈ begin - MOI.ScalarQuadraticFunction(MOI.ScalarAffineTerm.([2], [x]), - MOI.ScalarQuadraticTerm.([1, 2, 3], [x, y, x], [x, y, y]), 7) + - MOI.SingleVariable(x) - end - @test f ≈ MOI.ScalarQuadraticFunction(MOI.ScalarAffineTerm.([3], [x]), - MOI.ScalarQuadraticTerm.([1, 2, 3], [x, y, x], [x, y, y]), 10) - 3 - @test f ≈ - 2.0 * MOI.ScalarQuadraticFunction(MOI.ScalarAffineTerm.([3.0], [x]), - MOI.ScalarQuadraticTerm.([1.0, 2.0, 3.0], [x, y, x], [x, y, y]), 7.0) / 2.0 + @test f ≈ begin + MOI.ScalarQuadraticFunction(MOI.ScalarAffineTerm{Int}[], + MOI.ScalarQuadraticTerm.([1, 2, 3], [x, y, x], [x, y, y]), 2) + + MOI.ScalarAffineFunction([MOI.ScalarAffineTerm(3, x)], 5) end - @testset "modification" begin - f = MOIU.modifyfunction(f, MOI.ScalarConstantChange(9)) - @test f.constant == 9 - f = MOIU.modifyfunction(f, MOI.ScalarCoefficientChange(y, 0)) - @test f.affine_terms == MOI.ScalarAffineTerm.([3], [x]) - g = deepcopy(f) - @test f ≈ g - f = MOIU.modifyfunction(f, MOI.ScalarCoefficientChange(y, 2)) - @test !(f ≈ g) - @test g.affine_terms == MOI.ScalarAffineTerm.([3], [x]) - @test f.affine_terms == MOI.ScalarAffineTerm.([3, 2], [x, y]) + @test f ≈ begin + MOI.ScalarQuadraticFunction(MOI.ScalarAffineTerm{Int}[], + MOI.ScalarQuadraticTerm.([1, 2, 3], [x, y, x], [x, y, y]), 12) - + MOI.ScalarAffineFunction([MOI.ScalarAffineTerm(-3, x)], 5) end + @test f ≈ begin + MOI.ScalarQuadraticFunction(MOI.ScalarAffineTerm.([2], [x]), + MOI.ScalarQuadraticTerm.([1, 2, 3], [x, y, x], [x, y, y]), 7) + + MOI.SingleVariable(x) + end + @test f ≈ MOI.ScalarQuadraticFunction(MOI.ScalarAffineTerm.([3], [x]), + MOI.ScalarQuadraticTerm.([1, 2, 3], [x, y, x], [x, y, y]), 10) - 3 + @test f ≈ + 2.0 * MOI.ScalarQuadraticFunction(MOI.ScalarAffineTerm.([3.0], [x]), + MOI.ScalarQuadraticTerm.([1.0, 2.0, 3.0], [x, y, x], [x, y, y]), 7.0) / 2.0 end - end - @testset "Vector" begin - @testset "Affine" begin - f = MOIU.canonical(MOI.VectorAffineFunction(MOI.VectorAffineTerm.([2, 1, 2, 1, 1, 2, 2, 2, 2, 1, 1, 2, 1, 2], - MOI.ScalarAffineTerm.([3, 2, 3, -3, -1, -2, 3, -2, 1, 3, 5, -2, 0, -1], - [x, x, z, y, y, x, y, z, x, y, y, x, x, z])), [5, 7])) - @test MOI.output_dimension(f) == 2 - @test f.terms == MOI.VectorAffineTerm.([1, 1, 2], MOI.ScalarAffineTerm.([2, 4, 3], [x, y, y])) - @test MOIU.constant(f) == [5, 7] - f = MOIU.modifyfunction(f, MOI.VectorConstantChange([6, 8])) - @test MOIU.constant(f) == [6, 8] + @testset "modification" begin + f = MOIU.modifyfunction(f, MOI.ScalarConstantChange(9)) + @test f.constant == 9 + f = MOIU.modifyfunction(f, MOI.ScalarCoefficientChange(y, 0)) + @test f.affine_terms == MOI.ScalarAffineTerm.([3], [x]) g = deepcopy(f) @test f ≈ g - f = MOIU.modifyfunction(f, MOI.MultirowChange(y, [(2, 9)])) + f = MOIU.modifyfunction(f, MOI.ScalarCoefficientChange(y, 2)) @test !(f ≈ g) - @test f.terms == MOI.VectorAffineTerm.([1, 1, 2], MOI.ScalarAffineTerm.([2, 4, 9], [x, y, y])) - @test g.terms == MOI.VectorAffineTerm.([1, 1, 2], MOI.ScalarAffineTerm.([2, 4, 3], [x, y, y])) - f = MOIU.modifyfunction(f, MOI.MultirowChange(y, [(1, 0)])) - @test f.terms == MOI.VectorAffineTerm.([1, 2], MOI.ScalarAffineTerm.([2, 9], [x, y])) - end - @testset "Quadratic" begin - 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]) - @test MOI.output_dimension(f) == 3 - f = MOIU.modifyfunction(f, MOI.VectorConstantChange([10, 11, 12])) - @test MOIU.constant(f) == [10, 11, 12] - f = MOIU.modifyfunction(f, MOI.MultirowChange(y, [(2, 0), (1, 1)])) - @test f.affine_terms == MOI.VectorAffineTerm.([1, 2, 1], MOI.ScalarAffineTerm.([3, 1, 1], [x, x, y])) - g = deepcopy(f) - f = MOIU.modifyfunction(f, MOI.MultirowChange(x, [(1, 0), (3, 4)])) - @test f.affine_terms == MOI.VectorAffineTerm.([2, 1, 3], MOI.ScalarAffineTerm.([1, 1, 4], [x, y, x])) - @test g.affine_terms == MOI.VectorAffineTerm.([1, 2, 1], MOI.ScalarAffineTerm.([3, 1, 1], [x, x, y])) + @test g.affine_terms == MOI.ScalarAffineTerm.([3], [x]) + @test f.affine_terms == MOI.ScalarAffineTerm.([3, 2], [x, y]) end end - @testset "Conversion to canonical form" begin - function isapprox_ordered(f1::T, f2::T) where {T <: Union{MOI.ScalarAffineFunction, MOI.VectorAffineFunction}} - ((MOI.term_indices.(f1.terms) == MOI.term_indices.(f2.terms)) && - (MOI._constant(f1) ≈ MOI._constant(f2)) && - (MOI.coefficient.(f1.terms) ≈ MOI.coefficient.(f2.terms))) - end - function test_canonicalization(f::T, expected::T) where {T <: Union{MOI.ScalarAffineFunction, MOI.VectorAffineFunction}} - @test MOIU.iscanonical(expected) - g = @inferred(MOIU.canonical(f)) - @test isapprox_ordered(g, expected) - @test MOIU.iscanonical(g) - @test MOIU.iscanonical(expected) - @test isapprox_ordered(MOIU.canonical(g), g) - @test MOIU.canonical(g) !== g - @test @allocated(MOIU.canonicalize!(f)) == 0 - end - @testset "ScalarAffine" begin - @test MOIU.iscanonical(MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.(Float64[], MOI.VariableIndex.(Int[])), 1.0)) - @test !MOIU.iscanonical(MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([0.0], MOI.VariableIndex.([1])), 1.0)) - @test !MOIU.iscanonical(MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([1.0, 2.0], MOI.VariableIndex.([2, 1])), 2.0)) - @test !MOIU.iscanonical(MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([1.0, 0.0], MOI.VariableIndex.([1, 2])), 2.0)) +end +@testset "Vector" begin + @testset "Affine" begin + f = MOIU.canonical(MOI.VectorAffineFunction(MOI.VectorAffineTerm.([2, 1, 2, 1, 1, 2, 2, 2, 2, 1, 1, 2, 1, 2], + MOI.ScalarAffineTerm.([3, 2, 3, -3, -1, -2, 3, -2, 1, 3, 5, -2, 0, -1], + [x, x, z, y, y, x, y, z, x, y, y, x, x, z])), [5, 7])) + @test MOI.output_dimension(f) == 2 + @test f.terms == MOI.VectorAffineTerm.([1, 1, 2], MOI.ScalarAffineTerm.([2, 4, 3], [x, y, y])) + @test MOIU.constant(f) == [5, 7] + f = MOIU.modifyfunction(f, MOI.VectorConstantChange([6, 8])) + @test MOIU.constant(f) == [6, 8] + g = deepcopy(f) + @test f ≈ g + f = MOIU.modifyfunction(f, MOI.MultirowChange(y, [(2, 9)])) + @test !(f ≈ g) + @test f.terms == MOI.VectorAffineTerm.([1, 1, 2], MOI.ScalarAffineTerm.([2, 4, 9], [x, y, y])) + @test g.terms == MOI.VectorAffineTerm.([1, 1, 2], MOI.ScalarAffineTerm.([2, 4, 3], [x, y, y])) + f = MOIU.modifyfunction(f, MOI.MultirowChange(y, [(1, 0)])) + @test f.terms == MOI.VectorAffineTerm.([1, 2], MOI.ScalarAffineTerm.([2, 9], [x, y])) + end + @testset "Quadratic" begin + 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]) + @test MOI.output_dimension(f) == 3 + f = MOIU.modifyfunction(f, MOI.VectorConstantChange([10, 11, 12])) + @test MOIU.constant(f) == [10, 11, 12] + f = MOIU.modifyfunction(f, MOI.MultirowChange(y, [(2, 0), (1, 1)])) + @test f.affine_terms == MOI.VectorAffineTerm.([1, 2, 1], MOI.ScalarAffineTerm.([3, 1, 1], [x, x, y])) + g = deepcopy(f) + f = MOIU.modifyfunction(f, MOI.MultirowChange(x, [(1, 0), (3, 4)])) + @test f.affine_terms == MOI.VectorAffineTerm.([2, 1, 3], MOI.ScalarAffineTerm.([1, 1, 4], [x, y, x])) + @test g.affine_terms == MOI.VectorAffineTerm.([1, 2, 1], MOI.ScalarAffineTerm.([3, 1, 1], [x, x, y])) + end +end +@testset "Conversion to canonical form" begin + function isapprox_ordered(f1::T, f2::T) where {T <: Union{MOI.ScalarAffineFunction, MOI.VectorAffineFunction}} + ((MOI.term_indices.(f1.terms) == MOI.term_indices.(f2.terms)) && + (MOI._constant(f1) ≈ MOI._constant(f2)) && + (MOI.coefficient.(f1.terms) ≈ MOI.coefficient.(f2.terms))) + end + function test_canonicalization(f::T, expected::T) where {T <: Union{MOI.ScalarAffineFunction, MOI.VectorAffineFunction}} + @test MOIU.iscanonical(expected) + g = @inferred(MOIU.canonical(f)) + @test isapprox_ordered(g, expected) + @test MOIU.iscanonical(g) + @test MOIU.iscanonical(expected) + @test isapprox_ordered(MOIU.canonical(g), g) + @test MOIU.canonical(g) !== g + @test @allocated(MOIU.canonicalize!(f)) == 0 + end + @testset "ScalarAffine" begin + @test MOIU.iscanonical(MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.(Float64[], MOI.VariableIndex.(Int[])), 1.0)) + @test !MOIU.iscanonical(MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([0.0], MOI.VariableIndex.([1])), 1.0)) + @test !MOIU.iscanonical(MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([1.0, 2.0], MOI.VariableIndex.([2, 1])), 2.0)) + @test !MOIU.iscanonical(MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([1.0, 0.0], MOI.VariableIndex.([1, 2])), 2.0)) - test_canonicalization( - MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.(Float64[], MOI.VariableIndex[]), 1.5), - MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.(Float64[], MOI.VariableIndex[]), 1.5), - ) - test_canonicalization( - MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([0.0], [MOI.VariableIndex(1)]), -2.0), - MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.(Float64[], MOI.VariableIndex[]), -2.0), - ) - test_canonicalization( - MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([0.0], [MOI.VariableIndex(2)]), -2.0), - MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.(Float64[], MOI.VariableIndex[]), -2.0), - ) - test_canonicalization( - MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([3.0], [MOI.VariableIndex(2)]), 1.0), - MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([3.0], [MOI.VariableIndex(2)]), 1.0), - ) - test_canonicalization( - MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([3.0, 4.0], MOI.VariableIndex.([2, 1])), 0.0), - MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([4.0, 3.0], MOI.VariableIndex.([1, 2])), 0.0), - ) - test_canonicalization( - MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([1.0, 0.1], MOI.VariableIndex.([1, 1])), 5.0), - MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([1.1], MOI.VariableIndex.([1])), 5.0), - ) - test_canonicalization( - MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([1.0, 0.5, 2.0], MOI.VariableIndex.([1, 3, 1])), 5.0), - MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([3.0, 0.5], MOI.VariableIndex.([1, 3])), 5.0), - ) - test_canonicalization( - MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([1.0, 0.5, 2.0], MOI.VariableIndex.([1, 3, 1])), 5.0), - MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([3.0, 0.5], MOI.VariableIndex.([1, 3])), 5.0), - ) - test_canonicalization( - MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([1.0, 2.0, 3.0, 4.0, 5.0], MOI.VariableIndex.([1, 3, 1, 3, 2])), 5.0), - MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([4.0, 5.0, 6.0], MOI.VariableIndex.([1, 2, 3])), 5.0), - ) - test_canonicalization( - MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([1.0, -1.0], MOI.VariableIndex.([7, 7])), 5.0), - MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.(Float64[], MOI.VariableIndex.(Int[])), 5.0), - ) - test_canonicalization( - MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([1.0, -1.0, 0.5], MOI.VariableIndex.([7, 7, 2])), 5.0), - MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([0.5], MOI.VariableIndex.([2])), 5.0), - ) - test_canonicalization( - MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([1.0, -0.5, 0.5, -0.5], MOI.VariableIndex.([7, 7, 2, 7])), 5.0), - MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([0.5], MOI.VariableIndex.([2])), 5.0), - ) - end - @testset "VectorAffine" begin - @test MOIU.iscanonical(MOI.VectorAffineFunction(MOI.VectorAffineTerm.(Int[], MOI.ScalarAffineTerm.(Float64[], MOI.VariableIndex.(Int[]))), Float64[])) - @test !MOIU.iscanonical(MOI.VectorAffineFunction(MOI.VectorAffineTerm.([1], MOI.ScalarAffineTerm.([0.0], MOI.VariableIndex.([1]))), [1.0])) - @test !MOIU.iscanonical(MOI.VectorAffineFunction(MOI.VectorAffineTerm.([1, 2], MOI.ScalarAffineTerm.([0.0, 1.0], MOI.VariableIndex.([1, 2]))), [1.0])) - @test !MOIU.iscanonical(MOI.VectorAffineFunction(MOI.VectorAffineTerm.([2, 1], MOI.ScalarAffineTerm.([1.0, 1.0], MOI.VariableIndex.([1, 2]))), [1.0])) - @test !MOIU.iscanonical(MOI.VectorAffineFunction(MOI.VectorAffineTerm.([1, 1], MOI.ScalarAffineTerm.([1.0, -1.0], MOI.VariableIndex.([1, 1]))), [1.0])) - @test !MOIU.iscanonical(MOI.VectorAffineFunction(MOI.VectorAffineTerm.([1, 1], MOI.ScalarAffineTerm.([1.0, 1.0], MOI.VariableIndex.([1, 1]))), [1.0])) + test_canonicalization( + MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.(Float64[], MOI.VariableIndex[]), 1.5), + MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.(Float64[], MOI.VariableIndex[]), 1.5), + ) + test_canonicalization( + MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([0.0], [MOI.VariableIndex(1)]), -2.0), + MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.(Float64[], MOI.VariableIndex[]), -2.0), + ) + test_canonicalization( + MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([0.0], [MOI.VariableIndex(2)]), -2.0), + MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.(Float64[], MOI.VariableIndex[]), -2.0), + ) + test_canonicalization( + MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([3.0], [MOI.VariableIndex(2)]), 1.0), + MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([3.0], [MOI.VariableIndex(2)]), 1.0), + ) + test_canonicalization( + MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([3.0, 4.0], MOI.VariableIndex.([2, 1])), 0.0), + MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([4.0, 3.0], MOI.VariableIndex.([1, 2])), 0.0), + ) + test_canonicalization( + MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([1.0, 0.1], MOI.VariableIndex.([1, 1])), 5.0), + MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([1.1], MOI.VariableIndex.([1])), 5.0), + ) + test_canonicalization( + MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([1.0, 0.5, 2.0], MOI.VariableIndex.([1, 3, 1])), 5.0), + MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([3.0, 0.5], MOI.VariableIndex.([1, 3])), 5.0), + ) + test_canonicalization( + MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([1.0, 0.5, 2.0], MOI.VariableIndex.([1, 3, 1])), 5.0), + MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([3.0, 0.5], MOI.VariableIndex.([1, 3])), 5.0), + ) + test_canonicalization( + MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([1.0, 2.0, 3.0, 4.0, 5.0], MOI.VariableIndex.([1, 3, 1, 3, 2])), 5.0), + MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([4.0, 5.0, 6.0], MOI.VariableIndex.([1, 2, 3])), 5.0), + ) + test_canonicalization( + MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([1.0, -1.0], MOI.VariableIndex.([7, 7])), 5.0), + MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.(Float64[], MOI.VariableIndex.(Int[])), 5.0), + ) + test_canonicalization( + MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([1.0, -1.0, 0.5], MOI.VariableIndex.([7, 7, 2])), 5.0), + MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([0.5], MOI.VariableIndex.([2])), 5.0), + ) + test_canonicalization( + MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([1.0, -0.5, 0.5, -0.5], MOI.VariableIndex.([7, 7, 2, 7])), 5.0), + MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([0.5], MOI.VariableIndex.([2])), 5.0), + ) + end + @testset "VectorAffine" begin + @test MOIU.iscanonical(MOI.VectorAffineFunction(MOI.VectorAffineTerm.(Int[], MOI.ScalarAffineTerm.(Float64[], MOI.VariableIndex.(Int[]))), Float64[])) + @test !MOIU.iscanonical(MOI.VectorAffineFunction(MOI.VectorAffineTerm.([1], MOI.ScalarAffineTerm.([0.0], MOI.VariableIndex.([1]))), [1.0])) + @test !MOIU.iscanonical(MOI.VectorAffineFunction(MOI.VectorAffineTerm.([1, 2], MOI.ScalarAffineTerm.([0.0, 1.0], MOI.VariableIndex.([1, 2]))), [1.0])) + @test !MOIU.iscanonical(MOI.VectorAffineFunction(MOI.VectorAffineTerm.([2, 1], MOI.ScalarAffineTerm.([1.0, 1.0], MOI.VariableIndex.([1, 2]))), [1.0])) + @test !MOIU.iscanonical(MOI.VectorAffineFunction(MOI.VectorAffineTerm.([1, 1], MOI.ScalarAffineTerm.([1.0, -1.0], MOI.VariableIndex.([1, 1]))), [1.0])) + @test !MOIU.iscanonical(MOI.VectorAffineFunction(MOI.VectorAffineTerm.([1, 1], MOI.ScalarAffineTerm.([1.0, 1.0], MOI.VariableIndex.([1, 1]))), [1.0])) - test_canonicalization( - MOI.VectorAffineFunction(MOI.VectorAffineTerm.(Int[], MOI.ScalarAffineTerm.(Float64[], MOI.VariableIndex.(Int[]))), Float64[]), - MOI.VectorAffineFunction(MOI.VectorAffineTerm.(Int[], MOI.ScalarAffineTerm.(Float64[], MOI.VariableIndex.(Int[]))), Float64[]) - ) - test_canonicalization( - MOI.VectorAffineFunction(MOI.VectorAffineTerm.([3], MOI.ScalarAffineTerm.([0.0], MOI.VariableIndex.([5]))), [1.0]), - MOI.VectorAffineFunction(MOI.VectorAffineTerm.(Int[], MOI.ScalarAffineTerm.(Float64[], MOI.VariableIndex.(Int[]))), [1.0]) - ) - test_canonicalization( - MOI.VectorAffineFunction(MOI.VectorAffineTerm.([3, 2], MOI.ScalarAffineTerm.([1.0, 2.0], MOI.VariableIndex.([5, 6]))), [1.0, 2.0, 3.0]), - MOI.VectorAffineFunction(MOI.VectorAffineTerm.([2, 3], MOI.ScalarAffineTerm.([2.0, 1.0], MOI.VariableIndex.([6, 5]))), [1.0, 2.0, 3.0]) - ) - test_canonicalization( - MOI.VectorAffineFunction(MOI.VectorAffineTerm.([3, 3], MOI.ScalarAffineTerm.([1.0, 2.0], MOI.VariableIndex.([6, 5]))), [1.0, 2.0, 3.0]), - MOI.VectorAffineFunction(MOI.VectorAffineTerm.([3, 3], MOI.ScalarAffineTerm.([2.0, 1.0], MOI.VariableIndex.([5, 6]))), [1.0, 2.0, 3.0]) - ) - test_canonicalization( - MOI.VectorAffineFunction(MOI.VectorAffineTerm.([3, 3], MOI.ScalarAffineTerm.([1.0, 2.0], MOI.VariableIndex.([1, 1]))), [1.0, 2.0, 3.0]), - MOI.VectorAffineFunction(MOI.VectorAffineTerm.([3], MOI.ScalarAffineTerm.([3.0], MOI.VariableIndex.([1]))), [1.0, 2.0, 3.0]) - ) - test_canonicalization( - MOI.VectorAffineFunction(MOI.VectorAffineTerm.([1, 1, 1], MOI.ScalarAffineTerm.([1.0, 2.0, 3.0], MOI.VariableIndex.([1, 2, 1]))), [4.0, 5.0, 6.0]), - MOI.VectorAffineFunction(MOI.VectorAffineTerm.([1, 1], MOI.ScalarAffineTerm.([4.0, 2.0], MOI.VariableIndex.([1, 2]))), [4.0, 5.0, 6.0]), - ) - test_canonicalization( - MOI.VectorAffineFunction(MOI.VectorAffineTerm.([1, 1, 1], MOI.ScalarAffineTerm.([1.0, 2.0, 3.0], MOI.VariableIndex.([2, 1, 1]))), [4.0, 5.0, 6.0]), - MOI.VectorAffineFunction(MOI.VectorAffineTerm.([1, 1], MOI.ScalarAffineTerm.([5.0, 1.0], MOI.VariableIndex.([1, 2]))), [4.0, 5.0, 6.0]), - ) - test_canonicalization( - MOI.VectorAffineFunction(MOI.VectorAffineTerm.([2, 3, 3], MOI.ScalarAffineTerm.([1.0, 2.0, 3.0], MOI.VariableIndex.([1, 1, 1]))), [4.0, 5.0, 6.0]), - MOI.VectorAffineFunction(MOI.VectorAffineTerm.([2, 3], MOI.ScalarAffineTerm.([1.0, 5.0], MOI.VariableIndex.([1, 1]))), [4.0, 5.0, 6.0]), - ) - test_canonicalization( - MOI.VectorAffineFunction(MOI.VectorAffineTerm.([2, 3, 3], MOI.ScalarAffineTerm.([1.0, -3.0, 3.0], MOI.VariableIndex.([1, 1, 1]))), [4.0, 5.0, 6.0]), - MOI.VectorAffineFunction(MOI.VectorAffineTerm.([2], MOI.ScalarAffineTerm.([1.0], MOI.VariableIndex.([1]))), [4.0, 5.0, 6.0]), - ) - test_canonicalization( - MOI.VectorAffineFunction(MOI.VectorAffineTerm.([2, 3, 3, 3], MOI.ScalarAffineTerm.([1.0, 3.0, -1.0, -2.0], MOI.VariableIndex.([1, 1, 1, 1]))), [4.0, 5.0, 6.0]), - MOI.VectorAffineFunction(MOI.VectorAffineTerm.([2], MOI.ScalarAffineTerm.([1.0], MOI.VariableIndex.([1]))), [4.0, 5.0, 6.0]), - ) - end + test_canonicalization( + MOI.VectorAffineFunction(MOI.VectorAffineTerm.(Int[], MOI.ScalarAffineTerm.(Float64[], MOI.VariableIndex.(Int[]))), Float64[]), + MOI.VectorAffineFunction(MOI.VectorAffineTerm.(Int[], MOI.ScalarAffineTerm.(Float64[], MOI.VariableIndex.(Int[]))), Float64[]) + ) + test_canonicalization( + MOI.VectorAffineFunction(MOI.VectorAffineTerm.([3], MOI.ScalarAffineTerm.([0.0], MOI.VariableIndex.([5]))), [1.0]), + MOI.VectorAffineFunction(MOI.VectorAffineTerm.(Int[], MOI.ScalarAffineTerm.(Float64[], MOI.VariableIndex.(Int[]))), [1.0]) + ) + test_canonicalization( + MOI.VectorAffineFunction(MOI.VectorAffineTerm.([3, 2], MOI.ScalarAffineTerm.([1.0, 2.0], MOI.VariableIndex.([5, 6]))), [1.0, 2.0, 3.0]), + MOI.VectorAffineFunction(MOI.VectorAffineTerm.([2, 3], MOI.ScalarAffineTerm.([2.0, 1.0], MOI.VariableIndex.([6, 5]))), [1.0, 2.0, 3.0]) + ) + test_canonicalization( + MOI.VectorAffineFunction(MOI.VectorAffineTerm.([3, 3], MOI.ScalarAffineTerm.([1.0, 2.0], MOI.VariableIndex.([6, 5]))), [1.0, 2.0, 3.0]), + MOI.VectorAffineFunction(MOI.VectorAffineTerm.([3, 3], MOI.ScalarAffineTerm.([2.0, 1.0], MOI.VariableIndex.([5, 6]))), [1.0, 2.0, 3.0]) + ) + test_canonicalization( + MOI.VectorAffineFunction(MOI.VectorAffineTerm.([3, 3], MOI.ScalarAffineTerm.([1.0, 2.0], MOI.VariableIndex.([1, 1]))), [1.0, 2.0, 3.0]), + MOI.VectorAffineFunction(MOI.VectorAffineTerm.([3], MOI.ScalarAffineTerm.([3.0], MOI.VariableIndex.([1]))), [1.0, 2.0, 3.0]) + ) + test_canonicalization( + MOI.VectorAffineFunction(MOI.VectorAffineTerm.([1, 1, 1], MOI.ScalarAffineTerm.([1.0, 2.0, 3.0], MOI.VariableIndex.([1, 2, 1]))), [4.0, 5.0, 6.0]), + MOI.VectorAffineFunction(MOI.VectorAffineTerm.([1, 1], MOI.ScalarAffineTerm.([4.0, 2.0], MOI.VariableIndex.([1, 2]))), [4.0, 5.0, 6.0]), + ) + test_canonicalization( + MOI.VectorAffineFunction(MOI.VectorAffineTerm.([1, 1, 1], MOI.ScalarAffineTerm.([1.0, 2.0, 3.0], MOI.VariableIndex.([2, 1, 1]))), [4.0, 5.0, 6.0]), + MOI.VectorAffineFunction(MOI.VectorAffineTerm.([1, 1], MOI.ScalarAffineTerm.([5.0, 1.0], MOI.VariableIndex.([1, 2]))), [4.0, 5.0, 6.0]), + ) + test_canonicalization( + MOI.VectorAffineFunction(MOI.VectorAffineTerm.([2, 3, 3], MOI.ScalarAffineTerm.([1.0, 2.0, 3.0], MOI.VariableIndex.([1, 1, 1]))), [4.0, 5.0, 6.0]), + MOI.VectorAffineFunction(MOI.VectorAffineTerm.([2, 3], MOI.ScalarAffineTerm.([1.0, 5.0], MOI.VariableIndex.([1, 1]))), [4.0, 5.0, 6.0]), + ) + test_canonicalization( + MOI.VectorAffineFunction(MOI.VectorAffineTerm.([2, 3, 3], MOI.ScalarAffineTerm.([1.0, -3.0, 3.0], MOI.VariableIndex.([1, 1, 1]))), [4.0, 5.0, 6.0]), + MOI.VectorAffineFunction(MOI.VectorAffineTerm.([2], MOI.ScalarAffineTerm.([1.0], MOI.VariableIndex.([1]))), [4.0, 5.0, 6.0]), + ) + test_canonicalization( + MOI.VectorAffineFunction(MOI.VectorAffineTerm.([2, 3, 3, 3], MOI.ScalarAffineTerm.([1.0, 3.0, -1.0, -2.0], MOI.VariableIndex.([1, 1, 1, 1]))), [4.0, 5.0, 6.0]), + MOI.VectorAffineFunction(MOI.VectorAffineTerm.([2], MOI.ScalarAffineTerm.([1.0], MOI.VariableIndex.([1]))), [4.0, 5.0, 6.0]), + ) 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) - @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 + @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 - @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 + @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 - for t in [MOI.VectorOfVariables, MOI.VectorAffineFunction{T}] - @test MOIU.promote_operation(-, T, t) == MOI.VectorAffineFunction{T} + 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 - t = MOI.VectorQuadraticFunction{T} - @test MOIU.promote_operation(-, T, t) == MOI.VectorQuadraticFunction{T} end + for t in [MOI.VectorOfVariables, MOI.VectorAffineFunction{T}] + @test MOIU.promote_operation(-, T, t) == MOI.VectorAffineFunction{T} + end + t = MOI.VectorQuadraticFunction{T} + @test MOIU.promote_operation(-, T, t) == MOI.VectorQuadraticFunction{T} + end - α = [1, 2, 3] - v = MOI.VectorOfVariables([y, w, y]) - g = MOI.VectorAffineFunction( - MOI.VectorAffineTerm.([3, 1], - MOI.ScalarAffineTerm.([5, 2], [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]) - f = MOI.VectorQuadraticFunction( + 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])), - [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])), + [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])), - [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 + [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 diff --git a/test/Utilities/mockoptimizer.jl b/test/Utilities/mockoptimizer.jl index 08896d752e..b9693709d9 100644 --- a/test/Utilities/mockoptimizer.jl +++ b/test/Utilities/mockoptimizer.jl @@ -1,4 +1,12 @@ -@testset "Mock optimizer default objective sense" begin +using Test +import MathOptInterface +const MOI = MathOptInterface +const MOIT = MOI.Test +const MOIU = MOI.Utilities + +include("../model_for_mock.jl") + +@testset "Default objective sense" begin MOIT.default_objective_test(MOIU.MockOptimizer(ModelForMock{Float64}())) end @@ -9,11 +17,11 @@ end MOIT.default_status_test(model) end -@testset "Mock optimizer name test" begin +@testset "Name test" begin MOIT.nametest(MOIU.MockOptimizer(ModelForMock{Float64}())) end -@testset "Mock optimizer optimizer attributes" begin +@testset "Optimizer attributes" begin optimizer = MOIU.MockOptimizer(ModelForMock{Float64}()) @test MOI.supports(optimizer, MOIU.MockModelAttribute()) MOI.set(optimizer, MOIU.MockModelAttribute(), 10) @@ -35,7 +43,7 @@ end @test MOI.get(optimizer, MOIU.MockConstraintAttribute(), [c1]) == [-12] end -@testset "Mock optimizer optimizer solve no result" begin +@testset "Optimizer solve no result" begin optimizer = MOIU.MockOptimizer(ModelForMock{Float64}()) v1 = MOI.add_variable(optimizer) @@ -48,7 +56,7 @@ end @test MOI.get(optimizer, MOI.ResultCount()) == 0 end -@testset "Mock optimizer optimizer solve with result" begin +@testset "Optimizer solve with result" begin optimizer = MOIU.MockOptimizer(ModelForMock{Float64}(), eval_objective_value=false, eval_variable_constraint_dual=false) diff --git a/test/Utilities/model.jl b/test/Utilities/model.jl index cc88ecf201..e1bf9409c5 100644 --- a/test/Utilities/model.jl +++ b/test/Utilities/model.jl @@ -1,3 +1,8 @@ +using Test +import MathOptInterface +const MOI = MathOptInterface +const MOIT = MOI.Test + # TODO: It's hard to find where Model is defined! # We need to test this in a module at the top level because it can't be defined diff --git a/test/Utilities/sets.jl b/test/Utilities/sets.jl index f4a3915367..0bf6d75a7a 100644 --- a/test/Utilities/sets.jl +++ b/test/Utilities/sets.jl @@ -1,17 +1,17 @@ -@testset "Sets constant" begin +@testset "Constant" begin @test MOIU.getconstant(MOI.EqualTo(3)) == 3 @test MOIU.getconstant(MOI.GreaterThan(6)) == 6 @test MOIU.getconstant(MOI.LessThan(2)) == 2 end -@testset "Sets shifts" begin +@testset "Shifts" begin @test MOIU.shift_constant(MOI.EqualTo(3), 1) == MOI.EqualTo(4) @test MOIU.shift_constant(MOI.GreaterThan(6), -1) == MOI.GreaterThan(5) @test MOIU.shift_constant(MOI.LessThan(2), 2) == MOI.LessThan(4) @test MOIU.shift_constant(MOI.Interval(-2, 3), 1) == MOI.Interval(-1, 4) end -@testset "Set dimension" begin +@testset "Dimension" begin @test MOI.dimension(MOI.EqualTo(3.0)) === 1 @test MOI.dimension(MOI.Reals(8)) === 8 @test MOI.dimension(MOI.DualExponentialCone()) === 3 diff --git a/test/Utilities/universalfallback.jl b/test/Utilities/universalfallback.jl index 8cb451e839..9911f869f3 100644 --- a/test/Utilities/universalfallback.jl +++ b/test/Utilities/universalfallback.jl @@ -61,117 +61,116 @@ struct UnknownOptimizerAttribute <: MOI.AbstractOptimizerAttribute end (), ()) -@testset "UniversalFallback" begin - # TODO: Restructure to avoid sharing state across testsets. It doesn't seem - # necessary to use the same uf object for all the tests. - model = ModelForUniversalFallback{Float64}() - uf = MOIU.UniversalFallback(model) +# TODO: Restructure to avoid sharing state across testsets. It doesn't seem +# necessary to use the same uf object for all the tests. +model = ModelForUniversalFallback{Float64}() +uf = MOIU.UniversalFallback(model) +@test MOI.is_empty(uf) +@testset "Copy Test" begin + MOIT.copytest(uf, Model{Float64}()) + @test !MOI.is_empty(uf) + MOI.empty!(uf) @test MOI.is_empty(uf) - @testset "Copy Test" begin - MOIT.copytest(uf, Model{Float64}()) - @test !MOI.is_empty(uf) - MOI.empty!(uf) - @test MOI.is_empty(uf) - end - @testset "Start Values Test" begin - src = MOIU.UniversalFallback(Model{Float64}()) - dest = MOIU.UniversalFallback(Model{Float64}()) - MOIT.start_values_test(dest, src) - end - @testset "Valid Test" begin - MOIT.validtest(uf) - @test !MOI.is_empty(uf) - MOI.empty!(uf) - @test MOI.is_empty(uf) - end - @testset "Empty Test" begin - MOIT.emptytest(uf) - @test MOI.is_empty(uf) - end - @testset "Name Test" begin - MOIT.nametest(uf) - @test !MOI.is_empty(uf) - MOI.empty!(uf) - @test MOI.is_empty(uf) - end - @testset "Optimizer Attribute" begin - attr = UnknownOptimizerAttribute() - listattr = MOI.ListOfOptimizerAttributesSet() - test_optmodattrs(uf, model, attr, listattr) - end - @testset "Model Attribute" begin - attr = MOIT.UnknownModelAttribute() - listattr = MOI.ListOfModelAttributesSet() - test_optmodattrs(uf, model, attr, listattr) +end +@testset "Start Values Test" begin + src = MOIU.UniversalFallback(Model{Float64}()) + dest = MOIU.UniversalFallback(Model{Float64}()) + MOIT.start_values_test(dest, src) +end +@testset "Valid Test" begin + MOIT.validtest(uf) + @test !MOI.is_empty(uf) + MOI.empty!(uf) + @test MOI.is_empty(uf) +end +@testset "Empty Test" begin + MOIT.emptytest(uf) + @test MOI.is_empty(uf) +end +@testset "Name Test" begin + MOIT.nametest(uf) + @test !MOI.is_empty(uf) + MOI.empty!(uf) + @test MOI.is_empty(uf) +end +@testset "Optimizer Attribute" begin + attr = UnknownOptimizerAttribute() + listattr = MOI.ListOfOptimizerAttributesSet() + test_optmodattrs(uf, model, attr, listattr) +end +@testset "Model Attribute" begin + attr = MOIT.UnknownModelAttribute() + listattr = MOI.ListOfModelAttributesSet() + test_optmodattrs(uf, model, attr, listattr) +end +x = MOI.add_variable(uf) +y, z = MOI.add_variables(uf, 2) +@testset "Variable Attribute" begin + VI = MOI.VariableIndex + attr = MOIT.UnknownVariableAttribute() + listattr = MOI.ListOfVariableAttributesSet() + test_varconattrs(uf, model, attr, listattr, VI, MOI.add_variable, x, y, z) +end +@testset "Constraint Attribute" begin + global x, y, z + attr = MOIT.UnknownConstraintAttribute() + @testset "Supported constraint" begin + cx = MOI.add_constraint(uf, x, MOI.LessThan(0.)) + cy = MOI.add_constraint(uf, y, MOI.LessThan(1.)) + cz = MOI.add_constraint(uf, z, MOI.LessThan(2.)) + CI = MOI.ConstraintIndex{MOI.SingleVariable, MOI.LessThan{Float64}} + listattr = MOI.ListOfConstraintAttributesSet{MOI.SingleVariable, MOI.LessThan{Float64}}() + test_varconattrs(uf, model, attr, listattr, CI, uf -> MOI.add_constraint(uf, x, MOI.LessThan(0.)), cx, cy, cz) + + MOI.set(uf, MOI.ConstraintFunction(), cx, MOI.SingleVariable(y)) + @test MOI.get(uf, MOI.ConstraintFunction(), cx) == MOI.SingleVariable(y) + + @test MOI.supports(uf, MOI.ConstraintName(), typeof(cx)) + MOI.set(uf, MOI.ConstraintName(), cx, "LessThan") + @test MOI.get(uf, MOI.ConstraintName(), cx) == "LessThan" + @test MOI.get(uf, typeof(cx), "LessThan") == cx + MOI.delete(uf, cx) + @test MOI.get(uf, typeof(cx), "LessThan") === nothing end + # To remove the constraint attributes added in the previous testset + MOI.empty!(uf) x = MOI.add_variable(uf) y, z = MOI.add_variables(uf, 2) - @testset "Variable Attribute" begin - VI = MOI.VariableIndex - attr = MOIT.UnknownVariableAttribute() - listattr = MOI.ListOfVariableAttributesSet() - test_varconattrs(uf, model, attr, listattr, VI, MOI.add_variable, x, y, z) - end - @testset "Constraint Attribute" begin - attr = MOIT.UnknownConstraintAttribute() - @testset "Supported constraint" begin - cx = MOI.add_constraint(uf, x, MOI.LessThan(0.)) - cy = MOI.add_constraint(uf, y, MOI.LessThan(1.)) - cz = MOI.add_constraint(uf, z, MOI.LessThan(2.)) - CI = MOI.ConstraintIndex{MOI.SingleVariable, MOI.LessThan{Float64}} - listattr = MOI.ListOfConstraintAttributesSet{MOI.SingleVariable, MOI.LessThan{Float64}}() - test_varconattrs(uf, model, attr, listattr, CI, uf -> MOI.add_constraint(uf, x, MOI.LessThan(0.)), cx, cy, cz) - - MOI.set(uf, MOI.ConstraintFunction(), cx, MOI.SingleVariable(y)) - @test MOI.get(uf, MOI.ConstraintFunction(), cx) == MOI.SingleVariable(y) - - @test MOI.supports(uf, MOI.ConstraintName(), typeof(cx)) - MOI.set(uf, MOI.ConstraintName(), cx, "LessThan") - @test MOI.get(uf, MOI.ConstraintName(), cx) == "LessThan" - @test MOI.get(uf, typeof(cx), "LessThan") == cx - MOI.delete(uf, cx) - @test MOI.get(uf, typeof(cx), "LessThan") === nothing - end - # To remove the constraint attributes added in the previous testset - MOI.empty!(uf) - x = MOI.add_variable(uf) - y, z = MOI.add_variables(uf, 2) - @testset "Unsupported constraint" begin - cx = MOI.add_constraint(uf, x, MOI.EqualTo(0.)) - cy = MOI.add_constraint(uf, y, MOI.EqualTo(1.)) - cz = MOI.add_constraint(uf, z, MOI.EqualTo(2.)) - CI = MOI.ConstraintIndex{MOI.SingleVariable, MOI.EqualTo{Float64}} - listattr = MOI.ListOfConstraintAttributesSet{MOI.SingleVariable, MOI.EqualTo{Float64}}() - test_varconattrs(uf, model, attr, listattr, CI, uf -> MOI.add_constraint(uf, x, MOI.EqualTo(0.)), cx, cy, cz) + @testset "Unsupported constraint" begin + cx = MOI.add_constraint(uf, x, MOI.EqualTo(0.)) + cy = MOI.add_constraint(uf, y, MOI.EqualTo(1.)) + cz = MOI.add_constraint(uf, z, MOI.EqualTo(2.)) + CI = MOI.ConstraintIndex{MOI.SingleVariable, MOI.EqualTo{Float64}} + listattr = MOI.ListOfConstraintAttributesSet{MOI.SingleVariable, MOI.EqualTo{Float64}}() + test_varconattrs(uf, model, attr, listattr, CI, uf -> MOI.add_constraint(uf, x, MOI.EqualTo(0.)), cx, cy, cz) - MOI.set(uf, MOI.ConstraintFunction(), cx, MOI.SingleVariable(y)) - @test MOI.get(uf, MOI.ConstraintFunction(), cx) == MOI.SingleVariable(y) + MOI.set(uf, MOI.ConstraintFunction(), cx, MOI.SingleVariable(y)) + @test MOI.get(uf, MOI.ConstraintFunction(), cx) == MOI.SingleVariable(y) - @test MOI.supports(uf, MOI.ConstraintName(), typeof(cx)) - MOI.set(uf, MOI.ConstraintName(), cx, "EqualTo") - @test MOI.get(uf, MOI.ConstraintName(), cx) == "EqualTo" - @test MOI.get(uf, typeof(cx), "EqualTo") == cx - MOI.delete(uf, cx) - @test MOI.get(uf, typeof(cx), "EqualTo") === nothing - end - end - config = MOIT.TestConfig(solve=false) - @testset "empty" begin - MOI.empty!(uf) - @test MOI.is_empty(uf) - end - @testset "Unit" begin - MOIT.unittest(uf, config) - end - @testset "Modification" begin - MOIT.modificationtest(uf, config) - end - @testset "Continuous Linear" begin - MOIT.contlineartest(uf, config) + @test MOI.supports(uf, MOI.ConstraintName(), typeof(cx)) + MOI.set(uf, MOI.ConstraintName(), cx, "EqualTo") + @test MOI.get(uf, MOI.ConstraintName(), cx) == "EqualTo" + @test MOI.get(uf, typeof(cx), "EqualTo") == cx + MOI.delete(uf, cx) + @test MOI.get(uf, typeof(cx), "EqualTo") === nothing end end +config = MOIT.TestConfig(solve=false) +@testset "empty" begin + MOI.empty!(uf) + @test MOI.is_empty(uf) +end +@testset "Unit" begin + MOIT.unittest(uf, config) +end +@testset "Modification" begin + MOIT.modificationtest(uf, config) +end +@testset "Continuous Linear" begin + MOIT.contlineartest(uf, config) +end -@testset "UniversalFallback duplicate names" begin +@testset "Duplicate names" begin model = ModelForUniversalFallback{Float64}() uf = MOIU.UniversalFallback(model) x = MOI.add_variable(uf) diff --git a/test/bridge.jl b/test/bridge.jl index 3f1598fb90..ef5ab3ed17 100644 --- a/test/bridge.jl +++ b/test/bridge.jl @@ -371,112 +371,6 @@ end end @testset "Bridge tests" begin - mock = MOIU.MockOptimizer(SimpleModel{Float64}()) - config = MOIT.TestConfig() - config_with_basis = MOIT.TestConfig(basis = true) - - @testset "GreaterToLess" begin - bridged_mock = MOIB.GreaterToLess{Float64}(mock) - - MOIU.set_mock_optimize!(mock, - (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [0, 0]), - (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [100, 0]), - (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [100, -100])) - MOIT.linear6test(bridged_mock, config) - - ci = first(MOI.get(bridged_mock, MOI.ListOfConstraintIndices{MOI.ScalarAffineFunction{Float64}, MOI.GreaterThan{Float64}}())) - test_delete_bridge(bridged_mock, ci, 2, - ((MOI.ScalarAffineFunction{Float64}, - MOI.LessThan{Float64}, 1),)) - end - - @testset "LessToGreater" begin - bridged_mock = MOIB.LessToGreater{Float64}(mock) - - MOIU.set_mock_optimize!(mock, - (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, - MOI.OPTIMAL, (MOI.FEASIBLE_POINT, [1.0]), - MOI.FEASIBLE_POINT, - (MOI.ScalarAffineFunction{Float64}, MOI.GreaterThan{Float64}) => [1.0] - ), - (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, - MOI.OPTIMAL, (MOI.FEASIBLE_POINT, [2.0]), - MOI.FEASIBLE_POINT, - (MOI.ScalarAffineFunction{Float64}, MOI.GreaterThan{Float64}) => [1.0] - ) - ) - MOIT.solve_set_scalaraffine_lessthan(bridged_mock, config) - - MOIU.set_mock_optimize!(mock, - (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, - MOI.OPTIMAL, (MOI.FEASIBLE_POINT, [1.0]), - MOI.FEASIBLE_POINT, - (MOI.ScalarAffineFunction{Float64}, MOI.GreaterThan{Float64}) => [1.0] - ), - (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, - MOI.OPTIMAL, (MOI.FEASIBLE_POINT, [0.5]), - MOI.FEASIBLE_POINT, - (MOI.ScalarAffineFunction{Float64}, MOI.GreaterThan{Float64}) => [0.5] - ) - ) - MOIT.solve_coef_scalaraffine_lessthan(bridged_mock, config) - - ci = first(MOI.get(bridged_mock, MOI.ListOfConstraintIndices{MOI.ScalarAffineFunction{Float64}, MOI.LessThan{Float64}}())) - test_delete_bridge(bridged_mock, ci, 1, - ((MOI.ScalarAffineFunction{Float64}, - MOI.GreaterThan{Float64}, 0),)) - end - - @testset "NonnegToNonpos" begin - bridged_mock = MOIB.NonnegToNonpos{Float64}(mock) - - MOIU.set_mock_optimize!(mock, - (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [0, 0]), - (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [100, 0]), - (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [100, -100])) - MOIT.linear7test(bridged_mock, config) - - ci = first(MOI.get(bridged_mock, MOI.ListOfConstraintIndices{MOI.VectorAffineFunction{Float64}, MOI.Nonnegatives}())) - test_delete_bridge(bridged_mock, ci, 2, - ((MOI.VectorAffineFunction{Float64}, - MOI.Nonpositives, 1),)) - end - - @testset "NonposToNonneg" begin - bridged_mock = MOIB.NonposToNonneg{Float64}(mock) - - MOIU.set_mock_optimize!(mock, - (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [0, 0]), - (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [100, 0]), - (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [100, -100])) - MOIT.linear7test(bridged_mock, config) - - MOIU.set_mock_optimize!(mock, - (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, - MOI.OPTIMAL, (MOI.FEASIBLE_POINT, [0.0, 0.0]) - ), - (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, - MOI.OPTIMAL, (MOI.FEASIBLE_POINT, [1.0, 0.75]) - ) - ) - MOIT.solve_const_vectoraffine_nonpos(bridged_mock, config) - - MOIU.set_mock_optimize!(mock, - (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!( - mock, MOI.OPTIMAL, (MOI.FEASIBLE_POINT, [0.5]) - ), - (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!( - mock, MOI.OPTIMAL, (MOI.FEASIBLE_POINT, [0.25]) - ) - ) - MOIT.solve_multirow_vectoraffine_nonpos(bridged_mock, config) - - ci = first(MOI.get(bridged_mock, MOI.ListOfConstraintIndices{MOI.VectorAffineFunction{Float64}, MOI.Nonpositives}())) - test_delete_bridge(bridged_mock, ci, 1, - ((MOI.VectorAffineFunction{Float64}, - MOI.Nonnegatives, 0),)) - end - @testset "Scalarize" begin bridged_mock = MOIB.Scalarize{Float64}(mock) # VectorOfVariables-in-Nonnegatives @@ -1023,57 +917,3 @@ end (MOI.VectorAffineFunction{Float64}, MOI.PositiveSemidefiniteConeTriangle, 0))) end end - -# We need to test this in a module at the top level because it can't be defined -# in a testset. If it runs without error, then we're okay. -module TestExternalBridge - using MathOptInterface - - struct StrictlyGreaterThan <: MathOptInterface.AbstractScalarSet end - struct StrictlyGreaterBridge{T} <: MathOptInterface.Bridges.AbstractBridge end - - function StrictlyGreaterBridge( - model, - func::MathOptInterface.SingleVariable, - set::StrictlyGreaterThan) - return StrictlyGreaterBridge{Float64}() - end - - function MathOptInterface.supports_constraint( - ::Type{StrictlyGreaterBridge{T}}, - ::Type{MathOptInterface.SingleVariable}, - ::Type{StrictlyGreaterThan}) where {T} - return true - end - - function MathOptInterface.Bridges.added_constraint_types( - ::Type{StrictlyGreaterBridge{T}}, - ::Type{MathOptInterface.SingleVariable}, - ::Type{StrictlyGreaterThan}) where {T} - return [( - MathOptInterface.SingleVariable, - MathOptInterface.GreaterThan{T} - )] - end - - MathOptInterface.Bridges.@bridge(StrictlyGreater, StrictlyGreaterBridge, - (StrictlyGreaterThan, ), - (), - (), - (), - (MathOptInterface.SingleVariable, ), - (), - (), - () - ) -end - -@testset "@bridge with external components" begin - model = SimpleModel{Float64}(); - @test MOI.supports_constraint(model, MOI.SingleVariable, MOI.GreaterThan{Float64}) - @test !MOI.supports_constraint(model, MOI.SingleVariable, TestExternalBridge.StrictlyGreaterThan) - - bridge = TestExternalBridge.StrictlyGreater{Float64}(model); - @test MOI.supports_constraint(bridge, MOI.SingleVariable, MOI.GreaterThan{Float64}) - @test MOI.supports_constraint(bridge, MOI.SingleVariable, TestExternalBridge.StrictlyGreaterThan) -end diff --git a/test/dummy.jl b/test/dummy.jl index e9b6081306..fc885815ac 100644 --- a/test/dummy.jl +++ b/test/dummy.jl @@ -1,3 +1,7 @@ +import MathOptInterface +const MOI = MathOptInterface +const MOIU = MOI.Utilities + abstract type AbstractDummyModel <: MOI.ModelLike end function MOI.empty!(::AbstractDummyModel) end @@ -19,6 +23,7 @@ end struct DummyModelWithAdd <: AbstractDummyModel end MOI.add_variable(::DummyModelWithAdd) = MOI.VariableIndex(0) +MOI.add_variables(::DummyModelWithAdd, n) = fill(MOI.VariableIndex(0), n) function MOI.add_constraint(::DummyModelWithAdd, ::MOI.SingleVariable, ::MOI.EqualTo{Float64}) return MOI.ConstraintIndex{MOI.SingleVariable, MOI.EqualTo{Float64}}(0) diff --git a/test/model.jl b/test/model.jl new file mode 100644 index 0000000000..9dc02cfc17 --- /dev/null +++ b/test/model.jl @@ -0,0 +1,17 @@ +# Needed by test spread over several files, defining it here make it easier to comment out tests +# Model supporting every MOI functions and sets +MOIU.@model(Model, + (MOI.ZeroOne, MOI.Integer), + (MOI.EqualTo, MOI.GreaterThan, MOI.LessThan, MOI.Interval, + MOI.Semicontinuous, MOI.Semiinteger), + (MOI.Reals, MOI.Zeros, MOI.Nonnegatives, MOI.Nonpositives, + MOI.SecondOrderCone, MOI.RotatedSecondOrderCone, + MOI.GeometricMeanCone, MOI.ExponentialCone, MOI.DualExponentialCone, + MOI.PositiveSemidefiniteConeTriangle, MOI.PositiveSemidefiniteConeSquare, + MOI.RootDetConeTriangle, MOI.RootDetConeSquare, MOI.LogDetConeTriangle, + MOI.LogDetConeSquare), + (MOI.PowerCone, MOI.DualPowerCone, MOI.SOS1, MOI.SOS2), + (MOI.SingleVariable,), + (MOI.ScalarAffineFunction, MOI.ScalarQuadraticFunction), + (MOI.VectorOfVariables,), + (MOI.VectorAffineFunction, MOI.VectorQuadraticFunction)) diff --git a/test/model_for_mock.jl b/test/model_for_mock.jl new file mode 100644 index 0000000000..b04c7aca40 --- /dev/null +++ b/test/model_for_mock.jl @@ -0,0 +1,9 @@ +# Model supporting only SecondOrderCone as non-LP cone. +MOIU.@model(ModelForMock, (MOI.ZeroOne, MOI.Integer), + (MOI.EqualTo, MOI.GreaterThan, MOI.LessThan, MOI.Interval), + (MOI.Zeros, MOI.Nonnegatives, MOI.Nonpositives, MOI.SecondOrderCone), + (), + (MOI.SingleVariable,), + (MOI.ScalarAffineFunction, MOI.ScalarQuadraticFunction), + (MOI.VectorOfVariables,), + (MOI.VectorAffineFunction,)) diff --git a/test/runtests.jl b/test/runtests.jl index fc6d780c86..20430f38d5 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -21,45 +21,9 @@ include("dummy.jl") include("attributes.jl") end -# Needed by test spread over several files, defining it here make it easier to comment out tests -# Model supporting every MOI functions and sets -MOIU.@model(Model, - (MOI.ZeroOne, MOI.Integer), - (MOI.EqualTo, MOI.GreaterThan, MOI.LessThan, MOI.Interval, - MOI.Semicontinuous, MOI.Semiinteger), - (MOI.Reals, MOI.Zeros, MOI.Nonnegatives, MOI.Nonpositives, - MOI.SecondOrderCone, MOI.RotatedSecondOrderCone, - MOI.GeometricMeanCone, MOI.ExponentialCone, MOI.DualExponentialCone, - MOI.PositiveSemidefiniteConeTriangle, MOI.PositiveSemidefiniteConeSquare, - MOI.RootDetConeTriangle, MOI.RootDetConeSquare, MOI.LogDetConeTriangle, - MOI.LogDetConeSquare), - (MOI.PowerCone, MOI.DualPowerCone, MOI.SOS1, MOI.SOS2), - (MOI.SingleVariable,), - (MOI.ScalarAffineFunction, MOI.ScalarQuadraticFunction), - (MOI.VectorOfVariables,), - (MOI.VectorAffineFunction, MOI.VectorQuadraticFunction)) - -# Model supporting only SecondOrderCone as non-LP cone. -MOIU.@model(ModelForMock, (MOI.ZeroOne, MOI.Integer), - (MOI.EqualTo, MOI.GreaterThan, MOI.LessThan, MOI.Interval), - (MOI.Zeros, MOI.Nonnegatives, MOI.Nonpositives, MOI.SecondOrderCone), - (), - (MOI.SingleVariable,), - (MOI.ScalarAffineFunction, MOI.ScalarQuadraticFunction), - (MOI.VectorOfVariables,), - (MOI.VectorAffineFunction,)) - # Utilities submodule tests @testset "MOI.Utilities" begin - include("Utilities/functions.jl") - include("Utilities/sets.jl") - include("Utilities/constraints.jl") - include("Utilities/model.jl") - include("Utilities/universalfallback.jl") - include("Utilities/parser.jl") - include("Utilities/mockoptimizer.jl") - include("Utilities/cachingoptimizer.jl") - include("Utilities/copy.jl") + include("Utilities/Utilities.jl") end # Test submodule tests From 3633e2aa167bf6b795ef6e7bcea8ed4d48ae46b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Legat?= Date: Fri, 26 Apr 2019 18:29:12 +0200 Subject: [PATCH 2/2] Finish Bridges --- test/Bridges/Bridges.jl | 12 +- test/Bridges/bridgeoptimizer.jl | 99 +++ test/Bridges/detbridge.jl | 21 + test/Bridges/external.jl | 8 + test/Bridges/flip_sign_bridge.jl | 2 + test/Bridges/functionize_bridge.jl | 96 +++ test/Bridges/geomeanbridge.jl | 10 + test/Bridges/intervalbridge.jl | 47 ++ test/Bridges/lazybridgeoptimizer.jl | 233 +++++++ test/Bridges/quadtosocbridge.jl | 65 ++ test/Bridges/rsocbridge.jl | 12 + test/Bridges/scalarizebridge.jl | 45 ++ test/Bridges/simple_model.jl | 12 + test/Bridges/slackbridge.jl | 138 +++++ test/Bridges/soctopsdbridge.jl | 23 + test/Bridges/squarepsdbridge.jl | 18 + test/Bridges/utilities.jl | 33 + test/Bridges/vectorizebridge.jl | 61 ++ test/bridge.jl | 919 ---------------------------- test/runtests.jl | 10 +- 20 files changed, 933 insertions(+), 931 deletions(-) create mode 100644 test/Bridges/bridgeoptimizer.jl create mode 100644 test/Bridges/detbridge.jl create mode 100644 test/Bridges/functionize_bridge.jl create mode 100644 test/Bridges/geomeanbridge.jl create mode 100644 test/Bridges/intervalbridge.jl create mode 100644 test/Bridges/lazybridgeoptimizer.jl create mode 100644 test/Bridges/quadtosocbridge.jl create mode 100644 test/Bridges/rsocbridge.jl create mode 100644 test/Bridges/scalarizebridge.jl create mode 100644 test/Bridges/simple_model.jl create mode 100644 test/Bridges/slackbridge.jl create mode 100644 test/Bridges/soctopsdbridge.jl create mode 100644 test/Bridges/squarepsdbridge.jl create mode 100644 test/Bridges/utilities.jl create mode 100644 test/Bridges/vectorizebridge.jl delete mode 100644 test/bridge.jl diff --git a/test/Bridges/Bridges.jl b/test/Bridges/Bridges.jl index b4dde39b23..f40ddb99e7 100644 --- a/test/Bridges/Bridges.jl +++ b/test/Bridges/Bridges.jl @@ -1,7 +1,11 @@ -include("bridge.jl") -include("bridgeoptimizer.jl") -include("singlebridgeoptimizer.jl") -include("lazybridgeoptimizer.jl") +using Test + +@testset "BridgeOptimizer" begin + include("bridgeoptimizer.jl") +end +@testset "LazyBridgeOptimizer" begin + include("lazybridgeoptimizer.jl") +end @testset "Separate bridges" begin include("flip_sign_bridge.jl") include("vectorizebridge.jl") diff --git a/test/Bridges/bridgeoptimizer.jl b/test/Bridges/bridgeoptimizer.jl new file mode 100644 index 0000000000..06283f3cf5 --- /dev/null +++ b/test/Bridges/bridgeoptimizer.jl @@ -0,0 +1,99 @@ +using Test + +using MathOptInterface +const MOI = MathOptInterface +const MOIT = MathOptInterface.Test +const MOIU = MathOptInterface.Utilities +const MOIB = MathOptInterface.Bridges + +include("simple_model.jl") +include("utilities.jl") + +struct UnknownConstraintAttribute <: MOI.AbstractConstraintAttribute end +MOI.is_set_by_optimize(::UnknownConstraintAttribute) = true + +mock = MOIU.MockOptimizer(SimpleModel{Float64}()) +bridged_mock = MOIB.SplitInterval{Float64}(mock) + +@testset "Unsupported constraint attribute" begin + attr = UnknownConstraintAttribute() + err = ArgumentError( + "Constraint bridge of type `MathOptInterface.Bridges.SplitIntervalBridge{Float64,MathOptInterface.SingleVariable}` " * + "does not support accessing the attribute `$attr`.") + x = MOI.add_variable(bridged_mock) + ci = MOI.add_constraint(bridged_mock, MOI.SingleVariable(x), + MOI.Interval(0.0, 1.0)) + @test_throws err MOI.get(bridged_mock, attr, ci) +end + +@testset "Issue #453" begin + MOI.empty!(bridged_mock) + MOIU.loadfromstring!(bridged_mock, """ + variables: x + maxobjective: 3.0x + c: 2.0x in Interval(1.0, 4.0) + d: x in LessThan(1.5) + """) + x = MOI.get(bridged_mock, MOI.VariableIndex, "x") + @test isa(x, MOI.VariableIndex) + c1 = MOI.get(bridged_mock, MOI.ConstraintIndex{MOI.ScalarAffineFunction{Float64}, MOI.Interval{Float64}}, "c") + @test isa(c1, MOI.ConstraintIndex{MOI.ScalarAffineFunction{Float64}, MOI.Interval{Float64}}) + c2 = MOI.get(bridged_mock, MOI.ConstraintIndex, "c") + @test c1 == c2 + d1 = MOI.get(bridged_mock, MOI.ConstraintIndex{MOI.SingleVariable, MOI.LessThan{Float64}}, "d") + @test isa(d1, MOI.ConstraintIndex{MOI.SingleVariable, MOI.LessThan{Float64}}) + d2 = MOI.get(bridged_mock, MOI.ConstraintIndex, "d") + @test d1 == d2 +end + +MOI.empty!(bridged_mock) + +@testset "Name test" begin + MOIT.nametest(bridged_mock) +end + +@testset "Copy test" begin + MOIT.failcopytestc(bridged_mock) + MOIT.failcopytestia(bridged_mock) + MOIT.failcopytestva(bridged_mock) + MOIT.failcopytestca(bridged_mock) + MOIT.copytest(bridged_mock, SimpleModel{Float64}()) +end + +@testset "Custom test" begin + model = MOIB.SplitInterval{Int}(SimpleModel{Int}()) + @test !MOIB.supports_bridging_constraint(model, MOI.VectorAffineFunction{Float64}, MOI.Interval{Float64}) + + x, y = MOI.add_variables(model, 2) + @test MOI.get(model, MOI.NumberOfVariables()) == 2 + + f1 = MOI.ScalarAffineFunction([MOI.ScalarAffineTerm(3, x)], 7) + c1 = MOI.add_constraint(model, f1, MOI.Interval(-1, 1)) + + @test MOI.get(model, MOI.ListOfConstraints()) == [(MOI.ScalarAffineFunction{Int},MOI.Interval{Int})] + test_noc(model, MOI.ScalarAffineFunction{Int}, MOI.GreaterThan{Int}, 0) + test_noc(model, MOI.ScalarAffineFunction{Int}, MOI.Interval{Int}, 1) + @test (@inferred MOI.get(model, MOI.ListOfConstraintIndices{MOI.ScalarAffineFunction{Int},MOI.Interval{Int}}())) == [c1] + + f2 = MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([2, -1], [x, y]), 2) + c2 = MOI.add_constraint(model, f1, MOI.GreaterThan(-2)) + + @test MOI.get(model, MOI.ListOfConstraints()) == [(MOI.ScalarAffineFunction{Int},MOI.GreaterThan{Int}), (MOI.ScalarAffineFunction{Int},MOI.Interval{Int})] + test_noc(model, MOI.ScalarAffineFunction{Int}, MOI.GreaterThan{Int}, 1) + test_noc(model, MOI.ScalarAffineFunction{Int}, MOI.Interval{Int}, 1) + @test (@inferred MOI.get(model, MOI.ListOfConstraintIndices{MOI.ScalarAffineFunction{Int},MOI.Interval{Int}}())) == [c1] + @test (@inferred MOI.get(model, MOI.ListOfConstraintIndices{MOI.ScalarAffineFunction{Int},MOI.GreaterThan{Int}}())) == [c2] + + @test MOI.is_valid(model, c2) + MOI.delete(model, c2) + + @test MOI.get(model, MOI.ListOfConstraints()) == [(MOI.ScalarAffineFunction{Int},MOI.Interval{Int})] + test_noc(model, MOI.ScalarAffineFunction{Int}, MOI.GreaterThan{Int}, 0) + test_noc(model, MOI.ScalarAffineFunction{Int}, MOI.Interval{Int}, 1) + @test (@inferred MOI.get(model, MOI.ListOfConstraintIndices{MOI.ScalarAffineFunction{Int},MOI.Interval{Int}}())) == [c1] +end + +@testset "Continuous Linear" begin + exclude = ["partial_start"] # VariablePrimalStart not supported. + MOIT.contlineartest(bridged_mock, MOIT.TestConfig(solve=false), exclude) +end diff --git a/test/Bridges/detbridge.jl b/test/Bridges/detbridge.jl new file mode 100644 index 0000000000..2e53b6f961 --- /dev/null +++ b/test/Bridges/detbridge.jl @@ -0,0 +1,21 @@ +@testset "LogDet" begin + bridged_mock = MOIB.LogDet{Float64}(mock) + mock.optimize! = (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [0, 1, 0, 1, 1, 0, 1, 0, 0, 1]) + MOIT.logdett1vtest(bridged_mock, config) + MOIT.logdett1ftest(bridged_mock, config) + # Dual is not yet implemented for LogDet bridge + ci = first(MOI.get(bridged_mock, MOI.ListOfConstraintIndices{MOI.VectorAffineFunction{Float64}, MOI.LogDetConeTriangle}())) + test_delete_bridge(bridged_mock, ci, 5, ((MOI.VectorAffineFunction{Float64}, MOI.ExponentialCone, 0), (MOI.VectorAffineFunction{Float64}, MOI.PositiveSemidefiniteConeTriangle, 0))) +end + +@testset "RootDet" begin + bridged_mock = MOIB.RootDet{Float64}(mock) + mock.optimize! = (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [1, 1, 0, 1, 1, 0, 1]) + MOIT.rootdett1vtest(bridged_mock, config) + MOIT.rootdett1ftest(bridged_mock, config) + # Dual is not yet implemented for RootDet bridge + ci = first(MOI.get(bridged_mock, MOI.ListOfConstraintIndices{MOI.VectorAffineFunction{Float64}, MOI.RootDetConeTriangle}())) + test_delete_bridge(bridged_mock, ci, 4, ((MOI.VectorAffineFunction{Float64}, MOI.RotatedSecondOrderCone, 0), + (MOI.VectorAffineFunction{Float64}, MOI.GeometricMeanCone, 0), + (MOI.VectorAffineFunction{Float64}, MOI.PositiveSemidefiniteConeTriangle, 0))) +end diff --git a/test/Bridges/external.jl b/test/Bridges/external.jl index e2d56b3b9b..15121e2d25 100644 --- a/test/Bridges/external.jl +++ b/test/Bridges/external.jl @@ -1,3 +1,11 @@ +using Test + +using MathOptInterface +const MOI = MathOptInterface +const MOIU = MathOptInterface.Utilities + +include("simple_model.jl") + # We need to test this in a module at the top level because it can't be defined # in a testset. If it runs without error, then we're okay. module TestExternalBridge diff --git a/test/Bridges/flip_sign_bridge.jl b/test/Bridges/flip_sign_bridge.jl index a1e3f49646..f1fae08549 100644 --- a/test/Bridges/flip_sign_bridge.jl +++ b/test/Bridges/flip_sign_bridge.jl @@ -1,3 +1,5 @@ +include("simple_model.jl") + mock = MOIU.MockOptimizer(SimpleModel{Float64}()) config = MOIT.TestConfig() config_with_basis = MOIT.TestConfig(basis = true) diff --git a/test/Bridges/functionize_bridge.jl b/test/Bridges/functionize_bridge.jl new file mode 100644 index 0000000000..7cb00c1174 --- /dev/null +++ b/test/Bridges/functionize_bridge.jl @@ -0,0 +1,96 @@ +@testset "Scalar functionize" begin + MOI.empty!(mock) + bridged_mock = MOIB.ScalarFunctionize{Float64}(mock) + x = MOI.add_variable(bridged_mock) + y = MOI.add_variable(bridged_mock) + sx = MOI.SingleVariable(x) + sy = MOI.SingleVariable(y) + ci = MOI.add_constraint(bridged_mock, sx, MOI.GreaterThan(0.0)) + @test MOI.get(bridged_mock, MOI.ConstraintFunction(), ci) ≈ sx + MOI.set(bridged_mock, MOI.ConstraintFunction(), ci, sy) + @test MOI.get(bridged_mock, MOI.ConstraintFunction(), ci) ≈ sy + @test MOI.get(bridged_mock, MOI.ConstraintSet(), ci) == MOI.GreaterThan(0.0) + MOI.set(bridged_mock, MOI.ConstraintSet(), ci, MOI.GreaterThan(1.0)) + @test MOI.get(bridged_mock, MOI.ConstraintSet(), ci) == MOI.GreaterThan(1.0) + test_delete_bridge(bridged_mock, ci, 2, ((MOI.ScalarAffineFunction{Float64}, MOI.Interval{Float64}, 0),)) + + MOIT.basic_constraint_tests(bridged_mock, config, + include=[(F, S) for + F in [MOI.SingleVariable], + S in [MOI.GreaterThan{Float64}, + MOI.LessThan{Float64}] + ]) + + for T in [Int, Float64], S in [MOI.GreaterThan{T}, MOI.LessThan{T}] + @test MOIB.added_constraint_types(MOIB.ScalarFunctionizeBridge{T, S}) == + [(MOI.ScalarAffineFunction{T}, S)] + end + + + @testset "linear2" begin + MOI.empty!(bridged_mock) + MOIU.set_mock_optimize!(mock, + (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [1, 0], + (MOI.ScalarAffineFunction{Float64}, MOI.LessThan{Float64}) => [-1], + (MOI.ScalarAffineFunction{Float64}, MOI.GreaterThan{Float64}) => [0, 1], + con_basis = + [(MOI.ScalarAffineFunction{Float64}, MOI.LessThan{Float64}) => [MOI.NONBASIC], + (MOI.ScalarAffineFunction{Float64}, MOI.GreaterThan{Float64}) => [MOI.BASIC, MOI.NONBASIC]])) + MOIT.linear2test(bridged_mock, config_with_basis) + + for (i, ci) in enumerate(MOI.get( + bridged_mock, + MOI.ListOfConstraintIndices{MOI.SingleVariable, + MOI.GreaterThan{Float64}}())) + test_delete_bridge(bridged_mock, ci, 2, + ((MOI.ScalarAffineFunction{Float64}, + MOI.GreaterThan{Float64}, 0),), + num_bridged = 3 - i) + end + end +end + +@testset "Vector functionize" begin + MOI.empty!(mock) + bridged_mock = MOIB.VectorFunctionize{Float64}(mock) + x = MOI.add_variable(bridged_mock) + y = MOI.add_variable(bridged_mock) + z = MOI.add_variable(bridged_mock) + v1 = MOI.VectorOfVariables([x,y,z]) + v2 = MOI.VectorOfVariables([x,y,y]) + ci = MOI.add_constraint(bridged_mock, v1, MOI.PowerCone(0.1)) + @test MOI.get(bridged_mock, MOI.ConstraintFunction(), ci) ≈ v1 + MOI.set(bridged_mock, MOI.ConstraintFunction(), ci, v2) + @test MOI.get(bridged_mock, MOI.ConstraintFunction(), ci) ≈ v2 + @test MOI.get(bridged_mock, MOI.ConstraintSet(), ci) == MOI.PowerCone(0.1) + MOI.set(bridged_mock, MOI.ConstraintSet(), ci, MOI.PowerCone(0.2)) + @test MOI.get(bridged_mock, MOI.ConstraintSet(), ci) == MOI.PowerCone(0.2) + test_delete_bridge(bridged_mock, ci, 3, ((MOI.VectorAffineFunction{Float64}, MOI.Nonnegatives, 0),)) + + MOIT.basic_constraint_tests(bridged_mock, config, + include=[(F, S) for + F in [MOI.VectorOfVariables], + S in [MOI.Nonnegatives, + MOI.Nonpositives] + ]) + + for T in [Int, Float64], S in [MOI.Nonnegatives, MOI.Nonpositives] + @test MOIB.added_constraint_types(MOIB.VectorFunctionizeBridge{T, S}) == + [(MOI.VectorAffineFunction{T}, S)] + end + + @testset "lin1v" begin + mock.optimize! = (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!( + mock, [1.0, 0.0, 2.0], + (MOI.VectorAffineFunction{Float64}, MOI.Nonnegatives) => [[0, 2, 0]], + (MOI.VectorAffineFunction{Float64}, MOI.Zeros) => [[-3, -1]]) + MOIT.lin1vtest(bridged_mock, config) + ci = first(MOI.get( + bridged_mock, + MOI.ListOfConstraintIndices{MOI.VectorOfVariables, + MOI.Nonnegatives}())) + test_delete_bridge(bridged_mock, ci, 3, + ((MOI.VectorAffineFunction{Float64}, + MOI.Nonnegatives, 0),)) + end +end diff --git a/test/Bridges/geomeanbridge.jl b/test/Bridges/geomeanbridge.jl new file mode 100644 index 0000000000..709720a7cb --- /dev/null +++ b/test/Bridges/geomeanbridge.jl @@ -0,0 +1,10 @@ +@testset "GeoMean" begin + mock.optimize! = (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [ones(4); 2; √2; √2]) + bridged_mock = MOIB.GeoMean{Float64}(mock) + MOIT.geomean1vtest(bridged_mock, config) + MOIT.geomean1ftest(bridged_mock, config) + # Dual is not yet implemented for GeoMean bridge + ci = first(MOI.get(bridged_mock, MOI.ListOfConstraintIndices{MOI.VectorAffineFunction{Float64}, MOI.GeometricMeanCone}())) + test_delete_bridge(bridged_mock, ci, 4, ((MOI.VectorAffineFunction{Float64}, MOI.RotatedSecondOrderCone, 0), + (MOI.ScalarAffineFunction{Float64}, MOI.LessThan{Float64}, 1))) +end diff --git a/test/Bridges/intervalbridge.jl b/test/Bridges/intervalbridge.jl new file mode 100644 index 0000000000..cb923af73d --- /dev/null +++ b/test/Bridges/intervalbridge.jl @@ -0,0 +1,47 @@ +@testset "Interval" begin + bridged_mock = MOIB.SplitInterval{Float64}(mock) + MOIT.basic_constraint_tests(bridged_mock, config, + include=[(MOI.SingleVariable, + MOI.Interval{Float64}), + (MOI.ScalarAffineFunction{Float64}, + MOI.Interval{Float64}), + (MOI.ScalarQuadraticFunction{Float64}, + MOI.Interval{Float64})]) + MOIU.set_mock_optimize!(mock, + (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [5.0, 5.0], con_basis = + [(MOI.ScalarAffineFunction{Float64}, MOI.GreaterThan{Float64}) => [MOI.BASIC], + (MOI.ScalarAffineFunction{Float64}, MOI.LessThan{Float64}) => [MOI.NONBASIC], + (MOI.SingleVariable, MOI.GreaterThan{Float64}) => [MOI.BASIC, MOI.BASIC]], + (MOI.ScalarAffineFunction{Float64}, MOI.GreaterThan{Float64}) => [0], + (MOI.ScalarAffineFunction{Float64}, MOI.LessThan{Float64}) => [-1]), + (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [2.5, 2.5], con_basis = + [(MOI.ScalarAffineFunction{Float64}, MOI.GreaterThan{Float64}) => [MOI.NONBASIC], + (MOI.ScalarAffineFunction{Float64}, MOI.LessThan{Float64}) => [MOI.BASIC], + (MOI.SingleVariable, MOI.GreaterThan{Float64}) => [MOI.BASIC, MOI.BASIC]], + (MOI.ScalarAffineFunction{Float64}, MOI.GreaterThan{Float64}) => [1], + (MOI.ScalarAffineFunction{Float64}, MOI.LessThan{Float64}) => [0]), + (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [1.0, 1.0], con_basis = + [(MOI.ScalarAffineFunction{Float64}, MOI.GreaterThan{Float64}) => [MOI.NONBASIC], + (MOI.ScalarAffineFunction{Float64}, MOI.LessThan{Float64}) => [MOI.BASIC], + (MOI.SingleVariable, MOI.GreaterThan{Float64}) => [MOI.BASIC, MOI.BASIC]]), + (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [6.0, 6.0], con_basis = + [(MOI.ScalarAffineFunction{Float64}, MOI.GreaterThan{Float64}) => [MOI.BASIC], + (MOI.ScalarAffineFunction{Float64}, MOI.LessThan{Float64}) => [MOI.NONBASIC], + (MOI.SingleVariable, MOI.GreaterThan{Float64}) => [MOI.BASIC, MOI.BASIC]])) + MOIT.linear10test(bridged_mock, config_with_basis) + MOIU.set_mock_optimize!(mock, + (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [0.0, 0.0], con_basis = + [(MOI.ScalarAffineFunction{Float64}, MOI.GreaterThan{Float64}) => [MOI.BASIC], + (MOI.ScalarAffineFunction{Float64}, MOI.LessThan{Float64}) => [MOI.BASIC], + (MOI.SingleVariable, MOI.GreaterThan{Float64}) => [MOI.NONBASIC, MOI.NONBASIC]], + (MOI.ScalarAffineFunction{Float64}, MOI.GreaterThan{Float64}) => [0], + (MOI.ScalarAffineFunction{Float64}, MOI.LessThan{Float64}) => [0])) + MOIT.linear10btest(bridged_mock, config_with_basis) + + ci = first(MOI.get(bridged_mock, MOI.ListOfConstraintIndices{MOI.ScalarAffineFunction{Float64}, MOI.Interval{Float64}}())) + newf = MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([1.0, -1.0], MOI.get(bridged_mock, MOI.ListOfVariableIndices())), 0.0) + MOI.set(bridged_mock, MOI.ConstraintFunction(), ci, newf) + @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 diff --git a/test/Bridges/lazybridgeoptimizer.jl b/test/Bridges/lazybridgeoptimizer.jl new file mode 100644 index 0000000000..2ce014b13d --- /dev/null +++ b/test/Bridges/lazybridgeoptimizer.jl @@ -0,0 +1,233 @@ +using Test + +using MathOptInterface +const MOI = MathOptInterface +const MOIT = MathOptInterface.Test +const MOIU = MathOptInterface.Utilities +const MOIB = MathOptInterface.Bridges + +include("utilities.jl") + +# Model not supporting RotatedSecondOrderCone +MOIU.@model(NoRSOCModel, + (), + (MOI.EqualTo, MOI.GreaterThan, MOI.LessThan), + (MOI.Zeros, MOI.Nonnegatives, MOI.Nonpositives, MOI.SecondOrderCone, + MOI.ExponentialCone, MOI.PositiveSemidefiniteConeTriangle), + (), + (MOI.SingleVariable,), + (MOI.ScalarAffineFunction, MOI.ScalarQuadraticFunction), + (MOI.VectorOfVariables,), + (MOI.VectorAffineFunction, MOI.VectorQuadraticFunction)) + +# Model not supporting VectorOfVariables and SingleVariable +MOIU.@model(NoVariableModel, + (MOI.ZeroOne, MOI.Integer), + (MOI.EqualTo, MOI.GreaterThan, MOI.LessThan), + (MOI.Zeros, MOI.Nonnegatives, MOI.Nonpositives, MOI.SecondOrderCone), + (), + (), + (MOI.ScalarAffineFunction,), + (), + (MOI.VectorAffineFunction,)) + +MOIU.@model(GreaterNonnegModel, + (), + (MOI.GreaterThan,), + (MOI.Nonnegatives,), + (), + (MOI.SingleVariable,), + (MOI.ScalarAffineFunction, MOI.ScalarQuadraticFunction), + (MOI.VectorOfVariables,), + (MOI.VectorAffineFunction, MOI.VectorQuadraticFunction)) + + +MOIU.@model(ModelNoVAFinSOC, + (), + (MOI.EqualTo, MOI.GreaterThan, MOI.LessThan, MOI.Interval), + (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,), + (MOI.VectorAffineFunction, MOI.VectorQuadraticFunction)) + +MOI.supports_constraint(::ModelNoVAFinSOC{Float64}, + ::Type{MOI.VectorAffineFunction{Float64}}, + ::Type{MOI.SecondOrderCone}) = false + +# Model supporting nothing +MOIU.@model NothingModel () () () () () () () () + +struct BridgeAddingNoConstraint{T} <: MOI.Bridges.AbstractBridge end +MOIB.added_constraint_types(::Type{BridgeAddingNoConstraint{T}}) where {T} = [] +function MOI.supports_constraint(::Type{<:BridgeAddingNoConstraint}, + ::Type{MOI.SingleVariable}, + ::Type{MOI.Integer}) + return true +end +function MOIB.concrete_bridge_type(::Type{<:BridgeAddingNoConstraint{T}}, + ::Type{MOI.SingleVariable}, + ::Type{MOI.Integer}) where {T} + return BridgeAddingNoConstraint{T} +end + +@testset "Bridge adding no constraint" begin + mock = MOIU.MockOptimizer(NothingModel{Int}()) + bridged = MOIB.LazyBridgeOptimizer(mock, NothingModel{Int}()) + MOI.Bridges.add_bridge(bridged, BridgeAddingNoConstraint{Float64}) + @test MOI.Bridges.supports_bridging_constraint(bridged, + MOI.SingleVariable, + MOI.Integer) +end + +@testset "Unsupported constraint with cycles" begin + # Test that `supports_constraint` works correctly when it is not + # supported but the bridges forms a cycle + mock = MOIU.MockOptimizer(NothingModel{Float64}()) + bridged = MOIB.full_bridge_optimizer(mock, Float64) + @test !MOI.supports_constraint( + bridged, MOI.SingleVariable, MOI.GreaterThan{Float64}) + @test !MOI.supports_constraint( + bridged, MOI.VectorAffineFunction{Float64}, MOI.Nonpositives) +end + +mock = MOIU.MockOptimizer(NoRSOCModel{Float64}()) +bridged_mock = MOIB.LazyBridgeOptimizer( + mock, MOIB.AllBridgedConstraints{Float64}()) + +@testset "UnsupportedConstraint when it cannot be bridged" begin + x = MOI.add_variables(bridged_mock, 4) + err = MOI.UnsupportedConstraint{MOI.VectorOfVariables, + MOI.RotatedSecondOrderCone}() + @test_throws err begin + MOI.add_constraint(bridged_mock, MOI.VectorOfVariables(x), + MOI.RotatedSecondOrderCone(4)) + end +end + +MOIB.add_bridge(bridged_mock, MOIB.SplitIntervalBridge{Float64}) +MOIB.add_bridge(bridged_mock, MOIB.RSOCtoPSDBridge{Float64}) +MOIB.add_bridge(bridged_mock, MOIB.SOCtoPSDBridge{Float64}) +MOIB.add_bridge(bridged_mock, MOIB.RSOCBridge{Float64}) + +@testset "Name test" begin + MOIT.nametest(bridged_mock) +end + +@testset "Copy test" begin + MOIT.failcopytestc(bridged_mock) + MOIT.failcopytestia(bridged_mock) + MOIT.failcopytestva(bridged_mock) + MOIT.failcopytestca(bridged_mock) + MOIT.copytest(bridged_mock, NoRSOCModel{Float64}()) +end + +# Test that RSOCtoPSD is used instead of RSOC+SOCtoPSD as it is a shortest path. +@testset "Bridge selection" begin + MOI.empty!(bridged_mock) + @test !(MOI.supports_constraint(bridged_mock, + MOI.VectorAffineFunction{Float64}, + MOI.LogDetConeTriangle)) + x = MOI.add_variables(bridged_mock, 3) + err = MOI.UnsupportedConstraint{MOI.VectorAffineFunction{Float64}, + MOI.LogDetConeTriangle}() + @test_throws err begin + MOIB.bridge_type(bridged_mock, MOI.VectorAffineFunction{Float64}, + MOI.LogDetConeTriangle) + end + c = MOI.add_constraint(bridged_mock, MOI.VectorOfVariables(x), + MOI.RotatedSecondOrderCone(3)) + @test MOIB.bridge_type(bridged_mock, MOI.VectorOfVariables, + MOI.RotatedSecondOrderCone) == MOIB.RSOCtoPSDBridge{Float64} + @test MOIB.bridge(bridged_mock, c) isa MOIB.RSOCtoPSDBridge + @test bridged_mock.dist[(MOI.VectorOfVariables, + MOI.RotatedSecondOrderCone)] == 1 +end + +@testset "Supports" begin + full_bridged_mock = MOIB.full_bridge_optimizer(mock, Float64) + greater_nonneg_mock = MOIU.MockOptimizer(GreaterNonnegModel{Float64}()) + full_bridged_greater_nonneg = MOIB.full_bridge_optimizer( + greater_nonneg_mock, Float64) + for F in [MOI.SingleVariable, MOI.ScalarAffineFunction{Float64}, + MOI.ScalarQuadraticFunction{Float64}] + @test MOI.supports_constraint(full_bridged_mock, F, + MOI.Interval{Float64}) + @test !MOI.supports_constraint( + greater_nonneg_mock, F, MOI.LessThan{Float64}) + @test MOI.supports_constraint( + full_bridged_greater_nonneg, F, MOI.LessThan{Float64}) + end + for F in [MOI.VectorOfVariables, MOI.VectorAffineFunction{Float64}, + MOI.VectorQuadraticFunction{Float64}] + @test MOI.supports_constraint(full_bridged_mock, F, + MOI.PositiveSemidefiniteConeSquare) + @test MOI.supports_constraint(full_bridged_mock, F, + MOI.GeometricMeanCone) + @test !MOI.supports_constraint( + greater_nonneg_mock, F, MOI.Nonpositives) + @test MOI.supports_constraint( + full_bridged_greater_nonneg, F, MOI.Nonnegatives) + end + for F in [MOI.VectorOfVariables, MOI.VectorAffineFunction{Float64}] + # The bridges in this for loop do not support yet + # VectorQuadraticFunction. See TODO's for the reason. + # TODO: Missing vcat for quadratic for supporting quadratic. + @test MOI.supports_constraint(full_bridged_mock, F, + MOI.RotatedSecondOrderCone) + # TODO: Det bridges need to use MOIU.operate to support quadratic. + @test MOI.supports_constraint(full_bridged_mock, F, + MOI.LogDetConeTriangle) + @test MOI.supports_constraint(full_bridged_mock, F, + MOI.RootDetConeTriangle) + end + mock2 = MOIU.MockOptimizer(ModelNoVAFinSOC{Float64}()) + @test !MOI.supports_constraint(mock2, MOI.VectorAffineFunction{Float64}, + MOI.SecondOrderCone) + full_bridged_mock2 = MOIB.full_bridge_optimizer(mock2, Float64) + @test MOI.supports_constraint(full_bridged_mock2, MOI.VectorAffineFunction{Float64}, + MOI.SecondOrderCone) + @testset "Unslack" begin + for T in [Float64, Int] + no_variable_mock = MOIU.MockOptimizer(NoVariableModel{T}()) + full_bridged_no_variable = MOIB.full_bridge_optimizer( + no_variable_mock, T) + for S in [MOI.LessThan{T}, MOI.GreaterThan{T}, MOI.EqualTo{T}, + MOI.ZeroOne, MOI.Integer] + @test MOI.supports_constraint( + full_bridged_no_variable, MOI.SingleVariable, S) + end + for S in [MOI.Nonpositives, MOI.Nonnegatives, + MOI.Zeros, MOI.SecondOrderCone] + @test MOI.supports_constraint( + full_bridged_no_variable, MOI.VectorOfVariables, S) + end + end + end +end + +@testset "Combining two briges" begin + full_bridged_mock = MOIB.full_bridge_optimizer(mock, Float64) + mock.optimize! = (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [1, 1, 0, 1, 1, 0, 1, √2]) + config = MOIT.TestConfig() + MOIT.rootdett1vtest(full_bridged_mock, config) + MOIT.rootdett1ftest(full_bridged_mock, config) + # Dual is not yet implemented for RootDet and GeoMean bridges + ci = first(MOI.get(full_bridged_mock, MOI.ListOfConstraintIndices{MOI.VectorAffineFunction{Float64}, MOI.RootDetConeTriangle}())) + test_delete_bridge(full_bridged_mock, ci, 4, ((MOI.VectorAffineFunction{Float64}, MOI.RotatedSecondOrderCone, 0), + (MOI.VectorAffineFunction{Float64}, MOI.GeometricMeanCone, 0), + (MOI.VectorAffineFunction{Float64}, MOI.PositiveSemidefiniteConeTriangle, 0)), + used_bridges = 3) +end + +@testset "Continuous Linear" begin + exclude = ["partial_start"] # VariablePrimalStart not supported. + MOIT.contlineartest(bridged_mock, MOIT.TestConfig(solve=false), exclude) +end + +@testset "Continuous Conic" begin + MOIT.contconictest(MOIB.full_bridge_optimizer(mock, Float64), MOIT.TestConfig(solve=false), ["logdets", "rootdets", "psds"]) +end diff --git a/test/Bridges/quadtosocbridge.jl b/test/Bridges/quadtosocbridge.jl new file mode 100644 index 0000000000..a430951a3f --- /dev/null +++ b/test/Bridges/quadtosocbridge.jl @@ -0,0 +1,65 @@ +@testset "QuadtoSOC" begin + bridged_mock = MOIB.QuadtoSOC{Float64}(mock) + @testset "Error for non-convex quadratic constraints" begin + x = MOI.add_variable(bridged_mock) + @test_throws ErrorException begin + MOI.add_constraint(bridged_mock, + MOI.ScalarQuadraticFunction(MOI.ScalarAffineTerm{Float64}[], + [MOI.ScalarQuadraticTerm(1.0, x, x)], + 0.0), + MOI.GreaterThan(0.0)) + end + @test_throws ErrorException begin + MOI.add_constraint(bridged_mock, + MOI.ScalarQuadraticFunction(MOI.ScalarAffineTerm{Float64}[], + [MOI.ScalarQuadraticTerm(-1.0, x, x)], + 0.0), + MOI.LessThan(0.0)) + end + end + @testset "Quadratic constraints with 2 variables" begin + MOIU.set_mock_optimize!(mock, + (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, + MOI.OPTIMAL, + (MOI.FEASIBLE_POINT, [0.5, 0.5]) + ), + (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, + MOI.OPTIMAL, + (MOI.FEASIBLE_POINT, [0.5, (√13 - 1)/4]) + ) + ) + MOIT.solve_qcp_edge_cases(bridged_mock, config) + ci = first(MOI.get(mock, + MOI.ListOfConstraintIndices{MOI.VectorAffineFunction{Float64}, + MOI.RotatedSecondOrderCone}())) + x, y = MOI.get(mock, MOI.ListOfVariableIndices()) + # The matrix is + # 2 1 + # 1 2 + # for which the cholesky factorization is U' * U with U = + # √2 √2/2 + # . √3/√2 + expected = MOI.VectorAffineFunction{Float64}(MOI.VectorAffineTerm.([3, 3, 4], + MOI.ScalarAffineTerm.([√2, √2/2, √3/√2], + [x, y, y])), + [1.0, 1.0, 0.0, 0.0]) + @test MOI.get(mock, MOI.ConstraintFunction(), ci) ≈ expected + end + @testset "QCP tests" begin + MOIU.set_mock_optimize!(mock, + (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [1/2, 7/4], MOI.FEASIBLE_POINT)) + MOIT.qcp1test(bridged_mock, config) + MOIU.set_mock_optimize!(mock, + (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [√2], MOI.FEASIBLE_POINT)) + MOIT.qcp2test(bridged_mock, config) + MOIU.set_mock_optimize!(mock, + (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [√2], MOI.FEASIBLE_POINT)) + MOIT.qcp3test(bridged_mock, config) + @testset "Bridge deletion" begin + ci = first(MOI.get(bridged_mock, + MOI.ListOfConstraintIndices{MOI.ScalarQuadraticFunction{Float64}, + MOI.LessThan{Float64}}())) + test_delete_bridge(bridged_mock, ci, 1, ((MOI.VectorAffineFunction{Float64}, MOI.RotatedSecondOrderCone, 0),)) + end + end +end diff --git a/test/Bridges/rsocbridge.jl b/test/Bridges/rsocbridge.jl new file mode 100644 index 0000000000..09d8b71f56 --- /dev/null +++ b/test/Bridges/rsocbridge.jl @@ -0,0 +1,12 @@ +@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], + (MOI.SingleVariable, MOI.EqualTo{Float64}) => [-√2, -1/√2], + (MOI.VectorAffineFunction{Float64}, MOI.SecondOrderCone) => [[3/2, 1/2, -1.0, -1.0]]) + MOIT.rotatedsoc1vtest(bridged_mock, config) + mock.optimize! = (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [1/√2, 1/√2], + (MOI.VectorAffineFunction{Float64}, MOI.SecondOrderCone) => [[3/2, 1/2, -1.0, -1.0]]) + MOIT.rotatedsoc1ftest(bridged_mock, config) + ci = first(MOI.get(bridged_mock, MOI.ListOfConstraintIndices{MOI.VectorAffineFunction{Float64}, MOI.RotatedSecondOrderCone}())) + test_delete_bridge(bridged_mock, ci, 2, ((MOI.VectorAffineFunction{Float64}, MOI.SecondOrderCone, 0),)) +end diff --git a/test/Bridges/scalarizebridge.jl b/test/Bridges/scalarizebridge.jl new file mode 100644 index 0000000000..9350b562bf --- /dev/null +++ b/test/Bridges/scalarizebridge.jl @@ -0,0 +1,45 @@ +@testset "Scalarize" begin + bridged_mock = MOIB.Scalarize{Float64}(mock) + # VectorOfVariables-in-Nonnegatives + # VectorAffineFunction-in-Zeros + mock.optimize! = (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [1.0, 0.0, 2.0], + (MOI.ScalarAffineFunction{Float64}, MOI.EqualTo{Float64}) => [-3, -1]) + MOIT.lin1vtest(bridged_mock, config) + ci = first(MOI.get(bridged_mock, MOI.ListOfConstraintIndices{MOI.VectorAffineFunction{Float64}, MOI.Zeros}())) + test_delete_bridge(bridged_mock, ci, 3, + ((MOI.ScalarAffineFunction{Float64}, MOI.EqualTo{Float64}, 0), + (MOI.SingleVariable, MOI.GreaterThan{Float64}, 0))) + ci = first(MOI.get(bridged_mock, MOI.ListOfConstraintIndices{MOI.VectorOfVariables, MOI.Nonnegatives}())) + test_delete_bridge(bridged_mock, ci, 3, + ((MOI.ScalarAffineFunction{Float64}, MOI.EqualTo{Float64}, 0), + (MOI.SingleVariable, MOI.GreaterThan{Float64}, 0))) + # VectorAffineFunction-in-Nonnegatives + # VectorAffineFunction-in-Zeros + mock.optimize! = (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [1.0, 0.0, 2.0], + (MOI.ScalarAffineFunction{Float64}, MOI.GreaterThan{Float64}) => [0, 2, 0], + (MOI.ScalarAffineFunction{Float64}, MOI.EqualTo{Float64}) => [-3, -1]) + MOIT.lin1ftest(bridged_mock, config) + ci = first(MOI.get(bridged_mock, MOI.ListOfConstraintIndices{MOI.VectorAffineFunction{Float64}, MOI.Zeros}())) + test_delete_bridge(bridged_mock, ci, 3, + ((MOI.ScalarAffineFunction{Float64}, MOI.EqualTo{Float64}, 0), + (MOI.ScalarAffineFunction{Float64}, MOI.GreaterThan{Float64}, 0))) + ci = first(MOI.get(bridged_mock, MOI.ListOfConstraintIndices{MOI.VectorAffineFunction{Float64}, MOI.Nonnegatives}())) + test_delete_bridge(bridged_mock, ci, 3, + ((MOI.ScalarAffineFunction{Float64}, MOI.EqualTo{Float64}, 0), + (MOI.ScalarAffineFunction{Float64}, MOI.GreaterThan{Float64}, 0))) + # VectorOfVariables-in-Nonnegatives + # VectorOfVariables-in-Nonpositives + # VectorOfVariables-in-Zeros + # VectorAffineFunction-in-Zeros + mock.optimize! = (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [-4, -3, 16, 0], + (MOI.ScalarAffineFunction{Float64}, MOI.EqualTo{Float64}) => [7, 2, -4]) + MOIT.lin2vtest(bridged_mock, config) + # VectorAffineFunction-in-Nonnegatives + # VectorAffineFunction-in-Nonpositives + # VectorAffineFunction-in-Zeros + mock.optimize! = (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [-4, -3, 16, 0], + (MOI.ScalarAffineFunction{Float64}, MOI.GreaterThan{Float64}) => [0], + (MOI.ScalarAffineFunction{Float64}, MOI.LessThan{Float64}) => [0], + (MOI.ScalarAffineFunction{Float64}, MOI.EqualTo{Float64}) => [7, 2, -4, 7]) + MOIT.lin2ftest(bridged_mock, config) +end diff --git a/test/Bridges/simple_model.jl b/test/Bridges/simple_model.jl new file mode 100644 index 0000000000..42322c6031 --- /dev/null +++ b/test/Bridges/simple_model.jl @@ -0,0 +1,12 @@ +# Model not supporting Interval +MOIU.@model(SimpleModel, + (), + (MOI.EqualTo, MOI.GreaterThan, MOI.LessThan, MOI.Interval), + (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,), + (MOI.VectorAffineFunction, MOI.VectorQuadraticFunction)) diff --git a/test/Bridges/slackbridge.jl b/test/Bridges/slackbridge.jl new file mode 100644 index 0000000000..952ffda016 --- /dev/null +++ b/test/Bridges/slackbridge.jl @@ -0,0 +1,138 @@ +@testset "Scalar slack" begin + MOI.empty!(mock) + bridged_mock = MOIB.ScalarSlack{Float64}(mock) + x = MOI.add_variable(bridged_mock) + y = MOI.add_variable(bridged_mock) + f = MOI.ScalarAffineFunction(MOI.ScalarAffineTerm{Float64}.([1.0, 2.0], [x, y]), 0.0) + ci = MOI.add_constraint(bridged_mock, f, MOI.GreaterThan(0.0)) + @test MOI.get(bridged_mock, MOI.ConstraintFunction(), ci) ≈ f + newf = MOI.ScalarAffineFunction(MOI.ScalarAffineTerm{Float64}.([2.0, 1.0], [x, y]), 0.0) + MOI.set(bridged_mock, MOI.ConstraintFunction(), ci, newf) + @test MOI.get(bridged_mock, MOI.ConstraintFunction(), ci) ≈ newf + @test MOI.get(bridged_mock, MOI.ConstraintSet(), ci) == MOI.GreaterThan(0.0) + MOI.set(bridged_mock, MOI.ConstraintSet(), ci, MOI.GreaterThan(1.0)) + @test MOI.get(bridged_mock, MOI.ConstraintSet(), ci) == MOI.GreaterThan(1.0) + MOI.modify(bridged_mock, ci, MOI.ScalarConstantChange{Float64}(1.0)) + @test MOI.get(bridged_mock, MOI.ConstraintFunction(), ci) ≈ + MOI.ScalarAffineFunction(MOI.ScalarAffineTerm{Float64}.([2.0, 1.0], [x, y]), 1.0) + test_delete_bridge(bridged_mock, ci, 2, ((MOI.ScalarAffineFunction{Float64}, MOI.Interval{Float64}, 0),)) + + MOIT.basic_constraint_tests(bridged_mock, config, + include=[(F, S) for + F in [MOI.ScalarAffineFunction{Float64}, + MOI.ScalarQuadraticFunction{Float64}], + 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], con_basis = + [(MOI.ScalarAffineFunction{Float64}, MOI.EqualTo{Float64}) => [MOI.NONBASIC], + (MOI.SingleVariable, MOI.GreaterThan{Float64}) => [MOI.BASIC, MOI.NONBASIC], + (MOI.SingleVariable, MOI.LessThan{Float64}) => [MOI.NONBASIC]])) + MOIT.linear2test(bridged_mock, MOIT.TestConfig(duals = false, basis = true)) + c1 = MOI.get(bridged_mock, MOI.ListOfConstraintIndices{MOI.ScalarAffineFunction{Float64}, MOI.LessThan{Float64}}()) + @test length(c1) == 1 + @test MOI.get(bridged_mock, MOI.ConstraintBasisStatus(), c1[]) == MOI.NONBASIC + + 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], + (MOI.ScalarAffineFunction{Float64}, MOI.EqualTo{Float64}) => [1, 0], + (MOI.SingleVariable, MOI.GreaterThan{Float64}) => [1], + (MOI.SingleVariable, MOI.LessThan{Float64}) => [0])) + MOIT.linear11test(bridged_mock, MOIT.TestConfig(duals = false)) + + c1 = MOI.get(bridged_mock, MOI.ListOfConstraintIndices{MOI.ScalarAffineFunction{Float64}, MOI.GreaterThan{Float64}}()) + @test length(c1) == 1 + @test MOI.get(bridged_mock, MOI.ConstraintPrimal(), c1[]) ≈ 1.0 + @test MOI.get(bridged_mock, MOI.ConstraintDual(), c1[]) ≈ 1.0 + c2 = MOI.get(bridged_mock, MOI.ListOfConstraintIndices{MOI.ScalarAffineFunction{Float64}, MOI.LessThan{Float64}}()) + @test length(c2) == 1 + @test MOI.get(bridged_mock, MOI.ConstraintPrimal(), c2[]) ≈ 1.0 + @test MOI.get(bridged_mock, MOI.ConstraintDual(), c2[]) ≈ 0.0 + + loc = MOI.get(bridged_mock, 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 + + 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 + MOI.empty!(mock) + bridged_mock = MOIB.VectorSlack{Float64}(mock) + x = MOI.add_variable(bridged_mock) + y = MOI.add_variable(bridged_mock) + f = MOI.VectorAffineFunction(MOI.VectorAffineTerm.(1, MOI.ScalarAffineTerm.([1.0, 2.0], [x, y])), [0.0]) + ci = MOI.add_constraint(bridged_mock, f, MOI.Nonpositives(1)) + @test MOI.get(bridged_mock, MOI.ConstraintFunction(), ci) ≈ f + newf = MOI.VectorAffineFunction(MOI.VectorAffineTerm.(1, MOI.ScalarAffineTerm.([2.0, 1.0], [x, y])), [0.0]) + MOI.set(bridged_mock, MOI.ConstraintFunction(), ci, newf) + @test MOI.get(bridged_mock, MOI.ConstraintFunction(), ci) ≈ newf + @test MOI.get(bridged_mock, MOI.ConstraintSet(), ci) == MOI.Nonpositives(1) + MOI.modify(bridged_mock, ci, MOI.VectorConstantChange([1.0])) + @test MOI.get(bridged_mock, MOI.ConstraintFunction(), ci) ≈ + MOI.VectorAffineFunction(MOI.VectorAffineTerm.(1, MOI.ScalarAffineTerm.([2.0, 1.0], [x, y])), [1.0]) + test_delete_bridge(bridged_mock, 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(bridged_mock, fp, MOI.PowerCone(0.1)) + @test MOI.get(bridged_mock, MOI.ConstraintSet(), cp) == MOI.PowerCone(0.1) + MOI.set(bridged_mock, MOI.ConstraintSet(), cp, MOI.PowerCone(0.2)) + @test MOI.get(bridged_mock, MOI.ConstraintSet(), cp) == MOI.PowerCone(0.2) + + MOIT.basic_constraint_tests(bridged_mock, config, + include=[(F, S) for + F in [MOI.VectorAffineFunction{Float64}, + MOI.VectorQuadraticFunction{Float64}], + S in [MOI.Nonnegatives, + MOI.Nonpositives] + ]) + + # 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], + (MOI.VectorAffineFunction{Float64}, MOI.Zeros) => [[1.], [1.]], + (MOI.VectorOfVariables, MOI.Nonnegatives) => [[1.]], + (MOI.VectorOfVariables, MOI.Nonpositives) => [[1.]])) + MOIT.linear7test(bridged_mock, config) + + c1 = MOI.get(bridged_mock, MOI.ListOfConstraintIndices{MOI.VectorAffineFunction{Float64}, MOI.Nonnegatives}()) + @test length(c1) == 1 + @test MOI.get(bridged_mock, MOI.ConstraintPrimal(), c1[]) ≈ [100.0] + @test MOI.get(bridged_mock, MOI.ConstraintDual(), c1[]) ≈ [1.0] + c2 = MOI.get(bridged_mock, MOI.ListOfConstraintIndices{MOI.VectorAffineFunction{Float64}, MOI.Nonpositives}()) + @test length(c2) == 1 + @test MOI.get(bridged_mock, MOI.ConstraintPrimal(), c2[]) ≈ [-100.0] + @test MOI.get(bridged_mock, MOI.ConstraintDual(), c2[]) ≈ [1.0] + + loc = MOI.get(bridged_mock, 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 + + 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 diff --git a/test/Bridges/soctopsdbridge.jl b/test/Bridges/soctopsdbridge.jl new file mode 100644 index 0000000000..b105a950af --- /dev/null +++ b/test/Bridges/soctopsdbridge.jl @@ -0,0 +1,23 @@ +@testset "SOCtoPSD" begin + bridged_mock = MOIB.SOCtoPSD{Float64}(mock) + mock.optimize! = (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [1.0, 1/√2, 1/√2], + (MOI.VectorAffineFunction{Float64}, MOI.PositiveSemidefiniteConeTriangle) => [[√2/2, -1/2, √2/4, -1/2, √2/4, √2/4]], + (MOI.VectorAffineFunction{Float64}, MOI.Zeros) => [[-√2]]) + MOIT.soc1vtest(bridged_mock, config) + MOIT.soc1ftest(bridged_mock, config) + ci = first(MOI.get(bridged_mock, MOI.ListOfConstraintIndices{MOI.VectorAffineFunction{Float64}, MOI.SecondOrderCone}())) + test_delete_bridge(bridged_mock, ci, 3, ((MOI.VectorAffineFunction{Float64}, MOI.PositiveSemidefiniteConeTriangle, 0),)) +end + +@testset "RSOCtoPSD" begin + bridged_mock = MOIB.RSOCtoPSD{Float64}(mock) + mock.optimize! = (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [1/√2, 1/√2, 0.5, 1.0], + (MOI.SingleVariable, MOI.EqualTo{Float64}) => [-√2, -1/√2], + (MOI.VectorAffineFunction{Float64}, MOI.PositiveSemidefiniteConeTriangle) => [[√2, -1/2, √2/8, -1/2, √2/8, √2/8]]) + MOIT.rotatedsoc1vtest(bridged_mock, config) + mock.optimize! = (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [1/√2, 1/√2], + (MOI.VectorAffineFunction{Float64}, MOI.PositiveSemidefiniteConeTriangle) => [[√2, -1/2, √2/8, -1/2, √2/8, √2/8]]) + MOIT.rotatedsoc1ftest(bridged_mock, config) + ci = first(MOI.get(bridged_mock, MOI.ListOfConstraintIndices{MOI.VectorAffineFunction{Float64}, MOI.RotatedSecondOrderCone}())) + test_delete_bridge(bridged_mock, ci, 2, ((MOI.VectorAffineFunction{Float64}, MOI.PositiveSemidefiniteConeTriangle, 0),)) +end diff --git a/test/Bridges/squarepsdbridge.jl b/test/Bridges/squarepsdbridge.jl new file mode 100644 index 0000000000..e3ff7e892c --- /dev/null +++ b/test/Bridges/squarepsdbridge.jl @@ -0,0 +1,18 @@ +@testset "SquarePSD" begin + bridged_mock = MOIB.SquarePSD{Float64}(mock) + mock.optimize! = (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, ones(4), + (MOI.ScalarAffineFunction{Float64}, MOI.EqualTo{Float64}) => [2, 2]) + MOIT.psds0vtest(bridged_mock, config) + mock.optimize! = (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, ones(4), + (MOI.VectorAffineFunction{Float64}, MOI.PositiveSemidefiniteConeTriangle) => [[1, -1, 1]], + (MOI.ScalarAffineFunction{Float64}, MOI.EqualTo{Float64}) => [2, 2]) + MOIT.psds0ftest(bridged_mock, config) + ci = first(MOI.get(bridged_mock, + MOI.ListOfConstraintIndices{MOI.VectorAffineFunction{Float64}, + MOI.PositiveSemidefiniteConeSquare}())) + test_delete_bridge(bridged_mock, ci, 4, + ((MOI.VectorAffineFunction{Float64}, + MOI.PositiveSemidefiniteConeTriangle, 0), + (MOI.ScalarAffineFunction{Float64}, + MOI.EqualTo{Float64}, 1))) +end diff --git a/test/Bridges/utilities.jl b/test/Bridges/utilities.jl new file mode 100644 index 0000000000..c6f8422cf2 --- /dev/null +++ b/test/Bridges/utilities.jl @@ -0,0 +1,33 @@ +function test_noc(bridged_mock, F, S, n) + @test MOI.get(bridged_mock, MOI.NumberOfConstraints{F, S}()) == n + @test length(MOI.get(bridged_mock, MOI.ListOfConstraintIndices{F, S}())) == n + @test ((F, S) in MOI.get(bridged_mock, MOI.ListOfConstraints())) == !iszero(n) +end + +# Test deletion of bridge +function test_delete_bridge( + m::MOIB.AbstractBridgeOptimizer, ci::MOI.ConstraintIndex{F, S}, nvars::Int, + nocs::Tuple; used_bridges = 1, num_bridged = 1) where {F, S} + num_bridges = length(m.bridges) + @test MOI.get(m, MOI.NumberOfVariables()) == nvars + test_noc(m, F, S, num_bridged) + for noc in nocs + test_noc(m, noc...) + end + @test MOI.is_valid(m, ci) + MOI.delete(m, ci) + @test_throws MOI.InvalidIndex{typeof(ci)} MOI.delete(m, ci) + try + MOI.delete(m, ci) + catch err + @test err.index == ci + end + @test !MOI.is_valid(m, ci) + @test length(m.bridges) == num_bridges - used_bridges + test_noc(m, F, S, num_bridged - 1) + # As the bridge has been removed, if the constraints it has created where not removed, it wouldn't be there to decrease this counter anymore + @test MOI.get(m, MOI.NumberOfVariables()) == nvars + for noc in nocs + test_noc(m, noc...) + end +end diff --git a/test/Bridges/vectorizebridge.jl b/test/Bridges/vectorizebridge.jl new file mode 100644 index 0000000000..59110eb87e --- /dev/null +++ b/test/Bridges/vectorizebridge.jl @@ -0,0 +1,61 @@ +@testset "Vectorize" begin + bridged_mock = MOIB.Vectorize{Float64}(mock) + + MOIT.scalar_function_constant_not_zero(bridged_mock) + + MOIT.basic_constraint_tests(bridged_mock, config, + include=Iterators.product( + [MOI.SingleVariable, + MOI.ScalarAffineFunction{Float64}], + # TODO add it when operate(vcat, ...) + # is implemented for quadratic + #MOI.ScalarQuadraticFunction{Float64}], + [MOI.EqualTo{Float64}, + MOI.GreaterThan{Float64}, + MOI.LessThan{Float64}])) + + MOIU.set_mock_optimize!(mock, + (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [1, 0], + (MOI.VectorAffineFunction{Float64}, MOI.Nonpositives) => [[-1]], + (MOI.VectorAffineFunction{Float64}, MOI.Nonnegatives) => [[0], [1]])) + MOIT.linear2test(bridged_mock, config) + + MOIU.set_mock_optimize!(mock, + (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [0, 0]), + (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [100, 0]), + (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [100, -100])) + MOIT.linear4test(bridged_mock, config) + + MOIU.set_mock_optimize!(mock, + (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [4/3, 4/3]), + (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [2, 0]), + (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [4, 0]), + (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [2])) + MOIT.linear5test(mock, config) + + MOIU.set_mock_optimize!(mock, + (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [0, 0]), + (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [100, 0]), + (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [100, -100])) + MOIT.linear6test(mock, config) + + MOIU.set_mock_optimize!(mock, + (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [0, 1/2, 1], + (MOI.VectorAffineFunction{Float64}, MOI.Nonpositives) => [[-1], [-2]], + (MOI.VectorAffineFunction{Float64}, MOI.Nonnegatives) => [[2], [0], [0]]), + (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [1], + (MOI.VectorAffineFunction{Float64}, MOI.Nonpositives) => [[-1]], + (MOI.VectorAffineFunction{Float64}, MOI.Nonnegatives) => [[0]])) + # linear14 has double variable bounds for the z variable + mock.eval_variable_constraint_dual = false + MOIT.linear14test(bridged_mock, config) + mock.eval_variable_constraint_dual = true + + mock.optimize! = (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, ones(3), + (MOI.VectorAffineFunction{Float64}, MOI.Zeros) => [[2]]) + MOIT.psdt0vtest(bridged_mock, config) + ci = first(MOI.get(bridged_mock, MOI.ListOfConstraintIndices{MOI.ScalarAffineFunction{Float64}, MOI.EqualTo{Float64}}())) + test_delete_bridge(bridged_mock, ci, 3, + ((MOI.VectorAffineFunction{Float64}, + MOI.Zeros, 0),)) +end diff --git a/test/bridge.jl b/test/bridge.jl deleted file mode 100644 index ef5ab3ed17..0000000000 --- a/test/bridge.jl +++ /dev/null @@ -1,919 +0,0 @@ -using Test - -using MathOptInterface -const MOI = MathOptInterface -const MOIT = MathOptInterface.Test -const MOIU = MathOptInterface.Utilities -const MOIB = MathOptInterface.Bridges - -# Model not supporting Interval -MOIU.@model(SimpleModel, - (), - (MOI.EqualTo, MOI.GreaterThan, MOI.LessThan, MOI.Interval), - (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,), - (MOI.VectorAffineFunction, MOI.VectorQuadraticFunction)) - -function test_noc(bridged_mock, F, S, n) - @test MOI.get(bridged_mock, MOI.NumberOfConstraints{F, S}()) == n - @test length(MOI.get(bridged_mock, MOI.ListOfConstraintIndices{F, S}())) == n - @test ((F, S) in MOI.get(bridged_mock, MOI.ListOfConstraints())) == !iszero(n) -end - -struct UnknownConstraintAttribute <: MOI.AbstractConstraintAttribute end -MOI.is_set_by_optimize(::UnknownConstraintAttribute) = true - -# Test deletion of bridge -function test_delete_bridge( - m::MOIB.AbstractBridgeOptimizer, ci::MOI.ConstraintIndex{F, S}, nvars::Int, - nocs::Tuple; used_bridges = 1, num_bridged = 1) where {F, S} - num_bridges = length(m.bridges) - @test MOI.get(m, MOI.NumberOfVariables()) == nvars - test_noc(m, F, S, num_bridged) - for noc in nocs - test_noc(m, noc...) - end - @test MOI.is_valid(m, ci) - MOI.delete(m, ci) - @test_throws MOI.InvalidIndex{typeof(ci)} MOI.delete(m, ci) - try - MOI.delete(m, ci) - catch err - @test err.index == ci - end - @test !MOI.is_valid(m, ci) - @test length(m.bridges) == num_bridges - used_bridges - test_noc(m, F, S, num_bridged - 1) - # As the bridge has been removed, if the constraints it has created where not removed, it wouldn't be there to decrease this counter anymore - @test MOI.get(m, MOI.NumberOfVariables()) == nvars - for noc in nocs - test_noc(m, noc...) - end -end - -@testset "BridgeOptimizer" begin - mock = MOIU.MockOptimizer(SimpleModel{Float64}()) - bridged_mock = MOIB.SplitInterval{Float64}(mock) - - @testset "Unsupported constraint attribute" begin - attr = UnknownConstraintAttribute() - err = ArgumentError( - "Constraint bridge of type `MathOptInterface.Bridges.SplitIntervalBridge{Float64,MathOptInterface.SingleVariable}` " * - "does not support accessing the attribute `$attr`.") - x = MOI.add_variable(bridged_mock) - ci = MOI.add_constraint(bridged_mock, MOI.SingleVariable(x), - MOI.Interval(0.0, 1.0)) - @test_throws err MOI.get(bridged_mock, attr, ci) - end - - @testset "Issue #453" begin - MOI.empty!(bridged_mock) - MOIU.loadfromstring!(bridged_mock, """ - variables: x - maxobjective: 3.0x - c: 2.0x in Interval(1.0, 4.0) - d: x in LessThan(1.5) - """) - x = MOI.get(bridged_mock, MOI.VariableIndex, "x") - @test isa(x, MOI.VariableIndex) - c1 = MOI.get(bridged_mock, MOI.ConstraintIndex{MOI.ScalarAffineFunction{Float64}, MOI.Interval{Float64}}, "c") - @test isa(c1, MOI.ConstraintIndex{MOI.ScalarAffineFunction{Float64}, MOI.Interval{Float64}}) - c2 = MOI.get(bridged_mock, MOI.ConstraintIndex, "c") - @test c1 == c2 - d1 = MOI.get(bridged_mock, MOI.ConstraintIndex{MOI.SingleVariable, MOI.LessThan{Float64}}, "d") - @test isa(d1, MOI.ConstraintIndex{MOI.SingleVariable, MOI.LessThan{Float64}}) - d2 = MOI.get(bridged_mock, MOI.ConstraintIndex, "d") - @test d1 == d2 - end - - MOI.empty!(bridged_mock) - - @testset "Name test" begin - MOIT.nametest(bridged_mock) - end - - @testset "Copy test" begin - MOIT.failcopytestc(bridged_mock) - MOIT.failcopytestia(bridged_mock) - MOIT.failcopytestva(bridged_mock) - MOIT.failcopytestca(bridged_mock) - MOIT.copytest(bridged_mock, SimpleModel{Float64}()) - end - - @testset "Custom test" begin - model = MOIB.SplitInterval{Int}(SimpleModel{Int}()) - @test !MOIB.supports_bridging_constraint(model, MOI.VectorAffineFunction{Float64}, MOI.Interval{Float64}) - - x, y = MOI.add_variables(model, 2) - @test MOI.get(model, MOI.NumberOfVariables()) == 2 - - f1 = MOI.ScalarAffineFunction([MOI.ScalarAffineTerm(3, x)], 7) - c1 = MOI.add_constraint(model, f1, MOI.Interval(-1, 1)) - - @test MOI.get(model, MOI.ListOfConstraints()) == [(MOI.ScalarAffineFunction{Int},MOI.Interval{Int})] - test_noc(model, MOI.ScalarAffineFunction{Int}, MOI.GreaterThan{Int}, 0) - test_noc(model, MOI.ScalarAffineFunction{Int}, MOI.Interval{Int}, 1) - @test (@inferred MOI.get(model, MOI.ListOfConstraintIndices{MOI.ScalarAffineFunction{Int},MOI.Interval{Int}}())) == [c1] - - f2 = MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([2, -1], [x, y]), 2) - c2 = MOI.add_constraint(model, f1, MOI.GreaterThan(-2)) - - @test MOI.get(model, MOI.ListOfConstraints()) == [(MOI.ScalarAffineFunction{Int},MOI.GreaterThan{Int}), (MOI.ScalarAffineFunction{Int},MOI.Interval{Int})] - test_noc(model, MOI.ScalarAffineFunction{Int}, MOI.GreaterThan{Int}, 1) - test_noc(model, MOI.ScalarAffineFunction{Int}, MOI.Interval{Int}, 1) - @test (@inferred MOI.get(model, MOI.ListOfConstraintIndices{MOI.ScalarAffineFunction{Int},MOI.Interval{Int}}())) == [c1] - @test (@inferred MOI.get(model, MOI.ListOfConstraintIndices{MOI.ScalarAffineFunction{Int},MOI.GreaterThan{Int}}())) == [c2] - - @test MOI.is_valid(model, c2) - MOI.delete(model, c2) - - @test MOI.get(model, MOI.ListOfConstraints()) == [(MOI.ScalarAffineFunction{Int},MOI.Interval{Int})] - test_noc(model, MOI.ScalarAffineFunction{Int}, MOI.GreaterThan{Int}, 0) - test_noc(model, MOI.ScalarAffineFunction{Int}, MOI.Interval{Int}, 1) - @test (@inferred MOI.get(model, MOI.ListOfConstraintIndices{MOI.ScalarAffineFunction{Int},MOI.Interval{Int}}())) == [c1] - end - - @testset "Continuous Linear" begin - exclude = ["partial_start"] # VariablePrimalStart not supported. - MOIT.contlineartest(bridged_mock, MOIT.TestConfig(solve=false), exclude) - end -end - -# Model not supporting RotatedSecondOrderCone -MOIU.@model(NoRSOCModel, - (), - (MOI.EqualTo, MOI.GreaterThan, MOI.LessThan), - (MOI.Zeros, MOI.Nonnegatives, MOI.Nonpositives, MOI.SecondOrderCone, - MOI.ExponentialCone, MOI.PositiveSemidefiniteConeTriangle), - (), - (MOI.SingleVariable,), - (MOI.ScalarAffineFunction, MOI.ScalarQuadraticFunction), - (MOI.VectorOfVariables,), - (MOI.VectorAffineFunction, MOI.VectorQuadraticFunction)) - -# Model not supporting VectorOfVariables and SingleVariable -MOIU.@model(NoVariableModel, - (MOI.ZeroOne, MOI.Integer), - (MOI.EqualTo, MOI.GreaterThan, MOI.LessThan), - (MOI.Zeros, MOI.Nonnegatives, MOI.Nonpositives, MOI.SecondOrderCone), - (), - (), - (MOI.ScalarAffineFunction,), - (), - (MOI.VectorAffineFunction,)) - -MOIU.@model(GreaterNonnegModel, - (), - (MOI.GreaterThan,), - (MOI.Nonnegatives,), - (), - (MOI.SingleVariable,), - (MOI.ScalarAffineFunction, MOI.ScalarQuadraticFunction), - (MOI.VectorOfVariables,), - (MOI.VectorAffineFunction, MOI.VectorQuadraticFunction)) - - -MOIU.@model(ModelNoVAFinSOC, - (), - (MOI.EqualTo, MOI.GreaterThan, MOI.LessThan, MOI.Interval), - (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,), - (MOI.VectorAffineFunction, MOI.VectorQuadraticFunction)) - -MOI.supports_constraint(::ModelNoVAFinSOC{Float64}, - ::Type{MOI.VectorAffineFunction{Float64}}, - ::Type{MOI.SecondOrderCone}) = false - -# Model supporting nothing -MOIU.@model NothingModel () () () () () () () () - -struct BridgeAddingNoConstraint{T} <: MOI.Bridges.AbstractBridge end -MOIB.added_constraint_types(::Type{BridgeAddingNoConstraint{T}}) where {T} = [] -function MOI.supports_constraint(::Type{<:BridgeAddingNoConstraint}, - ::Type{MOI.SingleVariable}, - ::Type{MOI.Integer}) - return true -end -function MOIB.concrete_bridge_type(::Type{<:BridgeAddingNoConstraint{T}}, - ::Type{MOI.SingleVariable}, - ::Type{MOI.Integer}) where {T} - return BridgeAddingNoConstraint{T} -end - -@testset "LazyBridgeOptimizer" begin - @testset "Bridge adding no constraint" begin - mock = MOIU.MockOptimizer(NothingModel{Int}()) - bridged = MOIB.LazyBridgeOptimizer(mock, NothingModel{Int}()) - MOI.Bridges.add_bridge(bridged, BridgeAddingNoConstraint{Float64}) - @test MOI.Bridges.supports_bridging_constraint(bridged, - MOI.SingleVariable, - MOI.Integer) - end - - @testset "Unsupported constraint with cycles" begin - # Test that `supports_constraint` works correctly when it is not - # supported but the bridges forms a cycle - mock = MOIU.MockOptimizer(NothingModel{Float64}()) - bridged = MOIB.full_bridge_optimizer(mock, Float64) - @test !MOI.supports_constraint( - bridged, MOI.SingleVariable, MOI.GreaterThan{Float64}) - @test !MOI.supports_constraint( - bridged, MOI.VectorAffineFunction{Float64}, MOI.Nonpositives) - end - - mock = MOIU.MockOptimizer(NoRSOCModel{Float64}()) - bridged_mock = MOIB.LazyBridgeOptimizer( - mock, MOIB.AllBridgedConstraints{Float64}()) - - @testset "UnsupportedConstraint when it cannot be bridged" begin - x = MOI.add_variables(bridged_mock, 4) - err = MOI.UnsupportedConstraint{MOI.VectorOfVariables, - MOI.RotatedSecondOrderCone}() - @test_throws err begin - MOI.add_constraint(bridged_mock, MOI.VectorOfVariables(x), - MOI.RotatedSecondOrderCone(4)) - end - end - - MOIB.add_bridge(bridged_mock, MOIB.SplitIntervalBridge{Float64}) - MOIB.add_bridge(bridged_mock, MOIB.RSOCtoPSDBridge{Float64}) - MOIB.add_bridge(bridged_mock, MOIB.SOCtoPSDBridge{Float64}) - MOIB.add_bridge(bridged_mock, MOIB.RSOCBridge{Float64}) - - @testset "Name test" begin - MOIT.nametest(bridged_mock) - end - - @testset "Copy test" begin - MOIT.failcopytestc(bridged_mock) - MOIT.failcopytestia(bridged_mock) - MOIT.failcopytestva(bridged_mock) - MOIT.failcopytestca(bridged_mock) - MOIT.copytest(bridged_mock, NoRSOCModel{Float64}()) - end - - # Test that RSOCtoPSD is used instead of RSOC+SOCtoPSD as it is a shortest path. - @testset "Bridge selection" begin - MOI.empty!(bridged_mock) - @test !(MOI.supports_constraint(bridged_mock, - MOI.VectorAffineFunction{Float64}, - MOI.LogDetConeTriangle)) - x = MOI.add_variables(bridged_mock, 3) - err = MOI.UnsupportedConstraint{MOI.VectorAffineFunction{Float64}, - MOI.LogDetConeTriangle}() - @test_throws err begin - MOIB.bridge_type(bridged_mock, MOI.VectorAffineFunction{Float64}, - MOI.LogDetConeTriangle) - end - c = MOI.add_constraint(bridged_mock, MOI.VectorOfVariables(x), - MOI.RotatedSecondOrderCone(3)) - @test MOIB.bridge_type(bridged_mock, MOI.VectorOfVariables, - MOI.RotatedSecondOrderCone) == MOIB.RSOCtoPSDBridge{Float64} - @test MOIB.bridge(bridged_mock, c) isa MOIB.RSOCtoPSDBridge - @test bridged_mock.dist[(MOI.VectorOfVariables, - MOI.RotatedSecondOrderCone)] == 1 - end - - @testset "Supports" begin - full_bridged_mock = MOIB.full_bridge_optimizer(mock, Float64) - greater_nonneg_mock = MOIU.MockOptimizer(GreaterNonnegModel{Float64}()) - full_bridged_greater_nonneg = MOIB.full_bridge_optimizer( - greater_nonneg_mock, Float64) - for F in [MOI.SingleVariable, MOI.ScalarAffineFunction{Float64}, - MOI.ScalarQuadraticFunction{Float64}] - @test MOI.supports_constraint(full_bridged_mock, F, - MOI.Interval{Float64}) - @test !MOI.supports_constraint( - greater_nonneg_mock, F, MOI.LessThan{Float64}) - @test MOI.supports_constraint( - full_bridged_greater_nonneg, F, MOI.LessThan{Float64}) - end - for F in [MOI.VectorOfVariables, MOI.VectorAffineFunction{Float64}, - MOI.VectorQuadraticFunction{Float64}] - @test MOI.supports_constraint(full_bridged_mock, F, - MOI.PositiveSemidefiniteConeSquare) - @test MOI.supports_constraint(full_bridged_mock, F, - MOI.GeometricMeanCone) - @test !MOI.supports_constraint( - greater_nonneg_mock, F, MOI.Nonpositives) - @test MOI.supports_constraint( - full_bridged_greater_nonneg, F, MOI.Nonnegatives) - end - for F in [MOI.VectorOfVariables, MOI.VectorAffineFunction{Float64}] - # The bridges in this for loop do not support yet - # VectorQuadraticFunction. See TODO's for the reason. - # TODO: Missing vcat for quadratic for supporting quadratic. - @test MOI.supports_constraint(full_bridged_mock, F, - MOI.RotatedSecondOrderCone) - # TODO: Det bridges need to use MOIU.operate to support quadratic. - @test MOI.supports_constraint(full_bridged_mock, F, - MOI.LogDetConeTriangle) - @test MOI.supports_constraint(full_bridged_mock, F, - MOI.RootDetConeTriangle) - end - mock2 = MOIU.MockOptimizer(ModelNoVAFinSOC{Float64}()) - @test !MOI.supports_constraint(mock2, MOI.VectorAffineFunction{Float64}, - MOI.SecondOrderCone) - full_bridged_mock2 = MOIB.full_bridge_optimizer(mock2, Float64) - @test MOI.supports_constraint(full_bridged_mock2, MOI.VectorAffineFunction{Float64}, - MOI.SecondOrderCone) - @testset "Unslack" begin - for T in [Float64, Int] - no_variable_mock = MOIU.MockOptimizer(NoVariableModel{T}()) - full_bridged_no_variable = MOIB.full_bridge_optimizer( - no_variable_mock, T) - for S in [MOI.LessThan{T}, MOI.GreaterThan{T}, MOI.EqualTo{T}, - MOI.ZeroOne, MOI.Integer] - @test MOI.supports_constraint( - full_bridged_no_variable, MOI.SingleVariable, S) - end - for S in [MOI.Nonpositives, MOI.Nonnegatives, - MOI.Zeros, MOI.SecondOrderCone] - @test MOI.supports_constraint( - full_bridged_no_variable, MOI.VectorOfVariables, S) - end - end - end - end - - @testset "Combining two briges" begin - full_bridged_mock = MOIB.full_bridge_optimizer(mock, Float64) - mock.optimize! = (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [1, 1, 0, 1, 1, 0, 1, √2]) - config = MOIT.TestConfig() - MOIT.rootdett1vtest(full_bridged_mock, config) - MOIT.rootdett1ftest(full_bridged_mock, config) - # Dual is not yet implemented for RootDet and GeoMean bridges - ci = first(MOI.get(full_bridged_mock, MOI.ListOfConstraintIndices{MOI.VectorAffineFunction{Float64}, MOI.RootDetConeTriangle}())) - test_delete_bridge(full_bridged_mock, ci, 4, ((MOI.VectorAffineFunction{Float64}, MOI.RotatedSecondOrderCone, 0), - (MOI.VectorAffineFunction{Float64}, MOI.GeometricMeanCone, 0), - (MOI.VectorAffineFunction{Float64}, MOI.PositiveSemidefiniteConeTriangle, 0)), - used_bridges = 3) - end - - @testset "Continuous Linear" begin - exclude = ["partial_start"] # VariablePrimalStart not supported. - MOIT.contlineartest(bridged_mock, MOIT.TestConfig(solve=false), exclude) - end - - @testset "Continuous Conic" begin - MOIT.contconictest(MOIB.full_bridge_optimizer(mock, Float64), MOIT.TestConfig(solve=false), ["logdets", "rootdets", "psds"]) - end -end - -@testset "Bridge tests" begin - @testset "Scalarize" begin - bridged_mock = MOIB.Scalarize{Float64}(mock) - # VectorOfVariables-in-Nonnegatives - # VectorAffineFunction-in-Zeros - mock.optimize! = (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [1.0, 0.0, 2.0], - (MOI.ScalarAffineFunction{Float64}, MOI.EqualTo{Float64}) => [-3, -1]) - MOIT.lin1vtest(bridged_mock, config) - ci = first(MOI.get(bridged_mock, MOI.ListOfConstraintIndices{MOI.VectorAffineFunction{Float64}, MOI.Zeros}())) - test_delete_bridge(bridged_mock, ci, 3, - ((MOI.ScalarAffineFunction{Float64}, MOI.EqualTo{Float64}, 0), - (MOI.SingleVariable, MOI.GreaterThan{Float64}, 0))) - ci = first(MOI.get(bridged_mock, MOI.ListOfConstraintIndices{MOI.VectorOfVariables, MOI.Nonnegatives}())) - test_delete_bridge(bridged_mock, ci, 3, - ((MOI.ScalarAffineFunction{Float64}, MOI.EqualTo{Float64}, 0), - (MOI.SingleVariable, MOI.GreaterThan{Float64}, 0))) - # VectorAffineFunction-in-Nonnegatives - # VectorAffineFunction-in-Zeros - mock.optimize! = (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [1.0, 0.0, 2.0], - (MOI.ScalarAffineFunction{Float64}, MOI.GreaterThan{Float64}) => [0, 2, 0], - (MOI.ScalarAffineFunction{Float64}, MOI.EqualTo{Float64}) => [-3, -1]) - MOIT.lin1ftest(bridged_mock, config) - ci = first(MOI.get(bridged_mock, MOI.ListOfConstraintIndices{MOI.VectorAffineFunction{Float64}, MOI.Zeros}())) - test_delete_bridge(bridged_mock, ci, 3, - ((MOI.ScalarAffineFunction{Float64}, MOI.EqualTo{Float64}, 0), - (MOI.ScalarAffineFunction{Float64}, MOI.GreaterThan{Float64}, 0))) - ci = first(MOI.get(bridged_mock, MOI.ListOfConstraintIndices{MOI.VectorAffineFunction{Float64}, MOI.Nonnegatives}())) - test_delete_bridge(bridged_mock, ci, 3, - ((MOI.ScalarAffineFunction{Float64}, MOI.EqualTo{Float64}, 0), - (MOI.ScalarAffineFunction{Float64}, MOI.GreaterThan{Float64}, 0))) - # VectorOfVariables-in-Nonnegatives - # VectorOfVariables-in-Nonpositives - # VectorOfVariables-in-Zeros - # VectorAffineFunction-in-Zeros - mock.optimize! = (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [-4, -3, 16, 0], - (MOI.ScalarAffineFunction{Float64}, MOI.EqualTo{Float64}) => [7, 2, -4]) - MOIT.lin2vtest(bridged_mock, config) - # VectorAffineFunction-in-Nonnegatives - # VectorAffineFunction-in-Nonpositives - # VectorAffineFunction-in-Zeros - mock.optimize! = (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [-4, -3, 16, 0], - (MOI.ScalarAffineFunction{Float64}, MOI.GreaterThan{Float64}) => [0], - (MOI.ScalarAffineFunction{Float64}, MOI.LessThan{Float64}) => [0], - (MOI.ScalarAffineFunction{Float64}, MOI.EqualTo{Float64}) => [7, 2, -4, 7]) - MOIT.lin2ftest(bridged_mock, config) - end - - @testset "Vectorize" begin - bridged_mock = MOIB.Vectorize{Float64}(mock) - - MOIT.scalar_function_constant_not_zero(bridged_mock) - - MOIT.basic_constraint_tests(bridged_mock, config, - include=Iterators.product( - [MOI.SingleVariable, - MOI.ScalarAffineFunction{Float64}], - # TODO add it when operate(vcat, ...) - # is implemented for quadratic - #MOI.ScalarQuadraticFunction{Float64}], - [MOI.EqualTo{Float64}, - MOI.GreaterThan{Float64}, - MOI.LessThan{Float64}])) - - MOIU.set_mock_optimize!(mock, - (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [1, 0], - (MOI.VectorAffineFunction{Float64}, MOI.Nonpositives) => [[-1]], - (MOI.VectorAffineFunction{Float64}, MOI.Nonnegatives) => [[0], [1]])) - MOIT.linear2test(bridged_mock, config) - - MOIU.set_mock_optimize!(mock, - (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [0, 0]), - (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [100, 0]), - (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [100, -100])) - MOIT.linear4test(bridged_mock, config) - - MOIU.set_mock_optimize!(mock, - (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [4/3, 4/3]), - (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [2, 0]), - (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [4, 0]), - (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [2])) - MOIT.linear5test(mock, config) - - MOIU.set_mock_optimize!(mock, - (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [0, 0]), - (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [100, 0]), - (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [100, -100])) - MOIT.linear6test(mock, config) - - MOIU.set_mock_optimize!(mock, - (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [0, 1/2, 1], - (MOI.VectorAffineFunction{Float64}, MOI.Nonpositives) => [[-1], [-2]], - (MOI.VectorAffineFunction{Float64}, MOI.Nonnegatives) => [[2], [0], [0]]), - (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [1], - (MOI.VectorAffineFunction{Float64}, MOI.Nonpositives) => [[-1]], - (MOI.VectorAffineFunction{Float64}, MOI.Nonnegatives) => [[0]])) - # linear14 has double variable bounds for the z variable - mock.eval_variable_constraint_dual = false - MOIT.linear14test(bridged_mock, config) - mock.eval_variable_constraint_dual = true - - mock.optimize! = (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, ones(3), - (MOI.VectorAffineFunction{Float64}, MOI.Zeros) => [[2]]) - MOIT.psdt0vtest(bridged_mock, config) - ci = first(MOI.get(bridged_mock, MOI.ListOfConstraintIndices{MOI.ScalarAffineFunction{Float64}, MOI.EqualTo{Float64}}())) - test_delete_bridge(bridged_mock, ci, 3, - ((MOI.VectorAffineFunction{Float64}, - MOI.Zeros, 0),)) - end - - @testset "Interval" begin - bridged_mock = MOIB.SplitInterval{Float64}(mock) - MOIT.basic_constraint_tests(bridged_mock, config, - include=[(MOI.SingleVariable, - MOI.Interval{Float64}), - (MOI.ScalarAffineFunction{Float64}, - MOI.Interval{Float64}), - (MOI.ScalarQuadraticFunction{Float64}, - MOI.Interval{Float64})]) - MOIU.set_mock_optimize!(mock, - (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [5.0, 5.0], con_basis = - [(MOI.ScalarAffineFunction{Float64}, MOI.GreaterThan{Float64}) => [MOI.BASIC], - (MOI.ScalarAffineFunction{Float64}, MOI.LessThan{Float64}) => [MOI.NONBASIC], - (MOI.SingleVariable, MOI.GreaterThan{Float64}) => [MOI.BASIC, MOI.BASIC]], - (MOI.ScalarAffineFunction{Float64}, MOI.GreaterThan{Float64}) => [0], - (MOI.ScalarAffineFunction{Float64}, MOI.LessThan{Float64}) => [-1]), - (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [2.5, 2.5], con_basis = - [(MOI.ScalarAffineFunction{Float64}, MOI.GreaterThan{Float64}) => [MOI.NONBASIC], - (MOI.ScalarAffineFunction{Float64}, MOI.LessThan{Float64}) => [MOI.BASIC], - (MOI.SingleVariable, MOI.GreaterThan{Float64}) => [MOI.BASIC, MOI.BASIC]], - (MOI.ScalarAffineFunction{Float64}, MOI.GreaterThan{Float64}) => [1], - (MOI.ScalarAffineFunction{Float64}, MOI.LessThan{Float64}) => [0]), - (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [1.0, 1.0], con_basis = - [(MOI.ScalarAffineFunction{Float64}, MOI.GreaterThan{Float64}) => [MOI.NONBASIC], - (MOI.ScalarAffineFunction{Float64}, MOI.LessThan{Float64}) => [MOI.BASIC], - (MOI.SingleVariable, MOI.GreaterThan{Float64}) => [MOI.BASIC, MOI.BASIC]]), - (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [6.0, 6.0], con_basis = - [(MOI.ScalarAffineFunction{Float64}, MOI.GreaterThan{Float64}) => [MOI.BASIC], - (MOI.ScalarAffineFunction{Float64}, MOI.LessThan{Float64}) => [MOI.NONBASIC], - (MOI.SingleVariable, MOI.GreaterThan{Float64}) => [MOI.BASIC, MOI.BASIC]])) - MOIT.linear10test(bridged_mock, config_with_basis) - MOIU.set_mock_optimize!(mock, - (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [0.0, 0.0], con_basis = - [(MOI.ScalarAffineFunction{Float64}, MOI.GreaterThan{Float64}) => [MOI.BASIC], - (MOI.ScalarAffineFunction{Float64}, MOI.LessThan{Float64}) => [MOI.BASIC], - (MOI.SingleVariable, MOI.GreaterThan{Float64}) => [MOI.NONBASIC, MOI.NONBASIC]], - (MOI.ScalarAffineFunction{Float64}, MOI.GreaterThan{Float64}) => [0], - (MOI.ScalarAffineFunction{Float64}, MOI.LessThan{Float64}) => [0])) - MOIT.linear10btest(bridged_mock, config_with_basis) - - ci = first(MOI.get(bridged_mock, MOI.ListOfConstraintIndices{MOI.ScalarAffineFunction{Float64}, MOI.Interval{Float64}}())) - newf = MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([1.0, -1.0], MOI.get(bridged_mock, MOI.ListOfVariableIndices())), 0.0) - MOI.set(bridged_mock, MOI.ConstraintFunction(), ci, newf) - @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 - @testset "Scalar slack" begin - MOI.empty!(mock) - bridged_mock = MOIB.ScalarSlack{Float64}(mock) - x = MOI.add_variable(bridged_mock) - y = MOI.add_variable(bridged_mock) - f = MOI.ScalarAffineFunction(MOI.ScalarAffineTerm{Float64}.([1.0, 2.0], [x, y]), 0.0) - ci = MOI.add_constraint(bridged_mock, f, MOI.GreaterThan(0.0)) - @test MOI.get(bridged_mock, MOI.ConstraintFunction(), ci) ≈ f - newf = MOI.ScalarAffineFunction(MOI.ScalarAffineTerm{Float64}.([2.0, 1.0], [x, y]), 0.0) - MOI.set(bridged_mock, MOI.ConstraintFunction(), ci, newf) - @test MOI.get(bridged_mock, MOI.ConstraintFunction(), ci) ≈ newf - @test MOI.get(bridged_mock, MOI.ConstraintSet(), ci) == MOI.GreaterThan(0.0) - MOI.set(bridged_mock, MOI.ConstraintSet(), ci, MOI.GreaterThan(1.0)) - @test MOI.get(bridged_mock, MOI.ConstraintSet(), ci) == MOI.GreaterThan(1.0) - MOI.modify(bridged_mock, ci, MOI.ScalarConstantChange{Float64}(1.0)) - @test MOI.get(bridged_mock, MOI.ConstraintFunction(), ci) ≈ - MOI.ScalarAffineFunction(MOI.ScalarAffineTerm{Float64}.([2.0, 1.0], [x, y]), 1.0) - test_delete_bridge(bridged_mock, ci, 2, ((MOI.ScalarAffineFunction{Float64}, MOI.Interval{Float64}, 0),)) - - MOIT.basic_constraint_tests(bridged_mock, config, - include=[(F, S) for - F in [MOI.ScalarAffineFunction{Float64}, - MOI.ScalarQuadraticFunction{Float64}], - 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], con_basis = - [(MOI.ScalarAffineFunction{Float64}, MOI.EqualTo{Float64}) => [MOI.NONBASIC], - (MOI.SingleVariable, MOI.GreaterThan{Float64}) => [MOI.BASIC, MOI.NONBASIC], - (MOI.SingleVariable, MOI.LessThan{Float64}) => [MOI.NONBASIC]])) - MOIT.linear2test(bridged_mock, MOIT.TestConfig(duals = false, basis = true)) - c1 = MOI.get(bridged_mock, MOI.ListOfConstraintIndices{MOI.ScalarAffineFunction{Float64}, MOI.LessThan{Float64}}()) - @test length(c1) == 1 - @test MOI.get(bridged_mock, MOI.ConstraintBasisStatus(), c1[]) == MOI.NONBASIC - - 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], - (MOI.ScalarAffineFunction{Float64}, MOI.EqualTo{Float64}) => [1, 0], - (MOI.SingleVariable, MOI.GreaterThan{Float64}) => [1], - (MOI.SingleVariable, MOI.LessThan{Float64}) => [0])) - MOIT.linear11test(bridged_mock, MOIT.TestConfig(duals = false)) - - c1 = MOI.get(bridged_mock, MOI.ListOfConstraintIndices{MOI.ScalarAffineFunction{Float64}, MOI.GreaterThan{Float64}}()) - @test length(c1) == 1 - @test MOI.get(bridged_mock, MOI.ConstraintPrimal(), c1[]) ≈ 1.0 - @test MOI.get(bridged_mock, MOI.ConstraintDual(), c1[]) ≈ 1.0 - c2 = MOI.get(bridged_mock, MOI.ListOfConstraintIndices{MOI.ScalarAffineFunction{Float64}, MOI.LessThan{Float64}}()) - @test length(c2) == 1 - @test MOI.get(bridged_mock, MOI.ConstraintPrimal(), c2[]) ≈ 1.0 - @test MOI.get(bridged_mock, MOI.ConstraintDual(), c2[]) ≈ 0.0 - - loc = MOI.get(bridged_mock, 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 - - 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 - MOI.empty!(mock) - bridged_mock = MOIB.VectorSlack{Float64}(mock) - x = MOI.add_variable(bridged_mock) - y = MOI.add_variable(bridged_mock) - f = MOI.VectorAffineFunction(MOI.VectorAffineTerm.(1, MOI.ScalarAffineTerm.([1.0, 2.0], [x, y])), [0.0]) - ci = MOI.add_constraint(bridged_mock, f, MOI.Nonpositives(1)) - @test MOI.get(bridged_mock, MOI.ConstraintFunction(), ci) ≈ f - newf = MOI.VectorAffineFunction(MOI.VectorAffineTerm.(1, MOI.ScalarAffineTerm.([2.0, 1.0], [x, y])), [0.0]) - MOI.set(bridged_mock, MOI.ConstraintFunction(), ci, newf) - @test MOI.get(bridged_mock, MOI.ConstraintFunction(), ci) ≈ newf - @test MOI.get(bridged_mock, MOI.ConstraintSet(), ci) == MOI.Nonpositives(1) - MOI.modify(bridged_mock, ci, MOI.VectorConstantChange([1.0])) - @test MOI.get(bridged_mock, MOI.ConstraintFunction(), ci) ≈ - MOI.VectorAffineFunction(MOI.VectorAffineTerm.(1, MOI.ScalarAffineTerm.([2.0, 1.0], [x, y])), [1.0]) - test_delete_bridge(bridged_mock, 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(bridged_mock, fp, MOI.PowerCone(0.1)) - @test MOI.get(bridged_mock, MOI.ConstraintSet(), cp) == MOI.PowerCone(0.1) - MOI.set(bridged_mock, MOI.ConstraintSet(), cp, MOI.PowerCone(0.2)) - @test MOI.get(bridged_mock, MOI.ConstraintSet(), cp) == MOI.PowerCone(0.2) - - MOIT.basic_constraint_tests(bridged_mock, config, - include=[(F, S) for - F in [MOI.VectorAffineFunction{Float64}, - MOI.VectorQuadraticFunction{Float64}], - S in [MOI.Nonnegatives, - MOI.Nonpositives] - ]) - - # 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], - (MOI.VectorAffineFunction{Float64}, MOI.Zeros) => [[1.], [1.]], - (MOI.VectorOfVariables, MOI.Nonnegatives) => [[1.]], - (MOI.VectorOfVariables, MOI.Nonpositives) => [[1.]])) - MOIT.linear7test(bridged_mock, config) - - c1 = MOI.get(bridged_mock, MOI.ListOfConstraintIndices{MOI.VectorAffineFunction{Float64}, MOI.Nonnegatives}()) - @test length(c1) == 1 - @test MOI.get(bridged_mock, MOI.ConstraintPrimal(), c1[]) ≈ [100.0] - @test MOI.get(bridged_mock, MOI.ConstraintDual(), c1[]) ≈ [1.0] - c2 = MOI.get(bridged_mock, MOI.ListOfConstraintIndices{MOI.VectorAffineFunction{Float64}, MOI.Nonpositives}()) - @test length(c2) == 1 - @test MOI.get(bridged_mock, MOI.ConstraintPrimal(), c2[]) ≈ [-100.0] - @test MOI.get(bridged_mock, MOI.ConstraintDual(), c2[]) ≈ [1.0] - - loc = MOI.get(bridged_mock, 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 - - 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 "Scalar functionize" begin - MOI.empty!(mock) - bridged_mock = MOIB.ScalarFunctionize{Float64}(mock) - x = MOI.add_variable(bridged_mock) - y = MOI.add_variable(bridged_mock) - sx = MOI.SingleVariable(x) - sy = MOI.SingleVariable(y) - ci = MOI.add_constraint(bridged_mock, sx, MOI.GreaterThan(0.0)) - @test MOI.get(bridged_mock, MOI.ConstraintFunction(), ci) ≈ sx - MOI.set(bridged_mock, MOI.ConstraintFunction(), ci, sy) - @test MOI.get(bridged_mock, MOI.ConstraintFunction(), ci) ≈ sy - @test MOI.get(bridged_mock, MOI.ConstraintSet(), ci) == MOI.GreaterThan(0.0) - MOI.set(bridged_mock, MOI.ConstraintSet(), ci, MOI.GreaterThan(1.0)) - @test MOI.get(bridged_mock, MOI.ConstraintSet(), ci) == MOI.GreaterThan(1.0) - test_delete_bridge(bridged_mock, ci, 2, ((MOI.ScalarAffineFunction{Float64}, MOI.Interval{Float64}, 0),)) - - MOIT.basic_constraint_tests(bridged_mock, config, - include=[(F, S) for - F in [MOI.SingleVariable], - S in [MOI.GreaterThan{Float64}, - MOI.LessThan{Float64}] - ]) - - for T in [Int, Float64], S in [MOI.GreaterThan{T}, MOI.LessThan{T}] - @test MOIB.added_constraint_types(MOIB.ScalarFunctionizeBridge{T, S}) == - [(MOI.ScalarAffineFunction{T}, S)] - end - - - @testset "linear2" begin - MOI.empty!(bridged_mock) - MOIU.set_mock_optimize!(mock, - (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [1, 0], - (MOI.ScalarAffineFunction{Float64}, MOI.LessThan{Float64}) => [-1], - (MOI.ScalarAffineFunction{Float64}, MOI.GreaterThan{Float64}) => [0, 1], - con_basis = - [(MOI.ScalarAffineFunction{Float64}, MOI.LessThan{Float64}) => [MOI.NONBASIC], - (MOI.ScalarAffineFunction{Float64}, MOI.GreaterThan{Float64}) => [MOI.BASIC, MOI.NONBASIC]])) - MOIT.linear2test(bridged_mock, config_with_basis) - - for (i, ci) in enumerate(MOI.get( - bridged_mock, - MOI.ListOfConstraintIndices{MOI.SingleVariable, - MOI.GreaterThan{Float64}}())) - test_delete_bridge(bridged_mock, ci, 2, - ((MOI.ScalarAffineFunction{Float64}, - MOI.GreaterThan{Float64}, 0),), - num_bridged = 3 - i) - end - end - end - - @testset "Vector functionize" begin - MOI.empty!(mock) - bridged_mock = MOIB.VectorFunctionize{Float64}(mock) - x = MOI.add_variable(bridged_mock) - y = MOI.add_variable(bridged_mock) - z = MOI.add_variable(bridged_mock) - v1 = MOI.VectorOfVariables([x,y,z]) - v2 = MOI.VectorOfVariables([x,y,y]) - ci = MOI.add_constraint(bridged_mock, v1, MOI.PowerCone(0.1)) - @test MOI.get(bridged_mock, MOI.ConstraintFunction(), ci) ≈ v1 - MOI.set(bridged_mock, MOI.ConstraintFunction(), ci, v2) - @test MOI.get(bridged_mock, MOI.ConstraintFunction(), ci) ≈ v2 - @test MOI.get(bridged_mock, MOI.ConstraintSet(), ci) == MOI.PowerCone(0.1) - MOI.set(bridged_mock, MOI.ConstraintSet(), ci, MOI.PowerCone(0.2)) - @test MOI.get(bridged_mock, MOI.ConstraintSet(), ci) == MOI.PowerCone(0.2) - test_delete_bridge(bridged_mock, ci, 3, ((MOI.VectorAffineFunction{Float64}, MOI.Nonnegatives, 0),)) - - MOIT.basic_constraint_tests(bridged_mock, config, - include=[(F, S) for - F in [MOI.VectorOfVariables], - S in [MOI.Nonnegatives, - MOI.Nonpositives] - ]) - - for T in [Int, Float64], S in [MOI.Nonnegatives, MOI.Nonpositives] - @test MOIB.added_constraint_types(MOIB.VectorFunctionizeBridge{T, S}) == - [(MOI.VectorAffineFunction{T}, S)] - end - - @testset "lin1v" begin - mock.optimize! = (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!( - mock, [1.0, 0.0, 2.0], - (MOI.VectorAffineFunction{Float64}, MOI.Nonnegatives) => [[0, 2, 0]], - (MOI.VectorAffineFunction{Float64}, MOI.Zeros) => [[-3, -1]]) - MOIT.lin1vtest(bridged_mock, config) - ci = first(MOI.get( - bridged_mock, - MOI.ListOfConstraintIndices{MOI.VectorOfVariables, - MOI.Nonnegatives}())) - test_delete_bridge(bridged_mock, ci, 3, - ((MOI.VectorAffineFunction{Float64}, - MOI.Nonnegatives, 0),)) - end - 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], - (MOI.SingleVariable, MOI.EqualTo{Float64}) => [-√2, -1/√2], - (MOI.VectorAffineFunction{Float64}, MOI.SecondOrderCone) => [[3/2, 1/2, -1.0, -1.0]]) - MOIT.rotatedsoc1vtest(bridged_mock, config) - mock.optimize! = (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [1/√2, 1/√2], - (MOI.VectorAffineFunction{Float64}, MOI.SecondOrderCone) => [[3/2, 1/2, -1.0, -1.0]]) - MOIT.rotatedsoc1ftest(bridged_mock, config) - ci = first(MOI.get(bridged_mock, MOI.ListOfConstraintIndices{MOI.VectorAffineFunction{Float64}, MOI.RotatedSecondOrderCone}())) - test_delete_bridge(bridged_mock, ci, 2, ((MOI.VectorAffineFunction{Float64}, MOI.SecondOrderCone, 0),)) - end - - @testset "QuadtoSOC" begin - bridged_mock = MOIB.QuadtoSOC{Float64}(mock) - @testset "Error for non-convex quadratic constraints" begin - x = MOI.add_variable(bridged_mock) - @test_throws ErrorException begin - MOI.add_constraint(bridged_mock, - MOI.ScalarQuadraticFunction(MOI.ScalarAffineTerm{Float64}[], - [MOI.ScalarQuadraticTerm(1.0, x, x)], - 0.0), - MOI.GreaterThan(0.0)) - end - @test_throws ErrorException begin - MOI.add_constraint(bridged_mock, - MOI.ScalarQuadraticFunction(MOI.ScalarAffineTerm{Float64}[], - [MOI.ScalarQuadraticTerm(-1.0, x, x)], - 0.0), - MOI.LessThan(0.0)) - end - end - @testset "Quadratic constraints with 2 variables" begin - MOIU.set_mock_optimize!(mock, - (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, - MOI.OPTIMAL, - (MOI.FEASIBLE_POINT, [0.5, 0.5]) - ), - (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, - MOI.OPTIMAL, - (MOI.FEASIBLE_POINT, [0.5, (√13 - 1)/4]) - ) - ) - MOIT.solve_qcp_edge_cases(bridged_mock, config) - ci = first(MOI.get(mock, - MOI.ListOfConstraintIndices{MOI.VectorAffineFunction{Float64}, - MOI.RotatedSecondOrderCone}())) - x, y = MOI.get(mock, MOI.ListOfVariableIndices()) - # The matrix is - # 2 1 - # 1 2 - # for which the cholesky factorization is U' * U with U = - # √2 √2/2 - # . √3/√2 - expected = MOI.VectorAffineFunction{Float64}(MOI.VectorAffineTerm.([3, 3, 4], - MOI.ScalarAffineTerm.([√2, √2/2, √3/√2], - [x, y, y])), - [1.0, 1.0, 0.0, 0.0]) - @test MOI.get(mock, MOI.ConstraintFunction(), ci) ≈ expected - end - @testset "QCP tests" begin - MOIU.set_mock_optimize!(mock, - (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [1/2, 7/4], MOI.FEASIBLE_POINT)) - MOIT.qcp1test(bridged_mock, config) - MOIU.set_mock_optimize!(mock, - (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [√2], MOI.FEASIBLE_POINT)) - MOIT.qcp2test(bridged_mock, config) - MOIU.set_mock_optimize!(mock, - (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [√2], MOI.FEASIBLE_POINT)) - MOIT.qcp3test(bridged_mock, config) - @testset "Bridge deletion" begin - ci = first(MOI.get(bridged_mock, - MOI.ListOfConstraintIndices{MOI.ScalarQuadraticFunction{Float64}, - MOI.LessThan{Float64}}())) - test_delete_bridge(bridged_mock, ci, 1, ((MOI.VectorAffineFunction{Float64}, MOI.RotatedSecondOrderCone, 0),)) - end - end - end - - @testset "SquarePSD" begin - bridged_mock = MOIB.SquarePSD{Float64}(mock) - mock.optimize! = (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, ones(4), - (MOI.ScalarAffineFunction{Float64}, MOI.EqualTo{Float64}) => [2, 2]) - MOIT.psds0vtest(bridged_mock, config) - mock.optimize! = (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, ones(4), - (MOI.VectorAffineFunction{Float64}, MOI.PositiveSemidefiniteConeTriangle) => [[1, -1, 1]], - (MOI.ScalarAffineFunction{Float64}, MOI.EqualTo{Float64}) => [2, 2]) - MOIT.psds0ftest(bridged_mock, config) - ci = first(MOI.get(bridged_mock, - MOI.ListOfConstraintIndices{MOI.VectorAffineFunction{Float64}, - MOI.PositiveSemidefiniteConeSquare}())) - test_delete_bridge(bridged_mock, ci, 4, - ((MOI.VectorAffineFunction{Float64}, - MOI.PositiveSemidefiniteConeTriangle, 0), - (MOI.ScalarAffineFunction{Float64}, - MOI.EqualTo{Float64}, 1))) - end - - @testset "GeoMean" begin - mock.optimize! = (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [ones(4); 2; √2; √2]) - bridged_mock = MOIB.GeoMean{Float64}(mock) - MOIT.geomean1vtest(bridged_mock, config) - MOIT.geomean1ftest(bridged_mock, config) - # Dual is not yet implemented for GeoMean bridge - ci = first(MOI.get(bridged_mock, MOI.ListOfConstraintIndices{MOI.VectorAffineFunction{Float64}, MOI.GeometricMeanCone}())) - test_delete_bridge(bridged_mock, ci, 4, ((MOI.VectorAffineFunction{Float64}, MOI.RotatedSecondOrderCone, 0), - (MOI.ScalarAffineFunction{Float64}, MOI.LessThan{Float64}, 1))) - end - - @testset "SOCtoPSD" begin - bridged_mock = MOIB.SOCtoPSD{Float64}(mock) - mock.optimize! = (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [1.0, 1/√2, 1/√2], - (MOI.VectorAffineFunction{Float64}, MOI.PositiveSemidefiniteConeTriangle) => [[√2/2, -1/2, √2/4, -1/2, √2/4, √2/4]], - (MOI.VectorAffineFunction{Float64}, MOI.Zeros) => [[-√2]]) - MOIT.soc1vtest(bridged_mock, config) - MOIT.soc1ftest(bridged_mock, config) - ci = first(MOI.get(bridged_mock, MOI.ListOfConstraintIndices{MOI.VectorAffineFunction{Float64}, MOI.SecondOrderCone}())) - test_delete_bridge(bridged_mock, ci, 3, ((MOI.VectorAffineFunction{Float64}, MOI.PositiveSemidefiniteConeTriangle, 0),)) - end - - @testset "RSOCtoPSD" begin - bridged_mock = MOIB.RSOCtoPSD{Float64}(mock) - mock.optimize! = (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [1/√2, 1/√2, 0.5, 1.0], - (MOI.SingleVariable, MOI.EqualTo{Float64}) => [-√2, -1/√2], - (MOI.VectorAffineFunction{Float64}, MOI.PositiveSemidefiniteConeTriangle) => [[√2, -1/2, √2/8, -1/2, √2/8, √2/8]]) - MOIT.rotatedsoc1vtest(bridged_mock, config) - mock.optimize! = (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [1/√2, 1/√2], - (MOI.VectorAffineFunction{Float64}, MOI.PositiveSemidefiniteConeTriangle) => [[√2, -1/2, √2/8, -1/2, √2/8, √2/8]]) - MOIT.rotatedsoc1ftest(bridged_mock, config) - ci = first(MOI.get(bridged_mock, MOI.ListOfConstraintIndices{MOI.VectorAffineFunction{Float64}, MOI.RotatedSecondOrderCone}())) - test_delete_bridge(bridged_mock, ci, 2, ((MOI.VectorAffineFunction{Float64}, MOI.PositiveSemidefiniteConeTriangle, 0),)) - end - - @testset "LogDet" begin - bridged_mock = MOIB.LogDet{Float64}(mock) - mock.optimize! = (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [0, 1, 0, 1, 1, 0, 1, 0, 0, 1]) - MOIT.logdett1vtest(bridged_mock, config) - MOIT.logdett1ftest(bridged_mock, config) - # Dual is not yet implemented for LogDet bridge - ci = first(MOI.get(bridged_mock, MOI.ListOfConstraintIndices{MOI.VectorAffineFunction{Float64}, MOI.LogDetConeTriangle}())) - test_delete_bridge(bridged_mock, ci, 5, ((MOI.VectorAffineFunction{Float64}, MOI.ExponentialCone, 0), (MOI.VectorAffineFunction{Float64}, MOI.PositiveSemidefiniteConeTriangle, 0))) - end - - @testset "RootDet" begin - bridged_mock = MOIB.RootDet{Float64}(mock) - mock.optimize! = (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, [1, 1, 0, 1, 1, 0, 1]) - MOIT.rootdett1vtest(bridged_mock, config) - MOIT.rootdett1ftest(bridged_mock, config) - # Dual is not yet implemented for RootDet bridge - ci = first(MOI.get(bridged_mock, MOI.ListOfConstraintIndices{MOI.VectorAffineFunction{Float64}, MOI.RootDetConeTriangle}())) - test_delete_bridge(bridged_mock, ci, 4, ((MOI.VectorAffineFunction{Float64}, MOI.RotatedSecondOrderCone, 0), - (MOI.VectorAffineFunction{Float64}, MOI.GeometricMeanCone, 0), - (MOI.VectorAffineFunction{Float64}, MOI.PositiveSemidefiniteConeTriangle, 0))) - end -end diff --git a/test/runtests.jl b/test/runtests.jl index 20430f38d5..13b56ac18f 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -29,18 +29,12 @@ end # Test submodule tests # It tests that the ConstraintPrimal value requested in the tests is consistent with the VariablePrimal @testset "MOI.Test" begin - include("Test/config.jl") - include("Test/unit.jl") - include("Test/contlinear.jl") - include("Test/contconic.jl") - include("Test/contquadratic.jl") - include("Test/intlinear.jl") - include("Test/intconic.jl") + include("Test/Test.jl") end @testset "MOI.Bridges" begin # Bridges submodule tests - include("bridge.jl") + include("Bridges/Bridges.jl") end # Test hygiene of @model macro