Eigenvalue and Singular Value Decomposition
Eigenvalues: The DNA of a Matrix
Eigenvalue decomposition reveals the intrinsic geometry of a linear transformation — its principal axes and scaling factors. In wireless communications, the eigenvalues of the channel correlation matrix determine the spatial degrees of freedom, the singular values of the channel matrix determine the capacity of each spatial stream, and PCA (principal component analysis) is eigendecomposition of the sample covariance.
Definition: Eigenvalue Decomposition
Eigenvalue Decomposition
A square matrix has eigenvalue decomposition , where is an eigenvalue and is the corresponding eigenvector. If is diagonalizable:
where .
eigenvalues, V = np.linalg.eig(A) # general matrix
eigenvalues, V = np.linalg.eigh(A) # Hermitian/symmetric
eigh is preferred when because it
guarantees real eigenvalues, orthogonal eigenvectors, and is
faster than eig (exploits symmetry via the divide-and-conquer algorithm).
Definition: Singular Value Decomposition (SVD)
Singular Value Decomposition (SVD)
Any matrix (not necessarily square) admits a factorization:
where (left singular vectors), (singular values on the diagonal), and (right singular vectors).
U, s, Vh = np.linalg.svd(A, full_matrices=True) # full SVD
U, s, Vh = np.linalg.svd(A, full_matrices=False) # reduced SVD
The reduced SVD returns , , where .
The singular values are always real and non-negative: . The eigenvalues of are .
Definition: Condition Number
Condition Number
The condition number of a matrix (in the 2-norm) is the ratio of its largest to smallest singular value:
kappa = np.linalg.cond(A)
# or equivalently:
s = np.linalg.svd(A, compute_uv=False)
kappa = s[0] / s[-1]
A matrix with is well-conditioned (stable to solve). A matrix with is ill-conditioned (solutions are sensitive to perturbations). For double precision, roughly digits of accuracy are lost in solving .
Definition: Numerical Rank
Numerical Rank
The numerical rank of a matrix is the number of singular values above a threshold :
In NumPy:
rank = np.linalg.matrix_rank(A) # default tolerance
rank = np.linalg.matrix_rank(A, tol=1e-6) # custom tolerance
The default tolerance is .
Theorem: Eckart-Young-Mirsky Theorem (Best Low-Rank Approximation)
The best rank- approximation to in the Frobenius (or spectral) norm is obtained by keeping only the largest singular values:
The approximation error is:
The SVD sorts the "information content" of a matrix by singular value. Truncating at rank keeps the most important components and discards the rest. This is the mathematical basis for PCA, image compression, and low-rank channel approximations.
Theorem: Spectral Theorem for Hermitian Matrices
A Hermitian matrix has:
- All real eigenvalues
- Orthogonal eigenvectors:
- Eigendecomposition
For a positive semidefinite (PSD) matrix, all eigenvalues are . For a positive definite (PD) matrix, all eigenvalues are .
Hermitian matrices are the complex generalization of real symmetric matrices. They appear everywhere in wireless: covariance matrices , Gram matrices , and correlation matrices are all Hermitian PSD.
Theorem: SVD-Eigenvalue Connection
For any :
- The singular values of are the square roots of the eigenvalues of (or ).
- The right singular vectors are the eigenvectors of .
- The left singular vectors are the eigenvectors of .
From SVD to eigendecomposition
If , then: which is the eigendecomposition of .
Example: Eigendecomposition of a Channel Covariance Matrix
Construct a spatial correlation matrix for a uniform linear array (ULA) with correlation coefficient . Compute its eigendecomposition and verify the spectral theorem.
Build the correlation matrix
import numpy as np
N = 4
rho = 0.7
# Exponential correlation model: R[i,j] = rho^|i-j|
R = np.array([[rho ** abs(i - j) for j in range(N)] for i in range(N)])
print("R =\n", R)
Eigendecompose with eigh
eigenvalues, V = np.linalg.eigh(R)
print(f"Eigenvalues: {eigenvalues}")
print(f"Sum of eigenvalues: {np.sum(eigenvalues):.4f}")
print(f"Trace of R: {np.trace(R):.4f}")
# Verify: V V^H = I (orthogonality)
print(f"V^H V = I? {np.allclose(V.conj().T @ V, np.eye(N))}")
# Verify: R = V Lambda V^H (reconstruction)
R_reconstructed = V @ np.diag(eigenvalues) @ V.conj().T
print(f"Reconstruction error: {np.linalg.norm(R - R_reconstructed):.2e}")
Example: Low-Rank Approximation via SVD
Approximate a matrix with a rank-5 version and measure the relative approximation error. Show how the error decreases as the rank increases.
SVD and truncation
import numpy as np
np.random.seed(42)
A = np.random.randn(100, 100)
U, s, Vh = np.linalg.svd(A, full_matrices=False)
for k in [1, 2, 5, 10, 20, 50]:
A_k = (U[:, :k] * s[:k]) @ Vh[:k, :]
rel_error = np.linalg.norm(A - A_k, 'fro') / np.linalg.norm(A, 'fro')
energy = np.sum(s[:k]**2) / np.sum(s**2) * 100
print(f"Rank {k:3d}: relative error = {rel_error:.4f}, "
f"energy captured = {energy:.1f}%")
Key insight
The Eckart-Young theorem guarantees this is the best possible rank- approximation. In practice, many real-world matrices (images, channel matrices with limited scattering) have rapidly decaying singular values, so a small captures most of the energy.
Example: Comparing eig and eigh for Hermitian Matrices
Generate a random Hermitian matrix and compare the results of
np.linalg.eig vs np.linalg.eigh. Verify that eigh returns
sorted real eigenvalues and is faster.
Comparison
import numpy as np
import time
N = 500
np.random.seed(42)
A = np.random.randn(N, N) + 1j * np.random.randn(N, N)
A = (A + A.conj().T) / 2 # make Hermitian
# eig (general)
t0 = time.perf_counter()
vals_eig, vecs_eig = np.linalg.eig(A)
t_eig = time.perf_counter() - t0
# eigh (Hermitian)
t0 = time.perf_counter()
vals_eigh, vecs_eigh = np.linalg.eigh(A)
t_eigh = time.perf_counter() - t0
print(f"eig time: {t_eig:.4f}s, max imag in eigenvalues: "
f"{np.max(np.abs(np.imag(vals_eig))):.2e}")
print(f"eigh time: {t_eigh:.4f}s, eigenvalues are real by construction")
print(f"Speedup: {t_eig/t_eigh:.1f}x")
Eigenvalue Decomposition Explorer
Visualize eigenvalues and eigenvectors of a 2x2 or 3x3 matrix. See how changing matrix entries affects the eigenvalue spectrum and eigenvector directions.
Parameters
SVD Low-Rank Approximation (Animated)
Watch a matrix being reconstructed as rank-1, rank-2, ... components are added. See the singular value spectrum and the reconstruction error decrease with each added component.
Parameters
eig vs eigh vs svd
| Property | np.linalg.eig | np.linalg.eigh | np.linalg.svd |
|---|---|---|---|
| Input | Any square matrix | Hermitian/symmetric only | Any matrix (m x n) |
| Eigenvalues | Complex, unsorted | Real, sorted ascending | Real non-negative, sorted descending |
| Eigenvectors | Not necessarily orthogonal | Orthonormal | Two sets: U and V, orthonormal |
| LAPACK routine | geev | heev / syev | gesdd |
| Complexity | but ~3x faster | or | |
| Use when | General eigenproblems | Covariance, correlation, Gram matrices | Any matrix, rank, pseudoinverse |
eigenvalue
A scalar such that for some nonzero vector . Eigenvalues characterize the scaling behavior of a linear transformation.
Related: singular value
singular value
The non-negative square roots of the eigenvalues of . Singular values measure the "gain" of a matrix along its principal directions.
Related: eigenvalue
Common Mistake: Using eig for Hermitian Matrices
Mistake:
Using np.linalg.eig on a matrix that is known to be Hermitian
(e.g., covariance matrix ).
Correction:
Use np.linalg.eigh for Hermitian matrices. It is faster, returns
real eigenvalues (no spurious imaginary parts), and guarantees
orthogonal eigenvectors. eig on a Hermitian matrix may return
eigenvalues with small imaginary parts due to roundoff.
Why This Matters: SVD Precoding for MIMO
In MIMO with channel state information at the transmitter (CSIT), the SVD of enables optimal precoding. By transmitting and receiving , the MIMO channel decomposes into parallel scalar channels: The singular values determine the gain on each stream. Water-filling across these streams achieves the channel capacity.
Historical Note: The SVD: From Beltrami to Big Data
The singular value decomposition was independently discovered by Eugenio Beltrami (1873) and Camille Jordan (1874). Gene Golub and William Kahan developed the modern computational algorithm in 1965. Today, SVD underpins recommender systems (Netflix Prize), natural language processing (latent semantic analysis), image compression, and MIMO wireless — one of the most versatile tools in all of applied mathematics.
Quick Check
When should you use np.linalg.eigh instead of np.linalg.eig?
When the matrix is Hermitian (or real symmetric)
When you want complex eigenvalues
When the matrix is rectangular
Always — eigh is a strict upgrade over eig
eigh exploits the Hermitian structure for speed and guaranteed real eigenvalues.
Key Takeaway
SVD is the Swiss Army knife of linear algebra. It works on any matrix (square or rectangular, real or complex), reveals the rank, condition number, range, and null space, provides the optimal low-rank approximation, and forms the basis for the pseudoinverse. When in doubt, compute the SVD.
Eigenvalue Applications
# Code from: ch06/python/eigenvalue_applications.py
# Load from backend supplements endpoint