diff --git a/gtsam/base/Manifold.h b/gtsam/base/Manifold.h index ceebf6bad..1eee71dfd 100644 --- a/gtsam/base/Manifold.h +++ b/gtsam/base/Manifold.h @@ -19,19 +19,12 @@ #include #include +#include +#include namespace gtsam { /** - * Concept check class for Manifold types - * Requires a mapping between a linear tangent space and the underlying - * manifold, of which Lie is a specialization. - * - * The necessary functions to implement for Manifold are defined - * below with additional details as to the interface. The - * concept checking function in class Manifold will check whether or not - * the function exists and throw compile-time errors. - * * 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), @@ -45,7 +38,130 @@ namespace gtsam { * 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. + * inverse operations. The new notion of a Chart guarantees that. + * + */ + +// Traits, same style as Boost.TypeTraits +// All meta-functions below ever only declare a single type +// or a type/value/value_type +// is manifold, by default this is false +template +struct is_manifold: public std::false_type { +}; + +// dimension, can return Eigen::Dynamic (-1) if not known at compile time +template +struct dimension; +//: public std::integral_constant { +// BOOST_STATIC_ASSERT(is_manifold::value); +//}; + +// Chart is a map from T -> vector, retract is its inverse +template +struct DefaultChart { + BOOST_STATIC_ASSERT(is_manifold::value); + typedef Eigen::Matrix::value, 1> vector; + DefaultChart(const T& t) : + t_(t) { + } + vector apply(const T& other) { + return t_.localCoordinates(other); + } + T retract(const vector& d) { + return t_.retract(d); + } +private: + T const & t_; +}; + +// double + +template<> +struct is_manifold : public std::true_type { +}; + +template<> +struct dimension : public std::integral_constant { +}; + +template<> +struct DefaultChart { + typedef Eigen::Matrix vector; + DefaultChart(double t) : + t_(t) { + } + vector apply(double other) { + vector d; + d << other - t_; + return d; + } + double retract(const vector& d) { + return t_ + d[0]; + } +private: + double t_; +}; + +// Fixed size Eigen::Matrix type + +template +struct is_manifold > : public std::true_type { +}; + +// TODO: Could be more sophisticated using Eigen traits and SFINAE? + +typedef std::integral_constant Dynamic; + +template +struct dimension > : public Dynamic { +}; + +template +struct dimension > : public Dynamic { + BOOST_STATIC_ASSERT(M!=Eigen::Dynamic); +}; + +template +struct dimension > : public Dynamic { + BOOST_STATIC_ASSERT(N!=Eigen::Dynamic); +}; + +template +struct dimension > : public std::integral_constant< + size_t, M * N> { + BOOST_STATIC_ASSERT(M!=Eigen::Dynamic && N!=Eigen::Dynamic); +}; + +template +struct DefaultChart > { + typedef Eigen::Matrix T; + typedef Eigen::Matrix::value, 1> vector; + DefaultChart(const T& t) : + t_(t) { + } + vector apply(const T& other) { + T diff = other - t_; + Eigen::Map map(diff.data()); + return vector(map); + } + T retract(const vector& d) { + Eigen::Map map(d.data()); + return t_ + map; + } +private: + T const & t_; +}; + +/** + * Old Concept check class for Manifold types + * Requires a mapping between a linear tangent space and the underlying + * manifold, of which Lie is a specialization. + * + * The necessary functions to implement for Manifold are defined + * below with additional details as to the interface. The + * concept checking function in class Manifold will check whether or not + * the function exists and throw compile-time errors. * * Returns dimensionality of the tangent space, which may be smaller than the number * of nonlinear parameters. @@ -61,7 +177,7 @@ namespace gtsam { * By convention, we use capital letters to designate a static function * @tparam T is a Lie type, like Point2, Pose3, etc. */ -template +template class ManifoldConcept { private: /** concept checking function - implement the functions this demands */ diff --git a/gtsam_unstable/nonlinear/tests/testExpression.cpp b/gtsam_unstable/nonlinear/tests/testExpression.cpp index e9a1b7163..45f8f3284 100644 --- a/gtsam_unstable/nonlinear/tests/testExpression.cpp +++ b/gtsam_unstable/nonlinear/tests/testExpression.cpp @@ -324,137 +324,8 @@ struct SnavelyReprojectionError { /* ************************************************************************* */ -/** - * 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 -// is manifold, by default this is false -template -struct is_manifold: public std::false_type { -}; - -// dimension, can return Eigen::Dynamic (-1) if not known at compile time -template -struct dimension; -//: public std::integral_constant { -// BOOST_STATIC_ASSERT(is_manifold::value); -//}; - -// Chart is a map from T -> vector, retract is its inverse -template -struct DefaultChart { - BOOST_STATIC_ASSERT(is_manifold::value); - typedef Eigen::Matrix::value, 1> vector; - DefaultChart(const T& t) : - t_(t) { - } - vector apply(const T& other) { - return t_.localCoordinates(other); - } - T retract(const vector& d) { - return t_.retract(d); - } -private: - T const & t_; -}; - -// double - -template<> -struct is_manifold : public true_type { -}; - -template<> -struct dimension : public integral_constant { -}; - -template<> -struct DefaultChart { - typedef Eigen::Matrix vector; - DefaultChart(double t) : - t_(t) { - } - vector apply(double other) { - vector d; - d << other - t_; - return d; - } - double retract(const vector& d) { - return t_ + d[0]; - } -private: - double t_; -}; - -// Fixed size Eigen::Matrix type - -template -struct is_manifold > : public true_type { -}; - -// TODO: Could be more sophisticated using Eigen traits and SFINAE? - -template -struct dimension > : public integral_constant< - size_t, Eigen::Dynamic> { -}; - -template -struct dimension > : public integral_constant< - size_t, Eigen::Dynamic> { - BOOST_STATIC_ASSERT(M!=Eigen::Dynamic); -}; - -template -struct dimension > : public integral_constant< - size_t, Eigen::Dynamic> { - BOOST_STATIC_ASSERT(N!=Eigen::Dynamic); -}; - -template -struct dimension > : public integral_constant< - size_t, M * N> { - BOOST_STATIC_ASSERT(M!=Eigen::Dynamic && N!=Eigen::Dynamic); -}; - -template -struct DefaultChart > { - typedef Eigen::Matrix T; - typedef Eigen::Matrix::value, 1> vector; - DefaultChart(const T& t) : - t_(t) { - } - vector apply(const T& other) { - T diff = other - t_; - Eigen::Map map(diff.data()); - return vector(map); - } - T retract(const vector& d) { - Eigen::Map map(d.data()); - return t_ + map; - } -private: - T const & t_; -}; - // Point2 +namespace gtsam { template<> struct is_manifold : public true_type { @@ -464,6 +335,8 @@ template<> struct dimension : public integral_constant { }; +} + // is_manifold TEST(Expression, is_manifold) { EXPECT(!is_manifold::value); @@ -495,7 +368,8 @@ TEST(Expression, Charts) { EXPECT(chart2.retract(Vector2(1,0))==Vector2(1,0)); DefaultChart chart3(0); - Eigen::Matrix v1; v1<<1; + Eigen::Matrix v1; + v1 << 1; EXPECT(chart3.apply(1)==v1); EXPECT(chart3.retract(v1)==1);