FAILURE MAP
← Case archive

FA-87211 / Physics integrator stability / Open access

Normal impulse clamps the increment instead of the accumulated total · case 01

Warm-started contacts can never reduce their impulse and stacks pop apart.

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

ROOT CAUSE

jn = old + max(0, d) clamps each delta instead of the running sum.

VERIFIED REPAIR

Clamp the accumulated impulse: jn = max(0, old + d).

Unsuccessful approach: Discarding the accumulated value and clamping only the delta forgets warm starting.

Case contract

solve(vn0, vt0, w, mu, iterations, cached, warm): several contact points share one relative normal and tangent velocity with inverse mass w. Warm start each point with warm*cached [jn, jt] and apply it to the velocities. Each iteration visits points in order: friction first (accumulated jt clamped to |jt|<=mu*jn), then normal (accumulated jn clamped >=0). Return [jn list, jt list, vn, vt] rounded to 6.

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(vn0, vt0, w, mu, iterations, cached, warm):
    vn, vt = vn0, vt0
    jn = [p[0] * warm for p in cached]
    jt = [p[1] * warm for p in cached]
    for i in range(len(cached)):
        vn += jn[i] * w
        vt += jt[i] * w
    for _ in range(iterations):
        for i in range(len(cached)):
            d = -vt / w
            old = jt[i]
            lim = mu * jn[i]
            jt[i] = max(-lim, min(lim, old + d))
            vt += (jt[i] - old) * w
            d = -vn / w
            old = jn[i]
            jn[i] = old + max(0.0, d)
            vn += (jn[i] - old) * w
    return [[round(a, 6) for a in jn], [round(b, 6) for b in jt], round(vn, 6), round(vt, 6)]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[[[-0.45, -2.63, 0.513, 0.66, 1, [[1.97, 0.621], [0.453, 0.29]], 1.0], [[0.424193, 0.453], [1.3002, 0.29898], 0.0, -1.809621]], [[0.685, -1.149, 1.581, 0.319, 3, [[1.639, 0.089], [0.704, 0.468], [1.459, 0.87]], 0.5], [[0.0, 0.0, 0.0], [-0.0, -0.0, -0.0], 0.685, -1.149]], [[-1.594, 2.364, 1.549, 0.048, 2, [[1.895, 0.55]], 0.0], [[1.029051], [-0.049394], -0.0, 2.287488]], [[-2.657, -0.433, 1.951, 0.145, 4, [[0.187, -0.817], [1.814, 0.214]], 0.8], [[0.0, 1.361866], [-0.0, 0.197471], 0.0, -0.047735]], [[-0.855, -2.504, 0.814, 0.093, 2, [[1.088, -0.346], [0.335, 0.267], [0.166, -0.923]], 0.5], [[0.799869, 0.1675, 0.083], [0.074388, 0.015578, 0.007719], 0.0, -2.424485]], [[-2.627, 0.982, 1.321, 0.021, 4, [[0.96, 0.236]], 0.0], [[1.988645], [-0.041762], 0.0, 0.926833]], [[-0.053, 0.5, 1.424, 0.558, 3, [[1.8, -0.583], [0.11, -0.264], [1.605, 0.145]], 0.0], [[0.037219, 0.0, 0.0], [-0.020768, -0.0, -0.0], 0.0, 0.470426]], [[-2.759, 2.073, 1.058, 0.692, 3, [[1.088, -0.192], [0.779, -0.936]], 0.0], [[2.60775, 0.0], [-1.804563, -0.0], 0.0, 0.163772]]], [[[-3.479, -1.706, 1.756, 0.721, 3, [[0.185, -0.244], [1.148, 0.085], [0.304, 0.857]], 0.0], [[1.981207, 0.0, 0.0], [0.971526, -0.0, -0.0], 0.0, 0.0]], [[-0.995, 2.177, 1.091, 0.541, 3, [[0.575, 0.478], [1.81, 0.14]], 1.0], [[0.0, 0.912007], [-0.0, -0.493396], 0.0, 1.638705]], [[-0.085, -2.818, 1.518, 0.65, 2, [[1.041, -0.373]], 0.8], [[0.055995], [0.036397], 0.0, -2.76275]], [[-2.979, 2.253, 1.354, 0.901, 1, [[0.338, -0.665], [1.715, -0.942]], 0.8], [[0.828148, 1.372], [-0.24363, -1.236172], 0.0, 0.249348]], [[-3.903, -0.953, 0.987, 0.656, 2, [[1.967, 0.024], [1.697, 0.748]], 0.8], [[2.596807, 1.3576], [0.367152, 0.5984], 0.0, 0.0]], [[-1.683, 0.185, 1.148, 0.932, 1, [[1.39, -0.092], [1.749, -0.433]], 0.8], [[0.066828, 1.3992], [0.18525, -0.3464], 0.0, 0.0]], [[-2.442, 2.875, 1.13, 0.105, 3, [[1.638, -0.98]], 1.0], [[2.161062], [-0.226912], -0.0, 2.61859]], [[-0.596, -1.289, 0.968, 0.942, 4, [[0.525, 0.213], [1.769, -0.294]], 0.8], [[0.0, 0.615702], [-0.0, 0.579992], 0.0, -0.727568]]], [[[-2.82, 1.429, 1.478, 0.114, 2, [[0.588, -0.945], [0.049, -0.934], [1.67, 0.896]], 0.0], [[1.907984, 0.0, 0.0], [-0.21751, -0.0, -0.0], 0.0, 1.10752]], [[-1.764, 0.95, 0.746, 0.826, 2, [[1.55, -0.124], [0.697, 0.933]], 0.5], [[2.016111, 0.3485], [-0.985597, -0.287861], -0.0, 0.0]], [[-2.57, -0.774, 0.853, 0.663, 1, [[1.534, 0.042], [1.328, 0.245], [1.533, 0.512]], 0.8], [[0.724096, 1.0624, 1.2264], [0.301786, 0.196, 0.4096], 0.0, 0.0]], [[-3.642, -1.139, 0.269, 0.879, 1, [[1.679, -0.147]], 0.8], [[13.539033], [1.180673], 0.0, -0.821399]], [[-1.853, -2.582, 1.326, 0.734, 3, [[1.333, -0.474], [0.916, -0.278], [0.74, -0.368]], 0.0], [[1.397436, 0.0, 0.0], [1.025718, -0.0, -0.0], 0.0, -1.221898]], [[-1.741, 2.952, 1.183, 0.686, 2, [[1.377, 0.722], [1.534, 0.263], [1.218, -0.431]], 0.8], [[0.0, 0.497282, 0.9744], [-0.0, -0.341136, -0.668438], 0.0, 1.757674]], [[-0.006, 0.983, 1.414, 0.09, 2, [[0.657, -0.202]], 0.5], [[0.004243], [-0.000382], -0.0, 0.98246]], [[-1.345, -2.266, 0.903, 0.154, 1, [[1.454, -0.867], [0.873, 0.725], [1.147, 0.427]], 0.8], [[0.0, 0.57188, 0.9176], [0.179133, 0.107554, 0.14131], -0.0, -1.879519]]], [[[-1.313, -2.133, 0.747, 0.274, 2, [[1.503, -0.183]], 0.5], [[1.757697], [0.481609], -0.0, -1.773238]], [[-0.452, 0.319, 1.522, 0.566, 1, [[0.052, -0.671], [1.955, 0.245]], 0.5], [[0.0, 0.296978], [-0.014716, -0.194877], 0.0, 0.0]], [[-1.164, 1.755, 1.237, 0.583, 4, [[1.08, -0.704], [0.957, 0.84], [0.832, -0.311]], 0.8], [[0.0, 0.275386, 0.6656], [-0.0, -0.16055, -0.388045], 0.0, 1.076388]], [[-3.064, 0.926, 1.276, 0.438, 1, [[1.816, 0.186], [1.017, 0.131]], 1.0], [[1.384254, 1.017], [-0.795408, 0.069703], 0.0, 0.0]], [[-0.273, -0.222, 0.442, 0.741, 4, [[1.663, -0.119], [1.445, 0.772], [0.248, 0.608]], 0.0], [[0.617647, 0.0, 0.0], [0.457676, -0.0, -0.0], 0.0, -0.019707]], [[0.642, 1.312, 0.774, 0.276, 3, [[0.568, 0.395]], 1.0], [[0.0], [-0.0], 0.642, 1.312]], [[-1.874, 1.271, 1.863, 0.73, 2, [[0.977, 0.873], [1.414, -0.258]], 1.0], [[0.0, 1.005904], [-0.0, -0.682233], 0.0, 0.0]], [[-1.311, -0.201, 1.222, 0.493, 1, [[0.285, -0.793], [0.403, 0.853]], 1.0], [[0.669831, 0.403], [-0.140505, 0.198679], 0.0, -0.129911]]], [[[-3.869, -1.566, 1.822, 0.635, 3, [[0.99, 0.726], [1.396, -0.851]], 0.0], [[2.123491, 0.0], [0.859495, -0.0], 0.0, 0.0]], [[-0.236, -1.26, 1.507, 0.291, 1, [[0.089, 0.562], [0.695, 0.022], [1.181, 0.137]], 0.8], [[0.0, 0.0, 0.156603], [0.020719, 0.161796, 0.274937], 0.0, -0.57062]], [[0.977, -0.644, 0.452, 0.107, 1, [[0.272, -0.393], [1.275, -0.698]], 0.0], [[0.0, 0.0], [-0.0, -0.0], 0.977, -0.644]], [[-0.335, 0.88, 0.885, 0.436, 3, [[0.424, 0.225], [0.346, -0.387], [0.517, -0.788]], 0.0], [[0.378531, 0.0, 0.0], [-0.16504, -0.0, -0.0], 0.0, 0.73394]], [[-3.102, 2.687, 0.678, 0.828, 3, [[1.24, -0.865], [0.364, 0.726]], 0.8], [[4.284021, 0.2912], [-3.54717, -0.241114], 0.0, 0.118544]], [[0.425, -1.829, 0.322, 0.126, 4, [[1.478, -0.649], [1.122, 0.164], [0.405, -0.483]], 0.0], [[0.0, 0.0, 0.0], [-0.0, -0.0, -0.0], 0.425, -1.829]], [[-0.464, 1.964, 1.129, 0.016, 2, [[1.578, 0.441]], 0.5], [[0.410983], [-0.006576], 0.0, 1.956576]], [[-1.818, 1.507, 1.927, 0.617, 2, [[1.271, -0.289], [1.241, 0.267], [0.553, -0.476]], 1.0], [[0.0, 0.390435, 0.553], [-0.0, -0.240899, -0.341201], 0.0, 0.385294]]]]
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[[1.97, 0.453], [1.3002, 0.29898], 0.792999, -1.809621][[0.424193, 0.453], [1.3002, 0.29898], 0.0, -1.809621]Failed
case 1[[0.8195, 0.352, 0.7295], [0.261421, 0.112288, 0.232711], 3.690481, -0.190252][[0.0, 0.0, 0.0], [-0.0, -0.0, -0.0], 0.685, -1.149]Failed
case 2[[1.029051], [-0.049394], 0.0, 2.287488][[1.029051], [-0.049394], -0.0, 2.287488]Passed
case 3[[0.1496, 1.4512], [0.021692, 0.200245], 0.466161, 0.0][[0.0, 1.361866], [-0.0, 0.197471], 0.0, -0.047735]Failed
case 4[[0.799869, 0.1675, 0.083], [0.074388, 0.015578, 0.007719], 0.0, -2.424485][[0.799869, 0.1675, 0.083], [0.074388, 0.015578, 0.007719], 0.0, -2.424485]Passed
case 5[[1.988645], [-0.041762], 0.0, 0.926833][[1.988645], [-0.041762], 0.0, 0.926833]Passed
case 6[[0.037219, 0.0, 0.0], [-0.020768, -0.0, -0.0], 0.0, 0.470426][[0.037219, 0.0, 0.0], [-0.020768, -0.0, -0.0], 0.0, 0.470426]Passed
case 7[[2.60775, 0.0], [-1.804563, -0.0], 0.0, 0.163772][[2.60775, 0.0], [-1.804563, -0.0], 0.0, 0.163772]Passed

