Skip to content

Commit 2a6f3b7

Browse files
araujomsdkarrasch
andauthored
make eigvals(::Diagonal) accept sortby (#1477)
Solves the `Diagonal` part of #1471 and #1450. I thought it would be better to start with `Diagonal`, as it was the only part that required a bit of thinking. I think it also makes sense in itself, since `eigen` accepted `sortby`, just `eigvals` and `eigvecs` did not. Even though the docstring said none did. If this is welcome I'll also do `SymTridiagonal`, and then we can document that eigenvalues are sorted by default. --------- Co-authored-by: Daniel Karrasch <[email protected]>
1 parent 189d49d commit 2a6f3b7

File tree

3 files changed

+18
-18
lines changed

3 files changed

+18
-18
lines changed

src/diagonal.jl

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1011,16 +1011,16 @@ end
10111011
_ortho_eltype(T) = Base.promote_op(/, T, T)
10121012
_ortho_eltype(T::Type{<:Number}) = typeof(one(T)/one(T))
10131013

1014-
# TODO Docstrings for eigvals, eigvecs, eigen all mention permute, scale, sortby as keyword args
1015-
# but not all of them below provide them. Do we need to fix that?
10161014
#Eigensystem
1017-
eigvals(D::Diagonal{<:Number}; permute::Bool=true, scale::Bool=true) = copy(D.diag)
1018-
eigvals(D::Diagonal; permute::Bool=true, scale::Bool=true) =
1019-
reduce(vcat, eigvals(x) for x in D.diag) #For block matrices, etc.
1020-
function eigvecs(D::Diagonal{T}) where {T<:AbstractMatrix}
1021-
diag_vecs = [ eigvecs(x) for x in D.diag ]
1015+
eigvals(D::Diagonal{<:Number}; permute::Bool=true, scale::Bool=true, sortby::Union{Function,Nothing}=nothing) = sorteig!(copy(D.diag), sortby)
1016+
eigvals(D::Diagonal; permute::Bool=true, scale::Bool=true, sortby::Union{Function,Nothing}=nothing) =
1017+
sorteig!(reduce(vcat, eigvals(x; sortby=nothing) for x in D.diag), sortby) #For block matrices, etc.
1018+
function _eigen(D::Diagonal{T}) where {T<:AbstractMatrix}
1019+
facts = [eigen(x; sortby=nothing) for x in D.diag]
1020+
λ = reduce(vcat, f.values for f in facts)
1021+
diag_vecs = [f.vectors for f in facts]
10221022
matT = promote_type(map(typeof, diag_vecs)...)
1023-
ncols_diag = [ size(x, 2) for x in D.diag ]
1023+
ncols_diag = [size(x, 2) for x in D.diag]
10241024
nrows = size(D, 1)
10251025
vecs = Matrix{Vector{eltype(matT)}}(undef, nrows, sum(ncols_diag))
10261026
for j in axes(D, 2), i in axes(D, 1)
@@ -1035,14 +1035,14 @@ function eigvecs(D::Diagonal{T}) where {T<:AbstractMatrix}
10351035
end
10361036
end
10371037
end
1038-
return vecs
1038+
return λ, vecs
10391039
end
10401040
function eigen(D::Diagonal; permute::Bool=true, scale::Bool=true, sortby::Union{Function,Nothing}=nothing)
10411041
if any(!isfinite, D.diag)
10421042
throw(ArgumentError("matrix contains Infs or NaNs"))
10431043
end
10441044
Td = _ortho_eltype(eltype(D))
1045-
λ = eigvals(D)
1045+
λ = eigvals(D; sortby=nothing)
10461046
if !isnothing(sortby)
10471047
p = sortperm(λ; alg=QuickSort, by=sortby)
10481048
λ = λ[p]
@@ -1059,8 +1059,7 @@ function eigen(D::Diagonal{<:AbstractMatrix}; permute::Bool=true, scale::Bool=tr
10591059
if any(any(!isfinite, x) for x in D.diag)
10601060
throw(ArgumentError("matrix contains Infs or NaNs"))
10611061
end
1062-
λ = eigvals(D)
1063-
evecs = eigvecs(D)
1062+
λ, evecs = _eigen(D)
10641063
if !isnothing(sortby)
10651064
p = sortperm(λ; alg=QuickSort, by=sortby)
10661065
λ = λ[p]

test/diagonal.jl

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -413,7 +413,7 @@ LinearAlgebra.istril(N::NotDiagonal) = istril(N.a)
413413
@test factorize(D) == D
414414

415415
@testset "Eigensystem" begin
416-
eigD = eigen(D)
416+
eigD = eigen(D, sortby=nothing)
417417
@test Diagonal(eigD.values) == D
418418
@test eigD.vectors == Matrix(I, size(D))
419419
eigsortD = eigen(D, sortby=LinearAlgebra.eigsortby)
@@ -564,7 +564,7 @@ end
564564
@testset "svdvals and eigvals (#11120/#11247)" begin
565565
D = Diagonal(Matrix{Float64}[randn(3,3), randn(2,2)])
566566
@test sort([svdvals(D)...;], rev = true) svdvals([D.diag[1] zeros(3,2); zeros(2,3) D.diag[2]])
567-
@test sort([eigvals(D)...;], by=LinearAlgebra.eigsortby) eigvals([D.diag[1] zeros(3,2); zeros(2,3) D.diag[2]])
567+
@test eigvals(D, sortby=LinearAlgebra.eigsortby) eigvals([D.diag[1] zeros(3,2); zeros(2,3) D.diag[2]])
568568
end
569569

570570
@testset "eigvals should return a copy of the diagonal" begin
@@ -853,7 +853,7 @@ end
853853
@testset "Eigensystem for block diagonal (issue #30681)" begin
854854
I2 = Matrix(I, 2,2)
855855
D = Diagonal([2.0*I2, 3.0*I2])
856-
eigD = eigen(D)
856+
eigD = eigen(D; sortby=LinearAlgebra.eigsortby)
857857
evals = [ 2.0, 2.0, 3.0, 3.0 ]
858858
evecs = [ [[ 1.0, 0.0 ]] [[ 0.0, 1.0 ]] [[ 0.0, 0.0 ]] [[ 0.0, 0.0 ]];
859859
[[ 0.0, 0.0 ]] [[ 0.0, 0.0 ]] [[ 1.0, 0.0 ]] [[ 0.0, 1.0 ]] ]
@@ -863,7 +863,7 @@ end
863863

864864
I3 = Matrix(I, 3,3)
865865
D = Diagonal([[0.0 -1.0; 1.0 0.0], 2.0*I3])
866-
eigD = eigen(D)
866+
eigD = eigen(D; sortby=LinearAlgebra.eigsortby)
867867
evals = [ -1.0im, 1.0im, 2.0, 2.0, 2.0 ]
868868
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]];
869869
[[ 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]] ]
@@ -1066,8 +1066,9 @@ end
10661066
@testset "eigenvalue sorting" begin
10671067
D = Diagonal([0.4, 0.2, -1.3])
10681068
@test eigvals(D) == eigen(D).values == [0.4, 0.2, -1.3] # not sorted by default
1069+
@test eigvals(D; sortby=LinearAlgebra.eigsortby) == [-1.3, 0.2, 0.4] # sortby keyword supported for eigvals(::Diagonal)
10691070
@test eigvals(Matrix(D)) == eigen(Matrix(D)).values == [-1.3, 0.2, 0.4] # sorted even if diagonal special case is detected
1070-
E = eigen(D, sortby=abs) # sortby keyword supported for eigen(::Diagonal)
1071+
E = eigen(D; sortby=abs) # sortby keyword supported for eigen(::Diagonal)
10711072
@test E.values == [0.2, 0.4, -1.3]
10721073
@test E.vectors == [0 1 0; 1 0 0; 0 0 1]
10731074
end

test/unitful.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ end
8686
@test U isa AbstractMatrix{<:Union{Real,Complex}}
8787
@test V isa AbstractMatrix{<:Union{Real,Complex}}
8888
@test s isa AbstractVector{<:Furlong{1}}
89-
E = eigen(Du)
89+
E = eigen(Du; sortby=nothing)
9090
vals, vecs = E
9191
@test Matrix(E) == Du
9292
@test vals isa AbstractVector{<:Furlong{1}}

0 commit comments

Comments
 (0)