SigmaField
Mathematical Foundations for Quant Finance
0 of 256 lessons
      1. 6.5.1 The explicit scheme and stabilityConcept · 35 min
      2. 6.5.2 Implicit schemes and Crank–NicolsonConcept · 35 min
      3. 6.5.3 Practice set: finite differencesPractice set · 20 min
      4. 6.5.4 Case study: pricing a European option on a gridCase study · 35 min

Level 6, Differential equations 6.5 Finite differences for PDEs Lesson 2 of 4

ConceptLesson 6.5.2 in Level 6, Differential equations. About 35 minutes.

Implicit schemes and Crank–Nicolson

The implicit scheme

Lesson 6.5.1 replaced uxxu_{xx} in ut=uxxu_t = u_{xx} by the second difference at the old time tnt_n. Take it at the new time tn+1t_{n + 1} instead:

uin+1−uinΔt=ui+1n+1−2uin+1+ui−1n+1Δx2\frac{u_i^{n+1} - u_i^n}{\Delta t} = \frac{u_{i+1}^{n+1} - 2u_i^{n+1} + u_{i-1}^{n+1}}{\Delta x^2}

Multiply by Δt\Delta t, write r=ΔtΔx2r = \frac{\Delta t}{\Delta x^2} as before, and gather the new values on the left:

Rule: The implicit scheme

−r ui−1n+1+(1+2r) uin+1−r ui+1n+1=uin-r\,u_{i-1}^{n+1} + (1 + 2r)\,u_i^{n+1} - r\,u_{i+1}^{n+1} = u_i^n

One equation for each inside point i=1,…,M−1i = 1, \ldots, M - 1. Each new value depends on its new neighbours, which are unknown too. So the scheme is implicit: a step solves all the equations together, as a linear system (lesson 3.3.1).

Seen from the new time, the time difference is now a backward difference (lesson 2.2.2). Its error is about −12utt Δt-\frac{1}{2}u_{tt}\,\Delta t (lesson 2.8.1), the same size as the forward difference's, so the implicit scheme is still first order in time.

One step by hand

Take M=4M = 4 cells with both ends held at 0. Start with a spike, 1 at the middle point and 0 elsewhere, and take r=1r = 1.

Call the three new inside values aa, bb and cc. Then the rule gives

3a−b=0−a+3b−c=1−b+3c=0\begin{aligned} 3a - b &= 0 \\ -a + 3b - c &= 1 \\ -b + 3c &= 0 \end{aligned}

Elimination (lesson 3.3.1) clears the matrix below its diagonal in two steps:

stepoperationnew rownew right side
1R2+13R1R_2 + \frac{1}{3}R_10, 83, −10,\ \frac{8}{3},\ -11
2R3+38R2R_3 + \frac{3}{8}R_20, 0, 2180,\ 0,\ \frac{21}{8}38\frac{3}{8}

Back substitution gives c=38÷218=17c = \frac{3}{8} \div \frac{21}{8} = \frac{1}{7}, then b=(1+c)÷83=37b = (1 + c) \div \frac{8}{3} = \frac{3}{7}, then a=b3=17a = \frac{b}{3} = \frac{1}{7}.

leftmiddleright
start010
explicit step, r=1r = 11−1-11
implicit step, r=1r = 10.14290.42860.1429

At r=1r = 1 the explicit scheme is unstable, and its middle value has gone negative, which heat never does. The implicit step spreads the spike smoothly. Its values add up to 57\frac{5}{7}, less than 1, because heat leaks out through the cold ends.

Boundary values

The first and last equations contain an end value. In the first, −r u0n+1-r\,u_0^{n+1} is known from the boundary condition, so it moves to the right side: (1+2r) u1n+1−r u2n+1=u1n+r u0n+1(1 + 2r)\,u_1^{n+1} - r\,u_2^{n+1} = u_1^n + r\,u_0^{n+1}.

