Skip to content

*syevr eigenvalues depend on whether eigenvectors are computed or not #997

Closed
@ev-br

Description

@ev-br

Naively, I'd expect that computed eigenvalues are exactly same whether eigenvectors are computed or not. However, for the symmetric dsyevr solver, this does not seem to be the case. The difference is "small", however it is very visible for e.g. when an eigenvalue is zero is exact arithmetics. Consider the following matrix

 1   -1    0
-1    2   -1
 0   -1    1

with the exact eigenvalues 0, 1, and 3.

Using dsyevr (the driver is below the fold) produces

 jobz = "V" info =            0
 w =    2.6645352591003757E-015   1.0000000000000018        3.0000000000000000     
 jobz = "N" info =            0
 w =    3.9250536344271737E-017  0.99999999999999978        3.0000000000000000  

Note the difference in the "zero" eigenvalue.

The questions is whether my expectation (jobz='N' is exactly equivalent to "run with jobz='V', discard eigenvectors") is too strong, or if it is a potentially fixable defect?

The origin of this question is scipy/scipy#12515

$ cat syevr.f90 
implicit none

integer, parameter :: n = 3
integer, parameter :: lda = n
real*8 :: a(lda, n)
real*8 :: abstol
real*8 :: vl, vu
integer :: il, iu
character*1 :: jobz

! outputs
integer :: m
integer :: ldz = n
real*8 :: w(1:n)
real*8 :: z(n, n)
integer :: isuppz(1:2*n)

integer :: lwork = 100
real*8 :: work(1:100)

integer :: liwork = 100
integer :: iwork(1:100)
integer :: info

external :: dsyevr

a(1, :) = (/ 1., -1., 0. /)
a(2, :) = (/ -1, 2, -1 /)
a(3, :) = (/ 0, -1, 1 /)

! not referenced when range='A'
vl = 0.d0
vu = 3.d0

il = 1
iu = n

abstol = 0.0d0

jobz = 'V'
call dsyevr(jobz, 'A', 'U', n, a, lda, vl, vu, il, iu, abstol, m, w, z, ldz, isuppz, work, lwork, iwork, liwork, info) 
print*, "jobz = ", jobz, "info = ", info
print*, "w = ", w

jobz = 'N'
call dsyevr(jobz, 'A', 'U', n, a, lda, vl, vu, il, iu, abstol, m, w, z, ldz, isuppz, work, lwork, iwork, liwork, info) 
print*, "jobz = ", jobz, "info = ", info
print*, "w = ", w

end

$ gfortran syevr.f90 -lblas -llapack
$ ./a.out 
 jobz = Vinfo =            0
 w =    2.6645352591003757E-015   1.0000000000000018        3.0000000000000000     
 jobz = Ninfo =            0
 w =    3.9250536344271737E-017  0.99999999999999978        3.0000000000000000 

with

$ gfortran --version
GNU Fortran (conda-forge gcc 12.3.0-5) 12.3.0
Copyright (C) 2022 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

and

$ mamba list |grep lapack
lapack                    3.9.0                    netlib    conda-forge
liblapack                 3.9.0           5_h92ddd45_netlib    conda-forge
liblapacke                3.9.0           5_h92ddd45_netlib    conda-forge

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions