I am trying to get the eigenvalues of a positive semi-definite matrix in Python using numpy.
All eigenvalues should be non-negative and real. The minimum eigenvalue should be zero. Sometimes, numpy.eig
returns complex values as eigenvalues even when they're supposed to be real (although the complex numbers have 0j
in the imaginary part). To a related SO question, the accepted answer suggests using numpy.eigh
instead of numpy.eig
. I tried numpy.eigh
but it produces incorrect results: in the second case in the MEW below, the smallest eigenvalue is not zero.
I know that numpy.eigh
is for a complex Hermitian or a real symmetric matrix. The second case below is none of these. But it seems numpy.eig
is known to return complex eigenvalues even in cases where it shouldn't (see linked question)! What should one do?
MWE (see output for second case):
import numpy as np
from numpy.random import RandomState
rng = RandomState(123456)
num_v = 4
weights = rng.uniform(0, 1, num_v * num_v).reshape((num_v, num_v))
weights = np.tril(weights) + np.triu(weights.T, 1)
np.fill_diagonal(weights, 0)
degrees = weights.sum(axis=0)
degrees_rw = 1 / degrees
D_rw = np.diag(degrees_rw)
degrees = 1 / np.sqrt(degrees)
D = np.diag(degrees)
I = np.eye(num_v)
laplacian = I - np.matmul(np.dot(D, weights), D)
laplacian_rw = I - np.matmul(D_rw, weights)
eigs1, _ = np.linalg.eig(laplacian)
eigs2, _ = np.linalg.eigh(laplacian)
print(np.sort(eigs1)[:10], "\n", np.sort(eigs2)[:10])
eigs1, _ = np.linalg.eig(laplacian_rw)
eigs2, _ = np.linalg.eigh(laplacian_rw)
print("\n", np.sort(eigs1)[:10], "\n", np.sort(eigs2)[:10])
Here's the output:
[0. 1.01712657 1.40644541 1.57642803]
[-1.08192365e-16 1.01712657e+00 1.40644541e+00 1.57642803e+00]
[-2.22044605e-16 1.01712657e+00 1.40644541e+00 1.57642803e+00]
[0.08710134 1.01779168 1.38159284 1.51351414]
Could someone please help me with this?
EDIT: previously, the graph in the MWE was directed. I edited the question with an undirected graph.