From 7300e8a348fa1db4b4d295894a133db84eebd9d2 Mon Sep 17 00:00:00 2001 From: Don van den Bergh Date: Wed, 10 Sep 2025 16:30:07 +0200 Subject: [PATCH 1/2] ensure inverse of Symmetric{<:,Diagonal} returns same type --- src/diagonal.jl | 4 ++++ src/symmetric.jl | 1 + test/symmetric.jl | 15 +++++++++++++++ 3 files changed, 20 insertions(+) diff --git a/src/diagonal.jl b/src/diagonal.jl index e60fb009..63cff1c8 100644 --- a/src/diagonal.jl +++ b/src/diagonal.jl @@ -970,6 +970,10 @@ function inv(D::Diagonal{T}) where T Diagonal(Di) end +# Ensure doubly wrapped matrices use efficient diagonal methods and return a Symmetric/Hermitian type +inv(A::Symmetric{<:Number,<:Diagonal}) = Symmetric(inv(A.data), sym_uplo(A.uplo)) +inv(A::Hermitian{<:Number,<:Diagonal}) = Hermitian(inv(real(A.data)), sym_uplo(A.uplo)) + function pinv(D::Diagonal{T}) where T Di = similar(D.diag, typeof(inv(oneunit(T)))) for i = 1:length(D.diag) diff --git a/src/symmetric.jl b/src/symmetric.jl index 2cc74763..d95c3dcd 100644 --- a/src/symmetric.jl +++ b/src/symmetric.jl @@ -987,6 +987,7 @@ See also [`hermitianpart!`](@ref) for the corresponding in-place operation. This function requires Julia 1.10 or later. """ hermitianpart(A::AbstractMatrix, uplo::Symbol=:U) = Hermitian(_hermitianpart(A), uplo) +hermitianpart(a::Number) = real(a) """ hermitianpart!(A::AbstractMatrix, uplo::Symbol=:U) -> Hermitian diff --git a/test/symmetric.jl b/test/symmetric.jl index 707b392d..ae10618f 100644 --- a/test/symmetric.jl +++ b/test/symmetric.jl @@ -874,6 +874,21 @@ end @test det(Hermitian(A))::Float64 == det(A) == 0.0 end +@testset "issue #1437: inverse of Symmetric|Hermitian{<:Any,<:Diagonal} returns of Symmetric|Hermitian{<:Any,<:Diagonal}" begin + Dreal = Diagonal(randn(3)) + Dcomplex = Diagonal(randn(ComplexF64, 3)) + # without wrapper + invDreal = inv(Dreal) + invDcomplex = inv(real(Dcomplex)) # because Hermitian implies a real diagonal + # with wrapper + SDreal = Symmetric(Dreal) + HDcomplex = Hermitian(Dcomplex) + @test inv(SDreal)::Symmetric{Float64,typeof(Dreal)} ≈ invDreal + @test inv(HDcomplex)::Hermitian{Float64,typeof(Dreal)} ≈ invDcomplex + Dcomplex[2,2] = 0 + @test_throws SingularException inv(HDcomplex) +end + @testset "symmetric()/hermitian() for Numbers" begin @test LinearAlgebra.symmetric(1) == LinearAlgebra.symmetric(1, :U) == 1 @test LinearAlgebra.symmetric_type(Int) == Int From af1fe0094769e7f7dbf8241eeb77d5af553da732 Mon Sep 17 00:00:00 2001 From: Don van den Bergh Date: Fri, 12 Sep 2025 09:40:42 +0200 Subject: [PATCH 2/2] remove hermitianpart(a::Number) --- src/symmetric.jl | 1 - 1 file changed, 1 deletion(-) diff --git a/src/symmetric.jl b/src/symmetric.jl index d95c3dcd..2cc74763 100644 --- a/src/symmetric.jl +++ b/src/symmetric.jl @@ -987,7 +987,6 @@ See also [`hermitianpart!`](@ref) for the corresponding in-place operation. This function requires Julia 1.10 or later. """ hermitianpart(A::AbstractMatrix, uplo::Symbol=:U) = Hermitian(_hermitianpart(A), uplo) -hermitianpart(a::Number) = real(a) """ hermitianpart!(A::AbstractMatrix, uplo::Symbol=:U) -> Hermitian