Predator and prey populations neither settle nor explode but cycle forever — so what is the AVERAGE population over a cycle, and does it depend on how wildly the cycle swings?
Units: dimensionless population — the prey time-average ⟨x⟩ = γ/δ = 2.0 and predator time-average ⟨y⟩ = α/β = 2.0, both equal to the coexistence fixed point; secondary knowns: small-amplitude period T₀ = 2π/√(αγ) = 2π, culling law ⟨x⟩ = (γ+m)/δ
▶ Run this simulationRead how it works
The mean of a boom-bust cycle sits exactly on the balance point: integrating ONLY the two Lotka–Volterra rate laws ẋ = αx − βxy, ẏ = δxy − γy and averaging the trajectory in time, the prey mean ⟨x⟩ = 2.000001 and predator mean ⟨y⟩ = 2.000000 land on the coexistence fixed point γ/δ = α/β = 2 to 6e-5% — and stay pinned there across 16 orbits from tiny to wide (amplitude-invariant to 5e-4%), Volterra's law of averages; the small-amplitude period extrapolates to T₀ = 2π/√(αγ) = 6.28315 (2π by extrapolation, not plugged); imposing a uniform mortality on BOTH species shifts the prey mean UP as (γ+m)/δ (fitted slope 2.0001, intercept 2.0000) while the predator mean falls at −1/β = −2 — the pesticide paradox; and the naive rival 'the mean is the middle of the range' (x_min+x_max)/2 is biased +13% AND amplitude-dependent (spreads 12%), dead while the time-average is invariant
Generator = classical RK4 stepping of the two local rate laws ẋ = αx − βxy − mx, ẏ = δxy − γy − my (m = 0 except in the culling gate) and a trapezoidal time-average — no closed form for the mean, the period, or the culling law anywhere in the recovery. The module's own coefficients (α = 1, β = ½, γ = 1, δ = ½ ⇒ fixed point (γ/δ, α/β) = (2, 2)), dt = 5e-4, averages taken as ∫x dt / ∫dt between the 1st and 6th detected prey maximum (5 whole periods). Gates: (A) law of averages — 12 initial conditions spanning a wide amplitude range (mulberry32), ⟨x⟩, ⟨y⟩ vs γ/δ, α/β within 4e-4, worst seed 8e-4; (B) amplitude invariance — a four-rung ladder of orbits (small → large) keeps ⟨x⟩ on γ/δ within 8e-4 while the arithmetic midpoint drifts away; (C) small-amplitude period — T fitted against amplitude² and extrapolated to amplitude 0 recovers T₀ = 2π/√(αγ) within 1e-3; (D) perturbation (Volterra's principle) — uniform culling m ∈ {0,0.1,0.2,0.3}, ⟨x⟩ vs m a line of slope 1/δ = 2 and intercept γ/δ = 2 (prey RISES), ⟨y⟩ slope −1/β = −2; (E) rival — the naive midpoint (x_min+x_max)/2 must miss γ/δ by ≥5% AND spread ≥5% across the ladder; (F) conservation — RK4 keeps V = δx − γ ln x + βy − α ln y to |ΔV/V| < 1e-5 so the closed-orbit telescoping ∫(ẋ/x)dt = 0 holds numerically; (G) scoring self-test. Every known number (γ/δ, 2π/√(αγ), (γ+m)/δ) is loaded from the reference or formed in the SCORER only.
Lotka–Volterra populations cycle forever on closed level curves of V = δx − γ ln x + βy − α ln y around the coexistence point (γ/δ, α/β). Because the orbit closes, ∫₀^T (ẋ/x) dt = [ln x]₀^T = 0, so ∫₀^T (α − βy) dt = 0 ⇒ the time-average ⟨y⟩ = α/β, and symmetrically ⟨x⟩ = γ/δ — the mean population sits EXACTLY on the fixed point at any amplitude (Volterra's law of averages, 1926). Linearizing about the fixed point gives frequency √(αγ), so the period → 2π/√(αγ) as amplitude → 0. Adding a uniform mortality m to both species moves the fixed point to ((γ+m)/δ, (α−m)/β): culling raises the prey mean and lowers the predator mean (Volterra's principle / the pesticide paradox).
12/12 pass in ~11 s, fully deterministic (fixed seed 20260717). A–G are the physics gates (this file's own re-typed RK4); H–L are the HONEST-MODULE CERTIFICATE, which sha256-pins, mechanically strips and EXECUTES the shipped src/modules/LotkaVolterraModule.ts through `new Function` with Babylon/DOM recorder stubs. Tampers: known_value 2.0 → 2.5 ⇒ A/B/E/K FAIL, exit 1, with the recovered ⟨x⟩ = 2.000001 and the on-screen ⟨x⟩ = 1.999220 BYTE-IDENTICAL and H/I/J/L correctly still green (they certify the module, not the value); module trapezoid → left-rectangle in the display path ⇒ H (sha) + J (tick-by-tick bit-compare) FAIL while I/K/L stay green — the bit-compare, not the tolerance gate, is what catches a quadrature swap; module DELTA 0.5 → 0.52 ⇒ all five of H/I/J/K/L FAIL.
Volterra's law of averages for the Lotka–Volterra system (Volterra 1926; Lotka 1925; Murray, Mathematical Biology I §3.1): the time-average of each population over a cycle equals the coexistence fixed point ⟨x⟩ = γ/δ, ⟨y⟩ = α/β, independent of amplitude. Non-circular because the generator contains only the RK4 stepping of the two local rate laws and a trapezoidal time-average — no γ/δ, no 2π/√(αγ), no (γ+m)/δ enters the recovery; the closed forms live exclusively in the scorer, and the fixed point is recovered by AVERAGING a trajectory that never references it (the RK4 stepper only knows the instantaneous rates). The recovery is sharper than a 'the loop encircles the fixed point' demo: it pins the mean to 6e-5% AND demonstrates the non-obvious amplitude-invariance across 16 orbits, recovers the small-amplitude period 2π by extrapolation from finite-amplitude orbits (never plugging into the formula), verifies the counterintuitive pesticide-paradox slope, and kills the naive 'mean = middle of range' rival structurally — the same trajectory that gives ⟨x⟩ = 2 gives a midpoint biased +13% and amplitude-dependent. Limits: the un-damped conservative Lotka–Volterra only (no prey carrying capacity — a logistic prey term destroys the conserved quantity and spirals to a stable fixed point, where the law of averages no longer holds; not tested); the coexistence regime (both species persist); mean-field ODEs, not the spatial/stochastic predator-prey lattice (demographic-noise cycles and their coherence are a different question).
RUNG 6 (validated + honest module). Two on-screen numbers were previously unreconciled; both are now PREDICTED, not tolerated, and the derisk EXECUTES the shipped module rather than a re-typed copy of it. (1) THE HEADLINE IS NOW ON SCREEN. At rung 5 the module displayed no time-average at all, so the finding's headline ⟨x⟩ = γ/δ was an oracle-only recovery — the screen could not have contradicted it. The module now accumulates a trapezoidal time-average of both populations between successive detected prey maxima and prints ⟨x⟩, ⟨y⟩ directly beside the fixed point (γ/δ, α/β) it is claimed to equal. Live values: ⟨x⟩ = 1.9992, ⟨y⟩ = 2.0000 against 2.0000, 2.0000. The prey residual is 3.90e-4 relative and ALTERNATES IN SIGN between consecutive cycles (1.999220 / 2.000656 / 1.999220 / …). That alternation is the whole story and gate K predicts it quantitatively: the module averages over the interval between two DETECTED maxima, a whole number of its own steps W = N·dt, which cannot equal the true period T_m, so a leftover sliver ε = W − T_m sits right at the peak where x is far above its mean. The model ⟨x⟩_window = (γ/δ·T_m + ε·x_peak)/W — with T_m and x_peak taken by parabolic interpolation of the MODULE's OWN samples, nothing imported from the oracle's finer integrator — accounts for 99.645% of the observed residual, with N alternating 1606/1607 and ε alternating −2.27e-3/+1.91e-3. The gate also carries a FLOOR (the residual must be at least 50% of the predicted sliver, measured 99.6%), so a module that simply printed a hardcoded 2.0 could not pass by looking perfect. The predator residual is 1.89e-6 — three orders smaller, because y's peak sits much closer to its own mean, so the same sliver carries far less weight. (2) THE PERIOD'S +6.54% IS PHYSICS, AND IT IS NOW PREDICTED TO 8.0e-7. The HUD shows a period of 6.69 beside a printed T₀ = 2π/√(αγ) = 6.28. At rung 5 this looked like a 6.5% miss and was excused in prose as 'the true finite-amplitude lengthening'. Gate L turns that excuse into a measurement: an INDEPENDENT T(amplitude) curve built from ten orbits of a DIFFERENT initial-condition family (launched on the prey axis at y₀ = α/β, whereas the module starts at (1,1)), integrated at the oracle's fine dt and interpolated at the SCREEN's own amplitude 1.795877, returns T = 6.69392403 against the screen's own sub-step period 6.69392938 — relative 8.0e-7. The same curve's small-amplitude end lands back on T₀ to 5.1e-5, confirming it is the right curve. So the gap is the boom-bust cycle genuinely lengthening as it swings wider, quantified, not an integrator error. The HUD text was corrected to match: it now reads 'period at THIS amplitude' with 'T₀ = 6.28 is the amplitude→0 limit', so the screen no longer invites the false comparison. Separately, the DISPLAYED whole-step period takes exactly two alternating values (6.691667 / 6.695833) which bracket the sub-step period and differ by exactly one dt = 1/240 — peak-detection quantisation, gated as such. (3) WHAT DID NOT CHANGE. The module's trajectory is untouched: the averaging accumulators only READ the state the integrator leaves behind, and gate I confirms the executed _step is still bit-for-bit the oracle's certified rk4 at all 96 000 probed states. The conserved quantity V drifts 6.6e-12 over the run (displayed as 0.000%), so the closed-orbit telescoping the law of averages rests on is realized on screen as well as in the oracle. Module edits this run were confined to src/modules/LotkaVolterraModule.ts: the live time-average, the HUD lines, and the period label.
npm run derisk -- predprey (scripts/predprey-derisk.mjs)scripts/oracles/predprey.reference.jsonV. Volterra, Mem. R. Accad. Naz. Lincei 2, 31 (1926); A. J. Lotka, 'Elements of Physical Biology' (Williams & Wilkins, 1925); U. D'Ancona, 'La lotta per l'esistenza' (1942); J. D. Murray, 'Mathematical Biology I' (Springer, 3rd ed. 2002), §3.1.