Sandomhet

CMPSC 111 - Numerical Linear Algebra

Solving systems of linear equations using LU decomposition and iterative methods like Jacobi and Gauss-Seidel.

Tue, Dec 9, 2025 15 min read

CMPSC 111 - Numerical Linear Algebra

Fundamental Subspaces of a Matrix

For a matrix A∈Rm×nA \in \mathbb{R}^{m \times n}:

SubspaceDefinitionDimension
Row(A)\text{Row}(A)Span of rows of AArank(A)\text{rank}(A)
Col(A)\text{Col}(A)Span of columns of AA with pivot positionsrank(A)\text{rank}(A)
N(A)N(A)Null space: x:Ax=0{x : Ax = 0}, free variablesn−rank(A)n - \text{rank}(A)
N(AT)N(A^T)Left null space: x:ATx=0{x: A^Tx = 0}m−rank(A)m - \text{rank}(A)
dim⁡(Row(A))=dim⁡(Col(A))=rank(A)dim⁡(Row(A))+dim⁡(N(A))=ndim⁡(Col(A))+dim⁡(N(AT))=m\begin{aligned} \dim(\text{Row}(A)) = \dim(\text{Col}(A)) = \text{rank}(A) \\ \dim(\text{Row}(A)) + \dim(N(A)) = n \\ \dim(\text{Col}(A)) + \dim(N(A^T)) = m \\ \end{aligned}
  • Row(A)Row(A): linearly independent rows.
  • Col(A)Col(A): linearly independent columns; non-zero pivots.
  • N(A)N(A): all the free variables. {x:Ax=0}\{x: Ax=0\}
  • N(AT)N(A^T): left null space, {y:ATy=0}\{y: A^Ty=0\}

Find these subspaces for an example: A=[123456789]A = \begin{bmatrix} 1 & 2 & 3 \\ 4 & 5 & 6 \\ 7 & 8 & 9 \end{bmatrix}, rref(A)=[10−1012000]rref(A) = \begin{bmatrix} 1 & 0 & -1 \\ 0 & 1 & 2 \\ 0 & 0 & 0 \end{bmatrix}

  • Row(A)=span{[1,0,−1],[0,1,2]}\text{Row}(A) = \text{span}\{[1, 0, -1], [0, 1, 2]\}
  • Col(A)=span{[147],[258]}\text{Col}(A) = \text{span}\{\begin{bmatrix}1 \\ 4 \\ 7\end{bmatrix}, \begin{bmatrix}2 \\ 5 \\ 8\end{bmatrix}\}
  • N(A)=span{[1−21]}N(A) = \text{span}\{\begin{bmatrix}1 \\ -2 \\ 1\end{bmatrix}\}
  • N(AT)=span{[1,−2,1]}N(A^T) = \text{span}\{[1, -2, 1]\}