SHA-256 / 5e1fba24515e88efc5274f1c1a3254946ec946cec0aa8a7d5336f98c4f21cc9d

2 / The unsuccessful fix

Exit 1
"""Failure Map reference implementation. Python standard library only."""
import json
import math
N = 1
observations = []
def solve(vn0, vt0, w, mu, iterations, cached, warm):
    vn, vt = vn0, vt0
    jn = [p[0] * warm for p in cached]
    jt = [p[1] * warm for p in cached]
    for i in range(len(cached)):
        vn += jn[i] * w
        vt += jt[i] * w
    for _ in range(iterations):
        for i in range(len(cached)):
            d = -vt / w
            old = jt[i]
            lim = mu * jn[i]
            jt[i] = max(-lim, min(lim, old + d))
            vt += (jt[i] - old) * w
            d = -vn / w
            old = jn[i]
            jn[i] = max(0.0, d)
            vn += (jn[i] - old) * w
    return [[round(a, 6) for a in jn], [round(b, 6) for b in jt], round(vn, 6), round(vt, 6)]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[[[-0.45, -2.63, 0.513, 0.66, 1, [[1.97, 0.621], [0.453, 0.29]], 1.0], [[0.424193, 0.453], [1.3002, 0.29898], 0.0, -1.809621]], [[0.685, -1.149, 1.581, 0.319, 3, [[1.639, 0.089], [0.704, 0.468], [1.459, 0.87]], 0.5], [[0.0, 0.0, 0.0], [-0.0, -0.0, -0.0], 0.685, -1.149]], [[-1.594, 2.364, 1.549, 0.048, 2, [[1.895, 0.55]], 0.0], [[1.029051], [-0.049394], -0.0, 2.287488]], [[-2.657, -0.433, 1.951, 0.145, 4, [[0.187, -0.817], [1.814, 0.214]], 0.8], [[0.0, 1.361866], [-0.0, 0.197471], 0.0, -0.047735]], [[-0.855, -2.504, 0.814, 0.093, 2, [[1.088, -0.346], [0.335, 0.267], [0.166, -0.923]], 0.5], [[0.799869, 0.1675, 0.083], [0.074388, 0.015578, 0.007719], 0.0, -2.424485]], [[-2.627, 0.982, 1.321, 0.021, 4, [[0.96, 0.236]], 0.0], [[1.988645], [-0.041762], 0.0, 0.926833]], [[-0.053, 0.5, 1.424, 0.558, 3, [[1.8, -0.583], [0.11, -0.264], [1.605, 0.145]], 0.0], [[0.037219, 0.0, 0.0], [-0.020768, -0.0, -0.0], 0.0, 0.470426]], [[-2.759, 2.073, 1.058, 0.692, 3, [[1.088, -0.192], [0.779, -0.936]], 0.0], [[2.60775, 0.0], [-1.804563, -0.0], 0.0, 0.163772]]], [[[-3.479, -1.706, 1.756, 0.721, 3, [[0.185, -0.244], [1.148, 0.085], [0.304, 0.857]], 0.0], [[1.981207, 0.0, 0.0], [0.971526, -0.0, -0.0], 0.0, 0.0]], [[-0.995, 2.177, 1.091, 0.541, 3, [[0.575, 0.478], [1.81, 0.14]], 1.0], [[0.0, 0.912007], [-0.0, -0.493396], 0.0, 1.638705]], [[-0.085, -2.818, 1.518, 0.65, 2, [[1.041, -0.373]], 0.8], [[0.055995], [0.036397], 0.0, -2.76275]], [[-2.979, 2.253, 1.354, 0.901, 1, [[0.338, -0.665], [1.715, -0.942]], 0.8], [[0.828148, 1.372], [-0.24363, -1.236172], 0.0, 0.249348]], [[-3.903, -0.953, 0.987, 0.656, 2, [[1.967, 0.024], [1.697, 0.748]], 0.8], [[2.596807, 1.3576], [0.367152, 0.5984], 0.0, 0.0]], [[-1.683, 0.185, 1.148, 0.932, 1, [[1.39, -0.092], [1.749, -0.433]], 0.8], [[0.066828, 1.3992], [0.18525, -0.3464], 0.0, 0.0]], [[-2.442, 2.875, 1.13, 0.105, 3, [[1.638, -0.98]], 1.0], [[2.161062], [-0.226912], -0.0, 2.61859]], [[-0.596, -1.289, 0.968, 0.942, 4, [[0.525, 0.213], [1.769, -0.294]], 0.8], [[0.0, 0.615702], [-0.0, 0.579992], 0.0, -0.727568]]], [[[-2.82, 1.429, 1.478, 0.114, 2, [[0.588, -0.945], [0.049, -0.934], [1.67, 0.896]], 0.0], [[1.907984, 0.0, 0.0], [-0.21751, -0.0, -0.0], 0.0, 1.10752]], [[-1.764, 0.95, 0.746, 0.826, 2, [[1.55, -0.124], [0.697, 0.933]], 0.5], [[2.016111, 0.3485], [-0.985597, -0.287861], -0.0, 0.0]], [[-2.57, -0.774, 0.853, 0.663, 1, [[1.534, 0.042], [1.328, 0.245], [1.533, 0.512]], 0.8], [[0.724096, 1.0624, 1.2264], [0.301786, 0.196, 0.4096], 0.0, 0.0]], [[-3.642, -1.139, 0.269, 0.879, 1, [[1.679, -0.147]], 0.8], [[13.539033], [1.180673], 0.0, -0.821399]], [[-1.853, -2.582, 1.326, 0.734, 3, [[1.333, -0.474], [0.916, -0.278], [0.74, -0.368]], 0.0], [[1.397436, 0.0, 0.0], [1.025718, -0.0, -0.0], 0.0, -1.221898]], [[-1.741, 2.952, 1.183, 0.686, 2, [[1.377, 0.722], [1.534, 0.263], [1.218, -0.431]], 0.8], [[0.0, 0.497282, 0.9744], [-0.0, -0.341136, -0.668438], 0.0, 1.757674]], [[-0.006, 0.983, 1.414, 0.09, 2, [[0.657, -0.202]], 0.5], [[0.004243], [-0.000382], -0.0, 0.98246]], [[-1.345, -2.266, 0.903, 0.154, 1, [[1.454, -0.867], [0.873, 0.725], [1.147, 0.427]], 0.8], [[0.0, 0.57188, 0.9176], [0.179133, 0.107554, 0.14131], -0.0, -1.879519]]], [[[-1.313, -2.133, 0.747, 0.274, 2, [[1.503, -0.183]], 0.5], [[1.757697], [0.481609], -0.0, -1.773238]], [[-0.452, 0.319, 1.522, 0.566, 1, [[0.052, -0.671], [1.955, 0.245]], 0.5], [[0.0, 0.296978], [-0.014716, -0.194877], 0.0, 0.0]], [[-1.164, 1.755, 1.237, 0.583, 4, [[1.08, -0.704], [0.957, 0.84], [0.832, -0.311]], 0.8], [[0.0, 0.275386, 0.6656], [-0.0, -0.16055, -0.388045], 0.0, 1.076388]], [[-3.064, 0.926, 1.276, 0.438, 1, [[1.816, 0.186], [1.017, 0.131]], 1.0], [[1.384254, 1.017], [-0.795408, 0.069703], 0.0, 0.0]], [[-0.273, -0.222, 0.442, 0.741, 4, [[1.663, -0.119], [1.445, 0.772], [0.248, 0.608]], 0.0], [[0.617647, 0.0, 0.0], [0.457676, -0.0, -0.0], 0.0, -0.019707]], [[0.642, 1.312, 0.774, 0.276, 3, [[0.568, 0.395]], 1.0], [[0.0], [-0.0], 0.642, 1.312]], [[-1.874, 1.271, 1.863, 0.73, 2, [[0.977, 0.873], [1.414, -0.258]], 1.0], [[0.0, 1.005904], [-0.0, -0.682233], 0.0, 0.0]], [[-1.311, -0.201, 1.222, 0.493, 1, [[0.285, -0.793], [0.403, 0.853]], 1.0], [[0.669831, 0.403], [-0.140505, 0.198679], 0.0, -0.129911]]], [[[-3.869, -1.566, 1.822, 0.635, 3, [[0.99, 0.726], [1.396, -0.851]], 0.0], [[2.123491, 0.0], [0.859495, -0.0], 0.0, 0.0]], [[-0.236, -1.26, 1.507, 0.291, 1, [[0.089, 0.562], [0.695, 0.022], [1.181, 0.137]], 0.8], [[0.0, 0.0, 0.156603], [0.020719, 0.161796, 0.274937], 0.0, -0.57062]], [[0.977, -0.644, 0.452, 0.107, 1, [[0.272, -0.393], [1.275, -0.698]], 0.0], [[0.0, 0.0], [-0.0, -0.0], 0.977, -0.644]], [[-0.335, 0.88, 0.885, 0.436, 3, [[0.424, 0.225], [0.346, -0.387], [0.517, -0.788]], 0.0], [[0.378531, 0.0, 0.0], [-0.16504, -0.0, -0.0], 0.0, 0.73394]], [[-3.102, 2.687, 0.678, 0.828, 3, [[1.24, -0.865], [0.364, 0.726]], 0.8], [[4.284021, 0.2912], [-3.54717, -0.241114], 0.0, 0.118544]], [[0.425, -1.829, 0.322, 0.126, 4, [[1.478, -0.649], [1.122, 0.164], [0.405, -0.483]], 0.0], [[0.0, 0.0, 0.0], [-0.0, -0.0, -0.0], 0.425, -1.829]], [[-0.464, 1.964, 1.129, 0.016, 2, [[1.578, 0.441]], 0.5], [[0.410983], [-0.006576], 0.0, 1.956576]], [[-1.818, 1.507, 1.927, 0.617, 2, [[1.271, -0.289], [1.241, 0.267], [0.553, -0.476]], 1.0], [[0.0, 0.390435, 0.553], [-0.0, -0.240899, -0.341201], 0.0, 0.385294]]]]
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[[0.0, 0.424193], [1.3002, 0.29898], -0.232389, -1.809621][[0.424193, 0.453], [1.3002, 0.29898], 0.0, -1.809621]Failed
case 1[[0.0, 0.0, 0.0], [-0.0, -0.0, -0.0], 0.685, -1.149][[0.0, 0.0, 0.0], [-0.0, -0.0, -0.0], 0.685, -1.149]Passed
case 2[[0.0], [-0.049394], -1.594, 2.287488][[1.029051], [-0.049394], -0.0, 2.287488]Failed
case 3[[0.0, 0.0], [-0.0, 0.197471], -2.657, -0.047735][[0.0, 1.361866], [-0.0, 0.197471], 0.0, -0.047735]Failed
case 4[[0.083, 0.255869, 0.544], [0.023796, 0.050592, 0.015577], -0.136345, -2.430768][[0.799869, 0.1675, 0.083], [0.074388, 0.015578, 0.007719], 0.0, -2.424485]Failed
case 5[[0.0], [-0.041762], -2.627, 0.926833][[1.988645], [-0.041762], 0.0, 0.926833]Failed
case 6[[0.0, 0.0, 0.037219], [-0.0, -0.020768, -0.0], 0.0, 0.470426][[0.037219, 0.0, 0.0], [-0.020768, -0.0, -0.0], 0.0, 0.470426]Failed
case 7[[0.0, 0.0], [-0.0, -1.804563], -2.759, 0.163772][[2.60775, 0.0], [-1.804563, -0.0], 0.0, 0.163772]Failed

