152 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			C++
		
	
	
			
		
		
	
	
			152 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			C++
		
	
	
| /*
 | |
|  * SubgraphPreconditioner.h
 | |
|  * Created on: Dec 31, 2009
 | |
|  * @author: Frank Dellaert
 | |
|  */
 | |
| 
 | |
| #ifndef SUBGRAPHPRECONDITIONER_H_
 | |
| #define SUBGRAPHPRECONDITIONER_H_
 | |
| 
 | |
| #include "GaussianFactorGraph.h"
 | |
| #include "GaussianBayesNet.h"
 | |
| #include "Ordering.h"
 | |
| 
 | |
| namespace gtsam {
 | |
| 
 | |
| 	/**
 | |
| 	 * Subgraph conditioner class, as explained in the RSS 2010 submission.
 | |
| 	 * Starting with a graph A*x=b, we split it in two systems A1*x=b1 and A2*x=b2
 | |
| 	 * We solve R1*x=c1, and make the substitution y=R1*x-c1.
 | |
| 	 * To use the class, give the Bayes Net R1*x=c1 and Graph A2*x=b2.
 | |
| 	 * Then solve for yhat using CG, and solve for xhat = system.x(yhat).
 | |
| 	 */
 | |
| 	class SubgraphPreconditioner {
 | |
| 
 | |
| 	public:
 | |
| 		typedef boost::shared_ptr<const GaussianBayesNet> sharedBayesNet;
 | |
| 		typedef boost::shared_ptr<const GaussianFactorGraph> sharedFG;
 | |
| 		typedef boost::shared_ptr<const VectorConfig> sharedConfig;
 | |
| 		typedef boost::shared_ptr<const Errors> sharedErrors;
 | |
| 
 | |
| 	private:
 | |
| 		sharedFG Ab1_, Ab2_;
 | |
| 		sharedBayesNet Rc1_;
 | |
| 		sharedConfig xbar_;
 | |
| 		sharedErrors b2bar_; /** b2 - A2*xbar */
 | |
| 
 | |
| 	public:
 | |
| 
 | |
| 		/**
 | |
| 		 * Constructor
 | |
| 		 * @param Rc1: the Bayes Net R1*x=c1
 | |
| 		 * @param Ab2: the Graph A2*x=b2
 | |
| 		 * @param xbar: the solution to R1*x=c1
 | |
| 		 */
 | |
| 		SubgraphPreconditioner(sharedFG& Ab1, sharedFG& Ab2, sharedBayesNet& Rc1,	sharedConfig& xbar);
 | |
| 
 | |
| 		std::pair<Matrix,Vector> Ab1(const Ordering& ordering) const { return Ab1_->matrix(ordering); }
 | |
| 		std::pair<Matrix,Vector> Ab2(const Ordering& ordering) const { return Ab2_->matrix(ordering); }
 | |
| 		Matrix A1(const Ordering& ordering) const { return Ab1_->sparse(ordering); }
 | |
| 		Matrix A2(const Ordering& ordering) const { return Ab2_->sparse(Ab1_->columnIndices(ordering)); }
 | |
| 		Vector b1() const { return Ab1_->rhsVector(); }
 | |
| 		Vector b2() const { return Ab2_->rhsVector(); }
 | |
| 		VectorConfig assembleConfig(const Vector& v, const Ordering& ordering) const { return Ab1_->assembleConfig(v, ordering); }
 | |
| 
 | |
| 		/* x = xbar + inv(R1)*y */
 | |
| 		VectorConfig x(const VectorConfig& y) const;
 | |
| 
 | |
| 		/* A zero VectorConfig with the structure of xbar */
 | |
| 		VectorConfig zero() const { return VectorConfig::zero(*xbar_);}
 | |
| 
 | |
| 		/* error, given y */
 | |
| 		double error(const VectorConfig& y) const;
 | |
| 
 | |
| 		/** gradient = y + inv(R1')*A2'*(A2*inv(R1)*y-b2bar) */
 | |
| 		VectorConfig gradient(const VectorConfig& y) const;
 | |
| 
 | |
| 		/** Apply operator A */
 | |
| 		Errors operator*(const VectorConfig& y) const;
 | |
| 
 | |
| 		/** Apply operator A in place: needs e allocated already */
 | |
| 		void multiplyInPlace(const VectorConfig& y, Errors& e) const;
 | |
| 
 | |
| 			/** Apply operator A' */
 | |
| 		VectorConfig operator^(const Errors& e) const;
 | |
| 
 | |
| 		/**
 | |
| 		 * Add A'*e to y
 | |
| 		 *  y += alpha*A'*[e1;e2] = [alpha*e1; alpha*inv(R1')*A2'*e2]
 | |
| 		 */
 | |
| 		void transposeMultiplyAdd(double alpha, const Errors& e, VectorConfig& y) const;
 | |
| 
 | |
| 		/**
 | |
| 		 * Add constraint part of the error only, used in both calls above
 | |
| 		 * y += alpha*inv(R1')*A2'*e2
 | |
| 		 * Takes a range indicating e2 !!!!
 | |
| 		 */
 | |
| 		void transposeMultiplyAdd2(double alpha, Errors::const_iterator begin,
 | |
| 				Errors::const_iterator end, VectorConfig& y) const;
 | |
| 
 | |
| 			/** print the object */
 | |
| 		void print(const std::string& s = "SubgraphPreconditioner") const;
 | |
| 	};
 | |
| 
 | |
|   /**
 | |
|    * A nonlinear system solver using subgraph preconditioning conjugate gradient
 | |
|    * Concept NonLinearSolver<G,T,L> implements
 | |
|    *   linearize: G * T -> L
 | |
|    *   solve : L -> VectorConfig
 | |
|    */
 | |
| 	template<class G, class T>
 | |
| 	class SubgraphPCG {
 | |
| 
 | |
| 	private:
 | |
| 		typedef typename T::Key Key;
 | |
| 		typedef typename G::Constraint Constraint;
 | |
| 		typedef typename G::Pose Pose;
 | |
| 
 | |
| 		// TODO not hardcode
 | |
| 		static const size_t maxIterations_=100;
 | |
| 		static const bool verbose_=false;
 | |
| 		static const double epsilon_=1e-4, epsilon_abs_=1e-5;
 | |
| 
 | |
| 		/* the ordering derived from the spanning tree */
 | |
| 		boost::shared_ptr<Ordering> ordering_;
 | |
| 
 | |
| 		/* the solution computed from the first subgraph */
 | |
| 		boost::shared_ptr<T> theta_bar_;
 | |
| 
 | |
| 		G T_, C_;
 | |
| 
 | |
| 	public:
 | |
| 		SubgraphPCG() {}
 | |
| 
 | |
| 		SubgraphPCG(const G& g, const T& theta0);
 | |
| 
 | |
| 		void initialize(const G& g, const T& theta0);
 | |
| 
 | |
| 		boost::shared_ptr<Ordering> ordering() const { return ordering_; }
 | |
| 
 | |
| 		boost::shared_ptr<T> theta_bar() const { return theta_bar_; }
 | |
| 
 | |
| 		/**
 | |
| 		 * linearize the non-linear graph around the current config and build the subgraph preconditioner systme
 | |
| 		 */
 | |
| 		boost::shared_ptr<SubgraphPreconditioner> linearize(const G& g, const T& theta_bar) const;
 | |
| 
 | |
|   	/**
 | |
|   	 * solve for the optimal displacement in the tangent space, and then solve
 | |
|   	 * the resulted linear system
 | |
|   	 */
 | |
|   	VectorConfig optimize(SubgraphPreconditioner& system) const;
 | |
| 	};
 | |
| 
 | |
| 	template<class G, class T> const size_t SubgraphPCG<G,T>::maxIterations_;
 | |
| 	template<class G, class T> const bool SubgraphPCG<G,T>::verbose_;
 | |
| 	template<class G, class T> const double SubgraphPCG<G,T>::epsilon_;
 | |
| 	template<class G, class T> const double	SubgraphPCG<G,T>::epsilon_abs_;
 | |
| 
 | |
| } // nsamespace gtsam
 | |
| 
 | |
| #endif /* SUBGRAPHPRECONDITIONER_H_ */
 |