The Crank–Nicolson Method

The explicit scheme for the heat equation is a delight to program — one line of arithmetic per grid point — but it comes with a leash. As the stability analysis shows, it is only conditionally stable: the mesh ratio must obey r = \alpha\,\Delta t/\Delta x^2 \le \tfrac12. Refine the spatial grid to chase some fine detail — halve \Delta x — and the largest legal time step drops by a factor of four, because the bound scales with \Delta x^2. On a genuinely fine grid you can be forced into millions of absurdly tiny steps just to keep the arithmetic from exploding.

The cure is to stop computing the new values one at a time and instead solve for the whole new time level at once. Schemes that do this are implicit, and the most celebrated member of the family — the workhorse of practical diffusion solvers since the 1940s — is the Crank–Nicolson method. It buys something remarkable: it is unconditionally stable (no cap on \Delta t at all) and, at the same time, second-order accurate in both space and time. The price is a small linear system solved once per step — and, as we will see, that system is tridiagonal, so the cost is almost as cheap as the explicit rule anyway.

One dial: the θ-method

The explicit and implicit schemes are not really two separate ideas — they are the two ends of a single dial. Start from the heat equation u_t = \alpha\,u_{xx} and, as always, replace the time derivative by a forward difference between level n and level n+1. The only question is where to evaluate the spatial second difference

\delta^2 u_i = u_{i+1} - 2u_i + u_{i-1}

— at the old level, the new level, or somewhere in between? The θ-method refuses to choose and takes a weighted average, with a single knob \theta \in [0,1]:

\frac{u_i^{n+1} - u_i^n}{\Delta t} = \frac{\alpha}{\Delta x^2}\Big[\,\theta\,\delta^2 u_i^{n+1} \; + \; (1-\theta)\,\delta^2 u_i^{n}\,\Big].

Turning the dial recovers three classic schemes:

So Crank–Nicolson is not an exotic new construction — it is simply the θ-method with the dial set dead-centre, averaging the old and new spatial curvatures.

The update: a tridiagonal system

Set \theta = \tfrac12 and write the mesh ratio r = \alpha\,\Delta t/\Delta x^2. Multiplying through by \Delta t and gathering every new-level value on the left, every old-level value on the right, gives the Crank–Nicolson update at each interior point i:

-\tfrac{r}{2}\,u_{i-1}^{n+1} + (1+r)\,u_i^{n+1} - \tfrac{r}{2}\,u_{i+1}^{n+1} \;=\; \tfrac{r}{2}\,u_{i-1}^{n} + (1-r)\,u_i^{n} + \tfrac{r}{2}\,u_{i+1}^{n}.

The right-hand side is entirely known — just old numbers combined with arithmetic, exactly like the explicit scheme. The left-hand side is where the difference lives: three unknown new values are tied together in one equation. Writing this equation at every interior grid point stacks up into a linear system

A\,\mathbf{u}^{n+1} = \mathbf{d},

where \mathbf{d} collects the known right-hand sides (plus the boundary values) and A is tridiagonal: the constant 1+r runs down the main diagonal, and -\tfrac{r}{2} sits on the two neighbouring diagonals — nothing anywhere else. That special shape matters enormously: a tridiagonal system of M unknowns is solved by the Thomas algorithm in O(M) work — one forward sweep and one back-substitution — so an implicit step costs only a small constant multiple of an explicit one, not the O(M^3) of a general matrix solve.

Why it is unconditionally stable

Run the same von Neumann test as before: feed in a single Fourier mode u_i^n = G^n e^{\mathrm{i} k x_i} and ask by how much one step multiplies it. Substituting into the Crank–Nicolson update and writing s = \sin^2\!\big(\tfrac{k\,\Delta x}{2}\big), the exponentials cancel and leave the amplification factor

G = \frac{1 - 2r\,s}{1 + 2r\,s}.

Here is the whole argument in one line. Because r > 0 and s \ge 0, the quantity 2rs is never negative, so the denominator 1 + 2rs is always at least as large in size as the numerator 1 - 2rs:

|1 - 2r s| \le 1 + 2r s \quad\Longrightarrow\quad |G| \le 1 \quad\text{for every mode } k.

No condition on r appears anywhere — the inequality holds for r = 0.5, for r = 50, for r = 5000. Contrast the explicit scheme, whose factor G = 1 - 4r s sails past -1 the moment r > \tfrac12. Crank–Nicolson simply cannot blow up. (Compare the fully implicit scheme, G = 1/(1+4rs), which is also unconditionally stable but loses the second-order time accuracy.)

