FAILURE MAP
← Case archive

FA-87331 / Physics integrator stability / Open access

Blowup factor is applied to the deviation rather than the energy · case 01

Explosions are detected one multiple of E0 too late.

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

ROOT CAUSE

The test is |E-E0| > blowup*E0.

VERIFIED REPAIR

Blow-up means E > blowup*E0.

Unsuccessful approach: Adding blowup to E0 mixes a factor with an energy.

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 = 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 abs(e - e0) > 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.87, 0.504], [-0.966, 0.5544], [-1.0758, 0.6098]], 1.889, 2.654, 0.01, 3.0], ['drift', 1, 0.508184]], [[[[-0.525, 0.127], [-0.5659, 0.1397], [-0.6321, 0.1537], [-0.6779, 0.169], [-0.7373, 0.1859], [-0.7883, 0.2045], [-0.8602, 0.225], [-0.9508, 0.2475], [-1.0348, 0.2722], [-1.13, 0.2995]], 4.571, 2.689, 0.1, 2.0], ['blowup', 5, 1.265832]], [[[[0.0, 0.0], [0.0023, 0.0], [0.008, 0.0], [0.0167, 0.0], [0.0239, 0.0]], 1.47, 2.583, 0.01, 2.0], ['ok', -1, 0.00042]], [[[[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.123, -0.843], [0.1274, -0.8177], [0.1304, -0.7932], [0.1322, -0.7694], [0.1354, -0.7463], [0.134, -0.7239], [0.1321, -0.7022], [0.1293, -0.6811]], 1.099, 1.464, 0.05, 2.0], ['drift', 1, 0.340106]], [[[[0.4, 0.057], [0.4385, 0.0627], [0.4824, 0.069], [0.5288, 0.0759], [0.5815, 0.0835], [0.6441, 0.0918], [0.7184, 0.101]], 4.732, 2.286, 0.05, 3.0], ['blowup', 6, 2.224782]], [[[[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.099, 0.306], [0.1145, 0.3366], [0.1305, 0.3703], [0.1459, 0.4073], [0.163, 0.448], [0.1873, 0.4928], [0.2145, 0.5421], [0.2438, 0.5963]], 4.583, 1.183, 0.05, 2.0], ['blowup', 4, 1.307149]]], [[[[[0.303, 0.246], [0.3325, 0.2706], [0.3676, 0.2977], [0.4034, 0.3274], [0.4447, 0.3602], [0.5066, 0.3962]], 0.771, 1.949, 0.05, 2.0], ['blowup', 4, 1.147733]], [[[[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.502, 0.885], [-0.4863, 0.8584], [-0.4555, 0.8327]], 2.684, 1.206, 0.05, 2.0], ['drift', 1, 0.140562]], [[[[-0.603, -0.678], [-0.6577, -0.7458], [-0.7284, -0.8204], [-0.7972, -0.9024], [-0.8767, -0.9927]], 0.53, 2.104, 0.05, 2.0], ['blowup', 4, 1.138787]], [[[[-0.1, 0.784], [-0.0885, 0.7056], [-0.0797, 0.635], [-0.0691, 0.5715], [-0.0592, 0.5144], [-0.0465, 0.4629], [-0.038, 0.4166], [-0.0274, 0.375], [-0.0209, 0.3375]], 1.117, 1.509, 0.1, 2.0], ['drift', 1, 0.816368]], [[[[-0.219, 0.241], [-0.2354, 0.2651], [-0.2595, 0.2916], [-0.2794, 0.3208], [-0.2964, 0.3528], [-0.3284, 0.3881], [-0.3564, 0.4269]], 0.937, 2.683, 0.1, 3.0], ['blowup', 6, 2.028221]], [[[[0.506, 0.106], [0.56, 0.1166], [0.6216, 0.1283]], 1.94, 1.02, 0.1, 1.5], ['blowup', 2, 0.508116]], [[[[0.59, 0.017], [0.6553, 0.0187], [0.7314, 0.0206], [0.8089, 0.0226]], 1.97, 2.3, 0.01, 1.5], ['blowup', 2, 0.536693]]], [[[[[0.0, 0.0], [0.0014, 0.0], [0.0084, 0.0], [0.011, 0.0], [0.0111, 0.0], [0.0128, 0.0], [0.0135, 0.0], [0.0196, 0.0], [0.02, 0.0], [0.0228, 0.0]], 3.696, 2.035, 0.05, 3.0], ['ok', -1, 0.000961]], [[[[0.056, 0.464], [0.059, 0.4733], [0.0698, 0.4827], [0.0778, 0.4924], [0.0816, 0.5022], [0.0858, 0.5123], [0.0935, 0.5225], [0.0998, 0.533], [0.1033, 0.5436]], 4.406, 0.942, 0.1, 1.5], ['blowup', 8, 0.502025]], [[[[0.515, 0.325], [0.5708, 0.3575], [0.6313, 0.3933], [0.7076, 0.4326]], 1.69, 2.495, 0.1, 1.5], ['blowup', 3, 0.844852]], [[[[0.494, 0.726], [0.4862, 0.7042], [0.4712, 0.6831], [0.4542, 0.6626]], 4.432, 1.484, 0.1, 1.5], ['drift', 2, 0.159841]], [[[[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.091, 0.126], [-0.0974, 0.1386], [-0.1056, 0.1525], [-0.109, 0.1677], [-0.1141, 0.1845]], 3.918, 1.984, 0.01, 1.5], ['blowup', 3, 0.600589]], [[[[-0.658, -0.73], [-0.6294, -0.7081], [-0.602, -0.6869], [-0.5702, -0.6663], [-0.5488, -0.6463], [-0.5258, -0.6269], [-0.5064, -0.6081]], 3.265, 1.032, 0.1, 3.0], ['drift', 2, 0.379247]], [[[[-0.705, 0.668], [-0.6267, 0.6012], [-0.5657, 0.5411], [-0.506, 0.487]], 1.47, 0.964, 0.1, 1.5], ['drift', 1, 0.478798]]], [[[[[0.334, 0.023], [0.3729, 0.0253], [0.4088, 0.0278], [0.4434, 0.0306], [0.4927, 0.0337], [0.544, 0.037], [0.5905, 0.0407]], 0.518, 1.765, 0.1, 2.0], ['blowup', 4, 1.175602]], [[[[-0.926, -0.589], [-1.0206, -0.6479], [-1.1345, -0.7127], [-1.2337, -0.784], [-1.3724, -0.8624], [-1.5174, -0.9486], [-1.681, -1.0434], [-1.8301, -1.1478]], 4.721, 0.832, 0.1, 1.5], ['blowup', 3, 0.774779]], [[[[0.586, -0.551], [0.5421, -0.4959], [0.4949, -0.4463], [0.4451, -0.4017], [0.405, -0.3615], [0.3696, -0.3254], [0.3317, -0.2928]], 3.218, 1.406, 0.01, 3.0], ['drift', 1, 0.690192]], [[[[0.157, -0.869], [0.1454, -0.7821], [0.1394, -0.7039]], 3.306, 2.61, 0.05, 2.0], ['drift', 1, 0.338631]], [[[[0.538, -0.735], [0.544, -0.735], [0.548, -0.735], [0.5601, -0.735], [0.5638, -0.735], [0.5724, -0.735], [0.5687, -0.735]], 3.032, 1.382, 0.1, 2.0], ['ok', -1, 0.071307]], [[[[0.785, 0.863], [0.8832, 0.9493], [0.9792, 1.0442], [1.0583, 1.1487], [1.1525, 1.2635], [1.2718, 1.3899], [1.406, 1.5289], [1.536, 1.6817], [1.6868, 1.8499], [1.8906, 2.0349]], 2.411, 1.758, 0.05, 2.0], ['blowup', 4, 1.149877]], [[[[0.607, 0.468], [0.6659, 0.5148], [0.7371, 0.5663], [0.8121, 0.6229], [0.8833, 0.6852], [0.9551, 0.7537], [1.0629, 0.8291], [1.1762, 0.912], [1.2767, 1.0032]], 3.454, 2.778, 0.1, 2.0], ['blowup', 4, 1.125993]], [[[[-0.536, -0.266], [-0.571, -0.2926], [-0.6311, -0.3219], [-0.6867, -0.354], [-0.7515, -0.3895], [-0.8208, -0.4284], [-0.892, -0.4712], [-0.9733, -0.5184], [-1.0789, -0.5702], [-1.2044, -0.6272]], 0.869, 1.94, 0.01, 3.0], ['blowup', 7, 2.474992]]], [[[[[-0.158, 0.273], [-0.1584, 0.2785], [-0.155, 0.284], [-0.1529, 0.2897], [-0.1492, 0.2955], [-0.1509, 0.3014], [-0.1437, 0.3074]], 3.45, 0.863, 0.1, 3.0], ['ok', -1, 0.043282]], [[[[-0.648, -0.612], [-0.7038, -0.6732], [-0.766, -0.7405], [-0.8245, -0.8146], [-0.9148, -0.896], [-1.0192, -0.9856], [-1.1118, -1.0842], [-1.2153, -1.1926]], 1.534, 1.581, 0.1, 3.0], ['blowup', 6, 2.037018]], [[[[0.355, -0.075], [0.3414, -0.0727], [0.3418, -0.0706], [0.3422, -0.0685], [0.3388, -0.0664]], 4.633, 0.948, 0.05, 1.5], ['drift', 1, 0.090335]], [[[[0.599, -0.265], [0.6726, -0.2915], [0.7436, -0.3207], [0.8129, -0.3527], [0.9144, -0.388], [1.0101, -0.4268], [1.1116, -0.4695], [1.2193, -0.5164]], 2.659, 2.064, 0.01, 3.0], ['blowup', 6, 2.403627]], [[[[0.174, -0.48], [0.1771, -0.4896], [0.1863, -0.4994], [0.1987, -0.5094], [0.2011, -0.5196]], 1.179, 1.294, 0.01, 1.5], ['drift', 1, 0.189336]], [[[[-0.924, -0.704], [-1.0228, -0.7744], [-1.1142, -0.8518], [-1.2121, -0.937], [-1.3027, -1.0307]], 2.196, 1.673, 0.05, 1.5], ['blowup', 3, 0.736344]], [[[[0.313, -0.637], [0.2866, -0.5733], [0.2588, -0.516], [0.2373, -0.4644], [0.2157, -0.4179], [0.1948, -0.3761], [0.1756, -0.3385], [0.1616, -0.3047]], 0.961, 2.937, 0.01, 2.0], ['drift', 1, 0.768431]], [[[[-0.261, -0.067], [-0.2815, -0.0737], [-0.2986, -0.0811], [-0.3218, -0.0892], [-0.3475, -0.0981], [-0.3727, -0.1079], [-0.3969, -0.1187], [-0.4396, -0.1306]], 0.593, 2.153, 0.01, 2.0], ['blowup', 5, 1.146139]]]]
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 fixtureActualExpectedOutcome
case 0['drift', 1, 0.508184]['drift', 1, 0.508184]Passed
case 1['blowup', 7, 2.297132]['blowup', 5, 1.265832]Failed
case 2['ok', -1, 0.00042]['ok', -1, 0.00042]Passed
case 3['blowup', 5, 1.764825]['blowup', 2, 0.500238]Failed
case 4['drift', 1, 0.340106]['drift', 1, 0.340106]Passed
case 5['drift', 1, 2.224782]['blowup', 6, 2.224782]Failed
case 6['drift', 1, 0.262788]['drift', 1, 0.262788]Passed
case 7['blowup', 6, 2.587374]['blowup', 4, 1.307149]Failed

SHA-256 / 912294ac4b9a8ce0b502ea0f53b87b3a1b2d7d50f78e990b0d453394806d18ed

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 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.87, 0.504], [-0.966, 0.5544], [-1.0758, 0.6098]], 1.889, 2.654, 0.01, 3.0], ['drift', 1, 0.508184]], [[[[-0.525, 0.127], [-0.5659, 0.1397], [-0.6321, 0.1537], [-0.6779, 0.169], [-0.7373, 0.1859], [-0.7883, 0.2045], [-0.8602, 0.225], [-0.9508, 0.2475], [-1.0348, 0.2722], [-1.13, 0.2995]], 4.571, 2.689, 0.1, 2.0], ['blowup', 5, 1.265832]], [[[[0.0, 0.0], [0.0023, 0.0], [0.008, 0.0], [0.0167, 0.0], [0.0239, 0.0]], 1.47, 2.583, 0.01, 2.0], ['ok', -1, 0.00042]], [[[[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.123, -0.843], [0.1274, -0.8177], [0.1304, -0.7932], [0.1322, -0.7694], [0.1354, -0.7463], [0.134, -0.7239], [0.1321, -0.7022], [0.1293, -0.6811]], 1.099, 1.464, 0.05, 2.0], ['drift', 1, 0.340106]], [[[[0.4, 0.057], [0.4385, 0.0627], [0.4824, 0.069], [0.5288, 0.0759], [0.5815, 0.0835], [0.6441, 0.0918], [0.7184, 0.101]], 4.732, 2.286, 0.05, 3.0], ['blowup', 6, 2.224782]], [[[[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.099, 0.306], [0.1145, 0.3366], [0.1305, 0.3703], [0.1459, 0.4073], [0.163, 0.448], [0.1873, 0.4928], [0.2145, 0.5421], [0.2438, 0.5963]], 4.583, 1.183, 0.05, 2.0], ['blowup', 4, 1.307149]]], [[[[[0.303, 0.246], [0.3325, 0.2706], [0.3676, 0.2977], [0.4034, 0.3274], [0.4447, 0.3602], [0.5066, 0.3962]], 0.771, 1.949, 0.05, 2.0], ['blowup', 4, 1.147733]], [[[[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.502, 0.885], [-0.4863, 0.8584], [-0.4555, 0.8327]], 2.684, 1.206, 0.05, 2.0], ['drift', 1, 0.140562]], [[[[-0.603, -0.678], [-0.6577, -0.7458], [-0.7284, -0.8204], [-0.7972, -0.9024], [-0.8767, -0.9927]], 0.53, 2.104, 0.05, 2.0], ['blowup', 4, 1.138787]], [[[[-0.1, 0.784], [-0.0885, 0.7056], [-0.0797, 0.635], [-0.0691, 0.5715], [-0.0592, 0.5144], [-0.0465, 0.4629], [-0.038, 0.4166], [-0.0274, 0.375], [-0.0209, 0.3375]], 1.117, 1.509, 0.1, 2.0], ['drift', 1, 0.816368]], [[[[-0.219, 0.241], [-0.2354, 0.2651], [-0.2595, 0.2916], [-0.2794, 0.3208], [-0.2964, 0.3528], [-0.3284, 0.3881], [-0.3564, 0.4269]], 0.937, 2.683, 0.1, 3.0], ['blowup', 6, 2.028221]], [[[[0.506, 0.106], [0.56, 0.1166], [0.6216, 0.1283]], 1.94, 1.02, 0.1, 1.5], ['blowup', 2, 0.508116]], [[[[0.59, 0.017], [0.6553, 0.0187], [0.7314, 0.0206], [0.8089, 0.0226]], 1.97, 2.3, 0.01, 1.5], ['blowup', 2, 0.536693]]], [[[[[0.0, 0.0], [0.0014, 0.0], [0.0084, 0.0], [0.011, 0.0], [0.0111, 0.0], [0.0128, 0.0], [0.0135, 0.0], [0.0196, 0.0], [0.02, 0.0], [0.0228, 0.0]], 3.696, 2.035, 0.05, 3.0], ['ok', -1, 0.000961]], [[[[0.056, 0.464], [0.059, 0.4733], [0.0698, 0.4827], [0.0778, 0.4924], [0.0816, 0.5022], [0.0858, 0.5123], [0.0935, 0.5225], [0.0998, 0.533], [0.1033, 0.5436]], 4.406, 0.942, 0.1, 1.5], ['blowup', 8, 0.502025]], [[[[0.515, 0.325], [0.5708, 0.3575], [0.6313, 0.3933], [0.7076, 0.4326]], 1.69, 2.495, 0.1, 1.5], ['blowup', 3, 0.844852]], [[[[0.494, 0.726], [0.4862, 0.7042], [0.4712, 0.6831], [0.4542, 0.6626]], 4.432, 1.484, 0.1, 1.5], ['drift', 2, 0.159841]], [[[[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.091, 0.126], [-0.0974, 0.1386], [-0.1056, 0.1525], [-0.109, 0.1677], [-0.1141, 0.1845]], 3.918, 1.984, 0.01, 1.5], ['blowup', 3, 0.600589]], [[[[-0.658, -0.73], [-0.6294, -0.7081], [-0.602, -0.6869], [-0.5702, -0.6663], [-0.5488, -0.6463], [-0.5258, -0.6269], [-0.5064, -0.6081]], 3.265, 1.032, 0.1, 3.0], ['drift', 2, 0.379247]], [[[[-0.705, 0.668], [-0.6267, 0.6012], [-0.5657, 0.5411], [-0.506, 0.487]], 1.47, 0.964, 0.1, 1.5], ['drift', 1, 0.478798]]], [[[[[0.334, 0.023], [0.3729, 0.0253], [0.4088, 0.0278], [0.4434, 0.0306], [0.4927, 0.0337], [0.544, 0.037], [0.5905, 0.0407]], 0.518, 1.765, 0.1, 2.0], ['blowup', 4, 1.175602]], [[[[-0.926, -0.589], [-1.0206, -0.6479], [-1.1345, -0.7127], [-1.2337, -0.784], [-1.3724, -0.8624], [-1.5174, -0.9486], [-1.681, -1.0434], [-1.8301, -1.1478]], 4.721, 0.832, 0.1, 1.5], ['blowup', 3, 0.774779]], [[[[0.586, -0.551], [0.5421, -0.4959], [0.4949, -0.4463], [0.4451, -0.4017], [0.405, -0.3615], [0.3696, -0.3254], [0.3317, -0.2928]], 3.218, 1.406, 0.01, 3.0], ['drift', 1, 0.690192]], [[[[0.157, -0.869], [0.1454, -0.7821], [0.1394, -0.7039]], 3.306, 2.61, 0.05, 2.0], ['drift', 1, 0.338631]], [[[[0.538, -0.735], [0.544, -0.735], [0.548, -0.735], [0.5601, -0.735], [0.5638, -0.735], [0.5724, -0.735], [0.5687, -0.735]], 3.032, 1.382, 0.1, 2.0], ['ok', -1, 0.071307]], [[[[0.785, 0.863], [0.8832, 0.9493], [0.9792, 1.0442], [1.0583, 1.1487], [1.1525, 1.2635], [1.2718, 1.3899], [1.406, 1.5289], [1.536, 1.6817], [1.6868, 1.8499], [1.8906, 2.0349]], 2.411, 1.758, 0.05, 2.0], ['blowup', 4, 1.149877]], [[[[0.607, 0.468], [0.6659, 0.5148], [0.7371, 0.5663], [0.8121, 0.6229], [0.8833, 0.6852], [0.9551, 0.7537], [1.0629, 0.8291], [1.1762, 0.912], [1.2767, 1.0032]], 3.454, 2.778, 0.1, 2.0], ['blowup', 4, 1.125993]], [[[[-0.536, -0.266], [-0.571, -0.2926], [-0.6311, -0.3219], [-0.6867, -0.354], [-0.7515, -0.3895], [-0.8208, -0.4284], [-0.892, -0.4712], [-0.9733, -0.5184], [-1.0789, -0.5702], [-1.2044, -0.6272]], 0.869, 1.94, 0.01, 3.0], ['blowup', 7, 2.474992]]], [[[[[-0.158, 0.273], [-0.1584, 0.2785], [-0.155, 0.284], [-0.1529, 0.2897], [-0.1492, 0.2955], [-0.1509, 0.3014], [-0.1437, 0.3074]], 3.45, 0.863, 0.1, 3.0], ['ok', -1, 0.043282]], [[[[-0.648, -0.612], [-0.7038, -0.6732], [-0.766, -0.7405], [-0.8245, -0.8146], [-0.9148, -0.896], [-1.0192, -0.9856], [-1.1118, -1.0842], [-1.2153, -1.1926]], 1.534, 1.581, 0.1, 3.0], ['blowup', 6, 2.037018]], [[[[0.355, -0.075], [0.3414, -0.0727], [0.3418, -0.0706], [0.3422, -0.0685], [0.3388, -0.0664]], 4.633, 0.948, 0.05, 1.5], ['drift', 1, 0.090335]], [[[[0.599, -0.265], [0.6726, -0.2915], [0.7436, -0.3207], [0.8129, -0.3527], [0.9144, -0.388], [1.0101, -0.4268], [1.1116, -0.4695], [1.2193, -0.5164]], 2.659, 2.064, 0.01, 3.0], ['blowup', 6, 2.403627]], [[[[0.174, -0.48], [0.1771, -0.4896], [0.1863, -0.4994], [0.1987, -0.5094], [0.2011, -0.5196]], 1.179, 1.294, 0.01, 1.5], ['drift', 1, 0.189336]], [[[[-0.924, -0.704], [-1.0228, -0.7744], [-1.1142, -0.8518], [-1.2121, -0.937], [-1.3027, -1.0307]], 2.196, 1.673, 0.05, 1.5], ['blowup', 3, 0.736344]], [[[[0.313, -0.637], [0.2866, -0.5733], [0.2588, -0.516], [0.2373, -0.4644], [0.2157, -0.4179], [0.1948, -0.3761], [0.1756, -0.3385], [0.1616, -0.3047]], 0.961, 2.937, 0.01, 2.0], ['drift', 1, 0.768431]], [[[[-0.261, -0.067], [-0.2815, -0.0737], [-0.2986, -0.0811], [-0.3218, -0.0892], [-0.3475, -0.0981], [-0.3727, -0.1079], [-0.3969, -0.1187], [-0.4396, -0.1306]], 0.593, 2.153, 0.01, 2.0], ['blowup', 5, 1.146139]]]]
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 fixtureActualExpectedOutcome
case 0['drift', 1, 0.508184]['drift', 1, 0.508184]Passed
case 1['blowup', 9, 3.663649]['blowup', 5, 1.265832]Failed
case 2['ok', -1, 0.00042]['ok', -1, 0.00042]Passed
case 3['drift', 1, 3.202471]['blowup', 2, 0.500238]Failed
case 4['drift', 1, 0.340106]['drift', 1, 0.340106]Passed
case 5['drift', 1, 2.224782]['blowup', 6, 2.224782]Failed
case 6['drift', 1, 0.262788]['drift', 1, 0.262788]Passed
case 7['drift', 1, 3.451492]['blowup', 4, 1.307149]Failed

SHA-256 / 88f6f8470d2d5bf4951e2b9c4fbb66f52a9244712bfd73314cbea80c8408b9bb

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.87, 0.504], [-0.966, 0.5544], [-1.0758, 0.6098]], 1.889, 2.654, 0.01, 3.0], ['drift', 1, 0.508184]], [[[[-0.525, 0.127], [-0.5659, 0.1397], [-0.6321, 0.1537], [-0.6779, 0.169], [-0.7373, 0.1859], [-0.7883, 0.2045], [-0.8602, 0.225], [-0.9508, 0.2475], [-1.0348, 0.2722], [-1.13, 0.2995]], 4.571, 2.689, 0.1, 2.0], ['blowup', 5, 1.265832]], [[[[0.0, 0.0], [0.0023, 0.0], [0.008, 0.0], [0.0167, 0.0], [0.0239, 0.0]], 1.47, 2.583, 0.01, 2.0], ['ok', -1, 0.00042]], [[[[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.123, -0.843], [0.1274, -0.8177], [0.1304, -0.7932], [0.1322, -0.7694], [0.1354, -0.7463], [0.134, -0.7239], [0.1321, -0.7022], [0.1293, -0.6811]], 1.099, 1.464, 0.05, 2.0], ['drift', 1, 0.340106]], [[[[0.4, 0.057], [0.4385, 0.0627], [0.4824, 0.069], [0.5288, 0.0759], [0.5815, 0.0835], [0.6441, 0.0918], [0.7184, 0.101]], 4.732, 2.286, 0.05, 3.0], ['blowup', 6, 2.224782]], [[[[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.099, 0.306], [0.1145, 0.3366], [0.1305, 0.3703], [0.1459, 0.4073], [0.163, 0.448], [0.1873, 0.4928], [0.2145, 0.5421], [0.2438, 0.5963]], 4.583, 1.183, 0.05, 2.0], ['blowup', 4, 1.307149]]], [[[[[0.303, 0.246], [0.3325, 0.2706], [0.3676, 0.2977], [0.4034, 0.3274], [0.4447, 0.3602], [0.5066, 0.3962]], 0.771, 1.949, 0.05, 2.0], ['blowup', 4, 1.147733]], [[[[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.502, 0.885], [-0.4863, 0.8584], [-0.4555, 0.8327]], 2.684, 1.206, 0.05, 2.0], ['drift', 1, 0.140562]], [[[[-0.603, -0.678], [-0.6577, -0.7458], [-0.7284, -0.8204], [-0.7972, -0.9024], [-0.8767, -0.9927]], 0.53, 2.104, 0.05, 2.0], ['blowup', 4, 1.138787]], [[[[-0.1, 0.784], [-0.0885, 0.7056], [-0.0797, 0.635], [-0.0691, 0.5715], [-0.0592, 0.5144], [-0.0465, 0.4629], [-0.038, 0.4166], [-0.0274, 0.375], [-0.0209, 0.3375]], 1.117, 1.509, 0.1, 2.0], ['drift', 1, 0.816368]], [[[[-0.219, 0.241], [-0.2354, 0.2651], [-0.2595, 0.2916], [-0.2794, 0.3208], [-0.2964, 0.3528], [-0.3284, 0.3881], [-0.3564, 0.4269]], 0.937, 2.683, 0.1, 3.0], ['blowup', 6, 2.028221]], [[[[0.506, 0.106], [0.56, 0.1166], [0.6216, 0.1283]], 1.94, 1.02, 0.1, 1.5], ['blowup', 2, 0.508116]], [[[[0.59, 0.017], [0.6553, 0.0187], [0.7314, 0.0206], [0.8089, 0.0226]], 1.97, 2.3, 0.01, 1.5], ['blowup', 2, 0.536693]]], [[[[[0.0, 0.0], [0.0014, 0.0], [0.0084, 0.0], [0.011, 0.0], [0.0111, 0.0], [0.0128, 0.0], [0.0135, 0.0], [0.0196, 0.0], [0.02, 0.0], [0.0228, 0.0]], 3.696, 2.035, 0.05, 3.0], ['ok', -1, 0.000961]], [[[[0.056, 0.464], [0.059, 0.4733], [0.0698, 0.4827], [0.0778, 0.4924], [0.0816, 0.5022], [0.0858, 0.5123], [0.0935, 0.5225], [0.0998, 0.533], [0.1033, 0.5436]], 4.406, 0.942, 0.1, 1.5], ['blowup', 8, 0.502025]], [[[[0.515, 0.325], [0.5708, 0.3575], [0.6313, 0.3933], [0.7076, 0.4326]], 1.69, 2.495, 0.1, 1.5], ['blowup', 3, 0.844852]], [[[[0.494, 0.726], [0.4862, 0.7042], [0.4712, 0.6831], [0.4542, 0.6626]], 4.432, 1.484, 0.1, 1.5], ['drift', 2, 0.159841]], [[[[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.091, 0.126], [-0.0974, 0.1386], [-0.1056, 0.1525], [-0.109, 0.1677], [-0.1141, 0.1845]], 3.918, 1.984, 0.01, 1.5], ['blowup', 3, 0.600589]], [[[[-0.658, -0.73], [-0.6294, -0.7081], [-0.602, -0.6869], [-0.5702, -0.6663], [-0.5488, -0.6463], [-0.5258, -0.6269], [-0.5064, -0.6081]], 3.265, 1.032, 0.1, 3.0], ['drift', 2, 0.379247]], [[[[-0.705, 0.668], [-0.6267, 0.6012], [-0.5657, 0.5411], [-0.506, 0.487]], 1.47, 0.964, 0.1, 1.5], ['drift', 1, 0.478798]]], [[[[[0.334, 0.023], [0.3729, 0.0253], [0.4088, 0.0278], [0.4434, 0.0306], [0.4927, 0.0337], [0.544, 0.037], [0.5905, 0.0407]], 0.518, 1.765, 0.1, 2.0], ['blowup', 4, 1.175602]], [[[[-0.926, -0.589], [-1.0206, -0.6479], [-1.1345, -0.7127], [-1.2337, -0.784], [-1.3724, -0.8624], [-1.5174, -0.9486], [-1.681, -1.0434], [-1.8301, -1.1478]], 4.721, 0.832, 0.1, 1.5], ['blowup', 3, 0.774779]], [[[[0.586, -0.551], [0.5421, -0.4959], [0.4949, -0.4463], [0.4451, -0.4017], [0.405, -0.3615], [0.3696, -0.3254], [0.3317, -0.2928]], 3.218, 1.406, 0.01, 3.0], ['drift', 1, 0.690192]], [[[[0.157, -0.869], [0.1454, -0.7821], [0.1394, -0.7039]], 3.306, 2.61, 0.05, 2.0], ['drift', 1, 0.338631]], [[[[0.538, -0.735], [0.544, -0.735], [0.548, -0.735], [0.5601, -0.735], [0.5638, -0.735], [0.5724, -0.735], [0.5687, -0.735]], 3.032, 1.382, 0.1, 2.0], ['ok', -1, 0.071307]], [[[[0.785, 0.863], [0.8832, 0.9493], [0.9792, 1.0442], [1.0583, 1.1487], [1.1525, 1.2635], [1.2718, 1.3899], [1.406, 1.5289], [1.536, 1.6817], [1.6868, 1.8499], [1.8906, 2.0349]], 2.411, 1.758, 0.05, 2.0], ['blowup', 4, 1.149877]], [[[[0.607, 0.468], [0.6659, 0.5148], [0.7371, 0.5663], [0.8121, 0.6229], [0.8833, 0.6852], [0.9551, 0.7537], [1.0629, 0.8291], [1.1762, 0.912], [1.2767, 1.0032]], 3.454, 2.778, 0.1, 2.0], ['blowup', 4, 1.125993]], [[[[-0.536, -0.266], [-0.571, -0.2926], [-0.6311, -0.3219], [-0.6867, -0.354], [-0.7515, -0.3895], [-0.8208, -0.4284], [-0.892, -0.4712], [-0.9733, -0.5184], [-1.0789, -0.5702], [-1.2044, -0.6272]], 0.869, 1.94, 0.01, 3.0], ['blowup', 7, 2.474992]]], [[[[[-0.158, 0.273], [-0.1584, 0.2785], [-0.155, 0.284], [-0.1529, 0.2897], [-0.1492, 0.2955], [-0.1509, 0.3014], [-0.1437, 0.3074]], 3.45, 0.863, 0.1, 3.0], ['ok', -1, 0.043282]], [[[[-0.648, -0.612], [-0.7038, -0.6732], [-0.766, -0.7405], [-0.8245, -0.8146], [-0.9148, -0.896], [-1.0192, -0.9856], [-1.1118, -1.0842], [-1.2153, -1.1926]], 1.534, 1.581, 0.1, 3.0], ['blowup', 6, 2.037018]], [[[[0.355, -0.075], [0.3414, -0.0727], [0.3418, -0.0706], [0.3422, -0.0685], [0.3388, -0.0664]], 4.633, 0.948, 0.05, 1.5], ['drift', 1, 0.090335]], [[[[0.599, -0.265], [0.6726, -0.2915], [0.7436, -0.3207], [0.8129, -0.3527], [0.9144, -0.388], [1.0101, -0.4268], [1.1116, -0.4695], [1.2193, -0.5164]], 2.659, 2.064, 0.01, 3.0], ['blowup', 6, 2.403627]], [[[[0.174, -0.48], [0.1771, -0.4896], [0.1863, -0.4994], [0.1987, -0.5094], [0.2011, -0.5196]], 1.179, 1.294, 0.01, 1.5], ['drift', 1, 0.189336]], [[[[-0.924, -0.704], [-1.0228, -0.7744], [-1.1142, -0.8518], [-1.2121, -0.937], [-1.3027, -1.0307]], 2.196, 1.673, 0.05, 1.5], ['blowup', 3, 0.736344]], [[[[0.313, -0.637], [0.2866, -0.5733], [0.2588, -0.516], [0.2373, -0.4644], [0.2157, -0.4179], [0.1948, -0.3761], [0.1756, -0.3385], [0.1616, -0.3047]], 0.961, 2.937, 0.01, 2.0], ['drift', 1, 0.768431]], [[[[-0.261, -0.067], [-0.2815, -0.0737], [-0.2986, -0.0811], [-0.3218, -0.0892], [-0.3475, -0.0981], [-0.3727, -0.1079], [-0.3969, -0.1187], [-0.4396, -0.1306]], 0.593, 2.153, 0.01, 2.0], ['blowup', 5, 1.146139]]]]
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 fixtureActualExpectedOutcome
case 0['drift', 1, 0.508184]['drift', 1, 0.508184]Passed
case 1['blowup', 5, 1.265832]['blowup', 5, 1.265832]Passed
case 2['ok', -1, 0.00042]['ok', -1, 0.00042]Passed
case 3['blowup', 2, 0.500238]['blowup', 2, 0.500238]Passed
case 4['drift', 1, 0.340106]['drift', 1, 0.340106]Passed
case 5['blowup', 6, 2.224782]['blowup', 6, 2.224782]Passed
case 6['drift', 1, 0.262788]['drift', 1, 0.262788]Passed
case 7['blowup', 4, 1.307149]['blowup', 4, 1.307149]Passed

SHA-256 / 44350e335504606725a3f206550c31cd396f77e7f414e84da1a537c866e074f0

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.876964+00:00.

Case digest / 47c23f7c42a509bcc6e231105e5806dfdcae391b0b83add2a2834d564a8de4c4