SHA-256 / a9ee3a92886cd92f9ab5ebf86dbda0841081c69d721156b4bd0923914ae3f147

3 / The verified repair

Exit 0
"""Failure Map reference implementation. Python standard library only."""
import json
import math
N = 1
observations = []
def solve(vn0, vt0, w, mu, iterations, cached, warm):
    vn, vt = vn0, vt0
    jn = [p[0] * warm for p in cached]
    jt = [p[1] * warm for p in cached]
    for i in range(len(cached)):
        vn += jn[i] * w
        vt += jt[i] * w
    for _ in range(iterations):
        for i in range(len(cached)):
            d = -vt / w
            old = jt[i]
            lim = mu * jn[i]
            jt[i] = max(-lim, min(lim, old + d))
            vt += (jt[i] - old) * w
            d = -vn / w
            old = jn[i]
            jn[i] = max(0.0, old + d)
            vn += (jn[i] - old) * w
    return [[round(a, 6) for a in jn], [round(b, 6) for b in jt], round(vn, 6), round(vt, 6)]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[[[-0.45, -2.63, 0.513, 0.66, 1, [[1.97, 0.621], [0.453, 0.29]], 1.0], [[0.424193, 0.453], [1.3002, 0.29898], 0.0, -1.809621]], [[0.685, -1.149, 1.581, 0.319, 3, [[1.639, 0.089], [0.704, 0.468], [1.459, 0.87]], 0.5], [[0.0, 0.0, 0.0], [-0.0, -0.0, -0.0], 0.685, -1.149]], [[-1.594, 2.364, 1.549, 0.048, 2, [[1.895, 0.55]], 0.0], [[1.029051], [-0.049394], -0.0, 2.287488]], [[-2.657, -0.433, 1.951, 0.145, 4, [[0.187, -0.817], [1.814, 0.214]], 0.8], [[0.0, 1.361866], [-0.0, 0.197471], 0.0, -0.047735]], [[-0.855, -2.504, 0.814, 0.093, 2, [[1.088, -0.346], [0.335, 0.267], [0.166, -0.923]], 0.5], [[0.799869, 0.1675, 0.083], [0.074388, 0.015578, 0.007719], 0.0, -2.424485]], [[-2.627, 0.982, 1.321, 0.021, 4, [[0.96, 0.236]], 0.0], [[1.988645], [-0.041762], 0.0, 0.926833]], [[-0.053, 0.5, 1.424, 0.558, 3, [[1.8, -0.583], [0.11, -0.264], [1.605, 0.145]], 0.0], [[0.037219, 0.0, 0.0], [-0.020768, -0.0, -0.0], 0.0, 0.470426]], [[-2.759, 2.073, 1.058, 0.692, 3, [[1.088, -0.192], [0.779, -0.936]], 0.0], [[2.60775, 0.0], [-1.804563, -0.0], 0.0, 0.163772]]], [[[-3.479, -1.706, 1.756, 0.721, 3, [[0.185, -0.244], [1.148, 0.085], [0.304, 0.857]], 0.0], [[1.981207, 0.0, 0.0], [0.971526, -0.0, -0.0], 0.0, 0.0]], [[-0.995, 2.177, 1.091, 0.541, 3, [[0.575, 0.478], [1.81, 0.14]], 1.0], [[0.0, 0.912007], [-0.0, -0.493396], 0.0, 1.638705]], [[-0.085, -2.818, 1.518, 0.65, 2, [[1.041, -0.373]], 0.8], [[0.055995], [0.036397], 0.0, -2.76275]], [[-2.979, 2.253, 1.354, 0.901, 1, [[0.338, -0.665], [1.715, -0.942]], 0.8], [[0.828148, 1.372], [-0.24363, -1.236172], 0.0, 0.249348]], [[-3.903, -0.953, 0.987, 0.656, 2, [[1.967, 0.024], [1.697, 0.748]], 0.8], [[2.596807, 1.3576], [0.367152, 0.5984], 0.0, 0.0]], [[-1.683, 0.185, 1.148, 0.932, 1, [[1.39, -0.092], [1.749, -0.433]], 0.8], [[0.066828, 1.3992], [0.18525, -0.3464], 0.0, 0.0]], [[-2.442, 2.875, 1.13, 0.105, 3, [[1.638, -0.98]], 1.0], [[2.161062], [-0.226912], -0.0, 2.61859]], [[-0.596, -1.289, 0.968, 0.942, 4, [[0.525, 0.213], [1.769, -0.294]], 0.8], [[0.0, 0.615702], [-0.0, 0.579992], 0.0, -0.727568]]], [[[-2.82, 1.429, 1.478, 0.114, 2, [[0.588, -0.945], [0.049, -0.934], [1.67, 0.896]], 0.0], [[1.907984, 0.0, 0.0], [-0.21751, -0.0, -0.0], 0.0, 1.10752]], [[-1.764, 0.95, 0.746, 0.826, 2, [[1.55, -0.124], [0.697, 0.933]], 0.5], [[2.016111, 0.3485], [-0.985597, -0.287861], -0.0, 0.0]], [[-2.57, -0.774, 0.853, 0.663, 1, [[1.534, 0.042], [1.328, 0.245], [1.533, 0.512]], 0.8], [[0.724096, 1.0624, 1.2264], [0.301786, 0.196, 0.4096], 0.0, 0.0]], [[-3.642, -1.139, 0.269, 0.879, 1, [[1.679, -0.147]], 0.8], [[13.539033], [1.180673], 0.0, -0.821399]], [[-1.853, -2.582, 1.326, 0.734, 3, [[1.333, -0.474], [0.916, -0.278], [0.74, -0.368]], 0.0], [[1.397436, 0.0, 0.0], [1.025718, -0.0, -0.0], 0.0, -1.221898]], [[-1.741, 2.952, 1.183, 0.686, 2, [[1.377, 0.722], [1.534, 0.263], [1.218, -0.431]], 0.8], [[0.0, 0.497282, 0.9744], [-0.0, -0.341136, -0.668438], 0.0, 1.757674]], [[-0.006, 0.983, 1.414, 0.09, 2, [[0.657, -0.202]], 0.5], [[0.004243], [-0.000382], -0.0, 0.98246]], [[-1.345, -2.266, 0.903, 0.154, 1, [[1.454, -0.867], [0.873, 0.725], [1.147, 0.427]], 0.8], [[0.0, 0.57188, 0.9176], [0.179133, 0.107554, 0.14131], -0.0, -1.879519]]], [[[-1.313, -2.133, 0.747, 0.274, 2, [[1.503, -0.183]], 0.5], [[1.757697], [0.481609], -0.0, -1.773238]], [[-0.452, 0.319, 1.522, 0.566, 1, [[0.052, -0.671], [1.955, 0.245]], 0.5], [[0.0, 0.296978], [-0.014716, -0.194877], 0.0, 0.0]], [[-1.164, 1.755, 1.237, 0.583, 4, [[1.08, -0.704], [0.957, 0.84], [0.832, -0.311]], 0.8], [[0.0, 0.275386, 0.6656], [-0.0, -0.16055, -0.388045], 0.0, 1.076388]], [[-3.064, 0.926, 1.276, 0.438, 1, [[1.816, 0.186], [1.017, 0.131]], 1.0], [[1.384254, 1.017], [-0.795408, 0.069703], 0.0, 0.0]], [[-0.273, -0.222, 0.442, 0.741, 4, [[1.663, -0.119], [1.445, 0.772], [0.248, 0.608]], 0.0], [[0.617647, 0.0, 0.0], [0.457676, -0.0, -0.0], 0.0, -0.019707]], [[0.642, 1.312, 0.774, 0.276, 3, [[0.568, 0.395]], 1.0], [[0.0], [-0.0], 0.642, 1.312]], [[-1.874, 1.271, 1.863, 0.73, 2, [[0.977, 0.873], [1.414, -0.258]], 1.0], [[0.0, 1.005904], [-0.0, -0.682233], 0.0, 0.0]], [[-1.311, -0.201, 1.222, 0.493, 1, [[0.285, -0.793], [0.403, 0.853]], 1.0], [[0.669831, 0.403], [-0.140505, 0.198679], 0.0, -0.129911]]], [[[-3.869, -1.566, 1.822, 0.635, 3, [[0.99, 0.726], [1.396, -0.851]], 0.0], [[2.123491, 0.0], [0.859495, -0.0], 0.0, 0.0]], [[-0.236, -1.26, 1.507, 0.291, 1, [[0.089, 0.562], [0.695, 0.022], [1.181, 0.137]], 0.8], [[0.0, 0.0, 0.156603], [0.020719, 0.161796, 0.274937], 0.0, -0.57062]], [[0.977, -0.644, 0.452, 0.107, 1, [[0.272, -0.393], [1.275, -0.698]], 0.0], [[0.0, 0.0], [-0.0, -0.0], 0.977, -0.644]], [[-0.335, 0.88, 0.885, 0.436, 3, [[0.424, 0.225], [0.346, -0.387], [0.517, -0.788]], 0.0], [[0.378531, 0.0, 0.0], [-0.16504, -0.0, -0.0], 0.0, 0.73394]], [[-3.102, 2.687, 0.678, 0.828, 3, [[1.24, -0.865], [0.364, 0.726]], 0.8], [[4.284021, 0.2912], [-3.54717, -0.241114], 0.0, 0.118544]], [[0.425, -1.829, 0.322, 0.126, 4, [[1.478, -0.649], [1.122, 0.164], [0.405, -0.483]], 0.0], [[0.0, 0.0, 0.0], [-0.0, -0.0, -0.0], 0.425, -1.829]], [[-0.464, 1.964, 1.129, 0.016, 2, [[1.578, 0.441]], 0.5], [[0.410983], [-0.006576], 0.0, 1.956576]], [[-1.818, 1.507, 1.927, 0.617, 2, [[1.271, -0.289], [1.241, 0.267], [0.553, -0.476]], 1.0], [[0.0, 0.390435, 0.553], [-0.0, -0.240899, -0.341201], 0.0, 0.385294]]]]
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[[0.424193, 0.453], [1.3002, 0.29898], 0.0, -1.809621][[0.424193, 0.453], [1.3002, 0.29898], 0.0, -1.809621]Passed
case 1[[0.0, 0.0, 0.0], [-0.0, -0.0, -0.0], 0.685, -1.149][[0.0, 0.0, 0.0], [-0.0, -0.0, -0.0], 0.685, -1.149]Passed
case 2[[1.029051], [-0.049394], -0.0, 2.287488][[1.029051], [-0.049394], -0.0, 2.287488]Passed
case 3[[0.0, 1.361866], [-0.0, 0.197471], 0.0, -0.047735][[0.0, 1.361866], [-0.0, 0.197471], 0.0, -0.047735]Passed
case 4[[0.799869, 0.1675, 0.083], [0.074388, 0.015578, 0.007719], 0.0, -2.424485][[0.799869, 0.1675, 0.083], [0.074388, 0.015578, 0.007719], 0.0, -2.424485]Passed
case 5[[1.988645], [-0.041762], 0.0, 0.926833][[1.988645], [-0.041762], 0.0, 0.926833]Passed
case 6[[0.037219, 0.0, 0.0], [-0.020768, -0.0, -0.0], 0.0, 0.470426][[0.037219, 0.0, 0.0], [-0.020768, -0.0, -0.0], 0.0, 0.470426]Passed
case 7[[2.60775, 0.0], [-1.804563, -0.0], 0.0, 0.163772][[2.60775, 0.0], [-1.804563, -0.0], 0.0, 0.163772]Passed

SHA-256 / ecb68b6dadca16d3f891beb36f18369243e52603be44e41a41e3463940b7eeda

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

Case digest / a18c267bce8f858824ef67dd1dd688574a8c5d58dec0b564c2efbd314a89e520