FA-65306 / Epidemic compartment models / Open access
Two-patch SIR with daily migration: simultaneous exchange · case 01
Migration creates or destroys people when flows are applied sequentially.
ROOT CAUSE
The second patch exchange uses the already-updated first patch.
VERIFIED REPAIR
Restore the simultaneous exchange rule: `a, b = comp[0] * travel, comp[1] * travel / comp[0] += b - a / comp[1] += a - b`.
Unsuccessful approach: Forgetting the outflow from patch 1 adds travellers without removing them.
Case contract
Each day: local frequency-dependent SIR in each patch using the current patch size, then every compartment exchanges fraction travel of each patch simultaneously; return [S pair, I pair, R pair] rounded 3.
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(beta, gamma, pops, i0s, travel, days):
s = [float(pops[k] - i0s[k]) for k in range(2)]
i = [float(x) for x in i0s]
r = [0.0, 0.0]
for _ in range(days):
n = [s[k] + i[k] + r[k] for k in range(2)]
inf = [beta * s[k] * i[k] / n[k] if n[k] > 0 else 0.0 for k in range(2)]
rec = [gamma * i[k] for k in range(2)]
for k in range(2):
s[k] -= inf[k]
i[k] += inf[k] - rec[k]
r[k] += rec[k]
for comp in (s, i, r):
comp[0] += comp[1] * travel - comp[0] * travel
comp[1] += comp[0] * travel - comp[1] * travel
return [[round(x, 3) for x in s], [round(x, 3) for x in i], [round(x, 3) for x in r]]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('regression: city and town',
(0.5, 0.2, [1000, 200], [10, 0], 0.05, 10),
[[611.99, 397.105], [74.874, 37.65], [52.607, 25.773]]),
('control: isolated patches',
(0.4, 0.2, [500, 500], [5, 0], 0.0, 8),
[[464.204, 500.0], [19.812, 0.0], [15.984, 0.0]]),
('regression: high mobility',
(0.6, 0.25, [300, 900], [0, 9], 0.3, 6),
[[557.673, 559.801], [25.331, 25.533], [15.766, 15.895]]),
('regression: both seeded',
(0.3, 0.1, [800, 400], [4, 4], 0.1, 12),
[[565.74, 538.406], [32.741, 32.614], [15.262, 15.237]]),
('control: boundary zero days',
(0.5, 0.2, [100, 100], [1, 1], 0.1, 0),
[[99.0, 99.0], [1.0, 1.0], [0.0, 0.0]]),
('regression: equal patches',
(0.5, 0.2, [400, 400], [8, 0], 0.2, 5),
[[377.224, 380.426], [15.15, 13.039], [7.625, 6.535]]),
('regression: tiny second patch',
(0.7, 0.3, [2000, 50], [20, 0], 0.02, 9),
[[1241.271, 264.206], [242.617, 45.744], [216.332, 39.829]])],
[('regression: city and town',
(0.5, 0.2, [1000, 200], [10, 0], 0.05, 10),
[[611.99, 397.105], [74.874, 37.65], [52.607, 25.773]]),
('control: isolated patches',
(0.4, 0.2, [500, 500], [5, 0], 0.0, 8),
[[464.204, 500.0], [19.812, 0.0], [15.984, 0.0]]),
('regression: high mobility',
(0.6, 0.25, [300, 900], [0, 9], 0.3, 6),
[[557.673, 559.801], [25.331, 25.533], [15.766, 15.895]]),
('regression: both seeded',
(0.3, 0.1, [800, 400], [4, 4], 0.1, 12),
[[565.74, 538.406], [32.741, 32.614], [15.262, 15.237]]),
('control: boundary zero days',
(0.5, 0.2, [100, 100], [1, 1], 0.1, 0),
[[99.0, 99.0], [1.0, 1.0], [0.0, 0.0]]),
('regression: equal patches',
(0.5, 0.2, [400, 400], [8, 0], 0.2, 5),
[[377.224, 380.426], [15.15, 13.039], [7.625, 6.535]]),
('regression: tiny second patch',
(0.7, 0.3, [2000, 50], [20, 0], 0.02, 9),
[[1241.271, 264.206], [242.617, 45.744], [216.332, 39.829]])],
[('regression: city and town',
(0.5, 0.2, [1000, 200], [10, 0], 0.05, 10),
[[611.99, 397.105], [74.874, 37.65], [52.607, 25.773]]),
('control: isolated patches',
(0.4, 0.2, [500, 500], [5, 0], 0.0, 8),
[[464.204, 500.0], [19.812, 0.0], [15.984, 0.0]]),
('regression: high mobility',
(0.6, 0.25, [300, 900], [0, 9], 0.3, 6),
[[557.673, 559.801], [25.331, 25.533], [15.766, 15.895]]),
('regression: both seeded',
(0.3, 0.1, [800, 400], [4, 4], 0.1, 12),
[[565.74, 538.406], [32.741, 32.614], [15.262, 15.237]]),
('control: boundary zero days',
(0.5, 0.2, [100, 100], [1, 1], 0.1, 0),
[[99.0, 99.0], [1.0, 1.0], [0.0, 0.0]]),
('regression: equal patches',
(0.5, 0.2, [400, 400], [8, 0], 0.2, 5),
[[377.224, 380.426], [15.15, 13.039], [7.625, 6.535]]),
('regression: tiny second patch',
(0.7, 0.3, [2000, 50], [20, 0], 0.02, 9),
[[1241.271, 264.206], [242.617, 45.744], [216.332, 39.829]])],
[('regression: city and town',
(0.5, 0.2, [1000, 200], [10, 0], 0.05, 10),
[[611.99, 397.105], [74.874, 37.65], [52.607, 25.773]]),
('control: isolated patches',
(0.4, 0.2, [500, 500], [5, 0], 0.0, 8),
[[464.204, 500.0], [19.812, 0.0], [15.984, 0.0]]),
('regression: high mobility',
(0.6, 0.25, [300, 900], [0, 9], 0.3, 6),
[[557.673, 559.801], [25.331, 25.533], [15.766, 15.895]]),
('regression: both seeded',
(0.3, 0.1, [800, 400], [4, 4], 0.1, 12),
[[565.74, 538.406], [32.741, 32.614], [15.262, 15.237]]),
('control: boundary zero days',
(0.5, 0.2, [100, 100], [1, 1], 0.1, 0),
[[99.0, 99.0], [1.0, 1.0], [0.0, 0.0]]),
('regression: equal patches',
(0.5, 0.2, [400, 400], [8, 0], 0.2, 5),
[[377.224, 380.426], [15.15, 13.039], [7.625, 6.535]]),
('regression: tiny second patch',
(0.7, 0.3, [2000, 50], [20, 0], 0.02, 9),
[[1241.271, 264.206], [242.617, 45.744], [216.332, 39.829]])],
[('regression: city and town',
(0.5, 0.2, [1000, 200], [10, 0], 0.05, 10),
[[611.99, 397.105], [74.874, 37.65], [52.607, 25.773]]),
('control: isolated patches',
(0.4, 0.2, [500, 500], [5, 0], 0.0, 8),
[[464.204, 500.0], [19.812, 0.0], [15.984, 0.0]]),
('regression: high mobility',
(0.6, 0.25, [300, 900], [0, 9], 0.3, 6),
[[557.673, 559.801], [25.331, 25.533], [15.766, 15.895]]),
('regression: both seeded',
(0.3, 0.1, [800, 400], [4, 4], 0.1, 12),
[[565.74, 538.406], [32.741, 32.614], [15.262, 15.237]]),
('control: boundary zero days',
(0.5, 0.2, [100, 100], [1, 1], 0.1, 0),
[[99.0, 99.0], [1.0, 1.0], [0.0, 0.0]]),
('regression: equal patches',
(0.5, 0.2, [400, 400], [8, 0], 0.2, 5),
[[377.224, 380.426], [15.15, 13.039], [7.625, 6.535]]),
('regression: tiny second patch',
(0.7, 0.3, [2000, 50], [20, 0], 0.02, 9),
[[1241.271, 264.206], [242.617, 45.744], [216.332, 39.829]])]]
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 fixture | Actual | Expected | Outcome |
|---|---|---|---|
| regression: city and town | [[609.949, 389.059], [74.517, 36.215], [52.35, 24.752]] | [[611.99, 397.105], [74.874, 37.65], [52.607, 25.773]] | Failed |
| control: isolated patches | [[464.204, 500.0], [19.812, 0.0], [15.984, 0.0]] | [[464.204, 500.0], [19.812, 0.0], [15.984, 0.0]] | Passed |
| regression: high mobility | [[600.353, 607.546], [29.366, 30.045], [18.337, 18.77]] | [[557.673, 559.801], [25.331, 25.533], [15.766, 15.895]] | Failed |
| regression: both seeded | [[558.307, 526.582], [32.705, 32.553], [15.255, 15.224]] | [[565.74, 538.406], [32.741, 32.614], [15.262, 15.237]] | Failed |
| control: boundary zero days | [[99.0, 99.0], [1.0, 1.0], [0.0, 0.0]] | [[99.0, 99.0], [1.0, 1.0], [0.0, 0.0]] | Passed |
| regression: equal patches | [[378.669, 383.111], [14.196, 11.262], [7.135, 5.627]] | [[377.224, 380.426], [15.15, 13.039], [7.625, 6.535]] | Failed |
| regression: tiny second patch | [[1240.935, 260.206], [242.549, 44.932], [216.271, 39.103]] | [[1241.271, 264.206], [242.617, 45.744], [216.332, 39.829]] | Failed |
SHA-256 / cbf3f5de93db34dc4b0461ed883369ef82b6a8af548fa1b7b86e55eb403bec27
2 / The unsuccessful fix
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
import math
N = 1
observations = []
def solve(beta, gamma, pops, i0s, travel, days):
s = [float(pops[k] - i0s[k]) for k in range(2)]
i = [float(x) for x in i0s]
r = [0.0, 0.0]
for _ in range(days):
n = [s[k] + i[k] + r[k] for k in range(2)]
inf = [beta * s[k] * i[k] / n[k] if n[k] > 0 else 0.0 for k in range(2)]
rec = [gamma * i[k] for k in range(2)]
for k in range(2):
s[k] -= inf[k]
i[k] += inf[k] - rec[k]
r[k] += rec[k]
for comp in (s, i, r):
a, b = comp[0] * travel, comp[1] * travel
comp[0] += b - a
comp[1] += a
return [[round(x, 3) for x in s], [round(x, 3) for x in i], [round(x, 3) for x in r]]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('regression: city and town',
(0.5, 0.2, [1000, 200], [10, 0], 0.05, 10),
[[611.99, 397.105], [74.874, 37.65], [52.607, 25.773]]),
('control: isolated patches',
(0.4, 0.2, [500, 500], [5, 0], 0.0, 8),
[[464.204, 500.0], [19.812, 0.0], [15.984, 0.0]]),
('regression: high mobility',
(0.6, 0.25, [300, 900], [0, 9], 0.3, 6),
[[557.673, 559.801], [25.331, 25.533], [15.766, 15.895]]),
('regression: both seeded',
(0.3, 0.1, [800, 400], [4, 4], 0.1, 12),
[[565.74, 538.406], [32.741, 32.614], [15.262, 15.237]]),
('control: boundary zero days',
(0.5, 0.2, [100, 100], [1, 1], 0.1, 0),
[[99.0, 99.0], [1.0, 1.0], [0.0, 0.0]]),
('regression: equal patches',
(0.5, 0.2, [400, 400], [8, 0], 0.2, 5),
[[377.224, 380.426], [15.15, 13.039], [7.625, 6.535]]),
('regression: tiny second patch',
(0.7, 0.3, [2000, 50], [20, 0], 0.02, 9),
[[1241.271, 264.206], [242.617, 45.744], [216.332, 39.829]])],
[('regression: city and town',
(0.5, 0.2, [1000, 200], [10, 0], 0.05, 10),
[[611.99, 397.105], [74.874, 37.65], [52.607, 25.773]]),
('control: isolated patches',
(0.4, 0.2, [500, 500], [5, 0], 0.0, 8),
[[464.204, 500.0], [19.812, 0.0], [15.984, 0.0]]),
('regression: high mobility',
(0.6, 0.25, [300, 900], [0, 9], 0.3, 6),
[[557.673, 559.801], [25.331, 25.533], [15.766, 15.895]]),
('regression: both seeded',
(0.3, 0.1, [800, 400], [4, 4], 0.1, 12),
[[565.74, 538.406], [32.741, 32.614], [15.262, 15.237]]),
('control: boundary zero days',
(0.5, 0.2, [100, 100], [1, 1], 0.1, 0),
[[99.0, 99.0], [1.0, 1.0], [0.0, 0.0]]),
('regression: equal patches',
(0.5, 0.2, [400, 400], [8, 0], 0.2, 5),
[[377.224, 380.426], [15.15, 13.039], [7.625, 6.535]]),
('regression: tiny second patch',
(0.7, 0.3, [2000, 50], [20, 0], 0.02, 9),
[[1241.271, 264.206], [242.617, 45.744], [216.332, 39.829]])],
[('regression: city and town',
(0.5, 0.2, [1000, 200], [10, 0], 0.05, 10),
[[611.99, 397.105], [74.874, 37.65], [52.607, 25.773]]),
('control: isolated patches',
(0.4, 0.2, [500, 500], [5, 0], 0.0, 8),
[[464.204, 500.0], [19.812, 0.0], [15.984, 0.0]]),
('regression: high mobility',
(0.6, 0.25, [300, 900], [0, 9], 0.3, 6),
[[557.673, 559.801], [25.331, 25.533], [15.766, 15.895]]),
('regression: both seeded',
(0.3, 0.1, [800, 400], [4, 4], 0.1, 12),
[[565.74, 538.406], [32.741, 32.614], [15.262, 15.237]]),
('control: boundary zero days',
(0.5, 0.2, [100, 100], [1, 1], 0.1, 0),
[[99.0, 99.0], [1.0, 1.0], [0.0, 0.0]]),
('regression: equal patches',
(0.5, 0.2, [400, 400], [8, 0], 0.2, 5),
[[377.224, 380.426], [15.15, 13.039], [7.625, 6.535]]),
('regression: tiny second patch',
(0.7, 0.3, [2000, 50], [20, 0], 0.02, 9),
[[1241.271, 264.206], [242.617, 45.744], [216.332, 39.829]])],
[('regression: city and town',
(0.5, 0.2, [1000, 200], [10, 0], 0.05, 10),
[[611.99, 397.105], [74.874, 37.65], [52.607, 25.773]]),
('control: isolated patches',
(0.4, 0.2, [500, 500], [5, 0], 0.0, 8),
[[464.204, 500.0], [19.812, 0.0], [15.984, 0.0]]),
('regression: high mobility',
(0.6, 0.25, [300, 900], [0, 9], 0.3, 6),
[[557.673, 559.801], [25.331, 25.533], [15.766, 15.895]]),
('regression: both seeded',
(0.3, 0.1, [800, 400], [4, 4], 0.1, 12),
[[565.74, 538.406], [32.741, 32.614], [15.262, 15.237]]),
('control: boundary zero days',
(0.5, 0.2, [100, 100], [1, 1], 0.1, 0),
[[99.0, 99.0], [1.0, 1.0], [0.0, 0.0]]),
('regression: equal patches',
(0.5, 0.2, [400, 400], [8, 0], 0.2, 5),
[[377.224, 380.426], [15.15, 13.039], [7.625, 6.535]]),
('regression: tiny second patch',
(0.7, 0.3, [2000, 50], [20, 0], 0.02, 9),
[[1241.271, 264.206], [242.617, 45.744], [216.332, 39.829]])],
[('regression: city and town',
(0.5, 0.2, [1000, 200], [10, 0], 0.05, 10),
[[611.99, 397.105], [74.874, 37.65], [52.607, 25.773]]),
('control: isolated patches',
(0.4, 0.2, [500, 500], [5, 0], 0.0, 8),
[[464.204, 500.0], [19.812, 0.0], [15.984, 0.0]]),
('regression: high mobility',
(0.6, 0.25, [300, 900], [0, 9], 0.3, 6),
[[557.673, 559.801], [25.331, 25.533], [15.766, 15.895]]),
('regression: both seeded',
(0.3, 0.1, [800, 400], [4, 4], 0.1, 12),
[[565.74, 538.406], [32.741, 32.614], [15.262, 15.237]]),
('control: boundary zero days',
(0.5, 0.2, [100, 100], [1, 1], 0.1, 0),
[[99.0, 99.0], [1.0, 1.0], [0.0, 0.0]]),
('regression: equal patches',
(0.5, 0.2, [400, 400], [8, 0], 0.2, 5),
[[377.224, 380.426], [15.15, 13.039], [7.625, 6.535]]),
('regression: tiny second patch',
(0.7, 0.3, [2000, 50], [20, 0], 0.02, 9),
[[1241.271, 264.206], [242.617, 45.744], [216.332, 39.829]])]]
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 fixture | Actual | Expected | Outcome |
|---|---|---|---|
| regression: city and town | [[638.763, 552.634], [76.423, 48.388], [53.574, 32.89]] | [[611.99, 397.105], [74.874, 37.65], [52.607, 25.773]] | Failed |
| control: isolated patches | [[464.204, 500.0], [19.812, 0.0], [15.984, 0.0]] | [[464.204, 500.0], [19.812, 0.0], [15.984, 0.0]] | Passed |
| regression: high mobility | [[1242.173, 2016.099], [62.297, 101.697], [38.942, 63.589]] | [[557.673, 559.801], [25.331, 25.533], [15.766, 15.895]] | Failed |
| regression: both seeded | [[797.005, 1185.958], [49.441, 77.246], [23.127, 36.223]] | [[565.74, 538.406], [32.741, 32.614], [15.262, 15.237]] | Failed |
| control: boundary zero days | [[99.0, 99.0], [1.0, 1.0], [0.0, 0.0]] | [[99.0, 99.0], [1.0, 1.0], [0.0, 0.0]] | Passed |
| regression: equal patches | [[508.656, 797.564], [16.895, 21.017], [8.466, 10.475]] | [[377.224, 380.426], [15.15, 13.039], [7.625, 6.535]] | Failed |
| regression: tiny second patch | [[1242.789, 291.335], [242.82, 49.833], [216.498, 43.292]] | [[1241.271, 264.206], [242.617, 45.744], [216.332, 39.829]] | Failed |
SHA-256 / 1df42afc7f559e1831015d49c157e7ed44585c75c7a8e2b251626dd49b76eba5
3 / The verified repair
Exit 0"""Failure Map reference implementation. Python standard library only."""
import json
import math
N = 1
observations = []
def solve(beta, gamma, pops, i0s, travel, days):
s = [float(pops[k] - i0s[k]) for k in range(2)]
i = [float(x) for x in i0s]
r = [0.0, 0.0]
for _ in range(days):
n = [s[k] + i[k] + r[k] for k in range(2)]
inf = [beta * s[k] * i[k] / n[k] if n[k] > 0 else 0.0 for k in range(2)]
rec = [gamma * i[k] for k in range(2)]
for k in range(2):
s[k] -= inf[k]
i[k] += inf[k] - rec[k]
r[k] += rec[k]
for comp in (s, i, r):
a, b = comp[0] * travel, comp[1] * travel
comp[0] += b - a
comp[1] += a - b
return [[round(x, 3) for x in s], [round(x, 3) for x in i], [round(x, 3) for x in r]]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('regression: city and town',
(0.5, 0.2, [1000, 200], [10, 0], 0.05, 10),
[[611.99, 397.105], [74.874, 37.65], [52.607, 25.773]]),
('control: isolated patches',
(0.4, 0.2, [500, 500], [5, 0], 0.0, 8),
[[464.204, 500.0], [19.812, 0.0], [15.984, 0.0]]),
('regression: high mobility',
(0.6, 0.25, [300, 900], [0, 9], 0.3, 6),
[[557.673, 559.801], [25.331, 25.533], [15.766, 15.895]]),
('regression: both seeded',
(0.3, 0.1, [800, 400], [4, 4], 0.1, 12),
[[565.74, 538.406], [32.741, 32.614], [15.262, 15.237]]),
('control: boundary zero days',
(0.5, 0.2, [100, 100], [1, 1], 0.1, 0),
[[99.0, 99.0], [1.0, 1.0], [0.0, 0.0]]),
('regression: equal patches',
(0.5, 0.2, [400, 400], [8, 0], 0.2, 5),
[[377.224, 380.426], [15.15, 13.039], [7.625, 6.535]]),
('regression: tiny second patch',
(0.7, 0.3, [2000, 50], [20, 0], 0.02, 9),
[[1241.271, 264.206], [242.617, 45.744], [216.332, 39.829]])],
[('regression: city and town',
(0.5, 0.2, [1000, 200], [10, 0], 0.05, 10),
[[611.99, 397.105], [74.874, 37.65], [52.607, 25.773]]),
('control: isolated patches',
(0.4, 0.2, [500, 500], [5, 0], 0.0, 8),
[[464.204, 500.0], [19.812, 0.0], [15.984, 0.0]]),
('regression: high mobility',
(0.6, 0.25, [300, 900], [0, 9], 0.3, 6),
[[557.673, 559.801], [25.331, 25.533], [15.766, 15.895]]),
('regression: both seeded',
(0.3, 0.1, [800, 400], [4, 4], 0.1, 12),
[[565.74, 538.406], [32.741, 32.614], [15.262, 15.237]]),
('control: boundary zero days',
(0.5, 0.2, [100, 100], [1, 1], 0.1, 0),
[[99.0, 99.0], [1.0, 1.0], [0.0, 0.0]]),
('regression: equal patches',
(0.5, 0.2, [400, 400], [8, 0], 0.2, 5),
[[377.224, 380.426], [15.15, 13.039], [7.625, 6.535]]),
('regression: tiny second patch',
(0.7, 0.3, [2000, 50], [20, 0], 0.02, 9),
[[1241.271, 264.206], [242.617, 45.744], [216.332, 39.829]])],
[('regression: city and town',
(0.5, 0.2, [1000, 200], [10, 0], 0.05, 10),
[[611.99, 397.105], [74.874, 37.65], [52.607, 25.773]]),
('control: isolated patches',
(0.4, 0.2, [500, 500], [5, 0], 0.0, 8),
[[464.204, 500.0], [19.812, 0.0], [15.984, 0.0]]),
('regression: high mobility',
(0.6, 0.25, [300, 900], [0, 9], 0.3, 6),
[[557.673, 559.801], [25.331, 25.533], [15.766, 15.895]]),
('regression: both seeded',
(0.3, 0.1, [800, 400], [4, 4], 0.1, 12),
[[565.74, 538.406], [32.741, 32.614], [15.262, 15.237]]),
('control: boundary zero days',
(0.5, 0.2, [100, 100], [1, 1], 0.1, 0),
[[99.0, 99.0], [1.0, 1.0], [0.0, 0.0]]),
('regression: equal patches',
(0.5, 0.2, [400, 400], [8, 0], 0.2, 5),
[[377.224, 380.426], [15.15, 13.039], [7.625, 6.535]]),
('regression: tiny second patch',
(0.7, 0.3, [2000, 50], [20, 0], 0.02, 9),
[[1241.271, 264.206], [242.617, 45.744], [216.332, 39.829]])],
[('regression: city and town',
(0.5, 0.2, [1000, 200], [10, 0], 0.05, 10),
[[611.99, 397.105], [74.874, 37.65], [52.607, 25.773]]),
('control: isolated patches',
(0.4, 0.2, [500, 500], [5, 0], 0.0, 8),
[[464.204, 500.0], [19.812, 0.0], [15.984, 0.0]]),
('regression: high mobility',
(0.6, 0.25, [300, 900], [0, 9], 0.3, 6),
[[557.673, 559.801], [25.331, 25.533], [15.766, 15.895]]),
('regression: both seeded',
(0.3, 0.1, [800, 400], [4, 4], 0.1, 12),
[[565.74, 538.406], [32.741, 32.614], [15.262, 15.237]]),
('control: boundary zero days',
(0.5, 0.2, [100, 100], [1, 1], 0.1, 0),
[[99.0, 99.0], [1.0, 1.0], [0.0, 0.0]]),
('regression: equal patches',
(0.5, 0.2, [400, 400], [8, 0], 0.2, 5),
[[377.224, 380.426], [15.15, 13.039], [7.625, 6.535]]),
('regression: tiny second patch',
(0.7, 0.3, [2000, 50], [20, 0], 0.02, 9),
[[1241.271, 264.206], [242.617, 45.744], [216.332, 39.829]])],
[('regression: city and town',
(0.5, 0.2, [1000, 200], [10, 0], 0.05, 10),
[[611.99, 397.105], [74.874, 37.65], [52.607, 25.773]]),
('control: isolated patches',
(0.4, 0.2, [500, 500], [5, 0], 0.0, 8),
[[464.204, 500.0], [19.812, 0.0], [15.984, 0.0]]),
('regression: high mobility',
(0.6, 0.25, [300, 900], [0, 9], 0.3, 6),
[[557.673, 559.801], [25.331, 25.533], [15.766, 15.895]]),
('regression: both seeded',
(0.3, 0.1, [800, 400], [4, 4], 0.1, 12),
[[565.74, 538.406], [32.741, 32.614], [15.262, 15.237]]),
('control: boundary zero days',
(0.5, 0.2, [100, 100], [1, 1], 0.1, 0),
[[99.0, 99.0], [1.0, 1.0], [0.0, 0.0]]),
('regression: equal patches',
(0.5, 0.2, [400, 400], [8, 0], 0.2, 5),
[[377.224, 380.426], [15.15, 13.039], [7.625, 6.535]]),
('regression: tiny second patch',
(0.7, 0.3, [2000, 50], [20, 0], 0.02, 9),
[[1241.271, 264.206], [242.617, 45.744], [216.332, 39.829]])]]
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 fixture | Actual | Expected | Outcome |
|---|---|---|---|
| regression: city and town | [[611.99, 397.105], [74.874, 37.65], [52.607, 25.773]] | [[611.99, 397.105], [74.874, 37.65], [52.607, 25.773]] | Passed |
| control: isolated patches | [[464.204, 500.0], [19.812, 0.0], [15.984, 0.0]] | [[464.204, 500.0], [19.812, 0.0], [15.984, 0.0]] | Passed |
| regression: high mobility | [[557.673, 559.801], [25.331, 25.533], [15.766, 15.895]] | [[557.673, 559.801], [25.331, 25.533], [15.766, 15.895]] | Passed |
| regression: both seeded | [[565.74, 538.406], [32.741, 32.614], [15.262, 15.237]] | [[565.74, 538.406], [32.741, 32.614], [15.262, 15.237]] | Passed |
| control: boundary zero days | [[99.0, 99.0], [1.0, 1.0], [0.0, 0.0]] | [[99.0, 99.0], [1.0, 1.0], [0.0, 0.0]] | Passed |
| regression: equal patches | [[377.224, 380.426], [15.15, 13.039], [7.625, 6.535]] | [[377.224, 380.426], [15.15, 13.039], [7.625, 6.535]] | Passed |
| regression: tiny second patch | [[1241.271, 264.206], [242.617, 45.744], [216.332, 39.829]] | [[1241.271, 264.206], [242.617, 45.744], [216.332, 39.829]] | Passed |
SHA-256 / ff3cdf895d98a7154256e91647ef57b387f795ea2105f8cb75fb2322caf37f15
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:32.681785+00:00.
Case digest / f4b43744712beb9a68a0a980de5849b8127f43f13a2558de4b5989f9df5b754a