We tried the textbook answer for simplex pricing and measured it
Measured 2026-09-03 with scripts/bench-solver.js, the same seeded benchmark every figure on our performance page comes from. Nineteen instances, chosen because they force the search to branch, each answer checked against a ground truth computed by a different method.
The advice, and why we went looking
The standard guidance on the simplex method is that steepest-edge pricing is the best-performing variant overall, and that within branch and bound it beats the alternatives comfortably. It is in the textbooks and it is what a practitioner will tell you.
We had never tested whether it held at our sizes. Our tableau is dense and our models are small by the standards of the literature, and both of those change the arithmetic. So we stopped assuming.
What our solver was already doing
Inside a whole-number search, every node is a linear program that differs from its parent by one tightened bound. That leaves the parent's basis dual feasible but rarely primal feasible, so the child is solved by repairing the parent's answer with a few dual simplex pivots rather than starting over. A cold solve is the fallback.
Nobody had counted how often that path was taken. So we instrumented it first. Across the benchmark, 94.2% of node linear programs are solved by dual repair, 5.8% cold, and none by a pure primal warm start. Dual simplex was already carrying the search. That measurement now rides on every result as lpStats.
Then we implemented steepest edge in both halves
Exact steepest-edge pricing is affordable for us because the tableau is dense: the true edge norm is one column scan, the same cost per column the pivot already pays. So we implemented it properly in both the primal pricing loop and the dual repair, put both behind a flag, and let the benchmark decide.
In the primal it lost, and not narrowly
On the pure linear-programming instances it chose the identical pivots at a large multiple of the cost. The largest instance, a thousand columns by four hundred rows, went from about 5 ms to about 65 ms for exactly the same four hundred pivots. Inside the tree it was not uniformly better on pivot counts either. We declined it.
In the dual repair it won
The benchmark's hardest instance, a hundred-set cover over a hundred and fifty elements, fell from about 145 ms to about 123 ms. Total pivots across the suite dropped from 34,030 to 32,810. One instance paid slightly more. Every one of the fifteen independently verified optima stayed proven, and nothing was truncated.
A note on which of these numbers are exact. The pivot counts are deterministic: the same build on the same instance performs the same pivots every time, on any machine, and the figures below will reproduce to the digit. The milliseconds are not. They move a percent or two between runs on the same machine and more between machines, so they are stated as approximate and should be read as a ratio rather than a promise. Where the two disagree, trust the pivots.
| Instance | Dantzig | Steepest dual | Pivots before | Pivots after |
|---|---|---|---|---|
| setcover 100x150 | ~145 ms | ~123 ms | 11,327 | 9,895 |
| setcover 40x60 | ~6 ms | ~5 ms | 1,362 | 1,116 |
| corr-knapsack 100 | ~4 ms | ~2 ms | 552 | 416 |
| setcover 60x100 | ~33 ms | ~35 ms | 4,946 | 5,659 |
| Whole suite | ~350 ms | ~330 ms | 34,030 | 32,810 |
What shipped
Dantzig pricing in the primal with a Bland fallback, steepest-edge row choice in the dual repair. Both rules stay behind a flag in the benchmark, so the decision can be re-argued with numbers rather than with citations. If someone re-measures at different sizes and the answer flips, the flag is there and the default should follow the measurement.
That is the whole point. The textbook advice was not wrong; it was untested at our sizes, and half of it did not survive the test. A benchmark that only confirms what you already believed is not measuring anything.
How to check this
Every number above is reproducible from the repository. The benchmark refuses to flatter itself: each instance is seeded, each answer is checked against a ground truth computed by an independent method, dynamic programming for the knapsack shapes, and a run that stops early is reported as truncated rather than fast. The engine ceilings and the rest of the measurements live on the performance page, including the sizes where the engines refuse to answer rather than guess.
Sortia is a Google Sheets add-on for risk analysis (estimates in, odds out), optimization and decision analysis. The engines run in the browser tab, so a hundred thousand trials finish in about 57 milliseconds and nothing needs installing on a locked-down machine. You can see what it does or read every measurement we publish.