FA-87321 / Physics integrator stability / Open access
Zero initial energy is scaled by a tiny epsilon · case 01
A system starting at rest reports astronomically large drift for any motion.
ROOT CAUSE
scale = max(e0, 1e-12).
VERIFIED REPAIR
Fall back to absolute drift (scale 1) when E0 is zero.
Unsuccessful approach: Adding one to E0 biases every relative measurement.
Case contract
solve(states, k, m, tol, blowup): states [[x,v],...] of a spring integrator; E=0.5 m v^2+0.5 k x^2. Relative drift r=|E-E0|/E0 (absolute when E0=0). Scan in order: first state with E>blowup*E0 (E0>0) returns ["blowup", index, its r]. Otherwise ["drift", first index with r>tol, max r] or ["ok", -1, max r].
Why this case matters
Game and robotics physics loops depend on integrator update order, step control and stabilization terms; a wrong decision point turns a stable simulation into drifting or exploding motion.
1 / The failure
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
import math
N = 1
observations = []
def solve(states, k, m, tol, blowup):
def en(s):
return 0.5 * m * s[1] * s[1] + 0.5 * k * s[0] * s[0]
e0 = en(states[0])
scale = max(e0, 1e-12)
worst = 0.0
first_drift = -1
for i, s in enumerate(states):
e = en(s)
if e0 > 0 and e > blowup * e0:
return ['blowup', i, round(abs(e - e0) / scale, 6)]
r = abs(e - e0) / scale
if r > worst:
worst = r
if r > tol and first_drift < 0:
first_drift = i
if first_drift >= 0:
return ['drift', first_drift, round(worst, 6)]
return ['ok', -1, round(worst, 6)]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[[[[[0.493, 0.31], [0.5123, 0.3162], [0.5233, 0.3225], [0.5391, 0.329], [0.5556, 0.3356]], 3.28, 0.666, 0.01, 1.5], ['drift', 1, 0.262788]], [[[[-0.321, 0.297], [-0.312, 0.297], [-0.3006, 0.297], [-0.2983, 0.297], [-0.2902, 0.297], [-0.2884, 0.297], [-0.2798, 0.297]], 4.843, 1.258, 0.01, 3.0], ['drift', 1, 0.196524]], [[[[0.0, 0.0], [0.0088, 0.0], [0.0184, 0.0], [0.0249, 0.0], [0.0337, 0.0], [0.0376, 0.0]], 4.601, 1.731, 0.01, 2.0], ['ok', -1, 0.003252]], [[[[0.477, 0.441], [0.5332, 0.4851], [0.587, 0.5336], [0.6484, 0.587], [0.7135, 0.6457], [0.8027, 0.7102], [0.9023, 0.7813], [0.9961, 0.8594]], 2.467, 1.129, 0.1, 1.5], ['blowup', 2, 0.500238]], [[[[0.865, 0.17], [0.8809, 0.17], [0.8942, 0.17], [0.8825, 0.17], [0.8875, 0.17]], 4.902, 1.518, 0.05, 2.0], ['drift', 2, 0.067843]], [[[[-0.87, 0.504], [-0.966, 0.5544], [-1.0758, 0.6098]], 1.889, 2.654, 0.01, 3.0], ['drift', 1, 0.508184]], [[[[0.0, 0.0], [0.0003, 0.0], [0.0028, 0.0]], 2.609, 1.21, 0.05, 2.0], ['ok', -1, 1e-05]], [[[[0.0, 0.0], [0.0033, 0.0], [0.0081, 0.0], [0.0083, 0.0], [0.0094, 0.0], [0.011, 0.0]], 4.869, 0.774, 0.01, 3.0], ['ok', -1, 0.000295]]], [[[[[0.0, 0.0], [0.0066, 0.0], [0.0158, 0.0], [0.0191, 0.0], [0.0228, 0.0], [0.023, 0.0]], 1.146, 1.18, 0.1, 1.5], ['ok', -1, 0.000303]], [[[[0.042, 0.553], [0.0478, 0.6083], [0.0589, 0.6691], [0.068, 0.736], [0.075, 0.8096], [0.0854, 0.8906], [0.1021, 0.9797], [0.1141, 1.0776], [0.129, 1.1854], [0.1496, 1.3039]], 4.629, 0.756, 0.05, 1.5], ['blowup', 3, 0.80035]], [[[[0.0, 0.0], [0.0048, 0.0], [0.0057, 0.0], [0.0079, 0.0], [0.0164, 0.0], [0.0238, 0.0], [0.0303, 0.0]], 2.704, 2.717, 0.05, 1.5], ['ok', -1, 0.001241]], [[[[-0.758, 0.799], [-0.7781, 0.815], [-0.7769, 0.8313], [-0.7869, 0.8479], [-0.7916, 0.8649], [-0.8053, 0.8822], [-0.8216, 0.8998]], 4.754, 2.008, 0.01, 1.5], ['drift', 1, 0.204677]], [[[[-0.306, -0.381], [-0.2757, -0.3429], [-0.2442, -0.3086], [-0.2172, -0.2777], [-0.1838, -0.25]], 4.213, 0.976, 0.05, 1.5], ['drift', 1, 0.620779]], [[[[0.0, 0.0], [0.004, 0.0], [0.0042, 0.0], [0.0053, 0.0], [0.0122, 0.0], [0.0206, 0.0]], 3.303, 2.508, 0.01, 1.5], ['ok', -1, 0.000701]], [[[[-0.894, -0.23], [-0.8548, -0.2231], [-0.8318, -0.2164]], 0.645, 1.279, 0.1, 3.0], ['drift', 2, 0.132042]], [[[[0.662, 0.589], [0.7231, 0.6479], [0.7925, 0.7127], [0.8677, 0.784], [0.9484, 0.8624], [1.0306, 0.9486]], 0.646, 2.733, 0.05, 1.5], ['blowup', 3, 0.759388]]], [[[[[0.161, 0.701], [0.177, 0.7711], [0.1998, 0.8482], [0.2203, 0.933], [0.2478, 1.0263], [0.2766, 1.129], [0.3101, 1.2419], [0.3431, 1.3661], [0.3873, 1.5027]], 4.831, 1.081, 0.05, 3.0], ['blowup', 6, 2.247575]], [[[[0.0, 0.0], [0.0071, 0.0], [0.0086, 0.0], [0.01, 0.0], [0.018, 0.0], [0.0265, 0.0], [0.0389, 0.0], [0.045, 0.0]], 0.98, 0.695, 0.01, 1.5], ['ok', -1, 0.000992]], [[[[0.0, 0.0], [0.0074, 0.0], [0.0076, 0.0], [0.0138, 0.0], [0.019, 0.0], [0.0234, 0.0]], 2.41, 1.708, 0.05, 2.0], ['ok', -1, 0.00066]], [[[[0.5, 0.768], [0.5589, 0.8448], [0.6268, 0.9293], [0.6862, 1.0222], [0.761, 1.1244], [0.8464, 1.2369], [0.948, 1.3606]], 1.574, 0.552, 0.1, 2.0], ['blowup', 4, 1.238152]], [[[[-0.005, 0.653], [-0.0025, 0.6334], [0.0024, 0.6144], [0.0104, 0.596], [0.011, 0.5781], [0.0162, 0.5608], [0.0226, 0.5439]], 4.817, 2.878, 0.05, 2.0], ['drift', 1, 0.304299]], [[[[-0.068, -0.749], [-0.0597, -0.764], [-0.0581, -0.7793]], 1.572, 1.363, 0.01, 2.0], ['drift', 1, 0.079225]], [[[[0.424, -0.518], [0.3855, -0.4662], [0.3514, -0.4196], [0.3157, -0.3776], [0.2873, -0.3399], [0.2561, -0.3059], [0.2353, -0.2753], [0.2146, -0.2478]], 3.595, 0.733, 0.05, 3.0], ['drift', 1, 0.750205]], [[[[0.0, 0.0], [0.0001, 0.0], [0.0078, 0.0], [0.0168, 0.0], [0.0187, 0.0], [0.0251, 0.0], [0.0345, 0.0], [0.0382, 0.0], [0.0451, 0.0], [0.05, 0.0]], 2.027, 0.528, 0.01, 3.0], ['ok', -1, 0.002534]]], [[[[[-0.057, -0.938], [-0.0508, -0.9099], [-0.0476, -0.8826], [-0.0384, -0.8561], [-0.0319, -0.8304], [-0.0282, -0.8055], [-0.0214, -0.7813], [-0.0139, -0.7579]], 1.511, 1.175, 0.05, 2.0], ['drift', 1, 0.349947]], [[[[-0.842, -0.267], [-0.9252, -0.2937], [-1.0242, -0.3231], [-1.1, -0.3554], [-1.2174, -0.3909]], 1.329, 0.961, 0.1, 2.0], ['blowup', 4, 1.094053]], [[[[0.391, -0.178], [0.4405, -0.1958], [0.4898, -0.2154], [0.5391, -0.2369], [0.6071, -0.2606], [0.6867, -0.2867], [0.7629, -0.3153], [0.8349, -0.3469]], 4.647, 2.014, 0.01, 3.0], ['blowup', 5, 2.044069]], [[[[-0.322, -0.896], [-0.3112, -0.8691], [-0.3041, -0.843], [-0.2959, -0.8178], [-0.2873, -0.7932], [-0.277, -0.7694], [-0.2571, -0.7463], [-0.2386, -0.724], [-0.2285, -0.7022], [-0.2117, -0.6812]], 3.185, 1.656, 0.05, 3.0], ['drift', 1, 0.450995]], [[[[0.0, 0.0], [0.0044, 0.0], [0.0106, 0.0], [0.0193, 0.0], [0.024, 0.0], [0.0241, 0.0], [0.03, 0.0], [0.0297, 0.0], [0.0363, 0.0]], 4.075, 1.166, 0.01, 2.0], ['ok', -1, 0.002685]], [[[[-0.431, -0.68], [-0.4341, -0.68], [-0.4283, -0.68]], 4.27, 1.291, 0.05, 3.0], ['ok', -1, 0.008237]], [[[[0.0, 0.0], [0.0056, 0.0], [0.0137, 0.0], [0.0234, 0.0], [0.0241, 0.0], [0.0298, 0.0], [0.0383, 0.0], [0.0446, 0.0], [0.0544, 0.0]], 1.23, 1.703, 0.05, 1.5], ['ok', -1, 0.00182]], [[[[0.0, 0.0], [0.0019, 0.0], [0.0053, 0.0], [0.0055, 0.0], [0.0091, 0.0]], 1.281, 2.065, 0.1, 2.0], ['ok', -1, 5.3e-05]]], [[[[[0.037, -0.064], [0.0453, -0.0704], [0.0527, -0.0774], [0.062, -0.0852]], 0.903, 1.942, 0.1, 3.0], ['drift', 1, 0.911531]], [[[[-0.097, -0.784], [-0.0875, -0.7605], [-0.0797, -0.7377], [-0.0737, -0.7155]], 2.42, 0.783, 0.1, 1.5], ['drift', 2, 0.178658]], [[[[0.0, 0.0], [0.0064, 0.0], [0.0094, 0.0], [0.0095, 0.0], [0.0153, 0.0], [0.014, 0.0], [0.02, 0.0], [0.0265, 0.0], [0.0314, 0.0], [0.0305, 0.0]], 3.651, 0.545, 0.05, 1.5], ['ok', -1, 0.0018]], [[[[0.089, 0.471], [0.0988, 0.5181], [0.1119, 0.5699], [0.1269, 0.6269]], 4.034, 1.802, 0.05, 1.5], ['blowup', 3, 0.790908]], [[[[0.0, 0.0], [0.0082, 0.0], [0.0165, 0.0], [0.017, 0.0], [0.0234, 0.0], [0.0239, 0.0]], 3.165, 1.885, 0.05, 2.0], ['ok', -1, 0.000904]], [[[[-0.223, -0.15], [-0.219, -0.15], [-0.21, -0.15]], 4.948, 2.31, 0.1, 2.0], ['ok', -1, 0.093453]], [[[[0.0, 0.0], [0.0055, 0.0], [0.0081, 0.0], [0.0095, 0.0], [0.0163, 0.0], [0.0203, 0.0], [0.0279, 0.0], [0.0288, 0.0], [0.0327, 0.0], [0.0328, 0.0]], 0.585, 2.269, 0.05, 1.5], ['ok', -1, 0.000315]], [[[[0.063, 0.62], [0.0704, 0.6324], [0.0763, 0.645], [0.0849, 0.6579], [0.089, 0.6711], [0.0943, 0.6845], [0.1044, 0.6982]], 0.574, 2.566, 0.01, 1.5], ['drift', 1, 0.271572]]]]
for i, (args, expected) in enumerate(fixtures[N-1]):
check("case %d" % i, 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 |
|---|---|---|---|
| case 0 | ['drift', 1, 0.262788] | ['drift', 1, 0.262788] | Passed |
| case 1 | ['drift', 1, 0.196524] | ['drift', 1, 0.196524] | Passed |
| case 2 | ['drift', 1, 3252354880.0] | ['ok', -1, 0.003252] | Failed |
| case 3 | ['blowup', 2, 0.500238] | ['blowup', 2, 0.500238] | Passed |
| case 4 | ['drift', 2, 0.067843] | ['drift', 2, 0.067843] | Passed |
| case 5 | ['drift', 1, 0.508184] | ['drift', 1, 0.508184] | Passed |
| case 6 | ['drift', 1, 10227280.0] | ['ok', -1, 1e-05] | Failed |
| case 7 | ['drift', 1, 294574500.0] | ['ok', -1, 0.000295] | Failed |
SHA-256 / e7cd41044f752191d679bf13f3060dbe225ea76eb2a6f4e0b9465f19111f96f2
2 / The unsuccessful fix
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
import math
N = 1
observations = []
def solve(states, k, m, tol, blowup):
def en(s):
return 0.5 * m * s[1] * s[1] + 0.5 * k * s[0] * s[0]
e0 = en(states[0])
scale = e0 + 1.0
worst = 0.0
first_drift = -1
for i, s in enumerate(states):
e = en(s)
if e0 > 0 and e > blowup * e0:
return ['blowup', i, round(abs(e - e0) / scale, 6)]
r = abs(e - e0) / scale
if r > worst:
worst = r
if r > tol and first_drift < 0:
first_drift = i
if first_drift >= 0:
return ['drift', first_drift, round(worst, 6)]
return ['ok', -1, round(worst, 6)]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[[[[[0.493, 0.31], [0.5123, 0.3162], [0.5233, 0.3225], [0.5391, 0.329], [0.5556, 0.3356]], 3.28, 0.666, 0.01, 1.5], ['drift', 1, 0.262788]], [[[[-0.321, 0.297], [-0.312, 0.297], [-0.3006, 0.297], [-0.2983, 0.297], [-0.2902, 0.297], [-0.2884, 0.297], [-0.2798, 0.297]], 4.843, 1.258, 0.01, 3.0], ['drift', 1, 0.196524]], [[[[0.0, 0.0], [0.0088, 0.0], [0.0184, 0.0], [0.0249, 0.0], [0.0337, 0.0], [0.0376, 0.0]], 4.601, 1.731, 0.01, 2.0], ['ok', -1, 0.003252]], [[[[0.477, 0.441], [0.5332, 0.4851], [0.587, 0.5336], [0.6484, 0.587], [0.7135, 0.6457], [0.8027, 0.7102], [0.9023, 0.7813], [0.9961, 0.8594]], 2.467, 1.129, 0.1, 1.5], ['blowup', 2, 0.500238]], [[[[0.865, 0.17], [0.8809, 0.17], [0.8942, 0.17], [0.8825, 0.17], [0.8875, 0.17]], 4.902, 1.518, 0.05, 2.0], ['drift', 2, 0.067843]], [[[[-0.87, 0.504], [-0.966, 0.5544], [-1.0758, 0.6098]], 1.889, 2.654, 0.01, 3.0], ['drift', 1, 0.508184]], [[[[0.0, 0.0], [0.0003, 0.0], [0.0028, 0.0]], 2.609, 1.21, 0.05, 2.0], ['ok', -1, 1e-05]], [[[[0.0, 0.0], [0.0033, 0.0], [0.0081, 0.0], [0.0083, 0.0], [0.0094, 0.0], [0.011, 0.0]], 4.869, 0.774, 0.01, 3.0], ['ok', -1, 0.000295]]], [[[[[0.0, 0.0], [0.0066, 0.0], [0.0158, 0.0], [0.0191, 0.0], [0.0228, 0.0], [0.023, 0.0]], 1.146, 1.18, 0.1, 1.5], ['ok', -1, 0.000303]], [[[[0.042, 0.553], [0.0478, 0.6083], [0.0589, 0.6691], [0.068, 0.736], [0.075, 0.8096], [0.0854, 0.8906], [0.1021, 0.9797], [0.1141, 1.0776], [0.129, 1.1854], [0.1496, 1.3039]], 4.629, 0.756, 0.05, 1.5], ['blowup', 3, 0.80035]], [[[[0.0, 0.0], [0.0048, 0.0], [0.0057, 0.0], [0.0079, 0.0], [0.0164, 0.0], [0.0238, 0.0], [0.0303, 0.0]], 2.704, 2.717, 0.05, 1.5], ['ok', -1, 0.001241]], [[[[-0.758, 0.799], [-0.7781, 0.815], [-0.7769, 0.8313], [-0.7869, 0.8479], [-0.7916, 0.8649], [-0.8053, 0.8822], [-0.8216, 0.8998]], 4.754, 2.008, 0.01, 1.5], ['drift', 1, 0.204677]], [[[[-0.306, -0.381], [-0.2757, -0.3429], [-0.2442, -0.3086], [-0.2172, -0.2777], [-0.1838, -0.25]], 4.213, 0.976, 0.05, 1.5], ['drift', 1, 0.620779]], [[[[0.0, 0.0], [0.004, 0.0], [0.0042, 0.0], [0.0053, 0.0], [0.0122, 0.0], [0.0206, 0.0]], 3.303, 2.508, 0.01, 1.5], ['ok', -1, 0.000701]], [[[[-0.894, -0.23], [-0.8548, -0.2231], [-0.8318, -0.2164]], 0.645, 1.279, 0.1, 3.0], ['drift', 2, 0.132042]], [[[[0.662, 0.589], [0.7231, 0.6479], [0.7925, 0.7127], [0.8677, 0.784], [0.9484, 0.8624], [1.0306, 0.9486]], 0.646, 2.733, 0.05, 1.5], ['blowup', 3, 0.759388]]], [[[[[0.161, 0.701], [0.177, 0.7711], [0.1998, 0.8482], [0.2203, 0.933], [0.2478, 1.0263], [0.2766, 1.129], [0.3101, 1.2419], [0.3431, 1.3661], [0.3873, 1.5027]], 4.831, 1.081, 0.05, 3.0], ['blowup', 6, 2.247575]], [[[[0.0, 0.0], [0.0071, 0.0], [0.0086, 0.0], [0.01, 0.0], [0.018, 0.0], [0.0265, 0.0], [0.0389, 0.0], [0.045, 0.0]], 0.98, 0.695, 0.01, 1.5], ['ok', -1, 0.000992]], [[[[0.0, 0.0], [0.0074, 0.0], [0.0076, 0.0], [0.0138, 0.0], [0.019, 0.0], [0.0234, 0.0]], 2.41, 1.708, 0.05, 2.0], ['ok', -1, 0.00066]], [[[[0.5, 0.768], [0.5589, 0.8448], [0.6268, 0.9293], [0.6862, 1.0222], [0.761, 1.1244], [0.8464, 1.2369], [0.948, 1.3606]], 1.574, 0.552, 0.1, 2.0], ['blowup', 4, 1.238152]], [[[[-0.005, 0.653], [-0.0025, 0.6334], [0.0024, 0.6144], [0.0104, 0.596], [0.011, 0.5781], [0.0162, 0.5608], [0.0226, 0.5439]], 4.817, 2.878, 0.05, 2.0], ['drift', 1, 0.304299]], [[[[-0.068, -0.749], [-0.0597, -0.764], [-0.0581, -0.7793]], 1.572, 1.363, 0.01, 2.0], ['drift', 1, 0.079225]], [[[[0.424, -0.518], [0.3855, -0.4662], [0.3514, -0.4196], [0.3157, -0.3776], [0.2873, -0.3399], [0.2561, -0.3059], [0.2353, -0.2753], [0.2146, -0.2478]], 3.595, 0.733, 0.05, 3.0], ['drift', 1, 0.750205]], [[[[0.0, 0.0], [0.0001, 0.0], [0.0078, 0.0], [0.0168, 0.0], [0.0187, 0.0], [0.0251, 0.0], [0.0345, 0.0], [0.0382, 0.0], [0.0451, 0.0], [0.05, 0.0]], 2.027, 0.528, 0.01, 3.0], ['ok', -1, 0.002534]]], [[[[[-0.057, -0.938], [-0.0508, -0.9099], [-0.0476, -0.8826], [-0.0384, -0.8561], [-0.0319, -0.8304], [-0.0282, -0.8055], [-0.0214, -0.7813], [-0.0139, -0.7579]], 1.511, 1.175, 0.05, 2.0], ['drift', 1, 0.349947]], [[[[-0.842, -0.267], [-0.9252, -0.2937], [-1.0242, -0.3231], [-1.1, -0.3554], [-1.2174, -0.3909]], 1.329, 0.961, 0.1, 2.0], ['blowup', 4, 1.094053]], [[[[0.391, -0.178], [0.4405, -0.1958], [0.4898, -0.2154], [0.5391, -0.2369], [0.6071, -0.2606], [0.6867, -0.2867], [0.7629, -0.3153], [0.8349, -0.3469]], 4.647, 2.014, 0.01, 3.0], ['blowup', 5, 2.044069]], [[[[-0.322, -0.896], [-0.3112, -0.8691], [-0.3041, -0.843], [-0.2959, -0.8178], [-0.2873, -0.7932], [-0.277, -0.7694], [-0.2571, -0.7463], [-0.2386, -0.724], [-0.2285, -0.7022], [-0.2117, -0.6812]], 3.185, 1.656, 0.05, 3.0], ['drift', 1, 0.450995]], [[[[0.0, 0.0], [0.0044, 0.0], [0.0106, 0.0], [0.0193, 0.0], [0.024, 0.0], [0.0241, 0.0], [0.03, 0.0], [0.0297, 0.0], [0.0363, 0.0]], 4.075, 1.166, 0.01, 2.0], ['ok', -1, 0.002685]], [[[[-0.431, -0.68], [-0.4341, -0.68], [-0.4283, -0.68]], 4.27, 1.291, 0.05, 3.0], ['ok', -1, 0.008237]], [[[[0.0, 0.0], [0.0056, 0.0], [0.0137, 0.0], [0.0234, 0.0], [0.0241, 0.0], [0.0298, 0.0], [0.0383, 0.0], [0.0446, 0.0], [0.0544, 0.0]], 1.23, 1.703, 0.05, 1.5], ['ok', -1, 0.00182]], [[[[0.0, 0.0], [0.0019, 0.0], [0.0053, 0.0], [0.0055, 0.0], [0.0091, 0.0]], 1.281, 2.065, 0.1, 2.0], ['ok', -1, 5.3e-05]]], [[[[[0.037, -0.064], [0.0453, -0.0704], [0.0527, -0.0774], [0.062, -0.0852]], 0.903, 1.942, 0.1, 3.0], ['drift', 1, 0.911531]], [[[[-0.097, -0.784], [-0.0875, -0.7605], [-0.0797, -0.7377], [-0.0737, -0.7155]], 2.42, 0.783, 0.1, 1.5], ['drift', 2, 0.178658]], [[[[0.0, 0.0], [0.0064, 0.0], [0.0094, 0.0], [0.0095, 0.0], [0.0153, 0.0], [0.014, 0.0], [0.02, 0.0], [0.0265, 0.0], [0.0314, 0.0], [0.0305, 0.0]], 3.651, 0.545, 0.05, 1.5], ['ok', -1, 0.0018]], [[[[0.089, 0.471], [0.0988, 0.5181], [0.1119, 0.5699], [0.1269, 0.6269]], 4.034, 1.802, 0.05, 1.5], ['blowup', 3, 0.790908]], [[[[0.0, 0.0], [0.0082, 0.0], [0.0165, 0.0], [0.017, 0.0], [0.0234, 0.0], [0.0239, 0.0]], 3.165, 1.885, 0.05, 2.0], ['ok', -1, 0.000904]], [[[[-0.223, -0.15], [-0.219, -0.15], [-0.21, -0.15]], 4.948, 2.31, 0.1, 2.0], ['ok', -1, 0.093453]], [[[[0.0, 0.0], [0.0055, 0.0], [0.0081, 0.0], [0.0095, 0.0], [0.0163, 0.0], [0.0203, 0.0], [0.0279, 0.0], [0.0288, 0.0], [0.0327, 0.0], [0.0328, 0.0]], 0.585, 2.269, 0.05, 1.5], ['ok', -1, 0.000315]], [[[[0.063, 0.62], [0.0704, 0.6324], [0.0763, 0.645], [0.0849, 0.6579], [0.089, 0.6711], [0.0943, 0.6845], [0.1044, 0.6982]], 0.574, 2.566, 0.01, 1.5], ['drift', 1, 0.271572]]]]
for i, (args, expected) in enumerate(fixtures[N-1]):
check("case %d" % i, 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 |
|---|---|---|---|
| case 0 | ['drift', 1, 0.079098] | ['drift', 1, 0.262788] | Failed |
| case 1 | ['drift', 1, 0.045931] | ['drift', 1, 0.196524] | Failed |
| case 2 | ['ok', -1, 0.003252] | ['ok', -1, 0.003252] | Passed |
| case 3 | ['blowup', 2, 0.140469] | ['blowup', 2, 0.500238] | Failed |
| case 4 | ['ok', -1, 0.044087] | ['drift', 2, 0.067843] | Failed |
| case 5 | ['drift', 1, 0.260527] | ['drift', 1, 0.508184] | Failed |
| case 6 | ['ok', -1, 1e-05] | ['ok', -1, 1e-05] | Passed |
| case 7 | ['ok', -1, 0.000295] | ['ok', -1, 0.000295] | Passed |
SHA-256 / 46843250f3a9729df3e33796897d5bb877bd734faecede546b84c69b9a2661b3
3 / The verified repair
Exit 0"""Failure Map reference implementation. Python standard library only."""
import json
import math
N = 1
observations = []
def solve(states, k, m, tol, blowup):
def en(s):
return 0.5 * m * s[1] * s[1] + 0.5 * k * s[0] * s[0]
e0 = en(states[0])
scale = e0 if e0 > 0 else 1.0
worst = 0.0
first_drift = -1
for i, s in enumerate(states):
e = en(s)
if e0 > 0 and e > blowup * e0:
return ['blowup', i, round(abs(e - e0) / scale, 6)]
r = abs(e - e0) / scale
if r > worst:
worst = r
if r > tol and first_drift < 0:
first_drift = i
if first_drift >= 0:
return ['drift', first_drift, round(worst, 6)]
return ['ok', -1, round(worst, 6)]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[[[[[0.493, 0.31], [0.5123, 0.3162], [0.5233, 0.3225], [0.5391, 0.329], [0.5556, 0.3356]], 3.28, 0.666, 0.01, 1.5], ['drift', 1, 0.262788]], [[[[-0.321, 0.297], [-0.312, 0.297], [-0.3006, 0.297], [-0.2983, 0.297], [-0.2902, 0.297], [-0.2884, 0.297], [-0.2798, 0.297]], 4.843, 1.258, 0.01, 3.0], ['drift', 1, 0.196524]], [[[[0.0, 0.0], [0.0088, 0.0], [0.0184, 0.0], [0.0249, 0.0], [0.0337, 0.0], [0.0376, 0.0]], 4.601, 1.731, 0.01, 2.0], ['ok', -1, 0.003252]], [[[[0.477, 0.441], [0.5332, 0.4851], [0.587, 0.5336], [0.6484, 0.587], [0.7135, 0.6457], [0.8027, 0.7102], [0.9023, 0.7813], [0.9961, 0.8594]], 2.467, 1.129, 0.1, 1.5], ['blowup', 2, 0.500238]], [[[[0.865, 0.17], [0.8809, 0.17], [0.8942, 0.17], [0.8825, 0.17], [0.8875, 0.17]], 4.902, 1.518, 0.05, 2.0], ['drift', 2, 0.067843]], [[[[-0.87, 0.504], [-0.966, 0.5544], [-1.0758, 0.6098]], 1.889, 2.654, 0.01, 3.0], ['drift', 1, 0.508184]], [[[[0.0, 0.0], [0.0003, 0.0], [0.0028, 0.0]], 2.609, 1.21, 0.05, 2.0], ['ok', -1, 1e-05]], [[[[0.0, 0.0], [0.0033, 0.0], [0.0081, 0.0], [0.0083, 0.0], [0.0094, 0.0], [0.011, 0.0]], 4.869, 0.774, 0.01, 3.0], ['ok', -1, 0.000295]]], [[[[[0.0, 0.0], [0.0066, 0.0], [0.0158, 0.0], [0.0191, 0.0], [0.0228, 0.0], [0.023, 0.0]], 1.146, 1.18, 0.1, 1.5], ['ok', -1, 0.000303]], [[[[0.042, 0.553], [0.0478, 0.6083], [0.0589, 0.6691], [0.068, 0.736], [0.075, 0.8096], [0.0854, 0.8906], [0.1021, 0.9797], [0.1141, 1.0776], [0.129, 1.1854], [0.1496, 1.3039]], 4.629, 0.756, 0.05, 1.5], ['blowup', 3, 0.80035]], [[[[0.0, 0.0], [0.0048, 0.0], [0.0057, 0.0], [0.0079, 0.0], [0.0164, 0.0], [0.0238, 0.0], [0.0303, 0.0]], 2.704, 2.717, 0.05, 1.5], ['ok', -1, 0.001241]], [[[[-0.758, 0.799], [-0.7781, 0.815], [-0.7769, 0.8313], [-0.7869, 0.8479], [-0.7916, 0.8649], [-0.8053, 0.8822], [-0.8216, 0.8998]], 4.754, 2.008, 0.01, 1.5], ['drift', 1, 0.204677]], [[[[-0.306, -0.381], [-0.2757, -0.3429], [-0.2442, -0.3086], [-0.2172, -0.2777], [-0.1838, -0.25]], 4.213, 0.976, 0.05, 1.5], ['drift', 1, 0.620779]], [[[[0.0, 0.0], [0.004, 0.0], [0.0042, 0.0], [0.0053, 0.0], [0.0122, 0.0], [0.0206, 0.0]], 3.303, 2.508, 0.01, 1.5], ['ok', -1, 0.000701]], [[[[-0.894, -0.23], [-0.8548, -0.2231], [-0.8318, -0.2164]], 0.645, 1.279, 0.1, 3.0], ['drift', 2, 0.132042]], [[[[0.662, 0.589], [0.7231, 0.6479], [0.7925, 0.7127], [0.8677, 0.784], [0.9484, 0.8624], [1.0306, 0.9486]], 0.646, 2.733, 0.05, 1.5], ['blowup', 3, 0.759388]]], [[[[[0.161, 0.701], [0.177, 0.7711], [0.1998, 0.8482], [0.2203, 0.933], [0.2478, 1.0263], [0.2766, 1.129], [0.3101, 1.2419], [0.3431, 1.3661], [0.3873, 1.5027]], 4.831, 1.081, 0.05, 3.0], ['blowup', 6, 2.247575]], [[[[0.0, 0.0], [0.0071, 0.0], [0.0086, 0.0], [0.01, 0.0], [0.018, 0.0], [0.0265, 0.0], [0.0389, 0.0], [0.045, 0.0]], 0.98, 0.695, 0.01, 1.5], ['ok', -1, 0.000992]], [[[[0.0, 0.0], [0.0074, 0.0], [0.0076, 0.0], [0.0138, 0.0], [0.019, 0.0], [0.0234, 0.0]], 2.41, 1.708, 0.05, 2.0], ['ok', -1, 0.00066]], [[[[0.5, 0.768], [0.5589, 0.8448], [0.6268, 0.9293], [0.6862, 1.0222], [0.761, 1.1244], [0.8464, 1.2369], [0.948, 1.3606]], 1.574, 0.552, 0.1, 2.0], ['blowup', 4, 1.238152]], [[[[-0.005, 0.653], [-0.0025, 0.6334], [0.0024, 0.6144], [0.0104, 0.596], [0.011, 0.5781], [0.0162, 0.5608], [0.0226, 0.5439]], 4.817, 2.878, 0.05, 2.0], ['drift', 1, 0.304299]], [[[[-0.068, -0.749], [-0.0597, -0.764], [-0.0581, -0.7793]], 1.572, 1.363, 0.01, 2.0], ['drift', 1, 0.079225]], [[[[0.424, -0.518], [0.3855, -0.4662], [0.3514, -0.4196], [0.3157, -0.3776], [0.2873, -0.3399], [0.2561, -0.3059], [0.2353, -0.2753], [0.2146, -0.2478]], 3.595, 0.733, 0.05, 3.0], ['drift', 1, 0.750205]], [[[[0.0, 0.0], [0.0001, 0.0], [0.0078, 0.0], [0.0168, 0.0], [0.0187, 0.0], [0.0251, 0.0], [0.0345, 0.0], [0.0382, 0.0], [0.0451, 0.0], [0.05, 0.0]], 2.027, 0.528, 0.01, 3.0], ['ok', -1, 0.002534]]], [[[[[-0.057, -0.938], [-0.0508, -0.9099], [-0.0476, -0.8826], [-0.0384, -0.8561], [-0.0319, -0.8304], [-0.0282, -0.8055], [-0.0214, -0.7813], [-0.0139, -0.7579]], 1.511, 1.175, 0.05, 2.0], ['drift', 1, 0.349947]], [[[[-0.842, -0.267], [-0.9252, -0.2937], [-1.0242, -0.3231], [-1.1, -0.3554], [-1.2174, -0.3909]], 1.329, 0.961, 0.1, 2.0], ['blowup', 4, 1.094053]], [[[[0.391, -0.178], [0.4405, -0.1958], [0.4898, -0.2154], [0.5391, -0.2369], [0.6071, -0.2606], [0.6867, -0.2867], [0.7629, -0.3153], [0.8349, -0.3469]], 4.647, 2.014, 0.01, 3.0], ['blowup', 5, 2.044069]], [[[[-0.322, -0.896], [-0.3112, -0.8691], [-0.3041, -0.843], [-0.2959, -0.8178], [-0.2873, -0.7932], [-0.277, -0.7694], [-0.2571, -0.7463], [-0.2386, -0.724], [-0.2285, -0.7022], [-0.2117, -0.6812]], 3.185, 1.656, 0.05, 3.0], ['drift', 1, 0.450995]], [[[[0.0, 0.0], [0.0044, 0.0], [0.0106, 0.0], [0.0193, 0.0], [0.024, 0.0], [0.0241, 0.0], [0.03, 0.0], [0.0297, 0.0], [0.0363, 0.0]], 4.075, 1.166, 0.01, 2.0], ['ok', -1, 0.002685]], [[[[-0.431, -0.68], [-0.4341, -0.68], [-0.4283, -0.68]], 4.27, 1.291, 0.05, 3.0], ['ok', -1, 0.008237]], [[[[0.0, 0.0], [0.0056, 0.0], [0.0137, 0.0], [0.0234, 0.0], [0.0241, 0.0], [0.0298, 0.0], [0.0383, 0.0], [0.0446, 0.0], [0.0544, 0.0]], 1.23, 1.703, 0.05, 1.5], ['ok', -1, 0.00182]], [[[[0.0, 0.0], [0.0019, 0.0], [0.0053, 0.0], [0.0055, 0.0], [0.0091, 0.0]], 1.281, 2.065, 0.1, 2.0], ['ok', -1, 5.3e-05]]], [[[[[0.037, -0.064], [0.0453, -0.0704], [0.0527, -0.0774], [0.062, -0.0852]], 0.903, 1.942, 0.1, 3.0], ['drift', 1, 0.911531]], [[[[-0.097, -0.784], [-0.0875, -0.7605], [-0.0797, -0.7377], [-0.0737, -0.7155]], 2.42, 0.783, 0.1, 1.5], ['drift', 2, 0.178658]], [[[[0.0, 0.0], [0.0064, 0.0], [0.0094, 0.0], [0.0095, 0.0], [0.0153, 0.0], [0.014, 0.0], [0.02, 0.0], [0.0265, 0.0], [0.0314, 0.0], [0.0305, 0.0]], 3.651, 0.545, 0.05, 1.5], ['ok', -1, 0.0018]], [[[[0.089, 0.471], [0.0988, 0.5181], [0.1119, 0.5699], [0.1269, 0.6269]], 4.034, 1.802, 0.05, 1.5], ['blowup', 3, 0.790908]], [[[[0.0, 0.0], [0.0082, 0.0], [0.0165, 0.0], [0.017, 0.0], [0.0234, 0.0], [0.0239, 0.0]], 3.165, 1.885, 0.05, 2.0], ['ok', -1, 0.000904]], [[[[-0.223, -0.15], [-0.219, -0.15], [-0.21, -0.15]], 4.948, 2.31, 0.1, 2.0], ['ok', -1, 0.093453]], [[[[0.0, 0.0], [0.0055, 0.0], [0.0081, 0.0], [0.0095, 0.0], [0.0163, 0.0], [0.0203, 0.0], [0.0279, 0.0], [0.0288, 0.0], [0.0327, 0.0], [0.0328, 0.0]], 0.585, 2.269, 0.05, 1.5], ['ok', -1, 0.000315]], [[[[0.063, 0.62], [0.0704, 0.6324], [0.0763, 0.645], [0.0849, 0.6579], [0.089, 0.6711], [0.0943, 0.6845], [0.1044, 0.6982]], 0.574, 2.566, 0.01, 1.5], ['drift', 1, 0.271572]]]]
for i, (args, expected) in enumerate(fixtures[N-1]):
check("case %d" % i, 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 |
|---|---|---|---|
| case 0 | ['drift', 1, 0.262788] | ['drift', 1, 0.262788] | Passed |
| case 1 | ['drift', 1, 0.196524] | ['drift', 1, 0.196524] | Passed |
| case 2 | ['ok', -1, 0.003252] | ['ok', -1, 0.003252] | Passed |
| case 3 | ['blowup', 2, 0.500238] | ['blowup', 2, 0.500238] | Passed |
| case 4 | ['drift', 2, 0.067843] | ['drift', 2, 0.067843] | Passed |
| case 5 | ['drift', 1, 0.508184] | ['drift', 1, 0.508184] | Passed |
| case 6 | ['ok', -1, 1e-05] | ['ok', -1, 1e-05] | Passed |
| case 7 | ['ok', -1, 0.000295] | ['ok', -1, 0.000295] | Passed |
SHA-256 / 26674010e076f6b0a7a0b8915861b3675d24ae7b93e5b8216e8141a8db0f51a5
Verification & scope
A deterministic bounded teaching model with stipulated toy conventions and rounded float output; not a production physics engine or a proof of numerical stability. 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:50:57.714585+00:00.
Case digest / bf304fbbdc62156f971eb4b68bd0a0af7211d8966b8dd0c2579e42e7cea031b9