Skip to content

Commit ea5f6bb

Browse files
authored
fix eigvals,eigvecs,eigen for Diagonal{Matrix} (#50897)
1 parent 73dfde8 commit ea5f6bb

File tree

2 files changed

+59
-3
lines changed

2 files changed

+59
-3
lines changed

src/diagonal.jl

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -300,7 +300,7 @@ end
300300
(*)(A::HermOrSym, D::Diagonal) =
301301
mul!(similar(A, promote_op(*, eltype(A), eltype(D.diag)), size(A)), A, D)
302302
(*)(D::Diagonal, A::AbstractMatrix) =
303-
mul!(similar(A, promote_op(*, eltype(A), eltype(D.diag))), D, A)
303+
mul!(similar(A, promote_op(*, eltype(D.diag), eltype(A))), D, A)
304304
(*)(D::Diagonal, A::HermOrSym) =
305305
mul!(similar(A, promote_op(*, eltype(A), eltype(D.diag)), size(A)), D, A)
306306

@@ -768,11 +768,32 @@ function pinv(D::Diagonal{T}, tol::Real) where T
768768
Diagonal(Di)
769769
end
770770

771+
# TODO Docstrings for eigvals, eigvecs, eigen all mention permute, scale, sortby as keyword args
772+
# but not all of them below provide them. Do we need to fix that?
771773
#Eigensystem
772774
eigvals(D::Diagonal{<:Number}; permute::Bool=true, scale::Bool=true) = copy(D.diag)
773775
eigvals(D::Diagonal; permute::Bool=true, scale::Bool=true) =
774-
[eigvals(x) for x in D.diag] #For block matrices, etc.
775-
eigvecs(D::Diagonal) = Matrix{eltype(D)}(I, size(D))
776+
reduce(vcat, eigvals(x) for x in D.diag) #For block matrices, etc.
777+
function eigvecs(D::Diagonal{T}) where T<:AbstractMatrix
778+
diag_vecs = [ eigvecs(x) for x in D.diag ]
779+
matT = reduce((a,b) -> promote_type(typeof(a),typeof(b)), diag_vecs)
780+
ncols_diag = [ size(x, 2) for x in D.diag ]
781+
nrows = size(D, 1)
782+
vecs = Matrix{Vector{eltype(matT)}}(undef, nrows, sum(ncols_diag))
783+
for j in axes(D, 2), i in axes(D, 1)
784+
jj = sum(view(ncols_diag,1:j-1))
785+
if i == j
786+
for k in 1:ncols_diag[j]
787+
vecs[i,jj+k] = diag_vecs[i][:,k]
788+
end
789+
else
790+
for k in 1:ncols_diag[j]
791+
vecs[i,jj+k] = zeros(eltype(T), ncols_diag[i])
792+
end
793+
end
794+
end
795+
return vecs
796+
end
776797
function eigen(D::Diagonal; permute::Bool=true, scale::Bool=true, sortby::Union{Function,Nothing}=nothing)
777798
if any(!isfinite, D.diag)
778799
throw(ArgumentError("matrix contains Infs or NaNs"))
@@ -791,6 +812,19 @@ function eigen(D::Diagonal; permute::Bool=true, scale::Bool=true, sortby::Union{
791812
end
792813
Eigen(λ, evecs)
793814
end
815+
function eigen(D::Diagonal{<:AbstractMatrix}; permute::Bool=true, scale::Bool=true, sortby::Union{Function,Nothing}=nothing)
816+
if any(any(!isfinite, x) for x in D.diag)
817+
throw(ArgumentError("matrix contains Infs or NaNs"))
818+
end
819+
λ = eigvals(D)
820+
evecs = eigvecs(D)
821+
if !isnothing(sortby)
822+
p = sortperm(λ; alg=QuickSort, by=sortby)
823+
λ = λ[p]
824+
evecs = evecs[:,p]
825+
end
826+
Eigen(λ, evecs)
827+
end
794828
function eigen(Da::Diagonal, Db::Diagonal; sortby::Union{Function,Nothing}=nothing)
795829
if any(!isfinite, Da.diag) || any(!isfinite, Db.diag)
796830
throw(ArgumentError("matrices contain Infs or NaNs"))

test/diagonal.jl

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -774,6 +774,28 @@ end
774774
end
775775
end
776776

777+
@testset "Eigensystem for block diagonal (issue #30681)" begin
778+
I2 = Matrix(I, 2,2)
779+
D = Diagonal([2.0*I2, 3.0*I2])
780+
eigD = eigen(D)
781+
evals = [ 2.0, 2.0, 3.0, 3.0 ]
782+
evecs = [ [[ 1.0, 0.0 ]] [[ 0.0, 1.0 ]] [[ 0.0, 0.0 ]] [[ 0.0, 0.0 ]];
783+
[[ 0.0, 0.0 ]] [[ 0.0, 0.0 ]] [[ 1.0, 0.0 ]] [[ 0.0, 1.0 ]] ]
784+
@test eigD.values == evals
785+
@test eigD.vectors == evecs
786+
@test D * eigD.vectors eigD.vectors * Diagonal(eigD.values)
787+
788+
I3 = Matrix(I, 3,3)
789+
D = Diagonal([[0.0 -1.0; 1.0 0.0], 2.0*I3])
790+
eigD = eigen(D)
791+
evals = [ -1.0im, 1.0im, 2.0, 2.0, 2.0 ]
792+
evecs = [ [[ 1/sqrt(2)+0im, 1/sqrt(2)*im ]] [[ 1/sqrt(2)+0im, -1/sqrt(2)*im ]] [[ 0.0, 0.0 ]] [[ 0.0, 0.0 ]] [[ 0.0, 0.0]];
793+
[[ 0.0, 0.0, 0.0 ]] [[ 0.0, 0.0, 0.0 ]] [[ 1.0, 0.0, 0.0 ]] [[ 0.0, 1.0, 0.0 ]] [[ 0.0, 0.0, 1.0]] ]
794+
@test eigD.values == evals
795+
@test eigD.vectors == evecs
796+
@test D * eigD.vectors eigD.vectors * Diagonal(eigD.values)
797+
end
798+
777799
@testset "linear solve for block diagonal matrices" begin
778800
D = Diagonal([rand(2,2) for _ in 1:5])
779801
b = [rand(2,2) for _ in 1:5]

0 commit comments

Comments
 (0)