Implemented manifold_traits to allow numerical derivatives wrpt Matrix arguments
							parent
							
								
									2cbba15573
								
							
						
					
					
						commit
						db037c96c5
					
				|  | @ -2,5 +2,8 @@ | |||
| file(GLOB nonlinear_headers "*.h") | ||||
| install(FILES ${nonlinear_headers} DESTINATION include/gtsam_unstable/nonlinear) | ||||
| 
 | ||||
| FIND_PACKAGE(Ceres REQUIRED) | ||||
| INCLUDE_DIRECTORIES(${CERES_INCLUDE_DIRS}) | ||||
| 
 | ||||
| # Add all tests | ||||
| add_subdirectory(tests) | ||||
|  |  | |||
|  | @ -23,7 +23,11 @@ | |||
| #include <gtsam_unstable/nonlinear/Expression.h> | ||||
| #include <gtsam/base/Testable.h> | ||||
| #include <gtsam/base/LieScalar.h> | ||||
| //#include <gtsam/base/numericalDerivative.h>
 | ||||
| 
 | ||||
| #include <ceres/internal/autodiff.h> | ||||
| 
 | ||||
| #undef CHECK | ||||
| #include <CppUnitLite/TestHarness.h> | ||||
| 
 | ||||
| #include <boost/assign/list_of.hpp> | ||||
|  | @ -258,24 +262,132 @@ struct Projective { | |||
|     } | ||||
|     return false; | ||||
|   } | ||||
|   Vector2 operator()(const MatrixRowMajor& P, const Vector4& X) const { | ||||
|     Vector2 x; | ||||
|     if (operator()(P.data(), X.data(), x.data())) | ||||
|       return x; | ||||
|     else | ||||
|       throw std::runtime_error("Projective fails"); | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| /* ************************************************************************* */ | ||||
| //#include "/Users/frank/include/ceres/autodiff_cost_function.h"
 | ||||
| 
 | ||||
| #include <boost/static_assert.hpp> | ||||
| 
 | ||||
| template<typename T> | ||||
| struct manifold_traits { | ||||
|   typedef T type; | ||||
|   static const size_t dimension = T::dimension; | ||||
|   typedef Eigen::Matrix<double, dimension, 1> tangent; | ||||
|   static tangent localCoordinates(const T& t1, const T& t2) { | ||||
|     return t1.localCoordinates(t2); | ||||
|   } | ||||
|   static type retract(const type& t, const tangent& d) { | ||||
|     return t.retract(d); | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| // Adapt constant size Eigen::Matrix types as manifold types
 | ||||
| template<int M, int N, int Options> | ||||
| struct manifold_traits<Eigen::Matrix<double, M, N, Options> > { | ||||
|   BOOST_STATIC_ASSERT(M!=Eigen::Dynamic && N!=Eigen::Dynamic); | ||||
|   typedef Eigen::Matrix<double, M, N, Options> type; | ||||
|   static const size_t dimension = M * N; | ||||
|   typedef Eigen::Matrix<double, dimension, 1> tangent; | ||||
|   static tangent localCoordinates(const type& t1, const type& t2) { | ||||
|     type diff = t2 - t1; | ||||
|     return tangent(Eigen::Map<tangent>(diff.data())); | ||||
|   } | ||||
|   static type retract(const type& t, const tangent& d) { | ||||
|     type sum = t + Eigen::Map<const type>(d.data()); | ||||
|     return sum; | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| // Test dimension traits
 | ||||
| TEST(Expression, Traits) { | ||||
|   EXPECT_LONGS_EQUAL(2, manifold_traits<Point2>::dimension); | ||||
|   EXPECT_LONGS_EQUAL(8, manifold_traits<Matrix24>::dimension); | ||||
| } | ||||
| 
 | ||||
| template<class Y, class X1, class X2> | ||||
| Matrix numericalDerivative21(boost::function<Y(const X1&, const X2&)> h, | ||||
|     const X1& x1, const X2& x2, double delta = 1e-5) { | ||||
|   Y hx = h(x1, x2); | ||||
|   double factor = 1.0 / (2.0 * delta); | ||||
|   static const size_t m = manifold_traits<Y>::dimension, n = | ||||
|       manifold_traits<X1>::dimension; | ||||
|   Eigen::Matrix<double, n, 1> d; | ||||
|   d.setZero(); | ||||
|   Matrix H = zeros(m, n); | ||||
|   for (size_t j = 0; j < n; j++) { | ||||
|     d(j) += delta; | ||||
|     Vector hxplus = manifold_traits<Y>::localCoordinates(hx, | ||||
|         h(manifold_traits<X1>::retract(x1, d), x2)); | ||||
|     d(j) -= 2 * delta; | ||||
|     Vector hxmin = manifold_traits<Y>::localCoordinates(hx, | ||||
|         h(manifold_traits<X1>::retract(x1, d), x2)); | ||||
|     d(j) += delta; | ||||
|     H.block<m, 1>(0, j) << (hxplus - hxmin) * factor; | ||||
|   } | ||||
|   return H; | ||||
| } | ||||
| 
 | ||||
| template<class Y, class X1, class X2> | ||||
| Matrix numericalDerivative22(boost::function<Y(const X1&, const X2&)> h, | ||||
|     const X1& x1, const X2& x2, double delta = 1e-5) { | ||||
|   Y hx = h(x1, x2); | ||||
|   double factor = 1.0 / (2.0 * delta); | ||||
|   static const size_t m = manifold_traits<Y>::dimension, n = | ||||
|       manifold_traits<X2>::dimension; | ||||
|   Eigen::Matrix<double, n, 1> d; | ||||
|   d.setZero(); | ||||
|   Matrix H = zeros(m, n); | ||||
|   for (size_t j = 0; j < n; j++) { | ||||
|     d(j) += delta; | ||||
|     Vector hxplus = manifold_traits<Y>::localCoordinates(hx, | ||||
|         h(x1, manifold_traits<X2>::retract(x2, d))); | ||||
|     d(j) -= 2 * delta; | ||||
|     Vector hxmin = manifold_traits<Y>::localCoordinates(hx, | ||||
|         h(x1, manifold_traits<X2>::retract(x2, d))); | ||||
|     d(j) += delta; | ||||
|     H.block<m, 1>(0, j) << (hxplus - hxmin) * factor; | ||||
|   } | ||||
|   return H; | ||||
| } | ||||
| /* ************************************************************************* */ | ||||
| // Test Ceres AutoDiff
 | ||||
| TEST(Expression, AutoDiff) { | ||||
|   using ceres::internal::AutoDiff; | ||||
| 
 | ||||
|   MatrixRowMajor P(3, 4); | ||||
|   // Instantiate function
 | ||||
|   Projective projective; | ||||
| 
 | ||||
|   // Make arguments
 | ||||
|   typedef Eigen::Matrix<double, 3, 4, Eigen::RowMajor> M; | ||||
|   M P; | ||||
|   P << 1, 0, 0, 0, 0, 1, 0, 5, 0, 0, 1, 0; | ||||
|   Vector4 X(10, 0, 5, 1); | ||||
| 
 | ||||
|   // Apply the mapping, to get image point b_x.
 | ||||
|   Projective projective; | ||||
|   Vector2 actual; | ||||
|   EXPECT(projective(P.data(), X.data(), actual.data())); | ||||
| 
 | ||||
|   Vector expected = Vector2(2, 1); | ||||
|   Vector2 actual = projective(P, X); | ||||
|   EXPECT(assert_equal(expected,actual,1e-9)); | ||||
| 
 | ||||
|   // Get expected derivatives
 | ||||
|   Matrix E1 = numericalDerivative21<Vector2, M, Vector4>(Projective(), P, X); | ||||
|   Matrix E2 = numericalDerivative22<Vector2, M, Vector4>(Projective(), P, X); | ||||
| 
 | ||||
|   // Get derivatives with AutoDiff
 | ||||
|   Vector2 actual2; | ||||
|   MatrixRowMajor H1(2, 12), H2(2, 4); | ||||
|   double *parameters[] = { P.data(), X.data() }; | ||||
|   double *jacobians[] = { H1.data(), H2.data() }; | ||||
|   CHECK( | ||||
|       (AutoDiff<Projective, double, 12, 4>::Differentiate( projective, parameters, 2, actual2.data(), jacobians))); | ||||
|   EXPECT(assert_equal(E1,H1,1e-8)); | ||||
|   EXPECT(assert_equal(E2,H2,1e-8)); | ||||
| } | ||||
| 
 | ||||
| /* ************************************************************************* */ | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue