EVERYTHING AIAI engineering, made visual
0/23 complete
LESSON 11 · MATHEMATICS × AI · BUILD

Any matrix is just
rotate, stretch, rotate.

A = U Σ Vᵀ says every matrix — square or not, invertible or not — is a rotation of the input, a stretch along perpendicular axes, then a rotation into the output. The stretch factors are the singular values.

75 MIN · 8 CHAPTERSPREREQ · LESSONS 01–03
FIG. 11 / Vᵀ, THEN Σ, THEN U
Vᵀ · ROTATE INPUT v₁ v₂
LESSON 11TYPE · BUILD~75 MINPREREQ · LESSONS 01–03ORIGINAL LESSON ↗
01 / ROTATE, SCALE, ROTATE

Every matrix performs three simple moves.

SVD writes an m × n matrix as a rotation of the input (Vᵀ), a stretch along perpendicular axes (Σ), and a rotation into the output (U). A unit circle becomes an ellipse; the singular values are its axis lengths. Nothing more exotic ever happens.

A = U Σ Vᵀ · (m×m)(m×n)(n×n)
02 / STRETCH FACTORS, RANKED

Singular values come sorted, and rank is how many are non-zero.

σ₁ ≥ σ₂ ≥ … ≥ σᵣ > 0. Each σᵢ says how far the matrix stretches its i-th principal direction; the number of non-zero values is the rank. A tiny σ is a direction the matrix nearly crushes — and nearly crushing is what makes compression possible.

σ₁ ≥ σ₂ ≥ … ≥ σᵣ > 0 · r = rank(A)
03 / KEEP THE BIG PATTERNS

Add the top-k pieces and you have the best rank-k copy.

Multiplying out U Σ Vᵀ gives a sum of rank-1 pieces: A = σ₁u₁v₁ᵀ + σ₂u₂v₂ᵀ + … . Keep the first k terms and discard the rest. Eckart–Young guarantees no other rank-k matrix is closer to A — and the leftover is exactly the singular values you dropped.

A_k = σ₁u₁v₁ᵀ + … + σₖuₖvₖᵀ
MENTAL MODEL IN ONE SENTENCE

Every matrix is a recipe — rotate the input into its natural directions, stretch each direction by a singular value, rotate into the output — and a low-rank approximation is simply refusing to perform the small stretches.

By the end you will be able to read U, Σ and Vᵀ off any shape, explain what a singular value measures, tell SVD from eigendecomposition (and why SVD wins for data), compress a matrix by keeping the top k patterns without losing the picture, and solve a least-squares fit with the pseudoinverse.

ROTATE, SCALE, ROTATE

Every matrix is
three simple moves.

Eigendecomposition demands a square matrix with a full set of independent eigenvectors. SVD demands nothing. Any matrix, any shape, any rank: rotate the input, stretch along perpendicular axes, rotate into the output.

The singular value decomposition of an m × n matrix A is A = U Σ Vᵀ, where U is m × m orthogonal, Σ is m × n with non-negative numbers on the diagonal, and V is n × n orthogonal. “Orthogonal” means the columns are perpendicular unit vectors, so the matrix is a pure rotation (possibly with a flip), and its transpose undoes it.

Plain English: read the product right to left. Vᵀ rotates the input space so the directions the matrix cares about line up with the coordinate axes. Σ then stretches or shrinks each axis by its singular value. U rotates the result into the output space. A sphere of unit inputs becomes an ellipsoid; the singular values are the ellipsoid’s axis lengths.

A = U · Σ · Vᵀ m×n m×m m×n n×n (any) rotate scale rotate Vᵀ rotates the input: rows are the right singular vectors vᵢ, an orthonormal basis of the input space ℝⁿ Σ scales axis i by σᵢ ≥ 0 (diagonal, sorted largest first) U rotates into the output: columns are the left singular vectors uᵢ, an orthonormal basis of the output space ℝᵐ A vᵢ = σᵢ uᵢ "take input direction vᵢ, stretch by σᵢ, land on output direction uᵢ"

The three stages, live

Set the four entries of a 2 × 2 matrix, then press play. The unit circle is rotated by Vᵀ, stretched by Σ, and rotated by U into the ellipse that A alone would have produced.

A =
σ = [3.000, 1.000] rank = 2 (full rank) det A = 3.000 κ(A) = σ₁/σ₂ = 3.000 A v₁ = σ₁ u₁: input direction v₁ lands on output direction u₁, stretched by σ₁. The ellipse axes are exactly σ₁ and σ₂.

Try [[1, 1], [1, 1]]: σ = [2, 0] and the circle collapses to a line segment. Try [[0, −1], [1, 0]]: σ = [1, 1], a pure rotation.

Derivation: where U, Σ and V come from — with a full 2 × 2 example
  1. Suppose A = UΣVᵀ with U and V orthogonal, so UᵀU = I and VᵀV = I. Multiply AᵀA out: (UΣVᵀ)ᵀ(UΣVᵀ) = VΣᵀUᵀUΣVᵀ = V(ΣᵀΣ)Vᵀ, and ΣᵀΣ is diagonal with the squared singular values on it.
  2. That is an eigendecomposition: AᵀA = V diag(σᵢ²) Vᵀ. So the columns of V are the eigenvectors of AᵀA and σᵢ = √(eigenvalueᵢ). AᵀA is symmetric, so its eigenvalues are real and never negative — the square roots are safe.
  3. The same trick on AAᵀ = U diag(σᵢ²) Uᵀ shows the columns of U are the eigenvectors of AAᵀ. Or skip it entirely and recover each uᵢ = A vᵢ / σᵢ, straight from A vᵢ = σᵢ uᵢ.
Example A = [[3, 0], [4, 5]] AᵀA = [[3,4],[0,5]] @ [[3,0],[4,5]] = [[25, 20], [20, 25]] characteristic equation: λ² − 50λ + (625 − 400) = λ² − 50λ + 225 = (λ − 45)(λ − 5) = 0 σ₁ = √45 = 6.7082 σ₂ = √5 = 2.2361 check: σ₁σ₂ = 6.7082 · 2.2361 = 15 = |det A| = |3·5 − 0·4| ✓ eigenvector for 45: [[−20,20],[20,−20]]v = 0 → v₁ = [0.7071, 0.7071] eigenvector for 5: [[ 20,20],[20, 20]]v = 0 → v₂ = [0.7071, −0.7071] u₁ = A v₁ / σ₁ = [2.1213, 6.3640] / 6.7082 = [0.3162, 0.9487] u₂ = A v₂ / σ₂ = [2.1213, −0.7071] / 2.2361 = [0.9487, −0.3162] u₁ · u₂ = 0.3000 − 0.3000 = 0 ✓ perpendicular, as promised reconstruction check, entry by entry: (1,1): 6.7082·0.3162·0.7071 + 2.2361·0.9487·0.7071 = 1.5000 + 1.5000 = 3 ✓ (1,2): 6.7082·0.3162·0.7071 + 2.2361·0.9487·(−0.7071) = 1.5000 − 1.5000 = 0 ✓ (2,1): 6.7082·0.9487·0.7071 + 2.2361·(−0.3162)·0.7071 = 4.5000 − 0.5000 = 4 ✓ (2,2): 6.7082·0.9487·0.7071 + 2.2361·(−0.3162)·(−0.7071) = 4.5000 + 0.5000 = 5 ✓ ‖A‖_F = √(9 + 0 + 16 + 25) = √50 = 7.0711 = √(45 + 5) ✓

Reading it geometrically: this matrix stretches the diagonal direction [1, 1] by 6.7 and the anti-diagonal by only 2.2, then tilts the result. The unit circle becomes an ellipse whose long axis is 6.7 and whose short axis is 2.2. The ratio σ₁/σ₂ = 3 tells you how elongated it is.

Quick check

A = U Σ Vᵀ. Which factor touches the input vector first when you compute A x?

THE THREE FACTORS

Two rotations
and one stretch.

U, Σ and Vᵀ each carry a job and a shape. Once you can say what lives in each factor, an SVD in someone’s code stops being a black box.

Vᵀ — the input rotation. Its rows are the right singular vectors v₁ … vₙ, an orthonormal basis of the input space. They are the directions in which the matrix acts independently: feed in vᵢ and the output is perpendicular to the output of every other vⱼ.

Σ — the stretch. Diagonal entries σ₁ ≥ σ₂ ≥ … ≥ 0. For a non-square matrix there are zeros beyond the min(m, n) positions, which is why the economy version throws them away.

U — the output rotation. Its columns are the left singular vectors u₁ … uₘ, an orthonormal basis of the output space. The pair is tied together by one equation: A vᵢ = σᵢ uᵢ.

orthogonality checks: UᵀU = I VᵀV = I (every column has length 1; different columns are perpendicular) reading the shapes (full → economy): A (m×n) = U (m×m) · Σ (m×n) · Vᵀ (n×n) = U (m×r) · Σ (r×r) · Vᵀ (r×n), r = min(m, n) the r×r block holds every non-zero σ; the rest of Σ is forced zeros

Shape console: no zero padding required

