Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Eigen for FillArrays #330

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/FillArrays.jl
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ import Base: size, getindex, setindex!, IndexStyle, checkbounds, convert,

import LinearAlgebra: rank, svdvals!, tril, triu, tril!, triu!, diag, transpose, adjoint, fill!,
dot, norm2, norm1, normInf, normMinusInf, normp, lmul!, rmul!, diagzero, AdjointAbsVec, TransposeAbsVec,
issymmetric, ishermitian, AdjOrTransAbsVec, checksquare, mul!, kron, AbstractTriangular
issymmetric, ishermitian, AdjOrTransAbsVec, checksquare, mul!, kron, AbstractTriangular,
eigvecs, eigvals, eigen


import Base.Broadcast: broadcasted, DefaultArrayStyle, broadcast_shape, BroadcastStyle, Broadcasted
Expand Down
38 changes: 38 additions & 0 deletions src/fillalgebra.jl
Original file line number Diff line number Diff line change
Expand Up @@ -564,3 +564,41 @@

triu(A::AbstractZerosMatrix, k::Integer=0) = A
tril(A::AbstractZerosMatrix, k::Integer=0) = A

# eigen
_eigenind(λ0, n, sortby) = (isnothing(sortby) || sortby(λ0) <= sortby(zero(λ0))) ? 1 : n

Check warning on line 569 in src/fillalgebra.jl

View check run for this annotation

Codecov / codecov/patch

src/fillalgebra.jl#L569

Added line #L569 was not covered by tests

function eigvals(A::AbstractFillMatrix{<:Union{Real, Complex}}; sortby = nothing)
Base.require_one_based_indexing(A)
n = checksquare(A)

Check warning on line 573 in src/fillalgebra.jl

View check run for this annotation

Codecov / codecov/patch

src/fillalgebra.jl#L571-L573

Added lines #L571 - L573 were not covered by tests
# only one non-trivial eigenvalue for a rank-1 matrix
λ0 = float(getindex_value(A)) * n
ind = _eigenind(λ0, n, sortby)
OneElement(λ0, ind, n)

Check warning on line 577 in src/fillalgebra.jl

View check run for this annotation

Codecov / codecov/patch

src/fillalgebra.jl#L575-L577

Added lines #L575 - L577 were not covered by tests
end

function eigvecs(A::AbstractFillMatrix{<:Union{Real, Complex}}; sortby = nothing)
Base.require_one_based_indexing(A)
n = checksquare(A)
M = similar(A, real(float(eltype(A))))
n == 0 && return M
val = getindex_value(A)
ind = _eigenind(val, n, sortby)

Check warning on line 586 in src/fillalgebra.jl

View check run for this annotation

Codecov / codecov/patch

src/fillalgebra.jl#L580-L586

Added lines #L580 - L586 were not covered by tests
# The non-trivial eigenvector is normalize(ones(n))
M[:, ind] .= inv(sqrt(n))

Check warning on line 588 in src/fillalgebra.jl

View check run for this annotation

Codecov / codecov/patch

src/fillalgebra.jl#L588

Added line #L588 was not covered by tests
# eigenvectors corresponding to zero eigenvalues
for (i, j) in enumerate(axes(M,2)[(ind == 1) .+ (1:end-1)])

Check warning on line 590 in src/fillalgebra.jl

View check run for this annotation

Codecov / codecov/patch

src/fillalgebra.jl#L590

Added line #L590 was not covered by tests
# The eigenvectors are v = normalize([ones(n-1); -(n-1)]), and sum(v) == 0
# The ordering is arbitrary,
# and we choose to order in terms of the number of non-zero elements
nrm = 1/sqrt(i*(i+1))
M[1:i, j] .= nrm
M[i+1, j] = -i * nrm
M[i+2:end, j] .= zero(eltype(M))
end
return M

Check warning on line 599 in src/fillalgebra.jl

View check run for this annotation

Codecov / codecov/patch

src/fillalgebra.jl#L594-L599

Added lines #L594 - L599 were not covered by tests
end

function eigen(A::AbstractFillMatrix{<:Union{Real, Complex}}; sortby = nothing)
Eigen(eigvals(A; sortby), eigvecs(A; sortby))

Check warning on line 603 in src/fillalgebra.jl

View check run for this annotation

Codecov / codecov/patch

src/fillalgebra.jl#L602-L603

Added lines #L602 - L603 were not covered by tests
end
26 changes: 26 additions & 0 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2984,6 +2984,32 @@ end
@test tril(Z, 2) === Z
end

@testset "eigen" begin
sortby = x -> (real(x), imag(x))
@testset "AbstractFill" begin
sizes = VERSION >= v"1.10" ? (0, 1, 4) : (1, 4)
@testset for val in (2.0, -2, 3+2im, 4 - 5im, 2im), n in sizes
sortby_val = iszero(real(val)) ? imag : sortby
F = Fill(val, n, n)
M = Matrix(F)
@test eigvals(F; sortby = sortby_val) ≈ eigvals(M; sortby = sortby_val)
λ, V = eigen(F; sortby = sortby_val)
@test λ == eigvals(F; sortby = sortby_val)
@test V'V ≈ I
@test F * V ≈ V * Diagonal(λ)
end
@testset for MT in (Ones, Zeros), T in (Float64, Int, ComplexF64), n in sizes
F = MT{T}(n,n)
M = Matrix(F)
@test eigvals(F; sortby) ≈ eigvals(M; sortby)
λ, V = eigen(F; sortby)
@test λ == eigvals(F; sortby)
@test V'V ≈ I
@test F * V ≈ V * Diagonal(λ)
end
end
end

@testset "Diagonal conversion (#389)" begin
@test convert(Diagonal{Int, Vector{Int}}, Zeros(5,5)) isa Diagonal{Int,Vector{Int}}
@test convert(Diagonal{Int, Vector{Int}}, Zeros(5,5)) == zeros(5,5)
Expand Down
Loading