testIncrementalFixedLagSmoother.cpp
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 
22 #include <gtsam/geometry/Point2.h>
24 #include <gtsam/nonlinear/Values.h>
27 #include <gtsam/inference/Key.h>
29 #include <gtsam/inference/Symbol.h>
30 #include <gtsam/base/debug.h>
31 
33 
34 using namespace std;
35 using namespace gtsam;
36 
37 Key MakeKey(size_t index) { return Symbol('x', index); }
38 
39 /* ************************************************************************* */
40 bool check_smoother(const NonlinearFactorGraph& fullgraph, const Values& fullinit, const IncrementalFixedLagSmoother& smoother, const Key& key) {
41 
42  GaussianFactorGraph linearized = *fullgraph.linearize(fullinit);
43  VectorValues delta = linearized.optimize();
44  Values fullfinal = fullinit.retract(delta);
45 
46  Point2 expected = fullfinal.at<Point2>(key);
47  Point2 actual = smoother.calculateEstimate<Point2>(key);
48 
49  return assert_equal(expected, actual);
50 }
51 
52 /* ************************************************************************* */
54  const ISAM2Clique::shared_ptr& clique, const std::string indent = "") {
55 
56  // Print the current clique
57  std::cout << indent << "P( ";
58  for(Key key: clique->conditional()->frontals()) {
59  std::cout << DefaultKeyFormatter(key) << " ";
60  }
61  if (clique->conditional()->nrParents() > 0)
62  std::cout << "| ";
63  for(Key key: clique->conditional()->parents()) {
64  std::cout << DefaultKeyFormatter(key) << " ";
65  }
66  std::cout << ")" << std::endl;
67 
68  // Recursively print all of the children
69  for(const ISAM2Clique::shared_ptr& child: clique->children) {
70  PrintSymbolicTreeHelper(child, indent + " ");
71  }
72 }
73 
74 /* ************************************************************************* */
76  const std::string& label) {
77  std::cout << label << std::endl;
78  if (!isam.roots().empty()) {
79  for(const ISAM2::sharedClique& root: isam.roots()) {
81  }
82  } else
83  std::cout << "{Empty Tree}" << std::endl;
84 }
85 
86 
87 /* ************************************************************************* */
89 {
90  // Test the IncrementalFixedLagSmoother in a pure linear environment. Thus, full optimization and
91  // the IncrementalFixedLagSmoother should be identical (even with the linearized approximations at
92  // the end of the smoothing lag)
93 
94  SETDEBUG("IncrementalFixedLagSmoother update", true);
95 
96  // Set up parameters
97  SharedDiagonal odometerNoise = noiseModel::Diagonal::Sigmas(Vector2(0.1, 0.1));
98  SharedDiagonal loopNoise = noiseModel::Diagonal::Sigmas(Vector2(0.1, 0.1));
99 
100  // Create a Fixed-Lag Smoother
101  typedef IncrementalFixedLagSmoother::KeyTimestampMap Timestamps;
102  IncrementalFixedLagSmoother smoother(12.0, ISAM2Params());
103 
104  // Create containers to keep the full graph
105  Values fullinit;
106  NonlinearFactorGraph fullgraph;
107 
108  // i keeps track of the time step
109  size_t i = 0;
110 
111  // Add a prior at time 0 and update the HMF
112  {
113  Key key0 = MakeKey(0);
114 
115  NonlinearFactorGraph newFactors;
116  Values newValues;
117  Timestamps newTimestamps;
118 
119  newFactors.addPrior(key0, Point2(0.0, 0.0), odometerNoise);
120  newValues.insert(key0, Point2(0.01, 0.01));
121  newTimestamps[key0] = 0.0;
122 
123  fullgraph.push_back(newFactors);
124  fullinit.insert(newValues);
125 
126  // Update the smoother
127  smoother.update(newFactors, newValues, newTimestamps);
128 
129  // Check
130  CHECK(check_smoother(fullgraph, fullinit, smoother, key0));
131 
132  ++i;
133  }
134 
135  // Add odometry from time 0 to time 5
136  while(i <= 5) {
137  Key key1 = MakeKey(i-1);
138  Key key2 = MakeKey(i);
139 
140  NonlinearFactorGraph newFactors;
141  Values newValues;
142  Timestamps newTimestamps;
143 
144  newFactors.push_back(BetweenFactor<Point2>(key1, key2, Point2(1.0, 0.0), odometerNoise));
145  newValues.insert(key2, Point2(double(i)+0.1, -0.1));
146  newTimestamps[key2] = double(i);
147 
148  fullgraph.push_back(newFactors);
149  fullinit.insert(newValues);
150 
151  // Update the smoother
152  smoother.update(newFactors, newValues, newTimestamps);
153 
154  // Check
155  CHECK(check_smoother(fullgraph, fullinit, smoother, key2));
156 
157  ++i;
158  }
159 
160  // Add odometry from time 5 to 6 to the HMF and a loop closure at time 5 to the TSM
161  {
162  // Add the odometry factor to the HMF
163  Key key1 = MakeKey(i-1);
164  Key key2 = MakeKey(i);
165 
166  NonlinearFactorGraph newFactors;
167  Values newValues;
168  Timestamps newTimestamps;
169 
170  newFactors.push_back(BetweenFactor<Point2>(key1, key2, Point2(1.0, 0.0), odometerNoise));
171  newFactors.push_back(BetweenFactor<Point2>(MakeKey(2), MakeKey(5), Point2(3.5, 0.0), loopNoise));
172  newValues.insert(key2, Point2(double(i)+0.1, -0.1));
173  newTimestamps[key2] = double(i);
174 
175  fullgraph.push_back(newFactors);
176  fullinit.insert(newValues);
177 
178  // Update the smoother
179  smoother.update(newFactors, newValues, newTimestamps);
180 
181  // Check
182  CHECK(check_smoother(fullgraph, fullinit, smoother, key2));
183 
184  ++i;
185  }
186 
187  // Add odometry from time 6 to time 15
188  while(i <= 15) {
189  Key key1 = MakeKey(i-1);
190  Key key2 = MakeKey(i);
191 
192  NonlinearFactorGraph newFactors;
193  Values newValues;
194  Timestamps newTimestamps;
195 
196  // Add the odometry factor twice to ensure the removeFactor test below works,
197  // where we need to keep the connectivity of the graph.
198  newFactors.push_back(BetweenFactor<Point2>(key1, key2, Point2(1.0, 0.0), odometerNoise));
199  newFactors.push_back(BetweenFactor<Point2>(key1, key2, Point2(1.0, 0.0), odometerNoise));
200  newValues.insert(key2, Point2(double(i)+0.1, -0.1));
201  newTimestamps[key2] = double(i);
202 
203  fullgraph.push_back(newFactors);
204  fullinit.insert(newValues);
205 
206  // Update the smoother
207  smoother.update(newFactors, newValues, newTimestamps);
208 
209  // Check
210  CHECK(check_smoother(fullgraph, fullinit, smoother, key2));
211 
212  ++i;
213  }
214 
215  // add/remove an extra factor
216  {
217  Key key1 = MakeKey(i-1);
218  Key key2 = MakeKey(i);
219 
220  NonlinearFactorGraph newFactors;
221  Values newValues;
222  Timestamps newTimestamps;
223 
224  // add 2 odometry factors
225  newFactors.push_back(BetweenFactor<Point2>(key1, key2, Point2(1.0, 0.0), odometerNoise));
226  newFactors.push_back(BetweenFactor<Point2>(key1, key2, Point2(1.0, 0.0), odometerNoise));
227  newValues.insert(key2, Point2(double(i)+0.1, -0.1));
228  newTimestamps[key2] = double(i);
229  ++i;
230 
231  fullgraph.push_back(newFactors);
232  fullinit.insert(newValues);
233 
234  // Update the smoother
235  smoother.update(newFactors, newValues, newTimestamps);
236 
237  // Check
238  CHECK(check_smoother(fullgraph, fullinit, smoother, key2));
239 
240  // now remove one of the two and try again
241  // empty values and new factors for fake update in which we only remove factors
242  NonlinearFactorGraph emptyNewFactors;
243  Values emptyNewValues;
244  Timestamps emptyNewTimestamps;
245 
246  size_t factorIndex = 25; // any index that does not break connectivity of the graph
247  FactorIndices factorToRemove;
248  factorToRemove.push_back(factorIndex);
249 
250  const NonlinearFactorGraph smootherFactorsBeforeRemove = smoother.getFactors();
251 
252  std::cout << "fullgraph.size() = " << fullgraph.size() << std::endl;
253  std::cout << "smootherFactorsBeforeRemove.size() = "
254  << smootherFactorsBeforeRemove.size() << std::endl;
255 
256  // remove factor
257  smoother.update(emptyNewFactors, emptyNewValues, emptyNewTimestamps,factorToRemove);
258 
259  // Note: the following test (checking that the number of factor is reduced by 1)
260  // fails since we are not reusing slots, hence also when removing a factor we do not change
261  // the size of the factor graph
262  // size_t nrFactorsAfterRemoval = smoother.getFactors().size();
263  // DOUBLES_EQUAL(nrFactorsBeforeRemoval-1, nrFactorsAfterRemoval, 1e-5);
264 
265  // check that the factors in the smoother are right
266  NonlinearFactorGraph actual = smoother.getFactors();
267  for(size_t i=0; i< smootherFactorsBeforeRemove.size(); i++){
268  // check that the factors that were not removed are there
269  if(smootherFactorsBeforeRemove[i] && i != factorIndex){
270  EXPECT(smootherFactorsBeforeRemove[i]->equals(*actual[i]));
271  }
272  else{ // while the factors that were not there or were removed are no longer there
273  EXPECT(!actual[i]);
274  }
275  }
276  }
277 
278  {
279  SETDEBUG("BayesTreeMarginalizationHelper", true);
280  PrintSymbolicTree(smoother.getISAM2(), "Bayes Tree Before marginalization test:");
281 
282  // Do pressure test on marginalization. Enlarge max_i to enhance the test.
283  const int max_i = 500;
284  while(i <= max_i) {
285  Key key_0 = MakeKey(i);
286  Key key_1 = MakeKey(i-1);
287  Key key_2 = MakeKey(i-2);
288  Key key_3 = MakeKey(i-3);
289  Key key_4 = MakeKey(i-4);
290  Key key_5 = MakeKey(i-5);
291  Key key_6 = MakeKey(i-6);
292  Key key_7 = MakeKey(i-7);
293  Key key_8 = MakeKey(i-8);
294  Key key_9 = MakeKey(i-9);
295  Key key_10 = MakeKey(i-10);
296 
297  NonlinearFactorGraph newFactors;
298  Values newValues;
299  Timestamps newTimestamps;
300 
301  // To make a complex graph
302  newFactors.push_back(BetweenFactor<Point2>(key_1, key_0, Point2(1.0, 0.0), odometerNoise));
303  if (i % 2 == 0)
304  newFactors.push_back(BetweenFactor<Point2>(key_2, key_1, Point2(1.0, 0.0), odometerNoise));
305  if (i % 3 == 0)
306  newFactors.push_back(BetweenFactor<Point2>(key_3, key_2, Point2(1.0, 0.0), odometerNoise));
307  if (i % 4 == 0)
308  newFactors.push_back(BetweenFactor<Point2>(key_4, key_3, Point2(1.0, 0.0), odometerNoise));
309  if (i % 5 == 0)
310  newFactors.push_back(BetweenFactor<Point2>(key_5, key_4, Point2(1.0, 0.0), odometerNoise));
311  if (i % 6 == 0)
312  newFactors.push_back(BetweenFactor<Point2>(key_6, key_5, Point2(1.0, 0.0), odometerNoise));
313  if (i % 7 == 0)
314  newFactors.push_back(BetweenFactor<Point2>(key_7, key_6, Point2(1.0, 0.0), odometerNoise));
315  if (i % 8 == 0)
316  newFactors.push_back(BetweenFactor<Point2>(key_8, key_7, Point2(1.0, 0.0), odometerNoise));
317  if (i % 9 == 0)
318  newFactors.push_back(BetweenFactor<Point2>(key_9, key_8, Point2(1.0, 0.0), odometerNoise));
319  if (i % 10 == 0)
320  newFactors.push_back(BetweenFactor<Point2>(key_10, key_9, Point2(1.0, 0.0), odometerNoise));
321 
322  newValues.insert(key_0, Point2(double(i)+0.1, -0.1));
323  newTimestamps[key_0] = double(i);
324 
325  fullgraph.push_back(newFactors);
326  fullinit.insert(newValues);
327 
328  // Update the smoother
329  smoother.update(newFactors, newValues, newTimestamps);
330 
331  // Check
332  CHECK(check_smoother(fullgraph, fullinit, smoother, key_0));
333  PrintSymbolicTree(smoother.getISAM2(), "Bayes Tree marginalization test: i = " + std::to_string(i));
334 
335  ++i;
336  }
337  }
338 }
339 
340 /* ************************************************************************* */
341 int main() { TestResult tr; return TestRegistry::runAllTests(tr);}
342 /* ************************************************************************* */
key1
const Symbol key1('v', 1)
TestRegistry::runAllTests
static int runAllTests(TestResult &result)
Definition: TestRegistry.cpp:27
gtsam::ISAM2Params
Definition: ISAM2Params.h:136
check_smoother
bool check_smoother(const NonlinearFactorGraph &fullgraph, const Values &fullinit, const IncrementalFixedLagSmoother &smoother, const Key &key)
Definition: testIncrementalFixedLagSmoother.cpp:40
main
int main()
Definition: testIncrementalFixedLagSmoother.cpp:341
GaussianFactorGraph.h
Linear Factor Graph where all factors are Gaussians.
gtsam::ISAM2
Definition: ISAM2.h:45
SETDEBUG
#define SETDEBUG(S, V)
Definition: debug.h:61
EXPECT
#define EXPECT(condition)
Definition: Test.h:150
gtsam::Vector2
Eigen::Vector2d Vector2
Definition: Vector.h:43
TestHarness.h
gtsam::NonlinearFactorGraph::linearize
std::shared_ptr< GaussianFactorGraph > linearize(const Values &linearizationPoint) const
Linearize a nonlinear factor graph.
Definition: NonlinearFactorGraph.cpp:239
Ordering.h
Variable ordering for the elimination algorithm.
GaussianBayesNet.h
Chordal Bayes Net, the result of eliminating a factor graph.
gtsam::ISAM2::sharedClique
Base::sharedClique sharedClique
Shared pointer to a clique.
Definition: ISAM2.h:103
Point2.h
2D Point
gtsam::DefaultKeyFormatter
KeyFormatter DefaultKeyFormatter
Assign default key formatter.
Definition: Key.cpp:30
Key.h
gtsam::GaussianFactorGraph
Definition: GaussianFactorGraph.h:73
gtsam::Values::at
const ValueType at(Key j) const
Definition: Values-inl.h:261
gtsam::Values::retract
Values retract(const VectorValues &delta) const
Definition: Values.cpp:99
gtsam::IncrementalFixedLagSmoother::update
Result update(const NonlinearFactorGraph &newFactors=NonlinearFactorGraph(), const Values &newTheta=Values(), const KeyTimestampMap &timestamps=KeyTimestampMap(), const FactorIndices &factorsToRemove=FactorIndices()) override
Definition: IncrementalFixedLagSmoother.cpp:45
gtsam::IncrementalFixedLagSmoother
Definition: IncrementalFixedLagSmoother.h:34
gtsam.examples.PlanarManipulatorExample.delta
def delta(g0, g1)
Definition: PlanarManipulatorExample.py:45
key2
const Symbol key2('v', 2)
gtsam::VectorValues
Definition: VectorValues.h:74
BetweenFactor.h
PrintSymbolicTree
void PrintSymbolicTree(const ISAM2 &isam, const std::string &label)
Definition: testIncrementalFixedLagSmoother.cpp:75
PrintSymbolicTreeHelper
void PrintSymbolicTreeHelper(const ISAM2Clique::shared_ptr &clique, const std::string indent="")
Definition: testIncrementalFixedLagSmoother.cpp:53
MakeKey
Key MakeKey(size_t index)
Definition: testIncrementalFixedLagSmoother.cpp:37
isam
NonlinearISAM isam(relinearizeInterval)
gtsam::NonlinearFactorGraph
Definition: NonlinearFactorGraph.h:55
gtsam::IncrementalFixedLagSmoother::getISAM2
const ISAM2 & getISAM2() const
Get the iSAM2 object which is used for the inference internally.
Definition: IncrementalFixedLagSmoother.h:118
gtsam::SharedDiagonal
noiseModel::Diagonal::shared_ptr SharedDiagonal
Definition: NoiseModel.h:764
cholesky::expected
Matrix expected
Definition: testMatrix.cpp:971
gtsam::NonlinearFactorGraph::addPrior
void addPrior(Key key, const T &prior, const SharedNoiseModel &model=nullptr)
Definition: NonlinearFactorGraph.h:199
Symbol.h
gtsam::Point2
Vector2 Point2
Definition: Point2.h:32
gtsam::equals
Definition: Testable.h:112
TestResult
Definition: TestResult.h:26
key
const gtsam::Symbol key('X', 0)
IncrementalFixedLagSmoother.h
An iSAM2-based fixed-lag smoother.
gtsam::FactorGraph::size
size_t size() const
Definition: FactorGraph.h:297
gtsam::ISAM2Clique::shared_ptr
std::shared_ptr< This > shared_ptr
Definition: ISAM2Clique.h:41
gtsam::IncrementalFixedLagSmoother::getFactors
const NonlinearFactorGraph & getFactors() const
Definition: IncrementalFixedLagSmoother.h:95
gtsam
traits
Definition: SFMdata.h:40
TEST
TEST(IncrementalFixedLagSmoother, Example)
Definition: testIncrementalFixedLagSmoother.cpp:88
NonlinearFactorGraph.h
Factor Graph consisting of non-linear factors.
gtsam::FactorGraph::push_back
IsDerived< DERIVEDFACTOR > push_back(std::shared_ptr< DERIVEDFACTOR > factor)
Add a factor directly using a shared_ptr.
Definition: FactorGraph.h:147
gtsam::Values
Definition: Values.h:65
CHECK
#define CHECK(condition)
Definition: Test.h:108
std
Definition: BFloat16.h:88
gtsam::Values::insert
void insert(Key j, const Value &val)
Definition: Values.cpp:156
gtsam::assert_equal
bool assert_equal(const Matrix &expected, const Matrix &actual, double tol)
Definition: Matrix.cpp:41
gtsam::IncrementalFixedLagSmoother::calculateEstimate
Values calculateEstimate() const override
Definition: IncrementalFixedLagSmoother.h:74
gtsam::GaussianFactorGraph::optimize
VectorValues optimize(const Eliminate &function=EliminationTraitsType::DefaultEliminate) const
Definition: GaussianFactorGraph.cpp:309
gtsam::Key
std::uint64_t Key
Integer nonlinear key type.
Definition: types.h:97
i
int i
Definition: BiCGSTAB_step_by_step.cpp:9
Values.h
A non-templated config holding any types of Manifold-group elements.
debug.h
Global debugging flags.
gtsam::Symbol
Definition: inference/Symbol.h:37
gtsam::FactorIndices
FastVector< FactorIndex > FactorIndices
Define collection types:
Definition: Factor.h:37
gtsam::BetweenFactor
Definition: BetweenFactor.h:40


gtsam
Author(s):
autogenerated on Sun Dec 22 2024 04:16:31