AI Knowledge Tree

Singular value decomposition

Construct the SVD of any matrix from the spectral theorem applied to AᵀA, and read it as rotate–scale–rotate.

The eigendecomposition applies only to square matrices and only when a full eigenbasis exists. The singular value decomposition extends the same geometry to any matrix, square or rectangular, and always exists[1, 2]. It is the factorization that underlies PCA, low-rank approximation, pseudo-inverses, and numerical rank computation.

Constructing the SVD

Let A∈Rm×nA \in \mathbb{R}^{m \times n}. The matrix A⊤A∈Rn×nA^\top A \in \mathbb{R}^{n \times n} is symmetric and PSD (previous lesson: x⊤A⊤Ax=∥Ax∥2≥0x^\top A^\top A x = \lVert Ax\rVert^2 \ge 0). By the spectral theorem, it has a real orthonormal eigenbasis.

Step 1: diagonalize A⊤AA^\top A.

A⊤A=VΛV⊤,V⊤V=I,Λ=diag⁡(λ1,…,λn),λi≥0.A^\top A = V\Lambda V^\top, \qquad V^\top V = I,\quad \Lambda = \operatorname{diag}(\lambda_1, \dots, \lambda_n),\quad \lambda_i \ge 0.

The eigenvalues are nonnegative by PSD. Order them λ1≥λ2≥⋯≥λn≥0\lambda_1 \ge \lambda_2 \ge \cdots \ge \lambda_n \ge 0. The singular values are σi=λi\sigma_i = \sqrt{\lambda_i}.

Step 2: construct the left singular vectors. For each σi>0\sigma_i > 0, define

ui=1σiAvi.u_i = \frac{1}{\sigma_i} A v_i.

These are unit vectors in Rm\mathbb{R}^m: ∥ui∥2=1σi2∥Avi∥2=1σi2vi⊤A⊤Avi=λiσi2=1\lVert u_i\rVert^2 = \frac{1}{\sigma_i^2} \lVert Av_i\rVert^2 = \frac{1}{\sigma_i^2} v_i^\top A^\top A v_i = \frac{\lambda_i}{\sigma_i^2} = 1.

They are mutually orthogonal: for i≠ji \neq j, ⟨ui,uj⟩=1σiσjvi⊤A⊤Avj=λjσiσj⟨vi,vj⟩=0\langle u_i, u_j\rangle = \frac{1}{\sigma_i\sigma_j} v_i^\top A^\top A v_j = \frac{\lambda_j}{\sigma_i\sigma_j}\langle v_i, v_j\rangle = 0.

Extend {u1,…,ur}\{u_1, \dots, u_r\} (where rr is the rank) to an orthonormal basis {u1,…,um}\{u_1, \dots, u_m\} of Rm\mathbb{R}^m by adding arbitrary orthonormal vectors.

Step 3: write A=UΣV⊤A = U\Sigma V^\top. By construction Avi=σiuiAv_i = \sigma_i u_i for i≤ri \le r and Avi=0Av_i = 0 for i>ri > r (those viv_i lie in ker⁡A\ker A). Collecting into matrices:

A[v1∣⋯∣vn]=[u1∣⋯∣um]Σ,A[v_1 \mid \cdots \mid v_n] = [u_1 \mid \cdots \mid u_m] \Sigma,

i.e. AV=UΣAV = U\Sigma, hence A=UΣV⊤A = U\Sigma V^\top.

Here U∈Rm×mU \in \mathbb{R}^{m \times m} and V∈Rn×nV \in \mathbb{R}^{n \times n} are orthogonal, and Σ∈Rm×n\Sigma \in \mathbb{R}^{m \times n} is zero everywhere except Σii=σi\Sigma_{ii} = \sigma_i for i≤ri \le r.

Geometric interpretation

A=UΣV⊤A = U\Sigma V^\top applied to a vector xx:

  1. V⊤xV^\top x: rotate xx in the domain Rn\mathbb{R}^n.
  2. Σ(V⊤x)\Sigma(V^\top x): scale the ii-th coordinate by σi\sigma_i (and possibly change dimension).
  3. U(ΣV⊤x)U(\Sigma V^\top x): rotate the result in the codomain Rm\mathbb{R}^m.

Every linear map is a rotation, followed by axis-aligned scaling, followed by another rotation. The singular values are the scale factors along the principal axes.

The four fundamental subspaces, revisited

From the SVD with r=rank⁡(A)r = \operatorname{rank}(A):

  • Column space: span⁡(u1,…,ur)\operatorname{span}(u_1, \dots, u_r).
  • Left null space: span⁡(ur+1,…,um)\operatorname{span}(u_{r+1}, \dots, u_m).
  • Row space: span⁡(v1,…,vr)\operatorname{span}(v_1, \dots, v_r).
  • Null space: span⁡(vr+1,…,vn)\operatorname{span}(v_{r+1}, \dots, v_n).

These four subspaces are mutually orthogonal in their respective spaces, and their dimensions satisfy rank + nullity = nn (rank–nullity theorem confirmed).

The SVD factors any matrix as rotate–scale–rotate: it maps the unit circle to an ellipse whose semi-axes are the singular values (ranked at right).
The SVD factors any matrix as rotate–scale–rotate: it maps the unit circle to an ellipse whose semi-axes are the singular values (ranked at right).

Check it on arrays

python · numpy
import numpy as np

A = np.array([[3.0, 2.0, 1.0],
              [0.0, 1.0, 4.0]])   # 2x3 matrix, rank 2

