Home / LA 101 / Module 7 / Lesson 1
Stories Mode

LU Decomposition

Factoring A into a lower triangular matrix L and an upper triangular matrix U is Gaussian elimination repackaged. Once the factorization is done, solving Ax = b for any right-hand side costs only O(n²) — the most important algorithm in computational linear algebra.

~18 min read M7 · L1 Intermediate

What is LU Decomposition?

Suppose you need to solve the linear system Ax = b not once, but dozens or hundreds of times — each time with a different right-hand side vector b but the same coefficient matrix A. This situation arises constantly in engineering: finite-element solvers assemble the same stiffness matrix K and then solve Ku = f for many different load vectors f; circuit simulators build a conductance matrix G once and solve Gv = i for many current vectors i.

The naive approach — run Gaussian elimination from scratch each time — is wasteful. All the work of reducing A to row echelon form is identical regardless of b. LU decomposition captures that work once and for all by factoring A into a product of two triangular matrices.

The key insight is that the process of Gaussian elimination on A can be recorded as two triangular factors: a lower triangular matrix L whose diagonal entries are all 1, and an upper triangular matrix U that is the row echelon form of A. Once A = LU is computed, any system Ax = b is solved in two cheap triangular-system steps.

The L and U Factors

A lower triangular matrix L has all its nonzero entries on or below the main diagonal. The special case relevant to LU decomposition is a unit lower triangular matrix — one whose diagonal entries are all exactly 1, with arbitrary values below the diagonal and zeros above. An upper triangular matrix U has all its nonzero entries on or above the main diagonal. The LU factorization writes

LU Factorization
A = LU, \quad L = \begin{pmatrix} 1 & 0 & \cdots & 0 \\ l_{21} & 1 & \cdots & 0 \\ \vdots & \ddots & \ddots & \vdots \\ l_{n1} & l_{n2} & \cdots & 1 \end{pmatrix}, \quad U = \begin{pmatrix} u_{11} & u_{12} & \cdots & u_{1n} \\ 0 & u_{22} & \cdots & u_{2n} \\ \vdots & \ddots & \ddots & \vdots \\ 0 & 0 & \cdots & u_{nn} \end{pmatrix}
A is expressed as the product of a unit lower triangular matrix L and an upper triangular matrix U. L stores the multipliers used during Gaussian elimination; U is the resulting row echelon form. The factorization exists whenever A can be reduced without row swaps — and with partial pivoting it always exists.

The structure is elegant: L encodes what was done to reduce A, and U records the result. Together they preserve all the arithmetic of Gaussian elimination in a form that can be reused.

Connection to Gaussian Elimination

Gaussian elimination proceeds by choosing a pivot in each column and subtracting multiples of the pivot row from all rows below it. The multiplier used to eliminate the entry in row i using the pivot in row k is

mik = aik / akk

Ordinarily these multipliers are discarded once the elimination is done. The LU factorization saves them: the multiplier mik is stored in position (i, k) of L — the very slot that was zeroed out during elimination. Every elimination step below the diagonal fills in one entry of L. The remaining reduced matrix is U.

To see why this works, note that subtracting mik times row k from row i is equivalent to left-multiplying by an elementary matrix Eik. Performing all such operations gives E · A = U, where E is the product of elementary matrices. The inverse of E is L: the lower triangular matrix whose off-diagonal entries are exactly the multipliers mik with their signs flipped back. Because the inverse of a product of lower triangular matrices is itself lower triangular, L inherits clean triangular structure.

In short: U is what Gaussian elimination produces; L remembers how it got there.

Solving Ax = b via Forward and Back Substitution

Once the factorization A = LU is in hand, solving Ax = b becomes a two-step process. Substituting A = LU into Ax = b gives LUx = b. Introducing the intermediate vector y = Ux splits this into two triangular systems:

Forward and Back Substitution
Ax = b \;\Rightarrow\; LUx = b \;\Rightarrow\; \begin{cases} Ly = b & \text{(forward substitution)} \\ Ux = y & \text{(back substitution)} \end{cases}
Step 1 — forward substitution: solve Ly = b. Because L is lower triangular with 1s on the diagonal, y₁ = b₁ immediately, and each subsequent yᵢ is obtained by substituting the previously computed values. Step 2 — back substitution: solve Ux = y. Because U is upper triangular, xₙ = yₙ/uₙₙ immediately, and each preceding xᵢ is obtained by back-substituting.

Forward Substitution in Detail

In forward substitution, the unknowns are solved from top to bottom. Since L is unit lower triangular, the first equation is simply y₁ = b₁. The second equation is l₂₁ y₁ + y₂ = b₂, giving y₂ = b₂ − l₂₁ y₁. In general, at row i we have

yᵢ = bᵢ − Σⱼ₌₁ⁱ⁻¹ lᵢⱼ yⱼ

This costs O(n²) operations total. Back substitution for Ux = y proceeds symmetrically from the bottom up, again O(n²).

Why LU? Efficiency for Multiple Right-Hand Sides

The whole point of LU decomposition is the separation of costs. Factorizing A = LU requires approximately n³/3 multiplications and additions — a one-time O(n³) investment. Once L and U are stored, each new right-hand side b requires only a forward substitution and a back substitution, each costing O(n²).

