From e922e555c57cbd585762f0f0ea54446639ea8c3d Mon Sep 17 00:00:00 2001 From: odow Date: Mon, 22 May 2023 09:58:37 +1200 Subject: [PATCH 1/3] Fix support for matrix in HermitianPSDCone --- src/sd.jl | 17 +++++++++++++++++ test/test_complex.jl | 37 +++++++++++++++++++++++++++++++++++-- 2 files changed, 52 insertions(+), 2 deletions(-) diff --git a/src/sd.jl b/src/sd.jl index 7cc1f00531f..192badba7aa 100644 --- a/src/sd.jl +++ b/src/sd.jl @@ -679,6 +679,23 @@ function build_constraint( ) end +function build_constraint( + _error::Function, + Q::AbstractMatrix{<:AbstractJuMPScalar}, + cone::HermitianPSDCone, +) + if !LinearAlgebra.ishermitian(Q) + _error( + "Unable to add matrix in HermitianPSDCone because the matrix is " * + "not Hermitian. If this error was unexpected, check the matrix " * + "for errors, or wrap the matrix `H` in " * + "`LinearAlgebra.Hermitian(H)` to force JuMP to treat the " * + "matrix as Hermitian.", + ) + end + return build_constraint(_error, LinearAlgebra.Hermitian(Q), cone) +end + function build_constraint(_error::Function, H::LinearAlgebra.Hermitian, ::Zeros) n = LinearAlgebra.checksquare(H) shape = HermitianMatrixShape(n) diff --git a/test/test_complex.jl b/test/test_complex.jl index 17f2b9e9560..3c9a17abf4e 100644 --- a/test/test_complex.jl +++ b/test/test_complex.jl @@ -14,10 +14,10 @@ using JuMP using Test import LinearAlgebra -import MutableArithmetics +import MutableArithmetics as MA import SparseArrays -const MA = MutableArithmetics +include(joinpath(@__DIR__, "utilities.jl")) function _test_dot(a, b) @test LinearAlgebra.dot(a, b) == conj(a) * b @@ -273,4 +273,37 @@ function test_isreal() return end +function test_numerically_hermitian_matrix() + model = Model() + @variable(model, X[1:2, 1:2] in HermitianPSDCone()) + @variable(model, t) + Y = X + LinearAlgebra.I(2) * t + @test LinearAlgebra.ishermitian(Y) + @test !(Y isa LinearAlgebra.Hermitian) + c = @constraint(model, Y in JuMP.HermitianPSDCone()) + @test c isa ConstraintRef + return +end + +function test_numerically_hermitian_matrix_error() + model = Model() + @variable(model, X[1:2, 1:2]) + @variable(model, t) + Y = X + LinearAlgebra.I(2) * t + @test !LinearAlgebra.ishermitian(Y) + @test !(Y isa LinearAlgebra.Hermitian) + @test_macro_throws( + ErrorException( + "In `@constraint(model, Y in HermitianPSDCone())`: " * + "Unable to add matrix in HermitianPSDCone because the matrix is " * + "not Hermitian. If this error was unexpected, check the matrix " * + "for errors, or wrap the matrix `H` in " * + "`LinearAlgebra.Hermitian(H)` to force JuMP to treat the matrix " * + "as Hermitian.", + ), + @constraint(model, Y in HermitianPSDCone()) + ) + return +end + end From 384d7ddb7b7dd41c6ffdde453ec03c561cc75002 Mon Sep 17 00:00:00 2001 From: Oscar Dowson Date: Mon, 22 May 2023 10:22:27 +1200 Subject: [PATCH 2/3] Update test/test_complex.jl --- test/test_complex.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_complex.jl b/test/test_complex.jl index 3c9a17abf4e..da4f4a91845 100644 --- a/test/test_complex.jl +++ b/test/test_complex.jl @@ -292,7 +292,7 @@ function test_numerically_hermitian_matrix_error() Y = X + LinearAlgebra.I(2) * t @test !LinearAlgebra.ishermitian(Y) @test !(Y isa LinearAlgebra.Hermitian) - @test_macro_throws( + @test_throws_strip( ErrorException( "In `@constraint(model, Y in HermitianPSDCone())`: " * "Unable to add matrix in HermitianPSDCone because the matrix is " * From 3479d1dfc479592776eed533b005da2e41917ea8 Mon Sep 17 00:00:00 2001 From: odow Date: Mon, 22 May 2023 21:14:14 +1200 Subject: [PATCH 3/3] Remove ishermitian check --- src/sd.jl | 15 +++++---------- test/test_complex.jl | 22 ++++------------------ 2 files changed, 9 insertions(+), 28 deletions(-) diff --git a/src/sd.jl b/src/sd.jl index 192badba7aa..403407c972a 100644 --- a/src/sd.jl +++ b/src/sd.jl @@ -684,16 +684,11 @@ function build_constraint( Q::AbstractMatrix{<:AbstractJuMPScalar}, cone::HermitianPSDCone, ) - if !LinearAlgebra.ishermitian(Q) - _error( - "Unable to add matrix in HermitianPSDCone because the matrix is " * - "not Hermitian. If this error was unexpected, check the matrix " * - "for errors, or wrap the matrix `H` in " * - "`LinearAlgebra.Hermitian(H)` to force JuMP to treat the " * - "matrix as Hermitian.", - ) - end - return build_constraint(_error, LinearAlgebra.Hermitian(Q), cone) + return _error( + "Unable to add matrix in HermitianPSDCone because the matrix is " * + "not a subtype of `LinearAlgebra.Hermitian`. To fix, wrap the matrix " * + "`H` in `LinearAlgebra.Hermitian(H)`.", + ) end function build_constraint(_error::Function, H::LinearAlgebra.Hermitian, ::Zeros) diff --git a/test/test_complex.jl b/test/test_complex.jl index da4f4a91845..7e8a49844b3 100644 --- a/test/test_complex.jl +++ b/test/test_complex.jl @@ -273,35 +273,21 @@ function test_isreal() return end -function test_numerically_hermitian_matrix() +function test_HermitianPSDCone_general_matrix_error() model = Model() @variable(model, X[1:2, 1:2] in HermitianPSDCone()) @variable(model, t) Y = X + LinearAlgebra.I(2) * t @test LinearAlgebra.ishermitian(Y) @test !(Y isa LinearAlgebra.Hermitian) - c = @constraint(model, Y in JuMP.HermitianPSDCone()) - @test c isa ConstraintRef - return -end - -function test_numerically_hermitian_matrix_error() - model = Model() - @variable(model, X[1:2, 1:2]) - @variable(model, t) - Y = X + LinearAlgebra.I(2) * t - @test !LinearAlgebra.ishermitian(Y) - @test !(Y isa LinearAlgebra.Hermitian) @test_throws_strip( ErrorException( "In `@constraint(model, Y in HermitianPSDCone())`: " * "Unable to add matrix in HermitianPSDCone because the matrix is " * - "not Hermitian. If this error was unexpected, check the matrix " * - "for errors, or wrap the matrix `H` in " * - "`LinearAlgebra.Hermitian(H)` to force JuMP to treat the matrix " * - "as Hermitian.", + "not a subtype of `LinearAlgebra.Hermitian`. To fix, wrap the " * + "matrix `H` in `LinearAlgebra.Hermitian(H)`.", ), - @constraint(model, Y in HermitianPSDCone()) + @constraint(model, Y in HermitianPSDCone()), ) return end