U, s, Vt = np.linalg.svd(A, full_matrices=True)
print("singular values:", np.round(s, 6))
print("U shape:", U.shape, "| Vt shape:", Vt.shape)

# Reconstruct: A = U Sigma V^T
Sigma = np.zeros_like(A)
Sigma[:len(s), :len(s)] = np.diag(s)
A_reconstructed = U @ Sigma @ Vt
print("reconstruction error:", np.max(np.abs(A - A_reconstructed)))   # ~1e-14

# Verify U and V are orthogonal
print("U^T U:\n", np.round(U.T @ U, 10))
print("V^T V:\n", np.round(Vt @ Vt.T, 10))

# Rotate-scale-rotate: trace through on a specific vector
v = np.array([1.0, 0.0, 0.0])
step1 = Vt @ v          # rotate in R^3
step2 = Sigma @ step1   # scale (and reduce to R^2)
step3 = U @ step2       # rotate in R^2
print("A @ v:", A @ v)
print("U Sigma V^T @ v:", np.round(step3, 10))   # same

The reconstruction error is near machine epsilon; both UU and V⊤V^\top pass the orthogonality check.

Exercises

Exercise 1. Compute the singular values of A=[200300]A = \begin{bmatrix} 2 & 0 \\ 0 & 3 \\ 0 & 0 \end{bmatrix} by hand, using A⊤AA^\top A.

Solution

Step 1. Form A⊤AA^\top A, a 2×22 \times 2 matrix:

A⊤A=[200030][200300]=[4009].A^\top A = \begin{bmatrix} 2 & 0 & 0 \\ 0 & 3 & 0 \end{bmatrix} \begin{bmatrix} 2 & 0 \\ 0 & 3 \\ 0 & 0 \end{bmatrix} = \begin{bmatrix} 4 & 0 \\ 0 & 9 \end{bmatrix}.

Step 2. This is already diagonal, so its eigenvalues are λ1=9\lambda_1 = 9 and λ2=4\lambda_2 = 4 (ordered largest first).

Step 3. The singular values are the square roots: σ1=9=3\sigma_1 = \sqrt 9 = 3 and σ2=4=2\sigma_2 = \sqrt 4 = 2. The third row of AA contributes nothing, which is why Σ\Sigma has a zero row in A=UΣV⊤A = U\Sigma V^\top.

Exercise 2. Show that the nonzero singular values of AA equal those of A⊤A^\top, so rank⁡(A)=rank⁡(A⊤)\operatorname{rank}(A) = \operatorname{rank}(A^\top).

Solution

Step 1. Write the SVD A=UΣV⊤A = U\Sigma V^\top with U,VU, V orthogonal. Transpose both sides: A⊤=(UΣV⊤)⊤=VΣ⊤U⊤A^\top = (U\Sigma V^\top)^\top = V \Sigma^\top U^\top.

Step 2. This is a valid SVD of A⊤A^\top: VV and U⊤U^\top are orthogonal, and Σ⊤\Sigma^\top is the (rectangular) diagonal matrix carrying the same diagonal entries σi\sigma_i as Σ\Sigma, only reshaped. So A⊤A^\top has the identical set of singular values.

Step 3. The rank equals the count of nonzero singular values (the number of uiu_i spanning the column space in the lesson). Since AA and A⊤A^\top share that count, rank⁡(A)=rank⁡(A⊤)\operatorname{rank}(A) = \operatorname{rank}(A^\top), which is the row-rank-equals-column-rank fact.

Exercise 3 (code). For a random 4×34 \times 3 matrix, verify that the left singular vectors ui=1σiAviu_i = \tfrac{1}{\sigma_i} A v_i from the construction match the columns of UU that np.linalg.svd returns (up to sign), and that ∥Avi∥=σi\lVert A v_i \rVert = \sigma_i.

Solution

The construction defines ui=Avi/σiu_i = A v_i / \sigma_i, so Avi=σiuiA v_i = \sigma_i u_i and ∥Avi∥=σi∥ui∥=σi\lVert A v_i \rVert = \sigma_i \lVert u_i \rVert = \sigma_i. Each column of UU must match the constructed uiu_i up to an overall sign (an SVD is unique only up to sign on paired singular vectors).

python · numpy
import numpy as np

rng = np.random.default_rng(0)
A = rng.normal(size=(4, 3))

U, s, Vt = np.linalg.svd(A, full_matrices=False)
V = Vt.T

for i, sigma in enumerate(s):
    Av = A @ V[:, i]
    u_constructed = Av / sigma
    # ||A v_i|| == sigma_i
    assert np.isclose(np.linalg.norm(Av), sigma)
    # u_constructed equals column i of U up to a sign flip
    assert np.allclose(u_constructed, U[:, i]) or \
           np.allclose(u_constructed, -U[:, i])

print("singular values:", np.round(s, 6))

Each ∥Avi∥\lVert A v_i \rVert reproduces σi\sigma_i, and the constructed left singular vectors agree with svd's UU up to sign, confirming the Step 2 construction ui=Avi/σiu_i = A v_i / \sigma_i.

With the SVD in hand, the next lesson uses it to find the best rank-kk approximation to AA and to define PCA.


References

  1. [1]Trefethen, L. N., & Bau, D. (1997). Numerical Linear Algebra. SIAM. Existence and geometry of the SVD (Lectures 4-5).↩
  2. [2]Golub, G. H., & Van Loan, C. F. (2013). Matrix Computations (4th ed.). Johns Hopkins University Press. The canonical reference for the SVD and its computation (doi:10.56021/9781421407944).↩