Added tests and fixes so that nonlinear equalities will optimize properly when error is allowed.
							parent
							
								
									1a11998273
								
							
						
					
					
						commit
						d1280495e3
					
				| 
						 | 
					@ -116,7 +116,7 @@ namespace gtsam {
 | 
				
			||||||
		virtual boost::shared_ptr<GaussianFactor> linearize(const Config& x) const {
 | 
							virtual boost::shared_ptr<GaussianFactor> linearize(const Config& x) const {
 | 
				
			||||||
			const T& xj = x[this->key_];
 | 
								const T& xj = x[this->key_];
 | 
				
			||||||
			Matrix A;
 | 
								Matrix A;
 | 
				
			||||||
			Vector b = - evaluateError(xj, A);
 | 
								Vector b = evaluateError(xj, A);
 | 
				
			||||||
			// TODO pass unwhitened + noise model to Gaussian factor
 | 
								// TODO pass unwhitened + noise model to Gaussian factor
 | 
				
			||||||
			SharedDiagonal model = noiseModel::Constrained::All(b.size());
 | 
								SharedDiagonal model = noiseModel::Constrained::All(b.size());
 | 
				
			||||||
			return	GaussianFactor::shared_ptr(new GaussianFactor(this->key_, A, b, model));
 | 
								return	GaussianFactor::shared_ptr(new GaussianFactor(this->key_, A, b, model));
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -9,8 +9,12 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "Key.h"
 | 
					#include "Key.h"
 | 
				
			||||||
#include "Pose2.h"
 | 
					#include "Pose2.h"
 | 
				
			||||||
 | 
					#include "Ordering.h"
 | 
				
			||||||
#include "VectorConfig.h"
 | 
					#include "VectorConfig.h"
 | 
				
			||||||
#include "NonlinearEquality.h"
 | 
					#include "NonlinearEquality.h"
 | 
				
			||||||
 | 
					#include "PriorFactor.h"
 | 
				
			||||||
 | 
					#include "NonlinearFactorGraph.h"
 | 
				
			||||||
 | 
					#include "NonlinearOptimizer-inl.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "LieConfig-inl.h"
 | 
					#include "LieConfig-inl.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -22,9 +26,13 @@ typedef boost::shared_ptr<NLE> shared_nle;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef TypedSymbol<Pose2, 'x'> PoseKey;
 | 
					typedef TypedSymbol<Pose2, 'x'> PoseKey;
 | 
				
			||||||
typedef LieConfig<PoseKey, Pose2> PoseConfig;
 | 
					typedef LieConfig<PoseKey, Pose2> PoseConfig;
 | 
				
			||||||
 | 
					typedef PriorFactor<PoseConfig, PoseKey, Pose2> PosePrior;
 | 
				
			||||||
typedef NonlinearEquality<PoseConfig, PoseKey, Pose2> PoseNLE;
 | 
					typedef NonlinearEquality<PoseConfig, PoseKey, Pose2> PoseNLE;
 | 
				
			||||||
typedef boost::shared_ptr<PoseNLE> shared_poseNLE;
 | 
					typedef boost::shared_ptr<PoseNLE> shared_poseNLE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef NonlinearFactorGraph<PoseConfig> PoseGraph;
 | 
				
			||||||
 | 
					typedef NonlinearOptimizer<PoseGraph,PoseConfig> PoseOptimizer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool vector_compare(const Vector& a, const Vector& b) {
 | 
					bool vector_compare(const Vector& a, const Vector& b) {
 | 
				
			||||||
	return equal_with_abs_tol(a, b, 1e-5);
 | 
						return equal_with_abs_tol(a, b, 1e-5);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -182,11 +190,105 @@ TEST ( NonlinearEquality, allow_error_vector ) {
 | 
				
			||||||
	// check linearization
 | 
						// check linearization
 | 
				
			||||||
	GaussianFactor::shared_ptr actLinFactor = nle.linearize(config);
 | 
						GaussianFactor::shared_ptr actLinFactor = nle.linearize(config);
 | 
				
			||||||
	Matrix A1 = eye(3,3);
 | 
						Matrix A1 = eye(3,3);
 | 
				
			||||||
	Vector b = -expVec;
 | 
						Vector b = expVec;
 | 
				
			||||||
	SharedDiagonal model = noiseModel::Constrained::All(3);
 | 
						SharedDiagonal model = noiseModel::Constrained::All(3);
 | 
				
			||||||
	GaussianFactor::shared_ptr expLinFactor(new GaussianFactor(key1, A1, b, model));
 | 
						GaussianFactor::shared_ptr expLinFactor(new GaussianFactor(key1, A1, b, model));
 | 
				
			||||||
	CHECK(assert_equal(*expLinFactor, *actLinFactor));
 | 
						CHECK(assert_equal(*expLinFactor, *actLinFactor));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* ************************************************************************* */
 | 
				
			||||||
 | 
					TEST ( NonlinearEquality, allow_error_pose ) {
 | 
				
			||||||
 | 
						PoseKey key1(1);
 | 
				
			||||||
 | 
						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);
 | 
				
			||||||
 | 
						Vector expVec = Vector_(3, -0.989992, -0.14112, 0.0);
 | 
				
			||||||
 | 
						CHECK(assert_equal(expVec, actVec, 1e-5));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// the actual error should have a gain on it
 | 
				
			||||||
 | 
						PoseConfig config;
 | 
				
			||||||
 | 
						config.insert(key1, badPoint1);
 | 
				
			||||||
 | 
						double actError = nle.error(config);
 | 
				
			||||||
 | 
						DOUBLES_EQUAL(500.0, actError, 1e-9);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// check linearization
 | 
				
			||||||
 | 
						GaussianFactor::shared_ptr actLinFactor = nle.linearize(config);
 | 
				
			||||||
 | 
						Matrix A1 = eye(3,3);
 | 
				
			||||||
 | 
						Vector b = expVec;
 | 
				
			||||||
 | 
						SharedDiagonal model = noiseModel::Constrained::All(3);
 | 
				
			||||||
 | 
						GaussianFactor::shared_ptr expLinFactor(new GaussianFactor(key1, A1, b, model));
 | 
				
			||||||
 | 
						CHECK(assert_equal(*expLinFactor, *actLinFactor, 1e-5));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* ************************************************************************* */
 | 
				
			||||||
 | 
					TEST ( NonlinearEquality, allow_error_optimize ) {
 | 
				
			||||||
 | 
						PoseKey key1(1);
 | 
				
			||||||
 | 
						Pose2 feasible1(1.0, 2.0, 3.0);
 | 
				
			||||||
 | 
						double error_gain = 500.0;
 | 
				
			||||||
 | 
						PoseNLE nle(key1, feasible1, error_gain);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// add to a graph
 | 
				
			||||||
 | 
						boost::shared_ptr<PoseGraph> graph(new PoseGraph());
 | 
				
			||||||
 | 
						graph->add(nle);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// initialize away from the ideal
 | 
				
			||||||
 | 
						Pose2 initPose(0.0, 2.0, 3.0);
 | 
				
			||||||
 | 
						boost::shared_ptr<PoseConfig> init(new PoseConfig());
 | 
				
			||||||
 | 
						init->insert(key1, initPose);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// optimize
 | 
				
			||||||
 | 
						boost::shared_ptr<Ordering> ord(new Ordering());
 | 
				
			||||||
 | 
						ord->push_back(key1);
 | 
				
			||||||
 | 
						PoseOptimizer::shared_solver solver(new PoseOptimizer::solver(ord));
 | 
				
			||||||
 | 
						PoseOptimizer optimizer(graph, init, solver);
 | 
				
			||||||
 | 
						double relThresh = 1e-5, absThresh = 1e-5;
 | 
				
			||||||
 | 
						PoseOptimizer result = optimizer.levenbergMarquardt(relThresh, absThresh, PoseOptimizer::SILENT);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// verify
 | 
				
			||||||
 | 
						PoseConfig expected;
 | 
				
			||||||
 | 
						expected.insert(key1, feasible1);
 | 
				
			||||||
 | 
						CHECK(assert_equal(expected, *result.config()));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* ************************************************************************* */
 | 
				
			||||||
 | 
					TEST ( NonlinearEquality, allow_error_optimize_with_factors ) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// create a hard constraint
 | 
				
			||||||
 | 
						PoseKey key1(1);
 | 
				
			||||||
 | 
						Pose2 feasible1(1.0, 2.0, 3.0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// initialize away from the ideal
 | 
				
			||||||
 | 
						boost::shared_ptr<PoseConfig> init(new PoseConfig());
 | 
				
			||||||
 | 
						Pose2 initPose(0.0, 2.0, 3.0);
 | 
				
			||||||
 | 
						init->insert(key1, initPose);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						double error_gain = 500.0;
 | 
				
			||||||
 | 
						PoseNLE nle(key1, feasible1, error_gain);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// create a soft prior that conflicts
 | 
				
			||||||
 | 
						PosePrior prior(key1, initPose, noiseModel::Isotropic::Sigma(3, 0.1));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// add to a graph
 | 
				
			||||||
 | 
						boost::shared_ptr<PoseGraph> graph(new PoseGraph());
 | 
				
			||||||
 | 
						graph->add(nle);
 | 
				
			||||||
 | 
						graph->add(prior);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// optimize
 | 
				
			||||||
 | 
						boost::shared_ptr<Ordering> ord(new Ordering());
 | 
				
			||||||
 | 
						ord->push_back(key1);
 | 
				
			||||||
 | 
						PoseOptimizer::shared_solver solver(new PoseOptimizer::solver(ord));
 | 
				
			||||||
 | 
						PoseOptimizer optimizer(graph, init, solver);
 | 
				
			||||||
 | 
						double relThresh = 1e-5, absThresh = 1e-5;
 | 
				
			||||||
 | 
						PoseOptimizer result = optimizer.levenbergMarquardt(relThresh, absThresh, PoseOptimizer::SILENT);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// verify
 | 
				
			||||||
 | 
						PoseConfig expected;
 | 
				
			||||||
 | 
						expected.insert(key1, feasible1);
 | 
				
			||||||
 | 
						CHECK(assert_equal(expected, *result.config()));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* ************************************************************************* */
 | 
					/* ************************************************************************* */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue