Skip to content

Skip zero entries in fraction-free row elimination#3

Closed
adelaett wants to merge 1 commit into
mainfrom
alain/fraction-free-simplex-pivot
Closed

Skip zero entries in fraction-free row elimination#3
adelaett wants to merge 1 commit into
mainfrom
alain/fraction-free-simplex-pivot

Conversation

@adelaett

@adelaett adelaett commented Jul 2, 2026

Copy link
Copy Markdown
Owner

What

Short-circuit zero cells in ff_eliminate (the fraction-free pivot inner loop).

Why

I measured cell-level statistics for the inner loop on the benchmark corpus and found these exact-rational tableaux are 65–80% zero mid-solve — much sparser than the ~50% assumed when ff_eliminate was written. Concretely, 55–67% of all inner-loop cell visits have both a.(j)=0 and the pivot-row entry row.(j)=0. For those cells the new value a.(j)*p - ac*row.(j) is identically zero (and Z.divexact 0 dprev = 0), yet the old code spent two bignum multiplies, a subtraction and an exact division to recompute a zero.

How

Add an a.(j)=0 short-circuit to every branch of ff_eliminate:

  • both a.(j) and row.(j) zero → leave the cell zero, no work at all (the dominant case);
  • only a.(j) zero → value is -ac*row.(j) (drop the vanishing a.(j)*p product);
  • only row.(j) zero → value is a.(j)*p (the existing fast path).

Each simplified expression is still the full Bareiss numerator for that cell (the dropped term is provably zero), so the exact /dprev division stays valid and every result is bit-identical. dune runtest passes with no golden changes.

Result

Benchmark harness (bench/evaluate.py --baseline main --candidate <branch> --rule bland --trials 30), correctness-checked against the GLPK + Gurobi oracle consensus:

  • VERDICT: ACCEPTED
  • Correctness: passed on all 19 held-out instances
  • Geomean speedup: 1.12× (+12.5%), 95% bootstrap CI [1.086, 1.163] (entirely above 1.0)
  • Pivot ratio: exactly 1.0000× — identical pivot sequence, pure per-pivot arithmetic savings
  • rand_25x60 16.5ms → 14.6ms; best instance degen_14 1.31×

This lands on top of the fraction-free + pricing + phase-1 work already merged in #2.

Store the tableau as Z.t numerators over one positive shared denominator d
(cell value = entry/d) and pivot with Edmonds' fraction-free rule
(a.(j) <- (a.(j)*p - a.(x)*row.(j)) / dprev, exact Z.divexact). This replaces
the Q.t array array tableau whose numerators/denominators blew up and paid a
GCD on every arithmetic op.

The change is behaviour-preserving: every cell value is exactly Q.make entry d,
so the Bland/max pivot sequence, verbose intermediate tableaux, and final
rational answers are byte-identical (dune runtest passes with no golden
regeneration). Selection compares signs (Z.sign) and ratios (Q.make b pv),
both denominator-invariant since d > 0.
@adelaett adelaett closed this Jul 2, 2026
@adelaett adelaett changed the title Fraction-free integer pivoting in the simplex tableau Skip zero entries in fraction-free row elimination Jul 2, 2026
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