Paired benchmark analysis
July 18, 2026 · View on GitHub
analyze_pair.py turns two benchmark_wk17a_first100.jl runs (a baseline and a candidate) into the
distribution of per-sample improvements — not just aggregate totals. It joins the two runs on
sample_index and emits a stats table plus plots.
The point: an aggregate like "−30% wall clock" hides the spread. The per-sample view shows whether the change helps every sample or a few, whether the expensive samples benefit, and whether solve statuses or semantic outcomes changed.
Run
Managed with uv; dependencies are pinned in uv.lock.
uv run analyze_pair.py \
--baseline <baseline-run-dir> --candidate <candidate-run-dir> --out <out-dir> \
--baseline-label "base <sha>" --candidate-label "candidate <sha>"
Each run dir must contain benchmark_per_sample.csv and benchmark_metrics.csv (as written by
benchmark_wk17a_first100.jl). The analyzer reads the recorded tightening algorithm from the
metrics file so the report footnote names the mode actually benchmarked.
Outputs (into <out-dir>)
improvement_stats.md/.csv— each run's objective, per-sample ratio distribution (min…max sweep, improved/regressed), aggregate saving + concentration, per-side solve-status counts, and status and semantic-outcome changes grouped by transition. Historical output without objective metadata usedclosest; cross-objective reports carry a prominent warning.ratio_ecdf.png— paired relative view: ECDF of per-samplecandidate/baselineratios, all series overlaid (dimensionless, so they share one axis).absolute_runtime_ecdf.png,absolute_calls_ecdf.png— per-side distributions (baseline vs candidate), grouped by unit.magnitude_scatter.png,calls_scatter.png— paired log-log candidate-vs-baseline scatter; below they = xdiagonal = candidate better.
The solver-call series and its plots appear only when both runs carry the instrumentation columns.
Reading the numbers
ratio= candidate ÷ baseline;< 1is faster/fewer.pooled ratio= candidate total ÷ baseline total — the aggregate counterpart to the per-samplemedian; the gap between them is the "aggregates hide the spread" story.top-10 concentration= the 10 samples with the largest absolute change as a share of the total absolute per-sample change (0–100%; high = a few samples dominate).