FA-87156 / Physics integrator stability / Open access
Quaternion derivative omits the one-half factor · case 01
Bodies spin at twice the commanded angular velocity.
ROOT CAUSE
The update adds dt*omega(x)q instead of 0.5*dt*omega(x)q.
VERIFIED REPAIR
q_dot = 0.5*omega(x)q.
Unsuccessful approach: Dropping dt instead applies a frame-rate dependent rotation.
Case contract
solve(q, omega, dt, steps): orientation quaternion [w,x,y,z], world-frame angular velocity omega. Each step q += 0.5*dt*(0,omega) (x) q (Hamilton product, omega on the left), then renormalize to unit length. Return q with w>=0 (negate all components otherwise), 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(q, omega, dt, steps):
def mul(a, b):
aw, ax, ay, az = a
bw, bx, by, bz = b
return [aw * bw - ax * bx - ay * by - az * bz,
aw * bx + ax * bw + ay * bz - az * by,
aw * by - ax * bz + ay * bw + az * bx,
aw * bz + ax * by - ay * bx + az * bw]
w = [0.0, omega[0], omega[1], omega[2]]
q = list(q)
for _ in range(steps):
d = mul(w, q)
q = [q[i] + dt * d[i] for i in range(4)]
n = math.sqrt(sum(c * c for c in q))
q = [c / n for c in q]
if q[0] < 0:
q = [-c for c in q]
return [round(c, 6) for c in q]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[[[[-0.2977, -0.6395, -0.6771, 0.2095], [-1.197, 2.519, 1.023], 0.01, 4], [0.282677, 0.606876, 0.698978, -0.251447]], [[[0.6028, 0.36, 0.6862, -0.1904], [-3.11, 3.795, -3.272], 0.01, 3], [0.568856, 0.353305, 0.691238, -0.271603]], [[[-0.1116, -0.6859, -0.2807, 0.6621], [-1.367, -3.32, -3.869], 0.05, 1], [0.093483, 0.757592, 0.180891, -0.620156]], [[[-0.6434, -0.5565, -0.5031, -0.1523], [-2.902, -3.621, 0.012], 0.05, 6], [0.967882, 0.094358, 0.128105, 0.194656]], [[[-0.097, -0.8118, -0.5153, 0.2571], [-3.033, 1.673, -3.711], 0.05, 4], [0.14645, 0.823671, 0.10506, -0.537663]], [[[0.1693, 0.5991, -0.3007, 0.7225], [-0.846, 0.203, 2.272], 0.1, 5], [0.11186, -0.653252, -0.222024, -0.71516]], [[[0.5438, 0.3302, -0.6582, 0.4024], [-2.872, -3.023, 2.126], 0.05, 4], [0.303775, 0.162656, -0.567546, 0.747767]], [[[0.5461, -0.5658, -0.6174, 0.02], [3.4, 1.942, -0.278], 0.1, 1], [0.689383, -0.470639, -0.549444, -0.036907]]], [[[[0.0263, -0.6798, 0.6943, 0.2347], [-2.851, -1.309, 1.331], 0.01, 4], [0.000571, 0.704341, -0.687306, -0.177522]], [[[-0.4028, 0.5372, 0.3775, -0.6377], [-2.487, -2.209, -0.784], 0.05, 1], [0.359741, -0.602665, -0.348298, 0.621346]], [[[-0.5078, 0.518, 0.6345, -0.2667], [-3.853, 1.735, 2.833], 0.1, 8], [0.503958, -0.266597, -0.338951, -0.748375]], [[[-0.6101, 0.4489, 0.5803, -0.2993], [-1.836, 0.702, 0.387], 0.1, 4], [0.458708, -0.546596, -0.378574, 0.589493]], [[[-0.6201, 0.2564, 0.3917, 0.6295], [-3.231, 0.2, 3.992], 0.1, 6], [0.380514, -0.125653, -0.593787, 0.697738]], [[[0.3814, -0.2986, 0.1575, 0.8605], [-3.688, 1.133, -3.049], 0.01, 8], [0.427474, -0.29093, 0.333927, 0.788111]], [[[0.8268, -0.0559, 0.3935, 0.398], [-0.387, 0.922, 1.986], 0.1, 7], [0.220922, -0.271091, 0.534556, 0.769385]], [[[0.5942, -0.6772, -0.0493, -0.4313], [3.399, 0.94, 0.682], 0.1, 1], [0.714833, -0.585403, 0.028378, -0.381461]]], [[[[-0.5755, -0.1729, 0.1896, -0.7765], [-1.564, 1.954, -3.317], 0.01, 5], [0.652658, 0.171677, -0.144528, 0.723655]], [[[0.7604, -0.3417, -0.0319, -0.5514], [-0.767, -1.411, 1.303], 0.01, 10], [0.77686, -0.328074, -0.128606, -0.52184]], [[[0.5865, 0.3862, 0.1527, 0.6954], [1.063, 0.714, -1.361], 0.05, 10], [0.626543, 0.664653, -0.067408, 0.401418]], [[[-0.7395, -0.3308, 0.5863, -0.0042], [-0.888, 0.133, 0.72], 0.01, 5], [0.74839, 0.324806, -0.577536, 0.029421]], [[[-0.3438, -0.8064, 0.2793, -0.3918], [0.487, -0.414, 0.563], 0.05, 6], [0.231973, 0.824132, -0.258947, 0.447149]], [[[0.4999, -0.5863, 0.4671, 0.4339], [2.074, -2.687, 0.552], 0.01, 9], [0.593908, -0.596606, 0.346469, 0.413876]], [[[-0.5477, -0.5732, 0.5822, 0.1802], [-0.237, 0.825, 0.304], 0.05, 3], [0.596708, 0.564271, -0.53714, -0.192402]], [[[-0.571, 0.1155, 0.5121, 0.6312], [2.085, -1.83, -1.285], 0.01, 1], [0.563386, -0.107047, -0.509932, -0.641176]]], [[[[0.3666, 0.5064, 0.4609, -0.6299], [3.995, -0.841, 3.579], 0.01, 5], [0.378645, 0.510325, 0.556833, -0.534914]], [[[0.4219, -0.4687, 0.5689, 0.5279], [0.463, -2.547, 1.302], 0.01, 12], [0.47396, -0.574451, 0.445159, 0.497194]], [[[0.2873, -0.6346, 0.6402, -0.324], [3.029, -0.324, 1.16], 0.1, 8], [0.817944, -0.105726, 0.220751, 0.520633]], [[[0.2307, 0.3931, 0.7631, -0.4581], [2.174, 2.113, 3.444], 0.05, 10], [0.080385, 0.450009, -0.879659, -0.131262]], [[[0.3265, 0.31, 0.1591, -0.8786], [-1.35, 2.136, -0.561], 0.01, 12], [0.297825, 0.173125, 0.117593, -0.931397]], [[[0.1401, -0.0998, 0.7197, 0.6726], [-3.242, -3.373, -3.717], 0.01, 11], [0.381235, -0.097044, 0.793491, 0.464343]], [[[0.2076, -0.1442, 0.9556, -0.1516], [2.825, 3.025, 3.659], 0.05, 2], [0.1052, -0.304075, 0.945742, 0.045198]], [[[-0.6707, -0.6061, 0.269, -0.3322], [3.574, -3.249, 3.855], 0.01, 11], [0.399347, 0.698471, -0.309175, 0.507021]]], [[[[-0.5935, 0.4863, -0.2285, -0.5992], [-3.647, -1.427, -2.483], 0.01, 8], [0.584933, -0.575475, 0.325818, 0.4696]], [[[0.0332, -0.1691, -0.7704, -0.6138], [2.17, 2.479, 1.5], 0.1, 9], [0.881211, -0.074251, 0.351735, -0.30698]], [[[-0.0537, -0.8252, -0.3784, 0.4159], [1.996, 0.032, -1.898], 0.01, 4], [0.004675, 0.840181, 0.363147, -0.402737]], [[[0.5273, 0.4224, -0.4746, 0.5641], [-2.08, 3.628, 3.896], 0.01, 13], [0.516939, 0.571342, -0.141768, 0.621485]], [[[0.146, 0.3762, -0.3041, -0.8629], [2.493, -0.838, 1.176], 0.1, 9], [0.018505, -0.586628, -0.738668, 0.331504]], [[[0.6849, 0.5407, -0.2962, 0.3882], [-0.491, 1.404, -3.859], 0.1, 6], [0.728679, -0.028374, -0.313273, -0.608344]], [[[0.1094, 0.2843, 0.727, 0.6154], [3.004, -3.908, 3.399], 0.05, 2], [0.099484, 0.04945, 0.631065, 0.767733]], [[[0.1785, -0.1228, -0.7653, 0.6061], [2.105, 0.281, 2.09], 0.01, 8], [0.145584, -0.036317, -0.819027, 0.553788]]]]
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.266654, 0.572107, 0.718362, -0.292482] | [0.282677, 0.606876, 0.698978, -0.251447] | Failed |
| case 1 | [0.530564, 0.343884, 0.69091, -0.350556] | [0.568856, 0.353305, 0.691238, -0.271603] | Failed |
| case 2 | [0.074442, 0.814558, 0.081441, -0.569492] | [0.093483, 0.757592, 0.180891, -0.620156] | Failed |
| case 3 | [0.85468, -0.399674, -0.295696, 0.149487] | [0.967882, 0.094358, 0.128105, 0.194656] | Failed |
| case 4 | [0.159557, 0.63869, -0.318607, -0.681987] | [0.14645, 0.823671, 0.10506, -0.537663] | Failed |
| case 5 | [0.347814, -0.483199, -0.655907, -0.464037] | [0.11186, -0.653252, -0.222024, -0.71516] | Failed |
| case 6 | [0.007311, -0.034152, -0.362678, 0.93126] | [0.303775, 0.162656, -0.567546, 0.747767] | Failed |
| case 7 | [0.799559, -0.366214, -0.467692, -0.088638] | [0.689383, -0.470639, -0.549444, -0.036907] | Failed |
SHA-256 / a26296c9179e1fa760c38b6dea46757e578515232db1f55553014a3bd2c6afe7
2 / The unsuccessful fix
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
import math
N = 1
observations = []
def solve(q, omega, dt, steps):
def mul(a, b):
aw, ax, ay, az = a
bw, bx, by, bz = b
return [aw * bw - ax * bx - ay * by - az * bz,
aw * bx + ax * bw + ay * bz - az * by,
aw * by - ax * bz + ay * bw + az * bx,
aw * bz + ax * by - ay * bx + az * bw]
w = [0.0, omega[0], omega[1], omega[2]]
q = list(q)
for _ in range(steps):
d = mul(w, q)
q = [q[i] + 0.5 * d[i] for i in range(4)]
n = math.sqrt(sum(c * c for c in q))
q = [c / n for c in q]
if q[0] < 0:
q = [-c for c in q]
return [round(c, 6) for c in q]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[[[[-0.2977, -0.6395, -0.6771, 0.2095], [-1.197, 2.519, 1.023], 0.01, 4], [0.282677, 0.606876, 0.698978, -0.251447]], [[[0.6028, 0.36, 0.6862, -0.1904], [-3.11, 3.795, -3.272], 0.01, 3], [0.568856, 0.353305, 0.691238, -0.271603]], [[[-0.1116, -0.6859, -0.2807, 0.6621], [-1.367, -3.32, -3.869], 0.05, 1], [0.093483, 0.757592, 0.180891, -0.620156]], [[[-0.6434, -0.5565, -0.5031, -0.1523], [-2.902, -3.621, 0.012], 0.05, 6], [0.967882, 0.094358, 0.128105, 0.194656]], [[[-0.097, -0.8118, -0.5153, 0.2571], [-3.033, 1.673, -3.711], 0.05, 4], [0.14645, 0.823671, 0.10506, -0.537663]], [[[0.1693, 0.5991, -0.3007, 0.7225], [-0.846, 0.203, 2.272], 0.1, 5], [0.11186, -0.653252, -0.222024, -0.71516]], [[[0.5438, 0.3302, -0.6582, 0.4024], [-2.872, -3.023, 2.126], 0.05, 4], [0.303775, 0.162656, -0.567546, 0.747767]], [[[0.5461, -0.5658, -0.6174, 0.02], [3.4, 1.942, -0.278], 0.1, 1], [0.689383, -0.470639, -0.549444, -0.036907]]], [[[[0.0263, -0.6798, 0.6943, 0.2347], [-2.851, -1.309, 1.331], 0.01, 4], [0.000571, 0.704341, -0.687306, -0.177522]], [[[-0.4028, 0.5372, 0.3775, -0.6377], [-2.487, -2.209, -0.784], 0.05, 1], [0.359741, -0.602665, -0.348298, 0.621346]], [[[-0.5078, 0.518, 0.6345, -0.2667], [-3.853, 1.735, 2.833], 0.1, 8], [0.503958, -0.266597, -0.338951, -0.748375]], [[[-0.6101, 0.4489, 0.5803, -0.2993], [-1.836, 0.702, 0.387], 0.1, 4], [0.458708, -0.546596, -0.378574, 0.589493]], [[[-0.6201, 0.2564, 0.3917, 0.6295], [-3.231, 0.2, 3.992], 0.1, 6], [0.380514, -0.125653, -0.593787, 0.697738]], [[[0.3814, -0.2986, 0.1575, 0.8605], [-3.688, 1.133, -3.049], 0.01, 8], [0.427474, -0.29093, 0.333927, 0.788111]], [[[0.8268, -0.0559, 0.3935, 0.398], [-0.387, 0.922, 1.986], 0.1, 7], [0.220922, -0.271091, 0.534556, 0.769385]], [[[0.5942, -0.6772, -0.0493, -0.4313], [3.399, 0.94, 0.682], 0.1, 1], [0.714833, -0.585403, 0.028378, -0.381461]]], [[[[-0.5755, -0.1729, 0.1896, -0.7765], [-1.564, 1.954, -3.317], 0.01, 5], [0.652658, 0.171677, -0.144528, 0.723655]], [[[0.7604, -0.3417, -0.0319, -0.5514], [-0.767, -1.411, 1.303], 0.01, 10], [0.77686, -0.328074, -0.128606, -0.52184]], [[[0.5865, 0.3862, 0.1527, 0.6954], [1.063, 0.714, -1.361], 0.05, 10], [0.626543, 0.664653, -0.067408, 0.401418]], [[[-0.7395, -0.3308, 0.5863, -0.0042], [-0.888, 0.133, 0.72], 0.01, 5], [0.74839, 0.324806, -0.577536, 0.029421]], [[[-0.3438, -0.8064, 0.2793, -0.3918], [0.487, -0.414, 0.563], 0.05, 6], [0.231973, 0.824132, -0.258947, 0.447149]], [[[0.4999, -0.5863, 0.4671, 0.4339], [2.074, -2.687, 0.552], 0.01, 9], [0.593908, -0.596606, 0.346469, 0.413876]], [[[-0.5477, -0.5732, 0.5822, 0.1802], [-0.237, 0.825, 0.304], 0.05, 3], [0.596708, 0.564271, -0.53714, -0.192402]], [[[-0.571, 0.1155, 0.5121, 0.6312], [2.085, -1.83, -1.285], 0.01, 1], [0.563386, -0.107047, -0.509932, -0.641176]]], [[[[0.3666, 0.5064, 0.4609, -0.6299], [3.995, -0.841, 3.579], 0.01, 5], [0.378645, 0.510325, 0.556833, -0.534914]], [[[0.4219, -0.4687, 0.5689, 0.5279], [0.463, -2.547, 1.302], 0.01, 12], [0.47396, -0.574451, 0.445159, 0.497194]], [[[0.2873, -0.6346, 0.6402, -0.324], [3.029, -0.324, 1.16], 0.1, 8], [0.817944, -0.105726, 0.220751, 0.520633]], [[[0.2307, 0.3931, 0.7631, -0.4581], [2.174, 2.113, 3.444], 0.05, 10], [0.080385, 0.450009, -0.879659, -0.131262]], [[[0.3265, 0.31, 0.1591, -0.8786], [-1.35, 2.136, -0.561], 0.01, 12], [0.297825, 0.173125, 0.117593, -0.931397]], [[[0.1401, -0.0998, 0.7197, 0.6726], [-3.242, -3.373, -3.717], 0.01, 11], [0.381235, -0.097044, 0.793491, 0.464343]], [[[0.2076, -0.1442, 0.9556, -0.1516], [2.825, 3.025, 3.659], 0.05, 2], [0.1052, -0.304075, 0.945742, 0.045198]], [[[-0.6707, -0.6061, 0.269, -0.3322], [3.574, -3.249, 3.855], 0.01, 11], [0.399347, 0.698471, -0.309175, 0.507021]]], [[[[-0.5935, 0.4863, -0.2285, -0.5992], [-3.647, -1.427, -2.483], 0.01, 8], [0.584933, -0.575475, 0.325818, 0.4696]], [[[0.0332, -0.1691, -0.7704, -0.6138], [2.17, 2.479, 1.5], 0.1, 9], [0.881211, -0.074251, 0.351735, -0.30698]], [[[-0.0537, -0.8252, -0.3784, 0.4159], [1.996, 0.032, -1.898], 0.01, 4], [0.004675, 0.840181, 0.363147, -0.402737]], [[[0.5273, 0.4224, -0.4746, 0.5641], [-2.08, 3.628, 3.896], 0.01, 13], [0.516939, 0.571342, -0.141768, 0.621485]], [[[0.146, 0.3762, -0.3041, -0.8629], [2.493, -0.838, 1.176], 0.1, 9], [0.018505, -0.586628, -0.738668, 0.331504]], [[[0.6849, 0.5407, -0.2962, 0.3882], [-0.491, 1.404, -3.859], 0.1, 6], [0.728679, -0.028374, -0.313273, -0.608344]], [[[0.1094, 0.2843, 0.727, 0.6154], [3.004, -3.908, 3.399], 0.05, 2], [0.099484, 0.04945, 0.631065, 0.767733]], [[[0.1785, -0.1228, -0.7653, 0.6061], [2.105, 0.281, 2.09], 0.01, 8], [0.145584, -0.036317, -0.819027, 0.553788]]]]
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.043105, 0.088464, 0.756124, -0.646987] | [0.282677, 0.606876, 0.698978, -0.251447] | Failed |
| case 1 | [0.302104, 0.265935, 0.619013, -0.674414] | [0.568856, 0.353305, 0.691238, -0.271603] | Failed |
| case 2 | [0.083072, -0.797815, 0.596655, -0.024357] | [0.093483, 0.757592, 0.180891, -0.620156] | Failed |
| case 3 | [0.968967, 0.089056, 0.123671, 0.194623] | [0.967882, 0.094358, 0.128105, 0.194656] | Failed |
| case 4 | [0.120201, 0.177017, -0.749161, -0.626877] | [0.14645, 0.823671, 0.10506, -0.537663] | Failed |
| case 5 | [0.371945, -0.446022, -0.699842, -0.415864] | [0.11186, -0.653252, -0.222024, -0.71516] | Failed |
| case 6 | [0.380708, 0.279644, -0.016354, -0.881245] | [0.303775, 0.162656, -0.567546, 0.747767] | Failed |
| case 7 | [0.958025, 0.134459, -0.01929, -0.252462] | [0.689383, -0.470639, -0.549444, -0.036907] | Failed |
SHA-256 / 80db11026080c0071b1f3f2b17dedcb357d5332fd3dfb0c4bfe4398becfcaf77
3 / The verified repair
Exit 0"""Failure Map reference implementation. Python standard library only."""
import json
import math
N = 1
observations = []
def solve(q, omega, dt, steps):
def mul(a, b):
aw, ax, ay, az = a
bw, bx, by, bz = b
return [aw * bw - ax * bx - ay * by - az * bz,
aw * bx + ax * bw + ay * bz - az * by,
aw * by - ax * bz + ay * bw + az * bx,
aw * bz + ax * by - ay * bx + az * bw]
w = [0.0, omega[0], omega[1], omega[2]]
q = list(q)
for _ in range(steps):
d = mul(w, q)
q = [q[i] + 0.5 * dt * d[i] for i in range(4)]
n = math.sqrt(sum(c * c for c in q))
q = [c / n for c in q]
if q[0] < 0:
q = [-c for c in q]
return [round(c, 6) for c in q]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[[[[-0.2977, -0.6395, -0.6771, 0.2095], [-1.197, 2.519, 1.023], 0.01, 4], [0.282677, 0.606876, 0.698978, -0.251447]], [[[0.6028, 0.36, 0.6862, -0.1904], [-3.11, 3.795, -3.272], 0.01, 3], [0.568856, 0.353305, 0.691238, -0.271603]], [[[-0.1116, -0.6859, -0.2807, 0.6621], [-1.367, -3.32, -3.869], 0.05, 1], [0.093483, 0.757592, 0.180891, -0.620156]], [[[-0.6434, -0.5565, -0.5031, -0.1523], [-2.902, -3.621, 0.012], 0.05, 6], [0.967882, 0.094358, 0.128105, 0.194656]], [[[-0.097, -0.8118, -0.5153, 0.2571], [-3.033, 1.673, -3.711], 0.05, 4], [0.14645, 0.823671, 0.10506, -0.537663]], [[[0.1693, 0.5991, -0.3007, 0.7225], [-0.846, 0.203, 2.272], 0.1, 5], [0.11186, -0.653252, -0.222024, -0.71516]], [[[0.5438, 0.3302, -0.6582, 0.4024], [-2.872, -3.023, 2.126], 0.05, 4], [0.303775, 0.162656, -0.567546, 0.747767]], [[[0.5461, -0.5658, -0.6174, 0.02], [3.4, 1.942, -0.278], 0.1, 1], [0.689383, -0.470639, -0.549444, -0.036907]]], [[[[0.0263, -0.6798, 0.6943, 0.2347], [-2.851, -1.309, 1.331], 0.01, 4], [0.000571, 0.704341, -0.687306, -0.177522]], [[[-0.4028, 0.5372, 0.3775, -0.6377], [-2.487, -2.209, -0.784], 0.05, 1], [0.359741, -0.602665, -0.348298, 0.621346]], [[[-0.5078, 0.518, 0.6345, -0.2667], [-3.853, 1.735, 2.833], 0.1, 8], [0.503958, -0.266597, -0.338951, -0.748375]], [[[-0.6101, 0.4489, 0.5803, -0.2993], [-1.836, 0.702, 0.387], 0.1, 4], [0.458708, -0.546596, -0.378574, 0.589493]], [[[-0.6201, 0.2564, 0.3917, 0.6295], [-3.231, 0.2, 3.992], 0.1, 6], [0.380514, -0.125653, -0.593787, 0.697738]], [[[0.3814, -0.2986, 0.1575, 0.8605], [-3.688, 1.133, -3.049], 0.01, 8], [0.427474, -0.29093, 0.333927, 0.788111]], [[[0.8268, -0.0559, 0.3935, 0.398], [-0.387, 0.922, 1.986], 0.1, 7], [0.220922, -0.271091, 0.534556, 0.769385]], [[[0.5942, -0.6772, -0.0493, -0.4313], [3.399, 0.94, 0.682], 0.1, 1], [0.714833, -0.585403, 0.028378, -0.381461]]], [[[[-0.5755, -0.1729, 0.1896, -0.7765], [-1.564, 1.954, -3.317], 0.01, 5], [0.652658, 0.171677, -0.144528, 0.723655]], [[[0.7604, -0.3417, -0.0319, -0.5514], [-0.767, -1.411, 1.303], 0.01, 10], [0.77686, -0.328074, -0.128606, -0.52184]], [[[0.5865, 0.3862, 0.1527, 0.6954], [1.063, 0.714, -1.361], 0.05, 10], [0.626543, 0.664653, -0.067408, 0.401418]], [[[-0.7395, -0.3308, 0.5863, -0.0042], [-0.888, 0.133, 0.72], 0.01, 5], [0.74839, 0.324806, -0.577536, 0.029421]], [[[-0.3438, -0.8064, 0.2793, -0.3918], [0.487, -0.414, 0.563], 0.05, 6], [0.231973, 0.824132, -0.258947, 0.447149]], [[[0.4999, -0.5863, 0.4671, 0.4339], [2.074, -2.687, 0.552], 0.01, 9], [0.593908, -0.596606, 0.346469, 0.413876]], [[[-0.5477, -0.5732, 0.5822, 0.1802], [-0.237, 0.825, 0.304], 0.05, 3], [0.596708, 0.564271, -0.53714, -0.192402]], [[[-0.571, 0.1155, 0.5121, 0.6312], [2.085, -1.83, -1.285], 0.01, 1], [0.563386, -0.107047, -0.509932, -0.641176]]], [[[[0.3666, 0.5064, 0.4609, -0.6299], [3.995, -0.841, 3.579], 0.01, 5], [0.378645, 0.510325, 0.556833, -0.534914]], [[[0.4219, -0.4687, 0.5689, 0.5279], [0.463, -2.547, 1.302], 0.01, 12], [0.47396, -0.574451, 0.445159, 0.497194]], [[[0.2873, -0.6346, 0.6402, -0.324], [3.029, -0.324, 1.16], 0.1, 8], [0.817944, -0.105726, 0.220751, 0.520633]], [[[0.2307, 0.3931, 0.7631, -0.4581], [2.174, 2.113, 3.444], 0.05, 10], [0.080385, 0.450009, -0.879659, -0.131262]], [[[0.3265, 0.31, 0.1591, -0.8786], [-1.35, 2.136, -0.561], 0.01, 12], [0.297825, 0.173125, 0.117593, -0.931397]], [[[0.1401, -0.0998, 0.7197, 0.6726], [-3.242, -3.373, -3.717], 0.01, 11], [0.381235, -0.097044, 0.793491, 0.464343]], [[[0.2076, -0.1442, 0.9556, -0.1516], [2.825, 3.025, 3.659], 0.05, 2], [0.1052, -0.304075, 0.945742, 0.045198]], [[[-0.6707, -0.6061, 0.269, -0.3322], [3.574, -3.249, 3.855], 0.01, 11], [0.399347, 0.698471, -0.309175, 0.507021]]], [[[[-0.5935, 0.4863, -0.2285, -0.5992], [-3.647, -1.427, -2.483], 0.01, 8], [0.584933, -0.575475, 0.325818, 0.4696]], [[[0.0332, -0.1691, -0.7704, -0.6138], [2.17, 2.479, 1.5], 0.1, 9], [0.881211, -0.074251, 0.351735, -0.30698]], [[[-0.0537, -0.8252, -0.3784, 0.4159], [1.996, 0.032, -1.898], 0.01, 4], [0.004675, 0.840181, 0.363147, -0.402737]], [[[0.5273, 0.4224, -0.4746, 0.5641], [-2.08, 3.628, 3.896], 0.01, 13], [0.516939, 0.571342, -0.141768, 0.621485]], [[[0.146, 0.3762, -0.3041, -0.8629], [2.493, -0.838, 1.176], 0.1, 9], [0.018505, -0.586628, -0.738668, 0.331504]], [[[0.6849, 0.5407, -0.2962, 0.3882], [-0.491, 1.404, -3.859], 0.1, 6], [0.728679, -0.028374, -0.313273, -0.608344]], [[[0.1094, 0.2843, 0.727, 0.6154], [3.004, -3.908, 3.399], 0.05, 2], [0.099484, 0.04945, 0.631065, 0.767733]], [[[0.1785, -0.1228, -0.7653, 0.6061], [2.105, 0.281, 2.09], 0.01, 8], [0.145584, -0.036317, -0.819027, 0.553788]]]]
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.282677, 0.606876, 0.698978, -0.251447] | [0.282677, 0.606876, 0.698978, -0.251447] | Passed |
| case 1 | [0.568856, 0.353305, 0.691238, -0.271603] | [0.568856, 0.353305, 0.691238, -0.271603] | Passed |
| case 2 | [0.093483, 0.757592, 0.180891, -0.620156] | [0.093483, 0.757592, 0.180891, -0.620156] | Passed |
| case 3 | [0.967882, 0.094358, 0.128105, 0.194656] | [0.967882, 0.094358, 0.128105, 0.194656] | Passed |
| case 4 | [0.14645, 0.823671, 0.10506, -0.537663] | [0.14645, 0.823671, 0.10506, -0.537663] | Passed |
| case 5 | [0.11186, -0.653252, -0.222024, -0.71516] | [0.11186, -0.653252, -0.222024, -0.71516] | Passed |
| case 6 | [0.303775, 0.162656, -0.567546, 0.747767] | [0.303775, 0.162656, -0.567546, 0.747767] | Passed |
| case 7 | [0.689383, -0.470639, -0.549444, -0.036907] | [0.689383, -0.470639, -0.549444, -0.036907] | Passed |
SHA-256 / b1c082bc7ca20f265c0a7180d3c2a1eba8dd92f37095f2186ac85eca14e14691
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.042207+00:00.
Case digest / e90a225eac25af5318bf2042640d31a6d484c6a43c6b85f5a7ef2e04c277ec1a