02 · The solver

Four engines behind one call, and a checker that trusts none of them.

solve(const Model&, const Options&) → Solution is the one entry point. Everything below plugs into it.

MPS · LP · QPSreader presolve8 reductions scalingRuiz + P-C solve()one entry pointdispatch by class dual simplexLP default · basis interior pointLP at scale · LDLᵀ restarted PDHGfirst-order · GPU shape branch & boundMILP · MIQP over QP postsolvere-measured independent verifiershares no code node LPs warm-start the dual simplex
Presolve's postsolve re-measures the recovered point against the original model, so a wrong dual surfaces as a violation rather than as a quiet wrong number.
Engines

Chosen by the problem class.

LP · default below 20,000 rows

Dual simplex

Bounded-variable revised simplex, sparse Markowitz LU, Devex pricing. Produces a basis: the node engine for branch and bound. auto picks it by a rule table whose every threshold names its CSV.

LP · primal

Primal simplex

Composite phase 1, no big-M. The hand-over engine when a basis needs repair.

LP · auto from 20,000 rows or 100,000 nonzeros

Interior point

Mehrotra predictor-corrector through a from-scratch sparse LDLᵀ with AMD ordering, started from Mehrotra's shifted point. On its own it verifies 72 of 89 Netlib instances (51 before the new start, 69 before it learned to raise its regularization when a Newton direction comes back non-finite). Its answer is pushed to a vertex by crossover, so it carries a basis; a set-up past a fifth of the time limit declines, and another engine takes the rest.

LP · first-order, auto from 100,000 rows

Restarted PDHG

Two sparse mat-vecs and a projection per iteration: the GPU shape. Finished by the interior point from its own point. The CUDA port compiles in CI; it has not run on a card.

MILP · MIQP

Branch and cut

Reliability branching, dive then best-bound, warm-started dual node LPs. Gomory, cover and mixed-integer rounding cuts at the root and in rounds below it, with an aged cut pool; off by default because the A/B on MIPLIB proves the same 9 with or without them.

QP

Condat-Vũ

Convexity decided by LDLᵀ before any arithmetic. A non-convex Hessian is refused, never reported as global.

Verification

Two readers, two arithmetics.

The verifier reads the model file and the solution file and re-derives feasibility, duality, integrality and the gap. Infeasible carries a Farkas certificate; unbounded carries a ray; an IIS carries witnesses. All proved, not trusted.

model.mpsthe original file SANKHYAC++, the solver verify_solution.pyPython, no shared code plan.solprices · rangescertificate · IIS two readers, two arithmetics, one verdict
Compared

Ahead and behind, on the same evidence.

Three kinds of solver exist: open-source simplex codes, commercial ones, GPU first-order codes.

Ahead

  • Independent checker on every answer. No open-source solver ships one; the commercial ones ship none.
  • Provenance enforced in CI, not asserted in a README.
  • Scale evidence with exact optima: generators build the model backwards from a known KKT point.
  • A planner's solution file: prices, ranges, conflict set, progress stream.
  • An honest ledger shipped with the product.

Behind

  • Raw simplex speed: about 2x HiGHS's wall time on the Netlib medium tier.
  • MILP proofs: 9 of 30 on MIPLIB, 14 reached. MIR cuts, aggregation and tree rounds exist and were measured to save nodes (0.835x) without adding a proof; one core in the tree.
  • Very large LPs: Mittelmann 2 of 8 inside 300 s, and only with the first-order engine.
  • GPU: written and compiled in CI, never run on a card. Not claimed.
  • Decades of tuning. This has four months.