Lotka–Volterra Equations — Predator–Prey Population Cycles
First formulated independently by Alfred Lotka (1920) and Vito Volterra (1926), the Lotka–Volterra equations model the cyclical oscillation of two interacting populations — a prey species and its predator. The model reveals how a simple two-equation system can produce perpetual, self-sustaining cycles without any external forcing.
1. The two-species model and assumptions
The classic Lotka–Volterra system involves two populations interacting in a predator–prey relationship:
Rabbits, fish, or any species that is hunted. Grows without limit in the absence of predators.
Foxes, sharks, or any predator. Depends entirely on prey for food; starves without it.
The model rests on four key assumptions:
- Unlimited prey growth: in the absence of predators, prey grow exponentially at rate α.
- Predator-only mortality: in the absence of prey, predators die exponentially at rate δ.
- Mass-action encounters: predation events are proportional to the product x·y — every predator is equally likely to encounter every prey individual.
- Closed ecosystem: no immigration, emigration, or seasonal effects. Only prey and predator.
2. System of ODEs — derivation
Let x(t) be the prey population and y(t) be the predator population. The four parameters are:
α — prey birth rate
Per-capita exponential growth rate of prey in the absence of predators. Typical: 0.5–2.0 yr⁻¹.
β — predation rate
Rate at which predators consume prey per unit of each population. Controls encounter efficiency. Typical: 0.01–0.1.
δ — predator growth rate
Conversion efficiency of consumed prey into predator offspring. Often δ < β. Typical: 0.001–0.02.
γ — predator death rate
Per-capita death rate of predators in the absence of prey. Typical: 0.2–1.0 yr⁻¹.
The governing equations are:
dy/dt = −γ·y + δ·x·y ← predator: dies alone, grows when fed
Term breakdown:
α·x — exponential prey birth (logistic if replaced by α·x·(1 − x/K))
−β·x·y — prey eaten: each predator-prey encounter removes β prey/time
−γ·y — predator starvation in absence of prey
δ·x·y — predator reproduction from consuming prey (δ = conversion factor)
The mass-action term β·x·y is the key nonlinearity.
Without it the equations decouple into two independent exponentials.
With it, the populations are coupled and oscillate indefinitely.
3. Equilibria and stability analysis
Setting dx/dt = dy/dt = 0 reveals two fixed points:
Both species extinct. Unstable saddle point.
Non-trivial equilibrium E* = (x*, y*):
x* = γ/δ ← prey level that keeps predators constant
y* = α/β ← predator level that keeps prey constant
Set dx/dt = 0: x(α − β·y) = 0 → y = α/β (for x ≠ 0)
Set dy/dt = 0: y(−γ + δ·x) = 0 → x = γ/δ (for y ≠ 0)
Linearisation at E*: The Jacobian matrix evaluated at the non-trivial equilibrium has purely imaginary eigenvalues:
[δ·y*, 0] ]
eigenvalues: λ = ± i·√(α·γ) ← purely imaginary → centre
Period of small oscillations: T ≈ 2π / √(α·γ)
Purely imaginary eigenvalues indicate a centre in the linearised system. For the fully nonlinear Lotka–Volterra equations, this centre is neutrally stable: perturbations do not grow or decay — they orbit the equilibrium forever on a closed trajectory whose shape depends on initial conditions.
4. Phase portrait and conservation law
The Lotka–Volterra system has a remarkable first integral (conserved quantity), analogous to energy conservation in mechanics:
Verification: dV/dt = (δ − γ/x)·(dx/dt) + (β − α/y)·(dy/dt)
= (δ − γ/x)·(αx − βxy) + (β − α/y)·(−γy + δxy)
= ... = 0 ✓ (cancellation is exact)
Each closed orbit in the phase plane (x, y) corresponds to a constant value of V. The orbit closest to the equilibrium E* has the smallest V; the amplitude of oscillation grows as V increases.
In the phase portrait you will observe:
- Clockwise closed curves around E* = (γ/δ, α/β).
- Prey peaks before predator peaks — the lag is a quarter-period (≈ T/4).
- Outer curves reach dangerously low minima — near-extinction before recovery.
- The equilibrium itself is the innermost point (infinitesimal oscillation).
5. Parameter effects — what changes the cycle?
Each parameter changes a specific aspect of the oscillation:
Increase α (faster prey growth)
Higher equilibrium predator count y* = α/β. Faster oscillations (period T ∝ 1/√α). Prey recover faster after predation.
Increase β (higher predation efficiency)
Lower equilibrium prey x* = γ/δ remains unchanged; prey equilibrium y* = α/β decreases. Larger amplitude swings.
Increase γ (faster predator death)
Predators collapse faster without food. Lower equilibrium predator density. Longer period T between peaks.
Increase δ (better food conversion)
Each kill produces more offspring. Lower equilibrium prey count x* = γ/δ. Oscillations become more tightly coupled.
Adding a
logistic cap for prey (αx(1−x/K))
transforms the neutral centre into a stable spiral: trajectories
spiral inward, reaching a unique limit cycle (if the equilibrium lies
inside the feasible region) or a stable point (if K is small).
6. JavaScript implementation with RK4
The 4th-order Runge–Kutta method (RK4) gives excellent accuracy at reasonable cost. Each step requires four evaluations of the right-hand side function:
// Lotka–Volterra right-hand side
function lv(x, y, α, β, γ, δ) {
return {
dxdt: α * x - β * x * y,
dydt: -γ * y + δ * x * y,
};
}
// RK4 single step
function rk4Step(x, y, h, α, β, γ, δ) {
const k1 = lv(x, y, α, β, γ, δ);
const k2 = lv(x + h/2*k1.dxdt, y + h/2*k1.dydt, α, β, γ, δ);
const k3 = lv(x + h/2*k2.dxdt, y + h/2*k2.dydt, α, β, γ, δ);
const k4 = lv(x + h*k3.dxdt, y + h*k3.dydt, α, β, γ, δ);
return {
x: x + (h/6) * (k1.dxdt + 2*k2.dxdt + 2*k3.dxdt + k4.dxdt),
y: y + (h/6) * (k1.dydt + 2*k2.dydt + 2*k3.dydt + k4.dydt),
};
}
// Simulate for T years with step h
function simulate(x0, y0, α, β, γ, δ, T, h = 0.01) {
const history = [{ t: 0, x: x0, y: y0 }];
let { x, y } = { x: x0, y: y0 };
for (let t = h; t <= T; t += h) {
({ x, y } = rk4Step(x, y, h, α, β, γ, δ));
// Guard against numerical blow-up near extinction
if (x < 0) x = 0;
if (y < 0) y = 0;
history.push({ t, x, y });
}
return history;
}
// Example: classic parameter set
const α = 1.0; // prey birth rate
const β = 0.1; // predation rate
const γ = 0.4; // predator death rate
const δ = 0.02; // predator conversion efficiency
const data = simulate(10, 5, α, β, γ, δ, 50);
// data[i].x → prey population at time data[i].t
// data[i].y → predator population at time data[i].t
Rendering the phase portrait
// Draw (x, y) trajectory on a 2D canvas
function drawPhasePortrait(ctx, data, W, H) {
const maxX = Math.max(...data.map(p => p.x)) * 1.1;
const maxY = Math.max(...data.map(p => p.y)) * 1.1;
const cx = p => (p.x / maxX) * W;
const cy = p => H - (p.y / maxY) * H;
ctx.beginPath();
data.forEach((p, i) => {
i === 0
? ctx.moveTo(cx(p), cy(p))
: ctx.lineTo(cx(p), cy(p));
});
ctx.strokeStyle = '#22c55e';
ctx.lineWidth = 1.5;
ctx.stroke();
// Mark equilibrium E* = (γ/δ, α/β)
const eq = { x: γ/δ, y: α/β };
ctx.beginPath();
ctx.arc(cx(eq), cy(eq), 5, 0, Math.PI * 2);
ctx.fillStyle = '#f59e0b';
ctx.fill();
}
🐺 Live Predator–Prey Simulation
Adjust α, β, γ, δ sliders and watch the population cycles in real time. Switch between time-series and phase-portrait view.
7. Extensions: competition, three species, stochasticity
Logistic prey (Rosenzweig–MacArthur model)
Replacing the linear prey term with a logistic cap introduces a carrying capacity K:
dy/dt = −γ·y + δ·x·y
Now the equilibrium can be a stable spiral or a limit cycle
depending on K vs (γ/δ). A "Hopf bifurcation" occurs at K = γ/(2δ).
This extension removes the structural instability and gives realistic closed limit cycles (Hopf attractors) for intermediate K values.
Competitive Lotka–Volterra (two prey species)
Two competing species sharing a resource:
dx₂/dt = r₂·x₂·(1 − (x₂ + α₂₁·x₁)/K₂)
αᵢⱼ = effect of species j on species i (competition coefficient)
Coexistence: α₁₂ < K₁/K₂ AND α₂₁ < K₂/K₁ (competitive coexistence)
Three-species food chains
Adding a top predator z (which eats y) creates a 3D ODE system. The trophic cascade can exhibit chaotic dynamics — the Hastings–Powell (1991) model showed that simple food chains can produce chaos without any stochastic driving, purely from the nonlinear interactions.
Stochastic extensions
Deterministic models give ensemble-average behaviour. Real populations are finite and discrete, making stochasticity essential for small populations:
- Demographic stochasticity: individual births and deaths are random events — use the Gillespie algorithm or τ-leaping for efficient simulation.
- Environmental stochasticity: parameters α, β vary randomly in time (e.g., seasonal forcing). Modelled by Itô stochastic differential equations.
- Spatial models: agents on a grid with local interactions. Can stabilise chaotic systems through spatial segregation of predator and prey.