Skip to content

Speed up leaving-variable test with a linear argmin ratio scan#5

Merged
adelaett merged 1 commit into
mainfrom
alain/simplex-leaving-argmin
Jul 2, 2026
Merged

Speed up leaving-variable test with a linear argmin ratio scan#5
adelaett merged 1 commit into
mainfrom
alain/simplex-leaving-argmin

Conversation

@adelaett

@adelaett adelaett commented Jul 2, 2026

Copy link
Copy Markdown
Owner

Summary

Speeds up the leaving-variable (minimum-ratio) test, which runs on every pivot regardless of pricing rule.

choose_leaving only ever needs the argmin of the candidate ratios, but the old code:

  1. built a list of Q.make b pv ratios — a GCD per candidate,
  2. List.fast_sorted it on (Q.compare, index) — cross-multiplying GCD-reduced fractions,
  3. then read only the head.

Profiling the hot rand_25x60 solve showed Q.compare as the 3rd hottest symbol, rivalling the core fraction-free Z.sub/Z.divexact.

Change

Replace the build-list-and-sort with a single linear argmin scan. Candidates are compared by ratio_compare, a direct cross-multiplication:

sign(b1/p1 − b2/p2) = sign(b1·p2 − b2·p1) · sign(p1) · sign(p2)

Only exact Z.mul/Z.sub/Z.sign on the shared-denominator integers — no GCD, no reduced-rational allocation, no sort. The sign correction makes it valid on the ignore_neg transition path too (negative pivots), so both paths share it.

Correctness

Bit-identical selection. Scanning rows upward and replacing only on a strict ratio decrease reproduces the old stable (ratio, index) ascending order, so the same leaving variable is chosen every time.

  • All golden cram tests pass unchanged (they diff full -v per-pivot tableaux).
  • Pivot geomean ratio 1.0000× and rational objectives match on every held-out instance.
  • Benchmark correctness: matches the GLPK + Gurobi oracle consensus on all 19 instances.

Performance

bench/evaluate.py --baseline main --candidate alain/simplex-leaving-argmin --rule bland --trials 60:

Metric Result
Time geomean speedup 1.127× (+12.68%)
95% bootstrap CI [1.089, 1.177] — entirely above 1.0
Pivot ratio 1.0000× (no behavioral change)
Correctness passed (GLPK + Gurobi)

Every instance is faster or equal (worst +4.7%). Verdict: ACCEPTED.

Note on trials: at --trials 30 laptop noise (CI ≈ [0.90, 1.04]) can flip this borderline ~12% win to REJECTED; --trials 60 gives a clean, stable verdict, as AGENTS.md advises for small speedups.

🤖 Generated with Claude Code

The minimum-ratio (leaving-variable) test only ever needs the argmin, but the
old code built a list of Q.make ratios and fully sorted it every pivot. Q.make
reduces each candidate by a GCD, and Q.compare in the sort cross-multiplies on
top — two GCD-carrying steps per comparison, plus an O(k log k) sort to read a
single element. Profiling the hot rand_25x60 solve showed Q.compare as the 3rd
hottest symbol, rivalling the core fraction-free Z.sub/Z.divexact.

Scan linearly for the min ratio (ties broken by lowest row index, matching the
old stable-sort order) and compare candidates with ratio_compare: a direct
cross-multiplication (sign of b1*p2 - b2*p1, corrected for pivot signs) using
only exact Z.mul/Z.sub/Z.sign on the shared-denominator integers -- no GCD, no
allocation of reduced rationals.

Leaving choice is bit-identical: all golden cram tests pass unchanged (they
diff full -v per-pivot tableaux) and pivot counts + rational objectives match
on every heldout instance. Isolated high-repeat A/B: +10.9% geomean, every
instance faster or equal.
@adelaett adelaett merged commit f34c03a into main Jul 2, 2026
12 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant