FA-86846 / Physics integrator stability / Open access
Spring restoring force pushes the mass away from rest · case 01
Displaced masses accelerate outward and the state grows exponentially.
ROOT CAUSE
The Hooke term is written +k*x, so the spring repels instead of restoring.
VERIFIED REPAIR
Use -k*x so the spring always accelerates the mass toward the rest position.
Unsuccessful approach: Using -k*abs(x) restores only on the positive side and pushes negative displacements further away.
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 - 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 = [[[[-0.104, -1.626, 5.159, 2.304, 0.637, 0.2, 0], [-0.104, -1.626]], [[-0.562, -1.226, 9.534, 1.694, 1.284, 0.13, 0], [-0.562, -1.226]], [[-1.786, -1.656, 13.016, 2.04, 1.641, 0.02, 1], [-1.814029, -1.40145]], [[0.685, -1.111, 8.677, 2.127, 1.752, 0.1, 8], [-0.325367, -0.873653]], [[-0.128, 1.776, 35.57, 0.657, 1.874, 0.04, 9], [0.123101, -0.690879]], [[1.0, 0.0, 10.0, 1.0, 0.0, 0.05, 0], [1.0, 0.0]], [[-1.072, -0.219, 22.982, 2.32, 1.666, 0.05, 1], [-1.056009, 0.319827]], [[0.514, 1.143, 25.432, 0.518, 1.496, 0.13, 9], [-0.010702, -0.661591]]], [[[1.742, -0.907, 38.421, 2.244, 0.819, 0.1, 5], [-1.031195, -5.442883]], [[-0.185, -0.874, 37.426, 1.485, 0.472, 0.04, 0], [-0.185, -0.874]], [[-0.365, 1.406, 18.892, 1.116, 1.872, 0.05, 6], [0.118578, 1.39259]], [[-1.356, 1.252, 26.385, 1.751, 0.173, 0.2, 5], [0.659131, -4.378629]], [[1.0, 0.0, 10.0, 1.0, 0.0, 0.05, 0], [1.0, 0.0]], [[-0.195, 1.451, 20.307, 2.688, 1.682, 0.1, 2], [0.095172, 1.395255]], [[1.907, 1.457, 31.983, 1.504, 0.494, 0.2, 0], [1.907, 1.457]], [[0.377, 1.608, 11.427, 2.764, 0.526, 0.13, 2], [0.705869, 0.97255]]], [[[-0.081, 1.898, 20.437, 2.775, 1.674, 0.04, 11], [0.532877, 0.702137]], [[0.87, 1.182, 19.781, 1.146, 0.3, 0.1, 0], [0.87, 1.182]], [[1.412, -1.43, 37.043, 2.676, 1.923, 0.01, 4], [1.33665, -2.148434]], [[0.0, 1.0, 4.0, 2.0, 0.5, 0.1, 3], [0.278786, 0.856518]], [[1.648, -0.117, 24.609, 0.651, 1.732, 0.05, 0], [1.648, -0.117]], [[1.0, 0.0, 10.0, 1.0, 0.0, 0.05, 0], [1.0, 0.0]], [[1.222, -1.354, 12.316, 2.895, 1.536, 0.2, 4], [-0.52136, -1.890917]], [[0.718, 1.584, 9.356, 1.657, 0.286, 0.02, 6], [0.869722, 1.022798]]], [[[-0.722, 1.788, 25.808, 1.535, 1.788, 0.01, 7], [-0.571189, 2.397082]], [[-0.981, -0.335, 12.78, 0.725, 0.124, 0.01, 16], [-0.805868, 2.27257]], [[0.76, 1.611, 15.529, 0.686, 0.511, 0.07, 14], [-0.242783, 2.493606]], [[1.977, 0.462, 36.991, 1.489, 1.033, 0.13, 0], [1.977, 0.462]], [[0.286, 1.636, 25.073, 1.437, 1.309, 0.1, 0], [0.286, 1.636]], [[-1.413, 0.664, 29.552, 2.975, 1.21, 0.13, 8], [1.104015, -1.060714]], [[0.0, 1.0, 4.0, 2.0, 0.5, 0.1, 3], [0.278786, 0.856518]], [[1.0, 0.0, 10.0, 1.0, 0.0, 0.05, 0], [1.0, 0.0]]], [[[-1.215, 0.2, 16.12, 1.251, 1.235, 0.02, 10], [-0.872021, 2.751611]], [[1.873, -0.51, 29.384, 1.99, 0.411, 0.2, 16], [1.352031, 0.801221]], [[-0.078, -0.863, 3.994, 2.622, 1.462, 0.1, 0], [-0.078, -0.863]], [[-0.914, 0.601, 8.25, 1.548, 0.798, 0.02, 0], [-0.914, 0.601]], [[1.0, 0.0, 10.0, 1.0, 0.0, 0.05, 0], [1.0, 0.0]], [[1.925, -1.211, 19.503, 2.115, 0.02, 0.13, 1], [1.574252, -3.400654]], [[-0.584, 1.144, 23.196, 1.052, 0.941, 0.2, 20], [-0.08891, 0.230159]], [[0.36, -1.513, 9.018, 1.848, 0.394, 0.05, 8], [-0.288846, -1.518381]]]]
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 | [-0.104, -1.626] | [-0.104, -1.626] | Passed |
| case 1 | [-0.562, -1.226] | [-0.562, -1.226] | Passed |
| case 2 | [-1.823145, -1.857265] | [-1.814029, -1.40145] | Failed |
| case 3 | [0.704864, 0.82706] | [-0.325367, -0.873653] | Failed |
| case 4 | [0.189531, 1.128832] | [0.123101, -0.690879] | Failed |
| case 5 | [1.0, 0.0] | [1.0, 0.0] | Passed |
| case 6 | [-1.109105, -0.7421] | [-1.056009, 0.319827] | Failed |
| case 7 | [386.76113, 1993.561829] | [-0.010702, -0.661591] | Failed |
SHA-256 / 49f8e462687102f105493a82c73eb1ae362f30642828e7e84e0bd6c27f3855c9
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 * abs(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 = [[[[-0.104, -1.626, 5.159, 2.304, 0.637, 0.2, 0], [-0.104, -1.626]], [[-0.562, -1.226, 9.534, 1.694, 1.284, 0.13, 0], [-0.562, -1.226]], [[-1.786, -1.656, 13.016, 2.04, 1.641, 0.02, 1], [-1.814029, -1.40145]], [[0.685, -1.111, 8.677, 2.127, 1.752, 0.1, 8], [-0.325367, -0.873653]], [[-0.128, 1.776, 35.57, 0.657, 1.874, 0.04, 9], [0.123101, -0.690879]], [[1.0, 0.0, 10.0, 1.0, 0.0, 0.05, 0], [1.0, 0.0]], [[-1.072, -0.219, 22.982, 2.32, 1.666, 0.05, 1], [-1.056009, 0.319827]], [[0.514, 1.143, 25.432, 0.518, 1.496, 0.13, 9], [-0.010702, -0.661591]]], [[[1.742, -0.907, 38.421, 2.244, 0.819, 0.1, 5], [-1.031195, -5.442883]], [[-0.185, -0.874, 37.426, 1.485, 0.472, 0.04, 0], [-0.185, -0.874]], [[-0.365, 1.406, 18.892, 1.116, 1.872, 0.05, 6], [0.118578, 1.39259]], [[-1.356, 1.252, 26.385, 1.751, 0.173, 0.2, 5], [0.659131, -4.378629]], [[1.0, 0.0, 10.0, 1.0, 0.0, 0.05, 0], [1.0, 0.0]], [[-0.195, 1.451, 20.307, 2.688, 1.682, 0.1, 2], [0.095172, 1.395255]], [[1.907, 1.457, 31.983, 1.504, 0.494, 0.2, 0], [1.907, 1.457]], [[0.377, 1.608, 11.427, 2.764, 0.526, 0.13, 2], [0.705869, 0.97255]]], [[[-0.081, 1.898, 20.437, 2.775, 1.674, 0.04, 11], [0.532877, 0.702137]], [[0.87, 1.182, 19.781, 1.146, 0.3, 0.1, 0], [0.87, 1.182]], [[1.412, -1.43, 37.043, 2.676, 1.923, 0.01, 4], [1.33665, -2.148434]], [[0.0, 1.0, 4.0, 2.0, 0.5, 0.1, 3], [0.278786, 0.856518]], [[1.648, -0.117, 24.609, 0.651, 1.732, 0.05, 0], [1.648, -0.117]], [[1.0, 0.0, 10.0, 1.0, 0.0, 0.05, 0], [1.0, 0.0]], [[1.222, -1.354, 12.316, 2.895, 1.536, 0.2, 4], [-0.52136, -1.890917]], [[0.718, 1.584, 9.356, 1.657, 0.286, 0.02, 6], [0.869722, 1.022798]]], [[[-0.722, 1.788, 25.808, 1.535, 1.788, 0.01, 7], [-0.571189, 2.397082]], [[-0.981, -0.335, 12.78, 0.725, 0.124, 0.01, 16], [-0.805868, 2.27257]], [[0.76, 1.611, 15.529, 0.686, 0.511, 0.07, 14], [-0.242783, 2.493606]], [[1.977, 0.462, 36.991, 1.489, 1.033, 0.13, 0], [1.977, 0.462]], [[0.286, 1.636, 25.073, 1.437, 1.309, 0.1, 0], [0.286, 1.636]], [[-1.413, 0.664, 29.552, 2.975, 1.21, 0.13, 8], [1.104015, -1.060714]], [[0.0, 1.0, 4.0, 2.0, 0.5, 0.1, 3], [0.278786, 0.856518]], [[1.0, 0.0, 10.0, 1.0, 0.0, 0.05, 0], [1.0, 0.0]]], [[[-1.215, 0.2, 16.12, 1.251, 1.235, 0.02, 10], [-0.872021, 2.751611]], [[1.873, -0.51, 29.384, 1.99, 0.411, 0.2, 16], [1.352031, 0.801221]], [[-0.078, -0.863, 3.994, 2.622, 1.462, 0.1, 0], [-0.078, -0.863]], [[-0.914, 0.601, 8.25, 1.548, 0.798, 0.02, 0], [-0.914, 0.601]], [[1.0, 0.0, 10.0, 1.0, 0.0, 0.05, 0], [1.0, 0.0]], [[1.925, -1.211, 19.503, 2.115, 0.02, 0.13, 1], [1.574252, -3.400654]], [[-0.584, 1.144, 23.196, 1.052, 0.941, 0.2, 20], [-0.08891, 0.230159]], [[0.36, -1.513, 9.018, 1.848, 0.394, 0.05, 8], [-0.288846, -1.518381]]]]
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 | [-0.104, -1.626] | [-0.104, -1.626] | Passed |
| case 1 | [-0.562, -1.226] | [-0.562, -1.226] | Passed |
| case 2 | [-1.823145, -1.857265] | [-1.814029, -1.40145] | Failed |
| case 3 | [-0.366875, -1.221102] | [-0.325367, -0.873653] | Failed |
| case 4 | [0.067202, -0.114341] | [0.123101, -0.690879] | Failed |
| case 5 | [1.0, 0.0] | [1.0, 0.0] | Passed |
| case 6 | [-1.109105, -0.7421] | [-1.056009, 0.319827] | Failed |
| case 7 | [-32.671793, -168.407784] | [-0.010702, -0.661591] | Failed |
SHA-256 / 9172e55a98852b2b1a7c0d0279ccefcebe1ad10d31215462a6e2460f19c2f507
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 = [[[[-0.104, -1.626, 5.159, 2.304, 0.637, 0.2, 0], [-0.104, -1.626]], [[-0.562, -1.226, 9.534, 1.694, 1.284, 0.13, 0], [-0.562, -1.226]], [[-1.786, -1.656, 13.016, 2.04, 1.641, 0.02, 1], [-1.814029, -1.40145]], [[0.685, -1.111, 8.677, 2.127, 1.752, 0.1, 8], [-0.325367, -0.873653]], [[-0.128, 1.776, 35.57, 0.657, 1.874, 0.04, 9], [0.123101, -0.690879]], [[1.0, 0.0, 10.0, 1.0, 0.0, 0.05, 0], [1.0, 0.0]], [[-1.072, -0.219, 22.982, 2.32, 1.666, 0.05, 1], [-1.056009, 0.319827]], [[0.514, 1.143, 25.432, 0.518, 1.496, 0.13, 9], [-0.010702, -0.661591]]], [[[1.742, -0.907, 38.421, 2.244, 0.819, 0.1, 5], [-1.031195, -5.442883]], [[-0.185, -0.874, 37.426, 1.485, 0.472, 0.04, 0], [-0.185, -0.874]], [[-0.365, 1.406, 18.892, 1.116, 1.872, 0.05, 6], [0.118578, 1.39259]], [[-1.356, 1.252, 26.385, 1.751, 0.173, 0.2, 5], [0.659131, -4.378629]], [[1.0, 0.0, 10.0, 1.0, 0.0, 0.05, 0], [1.0, 0.0]], [[-0.195, 1.451, 20.307, 2.688, 1.682, 0.1, 2], [0.095172, 1.395255]], [[1.907, 1.457, 31.983, 1.504, 0.494, 0.2, 0], [1.907, 1.457]], [[0.377, 1.608, 11.427, 2.764, 0.526, 0.13, 2], [0.705869, 0.97255]]], [[[-0.081, 1.898, 20.437, 2.775, 1.674, 0.04, 11], [0.532877, 0.702137]], [[0.87, 1.182, 19.781, 1.146, 0.3, 0.1, 0], [0.87, 1.182]], [[1.412, -1.43, 37.043, 2.676, 1.923, 0.01, 4], [1.33665, -2.148434]], [[0.0, 1.0, 4.0, 2.0, 0.5, 0.1, 3], [0.278786, 0.856518]], [[1.648, -0.117, 24.609, 0.651, 1.732, 0.05, 0], [1.648, -0.117]], [[1.0, 0.0, 10.0, 1.0, 0.0, 0.05, 0], [1.0, 0.0]], [[1.222, -1.354, 12.316, 2.895, 1.536, 0.2, 4], [-0.52136, -1.890917]], [[0.718, 1.584, 9.356, 1.657, 0.286, 0.02, 6], [0.869722, 1.022798]]], [[[-0.722, 1.788, 25.808, 1.535, 1.788, 0.01, 7], [-0.571189, 2.397082]], [[-0.981, -0.335, 12.78, 0.725, 0.124, 0.01, 16], [-0.805868, 2.27257]], [[0.76, 1.611, 15.529, 0.686, 0.511, 0.07, 14], [-0.242783, 2.493606]], [[1.977, 0.462, 36.991, 1.489, 1.033, 0.13, 0], [1.977, 0.462]], [[0.286, 1.636, 25.073, 1.437, 1.309, 0.1, 0], [0.286, 1.636]], [[-1.413, 0.664, 29.552, 2.975, 1.21, 0.13, 8], [1.104015, -1.060714]], [[0.0, 1.0, 4.0, 2.0, 0.5, 0.1, 3], [0.278786, 0.856518]], [[1.0, 0.0, 10.0, 1.0, 0.0, 0.05, 0], [1.0, 0.0]]], [[[-1.215, 0.2, 16.12, 1.251, 1.235, 0.02, 10], [-0.872021, 2.751611]], [[1.873, -0.51, 29.384, 1.99, 0.411, 0.2, 16], [1.352031, 0.801221]], [[-0.078, -0.863, 3.994, 2.622, 1.462, 0.1, 0], [-0.078, -0.863]], [[-0.914, 0.601, 8.25, 1.548, 0.798, 0.02, 0], [-0.914, 0.601]], [[1.0, 0.0, 10.0, 1.0, 0.0, 0.05, 0], [1.0, 0.0]], [[1.925, -1.211, 19.503, 2.115, 0.02, 0.13, 1], [1.574252, -3.400654]], [[-0.584, 1.144, 23.196, 1.052, 0.941, 0.2, 20], [-0.08891, 0.230159]], [[0.36, -1.513, 9.018, 1.848, 0.394, 0.05, 8], [-0.288846, -1.518381]]]]
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 | [-0.104, -1.626] | [-0.104, -1.626] | Passed |
| case 1 | [-0.562, -1.226] | [-0.562, -1.226] | Passed |
| case 2 | [-1.814029, -1.40145] | [-1.814029, -1.40145] | Passed |
| case 3 | [-0.325367, -0.873653] | [-0.325367, -0.873653] | Passed |
| case 4 | [0.123101, -0.690879] | [0.123101, -0.690879] | Passed |
| case 5 | [1.0, 0.0] | [1.0, 0.0] | Passed |
| case 6 | [-1.056009, 0.319827] | [-1.056009, 0.319827] | Passed |
| case 7 | [-0.010702, -0.661591] | [-0.010702, -0.661591] | Passed |
SHA-256 / e5b6831d6f5e316bfcdc58257b4573d5388fcdb092dd139c747f99027a609f4a
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.362540+00:00.
Case digest / 0be1e19aeafa46be965cdf430f101c5fef05673227976fbf88ce89881de114cd