A = sp.Matrix([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
rref_A, pivots = A.rref()
row_space = rref_A.rowspace()
col_space = A.columnspace()
null_space = A.nullspace()
left_null_space = A.T.nullspace()

Direct Methods for Solving Systems of Linear Equations

LU (Lower-Upper) Decomposition for Dense Matrix

Precondition: AA is a square matrix and non-singular (invertible).

A=LUA = LU where LL is lower triangular and UU is upper triangular.

L=[100l2110l31l321]L=\begin{bmatrix} 1 & 0 & 0 \\ l_{21} & 1 & 0 \\ l_{31} & l_{32} & 1 \end{bmatrix}, U=[u11u12u130u22u2300u33]U=\begin{bmatrix} u_{11} & u_{12} & u_{13} \\ 0 & u_{22} & u_{23} \\ 0 & 0 & u_{33} \end{bmatrix}

Ax=bAx = b can be solved by first solving Ly=bLy = b for yy using forward substitution, and then solving Ux=yUx = y for xx using backward substitution.

Ax=bLUx=bLy=b (forward substitution) Ux=y (backward substitution) \begin{aligned} Ax &= b \\ LUx &= b \\ Ly &= b \text{ (forward substitution) } \\ Ux &= y \text{ (backward substitution) } \\ \end{aligned}

Computational Complexity: O(n3)O(n^3) for LU decomposition, O(n2)O(n^2) for forward and backward substitution.

LU Decomposition with Partial Pivoting

Pivoting (row swapping) ensures numerical stability when a pivot element is zero or very small.
Permutation matrix PP such that PA=LUPA = LU.

Permutation Matrix

A permutation matrix PP is a square binary matrix that has exactly one entry of 1 in each row and each column and 0s elsewhere. It represents a reordering of the standard basis vectors.

Properties of Permutation Matrix:

  1. PP is obtained by permuting the rows of an identity matrix.
  2. Orthogonal: P−1=PTP^{-1} = P^T
  3. PAPA permutes the rows of AA.
  4. APAP permutes the columns of AA.
p = np.array([2, 0, 1])  # permutation vector
P = np.eye(3)[p]         # permutation matrix
b = np.random.rand(3)
A = np.random.rand(3,3)
# permuted b
b[p]
P @ b
# permuted A rows
A[p, :]
P @ A
# permuted A columns
A[:, p]
A @ P

Algorithm

Ax=bPAx=PbLUx=PbLy=Pb (forward substitution) Ux=y (backward substitution) \begin{aligned} Ax &= b \\ PAx &= Pb \\ LUx &= Pb \\ Ly &= Pb \text{ (forward substitution) } \\ Ux &= y \text{ (backward substitution) } \\ \end{aligned}
def LUsolve(A, b):
    L, U, p = cs111.LUfactor(A) # PA = LU
    y = cs111.Lsolve(L, b[p]) # Ly = Pb
    x = cs111.Usolve(U, y) # Ux = y
    return x

QR Decomposition & Least Squares

Precondition: A∈Rm×nA \in \mathbb{R}^{m \times n} with full column rank (rank(A)=n\text{rank}(A) = n) and m≥nm \geq n. It's an overdetermined system (more equations than unknowns).

A=QRA = QR where QQ is an orthogonal matrix and RR is an upper triangular matrix.

Q=[⋯q1q2q3⋯]Q=\begin{bmatrix} & \cdots & \\ q_1 & q_2 & q_3 \\ & \cdots & \\ \end{bmatrix}, R=[r11r12r130r22r2300r33⋮⋮⋮000]R=\begin{bmatrix} r_{11} & r_{12} & r_{13} \\ 0 & r_{22} & r_{23} \\ 0 & 0 & r_{33} \\ \vdots & \vdots & \vdots \\ 0 & 0 & 0 \end{bmatrix}

Since an overdetermined system may not have an exact solution, we can find the best approximate solution using least squares (least squares solution).

Solve Ax≈bAx \approx b is equivalent to solving ∣Ax−b∣≈0|Ax - b| \approx 0, which is equivalent to minimizing the residual r=b−Axr = b - Ax. The least squares solution minimizes the 2-norm of the residual: min⁡x∥r∥2=min⁡x∥b−Ax∥2\min_x \|r\|_2 = \min_x \|b - Ax\|_2

Orthogonal Matrix Properties

  1. QTQ=I=QQTQ^T Q = I = Q Q^T
  2. ∣Qv∣=∣v∣|Qv| = |v| for any vector vv (rotation, norm preservation).
  3. k(Q)=1k(Q) = 1 (well-conditioned).
  4. ∣Q∣=1|Q| = 1 (determinant).
  5. The columns are orthonormal vectors. (perpendicular and unit length)

Algorithm

Ax=bQRx=bQTQRx=QTbRx=QTb\begin{aligned} Ax &= b \\ QR x &= b \\ Q^T Q R x &= Q^T b \\ R x &= Q^T b \\ \end{aligned}
  1. Find Q,RQ, R such that A=QRA = QR.
  2. Compute QTbQ^T b.
  3. Solve the upper triangular system Rx=QTbR x = Q^T b using back substitution. (U-solve, economy size)

Computational Complexity: O(mn2)O(mn^2) for QR decomposition, O(mn)O(mn) for computing QTbQ^T b, and O(n2)O(n^2) for back substitution.

Two versions of QR factorization:

  • Full-size QR factorization: QQ is square (and big), RR is the same shape as AA.
  • Economic QR factorization: QQ is the same shape as AA, RR is square (and small).
def QRsolve(A, b):
    Q, R = scipy.linalg.qr(A, mode='economic') # A = QR
    b_hat = Q.T @ b # Q^T b
    x = cs111.Usolve(R, b_hat) # Rx = Q^T b
    return x

Methods to Compute QR Decomposition

  1. Gram-Schmidt Process
  2. Householder Reflections
  3. Givens Rotations

Applications

Data Fitting

y=kx+by = kx + b (linear regression).
Given data points (xi,yi)(x_i, y_i), we can set up the system Ax=bAx = b where:

A=[1x11x2⋮⋮1xn],x=[bk],b=[y1y2⋮yn]A = \begin{bmatrix} 1 & x_1 \\ 1 & x_2 \\ \vdots & \vdots \\ 1 & x_n \end{bmatrix}, \quad x = \begin{bmatrix} b \\ k \end{bmatrix}, \quad b = \begin{bmatrix} y_1 \\ y_2 \\ \vdots \\ y_n \end{bmatrix}

We can then use QR decomposition to find the least squares solution for xx.

Iterative Methods for Sparse Matrix

When AA is large and sparse, use iterative methods to save memory and computational resources.

Error, Residual, and Condition Number

  • Vector 2-Norm (Euclidean): ∥x∥2=∑i=1nxi2\|x\|_2 = \sqrt{\sum\limits_{i=1}^{n} x_i^2}
  • Matrix 2-Norm (Spectral): ∥A∥2=max⁡x≠0∣Ax∣∣x∣=max⁡∥x∥=1∥Ax∥\|A\|_2 = \max\limits_{x \neq 0} \frac{|Ax|}{|x|} = \max\limits_{\|x\|=1} \|Ax\| (How much AA stretches a vector)
  • Frobenius Norm: ∥A∥F=∑i=1m∑j=1naij2\|A\|_F = \sqrt{\sum\limits_{i=1}^{m} \sum\limits_{j=1}^{n} a_{ij}^2}
  • Error: e=∣x−x^∣e = |x - \hat{x}| (xx is true solution, x^\hat{x} is computed solution)
  • Relative Error: ∣x−x^∣∣x∣\frac{|x - \hat{x}|}{|x|}
  • Residual: r=b−Ax^r = b - A\hat{x}
  • Relative Residual: ∣b−Ax^∣∣b∣\frac{|b - A\hat{x}|}{|b|}
  • Condition Number: κ(A)=∥A∥∥A−1∥\kappa(A) = \|A\| \|A^{-1}\|. Explain why it matters.
    • If κ(A)\kappa(A) is large, the matrix is ill-conditioned, meaning small changes in bb can lead to large changes in the solution xx.
    • If κ(A)\kappa(A) is small, the matrix is well-conditioned, and the solution xx is more stable with respect to changes in bb.
    • If κ(A)\kappa(A) = 1, then AA is perfectly conditioned.
    • For Ax=bAx = b, x^=x+e\hat{x} = x + e where Ae=rAe = r. Thus, ∥e∥∥x∥≤κ(A)∥r∥∥b∥\frac{\|e\|}{\|x\|} \leq \kappa(A) \frac{\|r\|}{\|b\|}.
norm = npla.norm(x)
residual = npla.norm(b - A @ x)
relative_residual = npla.norm(b - A @ x) / npla.norm(b)
cond_number = npla.cond(A)

Jacobi Method

Precondition: AA is strictly diagonally dominant or symmetric positive definite.

Strictly diagonally dominant: ∣aii∣>∑j≠i∣aij∣|a_{ii}| > \sum\limits_{j \neq i} |a_{ij}| for all ii.

Decompose A=D+CA = D + C, where DD is the diagonal part and CC is the remainder.

D=[a110⋯00a22⋯0⋮⋮⋱⋮00⋯ann]D = \begin{bmatrix} a_{11} & 0 & \cdots & 0 \\ 0 & a_{22} & \cdots & 0 \\ \vdots & \vdots & \ddots & \vdots \\ 0 & 0 & \cdots & a_{nn} \end{bmatrix}, C=[0a12⋯a1na210⋯a2n⋮⋮⋱⋮an1an2⋯0]C = \begin{bmatrix} 0 & a_{12} & \cdots & a_{1n} \\ a_{21} & 0 & \cdots & a_{2n} \\ \vdots & \vdots & \ddots & \vdots \\ a_{n1} & a_{n2} & \cdots & 0 \end{bmatrix}

Element-based formula: xi(k+1)=1aii(bi−∑j≠iaijxj(k))x_i^{(k+1)} = \frac{1}{a_{ii}} \left(b_i - \sum\limits_{j \neq i} a_{ij} x_j^{(k)}\right)

Matrix-based formula: x(k+1)=D−1(b−Cx(k))x^{(k+1)} = D^{-1}(b - Cx^{(k)})

Algorithm

  1. Initialize x(0)x^{(0)} to an arbitrary vector, often the zero vector.
  2. For k=0,1,2,...k = 0, 1, 2, ... until convergence:
    • Update each component of xx using the element-based formula.
def jacobi(A, b, x0, tol=1e-10, max_iterations=1000):
    n = len(b)
    x = x0.copy()
    for k in range(max_iterations):
        x_new = x.copy()
        for i in range(n):
            sum_ax = sum(A[i][j] * x[j] for j in range(n) if j != i)
            x_new[i] = (b[i] - sum_ax) / A[i][i]
        if np.linalg.norm(x_new - x, ord=np.inf) < tol:
            return x_new
        x = x_new
    return x

Gauss-Seidel Method

Precondition: AA is strictly diagonally dominant or symmetric positive definite.

Decompose A=L+UA = L + U, where LL is the lower triangular part (including diagonal) and UU is the upper triangular part.

L=[a110⋯0a21a22⋯0⋮⋮⋱⋮an1an2⋯ann]L = \begin{bmatrix} a_{11} & 0 & \cdots & 0 \\ a_{21} & a_{22} & \cdots & 0 \\ \vdots & \vdots & \ddots & \vdots \\ a_{n1} & a_{n2} & \cdots & a_{nn} \end{bmatrix}, U=[0a12⋯a1n00⋯a2n⋮⋮⋱⋮00⋯0]U = \begin{bmatrix} 0 & a_{12} & \cdots & a_{1n} \\ 0 & 0 & \cdots & a_{2n} \\ \vdots & \vdots & \ddots & \vdots \\ 0 & 0 & \cdots & 0 \end{bmatrix}

Element-based formula: xi(k+1)=1aii(bi−∑j<iaijxj(k+1)−∑j>iaijxj(k))x_i^{(k+1)} = \frac{1}{a_{ii}} \left(b_i - \sum\limits_{j < i} a_{ij} x_j^{(k+1)} - \sum\limits_{j > i} a_{ij} x_j^{(k)}\right)

Matrix-based formula: x(k+1)=L−1(b−Ux(k))x^{(k+1)} = L^{-1}(b - U x^{(k)})

Algorithm

  1. Initialize x(0)x^{(0)} to an arbitrary vector, often the zero vector.
  2. For k=0,1,2,...k = 0, 1, 2, ... until convergence:
    • Update each component of xx using the element-based formula.
def gauss_seidel(A, b, x0, tol=1e-10, max_iterations=1000):
    n = len(b)
    x = x0.copy()
    for k in range(max_iterations):
        x_new = x.copy()
        for i in range(n):
            sum1 = sum(A[i][j] * x_new[j] for j in range(i))
            sum2 = sum(A[i][j] * x[j] for j in range(i + 1, n))
            x_new[i] = (b[i] - sum1 - sum2) / A[i][i]
        if np.linalg.norm(x_new - x, ord=np.inf) < tol:
            return x_new
        x = x_new
    return x

Conjugate Gradient Method

Precondition: AA is symmetric positive definite.

The iterative formula:

x(k+1)=x(k)+αkpkwhereαk=rkTrkpkTApkrk+1=rk−αkApkβk=rk+1Trk+1rkTrkpk+1=rk+1+βkpkx^{(k+1)} = x^{(k)} + \alpha_k p_k \\ \text{where} \\ \alpha_k = \frac{r_k^T r_k}{p_k^T A p_k} \\ r_{k+1} = r_k - \alpha_k A p_k \\ \beta_k = \frac{r_{k+1}^T r_{k+1}}{r_k^T r_k} \\ p_{k+1} = r_{k+1} + \beta_k p_k \\

where α\alpha is a step size and pp is the search direction.

Algorithm

  1. Initialize x0x_0 to an arbitrary vector, often the zero vector.
  2. Compute initial residual: r0=b−Ax0r_0 = b - A x_0
  3. Set initial search direction: p0=r0p_0 = r_0
  4. For k=0,1,2,...k = 0, 1, 2, ... until convergence
def conjugate_gradient(A, b, x0, tol=1e-10, max_iterations=1000):
    x = x0.copy()
    r = b - A @ x
    p = r.copy()
    for k in range(max_iterations):
        r_dot_r = r.T @ r
        Ap = A @ p
        alpha = r_dot_r / (p.T @ Ap)
        x_new = x + alpha * p
        r_new = r - alpha * Ap
        if np.linalg.norm(r_new) < tol:
            return x_new
        beta = (r_new.T @ r_new) / r_dot_r
        p = r_new + beta * p
        x = x_new
        r = r_new
    return x

Comparison of Iterative Methods

MethodPreconditionConvergence RateMemory Usage
JacobiStrictly diagonally dominant or SPDSlowLow
Gauss-SeidelStrictly diagonally dominant or SPDFaster than JacobiLow
Conjugate GradientSymmetric positive definiteFast (depends on condition number)Moderate (stores vectors)

Gradient Descent

Precondition: AA is symmetric positive definite.

  1. symmetric: A=ATA = A^T
  2. positive definite: xTAx>0x^T A x > 0 for all non-zero vectors xx.

Solving Ax=bAx = b is equivalent to minimizing the quadratic function f(x)=12xTAx−bTxf(x) = \frac{1}{2} x^T A x - b^T x
ff is strictly convex, has a unique minimum.

The iterative formula:

x(k+1)=x(k)−αk∇f(x(k))where∇f(x(k))=Ax(k)−b=−rkαk=rkTrkrkTArkx^{(k+1)} = x^{(k)} - \alpha_k \nabla f(x^{(k)}) \\ \text{where} \\ \nabla f(x^{(k)}) = A x^{(k)} - b = -r_k \\ \alpha_k = \frac{r_k^T r_k}{r_k^T A r_k} \\

Essentials: A transpose of a scalar is itself: cT=cc^T = c for c∈Rc \in \mathbb{R}.

To derive the gradient ∇f(x)\nabla f(x):

f(x+v)=12(x+v)TA(x+v)−bT(x+v)=12(xTAx+xTAv+vTAx+vTAv)−bTx−bTv Since (xTAv=(xTAv)T=vTATx=vTAx,bTv=vTb)=12(xTAx+2vTAx+vTAv)−bTx−vTb=f(x)+vT(Ax−b)+12vTAv=f(x)+vT∇f(x)+12vTAv\begin{aligned} f(x + v) &= \frac{1}{2} (x + v)^T A (x + v) - b^T (x + v) \\ &= \frac{1}{2} (x^T A x + x^T A v + v^T A x + v^T A v) - b^T x - b^T v \\ &\text{ Since } (x^T A v = (x^T A v)^T = v^T A^T x = v^T A x, b^T v = v^T b) \\ &= \frac{1}{2} (x^T A x + 2 v^T A x + v^T A v) - b^T x - v^T b \\ &= f(x) + v^T (A x - b) + \frac{1}{2} v^T A v \\ &= f(x) + v^T \nabla f(x) + \frac{1}{2} v^T A v \\ \end{aligned} f′(x)=lim⁡v→0f(x+v)−f(x)v=lim⁡v→0vT(Ax−b)+12vTAvv=lim⁡v→0(Ax−b)Tvv+lim⁡v→012vTAvv=(Ax−b)T\begin{aligned} f'(x) &= \lim\limits_{v \to 0} \frac{f(x + v) - f(x)}{v} \\ &= \lim\limits_{v \to 0} \frac{v^T (A x - b) + \frac{1}{2} v^T A v}{v} \\ &= \lim\limits_{v \to 0} \frac{(A x - b)^T v}{v} + \lim\limits_{v \to 0} \frac{\frac{1}{2}{v^T A v}}{v} \\ &= (A x - b)^T \\ \end{aligned}

Thus, ∇f(x)=(f′(x))T=Ax−b\nabla f(x) = (f'(x))^T = Ax - b.
−∇f(x(k))-\nabla f(x^{(k)}) is orthogonal to −∇f(x(k+1))-\nabla f(x^{(k+1)}).

The step size αk\alpha_k is chosen to minimize f(x(k+1))f(x^{(k+1)}), which means ddαkf(x(k+1))=0\frac{d}{d\alpha_k} f(x^{(k+1)}) = 0:

ddαkf(x(k+1))=ddαkf(x(k)−αk∇f(x(k)))=ddαkf(x(k)+αkrk)=ddαk(f(x(k))+αkrkT∇f(x(k))+12αk2rkTArk)=rkT∇f(x(k))+αkrkTArk=−rkTrk+αkrkTArk=0\begin{aligned} \frac{d}{d\alpha_k} f(x^{(k+1)}) &= \frac{d}{d\alpha_k} f(x^{(k)} - \alpha_k \nabla f(x^{(k)})) \\ &= \frac{d}{d\alpha_k} f(x^{(k)} + \alpha_k r_k) \\ &= \frac{d}{d\alpha_k} \left( f(x^{(k)}) + \alpha_k r_k^T \nabla f(x^{(k)}) + \frac{1}{2} \alpha_k^2 r_k^T A r_k \right) \\ &= r_k^T \nabla f(x^{(k)}) + \alpha_k r_k^T A r_k \\ &= -r_k^T r_k + \alpha_k r_k^T A r_k \\ &= 0 \\ \end{aligned}

Thus, αk=rkTrkrkTArk\alpha_k = \frac{r_k^T r_k}{r_k^T A r_k}.

SVD (Singular Value Decomposition)

Precondition: A∈Rm×nA \in \mathbb{R}^{m \times n} (no restrictions).

A=UΣVTA = U \Sigma V^T where U∈Rm×mU \in \mathbb{R}^{m \times m} and V∈Rn×nV \in \mathbb{R}^{n \times n} are orthogonal matrices, and Σ∈Rm×n\Sigma \in \mathbb{R}^{m \times n} is a diagonal matrix with non-negative real numbers on the diagonal (singular values).

U=[⋮⋮⋮⋮u1u2⋮um⋮⋮⋮⋮]U=\begin{bmatrix} \vdots & \vdots & \vdots & \vdots \\ u_1 & u_2 & \vdots & u_m \\ \vdots & \vdots & \vdots & \vdots \end{bmatrix}, V=[⋯v1T⋯⋯v2T⋯⋯⋯⋯⋯vnT⋯]V=\begin{bmatrix} \cdots & v_1^T & \cdots \\ \cdots & v_2^T & \cdots \\ \cdots & \cdots & \cdots \\ \cdots & v_n^T & \cdots \end{bmatrix}, Σ=[σ10⋯000σ2⋯0⋮⋮⋮⋱⋮⋮00⋯σr⋮00⋯00⋮⋮⋱⋮⋮00⋯00]\Sigma=\begin{bmatrix} \sigma_1 & 0 & \cdots & 0 & 0 \\ 0 & \sigma_2 & \cdots & 0 & \vdots \\ \vdots & \vdots & \ddots & \vdots & \vdots \\ 0 & 0 & \cdots & \sigma_r & \vdots \\ 0 & 0 & \cdots & 0 & 0 \\ \vdots & \vdots & \ddots & \vdots & \vdots \\ 0 & 0 & \cdots & 0 & 0 \end{bmatrix} where σ1≥σ2≥...≥σr>0\sigma_1 \geq \sigma_2 \geq ... \geq \sigma_r > 0 are the singular values of AA, and r=rank(A)r = \text{rank}(A), the number of non-zero singular values.

A=∑i=1rσiuiviTA = \sum\limits_{i=1}^r \sigma_i u_i v_i^T (outer product expansion).

  1. If we keep all singular values, we get the exact reconstruction of AA.
  2. If we keep only the top k(k<r)k (k < r) singular values, we get a rank-kk approximation of AA, denoted as Ak=∑i=1kσiuiviTA_k = \sum\limits_{i=1}^k \sigma_i u_i v_i^T.
  3. The rank-kk approximation AkA_k minimizes the Frobenius norm of the error: ∥A−Ak∥F\|A - A_k\|_F.
U, sigma, Vt = spla.svd(A)
Asum = np.zeros( A.shape )
for i in range( len( sigma ) ):
    Asum += sigma[i] * np.outer( U[:, i], Vt[i, :] )

Theorems

AV=UΣAV = U \Sigma.

VV responds a basis with nn columns. AVAV takes the orthonormal basis vectors viv_i from the row space of AA and maps them to the orthonormal basis vectors uiu_i from the column space of AA, scaled by the singular values σi\sigma_i. Avi=σiuiA v_i = \sigma_i u_i

Theorem:
∥A−Ak∥2=σk+1\|A - A_k\|_2 = \sigma_{k+1}

∥A∥F=∑i=1rσi2\|A\|_F = \sqrt{\sum\limits_{i=1}^r \sigma_i^2}.
∥A−Ak∥F=∑i=k+1rσi2\|A - A_k\|_F = \sqrt{\sum\limits_{i=k+1}^r \sigma_i^2}.

∥A∥2=max⁡x≠0∣Ax∣∣x∣=max⁡∣x∣=1∣Ax∣=max⁡∣x∣=1∣UΣVTx∣=max⁡∣UΣVT∣=σ1\begin{aligned} \|A\|_2 &= \max\limits_{x \neq 0} \frac{|Ax|}{|x|} \\ &= \max\limits_{|x|=1} |Ax| \\ &= \max\limits_{|x|=1} |U \Sigma V^T x| \\ &= \max |U \Sigma V^T| \\ % &= \max\limits_{|y|=1} | \Sigma y| \quad \text{(let } y = V^T x \text{)} \\ % &= \max\limits_{|y|=1} \sqrt{\sum\limits_{i=1}^r \sigma_i^2 y_i^2} \\ &= \sigma_1 \\ \end{aligned} ∥A∥=∥UΣVT∥=∥Σ∥=σ1∥A−1∥=∥VΣ−1UT∥=∥Σ−1∥=1σrκ(A)=∥A∥∥A−1∥=σ1σr\|A\| = \|U \Sigma V^T\| = \|\Sigma\| = \sigma_1 \\ \|A^{-1}\| = \|V \Sigma^{-1} U^T\| = \|\Sigma^{-1}\| = \frac{1}{\sigma_r} \\ \kappa(A) = \|A\| \|A^{-1}\| = \frac{\sigma_1}{\sigma_r} \\

The determinant of AA is the product of its singular values:

∣A∣=∏i=1rσi|A| = \prod\limits_{i=1}^r \sigma_i

Math Proof

For two vectors u∈Rmu \in \mathbb{R}^m and v∈Rnv \in \mathbb{R}^n,
Inner product: uTv=∑i=1nuivi=u⋅vu^T v = \sum\limits_{i=1}^{n} u_i v_i = u \cdot v (scalar).
Outer product: uvT=[u1v1u1v2⋯u1vnu2v1u2v2⋯u2vn⋮⋮⋱⋮umv1umv2⋯umvn]uv^T = \begin{bmatrix} u_1 v_1 & u_1 v_2 & \cdots & u_1 v_n \\ u_2 v_1 & u_2 v_2 & \cdots & u_2 v_n \\ \vdots & \vdots & \ddots & \vdots \\ u_m v_1 & u_m v_2 & \cdots & u_m v_n \end{bmatrix} (rank-1 matrix). Thus, (uvT)ij=uivj(uv^T)_{ij} = u_i v_j

(ABT)ij=∑k=1nAikBkjT=∑k=1nAikBjk=∑k=1n(ak)i(bk)j\begin{aligned} (AB^T)_{ij} &= \sum\limits_{k=1}^{n} A_{ik} B^T_{kj} \\ &= \sum\limits_{k=1}^{n} A_{ik} B_{jk} \\ &= \sum\limits_{k=1}^{n} (a_k)_i (b_k)_j \\ \end{aligned}

By definition of outer product, we have:

(∑k=1nakbkT)ij=∑k=1n(akbkT)ij=∑k=1n(ak)i(bk)j\begin{aligned} \left(\sum\limits_{k=1}^{n} a_k b_k^T\right)_{ij} &= \sum\limits_{k=1}^{n} (a_k b_k^T)_{ij} \\ &= \sum\limits_{k=1}^{n} (a_k)_i (b_k)_j \\ \end{aligned}

Therefore, ABT=∑i=1naibiTAB^T = \sum\limits_{i=1}^{n} a_i b_i^T where aia_i and bib_i are the ii-th columns of AA and BB respectively.

np.dot(U[:, k], Vt[k, :])
np.outer(U[:, k], Vt[k, :])

Image Compression

Suppose an image is m×nm \times n pixels, the storage is m×nm \times n.
With first kk terms in SVD, storage is mk+nk+k=k(m+n+1)mk + nk + k = k(m + n + 1).
Compression ratio: mnk(m+n+1)\dfrac{mn}{k(m + n + 1)}.

img = plt.imread('image.png')  # Load image
U, sigma, Vt = spla.svd(img, full_matrices=False)
k = 50  # Number of singular values to keep
Sigma_k = np.diag(sigma[:k])  # Create diagonal matrix with top k singular values
img_approx = U[:, :k] @ Sigma_k @ Vt[:k, :]  # Reconstruct the image
plt.imsave('compressed_image.png', img_approx.astype(np.uint8))  # Save compressed image

Principal Component Analysis (PCA)

PCA is SVD on the covariance matrix of the data.

PCA is a dimensionality reduction technique that transforms data into a new coordinate system that helps us to reduce the number of features in a dataset while keeping the most important information.

For vectors x,y∈Rnx, y \in \mathbb{R}^n, the Mean μ=1n∑i=1nxi\mu = \frac{1}{n} \sum\limits_{i=1}^{n} x_i. Define rx=[⋯xi−μ⋯]r_x = \begin{bmatrix} \cdots \\ x_i - \mu \\ \cdots \end{bmatrix} as the deviation from the mean. Then there is the Variance σ2=1n−1∑i=1n(xi−μ)2=rxTrx\sigma^2 = \frac{1}{n-1} \sum\limits_{i=1}^{n} (x_i - \mu)^2 = r_x^T r_x, and the Covariance σ=1n−1∑i=1n(xi−μx)(yi−μy)=rxTry\sigma = \frac{1}{n-1} \sum\limits_{i=1}^{n} (x_i - \mu_x)(y_i - \mu_y) = r_x^T r_y.

  • σxy>0\sigma_{xy} > 0: xx and yy are positively correlated, covary.
  • σxy<0\sigma_{xy} < 0: xx and yy are negatively correlated, anticovary.
  • σxy=0\sigma_{xy} = 0: xx and yy are uncorrelated.

The Data matrix D∈Rm×nD \in \mathbb{R}^{m \times n}, where mm is the number of samples and nn is the number of features.

The Mean matrix M∈Rm×nM \in \mathbb{R}^{m \times n} with μj=1m∑i=1mDij\mu_j = \frac{1}{m} \sum\limits_{i=1}^{m} D_{ij} is the mean of feature jj: M=[μ1μ2⋯μnμ1μ2⋯μn⋮⋮⋱⋮μ1μ2⋯μn]M = \begin{bmatrix} \mu_1 & \mu_2 & \cdots & \mu_n \\ \mu_1 & \mu_2 & \cdots & \mu_n \\ \vdots & \vdots & \ddots & \vdots \\ \mu_1 & \mu_2 & \cdots & \mu_n \\ \end{bmatrix}

The Centered data matrix is R=D−MR = D - M: R=[D11−μ1D12−μ2⋯D1n−μnD21−μ1D22−μ2⋯D2n−μn⋮⋮⋱⋮Dm1−μ1Dm2−μ2⋯Dmn−μn]R = \begin{bmatrix} D_{11} - \mu_1 & D_{12} - \mu_2 & \cdots & D_{1n} - \mu_n \\ D_{21} - \mu_1 & D_{22} - \mu_2 & \cdots & D_{2n} - \mu_n \\ \vdots & \vdots & \ddots & \vdots \\ D_{m1} - \mu_1 & D_{m2} - \mu_2 & \cdots & D_{mn} - \mu_n \\ \end{bmatrix}

The Covariance matrix C∈Rn×nC \in \mathbb{R}^{n \times n} with σij=Cov(i,j)=1m−1∑k=1m(Dki−μi)(Dkj−μj)\sigma_{ij} = \text{Cov}(i, j) = \frac{1}{m-1} \sum\limits_{k=1}^{m} (D_{ki} - \mu_i)(D_{kj} - \mu_j) is the covariance between features ii and jj, C=1m−1RTRC = \frac{1}{m-1} R^T R is symmetric: C=[σ11σ12⋯σ1nσ12σ22⋯σ2n⋮⋮⋱⋮σ1nσ2n⋯σnn]C = \begin{bmatrix} \sigma_{11} & \sigma_{12} & \cdots & \sigma_{1n} \\ \sigma_{12} & \sigma_{22} & \cdots & \sigma_{2n} \\ \vdots & \vdots & \ddots & \vdots \\ \sigma_{1n} & \sigma_{2n} & \cdots & \sigma_{nn} \\ \end{bmatrix}

SVD: C=UΣUTC = U \Sigma U^T where UU contains the eigenvectors (principal components) and Σ\Sigma contains the eigenvalues (each singular value). U=VU = V since CC is symmetric. Each column vector uiu_i represents a axis of the data.

Formula: D=M+[RU]UTD = M + [R U]U^T.
Approximation: D≈M+[RUk]UkTD \approx M + [R U_k]U_k^T where UkU_k contains the first kk columns of UU. (dimension reduction)

Proof of the formula:

D−M=R=RI=R(UUT)=(RU)UT\begin{aligned} D - M &= R \\ &= R I \\ &= R (U U^T) \\ &= (R U) U^T \\ \end{aligned}

Or by element-wise:
Theorem: v=(v⋅i)i+(v⋅j)j+(v⋅k)kv = (v \cdot i) i + (v \cdot j) j + (v \cdot k) k where {i,j,k}\{i, j, k\} form an orthonormal basis of R3\mathbb{R}^3.

Let rij=Dij−μjr_{ij} = D_{ij} - \mu_j. Since {uj}\{u_j\} of UU form an orthonormal basis, ri=∑j=1n(ri⋅ujT)ujT=∑j=1n(riuj)ujTr_i = \sum\limits_{j=1}^{n} (r_i \cdot u_j^T) u_j^T = \sum\limits_{j=1}^{n} (r_i u_j) u_j^T. [(riuj)(r_i u_j) is the scalar coefficient].
Therefore, R=(RU)UTR = (R U) U^T.

d=m+[(d−m)u1]u1T+[(d−m)u2]u2T+...+[(d−m)un]unTd = m + [(d - m) u_1] u_1^T + [(d - m) u_2] u_2^T + ... + [(d - m) u_n] u_n^T for each data point dd (row of DD).

Matrices and Tensors

A matrix is a 2-dimensional array of numbers, while a tensor is a multi-dimensional array of numbers. Tensors generalize matrices to higher dimensions.

Application of SVD Eigenfaces

Eigenfaces are a set of eigenvectors used in the computer vision problem of human face recognition. They are derived from the covariance matrix of a set of facial images using Singular Value Decomposition (SVD).

Data matrix D∈Rm×nD \in \mathbb{R}^{m \times n}, where mm is the number of images and nn is the number of pixels in each image (flattened). For example, there are 400 images of size 64x64 pixels, then m=400m = 400 and n=4096n = 4096.

For each pixel, we have the mean μj=1m∑i=1mDij\mu_j = \frac{1}{m} \sum\limits_{i=1}^{m} D_{ij} and variance σj2=1m−1∑i=1m(Dij−μj)2\sigma_j^2 = \frac{1}{m-1} \sum\limits_{i=1}^{m} (D_{ij} - \mu_j)^2. Then we have the normal distribution of pixel values across all images: N(μj,σj2)N(\mu_j, \sigma_j^2). We can sample randomly from this distribution to create new pixel values for new face images.

New faces: f=m+a1u1T+a2u2T+...+akukTf = m + a_1 u_1^T + a_2 u_2^T + ... + a_k u_k^T where aia_i are random coefficients sampled from N(0,σi2)N(0, \sigma_i^2), and uiu_i are the top kk eigenfaces.

what is eigenfaces?

  1. Compute the mean face: μ=1m∑i=1mDi\mu = \frac{1}{m} \sum\limits_{i=1}^{m} D_i where DiD_i is the ii-th image vector.
  2. Center the data: X=D−μX = D - \mu.
  3. Compute the covariance matrix: C=1m−1XTXC = \frac{1}{m-1} X^T X.
  4. Perform SVD on the covariance matrix: C=UΣUTC = U \Sigma U^T.
  5. The columns of UU are the eigenfaces.
def compute_eigenfaces(D, k):
    # D: data matrix of shape (m, n)
    # k: number of principal components to keep
    m, n = D.shape
    mu = np.mean(D, axis=0)  # mean face
    X = D - mu  # center the data
    C = np.cov(X, rowvar=False)  # covariance matrix
    U, S, Vt = np.linalg.svd(C)  # SVD
    eigenfaces = U[:, :k]  # top k eigenfaces
    return eigenfaces, mu
def generate_new_face(eigenfaces, mu):
    k = eigenfaces.shape[1]
    coefficients = np.random.randn(k)  # random coefficients
    new_face = mu + eigenfaces @ coefficients  # generate new face
    return new_face

Billiard Ball Simulation with Collision Detection

Conditions:

  1. Undisturbed motion between collisions (constant velocity).
  2. Perfectly elastic collisions (no energy loss).
  3. No external forces (e.g., friction, gravity).
  4. detect collisions between balls and walls, and between balls themselves.

Representation:

  • position vector p=[x,y]\mathbf{p} = [x, y], velocity vector v=[vx,vy]=[dxdt,dydt]\mathbf{v} = [v_x, v_y] = [\frac{dx}{dt}, \frac{dy}{dt}], radius rr, and mass mm.
  • the distance between two balls is given by d=∣p1−p2∣=(x1−x2)2+(y1−y2)2d = |\mathbf{p_1} - \mathbf{p_2}| = \sqrt{(x_1 - x_2)^2 + (y_1 - y_2)^2}.
  • The walls of the billiard table are represented as lines with defined boundaries.

Undisturbed Motion:

  • x′=x+vxdtx' = x + v_x dt
  • y′=y+vydty' = y + v_y dt

Collision with Walls:

  1. Detect collision with walls:

    • Left Wall: x′<xmin+rx' < x_{min} + r
    • Right Wall: x′>xmax−rx' > x_{max} - r
    • Bottom Wall: y′<ymin+ry' < y_{min} + r
    • Top Wall: y′>ymax−ry' > y_{max} - r
  2. Find the time of collision:

    • Left Wall: dtl=(xmin+r)−xvxdt_{l} = \frac{(x_{min} + r) - x}{v_x} if vx<0v_x < 0
    • Right Wall: dtr=(xmax−r)−xvxdt_{r} = \frac{(x_{max} - r) - x}{v_x} if vx>0v_x > 0
    • Bottom Wall: dtb=(ymin+r)−yvydt_{b} = \frac{(y_{min} + r) - y}{v_y} if vy<0v_y < 0
    • Top Wall: dtt=(ymax−r)−yvydt_{t} = \frac{(y_{max} - r) - y}{v_y} if vy>0v_y > 0
    • Choose the smallest positive dtdt among these to determine the next collision time.
  3. Adjust motion velocity:

    • Left or Right Wall: v′=[−vx,vy]v' = [-v_x, v_y]
    • Bottom or Top Wall: v′=[vx,−vy]v' = [v_x, -v_y]

Collision between Balls:

  1. Detect collision between balls:

    • For two balls with positions p1′\mathbf{p_1}' and p2′\mathbf{p_2}', and radii r1r_1 and r2r_2, a collision occurs if: ∣p1′−p2′∣=(x1′−x2′)2+(y1′−y2′)2≤r1+r2|\mathbf{p_1}' - \mathbf{p_2}'| = \sqrt{(x_1' - x_2')^2 + (y_1' - y_2')^2} \leq r_1 + r_2
  2. Find the time of collision:

    • dt=∣p1−p2∣−(r1+r2)∣v1−v2∣dt = \dfrac{|\mathbf{p_1} - \mathbf{p_2}| - (r_1 + r_2)}{|\mathbf{v_1} - \mathbf{v_2}|}
      ∣v1−v2∣=(v1x−v2x)2+(v1y−v2y)2|\mathbf{v_1} - \mathbf{v_2}| = \sqrt{(v_{1x} - v_{2x})^2 + (v_{1y} - v_{2y})^2}
  3. Adjust motion velocities upon collision:

    • Fact: v=(v⋅i)i+(v⋅j)jv = (v \cdot i) i + (v \cdot j) j for any coordinate system with orthonormal basis vectors i\mathbf{i} and j\mathbf{j}.

    • The unit normal vector n=p1−p2∣p1−p2∣\mathbf{n} = \frac{\mathbf{p_1} - \mathbf{p_2}}{|\mathbf{p_1} - \mathbf{p_2}|} at the point of collision.

    • The tangential vector t=[−ny,nx]\mathbf{t} = [ -n_y, n_x ] is perpendicular to n\mathbf{n}.

    • v=(v⋅n)n+(v⋅t)tv = (v \cdot n) n + (v \cdot t) t where n\mathbf{n} is the normal vector and t\mathbf{t} is the tangential vector at the point of collision.

    • v1=\bmatrixv1n,v1tv_1 = \bmatrix v_{1n}, v_{1t} and v2=[v2n,v2t]v_2 = [v_{2n}, v_{2t}], then v1′=[v2n,v1t]v_1' = [v_{2n}, v_{1t}] and $v_2' = [v_{1n}, v_{2t}].

Search

Loading search…