Move the sliders. Full SVD stores two big square rotations and a rectangular stretch; the economy version drops the dead zero block and keeps only the r = min(m, n) useful directions.

A · 5×3the data: any shape, any rank
=
U · 5×5left singular vectors: orthonormal output basis
·
Σ · 5×3σ₁ … σ3 on the diagonal; 0 forced zeros
·
Vᵀ · 3×3right singular vectors: orthonormal input basis
A is 5 × 3, so rank(A) ≤ min(5, 3) = 3 FULL shapes: U (5×5) Σ (5×3) Vᵀ (3×3) numbers stored: 5² + 5·3 + 3² = 49 Σ contains 0 forced zeros past row/col 3 ECONOMY shapes: U (5×3) Σ (3×3) Vᵀ (3×3) numbers stored: 5·3 + 3² + 3·3 = 33 (A itself stores 15)

NumPy returns the economy version when you pass full_matrices=False. The full U and V are enormous for tall matrices: a 1,000,000 × 100 matrix would store a million-by- million rotation it never needs.

Worked check: A is 3 × 2, not square A = [[1, 0], [0, 1], [1, 1]] AᵀA = [[2, 1], [1, 2]] → λ = 3 and 1 → σ = [√3 = 1.7321, 1] v₁ = [0.7071, 0.7071] v₂ = [0.7071, −0.7071] u₁ = A v₁ / σ₁ = [0.7071, 0.7071, 1.4142] / 1.7321 = [0.4082, 0.4082, 0.8165] (3 numbers: output space!) u₂ = A v₂ / σ₂ = [0.7071, −0.7071, 0] / 1 checks: ‖u₁‖ = √(0.1667 + 0.1667 + 0.6667) = 1 ✓ u₁ · u₂ = 0.2887 − 0.2887 + 0 = 0 ✓ ‖A‖_F = √(1 + 0 + 0 + 1 + 1 + 1) = 2 = √(3 + 1) ✓

The aha: the three factors are not three matrices you have to memorise — they are a coordinate system for the input (V), a list of how much each coordinate matters (Σ), and a coordinate system for the output (U). Change the basis, and every matrix becomes a diagonal scaling. That is the whole trick.

STRETCH FACTORS, RANKED

How big the stretch is
decides what matters.

The singular values are a size ranking of the directions a matrix uses. Their squares add up to the matrix’s total energy, which is what makes “keep the top k” a measurable promise instead of a hunch.

A singular value σᵢ is the length of the i-th semi-axis of the ellipse that the unit sphere becomes. It is always a non-negative real number, and the list is always sorted from largest to smallest. If σᵢ is zero, that direction was crushed completely: the matrix maps it to the zero vector, and it is not part of the matrix’s rank.

Plain English: the singular values tell you how much room the matrix actually uses. Count the non-zero ones and you have the rank. Square them and add, and you have the matrix’s energy — the quantity that low-rank approximation tries to preserve.

σ₁ ≥ σ₂ ≥ … ≥ σᵣ > 0, r = rank(A), σᵣ₊₁ = … = 0 σᵢ = length of the i-th axis of the image ellipsoid = how far A stretches along the input direction vᵢ energy identities (all exact): ‖A‖_F² = σ₁² + σ₂² + … + σᵣ² trace(AᵀA) = σ₁² + σ₂² + … + σᵣ² (sum of squared entries) |det A| = σ₁ · σ₂ · … · σₙ (square A only) κ(A) = σ_max / σ_min (condition number)

The spectrum tells you how compressible a matrix is

Same size matrix, three kinds of structure. Slide k and watch how much of the energy the top k singular values carry: fast decay means a small k already captures almost everything.

σ = [8.000, 4.000, 2.000, 1.000, 0.500, 0.250, 0.125, 0.060] energy kept Σ_{i≤k} σᵢ² / Σ σᵢ² = 99.61% relative error ‖A − A_k‖_F / ‖A‖_F = 0.0623 (both follow from Eckart–Young: the leftover is exactly 0.500, 0.250, 0.125, 0.060)

Noise keeps every direction alive: all eight bars are similar and no small k works. Two clean patterns is the opposite extreme — after k = 2 the curve is already flat at 100%.

