Skip to content

Commit 065d456

Browse files
authored
Materialize complex Symmetric matrices in eigen (#55348)
Currently, `eigen` for a complex Symmetric matrix fails, as there's no specialized LAPACK function to handle such matrices. We may instead materialize the matrix and use a generic solver. While a user may do it by themselves, I think returning an answer is better than throwing an error.
1 parent 22e5362 commit 065d456

File tree

4 files changed

+23
-6
lines changed

4 files changed

+23
-6
lines changed

stdlib/LinearAlgebra/src/bunchkaufman.jl

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,9 @@ function bunchkaufman!(A::StridedMatrix{<:BlasFloat}, rook::Bool = false; check:
127127
end
128128
end
129129

130+
bkcopy_oftype(A, S) = eigencopy_oftype(A, S)
131+
bkcopy_oftype(A::Symmetric{<:Complex}, S) = Symmetric(copytrito!(similar(parent(A), S, size(A)), A.data, A.uplo), sym_uplo(A.uplo))
132+
130133
"""
131134
bunchkaufman(A, rook::Bool=false; check = true) -> S::BunchKaufman
132135
@@ -206,7 +209,7 @@ julia> S.L*S.D*S.L' - A[S.p, S.p]
206209
```
207210
"""
208211
bunchkaufman(A::AbstractMatrix{T}, rook::Bool=false; check::Bool = true) where {T} =
209-
bunchkaufman!(eigencopy_oftype(A, typeof(sqrt(oneunit(T)))), rook; check = check)
212+
bunchkaufman!(bkcopy_oftype(A, typeof(sqrt(oneunit(T)))), rook; check = check)
210213

211214
BunchKaufman{T}(B::BunchKaufman) where {T} =
212215
BunchKaufman(convert(Matrix{T}, B.LD), B.ipiv, B.uplo, B.symmetric, B.rook, B.info)
@@ -1540,7 +1543,7 @@ function bunchkaufman(A::AbstractMatrix{TS},
15401543
rook::Bool = false;
15411544
check::Bool = true
15421545
) where TS <: ClosedScalar{TR} where TR <: ClosedReal
1543-
return bunchkaufman!(eigencopy_oftype(A, TS), rook; check)
1546+
return bunchkaufman!(bkcopy_oftype(A, TS), rook; check)
15441547
end
15451548

15461549
function bunchkaufman(A::AbstractMatrix{TS},
@@ -1562,15 +1565,15 @@ function bunchkaufman(A::AbstractMatrix{TS},
15621565
# We promote input to BigInt to avoid overflow problems
15631566
if TA == Nothing
15641567
if TS <: Integer
1565-
M = Rational{BigInt}.(eigencopy_oftype(A, TS))
1568+
M = Rational{BigInt}.(bkcopy_oftype(A, TS))
15661569
else
1567-
M = Complex{Rational{BigInt}}.(eigencopy_oftype(A, TS))
1570+
M = Complex{Rational{BigInt}}.(bkcopy_oftype(A, TS))
15681571
end
15691572
else
15701573
if TS <: Integer
1571-
M = TA(Rational{BigInt}.(eigencopy_oftype(A, TS)), Symbol(A.uplo))
1574+
M = TA(Rational{BigInt}.(bkcopy_oftype(A, TS)), Symbol(A.uplo))
15721575
else
1573-
M = TA(Complex{Rational{BigInt}}.(eigencopy_oftype(A, TS)),
1576+
M = TA(Complex{Rational{BigInt}}.(bkcopy_oftype(A, TS)),
15741577
Symbol(A.uplo))
15751578
end
15761579
end

stdlib/LinearAlgebra/src/symmetriceigen.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
# Call `copytrito!` instead of `copy_similar` to only copy the matching triangular half
55
eigencopy_oftype(A::Hermitian, S) = Hermitian(copytrito!(similar(parent(A), S, size(A)), A.data, A.uplo), sym_uplo(A.uplo))
66
eigencopy_oftype(A::Symmetric, S) = Symmetric(copytrito!(similar(parent(A), S, size(A)), A.data, A.uplo), sym_uplo(A.uplo))
7+
eigencopy_oftype(A::Symmetric{<:Complex}, S) = copyto!(similar(parent(A), S), A)
78

89
default_eigen_alg(A) = DivideAndConquer()
910

stdlib/LinearAlgebra/test/hessenberg.jl

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,4 +272,11 @@ end
272272
@test S[1,2] == S[Int8(1),UInt16(2)] == S[big(1), Int16(2)]
273273
end
274274

275+
@testset "complex Symmetric" begin
276+
D = diagm(0=>ComplexF64[1,2])
277+
S = Symmetric(D)
278+
H = hessenberg(S)
279+
@test H.H == D
280+
end
281+
275282
end # module TestHessenberg

stdlib/LinearAlgebra/test/symmetriceigen.jl

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,4 +173,10 @@ end
173173
@test D.vectors D32.vectors
174174
end
175175

176+
@testset "complex Symmetric" begin
177+
S = Symmetric(rand(ComplexF64,2,2))
178+
λ, v = eigen(S)
179+
@test S * v v * Diagonal(λ)
180+
end
181+
176182
end # module TestSymmetricEigen

0 commit comments

Comments
 (0)