# Batch-state equivalence check

Public reproduction note: archive aliases and `SIMCOMPARE_ROOT` are portable placeholders; use your own archive and checkout locations. Private deployment identifiers are omitted.

Instance 52582439, unchanged pinned environments and models. A separate validation
rerun captures every physics step, including initial state, for all 14 native
scaling cases: slide/drop, CPU MuJoCo n=1, native MJWarp and Genesis n=1/16/128.
Each case has three repetitions, 1,001 samples per world at dt=1 ms. Warm-up and
reset match the timing probe. All recordings contain finite positions,
quaternions and linear/angular velocities. No contact-force equivalence claim.

Evidence: repository-root `output/archive-runtime/results/runtime-equivalence-01/`,
including 14 NPZ trajectory archives, JSON metadata, logs and `comparison.json`.
Validation adds synchronous per-step readback, so its timing fields are explicitly
invalid for performance comparison. Original runtime evidence is unchanged.

## Within-engine batch versus one-world trajectories

Initial q/v arrays match exactly at every tested batch size. Compare each world
against the corresponding repeat of the one-world run, over all 1,001 samples.
Quaternion comparison accounts for sign equivalence and normalization.

| Engine / task | Maximum position difference, n=128 | Maximum orientation difference | Maximum linear velocity difference | Interpretation |
| --- | ---: | ---: | ---: | --- |
| Genesis / slide | 3.583e-12 m | 4.617e-12 rad | 2.084e-11 m/s | Numerical equivalence, not bit-identical |
| Genesis / drop | 0 | 0 | 0 | All captured q/v exactly identical |
| Native MJWarp / slide | 0.12884 mm | 0.001718 rad (0.0984°) | 0.021674 m/s | Close positions, not strict numerical equivalence |
| Native MJWarp / drop | 1.608e-9 m | 8.238e-8 rad | 5.778e-8 m/s | Numerical equivalence, not bit-identical |

The 16-world cases give the same qualitative outcome: MJWarp slide max position
0.12866 mm, orientation 0.001717 rad and velocity 0.021673 m/s. Genesis slide
differences equal those at n=128 to reported precision.

MJWarp slide worst linear velocity deviation occurs at 0.223 s, orientation
at 0.230 s, angular velocity at 0.233 s and position at 0.261 s. Maximum angular
velocity deviation is 0.9763 rad/s. Position RMS across all worlds/repeats/time
at n=128 is 0.01249 mm; linear velocity RMS is 0.000365 m/s. Thus the small final
position discrepancy alone understates the transient velocity differences.

Repeatability is important: repeated n=16/n=128 MJWarp sliding trials differ by
similar maxima (~0.129 mm, ~0.02168 m/s). A fixed, deterministic batch-size bias
has not been established; batching-associated/nondeterministic variation is a
better description. The root cause is not isolated by these recordings. Genesis
repeats are exact within each tested batch size. This does not promise determinism
on other scenes, precision modes, hardware or software versions.

The comparison script uses a strict numerical screen of 1 µm position,
1e-5 rad orientation, 1e-5 m/s linear velocity and 1e-4 rad/s angular velocity.
These are declared numerical tolerances, **not task-success or physical-accuracy
criteria**. MJWarp sliding fails that screen; Genesis and MJWarp drop pass.

## “Single-threaded” can mean a different comparison

One GPU world versus many GPU worlds is not CPU MuJoCo versus GPU execution.
The separate CPU comparison finds maximum position differences of ~1.714 µm
(native MJWarp slide), 0.101 µm (native MJWarp drop), 0.2764 mm (Genesis slide)
and 0.3336 mm (Genesis drop). These include engine/precision/contact-model
differences and must not be attributed to batching. Cross-engine angular
velocity frames are not reconciled; do not interpret those entries as errors.

No batched PhysX, Newton-importer, Panda, or deformable cases were in the scaling
benchmark, so this validation does not establish equivalence for those routes.
Native MJWarp here bypasses Newton's importer. The recorded full-harness trials
have a different readback/control path from the native primitive benchmark.

## Reproduce

From `SIMCOMPARE_ROOT`, for each task/engine/world-count above:

```sh
.venv-newton/bin/python runtime_batch_scale.py --backend mujoco_warp_native --worlds 128 --task slide --validate --output results/NEW/slide-mujoco_warp_native-n128.json
```

Use `.venv-genesis` for Genesis. The associated `.npz` is created exclusively;
never overwrite benchmark files. Then locally or remotely:

```sh
python runtime_equivalence.py results/NEW --output results/NEW/comparison.json
python -m unittest test_runtime_equivalence test_runtime_measure
```

Five timing/comparison tests pass, including broadcasting, quaternion sign
equivalence and a known 90-degree rotation. All validation runs have completed
and been downloaded locally; no new GPU jobs remain from this check.
