Skip to content

Commit ff8494f

Browse files
committed
Eigen for FillArrays
1 parent d498a3e commit ff8494f

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
@@ -562,3 +562,41 @@ end
562562

563563
triu(A::AbstractZerosMatrix, k::Integer=0) = A
564564
tril(A::AbstractZerosMatrix, k::Integer=0) = A
565+
566+
# eigen
567+
_eigenind(λ0, n, sortby) = (isnothing(sortby) || sortby(λ0) <= sortby(zero(λ0))) ? 1 : n
568+
569+
function eigvals(A::AbstractFillMatrix{<:Union{Real, Complex}}; sortby = nothing)
570+
Base.require_one_based_indexing(A)
571+
n = checksquare(A)
572+
# only one non-trivial eigenvalue for a rank-1 matrix
573+
λ0 = float(getindex_value(A)) * n
574+
ind = _eigenind(λ0, n, sortby)
575+
OneElement(λ0, ind, n)
576+
end
577+
578+
function eigvecs(A::AbstractFillMatrix{<:Union{Real, Complex}}; sortby = nothing)
579+
Base.require_one_based_indexing(A)
580+
n = checksquare(A)
581+
M = similar(A, real(float(eltype(A))))
582+
n == 0 && return M
583+
val = getindex_value(A)
584+
ind = _eigenind(val, n, sortby)
585+
# The non-trivial eigenvector is normalize(ones(n))
586+
M[:, ind] .= inv(sqrt(n))
587+
# eigenvectors corresponding to zero eigenvalues
588+
for (i, j) in enumerate(axes(M,2)[(ind == 1) .+ (1:end-1)])
589+
# The eigenvectors are v = normalize([ones(n-1); -(n-1)]), and sum(v) == 0
590+
# The ordering is arbitrary,
591+
# and we choose to order in terms of the number of non-zero elements
592+
nrm = 1/sqrt(i*(i+1))
593+
M[1:i, j] .= nrm
594+
M[i+1, j] = -i * nrm
595+
M[i+2:end, j] .= zero(eltype(M))
596+
end
597+
return M
598+
end
599+
600+
function eigen(A::AbstractFillMatrix{<:Number}; sortby = nothing)
601+
Eigen(eigvals(A; sortby), eigvecs(A; sortby))
602+
end

test/runtests.jl

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2940,3 +2940,27 @@ end
29402940
@test triu(Z, 2) === Z
29412941
@test tril(Z, 2) === Z
29422942
end
2943+
2944+
@testset "eigen" begin
2945+
sortby = x -> (real(x), imag(x))
2946+
@testset "AbstractFill" begin
2947+
@testset for val in (2.0, -2, 3+2im, 4 - 5im, 2im), n in (0, 1, 4)
2948+
F = Fill(val, n, n)
2949+
M = Matrix(F)
2950+
@test eigvals(F; sortby) eigvals(M; sortby)
2951+
λ, V = eigen(F; sortby)
2952+
@test λ == eigvals(F; sortby)
2953+
@test V'V I
2954+
@test F * V V * Diagonal(λ)
2955+
end
2956+
@testset for MT in (Ones, Zeros), T in (Float64, Int, ComplexF64), n in (0, 1, 4)
2957+
F = MT{T}(n,n)
2958+
M = Matrix(F)
2959+
@test eigvals(F; sortby) eigvals(M; sortby)
2960+
λ, V = eigen(F; sortby)
2961+
@test λ == eigvals(F; sortby)
2962+
@test V'V I
2963+
@test F * V V * Diagonal(λ)
2964+
end
2965+
end
2966+
end

0 commit comments

Comments
 (0)