Worked check: every identity on two small matrices
A = [[3, 0], [4, 5]] σ = [√45, √5] = [6.7082, 2.2361], r = 2 ‖A‖_F² = 3² + 0² + 4² + 5² = 50 = 45 + 5 = 50 ✓ trace(AᵀA) = 25 + 25 = 50 ✓ |det A| = |15| = 15 = 6.7082 · 2.2361 ✓ κ(A) = 6.7082 / 2.2361 = 3.000 A = [[1, 2], [2, 4]] σ = [5, 0], r = 1 this matrix sends every input onto the line through [1, 2]: A @ [1, 2] = [5, 10] = 5 · [1, 2] so the unit direction u₁ = [1, 2]/√5 is unchanged, just stretched 5×: A u₁ = 5 u₁ = σ₁u₁ ✓ the second singular value is exactly zero → rank 1, no inverse, and the condition number is undefined (division by σ₂ = 0) energy kept by the top k, same A as above: k = 1: 45 / 50 = 90.0% leftover = σ₂² = 5 k = 2: 50 / 50 = 100% exact

The energy identity is worth pausing on: the squared Frobenius norm is both the sum of squared entries and the sum of squared singular values. That is why the relative reconstruction error of a rank-k copy is exactly √(σₖ₊₁² + … + σᵣ²) / ‖A‖_F.

Quick check

A matrix has σ = [8, 5, 0.4]. Which statement is true?

WHY IT ALWAYS WORKS

Built from eigenvectors
of AᵀA and AAᵀ.

SVD is not a separate universe from eigendecomposition. Every singular value and vector is an eigenvalue and eigenvector in disguise — and the disguise is what removes all the restrictions.

Eigendecomposition fails in two situations: the matrix is not square, or it is square but lacks a full set of independent eigenvectors. Multiply A by Aᵀ and both problems vanish. AᵀA is always square, always symmetric, and symmetric matrices always have a full orthonormal set of eigenvectors with real eigenvalues. Even better, AᵀA is positive semi-definite, so those eigenvalues are ≥ 0 and can safely be square-rooted.

Plain English: the eigenvectors of AᵀA are the directions in which AᵀA only stretches, and its eigenvalues are the squares of the stretches A itself performs. Take the square roots and you have the singular values; the eigenvectors are the right singular vectors. Do the same with AAᵀ and you get the left ones.

A = U Σ Vᵀ AᵀA = (UΣVᵀ)ᵀ(UΣVᵀ) = V Σᵀ (UᵀU) Σ Vᵀ = V (ΣᵀΣ) Vᵀ = V · diag(σᵢ²) · Vᵀ → V and σᵢ² come from AᵀA AAᵀ = U Σ (VᵀV) Σᵀ Uᵀ = U · diag(σᵢ²) · Uᵀ → U comes from AAᵀ same eigenvalues σᵢ², two different eigenvector sets
Worked check: the symmetric case where the two decompositions coincide
B = [[2, 1], [1, 2]] (symmetric, positive definite) eigendecomposition of B: λ² − 4λ + 3 = 0 → (λ − 3)(λ − 1) = 0 λ₁ = 3, eigenvector [1, 1]/√2 λ₂ = 1, eigenvector [1, −1]/√2 B v₁ = [2.1213, 2.1213] = 3 · [0.7071, 0.7071] ✓ B v₂ = [0.7071, −0.7071] = 1 · [0.7071, −0.7071] ✓ SVD of B through BᵀB = B²: B² = [[5, 4], [4, 5]] → eigenvalues 9 and 1 σ = [√9, √1] = [3, 1] → identical to the eigenvalues of B right singular vectors: same [1, 1]/√2 and [1, −1]/√2 uᵢ = B vᵢ / σᵢ = λᵢvᵢ / λᵢ = vᵢ → U = V as well so for symmetric positive semi-definite B: SVD = eigendecomposition

This is the clean case. For a general non-symmetric matrix the eigenvalues may be negative or complex, but the singular values — built from AᵀA — are always non-negative reals. The sign information moves into the singular vectors instead. SVD is the eigendecomposition that never fails.

Quick check

A matrix A has condition number κ(A) = 10⁶. You solve a least-squares problem by forming AᵀA and inverting it. What is the condition number of the matrix you actually invert, and how many digits does that cost in float64?

The aha: SVD works on any shape because it is eigendecomposition applied to two symmetric matrices you can always build — AᵀA and AAᵀ. The reason to compute it another way is numerical: AᵀA is mathematically convenient and numerically dangerous, which is a pattern worth recognising far beyond this lesson.

KEEP THE BIG PATTERNS

Add the top pieces.
Drop the rest.

Multiplying out U Σ Vᵀ reveals the SVD as a recipe: one rank-1 pattern per singular value, stacked from most to least important. Stop early and you get the best simplified copy that rank allows.

Column-by-column multiplication turns A = U Σ Vᵀ into a sum of outer products:

A = σ₁ u₁v₁ᵀ + σ₂ u₂v₂ᵀ + … + σᵣ uᵣvᵣᵀ each term σᵢuᵢvᵢᵀ is an m×n matrix of rank 1: every column is a multiple of uᵢ, every row a multiple of vᵢᵀ. to store one term: m + n + 1 numbers instead of m·n. truncated SVD: A_k = σ₁u₁v₁ᵀ + … + σₖuₖvₖᵀ Eckart–Young theorem (minimal error over all rank-k matrices): spectral norm: ‖A − A_k‖₂ = σₖ₊₁ Frobenius norm: ‖A − A_k‖_F = √(σₖ₊₁² + … + σᵣ²)

Plain English: the first term is the single strongest pattern in the matrix, the second is the next strongest, and so on. If the singular values fall off quickly, a handful of terms reproduces the matrix to within a rounding error — and you never store the rest.

Rank-k reconstruction of a letterform

A 16 × 16 “A” decomposed exactly. Slide k: the reconstruction keeps the top k patterns and throws the rest away, and the difference panel shows exactly what was thrown.

σ₁ = 3.48 σ₂ = 2.38 σ₃ = 1.79 energy kept = 81.02% relative error = 0.4356 storage = 4 × (16 + 16 + 1) = 132 of 256 numbers rank of this bitmap = 8: only 8 of the 16 columns of the decomposition carry anything. leftover energy = 18.98%

At k = 4 the letter’s shape is already visible with 81% of the energy; k = 6–7 sharpens it and k = 8 is an exact copy. The bitmap only has rank 8 because its rows and columns repeat — pixels are a tiny, redundant world. Real photos are big enough for the savings to be dramatic, as the next lab shows.

Worked check: the rank-1 piece of A = [[3, 0], [4, 5]], by hand
σ₁u₁v₁ᵀ with σ₁ = 3√5, u₁ = [1, 3]/√10, v₁ = [1, 1]/√2: σ₁u₁v₁ᵀ = (3√5 / √20) · [[1, 1], [3, 3]] = (3/2) · [[1, 1], [3, 3]] = [[1.5, 1.5], [4.5, 4.5]] second piece: σ₂u₂v₂ᵀ = (√5 / √20) · [[3, −3], [−1, 1]] = (1/2) · [[3, −3], [−1, 1]] = [[1.5, −1.5], [−0.5, 0.5]] sum of both pieces = [[3, 0], [4, 5]] = A exactly ✓ leftover after k = 1: A − A₁ = [[1.5, −1.5], [−0.5, 0.5]] ‖A − A₁‖_F = √(2.25 + 2.25 + 0.25 + 0.25) = √5 = 2.2361 = σ₂ ✓ ‖A − A₁‖₂ = 2.2361 = σ₂ ✓ (the leftover IS the second piece) relative error = √5 / √50 = √0.1 = 0.3162 energy kept = 45 / 50 = 90%

Every number lines up because the terms are orthogonal: the rank-1 pieces do not overlap, so their energies add exactly and the error is precisely the singular values you dropped. That orthogonality is the engine behind Eckart–Young.

The aha: whether a matrix is compressible is not a property of its size but of its spectrum. Fast decay — a few large singular values followed by a cliff — means a small rank captures almost everything. Slow decay means the matrix genuinely uses all its dimensions, and truncating it destroys real information. The Eckart–Young theorem guarantees the truncated SVD makes the best of whichever situation you are in.

COMPRESSION & PCA

Pictures and data,
same arithmetic.

Once you can truncate a matrix, two of the most useful tools in data science fall out for free: image compression and principal component analysis. They are the same SVD with different stories attached.

A grayscale image is a matrix of pixel intensities. Store it with a rank-k SVD and the bill is k(m + n + 1) numbers instead of m · n: the k columns of U, the k columns of V and the k singular values.

800 × 600 photo = 480,000 numbers rank-k copy = k(800 + 600 + 1) = k · 1401 numbers k = 10: 14,010 → 2.9% of the original k = 50: 70,050 → 14.6% of the original k = 100: 140,100 → 29.2% of the original natural images decay fast: the first few σ carry shape and gradient, the last hundreds carry texture and noise

What a rank-k copy costs

A grayscale image is a matrix of pixel intensities. Slide k and compare the two grids, then read the bill: a rank-k copy stores k(m + n + 1) numbers instead of m · n.

ORIGINAL · 16 × 16 = 256
RANK 4 · 4 × (16 + 16 + 1) = 132 NUMBERS
relative error for this bitmap = 0.0865 energy kept = 99.25% THIS 16 × 16 BITMAP: rank 4 stores 132 of 256 numbers (52%) a small image only pays off at small k AN 800 × 600 PHOTO AT THE SAME RANK: rank 4 stores 5604 of 480,000 numbers (1.17%) the same k gets dramatically cheaper as the image grows
kstored numbers (800×600)% of originalrelative error (this bitmap)
114010.29%0.1795
228020.58%0.1445
456041.17%0.0865
8112082.33%0.0464
16224164.67%0.0000

Natural images decay fast: the first few singular values carry shapes and gradients, the last hundreds carry texture and noise. Noise has no low-rank structure, so compressing it just blurs it.

PCA is SVD. This is not an analogy. Take a data matrix X with n samples as rows and d features as columns, and center each column by subtracting its mean. The covariance matrix is C = XᵀX/(n − 1). Substitute X = U Σ Vᵀ and the whole thing collapses:

X = U Σ Vᵀ XᵀX = V (ΣᵀΣ) Vᵀ = V · diag(σᵢ²) · Vᵀ C = XᵀX/(n − 1) = V · diag(σᵢ²/(n − 1)) · Vᵀ principal components = columns of V (the right singular vectors) explained variance of PCᵢ = σᵢ² / (n − 1) scree plot = the singular values, squared and rescaled
tiny worked check: X has the 3 centered points (2, 1), (−2, −1), (0, 0) XᵀX = [[8, 4], [4, 2]] C = XᵀX/(n − 1) = [[4, 2], [2, 1]] eigenvalues of C: λ = 5 and 0 (trace 5, determinant 0) PC1 = [2, 1]/√5 = [0.8944, 0.4472], explaining 100% of the variance σ₁ = √(λ₁(n − 1)) = √(5 · 2) = √10 = 3.1623 check: ‖X‖_F² = (4 + 1) + (4 + 1) + 0 = 10 = σ₁² ✓ the three points sit exactly on a line, so one component suffices — a stylized example; real data splits its variance across several PCs

Recommendation systems tell the same story with different words. Write the user × movie ratings as a matrix and its SVD as U = user profiles in latent-factor space, Σ = how important each factor is, and Vᵀ = movie profiles in the same space. A predicted rating is the dot product of a user profile with a movie profile, weighted by Σ. Nobody has completely independent taste, so a handful of latent factors — action versus drama, old versus new — explain most of the matrix, and the missing entries get filled in by the rank-k approximation.

The aha: image compression and PCA look like different subjects — one is computer vision, the other statistics — but both are the statement “the useful structure lives in the top singular values.” Learn the truncation once and you have learned both.

SOLVING THE UNSOLVABLE

When there is no inverse,
invert what you can.

Most real systems have more equations than unknowns. They have no exact solution, but SVD still hands you the best one — the least-squares fit — through a generalized inverse.

A tall matrix A (m > n) turns Ax = b into more equations than unknowns, and usually no x satisfies all of them at once. The standard compromise is to minimize the squared error ‖Ax − b‖², which is exactly what fitting a line through noisy points does. The Moore–Penrose pseudoinverse A⁺ turns that compromise into a one-liner:

A = U Σ Vᵀ → A⁺ = V Σ⁺ Uᵀ Σ⁺ is Σ transposed, with every non-zero σᵢ replaced by 1/σᵢ (zeros stay zeros — a crushed direction cannot be un-crushed) shapes: A is m×n → A⁺ is n×m least squares: x = A⁺ b minimizes ‖Ax − b‖² (and when solutions exist, it picks the smallest one)

Least squares through the pseudoinverse

Nine noisy points, no line through all of them. A⁺ = V Σ⁺ Uᵀ finds the line that minimizes the sum of squared vertical residuals — the same answer the normal equations give, without ever forming AᵀA.

SVD pseudoinverse A⁺b: w = 1.1027 c = 0.5250 normal equations: w = 1.1027 c = 0.5250 largest disagreement = 1.33e-15 SSE = Σ residuals² = 0.6946 σ(A) = [7.9356, 1.3177] κ(A) = σ₁/σ₂ = 6.022

With no noise the fit lands on the true line. Add an outlier and watch least squares tilt toward it: the pseudoinverse answers the question you asked — smallest squared error — not the one you meant.

Derivation: why A⁺b is the least-squares answer — with exact numbers

Rotations do not change lengths, so multiplying by Uᵀ changes nothing about the size of the error:

