FAILURE MAP
← Case archive

FA-86851 / Physics integrator stability / Open access

Viscous damping force is applied as an acceleration without dividing by mass · case 01

Heavy bodies are over-damped and light ones under-damped relative to the contract.

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

ROOT CAUSE

Only the spring term is divided by mass because of operator precedence; c*v is used directly as acceleration.

VERIFIED REPAIR

Divide the whole force (-k*x - c*v) by the mass.

Unsuccessful approach: Dividing the damping term by mass inside the parentheses and again outside double-scales it.

Case contract

solve(x0, v0, k, m, c, dt, steps): damped spring a=(-k*x-c*v)/m integrated with semi-implicit Euler (velocity first, then position with the new velocity). Each frame of length dt is split into ceil(dt/0.05) equal substeps (at least one). Return [x, v] rounded to 6 decimals after steps frames.

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(x0, v0, k, m, c, dt, steps):
    n_sub = max(1, math.ceil(dt / 0.05 - 1e-12))
    h = dt / n_sub
    x, v = x0, v0
    for _ in range(steps):
        for _ in range(n_sub):
            a = -k * x / m - c * v
            v = v + a * h
            x = x + v * h
    return [round(x, 6), round(v, 6)]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[[[-1.484, 1.712, 27.312, 2.961, 1.788, 0.13, 4], [0.446958, 3.829901]], [[-0.104, -1.626, 5.159, 2.304, 0.637, 0.2, 0], [-0.104, -1.626]], [[1.0, 0.0, 10.0, 1.0, 0.0, 0.05, 0], [1.0, 0.0]], [[0.086, 0.733, 7.163, 2.307, 1.249, 0.05, 1], [0.12099, 0.699807]], [[1.545, 1.962, 22.255, 1.613, 1.385, 0.02, 0], [1.545, 1.962]], [[1.916, 1.522, 23.049, 0.619, 1.046, 0.2, 2], [-0.971294, -6.107647]], [[-1.343, -1.045, 36.463, 2.947, 1.73, 0.02, 1], [-1.357008, -0.700394]], [[0.567, -0.563, 3.019, 2.331, 1.024, 0.05, 8], [0.30826, -0.689182]]], [[[1.925, -0.173, 39.051, 1.209, 0.422, 0.01, 5], [1.824415, -3.211948]], [[-0.384, 0.483, 39.776, 2.351, 1.463, 0.04, 0], [-0.384, 0.483]], [[-1.087, 0.963, 34.734, 2.546, 1.868, 0.07, 9], [0.718936, 1.786483]], [[1.0, 0.0, 10.0, 1.0, 0.0, 0.05, 0], [1.0, 0.0]], [[1.742, -0.907, 38.421, 2.244, 0.819, 0.1, 5], [-1.031195, -5.442883]], [[-1.792, 1.668, 7.957, 1.875, 1.186, 0.04, 9], [-0.822549, 3.240967]], [[-1.669, -1.23, 27.053, 1.533, 0.991, 0.13, 5], [1.161742, 3.128527]], [[-1.46, -0.406, 15.912, 1.138, 0.653, 0.07, 0], [-1.46, -0.406]]], [[[-1.712, -1.9, 9.139, 0.693, 0.61, 0.05, 13], [0.624756, 4.351887]], [[0.6, -0.396, 35.253, 1.711, 1.361, 0.04, 8], [-0.018685, -2.456697]], [[1.207, 0.351, 14.617, 2.861, 0.895, 0.07, 6], [0.802339, -1.906391]], [[1.0, 0.0, 10.0, 1.0, 0.0, 0.05, 0], [1.0, 0.0]], [[1.648, -0.117, 24.609, 0.651, 1.732, 0.05, 0], [1.648, -0.117]], [[0.575, -1.191, 6.727, 1.218, 1.658, 0.2, 4], [-0.282948, -0.458231]], [[0.87, 1.182, 19.781, 1.146, 0.3, 0.1, 0], [0.87, 1.182]], [[0.566, 0.949, 26.197, 1.061, 0.815, 0.04, 4], [0.488626, -1.290634]]], [[[1.645, -1.841, 34.562, 1.534, 1.725, 0.2, 6], [0.803376, 1.245092]], [[-1.284, 1.069, 32.194, 0.542, 0.353, 0.05, 11], [0.174523, -8.251404]], [[-0.117, 1.853, 21.165, 2.719, 0.626, 0.07, 12], [0.503218, -0.957084]], [[0.484, 0.239, 12.355, 0.868, 0.3, 0.07, 0], [0.484, 0.239]], [[1.0, 0.0, 10.0, 1.0, 0.0, 0.05, 0], [1.0, 0.0]], [[1.074, -0.57, 32.767, 1.613, 0.402, 0.02, 7], [0.767571, -3.27442]], [[0.525, -0.515, 17.156, 2.442, 0.805, 0.05, 2], [0.447863, -0.851821]], [[1.977, 0.462, 36.991, 1.489, 1.033, 0.13, 0], [1.977, 0.462]]], [[[-1.576, -0.203, 24.72, 2.347, 1.363, 0.07, 10], [0.760633, 3.318988]], [[-1.172, -1.957, 14.575, 1.726, 0.305, 0.1, 12], [1.182005, 0.606601]], [[-0.914, 0.601, 8.25, 1.548, 0.798, 0.02, 0], [-0.914, 0.601]], [[-0.078, -0.863, 3.994, 2.622, 1.462, 0.1, 0], [-0.078, -0.863]], [[-1.215, 0.2, 16.12, 1.251, 1.235, 0.02, 10], [-0.872021, 2.751611]], [[1.0, 0.0, 10.0, 1.0, 0.0, 0.05, 0], [1.0, 0.0]], [[-0.66, -0.547, 35.572, 2.632, 0.117, 0.05, 8], [-0.1546, 2.305749]], [[1.873, -0.51, 29.384, 1.99, 0.411, 0.2, 16], [1.352031, 0.801221]]]]
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.089549, 2.75242][0.446958, 3.829901]Failed
case 1[-0.104, -1.626][-0.104, -1.626]Passed
case 2[1.0, 0.0][1.0, 0.0]Passed
case 3[0.119694, 0.673873][0.12099, 0.699807]Failed
case 4[1.545, 1.962][1.545, 1.962]Passed
case 5[-1.158401, -6.921323][-0.971294, -6.107647]Failed
case 6[-1.35653, -0.676506][-1.357008, -0.700394]Failed
case 7[0.336433, -0.568618][0.30826, -0.689182]Failed

SHA-256 / 2971b521803ee055ff13bb69c5384bfa4536029f47fd87eeebfae9508920f20c

2 / The unsuccessful fix

Exit 1
"""Failure Map reference implementation. Python standard library only."""
import json
import math
N = 1
observations = []
def solve(x0, v0, k, m, c, dt, steps):
    n_sub = max(1, math.ceil(dt / 0.05 - 1e-12))
    h = dt / n_sub
    x, v = x0, v0
    for _ in range(steps):
        for _ in range(n_sub):
            a = (-k * x - c * v / m) / m
            v = v + a * h
            x = x + v * h
    return [round(x, 6), round(v, 6)]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[[[-1.484, 1.712, 27.312, 2.961, 1.788, 0.13, 4], [0.446958, 3.829901]], [[-0.104, -1.626, 5.159, 2.304, 0.637, 0.2, 0], [-0.104, -1.626]], [[1.0, 0.0, 10.0, 1.0, 0.0, 0.05, 0], [1.0, 0.0]], [[0.086, 0.733, 7.163, 2.307, 1.249, 0.05, 1], [0.12099, 0.699807]], [[1.545, 1.962, 22.255, 1.613, 1.385, 0.02, 0], [1.545, 1.962]], [[1.916, 1.522, 23.049, 0.619, 1.046, 0.2, 2], [-0.971294, -6.107647]], [[-1.343, -1.045, 36.463, 2.947, 1.73, 0.02, 1], [-1.357008, -0.700394]], [[0.567, -0.563, 3.019, 2.331, 1.024, 0.05, 8], [0.30826, -0.689182]]], [[[1.925, -0.173, 39.051, 1.209, 0.422, 0.01, 5], [1.824415, -3.211948]], [[-0.384, 0.483, 39.776, 2.351, 1.463, 0.04, 0], [-0.384, 0.483]], [[-1.087, 0.963, 34.734, 2.546, 1.868, 0.07, 9], [0.718936, 1.786483]], [[1.0, 0.0, 10.0, 1.0, 0.0, 0.05, 0], [1.0, 0.0]], [[1.742, -0.907, 38.421, 2.244, 0.819, 0.1, 5], [-1.031195, -5.442883]], [[-1.792, 1.668, 7.957, 1.875, 1.186, 0.04, 9], [-0.822549, 3.240967]], [[-1.669, -1.23, 27.053, 1.533, 0.991, 0.13, 5], [1.161742, 3.128527]], [[-1.46, -0.406, 15.912, 1.138, 0.653, 0.07, 0], [-1.46, -0.406]]], [[[-1.712, -1.9, 9.139, 0.693, 0.61, 0.05, 13], [0.624756, 4.351887]], [[0.6, -0.396, 35.253, 1.711, 1.361, 0.04, 8], [-0.018685, -2.456697]], [[1.207, 0.351, 14.617, 2.861, 0.895, 0.07, 6], [0.802339, -1.906391]], [[1.0, 0.0, 10.0, 1.0, 0.0, 0.05, 0], [1.0, 0.0]], [[1.648, -0.117, 24.609, 0.651, 1.732, 0.05, 0], [1.648, -0.117]], [[0.575, -1.191, 6.727, 1.218, 1.658, 0.2, 4], [-0.282948, -0.458231]], [[0.87, 1.182, 19.781, 1.146, 0.3, 0.1, 0], [0.87, 1.182]], [[0.566, 0.949, 26.197, 1.061, 0.815, 0.04, 4], [0.488626, -1.290634]]], [[[1.645, -1.841, 34.562, 1.534, 1.725, 0.2, 6], [0.803376, 1.245092]], [[-1.284, 1.069, 32.194, 0.542, 0.353, 0.05, 11], [0.174523, -8.251404]], [[-0.117, 1.853, 21.165, 2.719, 0.626, 0.07, 12], [0.503218, -0.957084]], [[0.484, 0.239, 12.355, 0.868, 0.3, 0.07, 0], [0.484, 0.239]], [[1.0, 0.0, 10.0, 1.0, 0.0, 0.05, 0], [1.0, 0.0]], [[1.074, -0.57, 32.767, 1.613, 0.402, 0.02, 7], [0.767571, -3.27442]], [[0.525, -0.515, 17.156, 2.442, 0.805, 0.05, 2], [0.447863, -0.851821]], [[1.977, 0.462, 36.991, 1.489, 1.033, 0.13, 0], [1.977, 0.462]]], [[[-1.576, -0.203, 24.72, 2.347, 1.363, 0.07, 10], [0.760633, 3.318988]], [[-1.172, -1.957, 14.575, 1.726, 0.305, 0.1, 12], [1.182005, 0.606601]], [[-0.914, 0.601, 8.25, 1.548, 0.798, 0.02, 0], [-0.914, 0.601]], [[-0.078, -0.863, 3.994, 2.622, 1.462, 0.1, 0], [-0.078, -0.863]], [[-1.215, 0.2, 16.12, 1.251, 1.235, 0.02, 10], [-0.872021, 2.751611]], [[1.0, 0.0, 10.0, 1.0, 0.0, 0.05, 0], [1.0, 0.0]], [[-0.66, -0.547, 35.572, 2.632, 0.117, 0.05, 8], [-0.1546, 2.305749]], [[1.873, -0.51, 29.384, 1.99, 0.411, 0.2, 16], [1.352031, 0.801221]]]]
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.595139, 4.326906][0.446958, 3.829901]Failed
case 1[-0.104, -1.626][-0.104, -1.626]Passed
case 2[1.0, 0.0][1.0, 0.0]Passed
case 3[0.121552, 0.711048][0.12099, 0.699807]Failed
case 4[1.545, 1.962][1.545, 1.962]Passed
case 5[-0.704987, -5.053863][-0.971294, -6.107647]Failed
case 6[-1.35717, -0.7085][-1.357008, -0.700394]Failed
case 7[0.294996, -0.748576][0.30826, -0.689182]Failed

