gtsam
Loading...
Searching...
No Matches
FastSync-inl.h
Go to the documentation of this file.
1/* ----------------------------------------------------------------------------
2
3 * GTSAM Copyright 2010, Georgia Tech Research Corporation,
4 * Atlanta, Georgia 30332-0415
5 * All Rights Reserved
6 * Authors: Frank Dellaert, et al. (see THANKS for the full author list)
7
8 * See LICENSE for the license information
9
10 * -------------------------------------------------------------------------- */
11
16
17#pragma once
18
25
26#include <cmath>
27#include <stdexcept>
28#include <type_traits>
29
30namespace gtsam {
31
32template <class T>
33double FastSync<T>::isotropicSigma(const SharedNoiseModel& model) {
34 const auto isotropic =
35 std::dynamic_pointer_cast<noiseModel::Isotropic>(model);
36 if (!isotropic) {
37 throw std::invalid_argument("FastSync requires isotropic noise model");
38 }
39 return isotropic->sigma();
40}
41
42template <class T>
44 const auto addMeasurement = [this](Key key1, Key key2,
45 const T& measurement,
46 const SharedNoiseModel& model,
47 size_t expectedNoiseDimension) {
48 if (model->dim() != expectedNoiseDimension) {
49 throw std::invalid_argument(
50 "fastSync noise dimension does not match the factor residual");
51 }
52 const double sigma = isotropicSigma(model);
53 if (!std::isfinite(sigma) || sigma <= 0.0) {
54 throw std::invalid_argument(
55 "FastSync requires finite, positive measurement sigmas");
56 }
57 const MatrixN firstBlock = -measurement.matrix().transpose();
58 // Whitening by sigma gives the paper's precision kappa = 1 / sigma^2.
59 reducedGraph_.emplace_shared<JacobianFactor>(
60 key1, firstBlock, key2, MatrixN::Identity(), VectorN::Zero(),
62 };
63 const auto addPrior = [this](Key key, const T& value) {
64 if (++priorCount_ > 1) {
65 throw std::invalid_argument(
66 "fastSync supports at most one matching prior");
67 }
68 priorKey_ = key;
69 priorValue_ = value;
70 };
71
72 for (const auto& factor : graph) {
73 if (const auto between =
74 std::dynamic_pointer_cast<BetweenFactor<T>>(factor)) {
75 addMeasurement(between->key1(), between->key2(), between->measured(),
76 between->noiseModel(), T::dimension);
77 } else if (const auto between =
78 std::dynamic_pointer_cast<FrobeniusBetweenFactor<T>>(
79 factor)) {
80 addMeasurement(between->key1(), between->key2(), between->measured(),
81 between->noiseModel(), N * N);
82 } else if (const auto prior =
83 std::dynamic_pointer_cast<PriorFactor<T>>(factor)) {
84 addPrior(prior->key(), prior->prior());
85 } else if (const auto prior =
86 std::dynamic_pointer_cast<FrobeniusPrior<T>>(factor)) {
87 addPrior(prior->key(),
88 FastSyncProjection<T>::project(prior->priorMatrix()));
89 }
90 }
91 if (reducedGraph_.empty()) {
92 throw std::invalid_argument(
93 "FastSync requires at least one between measurement");
94 }
95}
96
97template <class T>
98void FastSync<T>::backSubstituteConditional(
99 const GaussianConditional& conditional, const Key& gaugeKey,
100 Values& solution) {
101 const Key frontalKey = conditional.firstFrontalKey();
102 if (frontalKey == gaugeKey) return;
103 if (conditional.nrFrontals() != 1) {
104 throw std::runtime_error(
105 "FastSync expected one frontal variable per conditional");
106 }
107
108 // The conditional encodes the paper's block equation
109 // X_j R_jj.transpose() + sum_k X_k R_jk.transpose() = 0.
110 MatrixN sum = MatrixN::Zero();
111 size_t parentIndex = 0;
112 for (const Key parentKey : conditional.parents()) {
113 if (!solution.exists(parentKey)) {
114 throw std::runtime_error(
115 "FastSync encountered an unsolved separator variable");
116 }
117 const MatrixN parentBlock = conditional.S().template block<N, N>(
118 0, static_cast<Eigen::Index>(parentIndex * N));
119 sum.noalias() += solution.at<MatrixN>(parentKey) * parentBlock.transpose();
120 ++parentIndex;
121 }
122
123 const MatrixN R = conditional.R();
124 const MatrixN transposeEstimate =
125 -R.template triangularView<Eigen::Upper>().solve(sum.transpose());
126 solution.insert(frontalKey, MatrixN(transposeEstimate.transpose()));
127}
128
129template <class T>
131 return solveOrdered(Ordering::Create(orderingType, reducedGraph_));
132}
133
134template <class T>
135Values FastSync<T>::solve(const Ordering& ordering) const {
136 const KeySet graphKeys = reducedGraph_.keys();
137 const KeySet orderingKeys(ordering);
138 if (ordering.size() != graphKeys.size() || orderingKeys != graphKeys) {
139 throw std::invalid_argument(
140 "FastSync ordering must contain every measurement graph key exactly "
141 "once");
142 }
143 return solveOrdered(ordering);
144}
145
146template <class T>
147Values FastSync<T>::solveOrdered(const Ordering& ordering) const {
148 const MatrixN identity = MatrixN::Identity();
149 const VectorN zero = VectorN::Zero();
150
151 GaussianFactorGraph graph = reducedGraph_;
152 const Key gaugeKey = ordering.back();
153 graph.emplace_shared<JacobianFactor>(gaugeKey, identity, zero,
155
156 const auto bayesNet =
158 if (!bayesNet || bayesNet->size() != ordering.size()) {
159 throw std::runtime_error("FastSync sequential Cholesky elimination failed");
160 }
161
162 Values solution;
163 solution.insert(gaugeKey, identity);
164 for (size_t reverseIndex = bayesNet->size(); reverseIndex > 0;
165 --reverseIndex) {
166 const auto& conditional = bayesNet->at(reverseIndex - 1);
167 backSubstituteConditional(*conditional, gaugeKey, solution);
168 }
169
170 if (solution.size() != ordering.size()) {
171 throw std::runtime_error("FastSync block back-substitution failed");
172 }
173 return solution;
174}
175
176template <class T>
178 Values projected;
179 for (const Key key : relaxed.keys()) {
180 projected.insert(key,
181 FastSyncProjection<T>::project(relaxed.at<MatrixN>(key)));
182 }
183
184 if (priorCount_ == 0) return projected;
185 if (!projected.exists(priorKey_)) {
186 throw std::invalid_argument(
187 "fastSync prior key is not in the measurement graph");
188 }
189
190 // Align with one common left transformation, preserving relative estimates.
191 const T estimatedPrior = projected.at<T>(priorKey_);
192 const T alignment =
193 traits<T>::Compose(priorValue_, traits<T>::Inverse(estimatedPrior));
194 Values aligned;
195 for (const auto& keyValue : projected.extract<T>()) {
196 aligned.insert(keyValue.first,
197 traits<T>::Compose(alignment, keyValue.second));
198 }
199 return aligned;
200}
201
202/* ************************************************************************* */
203template <class T>
205 Ordering::OrderingType orderingType) {
206 GTSAM_CONCEPT_ASSERT(IsMatrixLieGroup<T>);
207 const FastSync<T> solver(graph);
208 const Values relaxed = solver.solve(orderingType);
209 return solver.projectAndAlign(relaxed);
210}
211
212/* ************************************************************************* */
213template <class T>
214Values fastSync(const NonlinearFactorGraph& graph, const Ordering& ordering) {
215 GTSAM_CONCEPT_ASSERT(IsMatrixLieGroup<T>);
216 const FastSync<T> solver(graph);
217 const Values relaxed = solver.solve(ordering);
218 return solver.projectAndAlign(relaxed);
219}
220
221} // namespace gtsam
Variable ordering for the elimination algorithm.
Chordal Bayes Net, the result of eliminating a factor graph.
Linear Factor Graph where all factors are Gaussians.
Various factors that minimize some Frobenius norm.
std::pair< std::shared_ptr< GaussianConditional >, std::shared_ptr< GaussianFactor > > EliminatePreferCholesky(const GaussianFactorGraph &factors, const Ordering &keys)
Densely partially eliminate with Cholesky factorization.
Definition HessianFactor.cpp:646
Global functions in a separate testing namespace.
Definition chartTesting.h:28
Values fastSync(const NonlinearFactorGraph &graph, Ordering::OrderingType orderingType)
Initialize a synchronization graph using FAST-Sync.
Definition FastSync-inl.h:204
noiseModel::Base::shared_ptr SharedNoiseModel
Aliases.
Definition NoiseModel.h:846
std::uint64_t Key
Integer nonlinear key type.
Definition types.h:43
A manifold defines a space in which there is a notion of a linear tangent space that can be centered ...
Definition Group.h:37
Matrix Lie Group Concept.
Definition MatrixLieGroup.h:358
IsDerived< DERIVEDFACTOR > emplace_shared(Args &&... args)
Emplace a shared pointer to factor of given type.
Definition FactorGraph.h:153
Key firstFrontalKey() const
Convenience function to get the first frontal key.
Definition Conditional.h:139
Parents parents() const
return a view of the parent keys
Definition Conditional.h:150
size_t nrFrontals() const
return the number of frontals
Definition Conditional.h:133
std::shared_ptr< BayesNetType > eliminateSequential(OptionalOrderingType orderingType={}, const Eliminate &function=EliminationTraitsType::DefaultEliminate, OptionalVariableIndex variableIndex={}) const
Do sequential elimination of all variables to produce a Bayes net.
Definition EliminateableFactorGraph-inst.h:36
size_t size() const
Definition Factor.h:160
Definition Ordering.h:33
OrderingType
Type of ordering to use.
Definition Ordering.h:40
A GaussianConditional functions as the node in a Bayes network.
Definition GaussianConditional.h:43
constABlock R() const
Return a view of the upper-triangular R block of the conditional.
Definition GaussianConditional.h:237
constABlock S() const
Get a view of the parent blocks.
Definition GaussianConditional.h:240
A Linear Factor Graph is a factor graph where all factors are Gaussian, i.e.
Definition GaussianFactorGraph.h:77
A Gaussian factor in the squared-error form.
Definition JacobianFactor.h:92
static shared_ptr Sigma(size_t dim, double sigma, bool smart=true)
An isotropic noise model created by specifying a standard deviation sigma.
Definition NoiseModel.cpp:706
static shared_ptr Create(size_t dim)
Create a unit covariance noise model.
Definition NoiseModel.h:673
Definition NonlinearFactorGraph.h:57
A class for a soft prior on any Value type.
Definition PriorFactor.h:36
A non-templated config holding any types of Manifold-group elements.
Definition Values.h:65
const ValueType at(Key j) const
Retrieve a variable by key j.
Definition Values-inl.h:260
void insert(Key j, const Value &val)
Add a variable with the given j, throws KeyAlreadyExists<J> if j is already present.
Definition Values.cpp:170
KeyVector keys() const
Returns a vector of keys in the config.
Definition Values.cpp:235
Values extract(const KeyVector &keys) const
Returns a new Values holding copies of the values at the given keys, whatever their types.
Definition Values.cpp:252
bool exists(Key j) const
Check if a value exists with key j.
Definition Values.cpp:95
A class for a measurement predicted by "between(config[key1],config[key2])".
Definition BetweenFactor.h:45
Projection customization point used by fastSync().
Definition FastSync.h:54
Solver for the fixed-size ambient linear problem underlying FAST-Sync.
Definition FastSync.h:198
Values solve(Ordering::OrderingType orderingType=Ordering::METIS) const
Solve the relaxed ambient matrix problem and return one matrix per key.
Definition FastSync-inl.h:130
Values projectAndAlign(const Values &relaxed) const
Project relaxed matrices to T and align them to the optional matching prior stored by the constructor...
Definition FastSync-inl.h:177
FastSync(const NonlinearFactorGraph &graph)
Extract matching factors, validate their noise models, and build the reduced Gaussian graph.
Definition FastSync-inl.h:43
FrobeniusPrior calculates the Frobenius norm between a given matrix and a fixed-size matrix Lie group...
Definition FrobeniusFactor.h:100
FrobeniusBetweenFactor uses ||T2 - T1*T12_||_F, which only works if the Frobenius error is invariant ...
Definition FrobeniusFactor.h:366
In nonlinear factors, the error function returns the negative log-likelihood as a non-linear function...