| 
									
										
										
										
											2014-09-30 18:30:15 +08:00
										 |  |  | /* ----------------------------------------------------------------------------
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |  * GTSAM Copyright 2010, Georgia Tech Research Corporation,  | 
					
						
							|  |  |  |  * Atlanta, Georgia 30332-0415 | 
					
						
							|  |  |  |  * All Rights Reserved | 
					
						
							|  |  |  |  * Authors: Frank Dellaert, et al. (see THANKS for the full author list) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |  * See LICENSE for the license information | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |  * -------------------------------------------------------------------------- */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /**
 | 
					
						
							|  |  |  |  * @file Expression.h | 
					
						
							|  |  |  |  * @date September 18, 2014 | 
					
						
							|  |  |  |  * @author Frank Dellaert | 
					
						
							|  |  |  |  * @author Paul Furgale | 
					
						
							|  |  |  |  * @brief Expressions for Block Automatic Differentiation | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-09-30 18:34:03 +08:00
										 |  |  | #include <gtsam_unstable/nonlinear/Expression.h>
 | 
					
						
							| 
									
										
										
										
											2014-09-30 18:30:15 +08:00
										 |  |  | #include <gtsam/nonlinear/NonlinearFactor.h>
 | 
					
						
							| 
									
										
										
										
											2014-10-02 17:01:39 +08:00
										 |  |  | #include <gtsam/base/Testable.h>
 | 
					
						
							| 
									
										
										
										
											2014-09-30 18:30:15 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | namespace gtsam { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /**
 | 
					
						
							| 
									
										
										
										
											2014-10-09 19:00:56 +08:00
										 |  |  |  * Factor that supports arbitrary expressions via AD | 
					
						
							| 
									
										
										
										
											2014-09-30 18:30:15 +08:00
										 |  |  |  */ | 
					
						
							|  |  |  | template<class T> | 
					
						
							| 
									
										
										
										
											2014-10-09 19:00:56 +08:00
										 |  |  | class ExpressionFactor: public NoiseModelFactor { | 
					
						
							| 
									
										
										
										
											2014-09-30 18:30:15 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   const T measurement_; | 
					
						
							|  |  |  |   const Expression<T> expression_; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | public: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /// Constructor
 | 
					
						
							| 
									
										
										
										
											2014-10-09 19:00:56 +08:00
										 |  |  |   ExpressionFactor(const SharedNoiseModel& noiseModel, //
 | 
					
						
							| 
									
										
										
										
											2014-10-02 17:01:39 +08:00
										 |  |  |       const T& measurement, const Expression<T>& expression) : | 
					
						
							|  |  |  |       NoiseModelFactor(noiseModel, expression.keys()), //
 | 
					
						
							| 
									
										
										
										
											2014-09-30 18:30:15 +08:00
										 |  |  |       measurement_(measurement), expression_(expression) { | 
					
						
							| 
									
										
										
										
											2014-10-14 17:13:49 +08:00
										 |  |  |     if (!noiseModel) | 
					
						
							|  |  |  |       throw std::invalid_argument("ExpressionFactor: no NoiseModel."); | 
					
						
							|  |  |  |     if (noiseModel->dim() != T::dimension) | 
					
						
							|  |  |  |       throw std::invalid_argument( | 
					
						
							|  |  |  |           "ExpressionFactor was created with a NoiseModel of incorrect dimension."); | 
					
						
							| 
									
										
										
										
											2014-09-30 18:30:15 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-02 17:01:39 +08:00
										 |  |  |   /**
 | 
					
						
							|  |  |  |    * Error function *without* the NoiseModel, \f$ z-h(x) \f$. | 
					
						
							|  |  |  |    * We override this method to provide | 
					
						
							|  |  |  |    * both the function evaluation and its derivative(s) in H. | 
					
						
							|  |  |  |    */ | 
					
						
							|  |  |  |   virtual Vector unwhitenedError(const Values& x, | 
					
						
							|  |  |  |       boost::optional<std::vector<Matrix>&> H = boost::none) const { | 
					
						
							|  |  |  |     if (H) { | 
					
						
							| 
									
										
										
										
											2014-10-14 21:43:41 +08:00
										 |  |  |       // H should be pre-allocated
 | 
					
						
							| 
									
										
										
										
											2014-10-02 19:30:16 +08:00
										 |  |  |       assert(H->size()==size()); | 
					
						
							| 
									
										
										
										
											2014-10-14 21:43:41 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |       // Get dimensions of Jacobian matrices
 | 
					
						
							| 
									
										
										
										
											2014-10-14 23:16:31 +08:00
										 |  |  |       std::vector<size_t> dims = expression_.dimensions(); | 
					
						
							| 
									
										
										
										
											2014-10-14 21:43:41 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |       // Create and zero out blocks to be passed to expression_
 | 
					
						
							| 
									
										
										
										
											2014-10-14 23:16:31 +08:00
										 |  |  |       JacobianMap blocks; | 
					
						
							|  |  |  |       for(DenseIndex i=0;i<size();i++) { | 
					
						
							|  |  |  |         Matrix& Hi = H->at(i); | 
					
						
							|  |  |  |         Hi.resize(T::dimension, dims[i]); | 
					
						
							| 
									
										
										
										
											2014-10-14 21:43:41 +08:00
										 |  |  |         Hi.setZero(); // zero out
 | 
					
						
							| 
									
										
										
										
											2014-10-14 23:16:31 +08:00
										 |  |  |         Eigen::Block<Matrix> block = Hi.block(0,0,T::dimension, dims[i]); | 
					
						
							|  |  |  |         blocks.insert(std::make_pair(keys_[i], block)); | 
					
						
							| 
									
										
										
										
											2014-10-14 21:43:41 +08:00
										 |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       T value = expression_.value(x, blocks); | 
					
						
							| 
									
										
										
										
											2014-10-13 02:16:08 +08:00
										 |  |  |       return measurement_.localCoordinates(value); | 
					
						
							| 
									
										
										
										
											2014-10-02 17:01:39 +08:00
										 |  |  |     } else { | 
					
						
							|  |  |  |       const T& value = expression_.value(x); | 
					
						
							|  |  |  |       return measurement_.localCoordinates(value); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2014-09-30 18:30:15 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-14 23:16:31 +08:00
										 |  |  |   // Internal function to allocate a VerticalBlockMatrix and
 | 
					
						
							|  |  |  |   // create Eigen::Block<Matrix> views into it
 | 
					
						
							|  |  |  |   VerticalBlockMatrix prepareBlocks(JacobianMap& blocks) const { | 
					
						
							| 
									
										
										
										
											2014-10-11 23:05:53 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-14 21:43:41 +08:00
										 |  |  |     // Get dimensions of Jacobian matrices
 | 
					
						
							| 
									
										
										
										
											2014-10-14 23:16:31 +08:00
										 |  |  |     std::vector<size_t> dims = expression_.dimensions(); | 
					
						
							| 
									
										
										
										
											2014-10-12 17:05:43 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-14 14:59:01 +08:00
										 |  |  |     // Construct block matrix, is of right size but un-initialized
 | 
					
						
							| 
									
										
										
										
											2014-10-14 17:13:49 +08:00
										 |  |  |     VerticalBlockMatrix Ab(dims, T::dimension, true); | 
					
						
							| 
									
										
										
										
											2014-10-14 21:43:41 +08:00
										 |  |  |     Ab.matrix().setZero(); // zero out
 | 
					
						
							| 
									
										
										
										
											2014-10-12 17:05:43 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-14 21:43:41 +08:00
										 |  |  |     // Create blocks to be passed to expression_
 | 
					
						
							| 
									
										
										
										
											2014-10-14 23:16:31 +08:00
										 |  |  |     for(DenseIndex i=0;i<size();i++) | 
					
						
							|  |  |  |       blocks.insert(std::make_pair(keys_[i], Ab(i))); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return Ab; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   virtual boost::shared_ptr<GaussianFactor> linearize(const Values& x) const { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Construct VerticalBlockMatrix and views into it
 | 
					
						
							|  |  |  |     JacobianMap blocks; | 
					
						
							|  |  |  |     VerticalBlockMatrix Ab = prepareBlocks(blocks); | 
					
						
							| 
									
										
										
										
											2014-10-12 17:05:43 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-14 17:13:49 +08:00
										 |  |  |     // Evaluate error to get Jacobians and RHS vector b
 | 
					
						
							| 
									
										
										
										
											2014-10-14 21:43:41 +08:00
										 |  |  |     T value = expression_.value(x, blocks); | 
					
						
							| 
									
										
										
										
											2014-10-14 23:16:31 +08:00
										 |  |  |     Ab(size()).col(0) = -measurement_.localCoordinates(value); | 
					
						
							| 
									
										
										
										
											2014-10-14 17:13:49 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // Whiten the corresponding system now
 | 
					
						
							| 
									
										
										
										
											2014-10-14 23:16:31 +08:00
										 |  |  |     // TODO ! this->noiseModel_->WhitenSystem(Ab);
 | 
					
						
							| 
									
										
										
										
											2014-10-11 23:05:53 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // TODO pass unwhitened + noise model to Gaussian factor
 | 
					
						
							|  |  |  |     // For now, only linearized constrained factors have noise model at linear level!!!
 | 
					
						
							|  |  |  |     noiseModel::Constrained::shared_ptr constrained = //
 | 
					
						
							|  |  |  |         boost::dynamic_pointer_cast<noiseModel::Constrained>(this->noiseModel_); | 
					
						
							|  |  |  |     if (constrained) { | 
					
						
							| 
									
										
										
										
											2014-10-14 23:16:31 +08:00
										 |  |  |       return boost::make_shared<JacobianFactor>(this->keys(), Ab, | 
					
						
							| 
									
										
										
										
											2014-10-14 17:13:49 +08:00
										 |  |  |           constrained->unit()); | 
					
						
							| 
									
										
										
										
											2014-10-11 23:05:53 +08:00
										 |  |  |     } else | 
					
						
							| 
									
										
										
										
											2014-10-14 23:16:31 +08:00
										 |  |  |       return boost::make_shared<JacobianFactor>(this->keys(), Ab); | 
					
						
							| 
									
										
										
										
											2014-10-11 23:05:53 +08:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2014-09-30 18:30:15 +08:00
										 |  |  | }; | 
					
						
							| 
									
										
										
										
											2014-10-09 19:00:56 +08:00
										 |  |  | // ExpressionFactor
 | 
					
						
							| 
									
										
										
										
											2014-09-30 18:30:15 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 |