Skip to content
The Lumenary
Advanced undergraduateUndergraduate (second or third year) 120 min

Mathematical biology

Populations that grow and saturate, predators and prey that cycle, epidemics that ignite or fizzle — differential equations and maps as instruments for thinking about life, with honest attention to what models cannot do.

Formally verified · 16 LeanComputationally tested · 3 PythonAI-drafted · awaiting human reviewMathematically reviewed: Awaiting human review
MotivationH

Why model life with equations?

For almost a century the Hudson's Bay Company bought pelts from trappers across northern Canada, and its records show the numbers of lynx and snowshoe hare rising and falling in roughly ten-year cycles. In the Adriatic, the marine biologist Umberto D'Ancona noticed that during the First World War, when fishing was reduced, the proportion of predatory fish in the catch at ports such as Fiume (Rijeka) went up — and asked his father-in-law, the mathematician Vito Volterra, why. During the West African Ebola epidemic of 2014–16, teams of epidemiologists estimated how many people each case was infecting, to plan treatment centres and judge whether interventions were working. In each case a mathematical model turned a vague question into a precise one.

A model is a deliberately simplified description: we decide which quantities matter (population sizes, numbers infected), which processes change them (births, predation, infection), and write those processes as equations. Then mathematics tells us what the assumptions imply — equilibria, thresholds, oscillations, chaos — often things nobody expected. Finally the implications are compared with data, and the model is revised. The statistician George Box put the spirit memorably: "all models are wrong, but some are useful".

This lesson uses ordinary differential equations (solutions, equilibria, phase portraits) and linear algebra (eigenvalues, trace and determinant). Stochastic models, in which chance plays a role, connect to Markov chains.

IntuitionH

Growth with limits

A population with plentiful resources grows at a rate proportional to its size: N′=rNN' = rN, so N(t)=N0ertN(t) = N_0e^{rt} — Malthusian, exponential growth. No real population can do this for long. Pierre-François Verhulst (1838) proposed that the per-capita growth rate falls linearly as the population approaches a carrying capacity KK:

N′=rN(1−NK).N' = rN\Big(1 - \frac NK\Big).

The logistic equation (with r = K = 1)

Small populations grow almost exponentially, then level off at the carrying capacity 1. Populations above K decline towards it. Click to draw solutions: none crosses the equilibria N = 0 and N = K.

Examples

dy/dx = y·(1 − y)

Click the field to draw a solution, or type a start point below.

Start point

Solution curves: 4. They are numerical approximations (fourth-order Runge–Kutta), not exact formulas.

Latest curve through (0, −0.05).

The picture already contains the whole qualitative story: two equilibria, N=0N = 0 (unstable: a few individuals grow) and N=KN = K (stable: every positive population approaches it), and S-shaped growth in between. The same idea in discrete time — a population counted once per generation — produces something far richer, as we shall see.

DefinitionsH

Equilibria, stability and the models

Definition— equilibrium, stability, Jacobian

For an autonomous system x′=f(x)x' = f(x) with f:Rn→Rnf : \R^n \to \R^n continuously differentiable, an equilibrium is a point x∗x^* with f(x∗)=0f(x^*) = 0. It is stable if solutions that start near x∗x^* stay near it for all t≥0t \ge 0, and locally asymptotically stable if moreover they converge to it. The Jacobian J=Df(x∗)J = Df(x^*), the matrix of partial derivatives ∂fi/∂xj\partial f_i/\partial x_j at x∗x^*, defines the linearisation y′=Jyy' = Jy for the deviation y=x−x∗y = x - x^*.

Definition— fixed points and cycles of maps

For a discrete-time model xn+1=g(xn)x_{n+1} = g(x_n), a fixed point satisfies g(x∗)=x∗g(x^*) = x^*, and a pp-cycle is a set of pp distinct points permuted cyclically by gg (fixed points of gpg^p). Stability is defined as for equilibria, with n→∞n \to \infty in place of t→∞t \to \infty; the multiplier of a fixed point is g′(x∗)g'(x^*), and of a pp-cycle the product of g′g' along the cycle.

Definition— the classical models

  • Logistic equation: N′=rN(1−N/K)N' = rN(1 - N/K), with r,K>0r, K > 0.
  • Logistic map: xn+1=fr(xn)=rxn(1−xn)x_{n+1} = f_r(x_n) = rx_n(1 - x_n), with 0<r≤40 < r \le 4 and x∈[0,1]x \in [0, 1].
  • Lotka–Volterra predator–prey: prey xx and predators yy with x′=αx−βxyx' = \alpha x - \beta xy, y′=δxy−γyy' = \delta xy - \gamma y (α,β,γ,δ>0\alpha, \beta, \gamma, \delta > 0).
  • Lotka–Volterra competition (in scaled units): x′=x(1−x−a12y)x' = x(1 - x - a_{12}y), y′=ρ y(1−y−a21x)y' = \rho\,y(1 - y - a_{21}x) (a12,a21,ρ>0a_{12}, a_{21}, \rho > 0).
  • SIR epidemic (Kermack–McKendrick): a population of NN split into susceptible SS, infectious II and removed RR, with S′=−βSI/NS' = -\beta SI/N, I′=βSI/N−γII' = \beta SI/N - \gamma I, R′=γIR' = \gamma I. Here β\beta is the rate of infectious contacts per infected person and 1/γ1/\gamma the mean infectious period.

Definition— basic reproduction number

In the simple SIR model, R0=β/γR_0 = \beta/\gamma: the expected number of new infections caused by one infectious individual — infecting at rate β\beta for an average time 1/γ1/\gamma — in a population where everyone else is susceptible.

ProofH

One species: logistic growth and harvesting

Theorem— Theorem (the logistic equation)

For N0>0N_0 > 0 the logistic equation has the unique solution

N(t)=K1+Ce−rt,C=KN0−1,N(t) = \frac{K}{1 + Ce^{-rt}}, \qquad C = \frac{K}{N_0} - 1,

defined for all t≥0t \ge 0, and N(t)→KN(t) \to K as t→∞t \to \infty. The equilibrium N=0N = 0 is unstable and N=KN = K is asymptotically stable.

Proof

Separating variables with partial fractions, K dNN(K−N)=(1N+1K−N)dN=r dt\frac{K\,dN}{N(K - N)} = \big(\frac1N + \frac1{K - N}\big)dN = r\,dt, so ln⁡NK−N=rt+const\ln\frac{N}{K - N} = rt + \text{const}, which rearranges to the formula; differentiating confirms it (this check is formalised in Lean). The right-hand side rN(1−N/K)rN(1 - N/K) is continuously differentiable, hence locally Lipschitz, so by the Picard–Lindelöf theorem the solution is unique. Since e−rt→0e^{-rt} \to 0, N(t)→KN(t) \to K. For stability, f(N)=rN(1−N/K)f(N) = rN(1 - N/K) has f′(0)=r>0f'(0) = r > 0 and f′(K)=−r<0f'(K) = -r < 0: near 00 solutions move away, and near KK they move towards it (on each side of KK the sign of ff pushes NN towards KK).

∎

Example— Harvesting and collapse

A fishery removes a constant catch HH per year: N′=rN(1−N/K)−HN' = rN(1 - N/K) - H. Equilibria solve rKN2−rN+H=0\frac rK N^2 - rN + H = 0, with discriminant r2−4rH/Kr^2 - 4rH/K. For H<rK/4H < rK/4 there are two equilibria: the larger is stable and the smaller unstable (a population pushed below it collapses). At H=rK/4H = rK/4 — the maximum sustainable yield, the largest value of rN(1−N/K)rN(1 - N/K), attained at N=K/2N = K/2 — they merge, and for H>rK/4H > rK/4 there is no equilibrium at all: N′<0N' < 0 everywhere and the population is driven to extinction. This saddle-node bifurcation is a mathematical reason why fisheries managed close to maximum yield can collapse suddenly after a small increase in effort or a bad year, as the cod fishery off Newfoundland did in the early 1990s.

ProofH

Discrete generations: the logistic map and chaos

Many insects, annual plants and fish breed once a year in non-overlapping generations, so populations are naturally modelled by maps. The logistic map xn+1=rxn(1−xn)x_{n+1} = rx_n(1 - x_n) is the simplest non-linear one, and Robert May (1976) urged biologists to study it precisely because its behaviour is so rich.

Theorem— Theorem (stability of fixed points of maps)

Let gg be continuously differentiable near a fixed point x∗x^*. If ∣g′(x∗)∣<1|g'(x^*)| < 1, then x∗x^* is locally asymptotically stable: there is ε>0\varepsilon > 0 such that gn(x0)→x∗g^n(x_0) \to x^* for every ∣x0−x∗∣<ε|x_0 - x^*| < \varepsilon. If ∣g′(x∗)∣>1|g'(x^*)| > 1, it is unstable.

Proof

Choose kk with ∣g′(x∗)∣<k<1|g'(x^*)| < k < 1; by continuity ∣g′∣≤k|g'| \le k on an interval U=[x∗−ε,x∗+ε]U = [x^* - \varepsilon, x^* + \varepsilon]. By the mean value theorem, for x∈Ux \in U, ∣g(x)−x∗∣=∣g(x)−g(x∗)∣≤k∣x−x∗∣|g(x) - x^*| = |g(x) - g(x^*)| \le k|x - x^*|, so gg maps UU into itself and ∣gn(x0)−x∗∣≤kn∣x0−x∗∣→0|g^n(x_0) - x^*| \le k^n|x_0 - x^*| \to 0 (this is the contraction-mapping argument behind the Banach fixed-point theorem). If ∣g′(x∗)∣>k>1|g'(x^*)| > k > 1 on UU, the same estimate in reverse shows that every orbit starting in U∖{x∗}U \setminus \{x^*\} eventually leaves UU.

∎

For fr(x)=rx(1−x)f_r(x) = rx(1 - x): the fixed points are x=0x = 0 and x∗=1−1rx^* = 1 - \frac1r (in (0,1)(0, 1) for r>1r > 1), with fr′(x)=r(1−2x)f_r'(x) = r(1 - 2x), so fr′(0)=rf_r'(0) = r and fr′(x∗)=2−rf_r'(x^*) = 2 - r. Hence extinction is stable for r<1r < 1, and the positive equilibrium is stable exactly for 1<r<31 < r < 3. At r=3r = 3 the multiplier passes through −1-1, and a cycle of period two is born.

