Moved functors to Matrix.h, without Expression sugar
							parent
							
								
									01ed8810a0
								
							
						
					
					
						commit
						063e0a47ee
					
				|  | @ -21,15 +21,17 @@ | ||||||
| // \callgraph
 | // \callgraph
 | ||||||
| 
 | 
 | ||||||
| #pragma once | #pragma once | ||||||
|  | #include <gtsam/base/OptionalJacobian.h> | ||||||
| #include <gtsam/base/Vector.h> | #include <gtsam/base/Vector.h> | ||||||
| #include <gtsam/config.h>      // Configuration from CMake | #include <gtsam/config.h>      // Configuration from CMake | ||||||
| 
 | 
 | ||||||
| #include <boost/math/special_functions/fpclassify.hpp> |  | ||||||
| #include <Eigen/Core> | #include <Eigen/Core> | ||||||
| #include <Eigen/Cholesky> | #include <Eigen/Cholesky> | ||||||
| #include <Eigen/LU> | #include <Eigen/LU> | ||||||
| #include <boost/format.hpp> | #include <boost/format.hpp> | ||||||
|  | #include <boost/function.hpp> | ||||||
| #include <boost/tuple/tuple.hpp> | #include <boost/tuple/tuple.hpp> | ||||||
|  | #include <boost/math/special_functions/fpclassify.hpp> | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|  | @ -532,6 +534,75 @@ GTSAM_EXPORT Matrix expm(const Matrix& A, size_t K=7); | ||||||
| 
 | 
 | ||||||
| std::string formatMatrixIndented(const std::string& label, const Matrix& matrix, bool makeVectorHorizontal = false); | std::string formatMatrixIndented(const std::string& label, const Matrix& matrix, bool makeVectorHorizontal = false); | ||||||
| 
 | 
 | ||||||
