| 
									
										
										
										
											2009-09-09 12:43:04 +08:00
										 |  |  | /**
 | 
					
						
							|  |  |  |  * NonlinearOptimizer.h | 
					
						
							|  |  |  |  * @brief: Encapsulates nonlinear optimization state | 
					
						
							|  |  |  |  * @Author: Frank Dellaert | 
					
						
							|  |  |  |  * Created on: Sep 7, 2009 | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #ifndef NONLINEAROPTIMIZER_H_
 | 
					
						
							|  |  |  | #define NONLINEAROPTIMIZER_H_
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <boost/shared_ptr.hpp>
 | 
					
						
							|  |  |  | #include "NonlinearFactorGraph.h"
 | 
					
						
							|  |  |  | #include "FGConfig.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | namespace gtsam { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/**
 | 
					
						
							|  |  |  | 	 * The class NonlinearOptimizer encapsulates an optimization state. | 
					
						
							|  |  |  | 	 * Typically it is instantiated with a NonlinearFactorGraph and an initial config | 
					
						
							|  |  |  | 	 * and then one of the optimization routines is called. These recursively iterate | 
					
						
							|  |  |  | 	 * until convergence. All methods are functional and return a new state. | 
					
						
							|  |  |  | 	 * | 
					
						
							|  |  |  | 	 * The class is parameterized by the Config class type, in order to optimize | 
					
						
							|  |  |  | 	 * over non-vector configurations as well. | 
					
						
							|  |  |  | 	 * To use in code, include <gtsam/NonlinearOptimizer.cpp> in your cpp file | 
					
						
							|  |  |  | 	 * (the trick in http://www.ddj.com/cpp/184403420 did not work).
 | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	template<class FactorGraph, class Config> | 
					
						
							|  |  |  | 	class NonlinearOptimizer { | 
					
						
							|  |  |  | 	public: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// For performance reasons in recursion, we store configs in a shared_ptr
 | 
					
						
							|  |  |  | 		typedef boost::shared_ptr<const Config> shared_config; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		enum verbosityLevel { | 
					
						
							|  |  |  | 			SILENT, | 
					
						
							|  |  |  | 			ERROR, | 
					
						
							|  |  |  | 			LAMBDA, | 
					
						
							|  |  |  | 			CONFIG, | 
					
						
							|  |  |  | 			DELTA, | 
					
						
							|  |  |  | 			LINEAR, | 
					
						
							|  |  |  | 			TRYLAMBDA, | 
					
						
							|  |  |  | 			TRYCONFIG, | 
					
						
							|  |  |  | 			TRYDELTA, | 
					
						
							|  |  |  | 			DAMPED | 
					
						
							|  |  |  | 		}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	private: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// keep a reference to const versions of the graph and ordering
 | 
					
						
							|  |  |  | 		// These normally do not change
 | 
					
						
							|  |  |  | 		const FactorGraph* graph_; | 
					
						
							|  |  |  | 		const Ordering* ordering_; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// keep a configuration and its error
 | 
					
						
							|  |  |  | 		// These typically change once per iteration (in a functional way)
 | 
					
						
							|  |  |  | 		shared_config config_; | 
					
						
							|  |  |  | 		double error_; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// keep current lambda for use within LM only
 | 
					
						
							|  |  |  | 		// TODO: red flag, should we have an LM class ?
 | 
					
						
							|  |  |  | 		double lambda_; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// Recursively try to do tempered Gauss-Newton steps until we succeed
 | 
					
						
							|  |  |  | 		NonlinearOptimizer try_lambda(const LinearFactorGraph& linear, | 
					
						
							|  |  |  | 				verbosityLevel verbosity, double factor) const; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	public: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/**
 | 
					
						
							|  |  |  | 		 * Constructor | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		NonlinearOptimizer(const FactorGraph& graph, const Ordering& ordering, | 
					
						
							|  |  |  | 				shared_config config, double lambda = 1e-5); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/**
 | 
					
						
							|  |  |  | 		 * Return current error | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		double error() const { | 
					
						
							|  |  |  | 			return error_; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/**
 | 
					
						
							|  |  |  | 		 * Return current lambda | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		double lambda() const { | 
					
						
							|  |  |  | 			return lambda_; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-09-11 06:08:47 +08:00
										 |  |  | 		/**
 | 
					
						
							|  |  |  | 		 * Return the config | 
					
						
							|  |  |  | 		 */ | 
					
						
							| 
									
										
										
										
											2009-09-12 02:33:05 +08:00
										 |  |  | 		shared_config config() const{ | 
					
						
							| 
									
										
										
										
											2009-09-11 06:08:47 +08:00
										 |  |  | 			return config_; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-09-09 12:43:04 +08:00
										 |  |  | 		/**
 | 
					
						
							|  |  |  | 		 *  linearize and optimize | 
					
						
							|  |  |  | 		 *  Thi returns an FGConfig, i.e., vectors in tangent space of Config | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		FGConfig delta() const; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/**
 | 
					
						
							|  |  |  | 		 * Do one Gauss-Newton iteration and return next state | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		NonlinearOptimizer iterate(verbosityLevel verbosity = SILENT) const; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/**
 | 
					
						
							|  |  |  | 		 * Optimize a solution for a non linear factor graph | 
					
						
							|  |  |  | 		 * @param relativeTreshold | 
					
						
							|  |  |  | 		 * @param absoluteTreshold | 
					
						
							|  |  |  | 		 * @param verbosity Integer specifying how much output to provide | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		NonlinearOptimizer | 
					
						
							|  |  |  | 		gaussNewton(double relativeThreshold, double absoluteThreshold, | 
					
						
							|  |  |  | 				verbosityLevel verbosity = SILENT, int maxIterations = 100) const; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/**
 | 
					
						
							|  |  |  | 		 * One iteration of Levenberg Marquardt | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		NonlinearOptimizer iterateLM(verbosityLevel verbosity = SILENT, | 
					
						
							|  |  |  | 				double lambdaFactor = 10) const; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/**
 | 
					
						
							|  |  |  | 		 * Optimize using Levenberg-Marquardt. Really Levenberg's | 
					
						
							|  |  |  | 		 * algorithm at this moment, as we just add I*\lambda to Hessian | 
					
						
							|  |  |  | 		 * H'H. The probabilistic explanation is very simple: every | 
					
						
							|  |  |  | 		 * variable gets an extra Gaussian prior that biases staying at | 
					
						
							|  |  |  | 		 * current value, with variance 1/lambda. This is done very easily | 
					
						
							|  |  |  | 		 * (but perhaps wastefully) by adding a prior factor for each of | 
					
						
							|  |  |  | 		 * the variables, after linearization. | 
					
						
							|  |  |  | 		 * | 
					
						
							|  |  |  | 		 * @param relativeThreshold | 
					
						
							|  |  |  | 		 * @param absoluteThreshold | 
					
						
							|  |  |  | 		 * @param verbosity    Integer specifying how much output to provide | 
					
						
							|  |  |  | 		 * @param lambdaFactor Factor by which to decrease/increase lambda | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		NonlinearOptimizer | 
					
						
							|  |  |  | 		levenbergMarquardt(double relativeThreshold, double absoluteThreshold, | 
					
						
							|  |  |  | 				verbosityLevel verbosity = SILENT, int maxIterations = 100, | 
					
						
							|  |  |  | 				double lambdaFactor = 10) const; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #endif /* NONLINEAROPTIMIZER_H_ */
 |