| 
									
										
										
										
											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-11-22 21:55:32 +08:00
										 |  |  | #pragma once
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-27 00:26:04 +08:00
										 |  |  | #include <gtsam/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-10-15 06:28:53 +08:00
										 |  |  | #include <numeric>
 | 
					
						
							| 
									
										
										
										
											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
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-16 17:15:47 +08:00
										 |  |  |   T measurement_; ///< the measurement to be compared with the expression
 | 
					
						
							|  |  |  |   Expression<T> expression_; ///< the expression that is AD enabled
 | 
					
						
							| 
									
										
										
										
											2014-11-25 18:29:50 +08:00
										 |  |  |   FastVector<int> dims_; ///< dimensions of the Jacobian matrices
 | 
					
						
							| 
									
										
										
										
											2014-10-16 17:15:47 +08:00
										 |  |  |   size_t augmentedCols_; ///< total number of columns + 1 (for RHS)
 | 
					
						
							| 
									
										
										
										
											2014-09-30 18:30:15 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-21 07:26:17 +08:00
										 |  |  |   static const int Dim = traits::dimension<T>::value; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-09-30 18:30:15 +08:00
										 |  |  | 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) : | 
					
						
							| 
									
										
										
										
											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."); | 
					
						
							| 
									
										
										
										
											2014-10-21 07:26:17 +08:00
										 |  |  |     if (noiseModel->dim() != Dim) | 
					
						
							| 
									
										
										
										
											2014-10-14 17:13:49 +08:00
										 |  |  |       throw std::invalid_argument( | 
					
						
							|  |  |  |           "ExpressionFactor was created with a NoiseModel of incorrect dimension."); | 
					
						
							| 
									
										
										
										
											2014-10-16 18:01:20 +08:00
										 |  |  |     noiseModel_ = noiseModel; | 
					
						
							| 
									
										
										
										
											2014-10-16 17:15:47 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-25 17:53:26 +08:00
										 |  |  |     // Get keys and dimensions for Jacobian matrices
 | 
					
						
							| 
									
										
										
										
											2014-10-16 17:15:47 +08:00
										 |  |  |     // An Expression is assumed unmutable, so we do this now
 | 
					
						
							| 
									
										
										
										
											2014-11-25 18:29:50 +08:00
										 |  |  |     boost::tie(keys_, dims_) = expression_.keysAndDims(); | 
					
						
							| 
									
										
										
										
											2014-10-16 17:15:47 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // Add sizes to know how much memory to allocate on stack in linearize
 | 
					
						
							| 
									
										
										
										
											2014-11-25 18:29:50 +08:00
										 |  |  |     augmentedCols_ = std::accumulate(dims_.begin(), dims_.end(), 1); | 
					
						
							| 
									
										
										
										
											2014-10-16 17:15:47 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | #ifdef DEBUG_ExpressionFactor
 | 
					
						
							| 
									
										
										
										
											2014-11-25 18:29:50 +08:00
										 |  |  |     BOOST_FOREACH(size_t d, dims_) | 
					
						
							| 
									
										
										
										
											2014-10-16 17:15:47 +08:00
										 |  |  |     std::cout << d << " "; | 
					
						
							| 
									
										
										
										
											2014-10-21 07:26:17 +08:00
										 |  |  |     std::cout << " -> " << Dim << "x" << augmentedCols_ << std::endl; | 
					
						
							| 
									
										
										
										
											2014-10-16 17:15:47 +08:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2014-09-30 18:30:15 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-02 17:01:39 +08:00
										 |  |  |   /**
 | 
					
						
							| 
									
										
										
										
											2014-11-01 18:50:28 +08:00
										 |  |  |    * Error function *without* the NoiseModel, \f$ h(x)-z \f$. | 
					
						
							| 
									
										
										
										
											2014-10-02 17:01:39 +08:00
										 |  |  |    * 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 { | 
					
						
							| 
									
										
										
										
											2014-11-22 21:10:25 +08:00
										 |  |  |     DefaultChart<T> chart; | 
					
						
							| 
									
										
										
										
											2014-10-02 17:01:39 +08:00
										 |  |  |     if (H) { | 
					
						
							| 
									
										
										
										
											2014-11-25 23:13:30 +08:00
										 |  |  |       const T value = expression_.value(x, keys_, dims_, *H); | 
					
						
							| 
									
										
										
										
											2014-11-22 21:10:25 +08:00
										 |  |  |       return chart.local(measurement_, value); | 
					
						
							| 
									
										
										
										
											2014-10-02 17:01:39 +08:00
										 |  |  |     } else { | 
					
						
							| 
									
										
										
										
											2014-11-25 18:29:50 +08:00
										 |  |  |       const T value = expression_.value(x); | 
					
						
							| 
									
										
										
										
											2014-11-22 21:10:25 +08:00
										 |  |  |       return chart.local(measurement_, value); | 
					
						
							| 
									
										
										
										
											2014-10-02 17:01:39 +08:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2014-09-30 18:30:15 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-15 06:28:53 +08:00
										 |  |  |   virtual boost::shared_ptr<GaussianFactor> linearize(const Values& x) const { | 
					
						
							| 
									
										
										
										
											2014-11-02 20:53:22 +08:00
										 |  |  |     // Only linearize if the factor is active
 | 
					
						
							| 
									
										
										
										
											2014-11-02 21:37:52 +08:00
										 |  |  |     if (!active(x)) | 
					
						
							| 
									
										
										
										
											2014-11-02 20:53:22 +08:00
										 |  |  |       return boost::shared_ptr<JacobianFactor>(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-01 22:12:06 +08:00
										 |  |  |     // Create a writeable JacobianFactor in advance
 | 
					
						
							| 
									
										
										
										
											2014-11-02 20:45:54 +08:00
										 |  |  |     // In case noise model is constrained, we need to provide a noise model
 | 
					
						
							| 
									
										
										
										
											2014-11-26 19:33:17 +08:00
										 |  |  |     bool constrained = noiseModel_->isConstrained(); | 
					
						
							| 
									
										
										
										
											2014-11-02 18:40:48 +08:00
										 |  |  |     boost::shared_ptr<JacobianFactor> factor( | 
					
						
							| 
									
										
										
										
											2014-11-25 18:29:50 +08:00
										 |  |  |         constrained ? new JacobianFactor(keys_, dims_, Dim, | 
					
						
							| 
									
										
										
										
											2014-11-02 20:45:54 +08:00
										 |  |  |             boost::static_pointer_cast<noiseModel::Constrained>(noiseModel_)->unit()) : | 
					
						
							| 
									
										
										
										
											2014-11-25 18:29:50 +08:00
										 |  |  |             new JacobianFactor(keys_, dims_, Dim)); | 
					
						
							| 
									
										
										
										
											2014-10-12 17:05:43 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-01 18:35:49 +08:00
										 |  |  |     // Wrap keys and VerticalBlockMatrix into structure passed to expression_
 | 
					
						
							| 
									
										
										
										
											2014-11-02 19:01:52 +08:00
										 |  |  |     VerticalBlockMatrix& Ab = factor->matrixObject(); | 
					
						
							| 
									
										
										
										
											2014-11-25 17:53:26 +08:00
										 |  |  |     JacobianMap jacobianMap(keys_, Ab); | 
					
						
							| 
									
										
										
										
											2014-11-02 19:01:52 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // Zero out Jacobian so we can simply add to it
 | 
					
						
							|  |  |  |     Ab.matrix().setZero(); | 
					
						
							| 
									
										
										
										
											2014-10-19 17:19:09 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-25 18:29:50 +08:00
										 |  |  |     // Get value and Jacobians, writing directly into JacobianFactor
 | 
					
						
							| 
									
										
										
										
											2014-11-25 17:53:26 +08:00
										 |  |  |     T value = expression_.value(x, jacobianMap); // <<< Reverse AD happens here !
 | 
					
						
							| 
									
										
										
										
											2014-11-25 18:29:50 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // Evaluate error and set RHS vector b
 | 
					
						
							|  |  |  |     DefaultChart<T> chart; | 
					
						
							| 
									
										
										
										
											2014-11-22 21:10:25 +08:00
										 |  |  |     Ab(size()).col(0) = -chart.local(measurement_, value); | 
					
						
							| 
									
										
										
										
											2014-10-14 17:13:49 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-02 21:42:59 +08:00
										 |  |  |     // Whiten the corresponding system, Ab already contains RHS
 | 
					
						
							|  |  |  |     Vector dummy(Dim); | 
					
						
							| 
									
										
										
										
											2014-11-25 18:29:50 +08:00
										 |  |  |     noiseModel_->WhitenSystem(Ab.matrix(), dummy); | 
					
						
							| 
									
										
										
										
											2014-10-11 23:05:53 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-01 22:12:06 +08:00
										 |  |  |     return factor; | 
					
						
							| 
									
										
										
										
											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
										 |  |  | 
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 |