Skip to content

Commit 42f7c9d

Browse files
committed
Eigen for FillArrays
1 parent c7c34aa commit 42f7c9d

File tree

3 files changed

+64
-1
lines changed

3 files changed

+64
-1
lines changed

src/FillArrays.jl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@ import Base: size, getindex, setindex!, IndexStyle, checkbounds, convert,
1111

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

1617

1718
import Base.Broadcast: broadcasted, DefaultArrayStyle, broadcast_shape, BroadcastStyle, Broadcasted

src/fillalgebra.jl

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -524,3 +524,41 @@ end
524524
function LinearAlgebra.istril(A::AbstractFillMatrix, k::Integer = 0)
525525
iszero(A) || k >= size(A,2)-1
526526
end
527+
528+
# eigen
529+
_eigenind(λ0, n, sortby) = (isnothing(sortby) || sortby(λ0) <= sortby(zero(λ0))) ? 1 : n
530+
531+
function eigvals(A::AbstractFillMatrix{<:Number}; sortby = nothing)
532+
Base.require_one_based_indexing(A)
533+
n = checksquare(A)
534+
# only one non-trivial eigenvalue for a rank-1 matrix
535+
λ0 = float(getindex_value(A)) * n
536+
ind = _eigenind(λ0, n, sortby)
537+
OneElement(λ0, ind, n)
538+
end
539+
540+
function eigvecs(A::AbstractFillMatrix{<:Number}; sortby = nothing)
541+
Base.require_one_based_indexing(A)
542+
n = checksquare(A)
543+
M = similar(A, real(float(eltype(A))))
544+
n == 0 && return M
545+
val = getindex_value(A)
546+
ind = _eigenind(val, n, sortby)
547+
# The non-trivial eigenvector is normalize(ones(n))
548+
M[:, ind] .= inv(sqrt(n))
549+
# eigenvectors corresponding to zero eigenvalues
550+
for (i, j) in enumerate(axes(M,2)[(ind == 1) .+ (1:end-1)])
551+
# The eigenvectors are v = normalize([ones(n-1); -(n-1)]), and sum(v) == 0
552+
# The ordering is arbitrary,
553+
# and we choose to order in terms of the number of non-zero elements
554+
nrm = 1/sqrt(i*(i+1))
555+
M[1:i, j] .= nrm
556+
M[i+1, j] = -i * nrm
557+
M[i+2:end, j] .= zero(eltype(M))
558+
end
559+
return M
560+
end
561+
562+
function eigen(A::AbstractFillMatrix{<:Number}; sortby = nothing)
563+
Eigen(eigvals(A; sortby), eigvecs(A; sortby))
564+
end

test/runtests.jl

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2383,3 +2383,27 @@ end
23832383
end
23842384
end
23852385
end
2386+
2387+
@testset "eigen" begin
2388+
sortby = x -> (real(x), imag(x))
2389+
@testset "AbstractFill" begin
2390+
@testset for val in (2.0, -2, 3+2im, 4 - 5im, 2im), n in (0, 1, 4)
2391+
F = Fill(val, n, n)
2392+
M = Matrix(F)
2393+
@test eigvals(F; sortby) eigvals(M; sortby)
2394+
λ, V = eigen(F; sortby)
2395+
@test λ == eigvals(F; sortby)
2396+
@test V'V I
2397+
@test F * V V * Diagonal(λ)
2398+
end
2399+
@testset for MT in (Ones, Zeros), T in (Float64, Int, ComplexF64), n in (0, 1, 4)
2400+
F = MT{T}(n,n)
2401+
M = Matrix(F)
2402+
@test eigvals(F; sortby) eigvals(M; sortby)
2403+
λ, V = eigen(F; sortby)
2404+
@test λ == eigvals(F; sortby)
2405+
@test V'V I
2406+
@test F * V V * Diagonal(λ)
2407+
end
2408+
end
2409+
end

0 commit comments

Comments
 (0)