-
Notifications
You must be signed in to change notification settings - Fork 896
JacobianFactor now compute the error more efficiently by first assembling the X vector #2329
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
There was a problem hiding this 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 optimizes JacobianFactor error computation and fixes latent bugs related to iteration order in VectorValues and related containers when TBB is disabled. The main changes replace the FastMap-based fallback with std::unordered_map and ensure deterministic behavior by using key-sorted iteration where needed.
Key Changes:
- Optimized JacobianFactor error computation to assemble a combined vector and use direct matrix multiplication instead of iterative block multiplication
- Fixed VectorValues iteration order dependencies by using sorted() method in equals, operators, and other order-sensitive operations
- Replaced FastMap with std::unordered_map for ConcurrentMap when TBB is disabled
Reviewed changes
Copilot reviewed 15 out of 15 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| gtsam/linear/JacobianFactor.cpp | Optimized unweighted_error() to assemble augmented vector and use direct matrix multiplication |
| gtsam/linear/GaussianConditional.cpp | Refactored likelihood() to directly construct VerticalBlockMatrix instead of copy-then-offset |
| gtsam/linear/VectorValues.h | Changed sorted() return type to std::map<Key, const Vector&> and moved method to public section |
| gtsam/linear/VectorValues.cpp | Fixed equals, operators, dot, hasSameStructure to use key-sorted iteration for deterministic comparison |
| gtsam/linear/Errors.cpp | Updated createErrors to use sorted order for deterministic Errors vector construction |
| gtsam/linear/SubgraphPreconditioner.cpp | Fixed multiplyInPlace and related methods to iterate in key-sorted order |
| gtsam/nonlinear/Values.cpp | Removed TBB-specific dual-iterator code path, now uses find() uniformly |
| gtsam/inference/BayesTree-inst.h | Tightened equals() logic to compare by key instead of relying on iteration order |
| gtsam/base/ConcurrentMap.h | Replaced FastMap with std::unordered_map for non-TBB builds |
| tests/testSubgraphPreconditioner.cpp | Added verbosity control and reformatted for consistency |
| gtsam/sfm/tests/testShonanAveraging.cpp | Updated expected matrix values on Apple platform (reflects deterministic algorithm behavior) |
| gtsam/navigation/tests/testImuBias.cpp | Silenced unused variable warning with (void) cast |
| gtsam/navigation/tests/testCombinedImuFactor.cpp | Removed unused variable declaration |
| gtsam/geometry/tests/testPoint2.cpp | Silenced unused variable warning with (void) cast |
| gtsam/geometry/tests/testPoint3.cpp | Silenced unused variable warning with (void) cast |
| /** Sort by key (primarily for use with TBB, which uses an unordered map)*/ | ||
| std::map<Key, const Vector&> sorted() const; |
Copilot
AI
Dec 28, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The sorted() method should have doxygen-style documentation explaining its purpose, return value, and usage. The method returns a std::map containing references to the original Vectors, and this lifetime dependency should be documented to help users understand that the returned map is only valid as long as the VectorValues object exists and is not modified.
dellaert
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The JacobianFactor unweighted_error change seems like it should get its own small PR - I commented on one possible improvement.
This PR could then just be the change to unordered - which is a bit more controversial.
In both PRs it'd be nice to show the timing improvement in the PR comment, as I did in #2327.
|
|
||
| // Copy the augmented Jacobian matrix: | ||
| auto newAb = Ab_; | ||
| // Compute updated right-hand side: d - R * x |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What prompted this change? likelihood is not used very much so it's not a performance bottleneck I think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I did this to avoid hitting the slow path in unweighted_error as this used to be using firstBlock
gtsam/base/ConcurrentMap.h
Outdated
|
|
||
| // If we're not using TBB, use a FastMap for ConcurrentMap | ||
| #include <gtsam/base/FastMap.h> | ||
| // If we're not using TBB, use a std::unordered_map |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems like a lot of changes in this PR come from this change? Is it very much faster? Can you add performance numbers in the PR comment?
It's weird that that all this sorted business was not needed in TBB path which was already unordered...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think TBB might have latent bugs because their "unordered" container is actually not that unordered 🤷
…ling the X vector We also now directly assemble the new `GaussianConditional` instead of using the `copy-then-offset` strategy. During the implementation I also discovered some latent bugs related to the iteration order of the `VectorValues`. - Tighten `BayesTree::equals` logic and related `Values` handling. - Adjust Shonan averaging expected matrices and subgraph preconditioner test setup/verbosity. - Silence `Point2`/`Point3` constructor unused variable warnings.
f9ba50f to
e09072d
Compare
|
Result: Std: standard GTSAM BAL Benchmarks (Dubrovnik)All times in seconds (Multifrontal / Standard). dubrovnik‑16‑22106
dubrovnik‑88‑64298
dubrovnik‑135‑90642
Synthetic Chain Benchmarks (timeMultifrontalSolver)All times in seconds.
|
dellaert
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks ! PS, timing of MFS should not affected by error. Only shows up in nonlinear optimizer. There, BTW, we call it twice, one for delta and one for zero. I think that may be replaced with one new method errorDelta(delta) which omits the b add.
We also now directly assemble the new
GaussianConditionalinstead of using thecopy-then-offsetstrategy.During the implementation I also discovered some latent bugs related to the iteration order of the
VectorValues.ReplaceFastMap-basedConcurrentMapfallback withstd::unordered_mapwhen TBB is disabled.BayesTree::equalslogic and relatedValueshandling.Point2/Point3constructor unused variable warnings.