The last equation gains r uMn+1r\,u_M^{n+1} the same way. With both ends at 0, as here, nothing is added.

Try it

A is the matrix of the three equations and b their right side. The cell does the two elimination steps of the table and prints the new rows, then solves the system with np.linalg.solve.

The last line is lesson 6.5.1's explicit step at r=1r = 1, for comparison.

⌘/Ctrl + Enter runs the cell

Tridiagonal systems

With more points the matrix keeps the same pattern: 1+2r1 + 2r down the diagonal, −r-r just above and just below it, and 0 everywhere else. For four inside points:

A=(1+2r−r00−r1+2r−r00−r1+2r−r00−r1+2r)A = \begin{pmatrix} 1 + 2r & -r & 0 & 0 \\ -r & 1 + 2r & -r & 0 \\ 0 & -r & 1 + 2r & -r \\ 0 & 0 & -r & 1 + 2r \end{pmatrix}

A matrix whose only nonzero entries lie on the diagonal and the two lines beside it is tridiagonal. Each step of the implicit scheme solves Aun+1=bA\mathbf{u}^{n+1} = \mathbf{b}, where un+1\mathbf{u}^{n+1} holds the new inside values and b\mathbf{b} the old ones plus the boundary terms.

Elimination is cheap here. Each pivot has just one nonzero entry below it, and clearing it adds nothing new to the rows below. So the work grows like the number of points, not like its cube, as it does for a full matrix.

It is also safe. Each diagonal entry, 1+2r1 + 2r, is larger than the two others in its row put together, 2r2r. So elimination never meets a small pivot and needs no row swaps: the pivots above were 3, 83\frac{8}{3} and 218\frac{21}{8}, all above 2.

The condition number of lesson 3.3.2 is small too: 2.78 for the matrix above, and never more than 1+4r1 + 4r.

Rule: Solving a tridiagonal system

solve_banded((1, 1), ab, b)\texttt{solve\_banded((1, 1), ab, b)}

From scipy.linalg; the (1, 1) says one line above the diagonal and one below. ab stores them as three rows: the line above, shifted right by one; the diagonal; the line below, shifted left by one. The unused corners can hold anything.

For the example, ab is (∗−1−1333−1−1∗)\begin{pmatrix} \ast & -1 & -1 \\ 3 & 3 & 3 \\ -1 & -1 & \ast \end{pmatrix}, where ∗\ast marks the unused corners.

A full matrix wastes room. With 10,000 points it holds 10810^8 numbers, 800 MB, almost all of them 0. The three lines hold 30,000 numbers.

Try it

The first lines store the example's three lines in ab, with 0 in the corners, and solve it with solve_banded.

Then the condition number of the example, and of the matrix for 99 inside points with r=1r = 1 and r=5r = 5, beside 1+4r1 + 4r.

⌘/Ctrl + Enter runs the cell

Stable for every r

Lesson 6.5.1 measured stability with a zig-zag, whose second difference is −4-4 times itself. Put it into the implicit rule: (1+4r) un+1=un(1 + 4r)\,u^{n+1} = u^n, so each step multiplies the zig-zag by 11+4r\frac{1}{1 + 4r}.

That factor lies between 0 and 1 for every r>0r > 0. The zig-zag shrinks without flipping sign, and so does every smoother wave. The implicit scheme is unconditionally stable: no limit on rr.

rr0.250.51510
explicit, 1−4r1 - 4r0−1-1−3-3−19-19−39-39
implicit, 11+4r\frac{1}{1 + 4r}0.50.33330.20.04760.0244

Lesson 6.5.1's tent, min⁡(x,1−x)\min(x, 1 - x) on 20 cells, shows it. At r=5r = 5, ten times the explicit limit, the largest value falls to 0.3909, 0.3339, 0.2284 and 0.1272 after 1, 2, 5 and 10 steps. No value ever goes negative.

Now accuracy limits the step.

Take lesson 6.5.1's rod with its ends at 0 and 1. In 20 implicit steps of Δt=0.05\Delta t = 0.05 (r=5r = 5) it reaches the line u=xu = x, to within 2.19×10−42.19 \times 10^{-4} at t=1t = 1. The explicit scheme took 250 steps but got within 2.91×10−52.91 \times 10^{-5}: bigger steps, bigger errors.

Try it

implicit builds ab once, then each step adds the boundary terms to the old values and solves. The zig-zag factors come first.

Then the tent at r=5r = 5, with its largest and smallest values, and the rod with its ends at 0 and 1.

⌘/Ctrl + Enter runs the cell

Crank–Nicolson

The explicit scheme takes uxxu_{xx} at the old time, the implicit one at the new time. The Crank–Nicolson scheme takes the average of the two. Write δ2ui=ui+1−2ui+ui−1\delta^2 u_i = u_{i+1} - 2u_i + u_{i-1} for the second difference at point ii:

uin+1−uinΔt=δ2uin+δ2uin+12 Δx2\frac{u_i^{n+1} - u_i^n}{\Delta t} = \frac{\delta^2 u_i^n + \delta^2 u_i^{n+1}}{2\,\Delta x^2}

Gather the new values on the left and the old ones on the right:

Rule: Crank–Nicolson

−r2ui−1n+1+(1+r) uin+1−r2ui+1n+1=r2ui−1n+(1−r) uin+r2ui+1n\begin{gathered} -\tfrac{r}{2}u_{i-1}^{n+1} + (1 + r)\,u_i^{n+1} - \tfrac{r}{2}u_{i+1}^{n+1} \\[4pt] = \tfrac{r}{2}u_{i-1}^n + (1 - r)\,u_i^n + \tfrac{r}{2}u_{i+1}^n \end{gathered}

The left side is a tridiagonal system, as for the implicit scheme, with 1+r1 + r on the diagonal and −r2-\frac{r}{2} beside it. The right side is an explicit step of half the size, worked out from the old values.

The values each scheme links in one step, with their weights. When more than one new value appears, the new values are tied together and must be solved for at once: a tridiagonal system.

Why the average helps: uin+1−uinΔt\frac{u_i^{n+1} - u_i^n}{\Delta t} is a central difference about the half step tn+12Δtt_n + \frac{1}{2}\Delta t. The average of the two second differences sits at that half step too. Lesson 2.8.1's central difference has an error in h2h^2, not hh, and so does this one: Crank–Nicolson's time error shrinks like Δt2\Delta t^2.

The zig-zag factor is 1−2r1+2r\frac{1 - 2r}{1 + 2r}, which lies between −1-1 and 1 for every rr. So Crank–Nicolson is unconditionally stable too.

Back to the spike with r=1r = 1. The right side is (0.5,0,0.5)(0.5, 0, 0.5), and the system 2a−0.5b=0.52a - 0.5b = 0.5, −0.5a+2b−0.5c=0-0.5a + 2b - 0.5c = 0, −0.5b+2c=0.5-0.5b + 2c = 0.5 gives a=c=27≈0.2857a = c = \frac{2}{7} \approx 0.2857 and b=17≈0.1429b = \frac{1}{7} \approx 0.1429.

The middle has fallen below its neighbours: a dip the true solution never has. The last section of this lesson comes back to it.

Try it

crank_nicolson adds half an explicit step to the old values, then solves the tridiagonal system with solve_banded. The two += lines add the boundary terms; here both ends are 0.

The cell takes one step from the spike with r=1r = 1, then prints the zig-zag factor for five values of rr.

⌘/Ctrl + Enter runs the cell

Three schemes compared

Take lesson 6.5.1's rod with the profile sin⁡(πx)\sin(\pi x), whose exact solution is e−π2tsin⁡(πx)e^{-\pi^2 t}\sin(\pi x), and run to t=0.1t = 0.1. Refine space and time together, keeping Δt=Δx10\Delta t = \frac{\Delta x}{10}, so rr grows from 1 to 8: far too large for the explicit scheme. It runs instead at r=0.4r = 0.4, with the many more steps that needs.

