pydynamicestimator.tests.baselines.report_inverter_drift

Quantify how far the CURRENT inverter trajectories drift from the committed byte-identical baselines – the diagnostic companion to test_recur_{sim,est}_inverter.py (which only give boolean pass/fail).

Run from the repo root:

.venv/bin/python -m pydynamicestimator.tests.baselines.report_inverter_drift .venv/bin/python -m pydynamicestimator.tests.baselines.report_inverter_drift sim_ld

Purpose. The vectorization pass (A1 in docs/inverter_remaining_work.md) is the one inverter change that is not byte-identical: re-associating floating-point arithmetic shifts the trajectory at the ULP level, amplified by the nonlinear integrator + init Newton solves to ~1e-9..1e-6. The byte-identical gates can only say “diverged”; this tool says by how much and in which states, so you can (a) confirm the drift is reassociation-scale rather than a transcription bug, and (b) watch the actual margin against the 1e-6 sim / 1e-5 est gate tolerances.

It does NOT modify the baselines – it loads them read-only and compares. Capture a fresh reference only via create_baseline_inverter.py, and only when an intentional, validated numerics change makes the new trajectories the reference.

For each case it reports the array shape, the np.allclose gate verdict (same semantics as the test: atol gate + numpy’s default rtol=1e-5), the global max-abs / max-rel / RMS difference with the location of the worst element, and a per-state table of the largest-drifting rows – named when the row->name reconstruction matches the array (else bare indices, never a wrong label).

Attributes

GATE_ATOL

_REL_FLOOR

_DEVICE_ABBREV

Functions

_reconstruct_state_names(→ List[str])

Rebuild the per-row state names of x_full from the module globals that

report_case(→ Optional[dict])

Run one baseline case on the current code, diff it against the committed

main(→ int)

Module Contents

pydynamicestimator.tests.baselines.report_inverter_drift.GATE_ATOL
pydynamicestimator.tests.baselines.report_inverter_drift._REL_FLOOR = 1e-09
pydynamicestimator.tests.baselines.report_inverter_drift._DEVICE_ABBREV
pydynamicestimator.tests.baselines.report_inverter_drift._reconstruct_state_names(case: str, n_rows: int) List[str][source]

Rebuild the per-row state names of x_full from the module globals that run_inverter_case just populated, mirroring the exact device -> entry -> state -> (dynamic-line tail) ordering system.py uses to build the state vector.

The reconstruction is length-guarded: if anything is off (attribute missing, or the rebuilt list does not match n_rows) it returns plain x{i} indices rather than risk pinning a drift number on the wrong state.

Parameters:
  • case (str)

  • n_rows (int)

Return type:

List[str]

pydynamicestimator.tests.baselines.report_inverter_drift.report_case(case: str) dict | None[source]

Run one baseline case on the current code, diff it against the committed reference, print the report, and return the metrics dict (None if the baseline is missing or the shapes differ).

Parameters:

case (str)

Return type:

Optional[dict]

pydynamicestimator.tests.baselines.report_inverter_drift.main(argv: List[str]) int[source]
Parameters:

argv (List[str])

Return type:

int