diff --git a/src/Test/UnitTests/objectives.jl b/src/Test/UnitTests/objectives.jl index 79b6482746..25efa92939 100644 --- a/src/Test/UnitTests/objectives.jl +++ b/src/Test/UnitTests/objectives.jl @@ -155,51 +155,95 @@ function solve_qp_edge_cases(model::MOI.ModelLike, config::TestConfig) MOI.addconstraint!(model, MOI.SingleVariable(x[1]), MOI.GreaterThan(1.0)) MOI.addconstraint!(model, MOI.SingleVariable(x[2]), MOI.GreaterThan(2.0)) - # min x^2 + y^2 | x>=1, y>=2 - MOI.set!(model, - MOI.ObjectiveFunction{MOI.ScalarQuadraticFunction{Float64}}(), - MOI.ScalarQuadraticFunction( - MOI.ScalarAffineTerm{Float64}[], # affine terms - MOI.ScalarQuadraticTerm.([2.0, 2.0], x, x), # quad - 0.0 # constant + @testset "Basic model" begin + # min x^2 + y^2 | x>=1, y>=2 + MOI.set!(model, + MOI.ObjectiveFunction{MOI.ScalarQuadraticFunction{Float64}}(), + MOI.ScalarQuadraticFunction( + MOI.ScalarAffineTerm{Float64}[], # affine terms + MOI.ScalarQuadraticTerm.([2.0, 2.0], x, x), # quad + 0.0 # constant + ) ) - ) - test_model_solution(model, config; - objective_value = 5.0, - variable_primal = [(x[1], 1.0), (x[2], 2.0)] - ) - - # duplicate terms on diagonal - # min x^2 + x^2 | x>=1, y>=2 - MOI.set!(model, - MOI.ObjectiveFunction{MOI.ScalarQuadraticFunction{Float64}}(), - MOI.ScalarQuadraticFunction( - MOI.ScalarAffineTerm{Float64}[], # affine terms - MOI.ScalarQuadraticTerm.([2.0, 2.0], [x[1], x[1]], [x[1], x[1]]), # quad - 0.0 # constant + test_model_solution(model, config; + objective_value = 5.0, + variable_primal = [(x[1], 1.0), (x[2], 2.0)] ) - ) - test_model_solution(model, config; - objective_value = 2.0, - variable_primal = [(x[1], 1.0)] - ) + end + @testset "Duplicate linear terms" begin + # min x + x + x^2 + y^2 | x>=1, y>=2 + MOI.set!(model, + MOI.ObjectiveFunction{MOI.ScalarQuadraticFunction{Float64}}(), + MOI.ScalarQuadraticFunction( + MOI.ScalarAffineTerm.([1.0, 1.0], [x[1], x[1]]), # affine terms + MOI.ScalarQuadraticTerm.([2.0, 2.0], x, x), # quad + 0.0 # constant + ) + ) + test_model_solution(model, config; + objective_value = 7.0, + variable_primal = [(x[1], 1.0), (x[2], 2.0)] + ) + end + @testset "Duplicate diagonal terms" begin + # min x^2 + x^2 | x>=1, y>=2 + MOI.set!(model, + MOI.ObjectiveFunction{MOI.ScalarQuadraticFunction{Float64}}(), + MOI.ScalarQuadraticFunction( + MOI.ScalarAffineTerm{Float64}[], # affine terms + MOI.ScalarQuadraticTerm.([2.0, 2.0], [x[1], x[1]], [x[1], x[1]]), # quad + 0.0 # constant + ) + ) + test_model_solution(model, config; + objective_value = 2.0, + variable_primal = [(x[1], 1.0)] + ) + end + @testset "Duplicate off-diagonal terms" begin + # min x^2 + 0.25x*y + 0.25y*x + 0.5x*y + y^2 | x>=1, y>=2 + MOI.set!(model, + MOI.ObjectiveFunction{MOI.ScalarQuadraticFunction{Float64}}(), + MOI.ScalarQuadraticFunction( + MOI.ScalarAffineTerm{Float64}[], # affine terms + MOI.ScalarQuadraticTerm.( + [ 2.0, 0.25, 0.25, 0.5, 2.0], + [x[1], x[1], x[2], x[1], x[2]], + [x[1], x[2], x[1], x[2], x[2]]), # quad + 0.0 # constant + ) + ) + test_model_solution(model, config; + objective_value = 7.0, + variable_primal = [(x[1], 1.0), (x[2], 2.0)] + ) + end +end +unittests["solve_qp_edge_cases"] = solve_qp_edge_cases + +""" + solve_duplicate_terms_obj(model::MOI.ModelLike, config::TestConfig) - # duplicate terms on off-diagonal - # min x^2 + 0.25x*y + 0.25y*x + 0.5x*y + y^2 | x>=1, y>=2 - MOI.set!(model, - MOI.ObjectiveFunction{MOI.ScalarQuadraticFunction{Float64}}(), - MOI.ScalarQuadraticFunction( - MOI.ScalarAffineTerm{Float64}[], # affine terms - MOI.ScalarQuadraticTerm.( - [ 2.0, 0.25, 0.25, 0.5, 2.0], - [x[1], x[1], x[2], x[1], x[2]], - [x[1], x[2], x[1], x[2], x[2]]), # quad - 0.0 # constant +Test duplicate terms in linear objective, if `config.solve=true` confirm that it +solves correctly. +""" +function solve_duplicate_terms_obj(model::MOI.ModelLike, config::TestConfig) + MOI.empty!(model) + @test MOI.isempty(model) + x = MOI.addvariable!(model) + c = MOI.addconstraint!(model, MOI.SingleVariable(x), MOI.GreaterThan(1.0)) + MOI.set!(model, MOI.ObjectiveSense(), MOI.MinSense) + MOI.set!(model, MOI.ObjectiveFunction{MOI.ScalarAffineFunction{Float64}}(), + MOI.ScalarAffineFunction( + [MOI.ScalarAffineTerm(2.0, x), MOI.ScalarAffineTerm(1.0, x)], + 0.0 ) ) test_model_solution(model, config; - objective_value = 7.0, - variable_primal = [(x[1], 1.0), (x[2], 2.0)] + objective_value = 3.0, + variable_primal = [(x, 1.0)], + constraint_primal = [(c, 1.0)], + constraint_dual = [(c, 3.0)] ) end -unittests["solve_qp_edge_cases"] = solve_qp_edge_cases +unittests["solve_duplicate_terms_obj"] = solve_duplicate_terms_obj diff --git a/test/Test/unit.jl b/test/Test/unit.jl index e867584220..13da12640a 100644 --- a/test/Test/unit.jl +++ b/test/Test/unit.jl @@ -19,7 +19,8 @@ end "solve_affine_interval", "solve_qp_edge_cases", "solve_qcp_edge_cases", - "solve_affine_deletion_edge_cases" + "solve_affine_deletion_edge_cases", + "solve_duplicate_terms_obj" ]) @testset "solve_blank_obj" begin @@ -148,6 +149,10 @@ end MOI.Success, (MOI.FeasiblePoint, [1.0, 2.0]) ), + (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, + MOI.Success, + (MOI.FeasiblePoint, [1.0, 2.0]) + ), (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, MOI.Success, (MOI.FeasiblePoint, [1.0, 2.0]) @@ -155,7 +160,17 @@ end ) MOIT.solve_qp_edge_cases(mock, config) end - + @testset "solve_duplicate_terms_obj" begin + MOIU.set_mock_optimize!(mock, + (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock, + MOI.Success, + (MOI.FeasiblePoint, [1]), + MOI.FeasiblePoint, + (MOI.SingleVariable, MOI.GreaterThan{Float64}) => [3.0] + ) + ) + MOIT.solve_duplicate_terms_obj(mock, config) + end @testset "solve_affine_deletion_edge_cases" begin MOIU.set_mock_optimize!(mock, (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!(mock,