| 
									
										
										
										
											2009-12-29 00:26:16 +08:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * iterative-inl.h | 
					
						
							|  |  |  |  * @brief Iterative methods, template implementation | 
					
						
							|  |  |  |  * @author Frank Dellaert | 
					
						
							|  |  |  |  * Created on: Dec 28, 2009 | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-01-11 06:15:34 +08:00
										 |  |  | #pragma once
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-12-29 00:26:16 +08:00
										 |  |  | #include "GaussianFactorGraph.h"
 | 
					
						
							|  |  |  | #include "iterative.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | using namespace std; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | namespace gtsam { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* ************************************************************************* */ | 
					
						
							| 
									
										
										
										
											2010-02-14 13:52:20 +08:00
										 |  |  | 	// state for CG method
 | 
					
						
							| 
									
										
										
										
											2009-12-29 00:26:16 +08:00
										 |  |  | 	template<class S, class V, class E> | 
					
						
							| 
									
										
										
										
											2010-02-14 13:52:20 +08:00
										 |  |  | 	struct CGState { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		bool steepest, verbose; | 
					
						
							|  |  |  | 		double gamma, threshold; | 
					
						
							|  |  |  | 		size_t k, maxIterations, reset; | 
					
						
							|  |  |  | 		V g, d; | 
					
						
							|  |  |  | 		E Ad; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-02-21 07:43:41 +08:00
										 |  |  | 		/* ************************************************************************* */ | 
					
						
							|  |  |  | 		// Constructor
 | 
					
						
							| 
									
										
										
										
											2010-02-14 13:52:20 +08:00
										 |  |  | 		CGState(const S& Ab, const V& x, bool verb, double epsilon, | 
					
						
							|  |  |  | 				double epsilon_abs, size_t maxIt, bool steep) { | 
					
						
							|  |  |  | 			k = 0; | 
					
						
							|  |  |  | 			verbose = verb; | 
					
						
							|  |  |  | 			steepest = steep; | 
					
						
							| 
									
										
										
										
											2010-02-14 15:14:42 +08:00
										 |  |  | 			maxIterations = (maxIt > 0) ? maxIt : dim(x) * (steepest ? 10 : 1); | 
					
						
							| 
									
										
										
										
											2010-02-14 13:52:20 +08:00
										 |  |  | 			reset = (size_t) (sqrt(dim(x)) + 0.5); // when to reset
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// Start with g0 = A'*(A*x0-b), d0 = - g0
 | 
					
						
							|  |  |  | 			// i.e., first step is in direction of negative gradient
 | 
					
						
							|  |  |  | 			g = Ab.gradient(x); | 
					
						
							|  |  |  | 			d = g; // instead of negating gradient, alpha will be negated
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// init gamma and calculate threshold
 | 
					
						
							|  |  |  | 			gamma = dot(g, g); | 
					
						
							|  |  |  | 			threshold = ::max(epsilon_abs, epsilon * epsilon * gamma); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// Allocate and calculate A*d for first iteration
 | 
					
						
							|  |  |  | 			if (gamma > epsilon) Ad = Ab * d; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2009-12-29 00:26:16 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-02-21 07:43:41 +08:00
										 |  |  | 		/* ************************************************************************* */ | 
					
						
							|  |  |  | 		// print
 | 
					
						
							| 
									
										
										
										
											2010-02-14 15:14:42 +08:00
										 |  |  | 		void print(const V& x) { | 
					
						
							| 
									
										
										
										
											2010-02-14 13:52:20 +08:00
										 |  |  | 			cout << "iteration = " << k << endl; | 
					
						
							| 
									
										
										
										
											2010-02-14 15:14:42 +08:00
										 |  |  | 			gtsam::print(x,"x"); | 
					
						
							|  |  |  | 			gtsam::print(g, "g"); | 
					
						
							| 
									
										
										
										
											2010-02-14 13:52:20 +08:00
										 |  |  | 			cout << "dotg = " << gamma << endl; | 
					
						
							| 
									
										
										
										
											2010-02-14 15:14:42 +08:00
										 |  |  | 			gtsam::print(d, "d"); | 
					
						
							|  |  |  | 			gtsam::print(Ad, "Ad"); | 
					
						
							| 
									
										
										
										
											2010-02-14 13:52:20 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2009-12-29 00:26:16 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-02-21 07:43:41 +08:00
										 |  |  | 		/* ************************************************************************* */ | 
					
						
							|  |  |  | 		// step the solution
 | 
					
						
							| 
									
										
										
										
											2010-02-14 13:52:20 +08:00
										 |  |  | 		double takeOptimalStep(V& x) { | 
					
						
							| 
									
										
										
										
											2010-02-14 15:14:42 +08:00
										 |  |  | 			// TODO: can we use gamma instead of dot(d,g) ????? Answer not trivial
 | 
					
						
							| 
									
										
										
										
											2010-02-14 13:52:20 +08:00
										 |  |  | 			double alpha = -dot(d, g) / dot(Ad, Ad); // calculate optimal step-size
 | 
					
						
							|  |  |  | 			axpy(alpha, d, x); // // do step in new search direction, x += alpha*d
 | 
					
						
							|  |  |  | 			return alpha; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2010-01-31 01:31:05 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-02-21 07:43:41 +08:00
										 |  |  | 		/* ************************************************************************* */ | 
					
						
							|  |  |  | 		// take a step, return true if converged
 | 
					
						
							| 
									
										
										
										
											2010-02-14 13:52:20 +08:00
										 |  |  | 		bool step(const S& Ab, V& x) { | 
					
						
							|  |  |  | 			k += 1; // increase iteration number
 | 
					
						
							| 
									
										
										
										
											2009-12-29 00:26:16 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-02-14 13:52:20 +08:00
										 |  |  | 			double alpha = takeOptimalStep(x); | 
					
						
							| 
									
										
										
										
											2009-12-29 00:26:16 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-02-14 15:14:42 +08:00
										 |  |  | 			if (k >= maxIterations) return true; //---------------------------------->
 | 
					
						
							| 
									
										
										
										
											2009-12-29 00:26:16 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-12-31 18:27:39 +08:00
										 |  |  | 			// update gradient (or re-calculate at reset time)
 | 
					
						
							| 
									
										
										
										
											2010-02-14 13:52:20 +08:00
										 |  |  | 			if (k % reset == 0) | 
					
						
							| 
									
										
										
										
											2010-01-30 10:04:37 +08:00
										 |  |  | 				g = Ab.gradient(x); | 
					
						
							|  |  |  | 			else | 
					
						
							| 
									
										
										
										
											2010-01-31 07:59:29 +08:00
										 |  |  | 				// axpy(alpha, Ab ^ Ad, g);  // g += alpha*(Ab^Ad)
 | 
					
						
							|  |  |  | 				Ab.transposeMultiplyAdd(alpha, Ad, g); | 
					
						
							| 
									
										
										
										
											2009-12-29 00:26:16 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			// check for convergence
 | 
					
						
							| 
									
										
										
										
											2010-02-14 13:52:20 +08:00
										 |  |  | 			double new_gamma = dot(g, g); | 
					
						
							| 
									
										
										
										
											2010-02-14 15:14:42 +08:00
										 |  |  | 			if (verbose) cout << "iteration " << k << ": alpha = " << alpha | 
					
						
							|  |  |  | 					<< ", dotg = " << new_gamma << endl; | 
					
						
							|  |  |  | 			if (new_gamma < threshold) return true; //---------------------------------->
 | 
					
						
							| 
									
										
										
										
											2009-12-29 00:26:16 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			// calculate new search direction
 | 
					
						
							|  |  |  | 			if (steepest) | 
					
						
							| 
									
										
										
										
											2010-01-30 10:04:37 +08:00
										 |  |  | 				d = g; | 
					
						
							| 
									
										
										
										
											2009-12-29 00:26:16 +08:00
										 |  |  | 			else { | 
					
						
							| 
									
										
										
										
											2010-02-14 13:52:20 +08:00
										 |  |  | 				double beta = new_gamma / gamma; | 
					
						
							| 
									
										
										
										
											2010-01-30 12:01:49 +08:00
										 |  |  | 				// d = g + d*beta;
 | 
					
						
							| 
									
										
										
										
											2010-02-14 13:52:20 +08:00
										 |  |  | 				scal(beta, d); | 
					
						
							| 
									
										
										
										
											2010-01-30 12:01:49 +08:00
										 |  |  | 				axpy(1.0, g, d); | 
					
						
							| 
									
										
										
										
											2009-12-29 00:26:16 +08:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2010-02-14 15:14:42 +08:00
										 |  |  | 			gamma = new_gamma; | 
					
						
							| 
									
										
										
										
											2010-01-31 01:31:05 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			// In-place recalculation Ad <- A*d to avoid re-allocating Ad
 | 
					
						
							| 
									
										
										
										
											2010-02-14 13:52:20 +08:00
										 |  |  | 			Ab.multiplyInPlace(d, Ad); | 
					
						
							|  |  |  | 			return false; | 
					
						
							| 
									
										
										
										
											2009-12-29 00:26:16 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2010-02-14 13:52:20 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-02-21 07:43:41 +08:00
										 |  |  | 	}; // CGState Class
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* ************************************************************************* */ | 
					
						
							|  |  |  | 	// conjugate gradient method.
 | 
					
						
							|  |  |  | 	// S: linear system, V: step vector, E: errors
 | 
					
						
							| 
									
										
										
										
											2010-02-14 13:52:20 +08:00
										 |  |  | 	template<class S, class V, class E> | 
					
						
							|  |  |  | 	V conjugateGradients(const S& Ab, V x, bool verbose, double epsilon, | 
					
						
							|  |  |  | 			double epsilon_abs, size_t maxIterations, bool steepest = false) { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-03-07 08:10:02 +08:00
										 |  |  | 		CGState<S, V, E> state(Ab, x, verbose, epsilon, epsilon_abs, maxIterations,steepest); | 
					
						
							| 
									
										
										
										
											2010-02-14 13:52:20 +08:00
										 |  |  | 		if (verbose) cout << "CG: epsilon = " << epsilon << ", maxIterations = " | 
					
						
							| 
									
										
										
										
											2010-02-14 15:14:42 +08:00
										 |  |  | 				<< state.maxIterations << ", ||g0||^2 = " << state.gamma | 
					
						
							| 
									
										
										
										
											2010-02-14 13:52:20 +08:00
										 |  |  | 				<< ", threshold = " << state.threshold << endl; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-03-07 08:10:02 +08:00
										 |  |  | 		if (state.gamma < state.threshold) { | 
					
						
							|  |  |  | 			if (verbose) cout << "||g0||^2 < threshold, exiting immediately !" << endl; | 
					
						
							|  |  |  | 			return x; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-02-14 13:52:20 +08:00
										 |  |  | 		// loop maxIterations times
 | 
					
						
							|  |  |  | 		while (!state.step(Ab, x)) | 
					
						
							|  |  |  | 			; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-12-29 00:26:16 +08:00
										 |  |  | 		return x; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* ************************************************************************* */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | } // namespace gtsam
 |