Skip to content

Nonlinear multifrontal solver#2362

Merged
dellaert merged 9 commits intodevelopfrom
feature/NLMFSolver
Jan 19, 2026
Merged

Nonlinear multifrontal solver#2362
dellaert merged 9 commits intodevelopfrom
feature/NLMFSolver

Conversation

@dellaert
Copy link
Copy Markdown
Member

@dellaert dellaert commented Jan 17, 2026

This is the big one. This uses the new multifrontal solver in the nonlinear optimizer, by means of a derived class NonlinearMultifrontalSolver.

Refer to copilot summary for the detailed changes, but here are the perf numbers, for BAL (SLAM-like datasets likely have much greater wins, but I did not run those yet):

TBB On Linux

Dataset Legacy (Cholesky) s New (Solver) s Speedup
dubrovnik-16-22106-pre.txt 0.768 0.405 1.893x
dubrovnik-88-64298-pre.txt 3.146 2.123 1.482x
dubrovnik-135-90642-pre.txt 3.662 2.889 1.268x

TaskScheduler on Linux

Dataset Legacy (Cholesky) s New (Solver) s Speedup
dubrovnik-16-22106-pre.txt 1.157 0.497 2.326x
dubrovnik-88-64298-pre.txt 5.144 3.139 1.639x
dubrovnik-135-90642-pre.txt 5.987 4.781 1.252x

TBB On M1 Macbook

Dataset Legacy (Cholesky) s New (Solver) s Speedup
dubrovnik-16-22106-pre.txt 1.089 0.536 2.032x
dubrovnik-88-64298-pre.txt 5.732 3.238 1.770x
dubrovnik-135-90642-pre.txt 8.544 4.501 1.899x

TaskScheduler on M1

Dataset Legacy (Cholesky) s New (Solver) s Speedup
dubrovnik-16-22106-pre.txt 1.577 0.665 2.372x
dubrovnik-88-64298-pre.txt 8.064 4.022 2.005x
dubrovnik-135-90642-pre.txt 10.166 7.403 1.373x

Across both Linux and M1 macOS, the new TaskScheduler consistently outperforms the legacy Cholesky nonlinear optimizer and matches or exceeds TBB speedups, with the largest gains on smaller and mid-sized BAL problems (≈2.0–2.4×), while improvements taper to ≈1.25–1.9× on the largest Dubrovnik instance.

TaskScheduler closes much of the performance gap to TBB, but TBB still sets the raw-performance ceiling, especially at large scale (135 cameras).

Sample run (Mac, no TBB)

Processing BAL file: /Users/dellaert/git/github/examples/Data/dubrovnik-16-22106-pre.txt
Initial error: 4.18566e+06, values: 22122
iter      cost      cost_change    lambda  success iter_time
   0       108228      4.1e+06     0.0001      1      0.067
   1      5.9e+04        5e+04    3.3e-05      1      0.066
   2      1.9e+04        4e+04    3.3e-05      1      0.065
   3      1.8e+04      6.5e+02    1.1e-05      1      0.068
   4      1.8e+04           14    3.7e-06      1      0.067
  MultifrontalSolver: 0.68 s
Initial error: 4.2e+06, values: 22122
iter      cost      cost_change    lambda  success iter_time
   0        1e+05      4.1e+06     0.0001      1       0.26
   1      5.3e+04      4.9e+04    3.3e-05      1       0.26
   2      1.9e+04      3.4e+04    3.3e-05      1       0.26
   3      1.8e+04      1.1e+03    1.1e-05      1       0.25
   4      1.8e+04           87    3.8e-06      1       0.25
  MultifrontalCholesky: 1.5 s

Processing BAL file: /Users/dellaert/git/github/examples/Data/dubrovnik-88-64298-pre.txt
Initial error: 3.1e+07, values: 64386
iter      cost      cost_change    lambda  success iter_time
   0      3.6e+05        3e+07     0.0001      1       0.72
   1        3e+05      5.9e+04    3.3e-05      1       0.61
   2      2.9e+05      3.5e+03    1.1e-05      1       0.61
   3      2.9e+05      1.7e+03    9.5e-06      1        0.6
  MultifrontalSolver: 4.2 s
Initial error: 3.1e+07, values: 64386
iter      cost      cost_change    lambda  success iter_time
   0      3.6e+05        3e+07     0.0001      1        2.2
   1        3e+05      5.9e+04    3.3e-05      1        2.5
   2      2.9e+05      3.8e+03    1.1e-05      1        2.2
   3      2.9e+05      1.4e+03    9.7e-06      1          2
  MultifrontalCholesky: 9.8 s

Processing BAL file: /Users/dellaert/git/github/examples/Data/dubrovnik-135-90642-pre.txt
Initial error: 5.8e+07, values: 90777
iter      cost      cost_change    lambda  success iter_time
   0        4e+05      5.8e+07     0.0001      1        2.3
   1      3.8e+05      2.4e+04    3.3e-05      1        1.9
   2      3.8e+05     -3.5e+03    1.1e-05      1        1.8
  MultifrontalSolver: 8.3 s
Initial error: 5.8e+07, values: 90777
iter      cost      cost_change    lambda  success iter_time
   0        4e+05      5.8e+07     0.0001      1        3.8
   1      3.8e+05      2.3e+04    3.3e-05      1        3.6
   2      3.8e+05     -9.4e+02    1.1e-05      1        3.5
  MultifrontalCholesky: 12 s

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces a new NonlinearMultifrontalSolver class that integrates the recently-added multifrontal solver into the nonlinear optimization pipeline, enabling significant performance improvements for bundle adjustment and SLAM problems. The new solver becomes the default linear solver for nonlinear optimizers, replacing the legacy multifrontal Cholesky implementation.

Changes:

  • Introduced NonlinearMultifrontalSolver wrapping MultifrontalSolver with LM-style damping support
  • Changed default linear solver from MULTIFRONTAL_CHOLESKY to MULTIFRONTAL_SOLVER
  • Refactored damping parameters into standalone LMDampingParams struct and extracted MultifrontalParameters
  • Added deltaError() support to MultifrontalSolver for efficient error computation
  • Enhanced MultifrontalClique with damped elimination methods supporting both identity and diagonal damping
  • Integrated new solver into LevenbergMarquardtOptimizer and GaussNewtonOptimizer with automatic fallback

Reviewed changes

Copilot reviewed 23 out of 23 changed files in this pull request and generated 20 comments.

Show a summary per file
File Description
gtsam/nonlinear/NonlinearMultifrontalSolver.h/.cpp New solver class wrapping MultifrontalSolver with nonlinear-specific functionality
gtsam/nonlinear/LMDampingParams.h Extracted damping parameters into standalone header
gtsam/nonlinear/NonlinearOptimizerParams.h/.cpp Added MULTIFRONTAL_SOLVER enum and MultifrontalParameters field
gtsam/nonlinear/NonlinearOptimizer.h/.cpp Added ensureMultifrontalSolver method for lazy solver initialization
gtsam/nonlinear/LevenbergMarquardtParams.h/.cpp Refactored to use LMDampingParams struct
gtsam/nonlinear/LevenbergMarquardtOptimizer.cpp Integrated new solver with conditional usage based on params
gtsam/nonlinear/GaussNewtonOptimizer.cpp Added support for new multifrontal solver
gtsam/nonlinear/Values.h Added friend declaration for efficient value updates
gtsam/linear/MultifrontalParameters.h New header for multifrontal solver parameters
gtsam/linear/MultifrontalSolver.h/.cpp Added deltaError method and refactored parameter handling
gtsam/linear/MultifrontalClique.h/.cpp Enhanced with damped elimination, QR mode determination, and error tracking
gtsam/nonlinear/tests/testNonlinearMultifrontalSolver.cpp Comprehensive tests for new solver functionality
tests/testNonlinearOptimizer.cpp Updated to test all solver types including new MULTIFRONTAL_SOLVER
gtsam/linear/tests/testMultifrontalSolver.cpp Added deltaError tests and improved comment formatting
gtsam/base/tests/testSymmetricBlockMatrix.cpp Added tests for diagonal update helpers
timing/timeSFMBAL.cpp Refactored timing harness to compare solvers and support profiling
timing/timeNonlinearMultifrontalSolver.cpp New timing tool for direct solver benchmarking

@tzvist
Copy link
Copy Markdown
Contributor

tzvist commented Jan 18, 2026

Just out of curiosity what are the major changes that give the improved performance? (maybe you have already written some explanation and you can just point me to it?)

Base automatically changed from feature/deltaError to develop January 18, 2026 15:54
void initializeMatrices(const std::vector<size_t>& blockDims,
size_t totalNumRows);
/// Apply damping for QR elimination by writing into extra Ab_ rows.
void applyDampingQR(double lambda, const LMDampingParams& dampingParams,
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you add a context section on why and how we need the extra rows?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will do

Copy link
Copy Markdown
Collaborator

@ProfFan ProfFan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice! Let's merge this. I just moved to my new place and setting things up, but I will start implementing the TODOs now :)

@ProfFan
Copy link
Copy Markdown
Collaborator

ProfFan commented Jan 18, 2026

BTW, these are with Schur or COLAMD ordering? COLAMD takes 0.5s to run by itself. @dellaert

@tzvist It's mostly about tackling of the overheads of the traditional functional API. We plan to write everything up once we finish and hopefully tag a new release with the speedups :)

@dellaert
Copy link
Copy Markdown
Member Author

Just out of curiosity what are the major changes that give the improved performance? (maybe you have already written some explanation and you can just point me to it?)

@tzvist Please see #2350 - I just added a short description to what we're trying to do. It seems that you have a compute-heavy use case and we would love to have your help in making this even better; probably over preferring this over optimizing the earlier pipeline :-)

@dellaert
Copy link
Copy Markdown
Member Author

BTW, these are with Schur or COLAMD ordering? COLAMD takes 0.5s to run by itself. @dellaert

Schur

@dellaert
Copy link
Copy Markdown
Member Author

By the way, I'm dealing with some regressions. The new solver needs a non-null noise model to do the symbolic analysis. So I will disallow null pointers. I'm doing this in a different branch and I will target that branch after I have a new PR up.

@dellaert dellaert merged commit ef12d6c into develop Jan 19, 2026
34 checks passed
@dellaert dellaert deleted the feature/NLMFSolver branch January 19, 2026 18:02
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.

4 participants