From 9c97b1d8a0720a9a45e85ee532cdb3fedd28be32 Mon Sep 17 00:00:00 2001 From: dellaert Date: Sat, 18 Oct 2014 16:45:04 +0200 Subject: [PATCH] Some more refactoring --- .../nonlinear/tests/testExpression.cpp | 81 +++++++++++++------ 1 file changed, 58 insertions(+), 23 deletions(-) diff --git a/gtsam_unstable/nonlinear/tests/testExpression.cpp b/gtsam_unstable/nonlinear/tests/testExpression.cpp index 28d160799..b0abf6b6f 100644 --- a/gtsam_unstable/nonlinear/tests/testExpression.cpp +++ b/gtsam_unstable/nonlinear/tests/testExpression.cpp @@ -323,23 +323,39 @@ struct SnavelyReprojectionError { }; /* ************************************************************************* */ -// manifold_traits prototype -// Same style as Boost.TypeTraits + +/** + * A manifold defines a space in which there is a notion of a linear tangent space + * that can be centered around a given point on the manifold. These nonlinear + * spaces may have such properties as wrapping around (as is the case with rotations), + * which might make linear operations on parameters not return a viable element of + * the manifold. + * + * We perform optimization by computing a linear delta in the tangent space of the + * current estimate, and then apply this change using a retraction operation, which + * maps the change in tangent space back to the manifold itself. + * + * There may be multiple possible retractions for a given manifold, which can be chosen + * between depending on the computational complexity. The important criteria for + * the creation for the retract and localCoordinates functions is that they be + * inverse operations. + * + */ + +// Traits, same style as Boost.TypeTraits // All meta-functions below ever only declare a single type // or a type/value/value_type -#include -#include - -// is manifold +// is manifold, by default this is false template -struct is_manifold: public false_type { +struct is_manifold: public std::false_type { }; -// dimension +// dimension, can return Eigen::Dynamic (-1) if not known at compile time template -struct dimension; +struct dimension: public std::integral_constant { +}; -// TangentVector is eigen::Matrix type in tangent space +// TangentVector is Eigen::Matrix type in tangent space, can be Dynamic... template struct TangentVector { BOOST_STATIC_ASSERT(is_manifold::value); @@ -348,7 +364,7 @@ struct TangentVector { // default localCoordinates template -struct localCoordinates { +struct LocalCoordinates { typename TangentVector::type operator()(const T& t1, const T& t2) { return t1.localCoordinates(t2); } @@ -356,7 +372,7 @@ struct localCoordinates { // default retract template -struct retract { +struct Retract { T operator()(const T& t, const typename TangentVector::type& d) { return t.retract(d); } @@ -375,7 +391,7 @@ struct dimension > : public integral_consta }; template -struct localCoordinates > { +struct LocalCoordinates > { typedef Eigen::Matrix T; typedef typename TangentVector::type result_type; result_type operator()(const T& t1, const T& t2) { @@ -385,7 +401,7 @@ struct localCoordinates > { }; template -struct retract > { +struct Retract > { typedef Eigen::Matrix T; T operator()(const T& t, const typename TangentVector::type& d) { return t + Eigen::Map(d.data()); @@ -417,8 +433,14 @@ TEST(Expression, dimension) { // localCoordinates TEST(Expression, localCoordinates) { - EXPECT(localCoordinates()(Point2(0,0),Point2(1,0))==Vector2(1,0)); - EXPECT(localCoordinates()(Vector2(0,0),Vector2(1,0))==Vector2(1,0)); + EXPECT(LocalCoordinates()(Point2(0,0),Point2(1,0))==Vector2(1,0)); + EXPECT(LocalCoordinates()(Vector2(0,0),Vector2(1,0))==Vector2(1,0)); +} + +// retract +TEST(Expression, retract) { + EXPECT(Retract()(Point2(0,0),Vector2(1,0))==Point2(1,0)); + EXPECT(Retract()(Vector2(0,0),Vector2(1,0))==Vector2(1,0)); } /* ************************************************************************* */ @@ -426,21 +448,34 @@ TEST(Expression, localCoordinates) { template Matrix numericalDerivative(boost::function h, const X& x, double delta = 1e-5) { + BOOST_STATIC_ASSERT(is_manifold::value); - BOOST_STATIC_ASSERT(is_manifold::value); - Y hx = h(x); - double factor = 1.0 / (2.0 * delta); static const size_t M = dimension::value; + typedef typename TangentVector::type TangentY; + LocalCoordinates localCoordinates; + + BOOST_STATIC_ASSERT(is_manifold::value); static const size_t N = dimension::value; - Eigen::Matrix d; + typedef typename TangentVector::type TangentX; + Retract retract; + + // get value at x + Y hx = h(x); + + // Prepare a tangent vector to perturb x with + TangentX d; + d.setZero(); + + // Fill in Jacobian H Matrix H = zeros(M, N); + double factor = 1.0 / (2.0 * delta); for (size_t j = 0; j < N; j++) { - d.setZero(); d(j) = delta; - Vector hxplus = localCoordinates()(hx, h(retract()(x, d))); + TangentY hxplus = localCoordinates(hx, h(retract(x, d))); d(j) = -delta; - Vector hxmin = localCoordinates()(hx, h(retract()(x, d))); + TangentY hxmin = localCoordinates(hx, h(retract(x, d))); H.block(0, j) << (hxplus - hxmin) * factor; + d(j) = 0; } return H; }