A base class for Charts, no more ManifoldType trait...

release/4.3a0
Frank Dellaert 2014-12-05 21:18:53 +00:00
parent a9bb473424
commit 39ee5c5dca
1 changed files with 50 additions and 20 deletions

View File

@ -38,10 +38,10 @@ Chart
A given chart is implemented using a small class that defines the chart itself (from manifold to tangent space) and its inverse.
* types:
* `Manifold`, a pointer back to the type
* `ManifoldType`, a pointer back to the type
* valid expressions:
* `v = Chart::local(p,q)`, the chart, from manifold to tangent space, think of it as *q (-) p*
* `p = Chart::retract(p,v)`, the inverse chart, from tangent space to manifold, think of it as *p (+) v*
* `v = Chart::Local(p,q)`, the chart, from manifold to tangent space, think of it as *q (-) p*
* `p = Chart::Retract(p,v)`, the inverse chart, from tangent space to manifold, think of it as *p (+) v*
For many differential manifolds, an obvious mapping is the `exponential map`, which associates straight lines in the tangent space with geodesics on the manifold (and it's inverse, the log map). However, there are two cases in which we deviate from this:
@ -139,18 +139,54 @@ Unit tests heavily depend on the following two functions being defined for all t
Implementation
==============
GTSAM Types start with Uppercase, e.g., `gtsam::Point2`, and are models of the TESTABLE, MANIFOLD, GROUP, LIE_GROUP, and VECTOR_SPACE concepts.
GTSAM Types start with Uppercase, e.g., `gtsam::Point2`, and are models of the
TESTABLE, MANIFOLD, GROUP, LIE_GROUP, and VECTOR_SPACE concepts.
`gtsam::traits` is our way to associate these concepts with types, and we also define a limited number of `gtsam::tags` to select the correct implementation of certain functions at compile time (tag dispatching).
`gtsam::traits` is our way to associate these concepts with types,
and we also define a limited number of `gtsam::tags` to select the correct implementation
of certain functions at compile time (tag dispatching). Charts are done more conventionally, so we start there...
Interfaces
----------
Because Charts are always written by the user (or automatically generated, see below for vector spaces),
we enforce the Chart concept using an abstract base class, acting as an interface:
```
#!c++
template <class T, class Derived>
struct Chart {
typedef T ManifoldType;
typedef typename traits::TangentVector<T>::type TangentVector;
static TangentVector Local(const ManifoldType& p, const ManifoldType& q) {return Derived::local(p,q);}
static ManifoldType Retract(const ManifoldType& p, const TangentVector& v) {return Derived::retract(p,v);}
protected:
Chart(){ (void)&Local; (void)&Retract; } // enforce early instantiation.
}
```
The [CRTP](http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern) and the protected constructor
automatically check for the existence of the methods in the Derived class, whenever a new Chart is created by
struct MyChart : Chart<MyType,MyChart> { ... }
Traits
------
We will not use Eigen-style or STL-style traits, that define *many* properties at once. Rather, we use boost::mpl style meta-programming functions to facilitate meta-programming, which return a single type or value for every trait. Some rationale/history can be found [here](http://www.boost.org/doc/libs/1_55_0/libs/type_traits/doc/html/boost_typetraits/background.html).
However, a base class is not a good way to implement/check the other concepts, as we would like these
to apply equally well to types that are outside GTSAM control, e.g., `Eigen::VectorXd`. This is where
[traits](http://www.boost.org/doc/libs/1_57_0/libs/type_traits/doc/html/boost_typetraits/background.html) come in.
Traits allow us to play with types that are outside GTSAM control, e.g., `Eigen::VectorXd`. However, for GTSAM types, it is perfectly acceptable (and even desired) to define associated types as internal types, as well, rather than having to use traits internally.
We will not use Eigen-style or STL-style traits, that define *many* properties at once.
Rather, we use boost::mpl style meta-programming functions to facilitate meta-programming,
which return a single type or value for every trait. Some rationale/history can be
found [here](http://www.boost.org/doc/libs/1_55_0/libs/type_traits/doc/html/boost_typetraits/background.html).
as well.
Finally, note that not everything that makes a concept is defined by traits. For example, although a CHART type is supposed to have a `retract` function, there is no trait for this: rather, the
Note that not everything that makes a concept is defined by traits. Valid expressions such as group::compose are
defined simply as free functions.
Finally, for GTSAM types, it is perfectly acceptable (and even desired) to define associated types as internal types,
rather than having to use traits internally.
The conventions for `gtsam::traits` are as follows:
@ -171,7 +207,7 @@ The conventions for `gtsam::traits` are as follows:
* Functors: `gtsam::traits::someFunctor<T>::type`, i.e., they are mixedCase starting with a lowercase letter and define a functor (i.e., no *type*). The functor itself should define a `result_type`. A contrived example
struct Point2::manhattan {
struct Point2::manhattan {
typedef double result_type;
Point2 p_;
manhattan(const Point2& p) : p_(p) {}
@ -179,10 +215,9 @@ The conventions for `gtsam::traits` are as follows:
return abs(p_.x()-q.x()) + abs(p_.y()-q.x());
}
}
template<>
gtsam::traits::manhattan<Point2> : Point2::manhattan {}
template<> gtsam::traits::manhattan<Point2> : Point2::manhattan {}
By *inherting* the trait from the functor, we can just use the [currying](http://en.wikipedia.org/wiki/Currying) style `gtsam::traits::manhattan<Point2>℗(q)`. Note that, although technically a functor is a type, in spirit it is a free function and hence starts with a lowercase letter.
* Tags: `gtsam::traits::some_category<T>::type`, i.e., they are lower_case and define a *single* `type`, for example:
@ -261,8 +296,8 @@ An example of implementing a Manifold type is here:
#!c++
// GTSAM type
class Rot2 {
typedef Vector2 TangentVector;
class Chart {
typedef Vector2 TangentVector; // internal typedef, not required
class Chart : gtsam::Chart<Rot2,Chart>{
static TangentVector local(const Rot2& R1, const Rot2& R2);
static Rot2 retract(const Rot2& R, const TangentVector& v);
}
@ -286,11 +321,6 @@ An example of implementing a Manifold type is here:
template<>
struct defaultChart<Rot2> : Rot2::Chart {}
template<>
struct Manifold<Rot2::Chart> {
typedef Rot2 type;
}
}}
```