Theorem— Proposition (the period-2 cycle)

For r>3r > 3 the logistic map has exactly one 2-cycle, {x+,x−}\{x_+, x_-\} with x±=r+1±(r−3)(r+1)2rx_\pm = \dfrac{r + 1 \pm \sqrt{(r - 3)(r + 1)}}{2r}. Its multiplier is fr′(x+)fr′(x−)=−r2+2r+4f_r'(x_+)f_r'(x_-) = -r^2 + 2r + 4, so it is stable for 3<r<1+6≈3.4493 < r < 1 + \sqrt 6 \approx 3.449.

Proof

Points of period two are fixed points of fr∘frf_r \circ f_r that are not fixed points of frf_r. The quartic fr(fr(x))−xf_r(f_r(x)) - x is divisible by fr(x)−x=−x(rx−r+1)f_r(x) - x = -x(rx - r + 1), and the quotient is, up to a constant factor, r2x2−r(r+1)x+(r+1)r^2x^2 - r(r + 1)x + (r + 1), whose roots are x±x_\pm; they are real and distinct exactly when (r−3)(r+1)>0(r - 3)(r + 1) > 0, i.e. r>3r > 3. With s=(r−3)(r+1)s = \sqrt{(r-3)(r+1)} we have 1−2x±=−1∓sr1 - 2x_\pm = \frac{-1 \mp s}{r}, so the multiplier is r2⋅(1+s)(1−s)r2=1−s2=−r2+2r+4r^2\cdot\frac{(1 + s)(1 - s)}{r^2} = 1 - s^2 = -r^2 + 2r + 4. This lies in (−1,1)(-1, 1) iff r2−2r−5<0r^2 - 2r - 5 < 0 and r2−2r−3>0r^2 - 2r - 3 > 0, i.e. 3<r<1+63 < r < 1 + \sqrt 6. (The identities fr(x±)=x∓f_r(x_\pm) = x_\mp and the multiplier are verified in Lean.)

∎

The logistic map: from equilibrium to chaos

r = 2.8: the orbit spirals into a fixed point. r = 3.2: a 2-cycle. r = 3.5: a 4-cycle. r = 3.7: no pattern. r = 3.83: a 3-cycle appears out of the chaos.

f(x) =
x₀

Iterates xₖ against k

  • y = f(x)
  • y = x
  • cobweb path

Last iterates: x78 = 0.79946, x79 = 0.51304, x80 = 0.79946

The orbit appears to settle into a cycle of period 2: 0.513, 0.7995.

Fixed points in view (numerical): x* = 0 (repelling: |f′(x*)| > 1); x* = 0.6875 (repelling: |f′(x*)| > 1)

Based on 3,000 iterations in floating-point arithmetic: numerical evidence, not proof.

The road to chaos. As rr increases, the 2-cycle loses stability at r=1+6r = 1 + \sqrt 6 and a stable 4-cycle appears, then an 8-cycle, and so on: a period-doubling cascade at parameters r1=3<r2≈3.449<r3≈3.544<⋯r_1 = 3 < r_2 \approx 3.449 < r_3 \approx 3.544 < \cdots accumulating at r∞≈3.5699r_\infty \approx 3.5699. The gaps shrink geometrically: rn−rn−1rn+1−rn→δ=4.6692…\frac{r_n - r_{n-1}}{r_{n+1} - r_n} \to \delta = 4.6692\ldots. Mitchell Feigenbaum (1978) discovered numerically that the same δ\delta appears for every smooth unimodal map with a quadratic maximum — a universal constant — and Oscar Lanford (1982) proved his conjectures with a computer-assisted proof. Beyond r∞r_\infty, chaotic parameters and periodic "windows" interleave; the largest window, containing a stable 3-cycle, opens at r=1+8≈3.828r = 1 + \sqrt 8 \approx 3.828. By the Li–Yorke theorem (1975), a continuous map of an interval with a point of period three has points of every period (a special case of Sharkovskii's theorem, 1964).

Chaos at r=4r = 4. Substituting x=sin⁡2(πθ)x = \sin^2(\pi\theta) gives f4(x)=4sin⁡2(πθ)cos⁡2(πθ)=sin⁡2(2πθ)f_4(x) = 4\sin^2(\pi\theta)\cos^2(\pi\theta) = \sin^2(2\pi\theta): the logistic map is conjugate to the doubling map θ↦2θ mod 1\theta \mapsto 2\theta \bmod 1, which shifts the binary digits of θ\theta one place to the left. Two starting points that agree to 4040 binary digits disagree completely after about 4040 steps: sensitive dependence on initial conditions, with errors doubling at each step (Lyapunov exponent ln⁡2\ln 2). A deterministic model with one parameter can thus be unpredictable in practice — a sobering lesson for population forecasting, since field data with noisy, chaotic-looking fluctuations may come from very simple deterministic rules.

ProofH

Stability by linearisation

Theorem— Theorem (linearised stability)

Let x∗x^* be an equilibrium of x′=f(x)x' = f(x) with ff continuously differentiable, and J=Df(x∗)J = Df(x^*). If every eigenvalue of JJ has negative real part, then x∗x^* is locally asymptotically stable. If some eigenvalue has positive real part, it is unstable.

Proof

Sketch of the stable case. Because the eigenvalues of JJ have negative real parts, ∥etJ∥≤Ce−μt\|e^{tJ}\| \le Ce^{-\mu t} for some C,μ>0C, \mu > 0, so the matrix M=∫0∞etJ⊤etJ dtM = \int_0^\infty e^{tJ^\top}e^{tJ}\,dt converges; it is symmetric positive definite and satisfies the Lyapunov equation J⊤M+MJ=−IJ^\top M + MJ = -I. Let V(y)=y⊤MyV(y) = y^\top My for y=x−x∗y = x - x^*. Along solutions y′=Jy+o(∣y∣)y' = Jy + o(|y|), so V′=y⊤(J⊤M+MJ)y+o(∣y∣2)=−∣y∣2+o(∣y∣2)<0V' = y^\top(J^\top M + MJ)y + o(|y|^2) = -|y|^2 + o(|y|^2) < 0 for small y≠0y \ne 0. Since VV is comparable to ∣y∣2|y|^2, V′≤−cVV' \le -cV near 00, and VV, hence yy, decays exponentially. (The unstable case and the general theory are in Strogatz, Chapter 6, or Perko's Differential Equations and Dynamical Systems.)

∎

The Hartman–Grobman theorem says more: if no eigenvalue has zero real part (a hyperbolic equilibrium), the phase portrait near x∗x^* is a continuous deformation of that of y′=Jyy' = Jy. When some eigenvalue has zero real part — for example a centre, with purely imaginary eigenvalues — linearisation is inconclusive, and the nonlinear terms decide.

In the plane, the eigenvalues of JJ are the roots of λ2−τλ+Δ\lambda^2 - \tau\lambda + \Delta with τ=tr⁡J\tau = \operatorname{tr}J and Δ=det⁡J\Delta = \det J, so both have negative real part if and only if τ<0\tau < 0 and Δ>0\Delta > 0 (the trace–determinant test). The "if" direction is proved in Lean: if λ=a+bi\lambda = a + bi is a root, the imaginary part of the equation gives b(2a−τ)=0b(2a - \tau) = 0, so either a=τ/2<0a = \tau/2 < 0, or b=0b = 0 and a2−τa+Δ=0a^2 - \tau a + \Delta = 0, which is impossible for a≥0a \ge 0. A saddle has Δ<0\Delta < 0.

ProofH

Predators and prey

In the Lotka–Volterra model, prey grow exponentially without predators (αx\alpha x), predators starve without prey (−γy-\gamma y), and encounters, at a rate proportional to xyxy (the law of mass action), remove prey and feed predators. The equilibria are (0,0)(0, 0) and (x∗,y∗)=(γ/δ,α/β)(x^*, y^*) = (\gamma/\delta, \alpha/\beta), with Jacobians

J(0,0)=(α00−γ),J(x∗,y∗)=(0−βγ/δαδ/β0).J(0, 0) = \begin{pmatrix} \alpha & 0 \\ 0 & -\gamma \end{pmatrix}, \qquad J(x^*, y^*) = \begin{pmatrix} 0 & -\beta\gamma/\delta \\ \alpha\delta/\beta & 0 \end{pmatrix}.

The origin is a saddle. At the coexistence equilibrium τ=0\tau = 0 and Δ=αγ>0\Delta = \alpha\gamma > 0, so the eigenvalues are ±iαγ\pm i\sqrt{\alpha\gamma}: a linear centre, and the linearisation theorem says nothing. A conserved quantity settles the question.

