Matrices, vectors, arrays and Linear Algebra: MRPT and Eigen classes

MRPT uses the powerful Eigen C++ library (version 3 of the API) for managing numerical matrices and vectors, so if you are familiar with Eigen, you already understand a large part of MRPT classes, interfaces and methods!

If you don’t know Eigen, these are good starting points:

The main difference with the standard Eigen API is that MRPT extends Eigen::Matrix<> with many new typedefs and methods that extend the number of operations readily available for any vector or matrix, and by the way, provides a smooth transition for code relying on the former non-Eigen MRPT matrix APIs.

You can check out the documentation for Eigen::MatrixBase, which contains both the original Eigen methods plus those provided by MRPT (look for the sections named “MRPT plugin: …”) via a plugin mechanism.

2. MRPT-specific classes

For new code, it’s probably a good idea to directly use Eigen::Matrix<> (or any Eigen typedef: MatrixXd, MatrixXf, etc.) instead of MRPT types, since the latter allare Eigen::Matrix<>instances (in the Object Programming sense of “being derived from”) with different template arguments, as summarized in this table:

MRPT type Inherits from… Memory layout
mrpt::dynamicsize_vector < T >
Base class for:

  • mrpt::vector_float
  • mrpt::vector_double
Eigen::Matrix<>< T,Dynamic,1 > Auto (→ ColMajor)
mrpt::math::CArrayNumeric < T,LEN > Eigen::Matrix<>< T,N,1 > Auto (→ ColMajor)
mrpt::math::CMatrixTemplateNumeric < T >
With typedef‘s:

And with derived classes capable of binary serialization:

Eigen::Matrix<>< T,Dynamic,Dynamic > RowMajor
mrpt::math::CMatrixFixedNumeric < T, NROWS, NCOLS > Eigen::Matrix<>< T,NROWS, NCOLS > ColMajor only if NCOLS=1,
RowMajor otherwise.
  • mrpt::vector_signed_byte
  • mrpt::vector_signed_word
  • mrpt::vector_int
  • mrpt::vector_long
  • mrpt::vector_size_t
  • mrpt::vector_byte
  • mrpt::vector_word
  • mrpt::vector_uint
These classes are not based on Eigen,
but inherit from STL std::vector<>
Elements contiguous in memory,
as in any std::vector<>
mrpt::math::CArray<T,SIZE> Not based on Eigen, designed
to hold numeric or non-numeric elements.
Elements contiguous in memory.

MRPT classes inherit from Eigen::Matrix, but there a few more differences, which are enumerated below.

3. Differences between MRPT matrix classes and Eigen classes

  • Note in the table above that memory layout is significative since former MRPT classes all were RowMajor, while Eigen’s default is ColMajor. In general, users can’t notice the difference, except for some special situations, for example, the following code expect the matrix constructor to read the numbers from the array in RowMajor order (so “2” ends up in the first row, second column, etc.):
  • MRPT matrices’ default constructors set all entries to zero, while in Eigen the default values are undefined. Both approaches are useful in different cases.
  • Dumping an MRPT matrix to std::cout will append a final line feed, while with Eigen classes the cursor will remain at the end of the last printed line. So, these two print commands will produce exactly the same output:
     

4. Common errors (and their solutions!)

4.1. Alignment compile-time issues

Fixed-size vectorizable Eigen objects have special memory alignment requirements for efficiency. To refer to those classes plus any other class or struct that contains such matrices (at any depth down in the hierarchy!), I’ll use the name “problematic classes” (“problematic” standing for “needing special care for their alignment”).

There are plenty of affected classes in MRPT (CMatrixFixedNumericCPose3D, etc.), and there are good chances that your own classes are affected too, since just a single fixed-size matrix anywhere within a class marks it as “problematic”.

Normally the compiler handles the alignment requirements automatically, but there are some cases where it doesn’t, and you’ll find the following errors.

4.1.2. STL containers

If you have errors like:

around a STL container, then it means that you must use Eigen’s special aligned memory allocator for the container. This Eigen’s webpage explains this problem in detail.

But, in short these are the required changes:

Notice that MRPT provides mrpt::aligned_containers to ease the declaration of such STL containers.

4.1.3. The “parameter won’t be aligned” error:

If you have an error like:

and it wasn’t around an STL container, then you are trying to pass the “problematic” type as an argument by value. Read this page in Eigen’s website explaining the situation.

In short, the solution is to convert it to passing by reference:

4.2. Alignment run-time issues

If you find runtime errors like:

while accessing data members in a class that contains “problematic” types, and the instantiation of that class was created dynamically (with new), that is:

then, (first read the page cited in the error!) the problem will be most likely solved adding the EIGEN_MAKE_ALIGNED_OPERATOR_NEW macro to your class declaration:

When you create an instance of your class with new CoolStuff(); a custom memory allocator will be invoked that always returns aligned memory.

Important note: All MRPT classes inheriting from mrpt::utils::CObject already have this specialized new operators, so if your custom classes also inhirit fromCObject or CSerializable, you don’t have to use that macro.

4.3. Mixing numeric types: explicit casting

In order to avoid unintended conversions from matrices/vectors of one type to the other (e.g. double <->float), which cost time, Eigen raises the following error at runtime:

if you try something as:

The solution is to use the cast() explicit converter, that is:

4.4. resize() vs. setSize()

Notice that resize() is a native Eigen method that doesn’t preserve the old contents of the matrix, while setSize() is an MRPT method that pads with zerosthe new elements and keep the old values unchanged.

Refer to the documentation of Eigen::MatrixBase (which includes the plugin methods from MRPT).

5. Issues porting MRPT code from ≤ 0.9.2

Apart from finding the build or runtime errors mentioned above (which apply to either new or old Eigen and MRPT-based code), there are some important points to keep in mind if your code intensively used old (non-Eigen) MRPT vectors and matrices:

5.1. Issues with mrpt::vector_float and mrpt::vector_double

The types mrpt::vector_float and std::vector<float> (or the double versions) are not interchangeable any more.

5.2. Matrices constructors from poses (TPose2D,…) are now explicit

Example: Previous code “CMatrixDouble31 m = myPose2D;” won’t build now, should be: “CMatrixDouble31 m = CMatrixDouble31(myPose2D);”

5.3. Iterators to matrix elements

Iterators to vectors and matrices, which were implemented with a uniform interface with former MRPT classes, are not available anymore, since they are not provided by Eigen. Read about their reasons in this thread.

5.4. CVectorFloat and CVectorDouble

The use of these types is discouraged in new code. They are now synonymous with mrpt::vector_float and mrpt::vector_double.

5.5. The matrix method unit()

The method unit(), which sets a matrix to an identity matrix, had an inconsistent signature between fixed and dynamic sized matrices. It’s now unified in Eigen::MatrixBase::unit(), although you can always directly invoke Eigen’s setIdentity().

6. Advanced topics

6.1. Including boh MRPT and Eigen headers in your code

  • Include MRPT headers first (since it uses the plugin mechanism…).
  • Including “mrpt-base” assures Eigen headers are always already included.
  • Can’t mix version 2 & 3. Use either MRPT embedded version or other copy of Eigen version 3, but not both.
  • CMake-based mechanism to extend Eigen::MatrixBase plugins already in MRPT.