‖Ax − b‖ = ‖Uᵀ(Ax − b)‖ (U is a rotation) = ‖ΣVᵀx − Uᵀb‖ (substitute A = UΣVᵀ) write y = Vᵀx and c = Uᵀb, the input and target in singular coordinates: minimize Σᵢ (σᵢyᵢ − cᵢ)² + Σ over zero-σ directions of cᵢ² each non-zero term is zeroed by choosing yᵢ = cᵢ/σᵢ → y = Σ⁺c → x = VΣ⁺Uᵀb = A⁺b

The zero-σ terms are constants no choice of x can touch — those directions are simply unreachable, which is the honest meaning of “no exact solution.” Now the same system solved both ways:

A = [[1, 1], b = [3, 5, 6] fit y = w x + c [2, 1], [3, 1]] normal equations: AᵀA = [[14, 6], [6, 3]] Aᵀb = [31, 14] det = 14·3 − 6·6 = 6 w = (3·31 − 6·14) / 6 = 9/6 = 1.5 c = (−6·31 + 14·14) / 6 = 10/6 = 1.6667 predictions: [3.1667, 4.6667, 6.1667] residuals: [−0.1667, 0.3333, −0.1667] SSE = 0.0278 + 0.1111 + 0.0278 = 1/6 ≈ 0.1667 (the minimum) SVD route: σ = [4.0791, 0.6005], κ(A) = 6.793 x = A⁺b = VΣ⁺Uᵀb gives the identical [1.5, 1.6667] without ever forming AᵀA
Quick check

A is 5 × 2, b is a 5-vector, and Ax = b has no exact solution. What does x = A⁺b give you?

The aha: the pseudoinverse completes the promise SVD made at the start. Rotations that cannot fail to exist, stretches that may be zero, and a transpose to walk back across a rectangular shape — that is enough to “invert” any matrix as well as anything can be inverted, and the answer comes with an error guarantee attached. It is also the last piece of linear algebra you need before moving on: every other application in the course is a variation on these three moves.

CHECK YOURSELF

Five questions.
Then the terms worth keeping.

Answer before you look. The shape and conditioning questions are the ones that come up when an SVD-based pipeline misbehaves in practice.

0 / 5 answered · 0 correct

01What advantage does SVD have over eigendecomposition?

02What does “low-rank approximation” mean?

03In SVD A = U Σ Vᵀ, what geometric operation does each factor represent?

04Why does scikit-learn implement PCA using SVD instead of eigendecomposition of the covariance matrix?

05How does truncated SVD enable recommendation systems to predict missing ratings?

Key terms, demystified

Click a card to swap the lazy description for what it actually means.

Exercises from the lesson

