FAILURE MAP
← Case archive

FA-64951 / Epidemic compartment models / Open access

Reed-Frost expected chain-binomial generations: generation horizon · case 01

The chain is cut one generation short of the requested horizon.

Verified by executionVariant 1 · 7 checks per implementationDownload source bundle ↓JSON ↗

ROOT CAUSE

The generation loop runs one iteration too few.

THE FAILURE

The generation loop runs one iteration too few.

Unsuccessful approach: Adding an extra generation overshoots the requested horizon.

Case contract

Expected Reed-Frost: C[t+1] = S[t]*(1-(1-p)**C[t]), S[t+1]=S[t]-C[t+1]; cases are infectious for one generation only; stop early once expected cases fall below 1e-9; return [cases per generation including the index generation rounded to 4, final size including index cases rounded to 4]; None for invalid p or negative counts.

Why this case matters

Compartmental epidemic calculations drive outbreak forecasts, vaccine targets and hospital planning; a single wrong flow, rate conversion or boundary silently changes every downstream number.

1 / The failure

Exit 1
"""Failure Map reference implementation. Python standard library only."""
import json
import math
N = 1
observations = []
def solve(p, s0, i0, generations):
    if not 0 <= p <= 1 or s0 < 0 or i0 < 0:
        return None
    q = 1 - p
    s = float(s0)
    c = float(i0)
    cases = [round(c, 4)]
    for _ in range(generations - 1):
        nxt = s * (1 - q ** c)
        s -= nxt
        c = nxt
        cases.append(round(c, 4))
        if c < 1e-9:
            break
    return [cases, round(s0 + i0 - s, 4)]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('regression: household of 10',
   (0.1, 9, 1, 6),
   [[1.0, 0.9, 0.7328, 0.5474, 0.3822, 0.2541, 0.1633], 3.9798]),
  ('regression: school class',
   (0.04, 29, 1, 8),
   [[1.0, 1.16, 1.2876, 1.3596, 1.3602, 1.2872, 1.1541, 0.9844, 0.8038], 10.3969]),
  ('control: high contact probability', (0.5, 20, 2, 5), [[2.0, 15.0, 4.9998, 0.0001, 0.0], 22.0]),
  ('control: p zero no spread', (0.0, 10, 1, 4), [[1.0, 0.0], 1.0]),
  ('control: p one immediate saturation', (1.0, 10, 1, 4), [[1.0, 10.0, 0.0], 11.0]),
  ('control: no index cases', (0.2, 10, 0, 4), [[0.0, 0.0], 0.0]),
  ('control: invalid p', (1.5, 10, 1, 4), None)],
 [('control: p zero no spread', (0.0, 10, 1, 4), [[1.0, 0.0], 1.0]),
  ('control: p one immediate saturation', (1.0, 10, 1, 4), [[1.0, 10.0, 0.0], 11.0]),
  ('control: no index cases', (0.2, 10, 0, 4), [[0.0, 0.0], 0.0]),
  ('control: invalid p', (1.5, 10, 1, 4), None),
  ('regression: zero generations', (0.3, 10, 2, 0), [[2.0], 2.0]),
  ('regression: fading chain',
   (0.02, 30, 1, 10),
   [[1.0, 0.6, 0.3542, 0.2071, 0.1204, 0.0698, 0.0404, 0.0233, 0.0135, 0.0078, 0.0045], 2.4409]),
  ('regression: large ward',
   (0.03, 60, 3, 8),
   [[3.0, 5.2396, 8.0777, 10.182, 9.733, 6.8673, 3.7561, 1.7453, 0.7455], 49.3465])],
 [('control: high contact probability', (0.5, 20, 2, 5), [[2.0, 15.0, 4.9998, 0.0001, 0.0], 22.0]),
  ('control: p zero no spread', (0.0, 10, 1, 4), [[1.0, 0.0], 1.0]),
  ('control: invalid p', (1.5, 10, 1, 4), None),
  ('regression: zero generations', (0.3, 10, 2, 0), [[2.0], 2.0]),
  ('regression: fading chain',
   (0.02, 30, 1, 10),
   [[1.0, 0.6, 0.3542, 0.2071, 0.1204, 0.0698, 0.0404, 0.0233, 0.0135, 0.0078, 0.0045], 2.4409]),
  ('regression: large ward',
   (0.03, 60, 3, 8),
   [[3.0, 5.2396, 8.0777, 10.182, 9.733, 6.8673, 3.7561, 1.7453, 0.7455], 49.3465]),
  ('regression: two generations only', (0.15, 40, 4, 2), [[4.0, 19.1198, 19.9465], 43.0662])],
 [('regression: household of 10',
   (0.1, 9, 1, 6),
   [[1.0, 0.9, 0.7328, 0.5474, 0.3822, 0.2541, 0.1633], 3.9798]),
  ('regression: school class',
   (0.04, 29, 1, 8),
   [[1.0, 1.16, 1.2876, 1.3596, 1.3602, 1.2872, 1.1541, 0.9844, 0.8038], 10.3969]),
  ('control: high contact probability', (0.5, 20, 2, 5), [[2.0, 15.0, 4.9998, 0.0001, 0.0], 22.0]),
  ('control: p zero no spread', (0.0, 10, 1, 4), [[1.0, 0.0], 1.0]),
  ('control: p one immediate saturation', (1.0, 10, 1, 4), [[1.0, 10.0, 0.0], 11.0]),
  ('regression: large ward',
   (0.03, 60, 3, 8),
   [[3.0, 5.2396, 8.0777, 10.182, 9.733, 6.8673, 3.7561, 1.7453, 0.7455], 49.3465]),
  ('regression: two generations only', (0.15, 40, 4, 2), [[4.0, 19.1198, 19.9465], 43.0662])],
 [('regression: school class',
   (0.04, 29, 1, 8),
   [[1.0, 1.16, 1.2876, 1.3596, 1.3602, 1.2872, 1.1541, 0.9844, 0.8038], 10.3969]),
  ('control: high contact probability', (0.5, 20, 2, 5), [[2.0, 15.0, 4.9998, 0.0001, 0.0], 22.0]),
  ('control: p zero no spread', (0.0, 10, 1, 4), [[1.0, 0.0], 1.0]),
  ('control: p one immediate saturation', (1.0, 10, 1, 4), [[1.0, 10.0, 0.0], 11.0]),
  ('control: no index cases', (0.2, 10, 0, 4), [[0.0, 0.0], 0.0]),
  ('control: invalid p', (1.5, 10, 1, 4), None),
  ('regression: fading chain',
   (0.02, 30, 1, 10),
   [[1.0, 0.6, 0.3542, 0.2071, 0.1204, 0.0698, 0.0404, 0.0233, 0.0135, 0.0078, 0.0045], 2.4409])]]
for label, args, expected in fixtures[N - 1]:
    check(label, solve(*args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
Boundary fixtureActualExpectedOutcome
regression: household of 10[[1.0, 0.9, 0.7328, 0.5474, 0.3822, 0.2541], 3.8165][[1.0, 0.9, 0.7328, 0.5474, 0.3822, 0.2541, 0.1633], 3.9798]Failed
regression: school class[[1.0, 1.16, 1.2876, 1.3596, 1.3602, 1.2872, 1.1541, 0.9844], 9.5931][[1.0, 1.16, 1.2876, 1.3596, 1.3602, 1.2872, 1.1541, 0.9844, 0.8038], 10.3969]Failed
control: high contact probability[[2.0, 15.0, 4.9998, 0.0001, 0.0], 22.0][[2.0, 15.0, 4.9998, 0.0001, 0.0], 22.0]Passed
control: p zero no spread[[1.0, 0.0], 1.0][[1.0, 0.0], 1.0]Passed
control: p one immediate saturation[[1.0, 10.0, 0.0], 11.0][[1.0, 10.0, 0.0], 11.0]Passed
control: no index cases[[0.0, 0.0], 0.0][[0.0, 0.0], 0.0]Passed
control: invalid pNoneNonePassed

SHA-256 / aee747a6479781704f95f966549ff2450dd3fdb6f2ff547323c02e951d7605c4

2 / The unsuccessful fix

Exit 1
"""Failure Map reference implementation. Python standard library only."""
import json
import math
N = 1
observations = []
def solve(p, s0, i0, generations):
    if not 0 <= p <= 1 or s0 < 0 or i0 < 0:
        return None
    q = 1 - p
    s = float(s0)
    c = float(i0)
    cases = [round(c, 4)]
    for _ in range(generations + 1):
        nxt = s * (1 - q ** c)
        s -= nxt
        c = nxt
        cases.append(round(c, 4))
        if c < 1e-9:
            break
    return [cases, round(s0 + i0 - s, 4)]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('regression: household of 10',
   (0.1, 9, 1, 6),
   [[1.0, 0.9, 0.7328, 0.5474, 0.3822, 0.2541, 0.1633], 3.9798]),
  ('regression: school class',
   (0.04, 29, 1, 8),
   [[1.0, 1.16, 1.2876, 1.3596, 1.3602, 1.2872, 1.1541, 0.9844, 0.8038], 10.3969]),
  ('control: high contact probability', (0.5, 20, 2, 5), [[2.0, 15.0, 4.9998, 0.0001, 0.0], 22.0]),
  ('control: p zero no spread', (0.0, 10, 1, 4), [[1.0, 0.0], 1.0]),
  ('control: p one immediate saturation', (1.0, 10, 1, 4), [[1.0, 10.0, 0.0], 11.0]),
  ('control: no index cases', (0.2, 10, 0, 4), [[0.0, 0.0], 0.0]),
  ('control: invalid p', (1.5, 10, 1, 4), None)],
 [('control: p zero no spread', (0.0, 10, 1, 4), [[1.0, 0.0], 1.0]),
  ('control: p one immediate saturation', (1.0, 10, 1, 4), [[1.0, 10.0, 0.0], 11.0]),
  ('control: no index cases', (0.2, 10, 0, 4), [[0.0, 0.0], 0.0]),
  ('control: invalid p', (1.5, 10, 1, 4), None),
  ('regression: zero generations', (0.3, 10, 2, 0), [[2.0], 2.0]),
  ('regression: fading chain',
   (0.02, 30, 1, 10),
   [[1.0, 0.6, 0.3542, 0.2071, 0.1204, 0.0698, 0.0404, 0.0233, 0.0135, 0.0078, 0.0045], 2.4409]),
  ('regression: large ward',
   (0.03, 60, 3, 8),
   [[3.0, 5.2396, 8.0777, 10.182, 9.733, 6.8673, 3.7561, 1.7453, 0.7455], 49.3465])],
 [('control: high contact probability', (0.5, 20, 2, 5), [[2.0, 15.0, 4.9998, 0.0001, 0.0], 22.0]),
  ('control: p zero no spread', (0.0, 10, 1, 4), [[1.0, 0.0], 1.0]),
  ('control: invalid p', (1.5, 10, 1, 4), None),
  ('regression: zero generations', (0.3, 10, 2, 0), [[2.0], 2.0]),
  ('regression: fading chain',
   (0.02, 30, 1, 10),
   [[1.0, 0.6, 0.3542, 0.2071, 0.1204, 0.0698, 0.0404, 0.0233, 0.0135, 0.0078, 0.0045], 2.4409]),
  ('regression: large ward',
   (0.03, 60, 3, 8),
   [[3.0, 5.2396, 8.0777, 10.182, 9.733, 6.8673, 3.7561, 1.7453, 0.7455], 49.3465]),
  ('regression: two generations only', (0.15, 40, 4, 2), [[4.0, 19.1198, 19.9465], 43.0662])],
 [('regression: household of 10',
   (0.1, 9, 1, 6),
   [[1.0, 0.9, 0.7328, 0.5474, 0.3822, 0.2541, 0.1633], 3.9798]),
  ('regression: school class',
   (0.04, 29, 1, 8),
   [[1.0, 1.16, 1.2876, 1.3596, 1.3602, 1.2872, 1.1541, 0.9844, 0.8038], 10.3969]),
  ('control: high contact probability', (0.5, 20, 2, 5), [[2.0, 15.0, 4.9998, 0.0001, 0.0], 22.0]),
  ('control: p zero no spread', (0.0, 10, 1, 4), [[1.0, 0.0], 1.0]),
  ('control: p one immediate saturation', (1.0, 10, 1, 4), [[1.0, 10.0, 0.0], 11.0]),
  ('regression: large ward',
   (0.03, 60, 3, 8),
   [[3.0, 5.2396, 8.0777, 10.182, 9.733, 6.8673, 3.7561, 1.7453, 0.7455], 49.3465]),
  ('regression: two generations only', (0.15, 40, 4, 2), [[4.0, 19.1198, 19.9465], 43.0662])],
 [('regression: school class',
   (0.04, 29, 1, 8),
   [[1.0, 1.16, 1.2876, 1.3596, 1.3602, 1.2872, 1.1541, 0.9844, 0.8038], 10.3969]),
  ('control: high contact probability', (0.5, 20, 2, 5), [[2.0, 15.0, 4.9998, 0.0001, 0.0], 22.0]),
  ('control: p zero no spread', (0.0, 10, 1, 4), [[1.0, 0.0], 1.0]),
  ('control: p one immediate saturation', (1.0, 10, 1, 4), [[1.0, 10.0, 0.0], 11.0]),
  ('control: no index cases', (0.2, 10, 0, 4), [[0.0, 0.0], 0.0]),
  ('control: invalid p', (1.5, 10, 1, 4), None),
  ('regression: fading chain',
   (0.02, 30, 1, 10),
   [[1.0, 0.6, 0.3542, 0.2071, 0.1204, 0.0698, 0.0404, 0.0233, 0.0135, 0.0078, 0.0045], 2.4409])]]