cellsstepsimplicit errorCrank–Nicolson errorexplicit stepsexplicit error
10102.03×10−22.03 \times 10^{-2}2.73×10−32.73 \times 10^{-3}254.29×10−34.29 \times 10^{-3}
20209.63×10−39.63 \times 10^{-3}6.82×10−46.82 \times 10^{-4}1001.06×10−31.06 \times 10^{-3}
40404.68×10−34.68 \times 10^{-3}1.70×10−41.70 \times 10^{-4}4002.65×10−42.65 \times 10^{-4}
80802.30×10−32.30 \times 10^{-3}4.26×10−54.26 \times 10^{-5}1,6006.62×10−56.62 \times 10^{-5}

Each halving of both steps halves the implicit error: its Δt\Delta t term is the larger one. It divides Crank–Nicolson's error by 4, since both its terms are squares. On 80 cells, Crank–Nicolson takes 80 steps to beat what the explicit scheme gets in 1,600.

Rule: Three schemes

explicit: Δt+Δx2, r≤12implicit: Δt+Δx2, any rCrank–Nicolson: Δt2+Δx2, any r\begin{gathered} \text{explicit: } \Delta t + \Delta x^2, \ r \le \tfrac{1}{2} \\[4pt] \text{implicit: } \Delta t + \Delta x^2, \text{ any } r \\[4pt] \text{Crank–Nicolson: } \Delta t^2 + \Delta x^2, \text{ any } r \end{gathered}

How the error of each scheme shrinks, and when it is stable. The two implicit schemes cost one tridiagonal solve per step, which is cheap, so Crank–Nicolson is the usual choice.

Try it

theta_step does one step of either scheme: theta = 1 is implicit, theta = 0.5 is Crank–Nicolson (the weight on the new time). explicit is lesson 6.5.1's.

For each grid the cell prints the steps and the largest error of each scheme.

⌘/Ctrl + Enter runs the cell

Oscillations near a kink

Crank–Nicolson has one weakness. Start from the kink max⁡(x,0)\max(x, 0) on [−3,3][-3, 3], with the ends held, and take large steps: Δx=0.1\Delta x = 0.1 and Δt=0.1\Delta t = 0.1, so r=10r = 10. After 5 steps, at t=0.5t = 0.5, compare with the exact solution of lesson 6.4.2, u=x N ⁣(x2t)+2t φ ⁣(x2t)u = x\,N\!\left(\frac{x}{\sqrt{2t}}\right) + \sqrt{2t}\,\varphi\!\left(\frac{x}{\sqrt{2t}}\right).

Here NN and φ\varphi are the standard normal distribution function and density. The values look fine: for ∣x∣≤1.5|x| \le 1.5 they are within 1.0×10−21.0 \times 10^{-2} of the exact solution for the implicit scheme, 1.2×10−21.2 \times 10^{-2} for Crank–Nicolson. The second differences tell another story:

xx−0.2-0.2−0.1-0.100.10.2
exact uxxu_{xx}0.3910.3970.3990.3970.391
implicit0.4210.4300.4330.4300.421
Crank–Nicolson0.5452.065−2.764-2.7642.0650.545

These are spurious oscillations: a zig-zag that the true solution does not have. The kink holds a little of every wave, the zig-zag included. Crank–Nicolson multiplies the zig-zag by 1−2r1+2r=−0.9048\frac{1 - 2r}{1 + 2r} = -0.9048 per step, so it flips sign each step and hardly shrinks.

The values from the three solutions look alike, but their second differences do not. Crank–Nicolson's large steps leave a zig-zag at the kink that the implicit scheme removes at once.

The oscillation hides in the values and shows in the curvature. Case study 6.5.4 reads an option's gamma, a second derivative, off such a grid, so it matters there.

