Make JacobianMap a wrapper around a VerticalBlockMatrix, which avoids us having to make a vector of references into it
							parent
							
								
									8e7864dc96
								
							
						
					
					
						commit
						7b539fbb5c
					
				|  | @ -23,6 +23,7 @@ | |||
| #include <gtsam/base/Matrix.h> | ||||
| #include <gtsam/base/Testable.h> | ||||
| #include <gtsam/base/Manifold.h> | ||||
| #include <gtsam/base/VerticalBlockMatrix.h> | ||||
| 
 | ||||
| #include <boost/foreach.hpp> | ||||
| #include <boost/tuple/tuple.hpp> | ||||
|  | @ -49,8 +50,25 @@ namespace gtsam { | |||
| template<typename T> | ||||
| class Expression; | ||||
| 
 | ||||
| typedef std::pair<Key, Eigen::Block<Matrix> > JacobianPair; | ||||
| typedef std::vector<JacobianPair> JacobianMap; | ||||
| /**
 | ||||
|  * Expressions are designed to write their derivatives into an already allocated | ||||
|  * Jacobian of the correct size, of type VerticalBlockMatrix. | ||||
|  * The JacobianMap provides a mapping from keys to the underlying blocks. | ||||
|  */ | ||||
| class JacobianMap { | ||||
|   const FastVector<Key>& keys_; | ||||
|   VerticalBlockMatrix& Ab_; | ||||
| public: | ||||
|   JacobianMap(const FastVector<Key>& keys, VerticalBlockMatrix& Ab) : | ||||
|       keys_(keys), Ab_(Ab) { | ||||
|   } | ||||
|   /** Access a single block in the underlying matrix with read/write access */ | ||||
|   VerticalBlockMatrix::Block operator()(Key key) { | ||||
|     FastVector<Key>::const_iterator it = std::find(keys_.begin(),keys_.end(),key); | ||||
|     DenseIndex block = it - keys_.begin(); | ||||
|     return Ab_(block); | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| //-----------------------------------------------------------------------------
 | ||||
| /**
 | ||||
|  | @ -80,20 +98,14 @@ struct CallRecord { | |||
| template<int ROWS, int COLS> | ||||
| void handleLeafCase(const Eigen::Matrix<double, ROWS, COLS>& dTdA, | ||||
|     JacobianMap& jacobians, Key key) { | ||||
|   JacobianMap::iterator it = std::find_if(jacobians.begin(), jacobians.end(), | ||||
|       boost::bind(&JacobianPair::first, _1) == key); | ||||
|   assert(it!=jacobians.end()); | ||||
|   it->second.block < ROWS, COLS > (0, 0) += dTdA; // block makes HUGE difference
 | ||||
|   jacobians(key).block < ROWS, COLS > (0, 0) += dTdA; // block makes HUGE difference
 | ||||
| } | ||||
| /// Handle Leaf Case for Dynamic Matrix type (slower)
 | ||||
| template<> | ||||
| void handleLeafCase( | ||||
|     const Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic>& dTdA, | ||||
|     JacobianMap& jacobians, Key key) { | ||||
|   JacobianMap::iterator it = std::find_if(jacobians.begin(), jacobians.end(), | ||||
|       boost::bind(&JacobianPair::first, _1) == key); | ||||
|   assert(it!=jacobians.end()); | ||||
|   it->second += dTdA; | ||||
|   jacobians(key) += dTdA; | ||||
| } | ||||
| 
 | ||||
| //-----------------------------------------------------------------------------
 | ||||
|  |  | |||
|  | @ -123,7 +123,7 @@ public: | |||
|   } | ||||
| 
 | ||||
|   /// Return value and derivatives, reverse AD version
 | ||||
|   T reverse(const Values& values, JacobianMap& jacobians) const { | ||||
|   T value(const Values& values, JacobianMap& jacobians) const { | ||||
|     // The following piece of code is absolutely crucial for performance.
 | ||||
|     // We allocate a block of memory on the stack, which can be done at runtime
 | ||||
|     // with modern C++ compilers. The traceExecution then fills this memory
 | ||||
|  | @ -142,11 +142,6 @@ public: | |||
|     return root_->value(values); | ||||
|   } | ||||
| 
 | ||||
|   /// Return value and derivatives
 | ||||
|   T value(const Values& values, JacobianMap& jacobians) const { | ||||
|     return reverse(values, jacobians); | ||||
|   } | ||||
| 
 | ||||
|   const boost::shared_ptr<ExpressionNode<T> >& root() const { | ||||
|     return root_; | ||||
|   } | ||||
|  |  | |||
|  | @ -81,27 +81,27 @@ public: | |||
|    */ | ||||
|   virtual Vector unwhitenedError(const Values& x, | ||||
|       boost::optional<std::vector<Matrix>&> H = boost::none) const { | ||||
|     if (H) { | ||||
|       // H should be pre-allocated
 | ||||
|       assert(H->size()==size()); | ||||
| 
 | ||||
|       // Create and zero out blocks to be passed to expression_
 | ||||
|       JacobianMap blocks; | ||||
|       blocks.reserve(size()); | ||||
|       for (DenseIndex i = 0; i < size(); i++) { | ||||
|         Matrix& Hi = H->at(i); | ||||
|         Hi.resize(Dim, dimensions_[i]); | ||||
|         Hi.setZero(); // zero out
 | ||||
|         Eigen::Block<Matrix> block = Hi.block(0, 0, Dim, dimensions_[i]); | ||||
|         blocks.push_back(std::make_pair(keys_[i], block)); | ||||
|       } | ||||
| 
 | ||||
|       T value = expression_.value(x, blocks); | ||||
|       return measurement_.localCoordinates(value); | ||||
|     } else { | ||||
| //    if (H) {
 | ||||
| //      // H should be pre-allocated
 | ||||
| //      assert(H->size()==size());
 | ||||
| //
 | ||||
| //      // Create and zero out blocks to be passed to expression_
 | ||||
| //      JacobianMap blocks;
 | ||||
| //      blocks.reserve(size());
 | ||||
| //      for (DenseIndex i = 0; i < size(); i++) {
 | ||||
| //        Matrix& Hi = H->at(i);
 | ||||
| //        Hi.resize(Dim, dimensions_[i]);
 | ||||
| //        Hi.setZero(); // zero out
 | ||||
| //        Eigen::Block<Matrix> block = Hi.block(0, 0, Dim, dimensions_[i]);
 | ||||
| //        blocks.push_back(std::make_pair(keys_[i], block));
 | ||||
| //      }
 | ||||
| //
 | ||||
| //      T value = expression_.value(x, blocks);
 | ||||
| //      return measurement_.localCoordinates(value);
 | ||||
| //    } else {
 | ||||
|       const T& value = expression_.value(x); | ||||
|       return measurement_.localCoordinates(value); | ||||
|     } | ||||
| //    }
 | ||||
|   } | ||||
| 
 | ||||
|   virtual boost::shared_ptr<GaussianFactor> linearize(const Values& x) const { | ||||
|  | @ -120,14 +120,11 @@ public: | |||
|     // Construct block matrix, is of right size but un-initialized
 | ||||
|     VerticalBlockMatrix Ab(dimensions_, matrix, true); | ||||
| 
 | ||||
|     // Create blocks into Ab_ to be passed to expression_
 | ||||
|     JacobianMap blocks; | ||||
|     blocks.reserve(size()); | ||||
|     for (DenseIndex i = 0; i < size(); i++) | ||||
|       blocks.push_back(std::make_pair(keys_[i], Ab(i))); | ||||
|     // Wrap keys and VerticalBlockMatrix into structure passed to expression_
 | ||||
|     JacobianMap map(keys_,Ab); | ||||
| 
 | ||||
|     // Evaluate error to get Jacobians and RHS vector b
 | ||||
|     T value = expression_.value(x, blocks); // <<< Reverse AD happens here !
 | ||||
|     T value = expression_.value(x, map); // <<< Reverse AD happens here !
 | ||||
|     Ab(size()).col(0) = -measurement_.localCoordinates(value); | ||||
| 
 | ||||
|     // Whiten the corresponding system now
 | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue