testConcurrentIncrementalSmootherGN.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/nonlinear/ISAM2.h>
26 #include <gtsam/nonlinear/Values.h>
27 #include <gtsam/inference/Symbol.h>
28 #include <gtsam/inference/Key.h>
30 #include <gtsam/geometry/Pose3.h>
33 
34 using namespace std;
35 using namespace gtsam;
36 
37 namespace {
38 
39 // Set up initial pose, odometry difference, loop closure difference, and initialization errors
40 const Pose3 poseInitial;
41 const Pose3 poseOdometry( Rot3::RzRyRx(Vector3(0.05, 0.10, -0.75)), Point3(1.0, -0.25, 0.10) );
42 const Pose3 poseError( Rot3::RzRyRx(Vector3(0.01, 0.02, -0.1)), Point3(0.05, -0.05, 0.02) );
43 
44 // Set up noise models for the factors
45 const SharedDiagonal noisePrior = noiseModel::Isotropic::Sigma(6, 0.10);
46 const SharedDiagonal noiseOdometery = noiseModel::Diagonal::Sigmas((Vector(6) << 0.1, 0.1, 0.1, 0.5, 0.5, 0.5).finished());
47 const SharedDiagonal noiseLoop = noiseModel::Diagonal::Sigmas((Vector(6) << 0.25, 0.25, 0.25, 1.0, 1.0, 1.0).finished());
48 
49 /* ************************************************************************* */
50 Values BatchOptimize(const NonlinearFactorGraph& graph, const Values& theta, int maxIter = 100) {
51 
52  // Create an L-M optimizer
55 // parameters.maxIterations = maxIter;
56 // parameters.lambdaUpperBound = 1;
57 // parameters.lambdaInitial = 1;
58 // parameters.verbosity = NonlinearOptimizerParams::ERROR;
59 // parameters.verbosityLM = ISAM2Params::DAMPED;
60 // parameters.linearSolverType = NonlinearOptimizerParams::MULTIFRONTAL_QR;
61 
62  ISAM2 optimizer(parameters);
63  optimizer.update( graph, theta );
64  Values result = optimizer.calculateEstimate();
65  return result;
66 
67 }
68 
69 } // end namespace
70 
71 
72 
73 
74 /* ************************************************************************* */
75 TEST( ConcurrentIncrementalSmootherGN, equals )
76 {
77  // TODO: Test 'equals' more vigorously
78 
79  // Create a Concurrent Batch Smoother
80  ISAM2Params parameters1;
82  ConcurrentIncrementalSmoother smoother1(parameters1);
83 
84  // Create an identical Concurrent Batch Smoother
85  ISAM2Params parameters2;
87  ConcurrentIncrementalSmoother smoother2(parameters2);
88 
89  // Create a different Concurrent Batch Smoother
90  ISAM2Params parameters3;
92 // parameters3.maxIterations = 1;
93  ConcurrentIncrementalSmoother smoother3(parameters3);
94 
95  CHECK(assert_equal(smoother1, smoother1));
96  CHECK(assert_equal(smoother1, smoother2));
97 // CHECK(assert_inequal(smoother1, smoother3));
98 }
99 
100 /* ************************************************************************* */
101 TEST( ConcurrentIncrementalSmootherGN, getFactors )
102 {
103  // Create a Concurrent Batch Smoother
106  ConcurrentIncrementalSmoother smoother(parameters);
107 
108  // Expected graph is empty
109  NonlinearFactorGraph expected1;
110  // Get actual graph
111  NonlinearFactorGraph actual1 = smoother.getFactors();
112  // Check
113  CHECK(assert_equal(expected1, actual1));
114 
115  // Add some factors to the smoother
116  NonlinearFactorGraph newFactors1;
117  newFactors1.addPrior(1, poseInitial, noisePrior);
118  newFactors1.push_back(BetweenFactor<Pose3>(1, 2, poseOdometry, noiseOdometery));
119  Values newValues1;
120  newValues1.insert(1, Pose3());
121  newValues1.insert(2, newValues1.at<Pose3>(1).compose(poseOdometry));
122  smoother.update(newFactors1, newValues1);
123 
124  // Expected graph
125  NonlinearFactorGraph expected2;
126  expected2.push_back(newFactors1);
127  // Get actual graph
128  NonlinearFactorGraph actual2 = smoother.getFactors();
129  // Check
130  CHECK(assert_equal(expected2, actual2));
131 
132  // Add some more factors to the smoother
133  NonlinearFactorGraph newFactors2;
134  newFactors2.push_back(BetweenFactor<Pose3>(2, 3, poseOdometry, noiseOdometery));
135  newFactors2.push_back(BetweenFactor<Pose3>(3, 4, poseOdometry, noiseOdometery));
136  Values newValues2;
137  newValues2.insert(3, newValues1.at<Pose3>(2).compose(poseOdometry));
138  newValues2.insert(4, newValues2.at<Pose3>(3).compose(poseOdometry));
139  smoother.update(newFactors2, newValues2);
140 
141  // Expected graph
142  NonlinearFactorGraph expected3;
143  expected3.push_back(newFactors1);
144  expected3.push_back(newFactors2);
145  // Get actual graph
146  NonlinearFactorGraph actual3 = smoother.getFactors();
147  // Check
148  CHECK(assert_equal(expected3, actual3));
149 }
150 
151 /* ************************************************************************* */
152 TEST( ConcurrentIncrementalSmootherGN, getLinearizationPoint )
153 {
154  // Create a Concurrent Batch Smoother
157  ConcurrentIncrementalSmoother smoother(parameters);
158 
159  // Expected values is empty
160  Values expected1;
161  // Get Linearization Point
162  Values actual1 = smoother.getLinearizationPoint();
163  // Check
164  CHECK(assert_equal(expected1, actual1));
165 
166  // Add some factors to the smoother
167  NonlinearFactorGraph newFactors1;
168  newFactors1.addPrior(1, poseInitial, noisePrior);
169  newFactors1.push_back(BetweenFactor<Pose3>(1, 2, poseOdometry, noiseOdometery));
170  Values newValues1;
171  newValues1.insert(1, Pose3());
172  newValues1.insert(2, newValues1.at<Pose3>(1).compose(poseOdometry));
173  smoother.update(newFactors1, newValues1);
174 
175  // Expected values is equivalent to the provided values only because the provided linearization points were optimal
176  Values expected2;
177  expected2.insert(newValues1);
178  // Get actual linearization point
179  Values actual2 = smoother.getLinearizationPoint();
180  // Check
181  CHECK(assert_equal(expected2, actual2));
182 
183  // Add some more factors to the smoother
184  NonlinearFactorGraph newFactors2;
185  newFactors2.push_back(BetweenFactor<Pose3>(2, 3, poseOdometry, noiseOdometery));
186  newFactors2.push_back(BetweenFactor<Pose3>(3, 4, poseOdometry, noiseOdometery));
187  Values newValues2;
188  newValues2.insert(3, newValues1.at<Pose3>(2).compose(poseOdometry));
189  newValues2.insert(4, newValues2.at<Pose3>(3).compose(poseOdometry));
190  smoother.update(newFactors2, newValues2);
191 
192  // Expected values is equivalent to the provided values only because the provided linearization points were optimal
193  Values expected3;
194  expected3.insert(newValues1);
195  expected3.insert(newValues2);
196  // Get actual linearization point
197  Values actual3 = smoother.getLinearizationPoint();
198  // Check
199  CHECK(assert_equal(expected3, actual3));
200 }
201 
202 /* ************************************************************************* */
203 TEST( ConcurrentIncrementalSmootherGN, getDelta )
204 {
205  // TODO: Think about how to check ordering...
206 }
207 
208 /* ************************************************************************* */
209 TEST( ConcurrentIncrementalSmootherGN, calculateEstimate )
210 {
211  // Create a Concurrent Batch Smoother
214  ConcurrentIncrementalSmoother smoother(parameters);
215 
216  // Expected values is empty
217  Values expected1;
218  // Get Linearization Point
219  Values actual1 = smoother.calculateEstimate();
220  // Check
221  CHECK(assert_equal(expected1, actual1));
222 
223  // Add some factors to the smoother
224  NonlinearFactorGraph newFactors2;
225  newFactors2.addPrior(1, poseInitial, noisePrior);
226  newFactors2.push_back(BetweenFactor<Pose3>(1, 2, poseOdometry, noiseOdometery));
227  Values newValues2;
228  newValues2.insert(1, Pose3().compose(poseError));
229  newValues2.insert(2, newValues2.at<Pose3>(1).compose(poseOdometry).compose(poseError));
230  smoother.update(newFactors2, newValues2);
231 
232  // Expected values from full batch optimization
233  NonlinearFactorGraph allFactors2;
234  allFactors2.push_back(newFactors2);
235  Values allValues2;
236  allValues2.insert(newValues2);
237  Values expected2 = BatchOptimize(allFactors2, allValues2);
238  // Get actual linearization point
239  Values actual2 = smoother.calculateEstimate();
240  // Check
241  CHECK(assert_equal(expected2, actual2, 1e-6));
242 
243  // Add some more factors to the smoother
244  NonlinearFactorGraph newFactors3;
245  newFactors3.push_back(BetweenFactor<Pose3>(2, 3, poseOdometry, noiseOdometery));
246  newFactors3.push_back(BetweenFactor<Pose3>(3, 4, poseOdometry, noiseOdometery));
247  Values newValues3;
248  newValues3.insert(3, newValues2.at<Pose3>(2).compose(poseOdometry).compose(poseError));
249  newValues3.insert(4, newValues3.at<Pose3>(3).compose(poseOdometry).compose(poseError));
250  smoother.update(newFactors3, newValues3);
251 
252  // Expected values from full batch optimization
253  NonlinearFactorGraph allFactors3;
254  allFactors3.push_back(newFactors2);
255  allFactors3.push_back(newFactors3);
256  Values allValues3;
257  allValues3.insert(newValues2);
258  allValues3.insert(newValues3);
259  Values expected3 = BatchOptimize(allFactors3, allValues3);
260  // Get actual linearization point
261  Values actual3 = smoother.calculateEstimate();
262  // Check
263  CHECK(assert_equal(expected3, actual3, 1e-6));
264 
265  // Also check the single-variable version
266  Pose3 expectedPose1 = expected3.at<Pose3>(1);
267  Pose3 expectedPose2 = expected3.at<Pose3>(2);
268  Pose3 expectedPose3 = expected3.at<Pose3>(3);
269  Pose3 expectedPose4 = expected3.at<Pose3>(4);
270  // Also check the single-variable version
271  Pose3 actualPose1 = smoother.calculateEstimate<Pose3>(1);
272  Pose3 actualPose2 = smoother.calculateEstimate<Pose3>(2);
273  Pose3 actualPose3 = smoother.calculateEstimate<Pose3>(3);
274  Pose3 actualPose4 = smoother.calculateEstimate<Pose3>(4);
275  // Check
276  CHECK(assert_equal(expectedPose1, actualPose1, 1e-6));
277  CHECK(assert_equal(expectedPose2, actualPose2, 1e-6));
278  CHECK(assert_equal(expectedPose3, actualPose3, 1e-6));
279  CHECK(assert_equal(expectedPose4, actualPose4, 1e-6));
280 }
281 
282 /* ************************************************************************* */
283 TEST( ConcurrentIncrementalSmootherGN, update_empty )
284 {
285  // Create a set of optimizer parameters
288  // Create a Concurrent Batch Smoother
289  ConcurrentIncrementalSmoother smoother(parameters);
290 
291  // Call update
292  smoother.update();
293 }
294 
295 /* ************************************************************************* */
296 TEST( ConcurrentIncrementalSmootherGN, update_multiple )
297 {
298  // Create a Concurrent Batch Smoother
301  ConcurrentIncrementalSmoother smoother(parameters);
302 
303  // Expected values is empty
304  Values expected1;
305  // Get Linearization Point
306  Values actual1 = smoother.calculateEstimate();
307  // Check
308  CHECK(assert_equal(expected1, actual1));
309 
310  // Add some factors to the smoother
311  NonlinearFactorGraph newFactors2;
312  newFactors2.addPrior(1, poseInitial, noisePrior);
313  newFactors2.push_back(BetweenFactor<Pose3>(1, 2, poseOdometry, noiseOdometery));
314  Values newValues2;
315  newValues2.insert(1, Pose3().compose(poseError));
316  newValues2.insert(2, newValues2.at<Pose3>(1).compose(poseOdometry).compose(poseError));
317  smoother.update(newFactors2, newValues2);
318 
319  // Expected values from full batch optimization
320  NonlinearFactorGraph allFactors2;
321  allFactors2.push_back(newFactors2);
322  Values allValues2;
323  allValues2.insert(newValues2);
324  Values expected2 = BatchOptimize(allFactors2, allValues2);
325  // Get actual linearization point
326  Values actual2 = smoother.calculateEstimate();
327  // Check
328  CHECK(assert_equal(expected2, actual2, 1e-6));
329 
330  // Add some more factors to the smoother
331  NonlinearFactorGraph newFactors3;
332  newFactors3.push_back(BetweenFactor<Pose3>(2, 3, poseOdometry, noiseOdometery));
333  newFactors3.push_back(BetweenFactor<Pose3>(3, 4, poseOdometry, noiseOdometery));
334  Values newValues3;
335  newValues3.insert(3, newValues2.at<Pose3>(2).compose(poseOdometry).compose(poseError));
336  newValues3.insert(4, newValues3.at<Pose3>(3).compose(poseOdometry).compose(poseError));
337  smoother.update(newFactors3, newValues3);
338 
339  // Expected values from full batch optimization
340  NonlinearFactorGraph allFactors3;
341  allFactors3.push_back(newFactors2);
342  allFactors3.push_back(newFactors3);
343  Values allValues3;
344  allValues3.insert(newValues2);
345  allValues3.insert(newValues3);
346  Values expected3 = BatchOptimize(allFactors3, allValues3);
347  // Get actual linearization point
348  Values actual3 = smoother.calculateEstimate();
349  // Check
350  CHECK(assert_equal(expected3, actual3, 1e-6));
351 }
352 
353 /* ************************************************************************* */
354 TEST( ConcurrentIncrementalSmootherGN, synchronize_empty )
355 {
356  // Create a set of optimizer parameters
359  // Create a Concurrent Batch Smoother
360  ConcurrentIncrementalSmoother smoother(parameters);
361 
362  // Create empty containers *from* the filter
363  NonlinearFactorGraph smootherFactors, filterSumarization;
364  Values smootherValues, filterSeparatorValues;
365 
366  // Create expected values: these will be empty for this case
367  NonlinearFactorGraph expectedSmootherSummarization;
368  Values expectedSmootherSeparatorValues;
369 
370  // Synchronize
371  NonlinearFactorGraph actualSmootherSummarization;
372  Values actualSmootherSeparatorValues;
373  smoother.presync();
374  smoother.getSummarizedFactors(actualSmootherSummarization, actualSmootherSeparatorValues);
375  smoother.synchronize(smootherFactors, smootherValues, filterSumarization, filterSeparatorValues);
376  smoother.postsync();
377 
378  // Check
379  CHECK(assert_equal(expectedSmootherSummarization, actualSmootherSummarization, 1e-6));
380  CHECK(assert_equal(expectedSmootherSeparatorValues, actualSmootherSeparatorValues, 1e-6));
381 }
382 
383 /* ************************************************************************* */
384 TEST( ConcurrentIncrementalSmootherGN, synchronize_1 )
385 {
386  // Create a set of optimizer parameters
389 // parameters.maxIterations = 1;
390 
391  // Create a Concurrent Batch Smoother
392  ConcurrentIncrementalSmoother smoother(parameters);
393 
394  // Create a simple separator *from* the filter
395  NonlinearFactorGraph smootherFactors, filterSumarization;
396  Values smootherValues, filterSeparatorValues;
397  filterSeparatorValues.insert(1, Pose3().compose(poseError));
398  filterSeparatorValues.insert(2, filterSeparatorValues.at<Pose3>(1).compose(poseOdometry).compose(poseError));
400  ordering.push_back(1);
401  ordering.push_back(2);
402  filterSumarization.push_back(LinearContainerFactor(PriorFactor<Pose3>(1, poseInitial, noisePrior).linearize(filterSeparatorValues), filterSeparatorValues));
403  filterSumarization.push_back(LinearContainerFactor(BetweenFactor<Pose3>(1, 2, poseOdometry, noiseOdometery).linearize(filterSeparatorValues), filterSeparatorValues));
404 
405  // Create expected values: the smoother output will be empty for this case
406  NonlinearFactorGraph expectedSmootherSummarization;
407  Values expectedSmootherSeparatorValues;
408 
409  NonlinearFactorGraph actualSmootherSummarization;
410  Values actualSmootherSeparatorValues;
411  smoother.presync();
412  smoother.getSummarizedFactors(actualSmootherSummarization, actualSmootherSeparatorValues);
413  smoother.synchronize(smootherFactors, smootherValues, filterSumarization, filterSeparatorValues);
414  smoother.postsync();
415 
416  // Check
417  CHECK(assert_equal(expectedSmootherSummarization, actualSmootherSummarization, 1e-6));
418  CHECK(assert_equal(expectedSmootherSeparatorValues, actualSmootherSeparatorValues, 1e-6));
419 
420 
421  // Update the smoother
422  smoother.update();
423 
424  // Check the factor graph. It should contain only the filter-provided factors
425  NonlinearFactorGraph expectedFactorGraph = filterSumarization;
426  NonlinearFactorGraph actualFactorGraph = smoother.getFactors();
427  CHECK(assert_equal(expectedFactorGraph, actualFactorGraph, 1e-6));
428 
429  // Check the optimized value of smoother state
430  NonlinearFactorGraph allFactors;
431  allFactors.push_back(filterSumarization);
432  Values allValues;
433  allValues.insert(filterSeparatorValues);
434  Values expectedValues = BatchOptimize(allFactors, allValues,1);
435  Values actualValues = smoother.calculateEstimate();
436  CHECK(assert_equal(expectedValues, actualValues, 1e-6));
437 
438  // Check the linearization point. The separator should remain identical to the filter provided values
439  Values expectedLinearizationPoint = filterSeparatorValues;
440  Values actualLinearizationPoint = smoother.getLinearizationPoint();
441  CHECK(assert_equal(expectedLinearizationPoint, actualLinearizationPoint, 1e-6));
442 }
443 
444 
445 /* ************************************************************************* */
446 TEST( ConcurrentIncrementalSmootherGN, synchronize_2 )
447 {
448  // Create a set of optimizer parameters
451 // parameters.maxIterations = 1;
452 // parameters.lambdaUpperBound = 1;
453 // parameters.lambdaInitial = 1;
454 // parameters.verbosity = NonlinearOptimizerParams::ERROR;
455 // parameters.verbosityLM = ISAM2Params::DAMPED;
456 
457  // Create a Concurrent Batch Smoother
458  ConcurrentIncrementalSmoother smoother(parameters);
459 
460  // Create a separator and cached smoother factors *from* the filter
461  NonlinearFactorGraph smootherFactors, filterSumarization;
462  Values smootherValues, filterSeparatorValues;
463 
464  filterSeparatorValues.insert(1, Pose3().compose(poseError));
465  filterSeparatorValues.insert(2, filterSeparatorValues.at<Pose3>(1).compose(poseOdometry).compose(poseError));
466  filterSumarization.push_back(LinearContainerFactor(PriorFactor<Pose3>(1, poseInitial, noisePrior).linearize(filterSeparatorValues), filterSeparatorValues));
467  filterSumarization.push_back(LinearContainerFactor(BetweenFactor<Pose3>(1, 2, poseOdometry, noiseOdometery).linearize(filterSeparatorValues), filterSeparatorValues));
468  smootherFactors.push_back(BetweenFactor<Pose3>(2, 3, poseOdometry, noiseOdometery));
469  smootherFactors.push_back(BetweenFactor<Pose3>(3, 4, poseOdometry, noiseOdometery));
470  smootherValues.insert(3, filterSeparatorValues.at<Pose3>(2).compose(poseOdometry).compose(poseError));
471  smootherValues.insert(4, smootherValues.at<Pose3>(3).compose(poseOdometry).compose(poseError));
472 
473  // Create expected values: the smoother output will be empty for this case
474  NonlinearFactorGraph expectedSmootherSummarization;
475  Values expectedSmootherSeparatorValues;
476 
477  NonlinearFactorGraph actualSmootherSummarization;
478  Values actualSmootherSeparatorValues;
479  smoother.presync();
480  smoother.getSummarizedFactors(actualSmootherSummarization, actualSmootherSeparatorValues);
481  smoother.synchronize(smootherFactors, smootherValues, filterSumarization, filterSeparatorValues);
482  smoother.postsync();
483 
484  // Check
485  CHECK(assert_equal(expectedSmootherSummarization, actualSmootherSummarization, 1e-6));
486  CHECK(assert_equal(expectedSmootherSeparatorValues, actualSmootherSeparatorValues, 1e-6));
487 
488 
489  // Update the smoother
490  smoother.update();
491 
492  // Check the factor graph. It should contain only the filter-provided factors
493  NonlinearFactorGraph expectedFactorGraph;
494  expectedFactorGraph.push_back(smootherFactors);
495  expectedFactorGraph.push_back(filterSumarization);
496  NonlinearFactorGraph actualFactorGraph = smoother.getFactors();
497  CHECK(assert_equal(expectedFactorGraph, actualFactorGraph, 1e-6));
498 
499  // Check the optimized value of smoother state
500  NonlinearFactorGraph allFactors;
501  allFactors.push_back(filterSumarization);
502  allFactors.push_back(smootherFactors);
503  Values allValues;
504  allValues.insert(filterSeparatorValues);
505  allValues.insert(smootherValues);
506 // allValues.print("Batch LinPoint:\n");
507  Values expectedValues = BatchOptimize(allFactors, allValues, 1);
508  Values actualValues = smoother.calculateEstimate();
509  CHECK(assert_equal(expectedValues, actualValues, 1e-6));
510 
511  // Check the linearization point. The separator should remain identical to the filter provided values, but the others should be the optimal values
512  // Isam2 is changing internally the linearization points, so the following check is done only on the separator variables
513 // Values expectedLinearizationPoint = BatchOptimize(allFactors, allValues, 1);
514  Values expectedLinearizationPoint = filterSeparatorValues;
515  Values actualLinearizationPoint;
516  for(const auto key_value: filterSeparatorValues) {
517  actualLinearizationPoint.insert(key_value.key, smoother.getLinearizationPoint().at(key_value.key));
518  }
519  CHECK(assert_equal(expectedLinearizationPoint, actualLinearizationPoint, 1e-6));
520 }
521 
522 
523 
524 /* ************************************************************************* */
525 TEST( ConcurrentIncrementalSmootherGN, synchronize_3 )
526 {
527  // Create a set of optimizer parameters
530 // parameters.maxIterations = 1;
531 // parameters.lambdaUpperBound = 1;
532 // parameters.lambdaInitial = 1;
533 // parameters.verbosity = NonlinearOptimizerParams::ERROR;
534 // parameters.verbosityLM = ISAM2Params::DAMPED;
535 
536  // Create a Concurrent Batch Smoother
537  ConcurrentIncrementalSmoother smoother(parameters);
538 
539  // Create a separator and cached smoother factors *from* the filter
540  NonlinearFactorGraph smootherFactors, filterSumarization;
541  Values smootherValues, filterSeparatorValues;
542 
543  filterSeparatorValues.insert(1, Pose3().compose(poseError));
544  filterSeparatorValues.insert(2, filterSeparatorValues.at<Pose3>(1).compose(poseOdometry).compose(poseError));
545  filterSumarization.push_back(LinearContainerFactor(PriorFactor<Pose3>(1, poseInitial, noisePrior).linearize(filterSeparatorValues), filterSeparatorValues));
546  filterSumarization.push_back(LinearContainerFactor(BetweenFactor<Pose3>(1, 2, poseOdometry, noiseOdometery).linearize(filterSeparatorValues), filterSeparatorValues));
547  smootherFactors.push_back(BetweenFactor<Pose3>(2, 3, poseOdometry, noiseOdometery));
548  smootherFactors.push_back(BetweenFactor<Pose3>(3, 4, poseOdometry, noiseOdometery));
549  smootherFactors.addPrior(4, poseInitial, noisePrior);
550  smootherValues.insert(3, filterSeparatorValues.at<Pose3>(2).compose(poseOdometry).compose(poseError));
551  smootherValues.insert(4, smootherValues.at<Pose3>(3).compose(poseOdometry).compose(poseError));
552 
553  // Create expected values: the smoother output will be empty for this case
554  NonlinearFactorGraph expectedSmootherSummarization;
555  Values expectedSmootherSeparatorValues;
556 
557  NonlinearFactorGraph actualSmootherSummarization;
558  Values actualSmootherSeparatorValues;
559  smoother.presync();
560  smoother.getSummarizedFactors(actualSmootherSummarization, actualSmootherSeparatorValues);
561  smoother.synchronize(smootherFactors, smootherValues, filterSumarization, filterSeparatorValues);
562  smoother.postsync();
563 
564  // Check
565  CHECK(assert_equal(expectedSmootherSummarization, actualSmootherSummarization, 1e-6));
566  CHECK(assert_equal(expectedSmootherSeparatorValues, actualSmootherSeparatorValues, 1e-6));
567 
568 
569  // Update the smoother
570  smoother.update();
571 
572  smoother.presync();
573  smoother.getSummarizedFactors(actualSmootherSummarization, actualSmootherSeparatorValues);
574 
575  // Check the optimized value of smoother state
576  NonlinearFactorGraph allFactors = smootherFactors;
577  Values allValues = smoother.getLinearizationPoint();
578 // ordering = smoother.getOrdering(); // I'm really hoping this is an acceptable ordering...
579 
580  GaussianFactorGraph::shared_ptr LinFactorGraph = allFactors.linearize(allValues);
581 // GaussianSequentialSolver GSS = GaussianSequentialSolver(*LinFactorGraph);
582 // GaussianBayesNet::shared_ptr GBNsptr = GSS.eliminate();
583 
584  KeySet allkeys = LinFactorGraph->keys();
585  for(const auto key_value: filterSeparatorValues)
586  allkeys.erase(key_value.key);
587  KeyVector variables(allkeys.begin(), allkeys.end());
588  std::pair<GaussianBayesNet::shared_ptr, GaussianFactorGraph::shared_ptr> result = LinFactorGraph->eliminatePartialSequential(variables, EliminateCholesky);
589 
590  expectedSmootherSummarization.resize(0);
591  for(const GaussianFactor::shared_ptr& factor: *result.second) {
592  expectedSmootherSummarization.push_back(LinearContainerFactor(factor, allValues));
593  }
594 
595  CHECK(assert_equal(expectedSmootherSummarization, actualSmootherSummarization, 1e-6));
596 
597 }
598 
599 // =========================================================================================================
601 TEST( ConcurrentIncrementalSmoother, removeFactors_topology_1 )
602 {
603  // Create a set of optimizer parameters
606 
607  // Create a Concurrent Batch Smoother
608  ConcurrentIncrementalSmoother smoother(parameters);
609 
610  // Add some factors to the smoother
611  NonlinearFactorGraph newFactors;
612  newFactors.addPrior(1, poseInitial, noisePrior);
613  newFactors.push_back(BetweenFactor<Pose3>(1, 2, poseOdometry, noiseOdometery));
614  newFactors.push_back(BetweenFactor<Pose3>(2, 3, poseOdometry, noiseOdometery));
615  newFactors.push_back(BetweenFactor<Pose3>(3, 4, poseOdometry, noiseOdometery));
616  newFactors.push_back(BetweenFactor<Pose3>(1, 2, poseOdometry, noiseOdometery));
617 
618  Values newValues;
619  newValues.insert(1, Pose3().compose(poseError));
620  newValues.insert(2, newValues.at<Pose3>(1).compose(poseOdometry).compose(poseError));
621  newValues.insert(3, newValues.at<Pose3>(2).compose(poseOdometry).compose(poseError));
622  newValues.insert(4, newValues.at<Pose3>(3).compose(poseOdometry).compose(poseError));
623 
624  // Update the smoother: add all factors
625  smoother.update(newFactors, newValues);
626 
627  // factor we want to remove
628  // NOTE: we can remove factors, paying attention that the remaining graph remains connected
629  // we remove a single factor, the number 1, which is a BetweenFactor<Pose3>(1, 2, poseOdometry, noiseOdometery);
630  FactorIndices removeFactorIndices(2,1);
631 
632  // Add no factors to the smoother (we only want to test the removal)
633  NonlinearFactorGraph noFactors;
634  Values noValues;
635  smoother.update(noFactors, noValues, removeFactorIndices);
636 
637  NonlinearFactorGraph actualGraph = smoother.getFactors();
638 
639  actualGraph.print("actual graph: \n");
640 
642  expectedGraph.addPrior(1, poseInitial, noisePrior);
643  // we removed this one: expectedGraph.push_back(BetweenFactor<Pose3>(1, 2, poseOdometry, noiseOdometery));
644  // we should add an empty one, so that the ordering and labeling of the factors is preserved
645  expectedGraph.push_back(NonlinearFactor::shared_ptr());
646  expectedGraph.emplace_shared<BetweenFactor<Pose3> >(2, 3, poseOdometry, noiseOdometery);
647  expectedGraph.emplace_shared<BetweenFactor<Pose3> >(3, 4, poseOdometry, noiseOdometery);
648  expectedGraph.emplace_shared<BetweenFactor<Pose3> >(1, 2, poseOdometry, noiseOdometery);
649 
650 // CHECK(assert_equal(expectedGraph, actualGraph, 1e-6));
651 }
652 
654 //TEST( ConcurrentIncrementalSmoother, removeFactors_topology_2 )
655 //{
656 // // we try removing the last factor
657 //
658 // // Create a set of optimizer parameters
659 // LevenbergMarquardtParams parameters;
660 //
661 // // Create a Concurrent Batch Smoother
662 // ConcurrentBatchSmoother smoother(parameters);
663 //
664 // // Add some factors to the smoother
665 // NonlinearFactorGraph newFactors;
666 // newFactors.push_back(PriorFactor<Pose3>(1, poseInitial, noisePrior));
667 // newFactors.push_back(BetweenFactor<Pose3>(1, 2, poseOdometry, noiseOdometery));
668 // newFactors.push_back(BetweenFactor<Pose3>(2, 3, poseOdometry, noiseOdometery));
669 // newFactors.push_back(BetweenFactor<Pose3>(3, 4, poseOdometry, noiseOdometery));
670 // newFactors.push_back(BetweenFactor<Pose3>(1, 2, poseOdometry, noiseOdometery));
671 //
672 // Values newValues;
673 // newValues.insert(1, Pose3().compose(poseError));
674 // newValues.insert(2, newValues.at<Pose3>(1).compose(poseOdometry).compose(poseError));
675 // newValues.insert(3, newValues.at<Pose3>(2).compose(poseOdometry).compose(poseError));
676 // newValues.insert(4, newValues.at<Pose3>(3).compose(poseOdometry).compose(poseError));
677 //
678 // // Update the smoother: add all factors
679 // smoother.update(newFactors, newValues);
680 //
681 // // factor we want to remove
682 // // NOTE: we can remove factors, paying attention that the remaining graph remains connected
683 // // we remove a single factor, the number 1, which is a BetweenFactor<Pose3>(1, 2, poseOdometry, noiseOdometery);
684 // std::vector<size_t> removeFactorIndices(1,4);
685 //
686 // // Add no factors to the smoother (we only want to test the removal)
687 // NonlinearFactorGraph noFactors;
688 // Values noValues;
689 // smoother.update(noFactors, noValues, removeFactorIndices);
690 //
691 // NonlinearFactorGraph actualGraph = smoother.getFactors();
692 //
693 // NonlinearFactorGraph expectedGraph;
694 // expectedGraph.push_back(PriorFactor<Pose3>(1, poseInitial, noisePrior));
695 // expectedGraph.push_back(BetweenFactor<Pose3>(1, 2, poseOdometry, noiseOdometery));
696 // expectedGraph.push_back(BetweenFactor<Pose3>(2, 3, poseOdometry, noiseOdometery));
697 // expectedGraph.push_back(BetweenFactor<Pose3>(3, 4, poseOdometry, noiseOdometery));
698 // // we removed this one: expectedGraph.push_back(BetweenFactor<Pose3>(1, 2, poseOdometry, noiseOdometery));
699 // // we should add an empty one, so that the ordering and labeling of the factors is preserved
700 // expectedGraph.push_back(NonlinearFactor::shared_ptr());
701 //
702 // CHECK(assert_equal(expectedGraph, actualGraph, 1e-6));
703 //}
704 //
705 //
707 //TEST( ConcurrentBatchSmoother, removeFactors_topology_3 )
708 //{
709 // // we try removing the first factor
710 //
711 // // Create a set of optimizer parameters
712 // LevenbergMarquardtParams parameters;
713 // ConcurrentBatchSmoother Smoother(parameters);
714 //
715 // // Add some factors to the Smoother
716 // NonlinearFactorGraph newFactors;
717 // newFactors.push_back(PriorFactor<Pose3>(1, poseInitial, noisePrior));
718 // newFactors.push_back(PriorFactor<Pose3>(1, poseInitial, noisePrior));
719 // newFactors.push_back(BetweenFactor<Pose3>(1, 2, poseOdometry, noiseOdometery));
720 // newFactors.push_back(BetweenFactor<Pose3>(2, 3, poseOdometry, noiseOdometery));
721 // newFactors.push_back(BetweenFactor<Pose3>(3, 4, poseOdometry, noiseOdometery));
722 //
723 // Values newValues;
724 // newValues.insert(1, Pose3().compose(poseError));
725 // newValues.insert(2, newValues.at<Pose3>(1).compose(poseOdometry).compose(poseError));
726 // newValues.insert(3, newValues.at<Pose3>(2).compose(poseOdometry).compose(poseError));
727 // newValues.insert(4, newValues.at<Pose3>(3).compose(poseOdometry).compose(poseError));
728 //
729 // // Update the Smoother: add all factors
730 // Smoother.update(newFactors, newValues);
731 //
732 // // factor we want to remove
733 // // NOTE: we can remove factors, paying attention that the remaining graph remains connected
734 // // we remove a single factor, the number 0, which is a BetweenFactor<Pose3>(1, 2, poseOdometry, noiseOdometery);
735 // std::vector<size_t> removeFactorIndices(1,0);
736 //
737 // // Add no factors to the Smoother (we only want to test the removal)
738 // NonlinearFactorGraph noFactors;
739 // Values noValues;
740 // Smoother.update(noFactors, noValues, removeFactorIndices);
741 //
742 // NonlinearFactorGraph actualGraph = Smoother.getFactors();
743 //
744 // NonlinearFactorGraph expectedGraph;
745 // // we should add an empty one, so that the ordering and labeling of the factors is preserved
746 // expectedGraph.push_back(NonlinearFactor::shared_ptr());
747 // expectedGraph.push_back(PriorFactor<Pose3>(1, poseInitial, noisePrior));
748 // expectedGraph.push_back(BetweenFactor<Pose3>(1, 2, poseOdometry, noiseOdometery));
749 // expectedGraph.push_back(BetweenFactor<Pose3>(2, 3, poseOdometry, noiseOdometery));
750 // expectedGraph.push_back(BetweenFactor<Pose3>(3, 4, poseOdometry, noiseOdometery));
751 //
752 // CHECK(assert_equal(expectedGraph, actualGraph, 1e-6));
753 //}
754 //
756 //TEST( ConcurrentBatchSmoother, removeFactors_values )
757 //{
758 // // we try removing the last factor
759 //
760 // // Create a set of optimizer parameters
761 // LevenbergMarquardtParams parameters;
762 // ConcurrentBatchSmoother Smoother(parameters);
763 //
764 // // Add some factors to the Smoother
765 // NonlinearFactorGraph newFactors;
766 // newFactors.push_back(PriorFactor<Pose3>(1, poseInitial, noisePrior));
767 // newFactors.push_back(BetweenFactor<Pose3>(1, 2, poseOdometry, noiseOdometery));
768 // newFactors.push_back(BetweenFactor<Pose3>(2, 3, poseOdometry, noiseOdometery));
769 // newFactors.push_back(BetweenFactor<Pose3>(3, 4, poseOdometry, noiseOdometery));
770 // newFactors.push_back(BetweenFactor<Pose3>(1, 2, poseOdometry, noiseOdometery));
771 //
772 // Values newValues;
773 // newValues.insert(1, Pose3().compose(poseError));
774 // newValues.insert(2, newValues.at<Pose3>(1).compose(poseOdometry).compose(poseError));
775 // newValues.insert(3, newValues.at<Pose3>(2).compose(poseOdometry).compose(poseError));
776 // newValues.insert(4, newValues.at<Pose3>(3).compose(poseOdometry).compose(poseError));
777 //
778 // // Update the Smoother: add all factors
779 // Smoother.update(newFactors, newValues);
780 //
781 // // factor we want to remove
782 // // NOTE: we can remove factors, paying attention that the remaining graph remains connected
783 // // we remove a single factor, the number 4, which is a BetweenFactor<Pose3>(1, 2, poseOdometry, noiseOdometery);
784 // std::vector<size_t> removeFactorIndices(1,4);
785 //
786 // // Add no factors to the Smoother (we only want to test the removal)
787 // NonlinearFactorGraph noFactors;
788 // Values noValues;
789 // Smoother.update(noFactors, noValues, removeFactorIndices);
790 //
791 // NonlinearFactorGraph actualGraph = Smoother.getFactors();
792 // Values actualValues = Smoother.calculateEstimate();
793 //
794 // // note: factors are removed before the optimization
795 // NonlinearFactorGraph expectedGraph;
796 // expectedGraph.push_back(PriorFactor<Pose3>(1, poseInitial, noisePrior));
797 // expectedGraph.push_back(BetweenFactor<Pose3>(1, 2, poseOdometry, noiseOdometery));
798 // expectedGraph.push_back(BetweenFactor<Pose3>(2, 3, poseOdometry, noiseOdometery));
799 // expectedGraph.push_back(BetweenFactor<Pose3>(3, 4, poseOdometry, noiseOdometery));
800 // // we removed this one: expectedGraph.push_back(BetweenFactor<Pose3>(1, 2, poseOdometry, noiseOdometery));
801 // // we should add an empty one, so that the ordering and labeling of the factors is preserved
802 // expectedGraph.push_back(NonlinearFactor::shared_ptr());
803 //
804 // // Calculate expected factor graph and values
805 // Values expectedValues = BatchOptimize(expectedGraph, newValues);
806 //
807 // CHECK(assert_equal(expectedGraph, actualGraph, 1e-6));
808 // CHECK(assert_equal(expectedValues, actualValues, 1e-6));
809 //}
810 
811 
812 
813 
814 /* ************************************************************************* */
815 int main() { TestResult tr; return TestRegistry::runAllTests(tr);}
816 /* ************************************************************************* */
Provides additional testing facilities for common data structures.
#define CHECK(condition)
Definition: Test.h:109
static int runAllTests(TestResult &result)
Eigen::Vector3d Vector3
Definition: Vector.h:43
A non-templated config holding any types of Manifold-group elements.
Wrap Jacobian and Hessian linear factors to allow simple injection into a nonlinear graph...
Factor Graph consisting of non-linear factors.
void insert(Key j, const Value &val)
Definition: Values.cpp:140
static enum @843 ordering
boost::shared_ptr< This > shared_ptr
shared_ptr to this class
FastVector< FactorIndex > FactorIndices
Define collection types:
Definition: Factor.h:32
Definition: Half.h:150
An iSAM2-based Smoother that implements the Concurrent Filtering and Smoothing interface.
IsDerived< DERIVEDFACTOR > push_back(boost::shared_ptr< DERIVEDFACTOR > factor)
Add a factor directly using a shared_ptr.
Definition: FactorGraph.h:166
Rot2 theta
NonlinearFactorGraph graph
void getSummarizedFactors(NonlinearFactorGraph &summarizedFactors, Values &separatorValues) override
T compose(const T &t1, const T &t2)
Definition: lieProxies.h:39
void addPrior(Key key, const T &prior, const SharedNoiseModel &model=nullptr)
static NonlinearFactorGraph expectedGraph(const SharedNoiseModel &model)
Result update(const NonlinearFactorGraph &newFactors=NonlinearFactorGraph(), const Values &newTheta=Values(), const boost::optional< FactorIndices > &removeFactorIndices=boost::none)
IsDerived< DERIVEDFACTOR > emplace_shared(Args &&...args)
Emplace a shared pointer to factor of given type.
Definition: FactorGraph.h:172
std::pair< boost::shared_ptr< GaussianConditional >, boost::shared_ptr< HessianFactor > > EliminateCholesky(const GaussianFactorGraph &factors, const Ordering &keys)
FastVector< Key > KeyVector
Define collection type once and for all - also used in wrappers.
Definition: Key.h:86
Class compose(const Class &g) const
Definition: Lie.h:47
void synchronize(const NonlinearFactorGraph &smootherFactors, const Values &smootherValues, const NonlinearFactorGraph &summarizedFactors, const Values &separatorValues) override
Values result
const ValueType at(Key j) const
Definition: Values-inl.h:342
Incremental update functionality (ISAM2) for BayesTree, with fluid relinearization.
boost::shared_ptr< This > shared_ptr
A nonlinear optimizer that uses the Levenberg-Marquardt trust-region scheme.
Array< double, 1, 3 > e(1./3., 0.5, 2.)
OptimizationParams optimizationParams
Definition: ISAM2Params.h:150
boost::shared_ptr< This > shared_ptr
shared_ptr to this class
static ConjugateGradientParameters parameters
noiseModel::Diagonal::shared_ptr SharedDiagonal
Definition: NoiseModel.h:736
traits
Definition: chartTesting.h:28
bool assert_equal(const Matrix &expected, const Matrix &actual, double tol)
Definition: Matrix.cpp:42
void print(const std::string &str="NonlinearFactorGraph: ", const KeyFormatter &keyFormatter=DefaultKeyFormatter) const override
The junction tree.
TEST(ConcurrentIncrementalSmootherGN, equals)
void resize(size_t size)
Definition: FactorGraph.h:358
Vector3 Point3
Definition: Point3.h:35
boost::shared_ptr< GaussianFactorGraph > linearize(const Values &linearizationPoint) const
Linearize a nonlinear factor graph.
const NonlinearFactorGraph & getFactors() const
3D Pose
Eigen::Matrix< double, Eigen::Dynamic, 1 > Vector


gtsam
Author(s):
autogenerated on Sat May 8 2021 02:46:21