Four short problems. Try first; a worked answer is one click away.

  1. Compute the SVD of A = [[3, 0], [4, 5]] by hand, starting from the eigenvectors of AᵀA. Verify every number you can: unit lengths, perpendicularity, σ₁σ₂ = |det A|, and A vᵢ = σᵢ uᵢ.
    Show one worked answer

    AᵀA = [[25, 20], [20, 25]]. Characteristic equation: λ² − 50λ + 225 = 0 = (λ − 45)(λ − 5), so σ₁ = √45 = 6.7082 and σ₂ = √5 = 2.2361. Eigenvectors: v₁ = [1, 1]/√2 = [0.7071, 0.7071], v₂ = [1, −1]/√2 = [0.7071, −0.7071]. Then uᵢ = A vᵢ / σᵢ: A v₁ = [2.1213, 6.3640] → u₁ = [0.3162, 0.9487]; A v₂ = [2.1213, −0.7071] → u₂ = [0.9487, −0.3162]. Checks: ‖u₁‖ = √(0.1 + 0.9) = 1 ✓; u₁ · u₂ = 0.3 − 0.3 = 0 ✓; σ₁σ₂ = 6.7082 · 2.2361 = 15 = |3·5 − 0·4| = |det A| ✓; and U Σ Vᵀ reproduces [[3,0],[4,5]] entry by entry. The second singular value is about a third of the first — this matrix squashes the anti-diagonal direction.

  2. An 800 × 600 grayscale photo is approximated by a rank-50 truncated SVD. How many numbers does the copy store, and what fraction of the original 480,000 is that? Then do the same accounting at k = 10 and k = 100. Finally, for A = [[3, 0], [4, 5]], write the best rank-1 copy and its relative Frobenius error.
    Show one worked answer

    A rank-k copy stores k(m + n + 1) numbers: 50 · (800 + 600 + 1) = 70,050, which is 14.6% of 480,000. At k = 10: 10 · 1401 = 14,010 (2.9%); at k = 100: 140,100 (29.2%). For A = [[3,0],[4,5]] the best rank-1 copy is A₁ = σ₁u₁v₁ᵀ = 6.7082 · [0.3162, 0.9487] · [0.7071, 0.7071]ᵀ = [[1.5, 1.5], [4.5, 4.5]]. The leftover is [[1.5, −1.5], [−0.5, 0.5]], whose Frobenius norm is √(2.25 + 2.25 + 0.25 + 0.25) = √5 = 2.2361 = σ₂. Relative error = 2.2361 / 7.0711 = 0.316: A₁ keeps 90% of the energy (45/50).

  3. Fit a line y = wx + c to the three points (1, 3), (2, 5), (3, 6) — there is no line through all three, so find the least-squares one by solving the normal equations, and state the sum of squared residuals. Where does SVD's pseudoinverse enter?
    Show one worked answer

    The system A x = b has A = [[1,1],[2,1],[3,1]] and b = [3,5,6]. Normal equations: AᵀA = [[14, 6], [6, 3]], Aᵀb = [1·3+2·5+3·6, 3+5+6] = [31, 14]. det = 42 − 36 = 6, so w = (3·31 − 6·14)/6 = 9/6 = 1.5 and c = (−6·31 + 14·14)/6 = 10/6 = 1.6667. Predictions are [3.1667, 4.6667, 6.1667]; residuals [−0.1667, 0.3333, −0.1667]; SSE = 0.0278 + 0.1111 + 0.0278 = 1/6 ≈ 0.1667. SVD enters by replacing the inverse with A⁺ = V Σ⁺ Uᵀ: A's singular values are 4.0791 and 0.6005 (κ = 6.793), and x = A⁺b gives the identical [1.5, 1.6667] without ever forming AᵀA — the stable route in float32 or when A is nearly singular.

  4. A = [[2, 1], [1, 2]] is symmetric and positive definite. Compute its SVD and its eigendecomposition. Why do they coincide, and why does a symmetric positive-definite matrix never need a separate SVD formula?
    Show one worked answer

    Eigenvalues: λ² − 4λ + 3 = 0 → λ = 3 and 1, with eigenvectors [1,1]/√2 and [1,−1]/√2. So A = VDVᵀ with V = (1/√2)[[1,1],[1,−1]] and D = diag(3,1). For the SVD, AᵀA = A² = V D² Vᵀ, so σ₁ = √9 = 3, σ₂ = √1 = 1 and the right singular vectors are the same V. Since A vᵢ = λᵢ vᵢ with λᵢ > 0, uᵢ = A vᵢ / σᵢ = λᵢ vᵢ / λᵢ = vᵢ, so U = V as well. SVD and eigendecomposition are literally the same decomposition whenever the matrix is symmetric with non-negative eigenvalues — singular values are |eigenvalues|, and any negative sign moves into the singular vectors.

Terms this lesson borrows from later lessons (or outside)

You do not need to master these here. Each one gets a proper treatment in its own lesson; the one-line meaning is enough to keep reading. Orange dotted underlines in the prose point back to this list.

  • eigenvector & eigenvalueA vector that the matrix only scales, never rotates: Av = λv. SVD comes from the eigenvectors of AᵀA and AAᵀ. (Lesson 03)
  • featureOne input column: a single measured property of each example (age, pixel value, word count). (Lesson 10)
  • covariance matrixThe matrix of pairwise feature variances and covariances: C = XᵀX/(n−1) for centered data. Its eigenvectors are PCA's principal components. (Lesson 10)
  • principal component analysis (PCA)Finds the orthogonal directions of maximum variance and projects data onto the top few. It is literally SVD of the centered data matrix. (Lesson 10)
  • normal equationsThe one-shot least-squares formula (XᵀX)w = Xᵀy. It gives the same answer as the SVD pseudoinverse but loses precision when XᵀX is ill-conditioned. (Lesson 17)
  • NumPyNumerical Python: the standard array library, fast because its loops run in compiled C. np.linalg.svd returns Vᵀ, not V. (outside these lessons)
  • LoRALow-Rank Adaptation: a fine-tuning method that trains two skinny matrices B (d × r) and A (r × d) instead of the full d × d weight update, so ΔW = BA has rank at most r ≪ d. (later, fine-tuning)
KEEP GOING

A picture is a start.
Practice is the rest.

This lesson is a port of an open course. Everything here traces back to it — and the next step is running the code yourself.

Lesson text adapted from AI Engineering from Scratch (Phase 01, Lesson 11) and the Math Foundations Notebook reference build. The animated decomposition hero, the stage, shape, spectrum, rank, compression and pseudoinverse labs, the second fully worked numeric example, and the LoRA forward link are original to this page. Every singular value, reconstruction and least-squares number was recomputed for this module, and every lab runs in your browser.