From 58afc1358f8622d0fc294b82a6d1255415c5ca53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Legat?= Date: Tue, 17 Dec 2024 12:31:25 +0100 Subject: [PATCH 1/7] Add test with multiple PSD variable on same constraint --- src/Test/test_conic.jl | 72 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) diff --git a/src/Test/test_conic.jl b/src/Test/test_conic.jl index b2dca3f3da..9e4d1684ae 100644 --- a/src/Test/test_conic.jl +++ b/src/Test/test_conic.jl @@ -5770,6 +5770,78 @@ function setup_test( return end +function test_conic_PositiveSemidefiniteConeTriangle_4( + model::MOI.ModelLike, + config::Config{T}, +) where {T<:Real} + atol = config.atol + rtol = config.rtol + @requires MOI.supports_incremental_interface(model) + @requires MOI.supports(model, MOI.ObjectiveFunction{MOI.ScalarAffineFunction{T}}()) + @requires MOI.supports(model, MOI.ObjectiveSense()) + @requires MOI.supports_constraint( + model, + MOI.VectorOfVariables, + MOI.PositiveSemidefiniteConeTriangle, + ) + @requires MOI.supports_constraint( + model, + MOI.ScalarAffineFunction{T}, + MOI.EqualTo{T}, + ) + @requires MOI.supports_constraint( + model, + MOI.ScalarAffineFunction{T}, + MOI.GreaterThan{T}, + ) + + x, cx = MOI.add_constrained_variables(model, MOI.PositiveSemidefiniteConeTriangle(2)) + y, cy = MOI.add_constrained_variables(model, MOI.PositiveSemidefiniteConeTriangle(2)) + c1 = MOI.add_constraint(model, sum(1.0 .* x) - sum(1.0 .* y), MOI.EqualTo(0.0)) + c2 = MOI.add_constraint(model, 1.0 * y[1] + 1.0 * y[3], MOI.GreaterThan(1.0)) + obj = 1.0 * x[1] + 1.0 * x[3] + MOI.set(model, MOI.ObjectiveSense(), MOI.MIN_SENSE) + MOI.set(model, MOI.ObjectiveFunction{typeof(obj)}(), obj) + if _supports(config, MOI.optimize!) + @test MOI.get(model, MOI.TerminationStatus()) == MOI.OPTIMIZE_NOT_CALLED + MOI.optimize!(model) + @test MOI.get(model, MOI.TerminationStatus()) == config.optimal_status + @test MOI.get(model, MOI.PrimalStatus()) == MOI.FEASIBLE_POINT + if _supports(config, MOI.ConstraintDual) + @test MOI.get(model, MOI.DualStatus()) == MOI.FEASIBLE_POINT + end + @test MOI.get.(model, MOI.VariablePrimal(), x) ≈ ones(3) ./ T(6) atol = atol rtol = rtol + @test MOI.get.(model, MOI.VariablePrimal(), y) ≈ [1, -1, 1] ./ T(2) atol = atol rtol = rtol + if _supports(config, MOI.ConstraintDual) + @test MOI.get(model, MOI.ConstraintDual(), cx) ≈ [1, -1, 1] ./ T(3) atol = atol rtol = rtol + @test MOI.get(model, MOI.ConstraintDual(), cy) ≈ ones(3) ./ T(3) atol = atol rtol = rtol + @test MOI.get(model, MOI.ConstraintDual(), c1) ≈ T(2)/T(3) atol = atol rtol = rtol + @test MOI.get(model, MOI.ConstraintDual(), c2) ≈ T(1)/T(3) atol = atol rtol = rtol + end + end + return +end + +# Test with multiple PSD variable on the same constraint in order to catch +# https://github.com/jump-dev/MosekTools.jl/issues/139 +function setup_test( + ::typeof(test_conic_PositiveSemidefiniteConeTriangle_4), + model::MOIU.MockOptimizer, + ::Config{T}, +) where {T<:Real} + MOIU.set_mock_optimize!( + model, + (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!( + mock, + [[1, 1, 1] / T(6); [1, -1, 1] / T(2)], + (MOI.VectorOfVariables, MOI.PositiveSemidefiniteConeTriangle) => [[1, -1, 1] ./ T(3), ones(3) ./ T(3)], + (MOI.ScalarAffineFunction{T}, MOI.EqualTo{T}) => [T(2)/T(3)], + (MOI.ScalarAffineFunction{T}, MOI.GreaterThan{T}) => [T(1)/T(3)], + ), + ) + return +end + """ _test_det_cone_helper_ellipsoid( model::MOI.ModelLike, From ec2b976c9f49143c881a5a7a29859e46d93ec3b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Legat?= Date: Tue, 17 Dec 2024 12:40:23 +0100 Subject: [PATCH 2/7] Fix format --- src/Test/test_conic.jl | 50 ++++++++++++++++++++++++++++++------------ 1 file changed, 36 insertions(+), 14 deletions(-) diff --git a/src/Test/test_conic.jl b/src/Test/test_conic.jl index 9e4d1684ae..11730d41e6 100644 --- a/src/Test/test_conic.jl +++ b/src/Test/test_conic.jl @@ -5777,7 +5777,10 @@ function test_conic_PositiveSemidefiniteConeTriangle_4( atol = config.atol rtol = config.rtol @requires MOI.supports_incremental_interface(model) - @requires MOI.supports(model, MOI.ObjectiveFunction{MOI.ScalarAffineFunction{T}}()) + @requires MOI.supports( + model, + MOI.ObjectiveFunction{MOI.ScalarAffineFunction{T}}(), + ) @requires MOI.supports(model, MOI.ObjectiveSense()) @requires MOI.supports_constraint( model, @@ -5795,10 +5798,21 @@ function test_conic_PositiveSemidefiniteConeTriangle_4( MOI.GreaterThan{T}, ) - x, cx = MOI.add_constrained_variables(model, MOI.PositiveSemidefiniteConeTriangle(2)) - y, cy = MOI.add_constrained_variables(model, MOI.PositiveSemidefiniteConeTriangle(2)) - c1 = MOI.add_constraint(model, sum(1.0 .* x) - sum(1.0 .* y), MOI.EqualTo(0.0)) - c2 = MOI.add_constraint(model, 1.0 * y[1] + 1.0 * y[3], MOI.GreaterThan(1.0)) + x, cx = MOI.add_constrained_variables( + model, + MOI.PositiveSemidefiniteConeTriangle(2), + ) + y, cy = MOI.add_constrained_variables( + model, + MOI.PositiveSemidefiniteConeTriangle(2), + ) + c1 = MOI.add_constraint( + model, + sum(1.0 .* x) - sum(1.0 .* y), + MOI.EqualTo(0.0), + ) + c2 = + MOI.add_constraint(model, 1.0 * y[1] + 1.0 * y[3], MOI.GreaterThan(1.0)) obj = 1.0 * x[1] + 1.0 * x[3] MOI.set(model, MOI.ObjectiveSense(), MOI.MIN_SENSE) MOI.set(model, MOI.ObjectiveFunction{typeof(obj)}(), obj) @@ -5810,13 +5824,19 @@ function test_conic_PositiveSemidefiniteConeTriangle_4( if _supports(config, MOI.ConstraintDual) @test MOI.get(model, MOI.DualStatus()) == MOI.FEASIBLE_POINT end - @test MOI.get.(model, MOI.VariablePrimal(), x) ≈ ones(3) ./ T(6) atol = atol rtol = rtol - @test MOI.get.(model, MOI.VariablePrimal(), y) ≈ [1, -1, 1] ./ T(2) atol = atol rtol = rtol + @test MOI.get.(model, MOI.VariablePrimal(), x) ≈ ones(3) ./ T(6) atol = + atol rtol = rtol + @test MOI.get.(model, MOI.VariablePrimal(), y) ≈ [1, -1, 1] ./ T(2) atol = + atol rtol = rtol if _supports(config, MOI.ConstraintDual) - @test MOI.get(model, MOI.ConstraintDual(), cx) ≈ [1, -1, 1] ./ T(3) atol = atol rtol = rtol - @test MOI.get(model, MOI.ConstraintDual(), cy) ≈ ones(3) ./ T(3) atol = atol rtol = rtol - @test MOI.get(model, MOI.ConstraintDual(), c1) ≈ T(2)/T(3) atol = atol rtol = rtol - @test MOI.get(model, MOI.ConstraintDual(), c2) ≈ T(1)/T(3) atol = atol rtol = rtol + @test MOI.get(model, MOI.ConstraintDual(), cx) ≈ [1, -1, 1] ./ T(3) atol = + atol rtol = rtol + @test MOI.get(model, MOI.ConstraintDual(), cy) ≈ ones(3) ./ T(3) atol = + atol rtol = rtol + @test MOI.get(model, MOI.ConstraintDual(), c1) ≈ T(2) / T(3) atol = + atol rtol = rtol + @test MOI.get(model, MOI.ConstraintDual(), c2) ≈ T(1) / T(3) atol = + atol rtol = rtol end end return @@ -5834,9 +5854,11 @@ function setup_test( (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!( mock, [[1, 1, 1] / T(6); [1, -1, 1] / T(2)], - (MOI.VectorOfVariables, MOI.PositiveSemidefiniteConeTriangle) => [[1, -1, 1] ./ T(3), ones(3) ./ T(3)], - (MOI.ScalarAffineFunction{T}, MOI.EqualTo{T}) => [T(2)/T(3)], - (MOI.ScalarAffineFunction{T}, MOI.GreaterThan{T}) => [T(1)/T(3)], + (MOI.VectorOfVariables, MOI.PositiveSemidefiniteConeTriangle) => + [[1, -1, 1] ./ T(3), ones(3) ./ T(3)], + (MOI.ScalarAffineFunction{T}, MOI.EqualTo{T}) => [T(2) / T(3)], + (MOI.ScalarAffineFunction{T}, MOI.GreaterThan{T}) => + [T(1) / T(3)], ), ) return From ee07c24d544053e4f87812af65fa86788c71bf4d Mon Sep 17 00:00:00 2001 From: Oscar Dowson Date: Wed, 18 Dec 2024 13:49:52 +1300 Subject: [PATCH 3/7] Update test_conic.jl --- src/Test/test_conic.jl | 63 +++++++++++++++++++----------------------- 1 file changed, 29 insertions(+), 34 deletions(-) diff --git a/src/Test/test_conic.jl b/src/Test/test_conic.jl index 11730d41e6..596ffa9bc2 100644 --- a/src/Test/test_conic.jl +++ b/src/Test/test_conic.jl @@ -5770,13 +5770,14 @@ function setup_test( return end +# Test with multiple PSD variable on the same constraint in order to catch +# https://github.com/jump-dev/MosekTools.jl/issues/139 function test_conic_PositiveSemidefiniteConeTriangle_4( model::MOI.ModelLike, config::Config{T}, ) where {T<:Real} - atol = config.atol - rtol = config.rtol @requires MOI.supports_incremental_interface(model) + @requires _supports(config, MOI.optimize!) @requires MOI.supports( model, MOI.ObjectiveFunction{MOI.ScalarAffineFunction{T}}(), @@ -5797,7 +5798,6 @@ function test_conic_PositiveSemidefiniteConeTriangle_4( MOI.ScalarAffineFunction{T}, MOI.GreaterThan{T}, ) - x, cx = MOI.add_constrained_variables( model, MOI.PositiveSemidefiniteConeTriangle(2), @@ -5808,42 +5808,37 @@ function test_conic_PositiveSemidefiniteConeTriangle_4( ) c1 = MOI.add_constraint( model, - sum(1.0 .* x) - sum(1.0 .* y), - MOI.EqualTo(0.0), + sum(one(T) .* x) - sum(one(T) .* y), + MOI.EqualTo(zero(T)), ) - c2 = - MOI.add_constraint(model, 1.0 * y[1] + 1.0 * y[3], MOI.GreaterThan(1.0)) - obj = 1.0 * x[1] + 1.0 * x[3] + c2 = MOI.add_constraint( + model, + one(T) * y[1] + one(T) * y[3], + MOI.GreaterThan(one(T)), + ) + obj = one(T) * x[1] + one(T) * x[3] MOI.set(model, MOI.ObjectiveSense(), MOI.MIN_SENSE) MOI.set(model, MOI.ObjectiveFunction{typeof(obj)}(), obj) - if _supports(config, MOI.optimize!) - @test MOI.get(model, MOI.TerminationStatus()) == MOI.OPTIMIZE_NOT_CALLED - MOI.optimize!(model) - @test MOI.get(model, MOI.TerminationStatus()) == config.optimal_status - @test MOI.get(model, MOI.PrimalStatus()) == MOI.FEASIBLE_POINT - if _supports(config, MOI.ConstraintDual) - @test MOI.get(model, MOI.DualStatus()) == MOI.FEASIBLE_POINT - end - @test MOI.get.(model, MOI.VariablePrimal(), x) ≈ ones(3) ./ T(6) atol = - atol rtol = rtol - @test MOI.get.(model, MOI.VariablePrimal(), y) ≈ [1, -1, 1] ./ T(2) atol = - atol rtol = rtol - if _supports(config, MOI.ConstraintDual) - @test MOI.get(model, MOI.ConstraintDual(), cx) ≈ [1, -1, 1] ./ T(3) atol = - atol rtol = rtol - @test MOI.get(model, MOI.ConstraintDual(), cy) ≈ ones(3) ./ T(3) atol = - atol rtol = rtol - @test MOI.get(model, MOI.ConstraintDual(), c1) ≈ T(2) / T(3) atol = - atol rtol = rtol - @test MOI.get(model, MOI.ConstraintDual(), c2) ≈ T(1) / T(3) atol = - atol rtol = rtol - end + @test MOI.get(model, MOI.TerminationStatus()) == MOI.OPTIMIZE_NOT_CALLED + MOI.optimize!(model) + @test MOI.get(model, MOI.TerminationStatus()) == config.optimal_status + @test MOI.get(model, MOI.PrimalStatus()) == MOI.FEASIBLE_POINT + x_primal = MOI.get.(model, MOI.VariablePrimal(), x) + @test ≈(x_primal, ones(T, 3) ./ T(6), config) + y_primal = MOI.get.(model, MOI.VariablePrimal(), y) + @test ≈(y_primal, T[1, -1, 1] ./ T(2) config) + if _supports(config, MOI.ConstraintDual) + @test MOI.get(model, MOI.DualStatus()) == MOI.FEASIBLE_POINT + x_dual = MOI.get(model, MOI.ConstraintDual(), cx) + @test ≈(x_dual, [1, -1, 1] ./ T(3) config) + y_dual = MOI.get(model, MOI.ConstraintDual(), cy) + @test ≈(y_dual, ones(T, 3) ./ T(3) config) + @test ≈(MOI.get(model, MOI.ConstraintDual(), c1), T(2) / T(3) config) + @test ≈(MOI.get(model, MOI.ConstraintDual(), c2), T(1) / T(3), config) end return end -# Test with multiple PSD variable on the same constraint in order to catch -# https://github.com/jump-dev/MosekTools.jl/issues/139 function setup_test( ::typeof(test_conic_PositiveSemidefiniteConeTriangle_4), model::MOIU.MockOptimizer, @@ -5853,9 +5848,9 @@ function setup_test( model, (mock::MOIU.MockOptimizer) -> MOIU.mock_optimize!( mock, - [[1, 1, 1] / T(6); [1, -1, 1] / T(2)], + T[[1, 1, 1] / T(6); [1, -1, 1] / T(2)], (MOI.VectorOfVariables, MOI.PositiveSemidefiniteConeTriangle) => - [[1, -1, 1] ./ T(3), ones(3) ./ T(3)], + T[[1, -1, 1] ./ T(3), ones(T, 3) ./ T(3)], (MOI.ScalarAffineFunction{T}, MOI.EqualTo{T}) => [T(2) / T(3)], (MOI.ScalarAffineFunction{T}, MOI.GreaterThan{T}) => [T(1) / T(3)], From 56c3f99d365a64dfa34b890515981cd0037ad7cb Mon Sep 17 00:00:00 2001 From: Oscar Dowson Date: Thu, 19 Dec 2024 11:48:21 +1300 Subject: [PATCH 4/7] Apply suggestions from code review --- src/Test/test_conic.jl | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Test/test_conic.jl b/src/Test/test_conic.jl index 596ffa9bc2..34449f8601 100644 --- a/src/Test/test_conic.jl +++ b/src/Test/test_conic.jl @@ -5826,14 +5826,14 @@ function test_conic_PositiveSemidefiniteConeTriangle_4( x_primal = MOI.get.(model, MOI.VariablePrimal(), x) @test ≈(x_primal, ones(T, 3) ./ T(6), config) y_primal = MOI.get.(model, MOI.VariablePrimal(), y) - @test ≈(y_primal, T[1, -1, 1] ./ T(2) config) + @test ≈(y_primal, T[1, -1, 1] ./ T(2), config) if _supports(config, MOI.ConstraintDual) @test MOI.get(model, MOI.DualStatus()) == MOI.FEASIBLE_POINT x_dual = MOI.get(model, MOI.ConstraintDual(), cx) - @test ≈(x_dual, [1, -1, 1] ./ T(3) config) + @test ≈(x_dual, [1, -1, 1] ./ T(3), config) y_dual = MOI.get(model, MOI.ConstraintDual(), cy) - @test ≈(y_dual, ones(T, 3) ./ T(3) config) - @test ≈(MOI.get(model, MOI.ConstraintDual(), c1), T(2) / T(3) config) + @test ≈(y_dual, ones(T, 3) ./ T(3), config) + @test ≈(MOI.get(model, MOI.ConstraintDual(), c1), T(2) / T(3), config) @test ≈(MOI.get(model, MOI.ConstraintDual(), c2), T(1) / T(3), config) end return From b87988dcfa23333deda2ac34e63076c2b72d6b93 Mon Sep 17 00:00:00 2001 From: Oscar Dowson Date: Thu, 19 Dec 2024 11:56:10 +1300 Subject: [PATCH 5/7] Update src/Test/test_conic.jl --- src/Test/test_conic.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Test/test_conic.jl b/src/Test/test_conic.jl index 34449f8601..b6b8084763 100644 --- a/src/Test/test_conic.jl +++ b/src/Test/test_conic.jl @@ -5850,7 +5850,7 @@ function setup_test( mock, T[[1, 1, 1] / T(6); [1, -1, 1] / T(2)], (MOI.VectorOfVariables, MOI.PositiveSemidefiniteConeTriangle) => - T[[1, -1, 1] ./ T(3), ones(T, 3) ./ T(3)], + T[[1, -1, 1]./T(3), ones(T, 3)./T(3)], (MOI.ScalarAffineFunction{T}, MOI.EqualTo{T}) => [T(2) / T(3)], (MOI.ScalarAffineFunction{T}, MOI.GreaterThan{T}) => [T(1) / T(3)], From 560bbffef31a72e2932ba4cd5c61225a447a1d2f Mon Sep 17 00:00:00 2001 From: Oscar Dowson Date: Thu, 19 Dec 2024 14:27:10 +1300 Subject: [PATCH 6/7] Update src/Test/test_conic.jl --- src/Test/test_conic.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Test/test_conic.jl b/src/Test/test_conic.jl index b6b8084763..9697e1dc7e 100644 --- a/src/Test/test_conic.jl +++ b/src/Test/test_conic.jl @@ -5850,7 +5850,7 @@ function setup_test( mock, T[[1, 1, 1] / T(6); [1, -1, 1] / T(2)], (MOI.VectorOfVariables, MOI.PositiveSemidefiniteConeTriangle) => - T[[1, -1, 1]./T(3), ones(T, 3)./T(3)], + [[1, -1, 1]./T(3), ones(T, 3)./T(3)], (MOI.ScalarAffineFunction{T}, MOI.EqualTo{T}) => [T(2) / T(3)], (MOI.ScalarAffineFunction{T}, MOI.GreaterThan{T}) => [T(1) / T(3)], From 76983dd8f6e13504ff321ffe8a441fb0586c4175 Mon Sep 17 00:00:00 2001 From: Oscar Dowson Date: Thu, 19 Dec 2024 14:34:09 +1300 Subject: [PATCH 7/7] Update src/Test/test_conic.jl --- src/Test/test_conic.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Test/test_conic.jl b/src/Test/test_conic.jl index 9697e1dc7e..b9577ce026 100644 --- a/src/Test/test_conic.jl +++ b/src/Test/test_conic.jl @@ -5850,7 +5850,7 @@ function setup_test( mock, T[[1, 1, 1] / T(6); [1, -1, 1] / T(2)], (MOI.VectorOfVariables, MOI.PositiveSemidefiniteConeTriangle) => - [[1, -1, 1]./T(3), ones(T, 3)./T(3)], + [[1, -1, 1] ./ T(3), ones(T, 3) ./ T(3)], (MOI.ScalarAffineFunction{T}, MOI.EqualTo{T}) => [T(2) / T(3)], (MOI.ScalarAffineFunction{T}, MOI.GreaterThan{T}) => [T(1) / T(3)],