Skip to content

Eigenvalues

Compute eigenvalues and eigenvectors using np.linalg.

np.linalg.eig

1. Basic Usage

import numpy as np

def main():
    A = np.array([[4, 2],
                  [1, 3]])

    eigenvalues, eigenvectors = np.linalg.eig(A)

    print(f"Eigenvalues: {eigenvalues}")
    print()
    print("Eigenvectors (columns):")
    print(eigenvectors)

if __name__ == "__main__":
    main()

2. Mathematical Form

\(A v = \lambda v\)

where \(\lambda\) is eigenvalue, \(v\) is eigenvector.

3. Verify Result

import numpy as np

def main():
    A = np.array([[4, 2],
                  [1, 3]])

    eigenvalues, eigenvectors = np.linalg.eig(A)

    for i in range(len(eigenvalues)):
        lam = eigenvalues[i]
        v = eigenvectors[:, i]

        # A @ v should equal lam * v
        Av = A @ v
        lam_v = lam * v

        print(f"λ_{i} = {lam:.4f}")
        print(f"A @ v = {Av}")
        print(f"λ * v = {lam_v}")
        print(f"Match: {np.allclose(Av, lam_v)}")
        print()

if __name__ == "__main__":
    main()

np.linalg.eigvals

1. Eigenvalues Only

import numpy as np

def main():
    A = np.array([[4, 2],
                  [1, 3]])

    eigenvalues = np.linalg.eigvals(A)

    print(f"Eigenvalues: {eigenvalues}")

if __name__ == "__main__":
    main()

2. Faster Computation

Use when only eigenvalues are needed, not eigenvectors.

3. Complex Eigenvalues

import numpy as np

def main():
    # Rotation matrix has complex eigenvalues
    theta = np.pi / 4
    A = np.array([[np.cos(theta), -np.sin(theta)],
                  [np.sin(theta), np.cos(theta)]])

    eigenvalues = np.linalg.eigvals(A)

    print(f"Eigenvalues: {eigenvalues}")
    print(f"Magnitude: {np.abs(eigenvalues)}")

if __name__ == "__main__":
    main()

np.linalg.eigh

1. Symmetric Matrices

Specialized for symmetric (Hermitian) matrices.

import numpy as np

def main():
    # Symmetric matrix
    A = np.array([[4, 2, 1],
                  [2, 5, 3],
                  [1, 3, 6]])

    eigenvalues, eigenvectors = np.linalg.eigh(A)

    print(f"Eigenvalues: {eigenvalues}")
    print()
    print("Eigenvectors:")
    print(eigenvectors)

if __name__ == "__main__":
    main()

2. Real Eigenvalues

Symmetric matrices always have real eigenvalues.

import numpy as np

def main():
    A = np.array([[4, 2],
                  [2, 3]])

    # eigh guarantees real eigenvalues
    eigenvalues, eigenvectors = np.linalg.eigh(A)

    print(f"Eigenvalues (real): {eigenvalues}")
    print(f"Dtype: {eigenvalues.dtype}")

if __name__ == "__main__":
    main()

3. Orthogonal Eigenvectors

import numpy as np

def main():
    A = np.array([[4, 2, 1],
                  [2, 5, 3],
                  [1, 3, 6]])

    eigenvalues, V = np.linalg.eigh(A)

    # Eigenvectors are orthonormal
    print("V^T @ V =")
    print(np.round(V.T @ V, 10))

if __name__ == "__main__":
    main()

Sorted Eigenvalues

1. eigh Returns Sorted

import numpy as np

def main():
    A = np.array([[5, 2],
                  [2, 3]])

    # eigh returns eigenvalues in ascending order
    eigenvalues, eigenvectors = np.linalg.eigh(A)

    print(f"Eigenvalues (sorted): {eigenvalues}")

if __name__ == "__main__":
    main()

2. Sort eig Results

import numpy as np

def main():
    A = np.array([[5, 2],
                  [2, 3]])

    eigenvalues, eigenvectors = np.linalg.eig(A)

    # Sort by eigenvalue magnitude
    idx = np.argsort(np.abs(eigenvalues))[::-1]
    eigenvalues = eigenvalues[idx]
    eigenvectors = eigenvectors[:, idx]

    print(f"Sorted eigenvalues: {eigenvalues}")

if __name__ == "__main__":
    main()

3. Largest Eigenvalue

import numpy as np