Computational Cost
\underbrace{\frac{n^3}{3}\text{ flops}}_{{\text{factorize } A = LU}} + \underbrace{n^2\text{ flops}}_{{\text{each new } b}}
Factorization costs ~n³/3 flops (floating-point operations) — a one-time expense. Each solve costs ~n² flops. For k right-hand sides, the total cost is n³/3 + k·n² versus k·n³/3 if you reran elimination each time. The savings become enormous as k grows or n grows.

For a large system with n = 10,000, the factorization costs roughly 3.3 × 10¹¹ flops — expensive, but done once. Each subsequent solve then costs only 2 × 10⁸ flops, roughly 1,600 times cheaper. This asymmetry is why LU decomposition, not repeated Gaussian elimination, is the algorithm of choice in every serious scientific computing library.

Partial Pivoting for Numerical Stability

The basic LU factorization assumes that no pivot is zero — that we never need to divide by zero during elimination. In practice, even nonzero pivots can be numerically dangerous if they are very small: the resulting multipliers become very large, amplifying rounding errors in floating-point arithmetic.

Partial pivoting avoids this by reordering rows before each elimination step: at column k, search rows k through n for the entry with the largest absolute value, and swap that row to the pivot position. This ensures all multipliers satisfy |mik| ≤ 1, which bounds error growth.

Row reordering is encoded by a permutation matrix P. Instead of factoring A directly, partial pivoting computes the factorization of a permuted version of A:

LU with Partial Pivoting
PA = LU, \quad P \text{ permutation matrix encoding row swaps}
P is a permutation matrix encoding all the row swaps performed during pivoting. PA is the permuted (reordered) version of A, and PA = LU is always achievable. Solving Ax = b becomes: (1) permute b to get Pb, (2) forward-substitute Ly = Pb, (3) back-substitute Ux = y. In LAPACK and MATLAB, this is what happens inside every call to A\b.

Partial pivoting is nearly always sufficient. Complete pivoting — which also permutes columns — provides even stronger stability guarantees but requires tracking column swaps and is rarely used in practice.

A Worked 3×3 Example

Consider the matrix

A = [[2, 1, 1], [4, 3, 3], [8, 7, 9]]

Step 1 — Eliminate column 1. The pivot is a₁₁ = 2. The multipliers are m₂₁ = 4/2 = 2 and m₃₁ = 8/2 = 4. Subtracting 2 × row 1 from row 2 and 4 × row 1 from row 3 gives a new matrix with zeros in column 1 below the diagonal, and stores m₂₁ = 2 and m₃₁ = 4 in L.

Step 2 — Eliminate column 2. The new pivot is 1 (the (2,2) entry after step 1). The multiplier is m₃₂ = 1/1 = 1. Subtracting 1 × row 2 from row 3 completes U, and stores m₃₂ = 1 in L.

3×3 Worked Example
\begin{pmatrix}2&1&1\\4&3&3\\8&7&9\end{pmatrix} = \underbrace{\begin{pmatrix}1&0&0\\2&1&0\\4&1&1\end{pmatrix}}_{L} \underbrace{\begin{pmatrix}2&1&1\\0&1&1\\0&0&2\end{pmatrix}}_{U}
The 3×3 matrix A = [[2,1,1],[4,3,3],[8,7,9]] factors into L (lower triangular with 1s on the diagonal, multipliers below) and U (row echelon form). To verify: multiply L × U and confirm you recover A. L stores m₂₁ = 2, m₃₁ = 4, m₃₂ = 1; U is the matrix after both elimination steps.

To solve Ax = b for, say, b = [1, 3, 9]ᵀ: forward substitution gives y₁ = 1, y₂ = 3 − 2·1 = 1, y₃ = 9 − 4·1 − 1·1 = 4. Back substitution gives x₃ = 4/2 = 2, x₂ = (1 − 1·2)/1 = −1, x₁ = (1 − 1·(−1) − 1·2)/2 = 0. So x = [0, −1, 2]ᵀ.


Engineering Implication

LU decomposition is the workhorse of numerical linear algebra. MATLAB's backslash operator (A\b), NumPy's numpy.linalg.solve, and LAPACK's dgesv all compute a PA = LU factorization under the hood. Finite-element solvers assemble a global stiffness matrix once and then solve it for dozens of load cases using stored L and U factors. Circuit simulators build a modified nodal admittance matrix and solve it at each timestep, reusing the factorization when the topology is unchanged. LU decomposition is also the basis for computing matrix inverses (by solving AX = I column by column) and determinants (det A = det L · det U = product of diagonal entries of U, since det L = 1).

Key Takeaways

LU decomposition factors A = LU (or PA = LU with pivoting) by recording the multipliers of Gaussian elimination in L and the row echelon form in U. Solving Ax = b then costs only O(n²) per right-hand side after an O(n³/3) one-time factorization. Partial pivoting — choosing the largest-magnitude pivot at each step — ensures numerical stability and is standard in all production implementations. The triangular structure of L and U is what makes the two-step solve cheap: forward substitution fills in y from Ly = b top-to-bottom, and back substitution recovers x from Ux = y bottom-to-top.