Search code examples
pythonscipycomplex-numberseigenvalueeigenvector

Scipy eigsh returning wrong results for complex input matrix


I am trying to find the eigenvalues and eigenvectors of a complex matrix with scipy.sparse.linalg.eigsh using its shift-invert mode. With just real numbers in the matrix I get the same result for the spicy.linalg.eigh solver, but when adding the imaginary parts the eigenvalues diverge. A tiny example:

import numpy as np
from scipy.linalg import eigh
from scipy.sparse.linalg import eigsh

n = 10
X = np.random.random((n, n)) - 0.5 + (np.random.random((n, n)) - 0.5) * 1j
X = np.dot(X, X.T)  # create a symmetric matrix

evals_all, evecs_all = eigh(X)
evals_small, evecs_small = eigsh(X, 3, sigma=0, which='LM')

print(sorted(evals_all, key=abs))
print(sorted(evals_small, key=abs))

The prints in this case are for example

[0.041577858515751132, -0.084104744918533481, -0.58668240775486691, 0.63845672501004724, -1.2311727737115068, 1.5193345703630159, -1.8652302423152105, 1.9970059660853923, -2.6414593461321654, 2.8624290667460293]
[-0.017278543470343462, -0.32684893256215408, 0.34551438015659475]

whereas in the real case, the first three eigenvalues are identical.

I am aware that I'm passing a dense matrix to the sparse solver, but this is just intended as an example.

I am probably missing something obvious somewhere, but I'd be happy about some hints where to look. Thank you!


Solution

  • scipy is not checking your input if it's hermitian.

    Doing it like proposed in the link:

    if not np.allclose(X, np.asmatrix(X).H):
        raise ValueError('expected symmetric or Hermitian matrix')
    

    outputs:

    ValueError: expected symmetric or Hermitian matrix
    

    I think this is also indicated by those negative eigenvalues you see (but complex-based math is really not my speciality...).