def main():
    np.random.seed(42)
    A = np.random.randn(5, 5)
    A = A @ A.T  # Make symmetric positive semi-definite

    eigenvalues, eigenvectors = np.linalg.eigh(A)

    # Largest eigenvalue is last (eigh sorts ascending)
    largest_val = eigenvalues[-1]
    largest_vec = eigenvectors[:, -1]

    print(f"Largest eigenvalue: {largest_val:.4f}")
    print(f"Corresponding eigenvector: {largest_vec}")

if __name__ == "__main__":
    main()

Spectral Decomposition

1. Diagonalization

\(A = V \Lambda V^{-1}\)

import numpy as np

def main():
    A = np.array([[4, 2],
                  [1, 3]])

    eigenvalues, V = np.linalg.eig(A)
    Lambda = np.diag(eigenvalues)

    # Reconstruct A
    A_reconstructed = V @ Lambda @ np.linalg.inv(V)

    print("Original A:")
    print(A)
    print()
    print("V @ Λ @ V^(-1):")
    print(np.real(A_reconstructed).round(10))

if __name__ == "__main__":
    main()

2. Symmetric Case

\(A = V \Lambda V^T\) (V is orthogonal)

import numpy as np

def main():
    A = np.array([[4, 2],
                  [2, 3]])

    eigenvalues, V = np.linalg.eigh(A)
    Lambda = np.diag(eigenvalues)

    # Reconstruct (V is orthogonal, so V^(-1) = V^T)
    A_reconstructed = V @ Lambda @ V.T

    print("Original A:")
    print(A)
    print()
    print("V @ Λ @ V^T:")
    print(A_reconstructed.round(10))

if __name__ == "__main__":
    main()

3. Matrix Power

import numpy as np

def main():
    A = np.array([[4, 2],
                  [2, 3]])

    eigenvalues, V = np.linalg.eigh(A)

    # A^10 = V @ Λ^10 @ V^T
    Lambda_10 = np.diag(eigenvalues ** 10)
    A_10 = V @ Lambda_10 @ V.T

    print("A^10 via eigendecomposition:")
    print(A_10.round(2))
    print()
    print("A^10 via matrix_power:")
    print(np.linalg.matrix_power(A, 10).round(2))

if __name__ == "__main__":
    main()

Applications

1. Principal Components

import numpy as np

def main():
    np.random.seed(42)

    # Generate correlated data
    X = np.random.randn(100, 3)
    X[:, 1] = X[:, 0] + 0.1 * np.random.randn(100)

    # Center data
    X_centered = X - X.mean(axis=0)

    # Covariance matrix
    cov = np.cov(X_centered.T)

    # Eigendecomposition
    eigenvalues, eigenvectors = np.linalg.eigh(cov)

    # Sort descending
    idx = np.argsort(eigenvalues)[::-1]
    eigenvalues = eigenvalues[idx]
    eigenvectors = eigenvectors[:, idx]

    print("Eigenvalues (variance explained):")
    print(eigenvalues)
    print()
    print("Variance ratios:")
    print(eigenvalues / eigenvalues.sum())

if __name__ == "__main__":
    main()

2. Graph Laplacian

import numpy as np

def main():
    # Adjacency matrix
    A = np.array([[0, 1, 1, 0],
                  [1, 0, 1, 1],
                  [1, 1, 0, 1],
                  [0, 1, 1, 0]])

    # Degree matrix
    D = np.diag(A.sum(axis=1))

    # Laplacian
    L = D - A

    eigenvalues, eigenvectors = np.linalg.eigh(L)

    print("Laplacian eigenvalues:", eigenvalues.round(4))
    print("Second smallest (algebraic connectivity):", eigenvalues[1])

if __name__ == "__main__":
    main()

3. Stability Analysis

import numpy as np

def main():
    # System matrix
    A = np.array([[-1, 2],
                  [-1, -1]])

    eigenvalues = np.linalg.eigvals(A)

    print(f"Eigenvalues: {eigenvalues}")
    print(f"Real parts: {eigenvalues.real}")

    # System is stable if all real parts are negative
    is_stable = np.all(eigenvalues.real < 0)
    print(f"System is stable: {is_stable}")

if __name__ == "__main__":
    main()

Best Practices

1. Use eigh for Symmetric

eigh is faster and more numerically stable for symmetric matrices.

2. Check Matrix Properties

Verify symmetry before using eigh.

import numpy as np

def main():
    A = np.array([[4, 2],
                  [2, 3]])

    is_symmetric = np.allclose(A, A.T)
    print(f"Is symmetric: {is_symmetric}")

if __name__ == "__main__":
    main()

3. Handle Complex Results

eig may return complex eigenvalues even for real matrices.