for label, args, expected in fixtures[N - 1]:
    check(label, solve(*args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
Boundary fixtureActualExpectedOutcome
regression: household of 10[[1.0, 0.9, 0.7328, 0.5474, 0.3822, 0.2541, 0.1633, 0.1027], 4.0825][[1.0, 0.9, 0.7328, 0.5474, 0.3822, 0.2541, 0.1633], 3.9798]Failed
regression: school class[[1.0, 1.16, 1.2876, 1.3596, 1.3602, 1.2872, 1.1541, 0.9844, 0.8038, 0.6328], 11.0297][[1.0, 1.16, 1.2876, 1.3596, 1.3602, 1.2872, 1.1541, 0.9844, 0.8038], 10.3969]Failed
control: high contact probability[[2.0, 15.0, 4.9998, 0.0001, 0.0], 22.0][[2.0, 15.0, 4.9998, 0.0001, 0.0], 22.0]Passed
control: p zero no spread[[1.0, 0.0], 1.0][[1.0, 0.0], 1.0]Passed
control: p one immediate saturation[[1.0, 10.0, 0.0], 11.0][[1.0, 10.0, 0.0], 11.0]Passed
control: no index cases[[0.0, 0.0], 0.0][[0.0, 0.0], 0.0]Passed
control: invalid pNoneNonePassed

SHA-256 / ddccd018e3c62ce631a0c0540aa127f7eb879ecc82450ff1ebe3551c476102ab

HELD IN THE MEMBER ARCHIVE

The verified repair and its recorded checks are member-only.

This mechanism has 7 recorded checks per implementation. The open-access tier publishes the failure and the unsuccessful fix; the repaired source that passes every check, and the observations that prove it, are available to members.

Every case sharing this mechanism uses the same contract and the same repair, so this one record is held back for all of them.

Member access is invitation-based. Sign in with your invited account to inspect the repair.

Sign in to the archive ↗

Verification & scope

Deterministic bounded teaching model with a stipulated contract; not a validated scientific or public-health modelling library. This reproducer isolates one failure mechanism. Results cover the supplied fixtures. Variants within a family share a test contract and should remain grouped when constructing evaluation splits. Related mechanisms with a shared evaluation_group must also remain together; these controlled models are not independent production incidents.

Observations recorded using Python 3.12.14 at 2026-09-29T14:47:29.463895+00:00.

Case digest / cbcad2973bfd93055e01e0d68d85bfa97556b1ec0bec8ce903bbcaa81168b116