I have a question about the documentation of “transformations” (i.e., multiplying the inverse of a matrix times a vector without explicitly forming the inverse) in ArnoldiMethod.jl, although I think the topic is of broader interest than just this package.
From the documentation:
using ArnoldiMethod, LinearAlgebra, LinearMaps
# Define a matrix whose eigenvalues you want
A = rand(100,100)
# Factorizes A and builds a linear map that applies inv(A) to a vector.
function construct_linear_map(A)
F = factorize(A)
LinearMap{eltype(A)}((y, x) -> ldiv!(y, F, x), size(A,1), ismutating=true)
end
# Target the largest eigenvalues of the inverted problem
decomp, = partialschur(construct_linear_map(A), nev=4, tol=1e-5, restarts=100, which=LM())
λs_inv, X = partialeigen(decomp)
However, I would replace the definition of construct_linear_map
and the call to partial_schur
with the somewhat simpler
F = factorize(A)
linearmap = LinearMap{eltype(A)}((y, x) -> ldiv!(y, F, x), size(A,1), ismutating=true)
decomp, = partialschur(linearmap, nev=4, tol=1e-5, restarts=100, which=LM())
The example for a generalized eigenvalue problem is more complicated:
using ArnoldiMethod, LinearAlgebra, LinearMaps
# Define the matrices of the generalized eigenvalue problem
A, B = rand(100,100), rand(100,100)
struct ShiftAndInvert{TA,TB,TT}
A_lu::TA
B::TB
temp::TT
end
function (M::ShiftAndInvert)(y,x)
mul!(M.temp, M.B, x)
ldiv!(y, M.A_lu, M.temp)
end
function construct_linear_map(A,B)
a = ShiftAndInvert(factorize(A),B,Vector{eltype(A)}(undef, size(A,1)))
LinearMap{eltype(A)}(a, size(A,1), ismutating=true)
end
# Target the largest eigenvalues of the inverted problem
decomp, = partialschur(construct_linear_map(A, B), nev=4, tol=1e-5, restarts=100, which=LM())
λs_inv, X = partialeigen(decomp)
I would simplify this code by replacing the definitions of ShiftAndInvert
and construct_linear_map
and the call to partialschur
with
F = factorize(A)
linearmap = LinearMap{eltype(A)}((y, x) -> ldiv!(y, F, B * x), size(A,1), ismutating=true)
decomp, = partialschur(linearmap, nev=4, tol=1e-5, restarts=100, which=LM())
When I use my approach in my own work (full disclosure: not these eigenvalue problems specifically), it seems to work fine (e.g., @code_warntype
doesn’t report any type instabilities). So why what appears to me more complicated code?