Module 7: Orthogonality
np.linalg.qr, Gram-Schmidt (or a numerically stable version) is running under the hood.Given any set of linearly independent vectors, Gram-Schmidt produces an orthonormal basis — vectors that are all perpendicular to each other and all have length 1.
An orthonormal basis is the coordinate system equivalent of a clean desk. Calculations become much simpler:
Given two vectors u and v:
Now e₁ and e₂ are unit vectors and e₁ · e₂ = 0. They form an orthonormal basis for the same subspace that u and v spanned.
The same process extends to n vectors: at each step, subtract projections onto all previously computed basis vectors, then normalize.
Drag the input vectors u and v (faint arrows). The solid arrows are the Gram-Schmidt output e₁ and e₂ — always perpendicular, always length 1 (shown scaled up for visibility). The yellow dashed line is the projection that gets subtracted in step 2.
import numpy as np
A = np.array([[3., 1.], [1., 3.]])
# Q has orthonormal columns (Gram-Schmidt result)
# R is upper triangular
Q, R = np.linalg.qr(A)
print(Q) # orthonormal columns
print(Q.T @ Q) # ≈ identity
print(np.allclose(Q @ R, A)) # Truee₁ = [0.95, 0.32] (unit, from u)
e₂ = [-0.32, 0.95] (unit, ⊥ e₁)
e₁ · e₂ = 0 ≈ 0 ✓
Faint arrows = inputs u, v. Solid arrows = orthonormal output e₁, e₂ (shown at 3× scale). Yellow dashed = the projection that gets subtracted.