Two remedies are standard. Keep rr moderate near the kink: with Δt=0.01\Delta t = 0.01 (r=1r = 1) the factor is −13-\frac{1}{3} and the zig-zag dies quickly.

Or start with the implicit scheme, which removes the zig-zag at once. Replace the first step by two implicit steps of half the length, then carry on with Crank–Nicolson. This is Rannacher's start, after the mathematician who studied it.

With Rannacher's start the values are within 1.2×10−31.2 \times 10^{-3}, ten times closer than either scheme alone. The second differences are 0.383, 0.398, 0.424, 0.398 and 0.383, with a largest error of 0.025 near the kink.

Try it

theta_step is from the last cell, and exact is lesson 6.4.2's solution for the kink, whose uxxu_{xx} at t=0.5t = 0.5 is φ(x)\varphi(x). Each run prints its largest value error for ∣x∣≤1.5|x| \le 1.5, its second differences at the five middle points and their largest error.

The third run is Rannacher's start: two implicit half steps, then four Crank–Nicolson steps.

⌘/Ctrl + Enter runs the cell

Common mistakes

  1. Forgetting the boundary terms. A known end value moves to the right side of the first or last equation. Leaving it out holds that end at 0.
  2. Building the full matrix. np.linalg.solve gives the right answer, but its memory grows like the square of the points and its work like the cube. Use solve_banded.
  3. Misplacing the lines in ab. The line above the diagonal is shifted right, ab[0, 1:]; the line below is shifted left, ab[2, :-1].
  4. Taking stable for accurate. The implicit scheme survives any Δt\Delta t, but its error grows with Δt\Delta t.
  5. Copying the explicit weights into Crank–Nicolson. Its right side has 1−r1 - r in the middle, not 1−2r1 - 2r: each side carries half the second difference.
  6. Trusting Crank–Nicolson's curvature near a kink. With large rr the values look smooth while the second differences zig-zag. Take smaller steps there, or start with implicit steps.

Implicit schemes and Crank–Nicolson

0 of 12 correct

  1. 1.
  2. 2.
  3. 3.
  4. 4.
  5. 5.
  6. 6.
  7. 7.
  8. 8.
  9. 9.
  10. 10.
  11. 11.
  12. 12.
How to type answers
  • Powers with ^: x^7, 2^(1/3), a^-2.
  • Multiply with * or by writing side by side: 3x^2, 2(x+1).
  • ln(x) is the natural log, log(x, 2) is log base 2, e is Euler's number, sqrt(x) is a square root.
  • sin(x), cos(x) and tan(x) take radians; write pi for π and sin(x)^2 for sin²x.
  • Your first answer to each question is saved: it counts towards your score and brings the question back for review.
  • Exact answers like ln(20)/ln(3) are best. Decimals need about 4 significant figures.

Summary card

  • The implicit scheme takes the second difference at the new time: −r ui−1n+1+(1+2r) uin+1−r ui+1n+1=uin-r\,u_{i-1}^{n+1} + (1 + 2r)\,u_i^{n+1} - r\,u_{i+1}^{n+1} = u_i^n. Each step solves a tridiagonal system, with known end values moved to the right side.
  • scipy.linalg.solve_banded((1, 1), ab, b) solves it with work proportional to the number of points; ab holds the line above (shifted right), the diagonal and the line below (shifted left).
  • The implicit scheme multiplies a zig-zag by 11+4r\frac{1}{1 + 4r}: stable for every rr, but first order in time.
  • Crank–Nicolson averages the explicit and implicit second differences. It is stable for every rr, and its error shrinks like Δt2+Δx2\Delta t^2 + \Delta x^2.
  • Near a kink with large rr, Crank–Nicolson leaves a zig-zag (factor 1−2r1+2r\frac{1 - 2r}{1 + 2r}, close to −1-1) that shows in the second differences. Take smaller steps there, or start with two implicit half steps (Rannacher's start).

Free further reading

Optional. This lesson covers what you need; these add more examples and practice. All are free to read.