SHA-256 / d0e7adac2473f0f11a1f3fa272b02feacaf79c5878688b099a06f15ee60363c7

3 / The verified repair

Exit 0
"""Failure Map reference implementation. Python standard library only."""
import json
import math
N = 1
observations = []
def solve(x0, v0, k, m, c, dt, steps):
    n_sub = max(1, math.ceil(dt / 0.05 - 1e-12))
    h = dt / n_sub
    x, v = x0, v0
    for _ in range(steps):
        for _ in range(n_sub):
            a = (-k * x - c * v) / m
            v = v + a * h
            x = x + v * h
    return [round(x, 6), round(v, 6)]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[[[-1.484, 1.712, 27.312, 2.961, 1.788, 0.13, 4], [0.446958, 3.829901]], [[-0.104, -1.626, 5.159, 2.304, 0.637, 0.2, 0], [-0.104, -1.626]], [[1.0, 0.0, 10.0, 1.0, 0.0, 0.05, 0], [1.0, 0.0]], [[0.086, 0.733, 7.163, 2.307, 1.249, 0.05, 1], [0.12099, 0.699807]], [[1.545, 1.962, 22.255, 1.613, 1.385, 0.02, 0], [1.545, 1.962]], [[1.916, 1.522, 23.049, 0.619, 1.046, 0.2, 2], [-0.971294, -6.107647]], [[-1.343, -1.045, 36.463, 2.947, 1.73, 0.02, 1], [-1.357008, -0.700394]], [[0.567, -0.563, 3.019, 2.331, 1.024, 0.05, 8], [0.30826, -0.689182]]], [[[1.925, -0.173, 39.051, 1.209, 0.422, 0.01, 5], [1.824415, -3.211948]], [[-0.384, 0.483, 39.776, 2.351, 1.463, 0.04, 0], [-0.384, 0.483]], [[-1.087, 0.963, 34.734, 2.546, 1.868, 0.07, 9], [0.718936, 1.786483]], [[1.0, 0.0, 10.0, 1.0, 0.0, 0.05, 0], [1.0, 0.0]], [[1.742, -0.907, 38.421, 2.244, 0.819, 0.1, 5], [-1.031195, -5.442883]], [[-1.792, 1.668, 7.957, 1.875, 1.186, 0.04, 9], [-0.822549, 3.240967]], [[-1.669, -1.23, 27.053, 1.533, 0.991, 0.13, 5], [1.161742, 3.128527]], [[-1.46, -0.406, 15.912, 1.138, 0.653, 0.07, 0], [-1.46, -0.406]]], [[[-1.712, -1.9, 9.139, 0.693, 0.61, 0.05, 13], [0.624756, 4.351887]], [[0.6, -0.396, 35.253, 1.711, 1.361, 0.04, 8], [-0.018685, -2.456697]], [[1.207, 0.351, 14.617, 2.861, 0.895, 0.07, 6], [0.802339, -1.906391]], [[1.0, 0.0, 10.0, 1.0, 0.0, 0.05, 0], [1.0, 0.0]], [[1.648, -0.117, 24.609, 0.651, 1.732, 0.05, 0], [1.648, -0.117]], [[0.575, -1.191, 6.727, 1.218, 1.658, 0.2, 4], [-0.282948, -0.458231]], [[0.87, 1.182, 19.781, 1.146, 0.3, 0.1, 0], [0.87, 1.182]], [[0.566, 0.949, 26.197, 1.061, 0.815, 0.04, 4], [0.488626, -1.290634]]], [[[1.645, -1.841, 34.562, 1.534, 1.725, 0.2, 6], [0.803376, 1.245092]], [[-1.284, 1.069, 32.194, 0.542, 0.353, 0.05, 11], [0.174523, -8.251404]], [[-0.117, 1.853, 21.165, 2.719, 0.626, 0.07, 12], [0.503218, -0.957084]], [[0.484, 0.239, 12.355, 0.868, 0.3, 0.07, 0], [0.484, 0.239]], [[1.0, 0.0, 10.0, 1.0, 0.0, 0.05, 0], [1.0, 0.0]], [[1.074, -0.57, 32.767, 1.613, 0.402, 0.02, 7], [0.767571, -3.27442]], [[0.525, -0.515, 17.156, 2.442, 0.805, 0.05, 2], [0.447863, -0.851821]], [[1.977, 0.462, 36.991, 1.489, 1.033, 0.13, 0], [1.977, 0.462]]], [[[-1.576, -0.203, 24.72, 2.347, 1.363, 0.07, 10], [0.760633, 3.318988]], [[-1.172, -1.957, 14.575, 1.726, 0.305, 0.1, 12], [1.182005, 0.606601]], [[-0.914, 0.601, 8.25, 1.548, 0.798, 0.02, 0], [-0.914, 0.601]], [[-0.078, -0.863, 3.994, 2.622, 1.462, 0.1, 0], [-0.078, -0.863]], [[-1.215, 0.2, 16.12, 1.251, 1.235, 0.02, 10], [-0.872021, 2.751611]], [[1.0, 0.0, 10.0, 1.0, 0.0, 0.05, 0], [1.0, 0.0]], [[-0.66, -0.547, 35.572, 2.632, 0.117, 0.05, 8], [-0.1546, 2.305749]], [[1.873, -0.51, 29.384, 1.99, 0.411, 0.2, 16], [1.352031, 0.801221]]]]
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.446958, 3.829901][0.446958, 3.829901]Passed
case 1[-0.104, -1.626][-0.104, -1.626]Passed
case 2[1.0, 0.0][1.0, 0.0]Passed
case 3[0.12099, 0.699807][0.12099, 0.699807]Passed
case 4[1.545, 1.962][1.545, 1.962]Passed
case 5[-0.971294, -6.107647][-0.971294, -6.107647]Passed
case 6[-1.357008, -0.700394][-1.357008, -0.700394]Passed
case 7[0.30826, -0.689182][0.30826, -0.689182]Passed

SHA-256 / 15926f856752c86fc1eb7b319ba2894e9cbd594d094d3fa3d79ae831ef44dad0

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

Case digest / 5d0b334a70eccb3cf65622c851e662d2dcc098b0b5b6ea5a5fe688b5c7fbeb7f