diff --git a/src/Test/test_conic.jl b/src/Test/test_conic.jl index b2dca3f3da..b9577ce026 100644 --- a/src/Test/test_conic.jl +++ b/src/Test/test_conic.jl @@ -5770,6 +5770,95 @@ 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} + @requires MOI.supports_incremental_interface(model) + @requires _supports(config, MOI.optimize!) + @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(one(T) .* x) - sum(one(T) .* y), + MOI.EqualTo(zero(T)), + ) + 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) + @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 + +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, + 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)], + (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,