One step, in code

The entire method is: build the known right-hand side from the old row, then solve the tridiagonal system for the new row. Because the matrix is tridiagonal, the solve is the classic Thomas algorithm — a forward sweep to eliminate the sub-diagonal, then a back-substitution. Here is one Crank–Nicolson step on the interior points, with the ends held at fixed (Dirichlet) boundary values:

// One Crank–Nicolson step on interior points 1 .. N-1 (Dirichlet ends held fixed). // Solve A u^{n+1} = d, where A = tridiag(-r/2, 1+r, -r/2). function crankNicolsonStep(u: number[], r: number): number[] { const N = u.length - 1; const a = -r / 2, b = 1 + r, c = -r / 2; // sub-, main-, super-diagonal // Right-hand side d[i], built entirely from the OLD level u. const d: number[] = []; for (let i = 1; i < N; i++) d[i] = (r / 2) * u[i - 1] + (1 - r) * u[i] + (r / 2) * u[i + 1]; // Thomas algorithm — forward sweep (modified super-diagonal cp, RHS dp). const cp: number[] = [], dp: number[] = []; cp[1] = c / b; dp[1] = d[1] / b; for (let i = 2; i < N; i++) { const m = b - a * cp[i - 1]; cp[i] = c / m; dp[i] = (d[i] - a * dp[i - 1]) / m; } // Back-substitution into the new row v (boundaries v[0], v[N] unchanged). const v = u.slice(); v[N - 1] = dp[N - 1]; for (let i = N - 2; i >= 1; i--) v[i] = dp[i] - cp[i] * v[i + 1]; return v; }

Notice there is no stability check anywhere — no test that r \le \tfrac12, because none is needed. You are free to pick \Delta t purely for accuracy, which is exactly the freedom the explicit scheme denies you.

Watch the amplification factor

This is the whole stability story on one picture. The horizontal axis is k\,\Delta x, sweeping from the smoothest mode (left) to the jagged highest-frequency mode k\,\Delta x = \pi (right); the vertical axis is the size |G| of the amplification factor. Anything above the dashed |G| = 1 line grows each step — an instability. Drag the mesh ratio r upward: the explicit curve |1 - 4r\,s| lifts its right end clean over the line the instant r passes 0.5, while the Crank–Nicolson curve \big|(1-2r s)/(1+2r s)\big| stays pinned at or below 1 no matter how far you push — visibly, permanently safe.

The method is named for two British mathematicians, John Crank (1916–2006) and Phyllis Nicolson (1917–1968), who published it in 1947. Their goal was thoroughly practical: solving the heat-conduction equation numerically at a time when a "computer" was often still a person with a mechanical desk calculator, and the earliest electronic machines were rare, temperamental, and desperately slow.

The explicit scheme's tiny stability-limited steps made such calculations agonisingly long by hand. Crank and Nicolson's insight — accept a bit more work per step (a tridiagonal solve) in exchange for removing the step-size limit entirely — turned an impractical multi-day computation into a feasible one. Nicolson, notably, did much of the numerical testing that showed the scheme actually behaved as the algebra promised. Nearly eighty years later their averaging trick is still the default time-stepper in countless diffusion, option-pricing, and reaction–diffusion codes.

Unconditional stability is not the same as accuracy. "Stable" only promises that errors will not explode — it says nothing about whether the answer is any good. Because Crank–Nicolson lets you take an arbitrarily large \Delta t without blowing up, it is tempting to crank the step way up to save time. But the time-truncation error is still O(\Delta t^2): too large a step quietly smears out sharp features and lags fast transients, giving a stable-but-wrong result. Stability keeps the numbers finite; accuracy is a separate budget you still have to pay.

There is a second, subtler trap. For the roughest mode, the amplification factor tends to G \to -1 as r grows large. A factor near -1 is stable (its size is 1) but it barely damps and it flips sign every step. So on discontinuous or sharp-cornered initial data — a step profile, a hot spot switched on instantly — Crank–Nicolson with a big \Delta t can show persistent, slowly-decaying oscillations (ringing) near the jump, even though nothing is technically unstable. If you see that, shrink \Delta t, or start with a couple of strongly-damping fully-implicit steps (the "Rannacher smoothing" trick) before switching to Crank–Nicolson.