Iterative Solvers for Linear Systems
Solve huge systems without factoring: improve a guess step by step, each step costing one matrix-vector multiply. The only option past millions of unknowns.
Why Does This Exist?
Direct solvers factor the matrix at . At that is operations: over. Yet science and ML routinely solve systems that large (PDE discretisations, graph Laplacians, Hessians). Iterative solvers never factor anything. They hold a guess , spend one matrix-vector multiply to improve it, and stop when the residual is small enough. Cost per step dense, sparse; total cost set by how fast the guesses converge.
Three methods cover the territory. Jacobi updates every coordinate from the old guess simultaneously. Gauss-Seidel reuses fresh values within the sweep, roughly doubling the speed. Conjugate gradient (CG) takes mutually conjugate directions and finishes SPD systems in at most steps in exact arithmetic, far fewer with clustered eigenvalues. Direct foundations are in linear systems and least squares; the giant-sparse regime continues in sparse matrix methods.
The one idea you need first
The residual measures how far a guess is from solving: zero means done. Iterative methods drive a norm of down without ever inverting. Convergence needs conditions (diagonal dominance for Jacobi/Gauss-Seidel, symmetric positive definiteness for CG), and violating them diverges or stalls rather than erroring.
Think of It Like This
Focusing a telescope by small turns
A telescope starts blurry. You turn one knob, check sharpness, turn the next, recheck. Each adjustment is cheap; the image converges without ever disassembling the optics (the direct-solver equivalent of a full rebuild per view).
Jacobi turns all knobs from the same blurry view, then looks. Gauss-Seidel looks after every single knob, so later knobs benefit from earlier ones in the same round. Conjugate gradient remembers past turns and never re-explores a direction, which is why it finishes in few rounds on friendly (well-conditioned, clustered-spectrum) skies.
How It Actually Works
Split with diagonal. Jacobi iterates : each coordinate solved fresh from stale neighbours. Converges if is strictly diagonally dominant (each diagonal beats its row sum). Gauss-Seidel splits (lower plus upper) and uses new values immediately: , via forward substitution per sweep. CG applies only to SPD : it minimises along -conjugate directions, converging at a rate set by rather than , which preconditioning improves by clustering eigenvalues.
Worked example
Solve by Jacobi from . The exact answer is .
- Step 1:
- Step 2:
Two cheap steps land at , already within of . Diagonal dominance (, ) guarantees the march continues to the answer. Gauss-Seidel would reuse inside step 1's second coordinate and arrive slightly faster.
Code
The point is the check: run Jacobi and confirm the iterates approach the exact answer.
def jacobi(a11: float, a12: float, a21: float, a22: float, b1: float, b2: float, steps: int) -> list[float]: x1, x2 = 0.0, 0.0 for _ in range(steps): x1, x2 = (b1 - a12 * x2) / a11, (b2 - a21 * x1) / a22 return [x1, x2]
print([round(v, 4) for v in jacobi(4, 1, 1, 3, 1, 2, 1)]) # -> [0.25, 0.6667]print([round(v, 4) for v in jacobi(4, 1, 1, 3, 1, 2, 2)]) # -> [0.0833, 0.5833]Note the subtlety the code hides: both updates in one line use the old pair on the right (tuple assignment evaluates first), which is exactly Jacobi semantics. Gauss-Seidel would assign sequentially instead.
Watch Out For
Running conjugate gradient on a non-SPD matrix
CG minimises an energy that exists only for symmetric positive definite . On indefinite or asymmetric systems it can stagnate, oscillate or return confident garbage with a small residual in the wrong norm. Verify SPD (Cholesky succeeds, eigenvalues positive) before CG; otherwise reach for GMRES or MINRES, which handle asymmetry and indefiniteness respectively.
Iterating an ill-conditioned system without a preconditioner
CG converges in steps, so means a thousand iterations of expensive matvecs. A preconditioner that is cheap to invert clusters the spectrum of and collapses the count. Jacobi itself doubles as the cheapest preconditioner (diagonal scaling). Unpreconditioned iteration on hard problems is how clusters burn budgets.
The Quick Version
- Iterative solvers refine guesses per matvec instead of factoring at .
- Jacobi updates from stale values; Gauss-Seidel reuses fresh ones; CG finishes SPD systems via conjugate directions.
- Two Jacobi steps reach , near the exact .
- Convergence needs conditions: diagonal dominance, or SPD for CG.
- CG on non-SPD input and unpreconditioned runs on ill-conditioned systems are the two classic failures.