Theorem— Theorem (Volterra's conserved quantity)

Along every solution with x,y>0x, y > 0, the function

V(x,y)=δx−γln⁡x+βy−αln⁡yV(x, y) = \delta x - \gamma\ln x + \beta y - \alpha\ln y

is constant. VV has a strict global minimum on the open quadrant at (x∗,y∗)(x^*, y^*), and its level sets above the minimum are closed curves around it, so every positive solution other than the equilibrium is periodic.

Proof

By the chain rule, ddtV=(δ−γx)x′+(β−αy)y′=(δx−γ)(α−βy)+(βy−α)(δx−γ)=0\frac{d}{dt}V = \big(\delta - \frac\gamma x\big)x' + \big(\beta - \frac\alpha y\big)y' = (\delta x - \gamma)(\alpha - \beta y) + (\beta y - \alpha)(\delta x - \gamma) = 0 (formalised in Lean). Write V=F(x)+G(y)V = F(x) + G(y) with F(x)=δx−γln⁡xF(x) = \delta x - \gamma\ln x and G(y)=βy−αln⁡yG(y) = \beta y - \alpha\ln y. Each is strictly convex, tends to +∞+\infty at 00 and at ∞\infty, and has its minimum at x∗x^* (resp. y∗y^*). Hence for c>V(x∗,y∗)c > V(x^*, y^*) the set {V=c}\{V = c\} is a closed curve encircling the equilibrium: on each vertical line x=x0x = x_0 with F(x0)<c−G(y∗)F(x_0) < c - G(y^*) it contains exactly two points, merging at the two values of x0x_0 where F(x0)=c−G(y∗)F(x_0) = c - G(y^*). A solution starting on this compact curve stays on it, contains no equilibrium, and moves with speed bounded below, so it goes round the curve in finite time and repeats.

∎

Predator–prey cycles

Every orbit is a closed curve around the coexistence equilibrium. Prey peaks come before predator peaks. The widget's numerical integrator follows the level curves of V.

Examples

x′ = x·(1 − 0.5·y), y′ = y·(0.5·x − 1)

darker, longer arrows = faster forward in time backward in timeequilibrium (hollow = stable or centre)

Click the plane to start a trajectory, or type a start point below.

Start point

Trajectories: 3. They are numerical approximations (fourth-order Runge–Kutta), not exact formulas. The latest trajectory closes up: it is a periodic orbit.

Nonlinear system. Equilibria found numerically in this window, classified by their linearisation (Jacobian matrix):

  1. 1. (0, 0): saddle (unstable) (λ = −1, 1)
  2. 2. (2, 2): centre: closed orbits around it (λ = 0 ± 1i)

A centre of the linearisation is inconclusive for a nonlinear system: the true orbits may close up (as for the pendulum and predator–prey) or spiral slowly.

TDD = T²/412
Trace T and determinant D: below the T-axis, saddles; above the dashed parabola D = T²/4, spirals; between them, nodes; on the upper D-axis, centres. Left of the D-axis is stable, right is unstable.

Theorem— Theorem (cycle averages)

If a positive solution has period TT, then its averages over a period are the equilibrium values: 1T∫0Tx dt=γδ\frac1T\int_0^T x\,dt = \frac\gamma\delta and 1T∫0Ty dt=αβ\frac1T\int_0^T y\,dt = \frac\alpha\beta.

Proof

(ln⁡y)′=y′/y=δx−γ(\ln y)' = y'/y = \delta x - \gamma. Integrating over a period, 0=ln⁡y(T)−ln⁡y(0)=δ∫0Tx dt−γT0 = \ln y(T) - \ln y(0) = \delta\int_0^T x\,dt - \gamma T. The same argument with (ln⁡x)′=α−βy(\ln x)' = \alpha - \beta y gives the predator average. (The prey half is formalised in Lean, using the fundamental theorem of calculus.)

∎

This is Volterra's principle. Fishing that removes both species in proportion to their numbers changes α\alpha to α−ε\alpha - \varepsilon and γ\gamma to γ+ε\gamma + \varepsilon, so the average prey (γ+ε)/δ(\gamma + \varepsilon)/\delta rises and the average predators (α−ε)/β(\alpha - \varepsilon)/\beta fall. Reduced fishing during the war did the opposite — D'Ancona's observation explained. The same principle warns that spraying an insecticide that kills both a pest and its natural enemy can increase the pest on average.

Structural instability. The closed orbits are fragile: almost any change to the model destroys them. With self-limiting prey, x′=αx(1−x/K)−βxyx' = \alpha x(1 - x/K) - \beta xy, the coexistence equilibrium (when it exists) has τ<0\tau < 0 and Δ>0\Delta > 0 and becomes a stable spiral: oscillations damp out. With a saturating ("Holling type II", 1959) predator response βxy/(1+hx)\beta xy/(1 + hx), as in the Rosenzweig–MacArthur model (1963), the equilibrium can lose stability through a Hopf bifurcation and give way to a stable limit cycle — robust oscillations of a fixed amplitude, closer to the lynx–hare records. Rosenzweig's "paradox of enrichment" (1971) is a consequence: increasing the prey's carrying capacity can destabilise the system. A model whose qualitative behaviour changes under arbitrarily small perturbations should not be trusted for quantitative predictions.

ProofH

Competition

Two species competing for the same resources follow x′=x(1−x−a12y)x' = x(1 - x - a_{12}y), y′=ρy(1−y−a21x)y' = \rho y(1 - y - a_{21}x), where a12a_{12} measures the effect of yy on xx relative to xx's effect on itself. Besides (0,0)(0, 0), (1,0)(1, 0) and (0,1)(0, 1), there may be a coexistence equilibrium

(x∗,y∗)=(1−a121−a12a21, 1−a211−a12a21),(x^*, y^*) = \Big(\frac{1 - a_{12}}{1 - a_{12}a_{21}},\ \frac{1 - a_{21}}{1 - a_{12}a_{21}}\Big),

which is positive when a12,a21a_{12}, a_{21} are both less than 11 or both greater than 11.

Theorem— Proposition (coexistence or exclusion)

If a12<1a_{12} < 1 and a21<1a_{21} < 1, the coexistence equilibrium is locally asymptotically stable. If a12>1a_{12} > 1 and a21>1a_{21} > 1, it is a saddle, and the two single-species equilibria are both stable (the winner depends on the starting point). If a12<1<a21a_{12} < 1 < a_{21}, there is no coexistence equilibrium and (1,0)(1, 0) is stable: species xx excludes yy.

Proof

At a positive equilibrium, 1−x∗−a12y∗=01 - x^* - a_{12}y^* = 0 and 1−y∗−a21x∗=01 - y^* - a_{21}x^* = 0, so the Jacobian simplifies to J=(−x∗−a12x∗−ρa21y∗−ρy∗)J = \begin{pmatrix} -x^* & -a_{12}x^* \\ -\rho a_{21}y^* & -\rho y^*\end{pmatrix}, with τ=−(x∗+ρy∗)<0\tau = -(x^* + \rho y^*) < 0 and Δ=ρx∗y∗(1−a12a21)\Delta = \rho x^*y^*(1 - a_{12}a_{21}). If both aij<1a_{ij} < 1, then Δ>0\Delta > 0 and the trace–determinant test gives stability; if both exceed 11, Δ<0\Delta < 0: a saddle. At (1,0)(1, 0), J=(−1−a120ρ(1−a21))J = \begin{pmatrix} -1 & -a_{12} \\ 0 & \rho(1 - a_{21})\end{pmatrix} has eigenvalues −1-1 and ρ(1−a21)\rho(1 - a_{21}), negative exactly when a21>1a_{21} > 1; symmetrically for (0,1)(0, 1). The global statements follow from the nullclines, which divide the quadrant into regions where the direction of motion is fixed.

∎

Strong competition: a ≈ 1.5 both ways

The coexistence equilibrium (0.4, 0.4) is a saddle; starting points on either side of its stable separatrix lead to the exclusion of one species.

Examples

x′ = x·(1 − x − 1.5·y), y′ = y·(1 − y − 1.5·x)

darker, longer arrows = faster forward in time backward in timeequilibrium (hollow = stable or centre)

Click the plane to start a trajectory, or type a start point below.

Start point

Trajectories: 4. They are numerical approximations (fourth-order Runge–Kutta), not exact formulas.

Nonlinear system. Equilibria found numerically in this window, classified by their linearisation (Jacobian matrix):

  1. 1. (0, 0): unstable degenerate node (repeated eigenvalue) (λ = 1 (×2))
  2. 2. (0, 1): stable node (λ = −1, −0.5)
  3. 3. (0.4, 0.4): saddle (unstable) (λ = −1, 0.2)
  4. 4. (1, 0): stable node (λ = −1, −0.5)
TDD = T²/412, 43
Trace T and determinant D: below the T-axis, saddles; above the dashed parabola D = T²/4, spirals; between them, nodes; on the upper D-axis, centres. Left of the D-axis is stable, right is unstable.

Coexistence requires that each species limits itself more than it limits its competitor. Georgii Gause's laboratory experiments with Paramecium (1934) supported the resulting competitive exclusion principle: two species competing for exactly the same limiting resource cannot coexist indefinitely.

ProofH

Epidemics: the SIR model

The SIR model assumes a closed population (no births, deaths or migration on the time scale of the epidemic), homogeneous mixing (everyone equally likely to meet everyone), infection at rate βSI/N\beta SI/N (mass action), recovery at constant rate γ\gamma (an exponentially distributed infectious period with mean 1/γ1/\gamma), and lasting immunity. Adding the three equations, (S+I+R)′=0(S + I + R)' = 0: the population NN is constant.

Theorem— Theorem (threshold)

While I>0I > 0, the number infected is increasing exactly when R0 S/N>1R_0\,S/N > 1. In particular, an infection introduced into a fully susceptible population (S(0)≈NS(0) \approx N) initially grows if and only if R0>1R_0 > 1; since SS decreases, the epidemic peaks exactly when SS falls to N/R0N/R_0 and declines afterwards.

Proof

I′=γI(R0SN−1)I' = \gamma I\big(R_0\frac SN - 1\big), and γI>0\gamma I > 0. Since S′=−βSI/N≤0S' = -\beta SI/N \le 0, the factor R0S/N−1R_0S/N - 1 decreases in time, so II increases while it is positive and decreases once it is negative.

∎

Theorem— Theorem (final-size relation)

Along every solution with S>0S > 0, the quantity S+I−NR0ln⁡SS + I - \frac{N}{R_0}\ln S is constant. Consequently, if the epidemic starts with S(0)=S0S(0) = S_0 and negligible I(0)I(0), the number S∞=lim⁡t→∞S(t)S_\infty = \lim_{t \to \infty}S(t) who escape infection satisfies

ln⁡S∞S0=−R0 S0−S∞N.\ln\frac{S_\infty}{S_0} = -R_0\,\frac{S_0 - S_\infty}{N}.

For S0=NS_0 = N and R0>1R_0 > 1, the escaping fraction s=S∞/Ns = S_\infty/N is the unique root in (0,1)(0, 1) of s=e−R0(1−s)s = e^{-R_0(1 - s)}.

Proof

The derivative of S+I−NR0ln⁡SS + I - \frac{N}{R_0}\ln S is S′+I′−γNβS′S=−γI+γNβ⋅βIN=0S' + I' - \frac{\gamma N}{\beta}\frac{S'}{S} = -\gamma I + \frac{\gamma N}{\beta}\cdot\frac{\beta I}{N} = 0 (formalised in Lean). As t→∞t \to \infty, I(t)→0I(t) \to 0 (RR is increasing and bounded, so ∫0∞γI dt<∞\int_0^\infty \gamma I\,dt < \infty, and I′I' is bounded). Equating the invariant at t=0t = 0 (with I(0)≈0I(0) \approx 0) and at t=∞t = \infty gives the relation. For S0=NS_0 = N, let g(s)=s−e−R0(1−s)g(s) = s - e^{-R_0(1 - s)}: g(0)<0g(0) < 0, g(1)=0g(1) = 0 and g′(1)=1−R0<0g'(1) = 1 - R_0 < 0, so g>0g > 0 just below 11 and gg has a root in (0,1)(0, 1); it is unique because gg is strictly concave. The root s=1s = 1 corresponds to no epidemic.

∎

The final-size relation

The curves meet at s = 1 and, when R₀ > 1, at one more point: the fraction that escapes infection. For R₀ = 2.5 about 11% escape, so 89% are eventually infected.

  • s
  • exp(−R₀(1 − s))
  • s: y = 1
  • exp(−R₀(1 − s)): y = 1

Herd immunity and overshoot. If a fraction pp is immune (by vaccination or previous infection), an introduced infection grows only if R0(1−p)>1R_0(1 - p) > 1; the herd immunity threshold is pc=1−1/R0p_c = 1 - 1/R_0 — about 67%67\% for R0=3R_0 = 3 and 9292–94%94\% for measles, whose R0R_0 is classically estimated at 1212–1818. An unchecked epidemic infects more than this — 94%94\% for R0=3R_0 = 3 — because infections already under way continue after S/NS/N has fallen below 1/R01/R_0. The peak prevalence, from the invariant at the moment S=N/R0S = N/R_0, is Imax⁡/N=1−1+ln⁡R0R0I_{\max}/N = 1 - \frac{1 + \ln R_0}{R_0} (for S0=NS_0 = N).

SIR in the (S, I) plane, R₀ = 3 (N = 1)

Infections rise while S > 1/3 and fall afterwards. Each orbit ends on the S-axis at the fraction that escapes; starting from S ≈ 1, about 6%.

Examples

x′ = −0.3·x·y, y′ = 0.3·x·y − 0.1·y

darker, longer arrows = faster forward in time backward in timeequilibrium (hollow = stable or centre)

Click the plane to start a trajectory, or type a start point below.

Start point

Trajectories: 4. They are numerical approximations (fourth-order Runge–Kutta), not exact formulas.

Nonlinear system. Equilibria found numerically in this window, classified by their linearisation (Jacobian matrix):

  1. 1. (0.071, 0): degenerate: the determinant is 0, so the equilibria are not isolated (λ = −0.079, 0)
  2. 2. (0.214, 0): degenerate: the determinant is 0, so the equilibria are not isolated (λ = −0.036, 0)
  3. 3. (0.357, 0): degenerate: the determinant is 0, so the equilibria are not isolated (λ = 0, 0.007)
  4. 4. (0.5, 0): degenerate: the determinant is 0, so the equilibria are not isolated (λ = 0, 0.05)
  5. 5. (0.643, 0): degenerate: the determinant is 0, so the equilibria are not isolated (λ = 0, 0.093)
  6. 6. (0.786, 0): degenerate: the determinant is 0, so the equilibria are not isolated (λ = 0, 0.136)
TDD = T²/4123456
Trace T and determinant D: below the T-axis, saddles; above the dashed parabola D = T²/4, spirals; between them, nodes; on the upper D-axis, centres. Left of the D-axis is stable, right is unstable.

What R0R_0 is, and is not. R0=β/γR_0 = \beta/\gamma combines a contact rate and a duration: it depends on how people meet (household size, schools, markets, transport), on the environment (season, ventilation, mosquito density for malaria), on the pathogen, and on behaviour. It is a property of a pathogen in a population, not a biological constant. Estimates for the same disease vary widely between settings, and the effective reproduction number RtR_t, which accounts for immunity and interventions, is what epidemic monitoring tracks. In 2014 the WHO Ebola Response Team estimated reproduction numbers of roughly 1.51.5–22 in Guinea, Liberia and Sierra Leone before control measures took hold.

ExplanationH

Chance, space and the limits of models

Small numbers and chance. Deterministic equations describe large populations. When an infection is introduced by one person, chance dominates: each case might infect nobody. In the stochastic SIR model the early phase is a branching process, and with an exponentially distributed infectious period the probability that the introduction dies out by chance is 1/R01/R_0 (for R0>1R_0 > 1). Small populations also drift genetically and can go extinct by bad luck even when the deterministic model predicts persistence; the Wright–Fisher chain in Markov chains is the basic model.

Space. Populations spread: Fisher (1937) and Kolmogorov, Petrovsky and Piskunov (1937) showed that ut=Duxx+ru(1−u)u_t = Du_{xx} + ru(1 - u) has travelling waves moving at speed 2rD2\sqrt{rD}, a model for the spread of advantageous genes and invading species. Alan Turing (1952) showed that two diffusing, reacting chemicals can spontaneously form spatial patterns — a proposed mechanism for spots and stripes on animal coats, now supported in several developmental systems.

Models are not forecasts. A model's output is a conditional statement: if these mechanisms, with these parameters, then this. Its predictions are only as good as its assumptions, and structural choices (homogeneous mixing versus contact networks, fixed versus changing behaviour) can matter more than parameter values. Epidemic models are often used to compare scenarios — what happens with and without an intervention — rather than to forecast the future, and because people change their behaviour in response to an epidemic (and to model projections), a projection that leads to action may never come true, which does not make it wrong. Good practice reports parameter uncertainty, tests sensitivity to assumptions, compares several model structures, and confronts the model with data.

Formal mathematicsF

Mathematical biology in Lean and Mathlib

Mathlib has the calculus needed here — HasDerivAt, logarithms and exponentials, the fundamental theorem of calculus — but no library of biological models, and not the linearisation theorem, Hartman–Grobman or Poincaré–Bendixson. The module proves the lesson's computations as theorems about arbitrary solutions: a hypothesis HasDerivAt x (α * x t - β * x t * y t) t says that x satisfies the prey equation at time t.

Logistic growth: the explicit solution, verified by differentiation, and its limit:

logistic_ode_solvesLean 4Proved here from basic factsFormally verified
/-- **The logistic equation** `N' = r N (1 − N/K)` is solved by
`N(t) = K / (1 + C e^{−rt})` (found by separation of variables; here verified by
differentiation). With `C = K/N₀ − 1` this is the solution with `N(0) = N₀`. -/
theorem logistic_ode_solves {r K C : ℝ} (hK : K ≠ 0) (hC : 0 ≤ C) (t : ℝ) :
    HasDerivAt (fun s => K / (1 + C * exp (-(r * s))))
      (r * (K / (1 + C * exp (-(r * t)))) * (1 - K / (1 + C * exp (-(r * t))) / K)) t := by
  have hpos : 0 < 1 + C * exp (-(r * t)) := by positivity
  have h0 := (hasDerivAt_id t).const_mul (-r)
  have hinner : HasDerivAt (fun s => -(r * s)) (-r) t := by
    convert h0 using 1
    · funext s
      simp only [id]
      ring
    · ring
  have hd : HasDerivAt (fun s => 1 + C * exp (-(r * s))) (C * (exp (-(r * t)) * (-r))) t :=
    ((hinner.exp).const_mul C).const_add 1
  have h := (hasDerivAt_const t K).div hd hpos.ne'
  convert h using 1
  field_simp
  ring
Axioms used: propext, Classical.choice, Quot.soundformal/Lumenary/MathematicalBiology.leanTry it in the Lean web editor
logistic_ode_limitLean 4Proved here from basic factsFormally verified
/-- Every positive logistic solution approaches the **carrying capacity**: if `r > 0` then
`K / (1 + C e^{−rt}) → K` as `t → ∞`, because `e^{−rt} → 0`. -/
theorem logistic_ode_limit {r K C : ℝ} (hr : 0 < r) :
    Tendsto (fun t => K / (1 + C * exp (-(r * t)))) atTop (𝓝 K) := by
  have hexp : Tendsto (fun t => exp (-(r * t))) atTop (𝓝 0) := by
    have : Tendsto (fun t => r * t) atTop atTop := tendsto_id.const_mul_atTop hr
    exact tendsto_exp_neg_atTop_nhds_zero.comp this |>.congr fun t => rfl
  have hden : Tendsto (fun t => 1 + C * exp (-(r * t))) atTop (𝓝 1) := by
    simpa using (hexp.const_mul C).const_add 1
  have h := (tendsto_const_nhds (x := K)).div hden one_ne_zero
  rw [div_one] at h
  exact h
Axioms used: propext, Classical.choice, Quot.soundformal/Lumenary/MathematicalBiology.leanTry it in the Lean web editor

The logistic map: fixed points, the multiplier 2−r2 - r, the stability range 1<r<31 < r < 3, the 2-cycle and its multiplier; and Mathlib's Banach fixed-point theorem, the principle behind the stability criterion:

logisticMapLean 4Formally verified
/-- The **logistic map** `f_r(x) = r x (1 − x)`, a discrete-time model of a population
(as a fraction of its maximum) in non-overlapping generations. -/
def logisticMap (r x : ℝ) : ℝ := r * x * (1 - x)
Axioms used: propext, Classical.choice, Quot.soundformal/Lumenary/MathematicalBiology.leanTry it in the Lean web editor
logistic_fixed_pointsLean 4Proved here from basic factsFormally verified
/-- **Fixed points of the logistic map.** For `r ≠ 0`, `f_r(x) = x` exactly when `x = 0`
(extinction) or `x = 1 − 1/r` (the non-trivial equilibrium, in `(0, 1)` when `r > 1`).
Proof: `r x (1 − x) − x = x (r − 1 − r x)`. -/
theorem logistic_fixed_points {r : ℝ} (hr : r ≠ 0) (x : ℝ) :
    logisticMap r x = x ↔ x = 0 ∨ x = 1 - 1 / r := by
  unfold logisticMap
  constructor
  · intro h
    have hfac : x * (r - 1 - r * x) = 0 := by linarith [h]
    rcases mul_eq_zero.mp hfac with h0 | h1
    · exact Or.inl h0
    · right
      field_simp
      linarith
  · rintro (rfl | rfl)
    · ring
    · field_simp
      ring
Axioms used: propext, Classical.choice, Quot.soundformal/Lumenary/MathematicalBiology.leanTry it in the Lean web editor
logistic_map_derivLean 4Proved here from basic factsFormally verified
/-- The derivative of the logistic map is `f_r'(x) = r (1 − 2x)`; at the non-trivial fixed
point `x* = 1 − 1/r` it equals `2 − r`. -/
theorem logistic_map_deriv {r : ℝ} (hr : r ≠ 0) :
    HasDerivAt (logisticMap r) (2 - r) (1 - 1 / r) := by
  have h : HasDerivAt (fun x => r * x * (1 - x)) (r * 1 * (1 - (1 - 1 / r)) + r * (1 - 1 / r) * (-1))
      (1 - 1 / r) :=
    ((hasDerivAt_id' _).const_mul r).mul ((hasDerivAt_id' _).const_sub 1 |>.congr_deriv (by simp))
  have hv : r * 1 * (1 - (1 - 1 / r)) + r * (1 - 1 / r) * (-1) = 2 - r := by
    field_simp
    ring
  rw [hv] at h
  exact h
Axioms used: propext, Classical.choice, Quot.soundformal/Lumenary/MathematicalBiology.leanTry it in the Lean web editor
logistic_stable_iffLean 4Proved here from basic factsFormally verified
/-- **Stability of the non-trivial equilibrium.** A fixed point of a smooth map is
asymptotically stable when `|f'(x*)| < 1`; here `|2 − r| < 1` exactly when `1 < r < 3`.
At `r = 3` the multiplier passes through `−1` and the period-doubling cascade begins. -/
theorem logistic_stable_iff (r : ℝ) : |2 - r| < 1 ↔ 1 < r ∧ r < 3 := by
  rw [abs_lt]
  constructor <;> intro h <;> constructor <;> linarith [h.1, h.2]
Axioms used: propext, Classical.choice, Quot.soundformal/Lumenary/MathematicalBiology.leanTry it in the Lean web editor
logistic_period_twoLean 4Proved here from basic factsFormally verified
/-- **The period-2 cycle.** For `r ≥ 3`, with `s = √((r − 3)(r + 1))`, the points
`x± = (r + 1 ± s)/(2r)` are swapped by the logistic map: `f_r(x₊) = x₋` and `f_r(x₋) = x₊`.
(They coincide with the fixed point `1 − 1/r` at `r = 3` and separate for `r > 3`.)
Proof: expand, using `s² = r² − 2r − 3`. -/
theorem logistic_period_two {r : ℝ} (hr : 3 ≤ r) :
    let s := Real.sqrt ((r - 3) * (r + 1))
    logisticMap r ((r + 1 + s) / (2 * r)) = (r + 1 - s) / (2 * r) ∧
      logisticMap r ((r + 1 - s) / (2 * r)) = (r + 1 + s) / (2 * r) := by
  intro s
  have hr0 : r ≠ 0 := by linarith
  have hs : s ^ 2 = (r - 3) * (r + 1) := Real.sq_sqrt (by nlinarith)
  unfold logisticMap
  constructor
  · field_simp
    linear_combination -hs
  · field_simp
    linear_combination -hs
Axioms used: propext, Classical.choice, Quot.soundformal/Lumenary/MathematicalBiology.leanTry it in the Lean web editor
period_two_multiplierLean 4Proved here from basic factsFormally verified
/-- **Stability of the 2-cycle.** The multiplier of the cycle — the derivative of `f_r ∘ f_r`
along it, `f_r'(x₊) f_r'(x₋) = r²(1 − 2x₊)(1 − 2x₋)` — equals `−r² + 2r + 4`. It lies in
`(−1, 1)` exactly for `3 < r < 1 + √6 ≈ 3.449`, where the 2-cycle is stable and the next
doubling begins. -/
theorem period_two_multiplier {r : ℝ} (hr : 3 ≤ r) :
    let s := Real.sqrt ((r - 3) * (r + 1))
    (r * (1 - 2 * ((r + 1 + s) / (2 * r)))) * (r * (1 - 2 * ((r + 1 - s) / (2 * r)))) =
      -r ^ 2 + 2 * r + 4 := by
  intro s
  have hr0 : r ≠ 0 := by linarith
  have hs : s ^ 2 = (r - 3) * (r + 1) := Real.sq_sqrt (by nlinarith)
  field_simp
  linear_combination -hs
Axioms used: propext, Classical.choice, Quot.soundformal/Lumenary/MathematicalBiology.leanTry it in the Lean web editor
contraction_convergesLean 4Applies a library theoremFormally verified
/-- **Why stable fixed points attract: the Banach fixed-point theorem.** If a map of a complete
metric space is a contraction (`dist (f x) (f y) ≤ K dist x y` with `K < 1`), its iterates
from any starting point converge to its unique fixed point. Near a fixed point with
`|f'(x*)| < 1` a smooth map is a contraction of a small interval, which is the proof of the
stability criterion. This is Mathlib's `ContractingWith.tendsto_iterate_fixedPoint`. -/
theorem contraction_converges {α : Type*} [MetricSpace α] [CompleteSpace α] [Nonempty α]
    {K : NNReal} {f : α → α} (hf : ContractingWith K f) (x : α) :
    Tendsto (fun n => f^[n] x) atTop (𝓝 (ContractingWith.fixedPoint f hf)) :=
  hf.tendsto_iterate_fixedPoint x
Axioms used: propext, Classical.choice, Quot.soundformal/Lumenary/MathematicalBiology.leanTry it in the Lean web editor

Predator and prey: Volterra's conserved quantity along any positive solution, and the prey average over a cycle, via the fundamental theorem of calculus:

lotka_volterra_conservedLean 4Proved here from basic factsFormally verified
/-- **The Lotka–Volterra conserved quantity.** Along any positive solution of
`x' = αx − βxy` (prey), `y' = δxy − γy` (predators), the function
`V(x, y) = δx − γ log x + βy − α log y` has zero derivative, so it is constant and orbits lie
on its level curves (which are closed curves around the equilibrium `(γ/δ, α/β)`).
Proof: `V' = (δ − γ/x) x' + (β − α/y) y' = (δx − γ)(α − βy) + (βy − α)(δx − γ) = 0`. -/
theorem lotka_volterra_conserved {α β γ δ : ℝ} {x y : ℝ → ℝ} {t : ℝ} (hx : 0 < x t)
    (hy : 0 < y t) (hx' : HasDerivAt x (α * x t - β * x t * y t) t)
    (hy' : HasDerivAt y (δ * x t * y t - γ * y t) t) :
    HasDerivAt (fun s => δ * x s - γ * log (x s) + β * y s - α * log (y s)) 0 t := by
  have h1 := hx'.const_mul δ
  have h2 := (hx'.log hx.ne').const_mul γ
  have h3 := hy'.const_mul β
  have h4 := (hy'.log hy.ne').const_mul α
  have h := ((h1.sub h2).add h3).sub h4
  convert h using 1
  field_simp
  ring
Axioms used: propext, Classical.choice, Quot.soundformal/Lumenary/MathematicalBiology.leanTry it in the Lean web editor
lotka_volterra_averageLean 4Proved here from basic factsFormally verified
/-- **Averages over a cycle equal the equilibrium.** If a positive solution is periodic with
period `T > 0` (`y(T) = y(0)`), then the average prey population over a period is
`(1/T) ∫₀ᵀ x = γ/δ`. Proof: `(log y)' = y'/y = δx − γ`; integrate over a period, where
`log y` returns to its initial value. (This is Volterra's explanation of D'Ancona's
observation that reduced fishing during the First World War raised the share of predators.) -/
theorem lotka_volterra_average {α β γ δ T : ℝ} (hδ : δ ≠ 0) (hT : 0 < T) {x y : ℝ → ℝ}
    (hy : ∀ t, 0 < y t) (hx' : ∀ t, HasDerivAt x (α * x t - β * x t * y t) t)
    (hy' : ∀ t, HasDerivAt y (δ * x t * y t - γ * y t) t) (hper : y T = y 0) :
    (∫ t in (0 : ℝ)..T, x t) / T = γ / δ := by
  have hxc : Continuous x := continuous_iff_continuousAt.mpr fun t => (hx' t).continuousAt
  -- `(log y)' = δ x − γ`.
  have hlog : ∀ t, HasDerivAt (fun s => log (y s)) (δ * x t - γ) t := by
    intro t
    have := (hy' t).log (hy t).ne'
    convert this using 1
    field_simp [(hy t).ne']
  have hint : IntervalIntegrable (fun t => δ * x t - γ) MeasureTheory.volume 0 T :=
    ((hxc.const_mul δ).sub continuous_const).intervalIntegrable 0 T
  have hftc := intervalIntegral.integral_eq_sub_of_hasDerivAt (fun t _ => hlog t) hint
  rw [hper, sub_self, intervalIntegral.integral_sub
    ((hxc.const_mul δ).intervalIntegrable 0 T) intervalIntegrable_const,
    intervalIntegral.integral_const_mul, intervalIntegral.integral_const, smul_eq_mul,
    sub_zero] at hftc
  field_simp
  linarith
Axioms used: propext, Classical.choice, Quot.soundformal/Lumenary/MathematicalBiology.leanTry it in the Lean web editor

Epidemics: conservation of the population, the threshold, the invariant behind the final-size relation, and the herd immunity threshold:

sir_total_constantLean 4Proved here from basic factsFormally verified
/-- **The SIR model conserves the population.** If `S' = −βSI/N`, `I' = βSI/N − γI` and
`R' = γI`, then `(S + I + R)' = 0`: everyone is always susceptible, infected or removed. -/
theorem sir_total_constant {β γ N : ℝ} {S I R : ℝ → ℝ} {t : ℝ}
    (hS : HasDerivAt S (-(β * S t * I t / N)) t)
    (hI : HasDerivAt I (β * S t * I t / N - γ * I t) t) (hR : HasDerivAt R (γ * I t) t) :
    HasDerivAt (fun s => S s + I s + R s) 0 t := by
  convert (hS.add hI).add hR using 1
  ring
Axioms used: propext, Classical.choice, Quot.soundformal/Lumenary/MathematicalBiology.leanTry it in the Lean web editor
sir_thresholdLean 4Proved here from basic factsFormally verified
/-- **The epidemic threshold.** When infection is present (`I > 0`), the number infected is
increasing (`I' > 0`) exactly when `R₀ · S/N > 1`, where `R₀ = β/γ` (`β, γ, N > 0`). -/
theorem sir_threshold {β γ N S I : ℝ} (hγ : 0 < γ) (hN : 0 < N) (hI : 0 < I) :
    0 < β * S * I / N - γ * I ↔ 1 < β / γ * (S / N) := by
  have key : β * S * I / N - γ * I = γ * I * (β / γ * (S / N) - 1) := by
    field_simp
  rw [key]
  constructor
  · intro h
    have := (mul_pos_iff_of_pos_left (mul_pos hγ hI)).mp h
    linarith
  · intro h
    exact mul_pos (mul_pos hγ hI) (by linarith)
Axioms used: propext, Classical.choice, Quot.soundformal/Lumenary/MathematicalBiology.leanTry it in the Lean web editor
sir_invariantLean 4Proved here from basic factsFormally verified
/-- **The invariant behind the final-size relation.** Along a solution of the SIR model with
`S > 0`, the quantity `S + I − (N/R₀) log S` (with `R₀ = β/γ`, written `γN/β`) is constant.
Proof: its derivative is `S' + I' − (γN/β) S'/S = −γI + γI = 0`. Comparing its values at the
start (`I ≈ 0`, `S ≈ N`) and the end (`I = 0`) of an epidemic gives the final-size relation
`log(S∞/S₀) = R₀ (S∞ − S₀)/N`. -/
theorem sir_invariant {β γ N : ℝ} (hβ : β ≠ 0) (hN : N ≠ 0) {S I : ℝ → ℝ} {t : ℝ}
    (hpos : 0 < S t) (hS : HasDerivAt S (-(β * S t * I t / N)) t)
    (hI : HasDerivAt I (β * S t * I t / N - γ * I t) t) :
    HasDerivAt (fun s => S s + I s - γ * N / β * log (S s)) 0 t := by
  convert (hS.add hI).sub ((hS.log hpos.ne').const_mul (γ * N / β)) using 1
  field_simp
  ring
Axioms used: propext, Classical.choice, Quot.soundformal/Lumenary/MathematicalBiology.leanTry it in the Lean web editor
herd_immunityLean 4Proved here from basic factsFormally verified
/-- **Herd immunity threshold.** If a fraction `p` of the population is immune, an
introduced infection grows only if `R₀ (1 − p) > 1`. So it cannot grow exactly when
`p ≥ 1 − 1/R₀` (for `R₀ > 0`): about `92–94%` for measles (`R₀ ≈ 12–18`). -/
theorem herd_immunity {R₀ p : ℝ} (hR : 0 < R₀) : R₀ * (1 - p) ≤ 1 ↔ 1 - 1 / R₀ ≤ p := by
  constructor
  · intro h
    have : 1 - p ≤ 1 / R₀ := by
      rw [le_div_iff₀ hR]
      linarith
    linarith
  · intro h
    have : 1 - p ≤ 1 / R₀ := by linarith
    rw [le_div_iff₀ hR] at this
    linarith
Axioms used: propext, Classical.choice, Quot.soundformal/Lumenary/MathematicalBiology.leanTry it in the Lean web editor

Linear stability: the trace–determinant test, for complex roots of the characteristic polynomial:

trace_det_stableLean 4Proved here from basic factsFormally verified
/-- **The trace–determinant test.** If a real `2 × 2` Jacobian has trace `τ < 0` and
determinant `Δ > 0`, every root `λ` of its characteristic polynomial `λ² − τλ + Δ` has
negative real part, so the equilibrium is locally asymptotically stable (by the linearisation
theorem). Proof: write `λ = a + bi`. The imaginary part of the equation is `b(2a − τ) = 0`;
if `b ≠ 0` then `a = τ/2 < 0`, and if `b = 0` then `a² − τa + Δ = 0` forces `a < 0`. -/
theorem trace_det_stable {τ Δ : ℝ} (hτ : τ < 0) (hΔ : 0 < Δ) {z : ℂ}
    (hz : z ^ 2 - τ * z + Δ = 0) : z.re < 0 := by
  have hre := congrArg Complex.re hz
  have him := congrArg Complex.im hz
  simp [pow_two] at hre him
  by_cases hb : z.im = 0
  · rw [hb] at hre
    by_contra hnn
    push Not at hnn
    nlinarith
  · have h2 : 2 * z.re - τ = 0 := by
      have : z.im * (2 * z.re - τ) = 0 := by linarith
      rcases mul_eq_zero.mp this with h | h
      · exact absurd h hb
      · exact h
    linarith
Axioms used: propext, Classical.choice, Quot.soundformal/Lumenary/MathematicalBiology.leanTry it in the Lean web editor

What is and is not formalised. Proved here: all the identities and inequalities above — explicit solutions, fixed points and multipliers, the 2-cycle, the conserved quantities, the cycle average of the prey, the SIR threshold and invariant, herd immunity and the trace–determinant test (in the "if" direction). Cited from Mathlib: the Banach fixed-point theorem. Not formalised: existence and uniqueness of solutions for these models (Mathlib's Picard–Lindelöf theorem would provide them), the linearisation theorem, the closedness of the Lotka–Volterra level curves, the final-size limit argument (I→0I \to 0), the competition analysis, period doubling beyond period two, Feigenbaum universality and chaos.

ComputationC

Cascades, cycles and epidemics, computed

First, the logistic map: attractor periods, superstable parameters found by Newton's method with the ratios of their gaps approaching Feigenbaum's constant, and Lyapunov exponents.

Logistic map: period doubling, Feigenbaum ratios and Lyapunov exponentsPythonNumerical approximationComputationally tested
"""The logistic map x -> r x (1 - x): period doubling, Feigenbaum's constant and chaos.

For each growth rate r we iterate the map past its transient and detect the
period of the attractor. Then we locate the "superstable" parameters R_n at
which the critical point 1/2 lies on a cycle of period 2^n, by Newton's
method, and form the ratios (R_n - R_(n-1)) / (R_(n+1) - R_n), which approach
Feigenbaum's constant 4.669... Finally the Lyapunov exponent - the average of
log|f'(x_k)| along the orbit - is negative on stable cycles and equals log 2
at r = 4, where nearby orbits separate exponentially.
"""

import math

def logistic(r, x):
    """One step of the logistic map."""
    return r * x * (1 - x)

def orbit(r, x0, n):
    """[x_0, ..., x_n] for the logistic map."""
    xs = [x0]
    for _ in range(n):
        xs.append(logistic(r, xs[-1]))
    return xs

def attractor_period(r, x0=0.2, transient=3000, max_period=64, tol=1e-9):
    """Smallest p <= max_period with x_(n+p) = x_n after the transient, else None."""
    x = x0
    for _ in range(transient):
        x = logistic(r, x)
    start = x
    for p in range(1, max_period + 1):
        x = logistic(r, x)
        if abs(x - start) < tol:
            return p
    return None

def superstable_gap(r, n):
    """f_r^(2^n)(1/2) - 1/2: zero exactly when 1/2 lies on a 2^n-cycle."""
    x = 0.5
    for _ in range(2 ** n):
        x = logistic(r, x)
    return x - 0.5

def superstable_parameters(count):
    """R_0 = 2, R_1 = 1 + sqrt 5, ... found by Newton's method with a numerical
    derivative, each started from an extrapolation of the previous gaps."""
    rs = [2.0, 1 + math.sqrt(5)]
    delta = 4.0
    while len(rs) < count:
        n = len(rs)
        r = rs[-1] + (rs[-1] - rs[-2]) / delta
        for _ in range(60):
            g = superstable_gap(r, n)
            h = 1e-10
            dg = (superstable_gap(r + h, n) - superstable_gap(r - h, n)) / (2 * h)
            step = g / dg
            r -= step
            if abs(step) < 1e-14:
                break
        rs.append(r)
        delta = (rs[-2] - rs[-3]) / (rs[-1] - rs[-2])
    return rs

def lyapunov(r, x0=0.2, transient=1000, n=20000):
    """Average of log|f_r'(x_k)| = log|r (1 - 2 x_k)| along the orbit."""
    x = x0
    for _ in range(transient):
        x = logistic(r, x)
    total = 0.0
    for _ in range(n):
        total += math.log(abs(r * (1 - 2 * x)) + 1e-300)
        x = logistic(r, x)
    return total / n

def main():
    print("Attractor period after 3000 iterations from x0 = 0.2:")
    for r in [2.8, 3.2, 3.5, 3.56, 3.7, 3.83]:
        p = attractor_period(r)
        print(f"  r = {r:<5} period {p if p else 'none found (chaotic?)'}")
    rs = superstable_parameters(8)
    print()
    print("Superstable parameters R_n and Feigenbaum ratios:")
    for n, r in enumerate(rs):
        line = f"  R_{n} = {r:.10f}"
        if n >= 2:
            ratio = (rs[n - 1] - rs[n - 2]) / (rs[n] - rs[n - 1])
            line += f"   ratio {ratio:.5f}"
        print(line)
    print("  (Feigenbaum's constant: 4.66920...)")
    print()
    print("Lyapunov exponents (negative: stable cycle; positive: chaos):")
    for r in [2.8, 3.2, 3.5, 3.7, 3.83, 4.0]:
        print(f"  r = {r:<5} {lyapunov(r):+.4f}")
    print(f"  log 2 = {math.log(2):.4f}")
    a, b = orbit(4.0, 0.3, 40), orbit(4.0, 0.3 + 1e-10, 40)
    gaps = [abs(x - y) for x, y in zip(a, b)]
    first = next(i for i, g in enumerate(gaps) if g > 0.1)
    print(f"At r = 4, starts 1e-10 apart differ by > 0.1 after {first} steps.")
    print()
    print("Epistemic status: floating-point iteration of finitely many steps.")
    print("Periods, ratios and exponents are numerical estimates; the")
    print("universality of Feigenbaum's constant was proved by Lanford (1982)")
    print("with computer assistance, and chaos at r = 4 is a theorem.")

if __name__ == "__main__":
    main()
Runs entirely in your browser, in an isolated worker. Nothing is sent to a server.

Next, the Lotka–Volterra model: Euler's method spirals outward and violates the conservation law; the Runge–Kutta method respects it, and the cycle averages match the equilibrium.

Lotka-Volterra: conserved quantity, Euler versus RK4, cycle averagesPythonNumerical approximationComputationally tested
"""Lotka-Volterra cycles: what a conserved quantity says about numerical methods.

Prey x and predators y obey x' = a x - b x y, y' = d x y - c y. The quantity
V = d x - c ln x + b y - a ln y is exactly conserved, so true orbits are closed.
We integrate with Euler's method and with classical Runge-Kutta (RK4) and
watch V: Euler's orbit spirals outward (V grows steadily), while RK4 keeps V
constant to many digits. With RK4 we also measure the period and check that
the average prey population over one cycle equals the equilibrium value c/d.
"""

import math

A, B, C, D = 1.0, 0.5, 0.75, 0.25  # prey growth, predation, predator death, conversion

def rhs(x, y):
    """Lotka-Volterra vector field."""
    return A * x - B * x * y, D * x * y - C * y

def conserved(x, y):
    """V = d x - c ln x + b y - a ln y."""
    return D * x - C * math.log(x) + B * y - A * math.log(y)

def euler_step(x, y, h):
    """One explicit Euler step."""
    fx, fy = rhs(x, y)
    return x + h * fx, y + h * fy

def rk4_step(x, y, h):
    """One classical Runge-Kutta step."""
    k1 = rhs(x, y)
    k2 = rhs(x + h / 2 * k1[0], y + h / 2 * k1[1])
    k3 = rhs(x + h / 2 * k2[0], y + h / 2 * k2[1])
    k4 = rhs(x + h * k3[0], y + h * k3[1])
    return (x + h / 6 * (k1[0] + 2 * k2[0] + 2 * k3[0] + k4[0]),
            y + h / 6 * (k1[1] + 2 * k2[1] + 2 * k3[1] + k4[1]))

def run(step, x, y, h, n):
    """Positions after 0, 1, ..., n steps."""
    path = [(x, y)]
    for _ in range(n):
        x, y = step(x, y, h)
        path.append((x, y))
    return path

def period_and_averages(x0, y0, h=0.001, t_max=40.0):
    """Period (time between successive upward crossings of y = a/b by the
    prey-rich branch) and the averages of x and y over that period, with RK4."""
    x, y = x0, y0
    crossings, t = [], 0.0
    sums, sx, sy = [], 0.0, 0.0
    while t < t_max and len(crossings) < 3:
        nx, ny = rk4_step(x, y, h)
        sx += h * (x + nx) / 2
        sy += h * (y + ny) / 2
        if y < A / B <= ny and nx > C / D:
            crossings.append(t + h)
            sums.append((sx, sy))
        x, y, t = nx, ny, t + h
    period = crossings[2] - crossings[1]
    avg_x = (sums[2][0] - sums[1][0]) / period
    avg_y = (sums[2][1] - sums[1][1]) / period
    return period, avg_x, avg_y

def main():
    x0, y0, h, n = 4.0, 1.0, 0.01, 3000
    v0 = conserved(x0, y0)
    eul = run(euler_step, x0, y0, h, n)
    rk = run(rk4_step, x0, y0, h, n)
    print(f"a = {A}, b = {B}, c = {C}, d = {D}; equilibrium (c/d, a/b) ="
          f" ({C / D:g}, {A / B:g})")
    print(f"Start (x, y) = ({x0}, {y0}), V = {v0:.6f}; step h = {h}")
    print("    t     V (Euler)      V (RK4)     max prey (Euler, RK4)")
    for k in [0, 500, 1000, 2000, 3000]:
        me = max(p[0] for p in eul[:k + 1])
        mr = max(p[0] for p in rk[:k + 1])
        print(f"{k * h:>5.0f} {conserved(*eul[k]):>12.6f} {conserved(*rk[k]):>12.6f}"
              f"   {me:>8.3f} {mr:>8.3f}")
    print("Euler's orbit spirals outward; RK4 stays on the closed level curve.")
    print()
    period, ax, ay = period_and_averages(x0, y0)
    print(f"RK4 period of the cycle: {period:.3f}"
          f" (small-oscillation value 2 pi/sqrt(ac) = {2 * math.pi / math.sqrt(A * C):.3f})")
    print(f"Average prey over a cycle {ax:.4f} (equilibrium c/d = {C / D:.4f})")
    print(f"Average predators         {ay:.4f} (equilibrium a/b = {A / B:.4f})")
    print()
    print("Epistemic status: floating-point integration with fixed steps. The")
    print("conservation of V and the cycle averages are theorems (V and the")
    print("prey average are proved in Lean); the numbers show how well each")
    print("method respects them.")

if __name__ == "__main__":
    main()
Runs entirely in your browser, in an isolated worker. Nothing is sent to a server.

Finally, the SIR model solved numerically for several values of R0R_0 and compared with the final-size relation, the peak formula and the herd immunity threshold.

SIR epidemics: Runge-Kutta solutions and the final-size relationPythonNumerical approximationComputationally tested
"""The SIR epidemic: numerical solution versus the final-size relation.

We solve S' = -beta S I, I' = beta S I - gamma I, R' = gamma I (fractions of a
population, N = 1) with the classical Runge-Kutta method, starting from one
infected person in ten thousand. We compare the simulated final size and peak
with the exact predictions of the lesson: the final susceptible fraction s
solves s = exp(-R0 (1 - s)), and the peak prevalence is
1 - (1 + ln R0)/R0. We also check that the invariant S + I - (1/R0) ln S stays
constant along the numerical solution.
"""

import math

def sir_rhs(state, beta, gamma):
    """Right-hand side of the SIR equations (population fractions)."""
    s, i, r = state
    infection = beta * s * i
    return (-infection, infection - gamma * i, gamma * i)

def rk4_step(state, h, beta, gamma):
    """One classical Runge-Kutta step."""
    def shift(base, k, c):
        return tuple(b + c * x for b, x in zip(base, k))
    k1 = sir_rhs(state, beta, gamma)
    k2 = sir_rhs(shift(state, k1, h / 2), beta, gamma)
    k3 = sir_rhs(shift(state, k2, h / 2), beta, gamma)
    k4 = sir_rhs(shift(state, k3, h), beta, gamma)
    return tuple(x + h / 6 * (a + 2 * b + 2 * c + d)
                 for x, a, b, c, d in zip(state, k1, k2, k3, k4))

def simulate(r0, gamma=0.1, i0=1e-4, h=0.5, days=1500):
    """Return (final S, peak I, day of peak, max drift of the invariant)."""
    beta = r0 * gamma
    state = (1 - i0, i0, 0.0)

    def invariant(st):
        return st[0] + st[1] - math.log(st[0]) / r0

    v0 = invariant(state)
    peak, peak_day, drift = state[1], 0.0, 0.0
    for step in range(1, int(days / h) + 1):
        state = rk4_step(state, h, beta, gamma)
        if state[1] > peak:
            peak, peak_day = state[1], step * h
        drift = max(drift, abs(invariant(state) - v0))
    return state[0], peak, peak_day, drift

def final_size(r0, s0=1.0, tol=1e-15):
    """Root s in (0, 1) of s = s0 exp(-R0 (1 - s)) for R0 > 1, by Newton's method."""
    s = 0.5 / r0
    for _ in range(100):
        g = s - s0 * math.exp(-r0 * (1 - s))
        dg = 1 - r0 * s0 * math.exp(-r0 * (1 - s))
        step = g / dg
        s -= step
        if abs(step) < tol:
            break
    return s

def peak_prevalence(r0):
    """Peak infected fraction 1 - (1 + ln R0)/R0 (for S(0) = 1, I(0) = 0+)."""
    return 1 - (1 + math.log(r0)) / r0

def main():
    print("SIR with gamma = 0.1/day, I(0) = 1e-4, RK4 with step 0.5 days")
    print("  R0 | attack rate: RK4  final-size | peak I: RK4 formula | day"
          " | herd 1-1/R0")
    for r0 in [1.5, 2.0, 3.0, 5.0]:
        s_end, peak, day, drift = simulate(r0)
        s_inf = final_size(r0)
        print(f" {r0:>3} |        {1 - s_end:.4f}    {1 - s_inf:.4f} |"
              f"  {peak:.4f}  {peak_prevalence(r0):.4f} | {day:>3.0f} |"
              f"   {1 - 1 / r0:.3f}")
    print()
    _, _, _, drift = simulate(3.0)
    print(f"Largest drift of S + I - ln(S)/R0 along the R0 = 3 run: {drift:.1e}")
    print("Attack rates exceed the herd immunity threshold: the epidemic")
    print("overshoots, because infections continue after S/N falls below 1/R0.")
    print("Small differences from the formulas come from I(0) > 0.")
    print()
    print("Epistemic status: numerical solution (RK4) of one deterministic model")
    print("with chosen parameters, compared with exact relations derived in the")
    print("lesson. It says nothing about whether real epidemics follow the SIR")
    print("assumptions (homogeneous mixing, fixed parameters, lasting immunity).")

if __name__ == "__main__":
    main()
Runs entirely in your browser, in an isolated worker. Nothing is sent to a server.

All three are numerical evidence (floating-point solutions of model equations). They test our formulas and our numerical methods; whether real populations follow these models is a separate, empirical question.

Exercises

Exercises

1. Mathematical biology

Warm-upHuman

For the logistic map xn+1=2.5 xn(1−xn)x_{n+1} = 2.5\,x_n(1 - x_n), what is the non-zero fixed point, in percent of the maximum population?

2. Mathematical biology

CoreHuman

For which growth rates rr is the non-zero fixed point x∗=1−1/rx^* = 1 - 1/r of the logistic map locally asymptotically stable? (Choose all that apply.)

Choose all that apply

3. Mathematical biology

Warm-upHuman

In the simple SIR model, an infection has R0=4R_0 = 4. What percentage of the population must be immune for an introduced infection not to grow (the herd immunity threshold)?

4. Mathematical biology

Warm-upHuman

Which statement about the basic reproduction number R0=β/γR_0 = \beta/\gamma is correct?

Choose one

5. Mathematical biology

CoreHuman

At the coexistence equilibrium of the Lotka–Volterra predator–prey model the Jacobian has eigenvalues ±iαγ\pm i\sqrt{\alpha\gamma}. What can we conclude from the linearisation alone?

Choose one

6. Mathematical biology

CoreHuman

In the competition model x′=x(1−x−a12y)x' = x(1 - x - a_{12}y), y′=y(1−y−a21x)y' = y(1 - y - a_{21}x), which parameters give a stable coexistence equilibrium?

Choose one

7. Mathematical biology

CoreHuman

A fish stock grows logistically with r=0.4r = 0.4 per year and carrying capacity K=10 000K = 10\,000 tonnes, and is harvested at a constant rate of HH tonnes per year. What is the largest HH for which a positive equilibrium exists (the maximum sustainable yield), in tonnes per year?

8. Mathematical biology

StretchHuman

In the SIR model with R0>1R_0 > 1 and almost everyone initially susceptible, when does the number of infected people reach its maximum?

Choose one

9. Mathematical biology

CoreFormal

Which Lean statement says that Volterra's quantity is conserved along a solution of the predator–prey equations at time t?

Choose one

10. Mathematical biology

StretchComputational

Write final_size(R0) returning the fraction 1−s1 - s of a population eventually infected in the SIR model, where s∈(0,1)s \in (0, 1) solves s=e−R0(1−s)s = e^{-R_0(1 - s)} (return 0.0 when R0≤1R_0 \le 1). Use bisection on g(s)=s−e−R0(1−s)g(s) = s - e^{-R_0(1 - s)}. Since g(1)=0g(1) = 0 as well, bracket the non-trivial root in [0,1/R0][0, 1/R_0], where g(0)<0<g(1/R0)g(0) < 0 < g(1/R_0).

Runs entirely in your browser, in an isolated worker. Nothing is sent to a server.
Common misconceptionsH

Common misconceptions

Misconception

"A model's prediction is a forecast of what will happen." A model makes conditional statements: if its mechanisms and parameter values are right, then this follows. Its outputs inherit every assumption — homogeneous mixing, constant rates, no behavioural change. Projections under different scenarios are tools for comparing choices; when the scenario does not occur (often because people acted on the projection), the model has not been refuted.

Misconception

"R0R_0 is a fixed biological constant of a disease." R0=β/γR_0 = \beta/\gamma depends on contact patterns, population density, environment and behaviour as well as on the pathogen. The same infection can have very different R0R_0 in a crowded city and a scattered rural population, or in different seasons; and what changes during an outbreak is the effective reproduction number RtR_t.

Misconception

"The predator–prey cycles are explained by the linearisation." At the coexistence equilibrium the linearisation is a centre, which is inconclusive: small nonlinear terms could turn it into a spiral either way. The closed orbits come from the exact conserved quantity VV — and they disappear when the model is perturbed, so real cycles need a robust mechanism such as a limit cycle.

Misconception

"Complicated behaviour needs a complicated model." The logistic map, with one parameter and one quadratic formula, produces period doubling and chaos. Conversely, irregular data do not prove that the underlying process is random — or that it is chaotic.

Misconception

"Reaching the herd immunity threshold ends an epidemic at that point." Once S/N<1/R0S/N < 1/R_0 infections decline, but those already infected keep transmitting, so an uncontrolled epidemic overshoots: with R0=3R_0 = 3 the threshold is 67%67\%, but about 94%94\% are eventually infected.

ViewpointsH

Many ways of seeing

Topology— What the phase plane allows

Planar dynamics is constrained by topology. Trajectories cannot cross, so by the Poincaré–Bendixson theorem a bounded trajectory of a C1C^1 planar system that stays away from equilibria approaches a periodic orbit: two-species continuous-time models cannot be chaotic, which is why chaos in population biology needs discrete generations (as in the logistic map), time delays, seasonal forcing or at least three species. Index theory adds another constraint: going once round a periodic orbit, the vector field turns exactly once, and the indices of the equilibria inside add up to +1+1; since a saddle has index −1-1 and a node, spiral or centre +1+1, every predator–prey cycle must enclose an equilibrium that is not a saddle — the coexistence point. The VectorField widget's loop mode computes such indices. See dynamical systems.

Geometry— Lotka–Volterra is a Hamiltonian system in disguise

In logarithmic coordinates u=ln⁡xu = \ln x, v=ln⁡yv = \ln y, the predator–prey equations become u′=α−βevu' = \alpha - \beta e^v, v′=δeu−γv' = \delta e^u - \gamma. With H(u,v)=δeu−γu+βev−αvH(u, v) = \delta e^u - \gamma u + \beta e^v - \alpha v — Volterra's VV rewritten — these are u′=−∂H/∂vu' = -\partial H/\partial v and v′=∂H/∂uv' = \partial H/\partial u: Hamilton's equations, as for a frictionless mechanical system. The flow therefore preserves area in the (u,v)(u, v)-plane, which is why there can be no attracting or repelling cycles: an attractor would shrink area. Geometrically, the orbits are the level curves of HH, a convex function whose sublevel sets are convex discs. Numerical methods that respect this structure (symplectic integrators) keep the orbits closed far better than Euler's method, as the second experiment shows for RK4 versus Euler. See classical mechanics.

Analysis— Lyapunov functions and conservation laws

The two central tools of the lesson are functions that do not increase along solutions. A conserved quantity (VV for predator–prey, S+I−NR0ln⁡SS + I - \frac N{R_0}\ln S for SIR) confines orbits to its level sets; a Lyapunov function — positive except at an equilibrium and decreasing along solutions — proves stability without solving anything, as the quadratic form y⊤Myy^\top My did in the linearisation theorem. For the predator–prey model with self-limiting prey, a function of Volterra's form built from the new equilibrium, V=δ(x−x∗ln⁡x)+β(y−y∗ln⁡y)V = \delta(x - x^*\ln x) + \beta(y - y^*\ln y), becomes a Lyapunov function: V′=−αδK(x−x∗)2≤0V' = -\frac{\alpha\delta}{K}(x - x^*)^2 \le 0, and LaSalle's invariance principle then gives global convergence to the equilibrium. Finding such functions is an art; for large classes of chemical and ecological models, functions of the form ∑i(xi−xi∗ln⁡xi)\sum_i (x_i - x_i^*\ln x_i) — relative entropies in disguise — do the job.

Probability— Branching processes and extinction

When few individuals are involved, the right model is random. In a Galton–Watson branching process each individual independently produces a random number of offspring with mean mm; the extinction probability qq is the smallest root in [0,1][0, 1] of q=φ(q)q = \varphi(q), where φ\varphi is the offspring generating function, and q<1q < 1 exactly when m>1m > 1. For an infection with R0=mR_0 = m, a deterministic epidemic is replaced by a gamble: with a geometric number of secondary cases (exponential infectious period), φ(s)=11+R0(1−s)\varphi(s) = \frac{1}{1 + R_0(1 - s)} and q=1/R0q = 1/R_0. Outbreaks that take off then behave like the deterministic SIR model — a law of large numbers for Markov processes (Kurtz, 1970) makes this precise. The same mathematics governs the survival of a new mutation (Haldane, 1927: a mutation with small selective advantage ss survives with probability about 2s2s) and the extinction of family names, Galton and Watson's original question (1874).

Physics— Mass action and chemical kinetics

The interaction terms βxy\beta xy and βSI/N\beta SI/N come from the law of mass action of chemical kinetics (Guldberg and Waage, 1864): the rate of a reaction between two well-mixed species is proportional to the product of their concentrations, because it is proportional to the rate of encounters. Lotka, a physical chemist, built his ecological models by analogy with autocatalytic reactions, and the predator–prey equations are formally the kinetics of the reactions X→2XX \to 2X, X+Y→2YX + Y \to 2Y, Y→∅Y \to \varnothing. The analogy is heuristic: animals and people do not mix like molecules in a stirred beaker, and network and spatial structure (who meets whom) can change thresholds and dynamics substantially. Chemical oscillators such as the Belousov–Zhabotinsky reaction, by contrast, really are well-mixed, and show the limit cycles that the robust ecological models predict.

History & global context

History and global context

  • Growth. Leonardo of Pisa's rabbit problem in the Liber Abaci (1202) is an early population model. Thomas Malthus's Essay on the Principle of Population (1798) contrasted geometric population growth with arithmetic growth of food; Pierre-François Verhulst introduced the logistic equation in 1838, and Raymond Pearl and Lowell Reed rediscovered it in 1920. Patrick Leslie's matrix models for age-structured populations followed in 1945.
  • Interacting species. Alfred Lotka (Elements of Physical Biology, 1925) and Vito Volterra (1926, prompted by Umberto D'Ancona's Adriatic fishery data) independently proposed the predator–prey equations. Georgii Gause's experiments in Moscow (The Struggle for Existence, 1934) tested competition models. Crawford Holling (1959) described predators' functional responses, and Michael Rosenzweig and Robert MacArthur (1963) analysed predator–prey stability graphically.
  • Epidemics. Daniel Bernoulli (1760) used a mathematical model to argue for smallpox inoculation. Ronald Ross, who had shown in India (1897) that mosquitoes transmit malaria, argued with a mathematical model (1911) that malaria could be controlled by reducing mosquito numbers below a threshold, without eliminating them; George Macdonald (1957) developed this into the theory of the reproduction number. William Kermack and Anderson McKendrick's 1927 paper introduced the SIR model and the threshold theorem. Roy Anderson and Robert May's Infectious Diseases of Humans (1991) synthesised the modern theory, used for HIV, measles, SARS (2003), Ebola (2014–16) and COVID-19 (2020 onwards).
  • Patterns and chaos. Ronald Fisher (1937) and Andrei Kolmogorov, Ivan Petrovsky and Nikolai Piskunov (1937) studied travelling waves of advantageous genes; Alan Turing's "The chemical basis of morphogenesis" (1952) proposed reaction–diffusion patterns. Robert May's review "Simple mathematical models with very complicated dynamics" (Nature, 1976) brought the logistic map's chaos to biologists; Mitchell Feigenbaum (1978) discovered its universality, and Oleksandr Sharkovsky (1964) and Tien-Yien Li and James Yorke (1975) had found the theorems on periods.
Further reading

Further reading

  • J. D. Murray, Mathematical Biology (1989; 3rd edition in two volumes, 2002–03) — the classic reference, from population dynamics to pattern formation.
  • Leah Edelstein-Keshet, Mathematical Models in Biology (1988; reprinted 2005) — discrete and continuous models with a gentle, thorough approach.
  • Steven H. Strogatz, Nonlinear Dynamics and Chaos (1994; 2nd edition 2015) — phase planes, bifurcations, the logistic map and chaos, with many biological examples.
  • Fred Brauer and Carlos Castillo-Chavez, Mathematical Models in Population Biology and Epidemiology (2001; 2nd edition 2012).
  • Roy M. Anderson and Robert M. May, Infectious Diseases of Humans: Dynamics and Control (1991).
  • Matt J. Keeling and Pejman Rohani, Modeling Infectious Diseases in Humans and Animals (2008) — with code, stochastic and network models.
  • Sarah P. Otto and Troy Day, A Biologist's Guide to Mathematical Modeling in Ecology and Evolution (2007).