Optimizing Your Own Types¶
Python and C++ code of this example can be found at optimize_custom_type.py and optimize_custom_type.cpp respectively.
miniSAM already has build-in support for optimizing various commonly used manifold types in C++ and Python, including Eigen::Vector
types in C++, numpy.array
in Python, and Lie groups \(SO(2)\), \(SE(2)\), \(SO(3)\), \(SE(3)\) and \(Sim(3)\), which are commonly used in SLAM and robotics problems, provided by Sophus library in both C++ and Python.
In this page we see how to customize manifold properties of any C++ or Python class for miniSAM. The example is given by defining a miniSAM-optimizable 2D vector space \(\mathbb{R}^2\) type.
Python example¶
In Python this is done by defining manifold-related member functions, including
dim(self)
, function returns local manifold dimensionality. For \(\mathbb{R}^2\) the dimensionality is just 2.local(self, other)
, function returns local coordinate ofother
defined at originself
. For \(\mathbb{R}^2\) since the local manifold is itself, this function returnsother - self
.retract(self, vec)
, given local coordinatevec
defined at originself
, this function returns point projected on manifold ofvec
. For \(\mathbb{R}^2\) since the local manifold is itself, this function returnsself + vec
.__repr__(self)
, function printself
to a string.
The example code:
# 2D point optimizable in miniSAM
class Point2D(object):
# constructor
def __init__(self, x, y):
self.x_ = float(x)
self.y_ = float(y)
# print function
def __repr__(self):
return 'custom 2D point [' + str(self.x_) + ', ' + str(self.y_) + ']\''
# local coordinate dimension
def dim(self):
return 2
# map manifold point other to local coordinate
def local(self, other):
return np.array([other.x_ - self.x_, other.y_ - self.y_], dtype=np.float)
# apply changes in local coordinate to manifold, \oplus operator
def retract(self, vec):
return Point2D(self.x_ + vec[0], self.y_ + vec[1])
C++ example¶
In C++ we use a non-intrusive technique called traits, which is a specialization of template minisam::traits<>
for the type we are adding manifold properties.
Using traits to define manifold properties has two major advantages:
- Optimizing a class without modifying it, or even without knowing details of implementation (e.g. optimization support for third-party C/C++ types).
- Making optimizing primitive types (like
double
) possible.
The specialization of template minisam::traits<>
needs following typedefs/static functions defined.
- typedef
manifold_tag
, usemanifold_tag
for regular manifold types andlie_group_tag
for a Lie group types. - typedef
TangentVector
, fixed or dynamic sizeEigen::Vector
which has size of manifold dimensionality. static Dim()
, function returns local manifold dimensionality.static Local()
, function returns local coordinate of input defined at origin.static Retract()
, given local coordinate input defined at origin, this function returns point projected on manifold.static Print()
, function to print tostd::ostream
.
Given a C++ 2D vector space class Point2D
class Point2D {
private:
double x_, y_;
public:
// ctor
Point2D(double x, double y) : x_(x), y_(y) {}
// access
double x() const { return x_; }
double y() const { return y_; }
};
The minisam::traits<Point2D>
specialization is defined by
// speialization of minisam::traits<Point2D>
namespace minisam {
template <>
struct traits<Point2D> {
// minisam type category tag, used for static checking
// must be manifold_tag or lie_group_tag to be optimizable
typedef manifold_tag type_category;
// print
static void Print(const Point2D& m, std::ostream& out = std::cout) {
out << "custom 2D point [" << m.x() << ", " << m.y() << "]'";
}
// tangent vector type defs
typedef Eigen::Matrix<double, 2, 1> TangentVector;
// local coordinate dimension
static constexpr size_t Dim(const Point2D&) { return 2; }
// map manifold point s to local coordinate
static TangentVector Local(const Point2D& origin, const Point2D& s) {
return Eigen::Matrix<double, 2, 1>(s.x() - origin.x(), s.y() - origin.y());
}
// apply changes in local coordinate to manifold, \oplus operator
static Point2D Retract(const Point2D& origin, const TangentVector& v) {
return Point2D(origin.x() + v[0], origin.y() + v[1]);
}
};
} // namespace minisam