sc: stop over-solving the solver's quadratic subproblem

Each major iteration of the sequential quadratic solver solves a
quadratic subproblem with Frank-Wolfe, where every inner step is
a CoinMP linear solve. The loop ran until the duality gap fell below
a tiny absolute floor, which on harder models meant many inner linear
solves spent driving the gap to a precision the outer loop does not
need: it re-samples and re-solves around the accepted step anyway.

Also stop once the gap has shrunk to a small fraction of its value
on the first inner step. The step is then good enough to accept,
and the outer trust-region loop corrects any remaining error. This
cuts inner linear solves with no loss of solution quality: on the
resource model the solver still reaches the same optimum.

Signed-off-by: Tomaž Vajngerl <tomaz.vajngerl@collabora.co.uk>
Change-Id: I80d118176840ab6c63ac939f962e8f8d3bb9a3b9
Reviewed-on: https://gerrit.collaboraoffice.com/c/online/+/4924
Tested-by: Jenkins CPCI <releng@collaboraoffice.com>
Reviewed-by: Miklos Vajna <vmiklos@collabora.com>
(cherry picked from commit b63997355fee236cded23bc32e813bc412ed8984)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/209439
Tested-by: Xisco Fauli <xiscofauli@libreoffice.org>
Reviewed-by: Xisco Fauli <xiscofauli@libreoffice.org>
Tested-by: Jenkins
This commit is contained in:
Tomaž Vajngerl
2026-09-16 09:44:20 +02:00
committed by Xisco Fauli
parent 8e0d1c26c5
commit 508dfcabb8
+9 -1
View File
@@ -373,6 +373,8 @@ SLPSolver::solveTrustRegionQp(const ScSolverCellHashMap& rCells, const std::vect
constexpr int nMaxFrankWolfe = 50;
constexpr double fGapTolerance = 1.0e-9;
constexpr double fGapFraction = 1.0e-3;
double fInitialGap = 0.0;
for (int nFrankWolfe = 0; nFrankWolfe < nMaxFrankWolfe; ++nFrankWolfe)
{
// Gradient of the quadratic model at the current step: B d + g.
@@ -399,7 +401,13 @@ SLPSolver::solveTrustRegionQp(const ScSolverCellHashMap& rCells, const std::vect
// Duality gap: how much the linear model could still improve.
double fGap = -dotProduct(aQuadraticGradient, aDirection);
if (fGap < fGapTolerance)
if (nFrankWolfe == 0)
fInitialGap = fGap;
// Stop once the subproblem is solved well enough: the gap has shrunk to
// a small fraction of its initial value, or below an absolute floor.
// Driving the gap all the way to zero is wasted work, because the outer
// trust-region loop re-samples and re-solves around the accepted step.
if (fGap < fGapTolerance || fGap < fGapFraction * fInitialGap)
break;
// Exact line search of the quadratic along the Frank-Wolfe direction.