| 
									
										
										
										
											2009-11-24 03:57:35 +08:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * @file SQPOptimizer-inl.h | 
					
						
							|  |  |  |  * @brief Implementation of the SQP Optimizer | 
					
						
							|  |  |  |  * @author Alex Cunningham | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #pragma once
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-24 05:25:31 +08:00
										 |  |  | #include <boost/foreach.hpp>
 | 
					
						
							| 
									
										
										
										
											2009-11-24 06:10:52 +08:00
										 |  |  | #include <boost/assign/std/list.hpp> // for operator +=
 | 
					
						
							|  |  |  | #include <boost/assign/std/map.hpp> // for insert
 | 
					
						
							| 
									
										
										
										
											2009-11-24 05:25:31 +08:00
										 |  |  | #include "GaussianFactorGraph.h"
 | 
					
						
							| 
									
										
										
										
											2009-11-24 14:39:27 +08:00
										 |  |  | #include "NonlinearFactorGraph.h"
 | 
					
						
							| 
									
										
										
										
											2009-11-24 03:57:35 +08:00
										 |  |  | #include "SQPOptimizer.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-28 01:59:03 +08:00
										 |  |  | // implementations
 | 
					
						
							|  |  |  | #include "NonlinearConstraint-inl.h"
 | 
					
						
							|  |  |  | #include "NonlinearFactorGraph-inl.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-24 03:57:35 +08:00
										 |  |  | using namespace std; | 
					
						
							| 
									
										
										
										
											2009-11-24 06:10:52 +08:00
										 |  |  | using namespace boost::assign; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-24 03:57:35 +08:00
										 |  |  | namespace gtsam { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-29 06:49:14 +08:00
										 |  |  | /* **************************************************************** */ | 
					
						
							|  |  |  | template <class G, class C> | 
					
						
							|  |  |  | double constraintError(const G& graph, const C& config) { | 
					
						
							|  |  |  | 	// local typedefs
 | 
					
						
							|  |  |  | 	typedef typename G::const_iterator const_iterator; | 
					
						
							|  |  |  | 	typedef NonlinearConstraint<C> NLConstraint; | 
					
						
							|  |  |  | 	typedef boost::shared_ptr<NLConstraint > shared_c; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// accumulate error
 | 
					
						
							|  |  |  | 	double error = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// find the constraints
 | 
					
						
							|  |  |  | 	for (const_iterator factor = graph.begin(); factor < graph.end(); factor++) { | 
					
						
							|  |  |  | 		const shared_c constraint = boost::shared_dynamic_cast<NLConstraint >(*factor); | 
					
						
							|  |  |  | 		if (constraint != NULL) { | 
					
						
							| 
									
										
										
										
											2010-01-18 13:38:53 +08:00
										 |  |  | 			Vector e = constraint->unwhitenedError(config); | 
					
						
							| 
									
										
										
										
											2009-11-29 06:49:14 +08:00
										 |  |  | 			error += inner_prod(trans(e),e); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return error; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-24 03:57:35 +08:00
										 |  |  | /* **************************************************************** */ | 
					
						
							|  |  |  | template <class G, class C> | 
					
						
							|  |  |  | SQPOptimizer<G,C>::SQPOptimizer(const G& graph, const Ordering& ordering, | 
					
						
							|  |  |  | 		shared_config config) | 
					
						
							| 
									
										
										
										
											2009-11-24 06:10:52 +08:00
										 |  |  | : graph_(&graph), ordering_(&ordering), full_ordering_(ordering), | 
					
						
							| 
									
										
										
										
											2009-11-29 06:49:14 +08:00
										 |  |  |   config_(config), lagrange_config_(new VectorConfig), error_(graph.error(*config)), | 
					
						
							|  |  |  |   constraint_error_(constraintError(graph, *config)) | 
					
						
							| 
									
										
										
										
											2009-11-24 03:57:35 +08:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2009-11-24 06:10:52 +08:00
										 |  |  | 	// local typedefs
 | 
					
						
							|  |  |  | 	typedef typename G::const_iterator const_iterator; | 
					
						
							|  |  |  | 	typedef NonlinearConstraint<C> NLConstraint; | 
					
						
							|  |  |  | 	typedef boost::shared_ptr<NLConstraint > shared_c; | 
					
						
							| 
									
										
										
										
											2009-11-24 03:57:35 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-24 06:10:52 +08:00
										 |  |  | 	// find the constraints
 | 
					
						
							|  |  |  | 	for (const_iterator factor = graph_->begin(); factor < graph_->end(); factor++) { | 
					
						
							|  |  |  | 		const shared_c constraint = boost::shared_dynamic_cast<NLConstraint >(*factor); | 
					
						
							|  |  |  | 		if (constraint != NULL) { | 
					
						
							|  |  |  | 			size_t p = constraint->nrConstraints(); | 
					
						
							|  |  |  | 			// update ordering
 | 
					
						
							|  |  |  | 			string key = constraint->lagrangeKey(); | 
					
						
							|  |  |  | 			full_ordering_ += key; | 
					
						
							|  |  |  | 			// initialize lagrange multipliers
 | 
					
						
							|  |  |  | 			lagrange_config_->insert(key, ones(p)); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2009-11-24 03:57:35 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* **************************************************************** */ | 
					
						
							|  |  |  | template <class G, class C> | 
					
						
							|  |  |  | SQPOptimizer<G,C>::SQPOptimizer(const G& graph, const Ordering& ordering, | 
					
						
							|  |  |  | 		shared_config config, shared_vconfig lagrange) | 
					
						
							| 
									
										
										
										
											2009-11-24 06:10:52 +08:00
										 |  |  | : graph_(&graph), ordering_(&ordering), full_ordering_(ordering), | 
					
						
							| 
									
										
										
										
											2009-11-29 06:49:14 +08:00
										 |  |  |   config_(config), lagrange_config_(lagrange), error_(graph.error(*config)), | 
					
						
							|  |  |  |   constraint_error_(constraintError(graph, *config)) | 
					
						
							| 
									
										
										
										
											2009-11-24 03:57:35 +08:00
										 |  |  | { | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-24 05:25:31 +08:00
										 |  |  | /* **************************************************************** */ | 
					
						
							|  |  |  | template<class G, class C> | 
					
						
							|  |  |  | SQPOptimizer<G, C> SQPOptimizer<G, C>::iterate(Verbosity v) const { | 
					
						
							|  |  |  | 	bool verbose = v == SQPOptimizer<G, C>::FULL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// local typedefs
 | 
					
						
							|  |  |  | 	typedef typename G::const_iterator const_iterator; | 
					
						
							|  |  |  | 	typedef NonlinearConstraint<C> NLConstraint; | 
					
						
							|  |  |  | 	typedef boost::shared_ptr<NLConstraint > shared_c; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// linearize the graph
 | 
					
						
							|  |  |  | 	GaussianFactorGraph fg; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-29 02:35:36 +08:00
										 |  |  | 	// prepare an ordering of lagrange multipliers to remove
 | 
					
						
							| 
									
										
										
										
											2009-12-01 01:36:34 +08:00
										 |  |  | 	Ordering keysToRemove; | 
					
						
							| 
									
										
										
										
											2009-11-29 02:35:36 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-24 05:25:31 +08:00
										 |  |  | 	// iterate over all factors and linearize
 | 
					
						
							|  |  |  | 	for (const_iterator factor = graph_->begin(); factor < graph_->end(); factor++) { | 
					
						
							|  |  |  | 		const shared_c constraint = boost::shared_dynamic_cast<NLConstraint >(*factor); | 
					
						
							|  |  |  | 		if (constraint == NULL) { | 
					
						
							|  |  |  | 			// if a regular factor, linearize using the default linearization
 | 
					
						
							|  |  |  | 			GaussianFactor::shared_ptr f = (*factor)->linearize(*config_); | 
					
						
							|  |  |  | 			if (verbose) f->print("Regular Factor"); | 
					
						
							|  |  |  | 			fg.push_back(f); | 
					
						
							| 
									
										
										
										
											2009-11-29 02:35:36 +08:00
										 |  |  | 		} else if (constraint->active(*config_)) { | 
					
						
							| 
									
										
										
										
											2009-11-24 05:25:31 +08:00
										 |  |  | 			// if a constraint, linearize using the constraint method (2 configs)
 | 
					
						
							|  |  |  | 			GaussianFactor::shared_ptr f, c; | 
					
						
							|  |  |  | 			boost::tie(f,c) = constraint->linearize(*config_, *lagrange_config_); | 
					
						
							|  |  |  | 			if (verbose) f->print("Constrained Factor"); | 
					
						
							|  |  |  | 			if (verbose) c->print("Constraint"); | 
					
						
							|  |  |  | 			fg.push_back(f); | 
					
						
							|  |  |  | 			fg.push_back(c); | 
					
						
							| 
									
										
										
										
											2009-11-29 02:35:36 +08:00
										 |  |  | 		} else { | 
					
						
							| 
									
										
										
										
											2009-11-29 05:44:07 +08:00
										 |  |  | 			if (verbose) constraint->print("Skipping..."); | 
					
						
							| 
									
										
										
										
											2009-12-01 01:36:34 +08:00
										 |  |  | 			keysToRemove += constraint->lagrangeKey(); | 
					
						
							| 
									
										
										
										
											2009-11-24 05:25:31 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if (verbose) fg.print("Before Optimization"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// optimize linear graph to get full delta config
 | 
					
						
							| 
									
										
										
										
											2009-12-01 01:36:34 +08:00
										 |  |  | 	VectorConfig delta = fg.optimize(full_ordering_.subtract(keysToRemove)); | 
					
						
							| 
									
										
										
										
											2009-11-24 05:25:31 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (verbose) delta.print("Delta Config"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// update both state variables
 | 
					
						
							| 
									
										
										
										
											2010-01-08 08:40:17 +08:00
										 |  |  | 	shared_config newConfig(new C(expmap(*config_, delta))); | 
					
						
							|  |  |  | 	shared_vconfig newLambdas(new VectorConfig(expmap(*lagrange_config_, delta))); | 
					
						
							| 
									
										
										
										
											2009-11-24 05:25:31 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// construct a new optimizer
 | 
					
						
							| 
									
										
										
										
											2009-12-01 01:36:34 +08:00
										 |  |  | 	return SQPOptimizer<G, C>(*graph_, full_ordering_, newConfig, newLambdas); | 
					
						
							| 
									
										
										
										
											2009-11-24 05:25:31 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-29 06:49:14 +08:00
										 |  |  | /* **************************************************************** */ | 
					
						
							|  |  |  | template<class G, class C> | 
					
						
							|  |  |  | SQPOptimizer<G, C> SQPOptimizer<G, C>::iterateSolve(double relThresh, double absThresh, | 
					
						
							|  |  |  | 		double constraintThresh, size_t maxIterations, Verbosity v) const { | 
					
						
							|  |  |  | 	bool verbose = v == SQPOptimizer<G, C>::FULL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// do an iteration
 | 
					
						
							|  |  |  | 	SQPOptimizer<G, C> next = iterate(v); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// if converged or out of iterations, return result
 | 
					
						
							|  |  |  | 	if (maxIterations == 1 || | 
					
						
							|  |  |  | 			next.checkConvergence(relThresh, absThresh, constraintThresh, | 
					
						
							|  |  |  | 								  error_, constraint_error_)) | 
					
						
							|  |  |  | 		return next; | 
					
						
							|  |  |  | 	else // otherwise, recurse with a lower maxIterations
 | 
					
						
							|  |  |  | 		return next.iterateSolve(relThresh, absThresh, constraintThresh, | 
					
						
							|  |  |  | 				maxIterations-1, v); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* **************************************************************** */ | 
					
						
							|  |  |  | template<class G, class C> | 
					
						
							|  |  |  | bool SQPOptimizer<G, C>::checkConvergence(double relThresh, double absThresh, | 
					
						
							|  |  |  | 		double constraintThresh, double full_error, double constraint_error) const { | 
					
						
							|  |  |  | 	// if error sufficiently low, then the system has converged
 | 
					
						
							|  |  |  | 	if (error_ < absThresh && constraint_error_ < constraintThresh) | 
					
						
							|  |  |  | 		return true; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// TODO: determine other cases
 | 
					
						
							|  |  |  | 	return false; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-29 02:35:36 +08:00
										 |  |  | /* **************************************************************** */ | 
					
						
							|  |  |  | template<class G, class C> | 
					
						
							|  |  |  | void SQPOptimizer<G, C>::print(const std::string& s) { | 
					
						
							|  |  |  | 	graph_->print("Nonlinear Graph"); | 
					
						
							|  |  |  | 	ordering_->print("Initial Ordering"); | 
					
						
							|  |  |  | 	full_ordering_.print("Ordering including all Lagrange Multipliers"); | 
					
						
							|  |  |  | 	config_->print("Real Config"); | 
					
						
							|  |  |  | 	lagrange_config_->print("Lagrange Multiplier Config"); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-24 03:57:35 +08:00
										 |  |  | } |