Fall back to the best iterate when terminating with a numerical error#229
Open
batterseapower wants to merge 2 commits into
Open
Fall back to the best iterate when terminating with a numerical error#229batterseapower wants to merge 2 commits into
batterseapower wants to merge 2 commits into
Conversation
…error On some ill-conditioned problems the last iterations before a NumericalError or InsufficientProgress termination degrade the iterate severely (e.g. the primal residual blows up by orders of magnitude chasing the final decade of duality gap), so the reduced-tolerance 'almost solved' check fails even though an excellent iterate was visited a few steps earlier. Track the best iterate seen (by the worst of gap_rel/res_primal/res_dual, only while kappa/tau <= 1) and restore it before post-processing when the solver terminates in an error state, mirroring how commercial solvers report their best point on stall.
Covers the three behaviours the fallback has to get right: a degraded final iterate is discarded in favour of the best one seen, a final iterate that is itself the best is left untouched, and iterates on the infeasibility path (ktratio > 1) are never eligible to be saved or restored.
batterseapower
marked this pull request as ready for review
July 15, 2026 03:24
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The bug
When the interior-point loop terminates with
NumericalErrororInsufficientProgress, the reduced-tolerance ("almost solved") acceptance check is evaluated against the final iterate. But on a numerical failure the final iterate is typically the one that just went bad -- that is why the solver stopped. The good iterate from one step earlier is discarded, and the solve is reported as a failure on the strength of a point the solver had already superseded.This shows up on problems whose attainable gap floor sits close to the requested tolerance: the primal residual jumps from ~1e-10 to ~3e-5 in a single step, the loop bails out, and the almost-solved test is then applied to the ruined point and fails. The solver had a perfectly acceptable answer in hand and threw it away.
The fix
Track the best iterate seen so far and restore it before the almost-solved check runs.
max(gap_rel, res_primal, res_dual)-- the worst of the quantities the (almost-)solved checks actually test, so "best" means best by the criterion the caller is about to be judged against.ktratio > 1are never candidates: those lie on the infeasibility-certificate path and must not be presented as approximate solutions.Solved.Cost is one extra
DefaultVariablesand a copy on strict improvement.Evidence
It only ever helps. Across the 133 Maros-Meszaros QPs that this build solves, the patch is bit-identical to stock: not a single status, iteration count, objective or returned residual changes. That is the expected result -- those problems terminate normally, so the restore never fires -- and it bounds the blast radius: the patch cannot regress a solve that was already succeeding.
The solver had those better iterates in hand and was reporting the degraded final one instead.
Tests. Three unit tests cover the semantics: a degraded final iterate is discarded in favour of the best seen; a final iterate that is itself the best is left untouched; iterates on the infeasibility path are never eligible to be saved or restored. Full suite green: 123 tests, 0 failures (
cargo test --release).