| 
									
										
										
										
											2010-10-14 12:54:38 +08:00
										 |  |  | /* ----------------------------------------------------------------------------
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-25 06:44:05 +08:00
										 |  |  |  * GTSAM Copyright 2010, Georgia Tech Research Corporation, | 
					
						
							| 
									
										
										
										
											2010-10-14 12:54:38 +08:00
										 |  |  |  * Atlanta, Georgia 30332-0415 | 
					
						
							|  |  |  |  * All Rights Reserved | 
					
						
							|  |  |  |  * Authors: Frank Dellaert, et al. (see THANKS for the full author list) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |  * See LICENSE for the license information | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |  * -------------------------------------------------------------------------- */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-13 00:41:18 +08:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * @file testNonlinearEquality.cpp | 
					
						
							|  |  |  |  * @author Alex Cunningham | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-06-10 04:15:44 +08:00
										 |  |  | #include <tests/simulated2DConstraints.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-11 10:26:22 +08:00
										 |  |  | #include <gtsam/nonlinear/PriorFactor.h>
 | 
					
						
							| 
									
										
										
										
											2012-07-24 06:46:21 +08:00
										 |  |  | #include <gtsam/slam/ProjectionFactor.h>
 | 
					
						
							| 
									
										
										
										
											2010-08-24 03:44:17 +08:00
										 |  |  | #include <gtsam/nonlinear/NonlinearEquality.h>
 | 
					
						
							| 
									
										
										
										
											2010-08-20 01:23:19 +08:00
										 |  |  | #include <gtsam/nonlinear/NonlinearFactorGraph.h>
 | 
					
						
							| 
									
										
										
										
											2012-03-02 00:07:23 +08:00
										 |  |  | #include <gtsam/nonlinear/LevenbergMarquardtOptimizer.h>
 | 
					
						
							| 
									
										
										
										
											2016-02-25 03:01:19 +08:00
										 |  |  | #include <gtsam/linear/GaussianBayesNet.h>
 | 
					
						
							|  |  |  | #include <gtsam/inference/Symbol.h>
 | 
					
						
							| 
									
										
										
										
											2012-07-24 06:46:21 +08:00
										 |  |  | #include <gtsam/geometry/Point2.h>
 | 
					
						
							| 
									
										
										
										
											2012-06-03 03:05:38 +08:00
										 |  |  | #include <gtsam/geometry/Pose2.h>
 | 
					
						
							| 
									
										
										
										
											2012-07-24 06:46:21 +08:00
										 |  |  | #include <gtsam/geometry/Point3.h>
 | 
					
						
							|  |  |  | #include <gtsam/geometry/Pose3.h>
 | 
					
						
							|  |  |  | #include <gtsam/geometry/Cal3_S2.h>
 | 
					
						
							| 
									
										
										
										
											2020-02-22 08:42:55 +08:00
										 |  |  | #include <gtsam/geometry/PinholeCamera.h>
 | 
					
						
							| 
									
										
										
										
											2012-06-03 03:05:38 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | #include <CppUnitLite/TestHarness.h>
 | 
					
						
							| 
									
										
										
										
											2009-11-13 00:41:18 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-13 10:06:52 +08:00
										 |  |  | using namespace std; | 
					
						
							|  |  |  | using namespace gtsam; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-01-31 06:00:13 +08:00
										 |  |  | namespace eq2D = simulated2D::equality_constraints; | 
					
						
							| 
									
										
										
										
											2011-11-10 10:05:03 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | static const double tol = 1e-5; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-02-07 12:02:20 +08:00
										 |  |  | typedef PriorFactor<Pose2> PosePrior; | 
					
						
							|  |  |  | typedef NonlinearEquality<Pose2> PoseNLE; | 
					
						
							| 
									
										
										
										
											2010-05-02 06:21:52 +08:00
										 |  |  | typedef boost::shared_ptr<PoseNLE> shared_poseNLE; | 
					
						
							| 
									
										
											  
											
												Large gtsam refactoring
To support faster development *and* better performance Richard and I pushed through a large refactoring of NonlinearFactors.
The following are the biggest changes:
1) NonLinearFactor1 and NonLinearFactor2 are now templated on Config, Key type, and X type, where X is the argument to the measurement function.
2) The measurement itself is no longer kept in the nonlinear factor. Instead, a derived class (see testVSLAMFactor, testNonlinearEquality, testPose3Factor etc...) has to implement a function to compute the errors, "evaluateErrors". Instead of (h(x)-z), it needs to return (z-h(x)), so Ax-b is an approximation of the error. IMPORTANT: evaluateErrors needs - if asked - *combine* the calculation of the function value h(x) and the derivatives dh(x)/dx. This was a major performance issue. To do this, boost::optional<Matrix&> arguments are provided, and tin EvaluateErrors you just  says something like
	if (H) *H = Matrix_(3,6,....);
3) We are no longer using int or strings for nonlinear factors. Instead, the preferred key type is now Symbol, defined in Key.h. This is both fast and cool: you can construct it from an int, and cast it to a strong. It also does type checking: a Symbol<Pose3,'x'> will not match a Symbol<Pose2,'x'>
4) minor: take a look at LieConfig.h: it help you avoid writing a lot of code bu automatically creating configs for a certain type. See e.g. Pose3Config.h. A "double" LieConfig is on the way - Thanks Richard and Manohar !
											
										 
											2010-01-14 06:25:03 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-25 15:47:25 +08:00
										 |  |  | static Symbol key('x', 1); | 
					
						
							| 
									
										
										
										
											2009-11-13 10:06:52 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-25 15:47:25 +08:00
										 |  |  | //******************************************************************************
 | 
					
						
							| 
									
										
										
										
											2009-11-13 10:06:52 +08:00
										 |  |  | TEST ( NonlinearEquality, linearization ) { | 
					
						
							| 
									
										
										
										
											2012-10-02 22:40:07 +08:00
										 |  |  |   Pose2 value = Pose2(2.1, 1.0, 2.0); | 
					
						
							|  |  |  |   Values linearize; | 
					
						
							|  |  |  |   linearize.insert(key, value); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // create a nonlinear equality constraint
 | 
					
						
							|  |  |  |   shared_poseNLE nle(new PoseNLE(key, value)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // check linearize
 | 
					
						
							|  |  |  |   SharedDiagonal constraintModel = noiseModel::Constrained::All(3); | 
					
						
							| 
									
										
										
										
											2016-04-16 04:54:46 +08:00
										 |  |  |   JacobianFactor expLF(key, I_3x3, Z_3x1, constraintModel); | 
					
						
							| 
									
										
										
										
											2013-08-06 21:44:22 +08:00
										 |  |  |   GaussianFactor::shared_ptr actualLF = nle->linearize(linearize); | 
					
						
							| 
									
										
										
										
											2013-08-07 02:04:37 +08:00
										 |  |  |   EXPECT(assert_equal((const GaussianFactor&)expLF, *actualLF)); | 
					
						
							| 
									
										
										
										
											2009-11-13 00:41:18 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-25 15:47:25 +08:00
										 |  |  | //******************************************************************************
 | 
					
						
							| 
									
										
										
										
											2010-05-02 06:21:52 +08:00
										 |  |  | TEST ( NonlinearEquality, linearization_pose ) { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-25 15:47:25 +08:00
										 |  |  |   Symbol key('x', 1); | 
					
						
							| 
									
										
										
										
											2012-10-02 22:40:07 +08:00
										 |  |  |   Pose2 value; | 
					
						
							|  |  |  |   Values config; | 
					
						
							|  |  |  |   config.insert(key, value); | 
					
						
							| 
									
										
										
										
											2010-05-02 06:21:52 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-02 22:40:07 +08:00
										 |  |  |   // create a nonlinear equality constraint
 | 
					
						
							|  |  |  |   shared_poseNLE nle(new PoseNLE(key, value)); | 
					
						
							| 
									
										
										
										
											2010-05-02 06:21:52 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-08-06 21:44:22 +08:00
										 |  |  |   GaussianFactor::shared_ptr actualLF = nle->linearize(config); | 
					
						
							| 
									
										
										
										
											2012-10-02 22:40:07 +08:00
										 |  |  |   EXPECT(true); | 
					
						
							| 
									
										
										
										
											2010-05-02 06:21:52 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-25 15:47:25 +08:00
										 |  |  | //******************************************************************************
 | 
					
						
							| 
									
										
										
										
											2009-11-13 10:06:52 +08:00
										 |  |  | TEST ( NonlinearEquality, linearization_fail ) { | 
					
						
							| 
									
										
										
										
											2012-10-02 22:40:07 +08:00
										 |  |  |   Pose2 value = Pose2(2.1, 1.0, 2.0); | 
					
						
							|  |  |  |   Pose2 wrong = Pose2(2.1, 3.0, 4.0); | 
					
						
							|  |  |  |   Values bad_linearize; | 
					
						
							|  |  |  |   bad_linearize.insert(key, wrong); | 
					
						
							| 
									
										
										
										
											2009-11-13 10:06:52 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-02 22:40:07 +08:00
										 |  |  |   // create a nonlinear equality constraint
 | 
					
						
							|  |  |  |   shared_poseNLE nle(new PoseNLE(key, value)); | 
					
						
							| 
									
										
										
										
											2009-11-13 10:06:52 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-02 22:40:07 +08:00
										 |  |  |   // check linearize to ensure that it fails for bad linearization points
 | 
					
						
							| 
									
										
										
										
											2013-08-06 21:44:22 +08:00
										 |  |  |   CHECK_EXCEPTION(nle->linearize(bad_linearize), std::invalid_argument); | 
					
						
							| 
									
										
										
										
											2009-11-13 10:06:52 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-25 15:47:25 +08:00
										 |  |  | //******************************************************************************
 | 
					
						
							| 
									
										
										
										
											2010-05-02 06:21:52 +08:00
										 |  |  | TEST ( NonlinearEquality, linearization_fail_pose ) { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-25 15:47:25 +08:00
										 |  |  |   Symbol key('x', 1); | 
					
						
							|  |  |  |   Pose2 value(2.0, 1.0, 2.0), wrong(2.0, 3.0, 4.0); | 
					
						
							| 
									
										
										
										
											2012-10-02 22:40:07 +08:00
										 |  |  |   Values bad_linearize; | 
					
						
							|  |  |  |   bad_linearize.insert(key, wrong); | 
					
						
							| 
									
										
										
										
											2010-05-02 06:21:52 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-02 22:40:07 +08:00
										 |  |  |   // create a nonlinear equality constraint
 | 
					
						
							|  |  |  |   shared_poseNLE nle(new PoseNLE(key, value)); | 
					
						
							| 
									
										
										
										
											2010-05-02 06:21:52 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-02 22:40:07 +08:00
										 |  |  |   // check linearize to ensure that it fails for bad linearization points
 | 
					
						
							| 
									
										
										
										
											2013-08-06 21:44:22 +08:00
										 |  |  |   CHECK_EXCEPTION(nle->linearize(bad_linearize), std::invalid_argument); | 
					
						
							| 
									
										
										
										
											2010-05-02 06:21:52 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-25 15:47:25 +08:00
										 |  |  | //******************************************************************************
 | 
					
						
							| 
									
										
										
										
											2010-05-02 06:21:52 +08:00
										 |  |  | TEST ( NonlinearEquality, linearization_fail_pose_origin ) { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-25 15:47:25 +08:00
										 |  |  |   Symbol key('x', 1); | 
					
						
							|  |  |  |   Pose2 value, wrong(2.0, 3.0, 4.0); | 
					
						
							| 
									
										
										
										
											2012-10-02 22:40:07 +08:00
										 |  |  |   Values bad_linearize; | 
					
						
							|  |  |  |   bad_linearize.insert(key, wrong); | 
					
						
							| 
									
										
										
										
											2010-05-02 06:21:52 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-02 22:40:07 +08:00
										 |  |  |   // create a nonlinear equality constraint
 | 
					
						
							|  |  |  |   shared_poseNLE nle(new PoseNLE(key, value)); | 
					
						
							| 
									
										
										
										
											2010-05-02 06:21:52 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-02 22:40:07 +08:00
										 |  |  |   // check linearize to ensure that it fails for bad linearization points
 | 
					
						
							| 
									
										
										
										
											2013-08-06 21:44:22 +08:00
										 |  |  |   CHECK_EXCEPTION(nle->linearize(bad_linearize), std::invalid_argument); | 
					
						
							| 
									
										
										
										
											2010-05-02 06:21:52 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-25 15:47:25 +08:00
										 |  |  | //******************************************************************************
 | 
					
						
							| 
									
										
										
										
											2009-11-13 10:06:52 +08:00
										 |  |  | TEST ( NonlinearEquality, error ) { | 
					
						
							| 
									
										
										
										
											2012-10-02 22:40:07 +08:00
										 |  |  |   Pose2 value = Pose2(2.1, 1.0, 2.0); | 
					
						
							|  |  |  |   Pose2 wrong = Pose2(2.1, 3.0, 4.0); | 
					
						
							|  |  |  |   Values feasible, bad_linearize; | 
					
						
							|  |  |  |   feasible.insert(key, value); | 
					
						
							|  |  |  |   bad_linearize.insert(key, wrong); | 
					
						
							| 
									
										
										
										
											2009-11-13 10:06:52 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-02 22:40:07 +08:00
										 |  |  |   // create a nonlinear equality constraint
 | 
					
						
							|  |  |  |   shared_poseNLE nle(new PoseNLE(key, value)); | 
					
						
							| 
									
										
										
										
											2009-11-13 10:06:52 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-02 22:40:07 +08:00
										 |  |  |   // check error function outputs
 | 
					
						
							|  |  |  |   Vector actual = nle->unwhitenedError(feasible); | 
					
						
							| 
									
										
										
										
											2016-04-16 04:54:46 +08:00
										 |  |  |   EXPECT(assert_equal(actual, Z_3x1)); | 
					
						
							| 
									
										
										
										
											2009-11-13 10:06:52 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-02 22:40:07 +08:00
										 |  |  |   actual = nle->unwhitenedError(bad_linearize); | 
					
						
							| 
									
										
										
										
											2014-11-25 15:47:25 +08:00
										 |  |  |   EXPECT( | 
					
						
							| 
									
										
										
										
											2016-03-12 12:10:18 +08:00
										 |  |  |       assert_equal(actual, Vector::Constant(3, std::numeric_limits<double>::infinity()))); | 
					
						
							| 
									
										
										
										
											2009-11-13 10:06:52 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-25 15:47:25 +08:00
										 |  |  | //******************************************************************************
 | 
					
						
							| 
									
										
										
										
											2009-11-13 10:06:52 +08:00
										 |  |  | TEST ( NonlinearEquality, equals ) { | 
					
						
							| 
									
										
										
										
											2012-10-02 22:40:07 +08:00
										 |  |  |   Pose2 value1 = Pose2(2.1, 1.0, 2.0); | 
					
						
							|  |  |  |   Pose2 value2 = Pose2(2.1, 3.0, 4.0); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // create some constraints to compare
 | 
					
						
							|  |  |  |   shared_poseNLE nle1(new PoseNLE(key, value1)); | 
					
						
							|  |  |  |   shared_poseNLE nle2(new PoseNLE(key, value1)); | 
					
						
							|  |  |  |   shared_poseNLE nle3(new PoseNLE(key, value2)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // verify
 | 
					
						
							| 
									
										
										
										
											2014-11-25 15:47:25 +08:00
										 |  |  |   EXPECT(nle1->equals(*nle2)); | 
					
						
							|  |  |  |   // basic equality = true
 | 
					
						
							|  |  |  |   EXPECT(nle2->equals(*nle1)); | 
					
						
							|  |  |  |   // test symmetry of equals()
 | 
					
						
							|  |  |  |   EXPECT(!nle1->equals(*nle3)); | 
					
						
							|  |  |  |   // test config
 | 
					
						
							| 
									
										
										
										
											2010-07-10 01:08:35 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-25 15:47:25 +08:00
										 |  |  | //******************************************************************************
 | 
					
						
							| 
									
										
										
										
											2010-07-10 01:08:35 +08:00
										 |  |  | TEST ( NonlinearEquality, allow_error_pose ) { | 
					
						
							| 
									
										
										
										
											2014-11-25 15:47:25 +08:00
										 |  |  |   Symbol key1('x', 1); | 
					
						
							| 
									
										
										
										
											2012-10-02 22:40:07 +08:00
										 |  |  |   Pose2 feasible1(1.0, 2.0, 3.0); | 
					
						
							|  |  |  |   double error_gain = 500.0; | 
					
						
							|  |  |  |   PoseNLE nle(key1, feasible1, error_gain); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // the unwhitened error should provide logmap to the feasible state
 | 
					
						
							|  |  |  |   Pose2 badPoint1(0.0, 2.0, 3.0); | 
					
						
							|  |  |  |   Vector actVec = nle.evaluateError(badPoint1); | 
					
						
							| 
									
										
										
										
											2014-11-24 02:22:25 +08:00
										 |  |  |   Vector expVec = Vector3(-0.989992, -0.14112, 0.0); | 
					
						
							| 
									
										
										
										
											2012-10-02 22:40:07 +08:00
										 |  |  |   EXPECT(assert_equal(expVec, actVec, 1e-5)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // the actual error should have a gain on it
 | 
					
						
							|  |  |  |   Values config; | 
					
						
							|  |  |  |   config.insert(key1, badPoint1); | 
					
						
							|  |  |  |   double actError = nle.error(config); | 
					
						
							|  |  |  |   DOUBLES_EQUAL(500.0, actError, 1e-9); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // check linearization
 | 
					
						
							| 
									
										
										
										
											2013-08-06 21:44:22 +08:00
										 |  |  |   GaussianFactor::shared_ptr actLinFactor = nle.linearize(config); | 
					
						
							| 
									
										
										
										
											2016-04-12 04:04:24 +08:00
										 |  |  |   Matrix A1 = I_3x3; | 
					
						
							| 
									
										
										
										
											2012-10-02 22:40:07 +08:00
										 |  |  |   Vector b = expVec; | 
					
						
							|  |  |  |   SharedDiagonal model = noiseModel::Constrained::All(3); | 
					
						
							| 
									
										
										
										
											2014-11-25 15:47:25 +08:00
										 |  |  |   GaussianFactor::shared_ptr expLinFactor( | 
					
						
							|  |  |  |       new JacobianFactor(key1, A1, b, model)); | 
					
						
							| 
									
										
										
										
											2012-10-02 22:40:07 +08:00
										 |  |  |   EXPECT(assert_equal(*expLinFactor, *actLinFactor, 1e-5)); | 
					
						
							| 
									
										
										
										
											2010-07-10 01:08:35 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-25 15:47:25 +08:00
										 |  |  | //******************************************************************************
 | 
					
						
							| 
									
										
										
										
											2010-07-10 01:08:35 +08:00
										 |  |  | TEST ( NonlinearEquality, allow_error_optimize ) { | 
					
						
							| 
									
										
										
										
											2014-11-25 15:47:25 +08:00
										 |  |  |   Symbol key1('x', 1); | 
					
						
							| 
									
										
										
										
											2012-10-02 22:40:07 +08:00
										 |  |  |   Pose2 feasible1(1.0, 2.0, 3.0); | 
					
						
							|  |  |  |   double error_gain = 500.0; | 
					
						
							|  |  |  |   PoseNLE nle(key1, feasible1, error_gain); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // add to a graph
 | 
					
						
							|  |  |  |   NonlinearFactorGraph graph; | 
					
						
							| 
									
										
										
										
											2013-08-06 21:44:22 +08:00
										 |  |  |   graph += nle; | 
					
						
							| 
									
										
										
										
											2012-10-02 22:40:07 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   // initialize away from the ideal
 | 
					
						
							|  |  |  |   Pose2 initPose(0.0, 2.0, 3.0); | 
					
						
							|  |  |  |   Values init; | 
					
						
							|  |  |  |   init.insert(key1, initPose); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // optimize
 | 
					
						
							| 
									
										
										
										
											2013-08-06 06:31:44 +08:00
										 |  |  |   Ordering ordering; | 
					
						
							| 
									
										
										
										
											2012-10-02 22:40:07 +08:00
										 |  |  |   ordering.push_back(key1); | 
					
						
							|  |  |  |   Values result = LevenbergMarquardtOptimizer(graph, init, ordering).optimize(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // verify
 | 
					
						
							|  |  |  |   Values expected; | 
					
						
							|  |  |  |   expected.insert(key1, feasible1); | 
					
						
							|  |  |  |   EXPECT(assert_equal(expected, result)); | 
					
						
							| 
									
										
										
										
											2010-07-10 01:08:35 +08:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2010-07-09 05:30:19 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-25 15:47:25 +08:00
										 |  |  | //******************************************************************************
 | 
					
						
							| 
									
										
										
										
											2010-07-10 01:08:35 +08:00
										 |  |  | TEST ( NonlinearEquality, allow_error_optimize_with_factors ) { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-02 22:40:07 +08:00
										 |  |  |   // create a hard constraint
 | 
					
						
							| 
									
										
										
										
											2014-11-25 15:47:25 +08:00
										 |  |  |   Symbol key1('x', 1); | 
					
						
							| 
									
										
										
										
											2012-10-02 22:40:07 +08:00
										 |  |  |   Pose2 feasible1(1.0, 2.0, 3.0); | 
					
						
							| 
									
										
										
										
											2010-07-10 01:08:35 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-02 22:40:07 +08:00
										 |  |  |   // initialize away from the ideal
 | 
					
						
							|  |  |  |   Values init; | 
					
						
							|  |  |  |   Pose2 initPose(0.0, 2.0, 3.0); | 
					
						
							|  |  |  |   init.insert(key1, initPose); | 
					
						
							| 
									
										
										
										
											2010-07-10 01:08:35 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-02 22:40:07 +08:00
										 |  |  |   double error_gain = 500.0; | 
					
						
							|  |  |  |   PoseNLE nle(key1, feasible1, error_gain); | 
					
						
							| 
									
										
										
										
											2010-07-10 01:08:35 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-02 22:40:07 +08:00
										 |  |  |   // create a soft prior that conflicts
 | 
					
						
							|  |  |  |   PosePrior prior(key1, initPose, noiseModel::Isotropic::Sigma(3, 0.1)); | 
					
						
							| 
									
										
										
										
											2010-07-10 01:08:35 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-02 22:40:07 +08:00
										 |  |  |   // add to a graph
 | 
					
						
							|  |  |  |   NonlinearFactorGraph graph; | 
					
						
							| 
									
										
										
										
											2013-08-06 21:44:22 +08:00
										 |  |  |   graph += nle; | 
					
						
							|  |  |  |   graph += prior; | 
					
						
							| 
									
										
										
										
											2010-07-10 01:08:35 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-02 22:40:07 +08:00
										 |  |  |   // optimize
 | 
					
						
							| 
									
										
										
										
											2013-08-06 06:31:44 +08:00
										 |  |  |   Ordering ordering; | 
					
						
							| 
									
										
										
										
											2012-10-02 22:40:07 +08:00
										 |  |  |   ordering.push_back(key1); | 
					
						
							| 
									
										
										
										
											2012-05-15 05:07:56 +08:00
										 |  |  |   Values actual = LevenbergMarquardtOptimizer(graph, init, ordering).optimize(); | 
					
						
							| 
									
										
										
										
											2010-07-10 01:08:35 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-02 22:40:07 +08:00
										 |  |  |   // verify
 | 
					
						
							|  |  |  |   Values expected; | 
					
						
							|  |  |  |   expected.insert(key1, feasible1); | 
					
						
							|  |  |  |   EXPECT(assert_equal(expected, actual)); | 
					
						
							| 
									
										
										
										
											2010-07-09 05:30:19 +08:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2009-11-13 10:06:52 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-25 15:47:25 +08:00
										 |  |  | //******************************************************************************
 | 
					
						
							| 
									
										
										
										
											2012-06-30 09:44:00 +08:00
										 |  |  | static SharedDiagonal hard_model = noiseModel::Constrained::All(2); | 
					
						
							|  |  |  | static SharedDiagonal soft_model = noiseModel::Isotropic::Sigma(2, 1.0); | 
					
						
							| 
									
										
										
										
											2011-11-10 10:05:03 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-25 15:47:25 +08:00
										 |  |  | //******************************************************************************
 | 
					
						
							| 
									
										
										
										
											2011-11-10 10:05:03 +08:00
										 |  |  | TEST( testNonlinearEqualityConstraint, unary_basics ) { | 
					
						
							| 
									
										
										
										
											2012-10-02 22:40:07 +08:00
										 |  |  |   Point2 pt(1.0, 2.0); | 
					
						
							| 
									
										
										
										
											2014-11-25 15:47:25 +08:00
										 |  |  |   Symbol key1('x', 1); | 
					
						
							| 
									
										
										
										
											2012-10-02 22:40:07 +08:00
										 |  |  |   double mu = 1000.0; | 
					
						
							|  |  |  |   eq2D::UnaryEqualityConstraint constraint(pt, key, mu); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   Values config1; | 
					
						
							|  |  |  |   config1.insert(key, pt); | 
					
						
							|  |  |  |   EXPECT(constraint.active(config1)); | 
					
						
							| 
									
										
										
										
											2016-04-16 04:54:46 +08:00
										 |  |  |   EXPECT(assert_equal(Z_2x1, constraint.evaluateError(pt), tol)); | 
					
						
							|  |  |  |   EXPECT(assert_equal(Z_2x1, constraint.unwhitenedError(config1), tol)); | 
					
						
							| 
									
										
										
										
											2012-10-02 22:40:07 +08:00
										 |  |  |   EXPECT_DOUBLES_EQUAL(0.0, constraint.error(config1), tol); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   Values config2; | 
					
						
							|  |  |  |   Point2 ptBad1(2.0, 2.0); | 
					
						
							|  |  |  |   config2.insert(key, ptBad1); | 
					
						
							|  |  |  |   EXPECT(constraint.active(config2)); | 
					
						
							| 
									
										
										
										
											2014-11-25 15:47:25 +08:00
										 |  |  |   EXPECT( | 
					
						
							|  |  |  |       assert_equal(Vector2(1.0, 0.0), constraint.evaluateError(ptBad1), tol)); | 
					
						
							|  |  |  |   EXPECT( | 
					
						
							|  |  |  |       assert_equal(Vector2(1.0, 0.0), constraint.unwhitenedError(config2), tol)); | 
					
						
							| 
									
										
										
										
											2012-10-02 22:40:07 +08:00
										 |  |  |   EXPECT_DOUBLES_EQUAL(500.0, constraint.error(config2), tol); | 
					
						
							| 
									
										
										
										
											2011-11-10 10:05:03 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-25 15:47:25 +08:00
										 |  |  | //******************************************************************************
 | 
					
						
							| 
									
										
										
										
											2011-11-10 10:05:03 +08:00
										 |  |  | TEST( testNonlinearEqualityConstraint, unary_linearization ) { | 
					
						
							| 
									
										
										
										
											2012-10-02 22:40:07 +08:00
										 |  |  |   Point2 pt(1.0, 2.0); | 
					
						
							| 
									
										
										
										
											2014-11-25 15:47:25 +08:00
										 |  |  |   Symbol key1('x', 1); | 
					
						
							| 
									
										
										
										
											2012-10-02 22:40:07 +08:00
										 |  |  |   double mu = 1000.0; | 
					
						
							|  |  |  |   eq2D::UnaryEqualityConstraint constraint(pt, key, mu); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   Values config1; | 
					
						
							|  |  |  |   config1.insert(key, pt); | 
					
						
							| 
									
										
										
										
											2013-08-06 21:44:22 +08:00
										 |  |  |   GaussianFactor::shared_ptr actual1 = constraint.linearize(config1); | 
					
						
							| 
									
										
										
										
											2014-11-25 15:47:25 +08:00
										 |  |  |   GaussianFactor::shared_ptr expected1( | 
					
						
							| 
									
										
										
										
											2016-04-16 04:54:46 +08:00
										 |  |  |       new JacobianFactor(key, I_2x2, Z_2x1, hard_model)); | 
					
						
							| 
									
										
										
										
											2012-10-02 22:40:07 +08:00
										 |  |  |   EXPECT(assert_equal(*expected1, *actual1, tol)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   Values config2; | 
					
						
							|  |  |  |   Point2 ptBad(2.0, 2.0); | 
					
						
							|  |  |  |   config2.insert(key, ptBad); | 
					
						
							| 
									
										
										
										
											2013-08-06 21:44:22 +08:00
										 |  |  |   GaussianFactor::shared_ptr actual2 = constraint.linearize(config2); | 
					
						
							| 
									
										
										
										
											2014-11-25 15:47:25 +08:00
										 |  |  |   GaussianFactor::shared_ptr expected2( | 
					
						
							| 
									
										
										
										
											2016-04-12 04:04:24 +08:00
										 |  |  |       new JacobianFactor(key, I_2x2, Vector2(-1.0, 0.0), hard_model)); | 
					
						
							| 
									
										
										
										
											2012-10-02 22:40:07 +08:00
										 |  |  |   EXPECT(assert_equal(*expected2, *actual2, tol)); | 
					
						
							| 
									
										
										
										
											2011-11-10 10:05:03 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-25 15:47:25 +08:00
										 |  |  | //******************************************************************************
 | 
					
						
							| 
									
										
										
										
											2011-11-10 10:05:03 +08:00
										 |  |  | TEST( testNonlinearEqualityConstraint, unary_simple_optimization ) { | 
					
						
							| 
									
										
										
										
											2012-10-02 22:40:07 +08:00
										 |  |  |   // create a single-node graph with a soft and hard constraint to
 | 
					
						
							|  |  |  |   // ensure that the hard constraint overrides the soft constraint
 | 
					
						
							|  |  |  |   Point2 truth_pt(1.0, 2.0); | 
					
						
							| 
									
										
										
										
											2014-11-25 15:47:25 +08:00
										 |  |  |   Symbol key('x', 1); | 
					
						
							| 
									
										
										
										
											2012-10-02 22:40:07 +08:00
										 |  |  |   double mu = 10.0; | 
					
						
							|  |  |  |   eq2D::UnaryEqualityConstraint::shared_ptr constraint( | 
					
						
							|  |  |  |       new eq2D::UnaryEqualityConstraint(truth_pt, key, mu)); | 
					
						
							| 
									
										
										
										
											2011-11-10 10:05:03 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-02 22:40:07 +08:00
										 |  |  |   Point2 badPt(100.0, -200.0); | 
					
						
							|  |  |  |   simulated2D::Prior::shared_ptr factor( | 
					
						
							|  |  |  |       new simulated2D::Prior(badPt, soft_model, key)); | 
					
						
							| 
									
										
										
										
											2011-11-10 10:05:03 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-02 22:40:07 +08:00
										 |  |  |   NonlinearFactorGraph graph; | 
					
						
							|  |  |  |   graph.push_back(constraint); | 
					
						
							|  |  |  |   graph.push_back(factor); | 
					
						
							| 
									
										
										
										
											2011-11-10 10:05:03 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-02 22:40:07 +08:00
										 |  |  |   Values initValues; | 
					
						
							|  |  |  |   initValues.insert(key, badPt); | 
					
						
							| 
									
										
										
										
											2011-11-10 10:05:03 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-02 22:40:07 +08:00
										 |  |  |   // verify error values
 | 
					
						
							|  |  |  |   EXPECT(constraint->active(initValues)); | 
					
						
							| 
									
										
										
										
											2011-11-10 10:05:03 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-02 22:40:07 +08:00
										 |  |  |   Values expected; | 
					
						
							|  |  |  |   expected.insert(key, truth_pt); | 
					
						
							|  |  |  |   EXPECT(constraint->active(expected)); | 
					
						
							|  |  |  |   EXPECT_DOUBLES_EQUAL(0.0, constraint->error(expected), tol); | 
					
						
							| 
									
										
										
										
											2011-11-10 10:05:03 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-02 22:40:07 +08:00
										 |  |  |   Values actual = LevenbergMarquardtOptimizer(graph, initValues).optimize(); | 
					
						
							|  |  |  |   EXPECT(assert_equal(expected, actual, tol)); | 
					
						
							| 
									
										
										
										
											2011-11-10 10:05:03 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-25 15:47:25 +08:00
										 |  |  | //******************************************************************************
 | 
					
						
							| 
									
										
										
										
											2011-11-10 10:05:03 +08:00
										 |  |  | TEST( testNonlinearEqualityConstraint, odo_basics ) { | 
					
						
							| 
									
										
										
										
											2012-10-02 22:40:07 +08:00
										 |  |  |   Point2 x1(1.0, 2.0), x2(2.0, 3.0), odom(1.0, 1.0); | 
					
						
							| 
									
										
										
										
											2014-11-25 15:47:25 +08:00
										 |  |  |   Symbol key1('x', 1), key2('x', 2); | 
					
						
							| 
									
										
										
										
											2012-10-02 22:40:07 +08:00
										 |  |  |   double mu = 1000.0; | 
					
						
							|  |  |  |   eq2D::OdoEqualityConstraint constraint(odom, key1, key2, mu); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   Values config1; | 
					
						
							|  |  |  |   config1.insert(key1, x1); | 
					
						
							|  |  |  |   config1.insert(key2, x2); | 
					
						
							|  |  |  |   EXPECT(constraint.active(config1)); | 
					
						
							| 
									
										
										
										
											2016-04-16 04:54:46 +08:00
										 |  |  |   EXPECT(assert_equal(Z_2x1, constraint.evaluateError(x1, x2), tol)); | 
					
						
							|  |  |  |   EXPECT(assert_equal(Z_2x1, constraint.unwhitenedError(config1), tol)); | 
					
						
							| 
									
										
										
										
											2012-10-02 22:40:07 +08:00
										 |  |  |   EXPECT_DOUBLES_EQUAL(0.0, constraint.error(config1), tol); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   Values config2; | 
					
						
							|  |  |  |   Point2 x1bad(2.0, 2.0); | 
					
						
							|  |  |  |   Point2 x2bad(2.0, 2.0); | 
					
						
							|  |  |  |   config2.insert(key1, x1bad); | 
					
						
							|  |  |  |   config2.insert(key2, x2bad); | 
					
						
							|  |  |  |   EXPECT(constraint.active(config2)); | 
					
						
							| 
									
										
										
										
											2014-11-25 15:47:25 +08:00
										 |  |  |   EXPECT( | 
					
						
							|  |  |  |       assert_equal(Vector2(-1.0, -1.0), constraint.evaluateError(x1bad, x2bad), tol)); | 
					
						
							|  |  |  |   EXPECT( | 
					
						
							|  |  |  |       assert_equal(Vector2(-1.0, -1.0), constraint.unwhitenedError(config2), tol)); | 
					
						
							| 
									
										
										
										
											2012-10-02 22:40:07 +08:00
										 |  |  |   EXPECT_DOUBLES_EQUAL(1000.0, constraint.error(config2), tol); | 
					
						
							| 
									
										
										
										
											2011-11-10 10:05:03 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-25 15:47:25 +08:00
										 |  |  | //******************************************************************************
 | 
					
						
							| 
									
										
										
										
											2011-11-10 10:05:03 +08:00
										 |  |  | TEST( testNonlinearEqualityConstraint, odo_linearization ) { | 
					
						
							| 
									
										
										
										
											2012-10-02 22:40:07 +08:00
										 |  |  |   Point2 x1(1.0, 2.0), x2(2.0, 3.0), odom(1.0, 1.0); | 
					
						
							| 
									
										
										
										
											2014-11-25 15:47:25 +08:00
										 |  |  |   Symbol key1('x', 1), key2('x', 2); | 
					
						
							| 
									
										
										
										
											2012-10-02 22:40:07 +08:00
										 |  |  |   double mu = 1000.0; | 
					
						
							|  |  |  |   eq2D::OdoEqualityConstraint constraint(odom, key1, key2, mu); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   Values config1; | 
					
						
							|  |  |  |   config1.insert(key1, x1); | 
					
						
							|  |  |  |   config1.insert(key2, x2); | 
					
						
							| 
									
										
										
										
											2013-08-06 21:44:22 +08:00
										 |  |  |   GaussianFactor::shared_ptr actual1 = constraint.linearize(config1); | 
					
						
							| 
									
										
										
										
											2013-08-06 06:31:44 +08:00
										 |  |  |   GaussianFactor::shared_ptr expected1( | 
					
						
							| 
									
										
										
										
											2016-04-16 04:54:46 +08:00
										 |  |  |       new JacobianFactor(key1, -I_2x2, key2, I_2x2, Z_2x1, | 
					
						
							| 
									
										
										
										
											2014-11-25 15:47:25 +08:00
										 |  |  |           hard_model)); | 
					
						
							| 
									
										
										
										
											2012-10-02 22:40:07 +08:00
										 |  |  |   EXPECT(assert_equal(*expected1, *actual1, tol)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   Values config2; | 
					
						
							|  |  |  |   Point2 x1bad(2.0, 2.0); | 
					
						
							|  |  |  |   Point2 x2bad(2.0, 2.0); | 
					
						
							|  |  |  |   config2.insert(key1, x1bad); | 
					
						
							|  |  |  |   config2.insert(key2, x2bad); | 
					
						
							| 
									
										
										
										
											2013-08-06 21:44:22 +08:00
										 |  |  |   GaussianFactor::shared_ptr actual2 = constraint.linearize(config2); | 
					
						
							| 
									
										
										
										
											2013-08-06 06:31:44 +08:00
										 |  |  |   GaussianFactor::shared_ptr expected2( | 
					
						
							| 
									
										
										
										
											2016-04-12 04:04:24 +08:00
										 |  |  |       new JacobianFactor(key1, -I_2x2, key2, I_2x2, Vector2(1.0, 1.0), | 
					
						
							| 
									
										
										
										
											2014-11-25 15:47:25 +08:00
										 |  |  |           hard_model)); | 
					
						
							| 
									
										
										
										
											2012-10-02 22:40:07 +08:00
										 |  |  |   EXPECT(assert_equal(*expected2, *actual2, tol)); | 
					
						
							| 
									
										
										
										
											2011-11-10 10:05:03 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-25 15:47:25 +08:00
										 |  |  | //******************************************************************************
 | 
					
						
							| 
									
										
										
										
											2011-11-10 10:05:03 +08:00
										 |  |  | TEST( testNonlinearEqualityConstraint, odo_simple_optimize ) { | 
					
						
							| 
									
										
										
										
											2012-10-02 22:40:07 +08:00
										 |  |  |   // create a two-node graph, connected by an odometry constraint, with
 | 
					
						
							|  |  |  |   // a hard prior on one variable, and a conflicting soft prior
 | 
					
						
							|  |  |  |   // on the other variable - the constraints should override the soft constraint
 | 
					
						
							|  |  |  |   Point2 truth_pt1(1.0, 2.0), truth_pt2(3.0, 2.0); | 
					
						
							| 
									
										
										
										
											2014-11-25 15:47:25 +08:00
										 |  |  |   Symbol key1('x', 1), key2('x', 2); | 
					
						
							| 
									
										
										
										
											2012-10-02 22:40:07 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   // hard prior on x1
 | 
					
						
							|  |  |  |   eq2D::UnaryEqualityConstraint::shared_ptr constraint1( | 
					
						
							|  |  |  |       new eq2D::UnaryEqualityConstraint(truth_pt1, key1)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // soft prior on x2
 | 
					
						
							|  |  |  |   Point2 badPt(100.0, -200.0); | 
					
						
							|  |  |  |   simulated2D::Prior::shared_ptr factor( | 
					
						
							|  |  |  |       new simulated2D::Prior(badPt, soft_model, key2)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // odometry constraint
 | 
					
						
							|  |  |  |   eq2D::OdoEqualityConstraint::shared_ptr constraint2( | 
					
						
							| 
									
										
										
										
											2014-12-22 23:02:33 +08:00
										 |  |  |       new eq2D::OdoEqualityConstraint(truth_pt2-truth_pt1, key1, key2)); | 
					
						
							| 
									
										
										
										
											2012-10-02 22:40:07 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   NonlinearFactorGraph graph; | 
					
						
							|  |  |  |   graph.push_back(constraint1); | 
					
						
							|  |  |  |   graph.push_back(constraint2); | 
					
						
							|  |  |  |   graph.push_back(factor); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   Values initValues; | 
					
						
							| 
									
										
										
										
											2016-06-06 14:52:04 +08:00
										 |  |  |   initValues.insert(key1, Point2(0,0)); | 
					
						
							| 
									
										
										
										
											2012-10-02 22:40:07 +08:00
										 |  |  |   initValues.insert(key2, badPt); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   Values actual = LevenbergMarquardtOptimizer(graph, initValues).optimize(); | 
					
						
							|  |  |  |   Values expected; | 
					
						
							|  |  |  |   expected.insert(key1, truth_pt1); | 
					
						
							|  |  |  |   expected.insert(key2, truth_pt2); | 
					
						
							|  |  |  |   CHECK(assert_equal(expected, actual, tol)); | 
					
						
							| 
									
										
										
										
											2011-11-10 10:05:03 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-25 15:47:25 +08:00
										 |  |  | //******************************************************************************
 | 
					
						
							| 
									
										
										
										
											2011-11-10 10:05:03 +08:00
										 |  |  | TEST (testNonlinearEqualityConstraint, two_pose ) { | 
					
						
							| 
									
										
										
										
											2012-10-02 22:40:07 +08:00
										 |  |  |   /*
 | 
					
						
							|  |  |  |    * Determining a ground truth linear system | 
					
						
							|  |  |  |    * with two poses seeing one landmark, with each pose | 
					
						
							|  |  |  |    * constrained to a particular value | 
					
						
							|  |  |  |    */ | 
					
						
							| 
									
										
										
										
											2011-11-10 10:05:03 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-03-23 01:46:43 +08:00
										 |  |  |   NonlinearFactorGraph graph; | 
					
						
							| 
									
										
										
										
											2011-11-10 10:05:03 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-25 15:47:25 +08:00
										 |  |  |   Symbol x1('x', 1), x2('x', 2); | 
					
						
							|  |  |  |   Symbol l1('l', 1), l2('l', 2); | 
					
						
							|  |  |  |   Point2 pt_x1(1.0, 1.0), pt_x2(5.0, 6.0); | 
					
						
							| 
									
										
										
										
											2013-08-06 21:44:22 +08:00
										 |  |  |   graph += eq2D::UnaryEqualityConstraint(pt_x1, x1); | 
					
						
							|  |  |  |   graph += eq2D::UnaryEqualityConstraint(pt_x2, x2); | 
					
						
							| 
									
										
										
										
											2012-10-02 22:40:07 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   Point2 z1(0.0, 5.0); | 
					
						
							|  |  |  |   SharedNoiseModel sigma(noiseModel::Isotropic::Sigma(2, 0.1)); | 
					
						
							| 
									
										
										
										
											2014-11-25 15:47:25 +08:00
										 |  |  |   graph += simulated2D::Measurement(z1, sigma, x1, l1); | 
					
						
							| 
									
										
										
										
											2012-10-02 22:40:07 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   Point2 z2(-4.0, 0.0); | 
					
						
							| 
									
										
										
										
											2014-11-25 15:47:25 +08:00
										 |  |  |   graph += simulated2D::Measurement(z2, sigma, x2, l2); | 
					
						
							| 
									
										
										
										
											2012-10-02 22:40:07 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-08-06 21:44:22 +08:00
										 |  |  |   graph += eq2D::PointEqualityConstraint(l1, l2); | 
					
						
							| 
									
										
										
										
											2012-10-02 22:40:07 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   Values initialEstimate; | 
					
						
							|  |  |  |   initialEstimate.insert(x1, pt_x1); | 
					
						
							| 
									
										
										
										
											2016-06-06 14:52:04 +08:00
										 |  |  |   initialEstimate.insert(x2, Point2(0,0)); | 
					
						
							| 
									
										
										
										
											2012-10-02 22:40:07 +08:00
										 |  |  |   initialEstimate.insert(l1, Point2(1.0, 6.0)); // ground truth
 | 
					
						
							|  |  |  |   initialEstimate.insert(l2, Point2(-4.0, 0.0)); // starting with a separate reference frame
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-25 15:47:25 +08:00
										 |  |  |   Values actual = | 
					
						
							|  |  |  |       LevenbergMarquardtOptimizer(graph, initialEstimate).optimize(); | 
					
						
							| 
									
										
										
										
											2012-10-02 22:40:07 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   Values expected; | 
					
						
							|  |  |  |   expected.insert(x1, pt_x1); | 
					
						
							|  |  |  |   expected.insert(l1, Point2(1.0, 6.0)); | 
					
						
							|  |  |  |   expected.insert(l2, Point2(1.0, 6.0)); | 
					
						
							|  |  |  |   expected.insert(x2, Point2(5.0, 6.0)); | 
					
						
							|  |  |  |   CHECK(assert_equal(expected, actual, 1e-5)); | 
					
						
							| 
									
										
										
										
											2011-11-10 10:05:03 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-25 15:47:25 +08:00
										 |  |  | //******************************************************************************
 | 
					
						
							| 
									
										
										
										
											2011-11-10 10:05:03 +08:00
										 |  |  | TEST (testNonlinearEqualityConstraint, map_warp ) { | 
					
						
							| 
									
										
										
										
											2012-10-02 22:40:07 +08:00
										 |  |  |   // get a graph
 | 
					
						
							| 
									
										
										
										
											2012-03-23 01:46:43 +08:00
										 |  |  |   NonlinearFactorGraph graph; | 
					
						
							| 
									
										
										
										
											2011-11-10 10:05:03 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-02 22:40:07 +08:00
										 |  |  |   // keys
 | 
					
						
							| 
									
										
										
										
											2014-11-25 15:47:25 +08:00
										 |  |  |   Symbol x1('x', 1), x2('x', 2); | 
					
						
							|  |  |  |   Symbol l1('l', 1), l2('l', 2); | 
					
						
							| 
									
										
										
										
											2011-11-10 10:05:03 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-02 22:40:07 +08:00
										 |  |  |   // constant constraint on x1
 | 
					
						
							|  |  |  |   Point2 pose1(1.0, 1.0); | 
					
						
							| 
									
										
										
										
											2013-08-06 21:44:22 +08:00
										 |  |  |   graph += eq2D::UnaryEqualityConstraint(pose1, x1); | 
					
						
							| 
									
										
										
										
											2011-11-10 10:05:03 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-06 07:23:40 +08:00
										 |  |  |   SharedDiagonal sigma = noiseModel::Isotropic::Sigma(2, 0.1); | 
					
						
							| 
									
										
										
										
											2011-11-10 10:05:03 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-02 22:40:07 +08:00
										 |  |  |   // measurement from x1 to l1
 | 
					
						
							|  |  |  |   Point2 z1(0.0, 5.0); | 
					
						
							| 
									
										
										
										
											2013-08-06 21:44:22 +08:00
										 |  |  |   graph += simulated2D::Measurement(z1, sigma, x1, l1); | 
					
						
							| 
									
										
										
										
											2011-11-10 10:05:03 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-02 22:40:07 +08:00
										 |  |  |   // measurement from x2 to l2
 | 
					
						
							|  |  |  |   Point2 z2(-4.0, 0.0); | 
					
						
							| 
									
										
										
										
											2013-08-06 21:44:22 +08:00
										 |  |  |   graph += simulated2D::Measurement(z2, sigma, x2, l2); | 
					
						
							| 
									
										
										
										
											2011-11-10 10:05:03 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-02 22:40:07 +08:00
										 |  |  |   // equality constraint between l1 and l2
 | 
					
						
							| 
									
										
										
										
											2013-08-06 21:44:22 +08:00
										 |  |  |   graph += eq2D::PointEqualityConstraint(l1, l2); | 
					
						
							| 
									
										
										
										
											2011-11-10 10:05:03 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-02 22:40:07 +08:00
										 |  |  |   // create an initial estimate
 | 
					
						
							|  |  |  |   Values initialEstimate; | 
					
						
							| 
									
										
										
										
											2014-11-25 15:47:25 +08:00
										 |  |  |   initialEstimate.insert(x1, Point2(1.0, 1.0)); | 
					
						
							|  |  |  |   initialEstimate.insert(l1, Point2(1.0, 6.0)); | 
					
						
							| 
									
										
										
										
											2012-10-02 22:40:07 +08:00
										 |  |  |   initialEstimate.insert(l2, Point2(-4.0, 0.0)); // starting with a separate reference frame
 | 
					
						
							| 
									
										
										
										
											2014-11-25 15:47:25 +08:00
										 |  |  |   initialEstimate.insert(x2, Point2(0.0, 0.0)); // other pose starts at origin
 | 
					
						
							| 
									
										
										
										
											2011-11-10 10:05:03 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-02 22:40:07 +08:00
										 |  |  |   // optimize
 | 
					
						
							| 
									
										
										
										
											2014-11-25 15:47:25 +08:00
										 |  |  |   Values actual = | 
					
						
							|  |  |  |       LevenbergMarquardtOptimizer(graph, initialEstimate).optimize(); | 
					
						
							| 
									
										
										
										
											2011-11-10 10:05:03 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-02 22:40:07 +08:00
										 |  |  |   Values expected; | 
					
						
							|  |  |  |   expected.insert(x1, Point2(1.0, 1.0)); | 
					
						
							|  |  |  |   expected.insert(l1, Point2(1.0, 6.0)); | 
					
						
							|  |  |  |   expected.insert(l2, Point2(1.0, 6.0)); | 
					
						
							|  |  |  |   expected.insert(x2, Point2(5.0, 6.0)); | 
					
						
							|  |  |  |   CHECK(assert_equal(expected, actual, tol)); | 
					
						
							| 
									
										
										
										
											2011-11-10 10:05:03 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-25 15:47:25 +08:00
										 |  |  | //******************************************************************************
 | 
					
						
							| 
									
										
										
										
											2011-11-10 10:05:03 +08:00
										 |  |  | TEST (testNonlinearEqualityConstraint, stereo_constrained ) { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-25 03:01:19 +08:00
										 |  |  |   // make a realistic calibration matrix
 | 
					
						
							|  |  |  |   static double fov = 60; // degrees
 | 
					
						
							|  |  |  |   static int w = 640, h = 480; | 
					
						
							|  |  |  |   static Cal3_S2 K(fov, w, h); | 
					
						
							|  |  |  |   static boost::shared_ptr<Cal3_S2> shK(new Cal3_S2(K)); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-02 22:40:07 +08:00
										 |  |  |   // create initial estimates
 | 
					
						
							| 
									
										
										
										
											2016-02-25 03:01:19 +08:00
										 |  |  |   Rot3 faceTowardsY(Point3(1, 0, 0), Point3(0, 0, -1), Point3(0, 1, 0)); | 
					
						
							| 
									
										
										
										
											2016-02-25 06:44:05 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   Pose3 poseLeft(faceTowardsY, Point3(0, 0, 0));  // origin, left camera
 | 
					
						
							| 
									
										
										
										
											2020-02-22 08:42:55 +08:00
										 |  |  |   PinholeCamera<Cal3_S2> leftCamera(poseLeft, K); | 
					
						
							| 
									
										
										
										
											2016-02-25 06:44:05 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   Pose3 poseRight(faceTowardsY, Point3(2, 0, 0));  // 2 units to the right
 | 
					
						
							| 
									
										
										
										
											2020-02-22 08:42:55 +08:00
										 |  |  |   PinholeCamera<Cal3_S2> rightCamera(poseRight, K); | 
					
						
							| 
									
										
										
										
											2016-02-25 06:44:05 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-25 03:01:19 +08:00
										 |  |  |   Point3 landmark(1, 5, 0); //centered between the cameras, 5 units away
 | 
					
						
							| 
									
										
										
										
											2012-10-02 22:40:07 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   // keys
 | 
					
						
							| 
									
										
										
										
											2016-02-25 03:01:19 +08:00
										 |  |  |   Symbol key_x1('x', 1), key_x2('x', 2); | 
					
						
							|  |  |  |   Symbol key_l1('l', 1), key_l2('l', 2); | 
					
						
							| 
									
										
										
										
											2011-11-10 10:05:03 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-02 22:40:07 +08:00
										 |  |  |   // create graph
 | 
					
						
							| 
									
										
										
										
											2016-02-25 03:01:19 +08:00
										 |  |  |   NonlinearFactorGraph graph; | 
					
						
							| 
									
										
										
										
											2011-11-10 10:05:03 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-02 22:40:07 +08:00
										 |  |  |   // create equality constraints for poses
 | 
					
						
							| 
									
										
										
										
											2016-02-25 03:01:19 +08:00
										 |  |  |   graph += NonlinearEquality<Pose3>(key_x1, leftCamera.pose()); | 
					
						
							|  |  |  |   graph += NonlinearEquality<Pose3>(key_x2, rightCamera.pose()); | 
					
						
							| 
									
										
										
										
											2011-11-10 10:05:03 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-02 22:40:07 +08:00
										 |  |  |   // create  factors
 | 
					
						
							| 
									
										
										
										
											2012-10-06 07:23:40 +08:00
										 |  |  |   SharedDiagonal vmodel = noiseModel::Unit::Create(2); | 
					
						
							| 
									
										
										
										
											2014-11-25 15:47:25 +08:00
										 |  |  |   graph += GenericProjectionFactor<Pose3, Point3, Cal3_S2>( | 
					
						
							| 
									
										
										
										
											2016-02-25 03:01:19 +08:00
										 |  |  |       leftCamera.project(landmark), vmodel, key_x1, key_l1, shK); | 
					
						
							| 
									
										
										
										
											2014-11-25 15:47:25 +08:00
										 |  |  |   graph += GenericProjectionFactor<Pose3, Point3, Cal3_S2>( | 
					
						
							| 
									
										
										
										
											2016-02-25 03:01:19 +08:00
										 |  |  |       rightCamera.project(landmark), vmodel, key_x2, key_l2, shK); | 
					
						
							| 
									
										
										
										
											2011-11-10 10:05:03 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-25 03:01:19 +08:00
										 |  |  |   // add equality constraint saying there is only one point
 | 
					
						
							|  |  |  |   graph += NonlinearEquality2<Point3>(key_l1, key_l2); | 
					
						
							| 
									
										
										
										
											2011-11-10 10:05:03 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-02 22:40:07 +08:00
										 |  |  |   // create initial data
 | 
					
						
							| 
									
										
										
										
											2016-02-25 03:01:19 +08:00
										 |  |  |   Point3 landmark1(0.5, 5, 0); | 
					
						
							|  |  |  |   Point3 landmark2(1.5, 5, 0); | 
					
						
							| 
									
										
										
										
											2011-11-10 10:05:03 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-02 22:40:07 +08:00
										 |  |  |   Values initValues; | 
					
						
							| 
									
										
										
										
											2016-02-25 03:01:19 +08:00
										 |  |  |   initValues.insert(key_x1, poseLeft); | 
					
						
							|  |  |  |   initValues.insert(key_x2, poseRight); | 
					
						
							|  |  |  |   initValues.insert(key_l1, landmark1); | 
					
						
							|  |  |  |   initValues.insert(key_l2, landmark2); | 
					
						
							| 
									
										
										
										
											2011-11-10 10:05:03 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-02 22:40:07 +08:00
										 |  |  |   // optimize
 | 
					
						
							|  |  |  |   Values actual = LevenbergMarquardtOptimizer(graph, initValues).optimize(); | 
					
						
							| 
									
										
										
										
											2011-11-10 10:05:03 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-02 22:40:07 +08:00
										 |  |  |   // create config
 | 
					
						
							|  |  |  |   Values truthValues; | 
					
						
							| 
									
										
										
										
											2016-02-25 03:01:19 +08:00
										 |  |  |   truthValues.insert(key_x1, leftCamera.pose()); | 
					
						
							|  |  |  |   truthValues.insert(key_x2, rightCamera.pose()); | 
					
						
							|  |  |  |   truthValues.insert(key_l1, landmark); | 
					
						
							|  |  |  |   truthValues.insert(key_l2, landmark); | 
					
						
							| 
									
										
										
										
											2011-11-10 10:05:03 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-02 22:40:07 +08:00
										 |  |  |   // check if correct
 | 
					
						
							|  |  |  |   CHECK(assert_equal(truthValues, actual, 1e-5)); | 
					
						
							| 
									
										
										
										
											2011-11-10 10:05:03 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-25 15:47:25 +08:00
										 |  |  | //******************************************************************************
 | 
					
						
							|  |  |  | int main() { | 
					
						
							|  |  |  |   TestResult tr; | 
					
						
							|  |  |  |   return TestRegistry::runAllTests(tr); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | //******************************************************************************
 |