-
-
Notifications
You must be signed in to change notification settings - Fork 5.5k
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
Add syevd LAPACK Hermitian eigensolver #49262
Conversation
Cool. Are there cases where we want to dispatch to this method by default, or do we just want to provide this? |
@jaemolihm The tests introduced for this PR are failing. |
Thank you @ViralBShah , I fixed the test by adding the real symmetric eigensolver interface.
The motivation is just to provide this. Choosing the default is more difficult because the timing also depends on the library used (and possibly on the hardware). |
Is it worth considering providing an option to the eigensolver interface to use this? Could be in a separate PR. |
Yes, it seems useful. Maybe something like below? using LinearAlgebra.LAPACK: syev!, syevd!, syevr!
using LinearAlgebra: RealHermSymComplexHerm, eigencopy_oftype, BlasReal, Eigen, sorteig!, LAPACK, eigtype
import LinearAlgebra: eigen!, eigen
function eigen(A::RealHermSymComplexHerm, method::Symbol; sortby::Union{Function,Nothing}=nothing)
S = eigtype(eltype(A))
eigen!(eigencopy_oftype(A, S), method; sortby)
end
function eigen!(A::RealHermSymComplexHerm{<:BlasReal,<:StridedMatrix}, method::Symbol; sortby::Union{Function,Nothing}=nothing)
if method == :syevr
Eigen(sorteig!(LAPACK.syevr!('V', 'A', A.uplo, A.data, 0.0, 0.0, 0, 0, -1.0)..., sortby)...)
elseif method == :syev
Eigen(sorteig!(LAPACK.syev!('V', A.uplo, A.data)..., sortby)...)
elseif method == :syevd
Eigen(sorteig!(LAPACK.syevd!('V', A.uplo, A.data)..., sortby)...)
else
throw(ArgumentError("Wrong method $method. Must be :syevr or :syev or :syevd."))
end
end |
Yes, something along those lines, but perhaps with slightly more descriptive names? |
Use the divide-and-conquer method, instead of the QR iteration used by | ||
`syev!` or multiple relatively robust representations used by `syevr!`. | ||
See James W. Demmel et al, SIAM J. Sci. Comput. 30, 3, 1508 (2008) for | ||
a comparison of the accuracy and performatce of different methods. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just noticed this typo in performance after merging.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I fixed this typo in the follow up PR #49355.
Added
syevd!
wrapper to LAPACK complex Hermitian eigensolvers zheevd and cheevd.It is more accurate than the existing wrappers (
syev!
,syevr
), and is also the fastest for large matrices (N > 100) with MKL.https://netlib.org/lapack/lawnspdf/lawn183.pdf
This is useful e.g. in JuliaMolSim/DFTK.jl#842
Benchmark (MKL, N = 100)
Benchmark (MKL, N = 1000)
Benchmark code
```julia using LinearAlgebra using BenchmarkTools using MKLfunction test_syev(h, tmp, jobz='V')
tmp .= h
LinearAlgebra.LAPACK.syev!(jobz, 'U', tmp)
end
function test_syevr(h, tmp, jobz='V')
tmp .= h
LinearAlgebra.LAPACK.syevr!(jobz, tmp)
end
function test_syevd(h, tmp, jobz='V')
tmp .= h
LinearAlgebra.LAPACK.syevd!(jobz, 'U', tmp)
end
N = 1000
T = Float64
h = rand(Complex{T}, N, N);
h .+= h';
tmp = zeros(Complex{T}, N, N);
@Btime test_syev($h, $tmp);
@Btime test_syevr($h, $tmp);
@Btime test_syevd($h, $tmp);
e, v = LinearAlgebra.LAPACK.syev!('V', 'U', copy(h));
@info norm(v' * v - I)
e, v = LinearAlgebra.LAPACK.syevr!('V', copy(h));
@info norm(v' * v - I)
e, v = LinearAlgebra.LAPACK.syevd!('V', 'U', copy(h));
@info norm(v' * v - I)