|  | /**
 | ||||||
|  |  * Functor that implements multiplication of a vector b with the inverse of a | ||||||
|  |  * matrix A. The derivatives are inspired by Mike Giles' "An extended collection | ||||||
|  |  * of matrix derivative results for forward and reverse mode algorithmic | ||||||
|  |  * differentiation", at https://people.maths.ox.ac.uk/gilesm/files/NA-08-01.pdf | ||||||
|  |  */ | ||||||
|  | template <int N> | ||||||
|  | struct MultiplyWithInverse { | ||||||
|  |   typedef Eigen::Matrix<double, N, 1> VectorN; | ||||||
|  |   typedef Eigen::Matrix<double, N, N> MatrixN; | ||||||
|  | 
 | ||||||
|  |   /// A.inverse() * b, with optional derivatives
 | ||||||
|  |   VectorN operator()(const MatrixN& A, const VectorN& b, | ||||||
|  |                      OptionalJacobian<N, N* N> H1 = boost::none, | ||||||
|  |                      OptionalJacobian<N, N> H2 = boost::none) const { | ||||||
|  |     const MatrixN invA = A.inverse(); | ||||||
|  |     const VectorN c = invA * b; | ||||||
|  |     // The derivative in A is just -[c[0]*invA c[1]*invA ... c[N-1]*invA]
 | ||||||
|  |     if (H1) | ||||||
|  |       for (size_t j = 0; j < N; j++) | ||||||
|  |         H1->template middleCols<N>(N * j) = -c[j] * invA; | ||||||
|  |     // The derivative in b is easy, as invA*b is just a linear map:
 | ||||||
|  |     if (H2) *H2 = invA; | ||||||
|  |     return c; | ||||||
|  |   } | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Functor that implements multiplication with the inverse of a matrix, itself | ||||||
|  |  * the result of a function f. It turn out we only need the derivatives of the | ||||||
|  |  * operator phi(a): b -> f(a) * b | ||||||
|  |  */ | ||||||
|  | template <typename T, int N> | ||||||
|  | struct MultiplyWithInverseFunction { | ||||||
|  |   enum { M = traits<T>::dimension }; | ||||||
|  |   typedef Eigen::Matrix<double, N, 1> VectorN; | ||||||
|  |   typedef Eigen::Matrix<double, N, N> MatrixN; | ||||||
|  | 
 | ||||||
|  |   // The function phi should calculate f(a)*b, with derivatives in a and b.
 | ||||||
|  |   // Naturally, the derivative in b is f(a).
 | ||||||
|  |   typedef boost::function<VectorN( | ||||||
|  |       const T&, const VectorN&, OptionalJacobian<N, M>, OptionalJacobian<N, N>)> | ||||||
|  |       Operator; | ||||||
|  | 
 | ||||||
|  |   /// Construct with function as explained above
 | ||||||
|  |   MultiplyWithInverseFunction(const Operator& phi) : phi_(phi) {} | ||||||
|  | 
 | ||||||
|  |   /// f(a).inverse() * b, with optional derivatives
 | ||||||
|  |   VectorN operator()(const T& a, const VectorN& b, | ||||||
|  |                      OptionalJacobian<N, M> H1 = boost::none, | ||||||
|  |                      OptionalJacobian<N, N> H2 = boost::none) const { | ||||||
|  |     MatrixN A; | ||||||
|  |     phi_(a, b, boost::none, A);  // get A = f(a) by calling f once
 | ||||||
|  |     const MatrixN invA = A.inverse(); | ||||||
|  |     const VectorN c = invA * b; | ||||||
|  | 
 | ||||||
|  |     if (H1) { | ||||||
|  |       Eigen::Matrix<double, N, M> H; | ||||||
|  |       phi_(a, c, H, boost::none);  // get derivative H of forward mapping
 | ||||||
|  |       *H1 = -invA* H; | ||||||
|  |     } | ||||||
|  |     if (H2) *H2 = invA; | ||||||
|  |     return c; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |  private: | ||||||
|  |   const Operator phi_; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| } // namespace gtsam
 | } // namespace gtsam
 | ||||||
| 
 | 
 | ||||||
| #include <boost/serialization/nvp.hpp> | #include <boost/serialization/nvp.hpp> | ||||||
|  |  | ||||||
|  | @ -24,90 +24,6 @@ Expression<T> compose(const Expression<T>& t1, const Expression<T>& t2) { | ||||||
|   return Expression<T>(traits<T>::Compose, t1, t2); |   return Expression<T>(traits<T>::Compose, t1, t2); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /**
 |  | ||||||
|  * Functor that implements multiplication of a vector b with the inverse of a |  | ||||||
|  * matrix A. The derivatives are inspired by Mike Giles' "An extended collection |  | ||||||
|  * of matrix derivative results for forward and reverse mode algorithmic |  | ||||||
|  * differentiation", at https://people.maths.ox.ac.uk/gilesm/files/NA-08-01.pdf |  | ||||||
|  * |  | ||||||
|  * Usage example: |  | ||||||
|   *  Expression<Vector3> expression = MultiplyWithInverse<3>()(Key(0), Key(1)); |  | ||||||
|  */ |  | ||||||
| template <int N> |  | ||||||
| struct MultiplyWithInverse { |  | ||||||
|   typedef Eigen::Matrix<double, N, 1> VectorN; |  | ||||||
|   typedef Eigen::Matrix<double, N, N> MatrixN; |  | ||||||
| 
 |  | ||||||
|   /// A.inverse() * b, with optional derivatives
 |  | ||||||
|   VectorN operator()(const MatrixN& A, const VectorN& b, |  | ||||||
|                      OptionalJacobian<N, N* N> H1 = boost::none, |  | ||||||
|                      OptionalJacobian<N, N> H2 = boost::none) const { |  | ||||||
|     const MatrixN invA = A.inverse(); |  | ||||||
|     const VectorN c = invA * b; |  | ||||||
|     // The derivative in A is just -[c[0]*invA c[1]*invA ... c[N-1]*invA]
 |  | ||||||
|     if (H1) |  | ||||||
|       for (size_t j = 0; j < N; j++) |  | ||||||
|         H1->template middleCols<N>(N * j) = -c[j] * invA; |  | ||||||
|     // The derivative in b is easy, as invA*b is just a linear map:
 |  | ||||||
|     if (H2) *H2 = invA; |  | ||||||
|     return c; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   /// Create expression
 |  | ||||||
|   Expression<VectorN> operator()(const Expression<MatrixN>& A_, |  | ||||||
|                                  const Expression<VectorN>& b_) const { |  | ||||||
|     return Expression<VectorN>(*this, A_, b_); |  | ||||||
|   } |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| /**
 |  | ||||||
|  * Functor that implements multiplication with the inverse of a matrix, itself |  | ||||||
|  * the result of a function f. It turn out we only need the derivatives of the |  | ||||||
|  * operator phi(a): b -> f(a) * b |  | ||||||
|  */ |  | ||||||
| template <typename T, int N> |  | ||||||
| struct MultiplyWithInverseFunction { |  | ||||||
|   enum { M = traits<T>::dimension }; |  | ||||||
|   typedef Eigen::Matrix<double, N, 1> VectorN; |  | ||||||
|   typedef Eigen::Matrix<double, N, N> MatrixN; |  | ||||||
| 
 |  | ||||||
|   // The function phi should calculate f(a)*b, with derivatives in a and b.
 |  | ||||||
|   // Naturally, the derivative in b is f(a).
 |  | ||||||
|   typedef boost::function<VectorN( |  | ||||||
|       const T&, const VectorN&, OptionalJacobian<N, M>, OptionalJacobian<N, N>)> |  | ||||||
|       Operator; |  | ||||||
| 
 |  | ||||||
|   /// Construct with function as explained above
 |  | ||||||
|   MultiplyWithInverseFunction(const Operator& phi) : phi_(phi) {} |  | ||||||
| 
 |  | ||||||
|   /// f(a).inverse() * b, with optional derivatives
 |  | ||||||
|   VectorN operator()(const T& a, const VectorN& b, |  | ||||||
|                      OptionalJacobian<N, M> H1 = boost::none, |  | ||||||
|                      OptionalJacobian<N, N> H2 = boost::none) const { |  | ||||||
|     MatrixN A; |  | ||||||
|     phi_(a, b, boost::none, A);  // get A = f(a) by calling f once
 |  | ||||||
|     const MatrixN invA = A.inverse(); |  | ||||||
|     const VectorN c = invA * b; |  | ||||||
| 
 |  | ||||||
|     if (H1) { |  | ||||||
|       Eigen::Matrix<double, N, M> H; |  | ||||||
|       phi_(a, c, H, boost::none);  // get derivative H of forward mapping
 |  | ||||||
|       *H1 = -invA* H; |  | ||||||
|     } |  | ||||||
|     if (H2) *H2 = invA; |  | ||||||
|     return c; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   /// Create expression
 |  | ||||||
|   Expression<VectorN> operator()(const Expression<T>& a_, |  | ||||||
|                                  const Expression<VectorN>& b_) const { |  | ||||||
|     return Expression<VectorN>(*this, a_, b_); |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|  private: |  | ||||||
|   const Operator phi_; |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| // Some typedefs
 | // Some typedefs
 | ||||||
| typedef Expression<double> double_; | typedef Expression<double> double_; | ||||||
| typedef Expression<Vector1> Vector1_; | typedef Expression<Vector1> Vector1_; | ||||||
|  |  | ||||||
|  | @ -605,7 +605,7 @@ TEST(ExpressionFactor, MultiplyWithInverse) { | ||||||
|   auto model = noiseModel::Isotropic::Sigma(3, 1); |   auto model = noiseModel::Isotropic::Sigma(3, 1); | ||||||
| 
 | 
 | ||||||
|   // Create expression
 |   // Create expression
 | ||||||
|   auto f_expr = MultiplyWithInverse<3>()(Key(0), Key(1)); |   Vector3_ f_expr(MultiplyWithInverse<3>(), Expression<Matrix3>(0), Vector3_(1)); | ||||||
| 
 | 
 | ||||||
|   // Check derivatives
 |   // Check derivatives
 | ||||||
|   Values values; |   Values values; | ||||||
|  | @ -638,7 +638,8 @@ TEST(ExpressionFactor, MultiplyWithInverseFunction) { | ||||||
|   auto model = noiseModel::Isotropic::Sigma(3, 1); |   auto model = noiseModel::Isotropic::Sigma(3, 1); | ||||||
| 
 | 
 | ||||||
|   using test_operator::f; |   using test_operator::f; | ||||||
|   auto f_expr = MultiplyWithInverseFunction<Point2, 3>(f)(Key(0), Key(1)); |   Vector3_ f_expr(MultiplyWithInverseFunction<Point2, 3>(f), | ||||||
|  |                   Expression<Point2>(0), Vector3_(1)); | ||||||
| 
 | 
 | ||||||
|   // Check derivatives
 |   // Check derivatives
 | ||||||
|   Point2 a(1, 2); |   Point2 a(1, 2); | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue