Re: [eigen] documentation: the long tutorial

[ Thread Index | Date Index | More lists.tuxfamily.org/eigen Archives ]


Attached here is my draft of the first page of the tutorial, on the
Matrix class. Comments welcome.

Benoit

2010/6/20 Gael Guennebaud <gael.guennebaud@xxxxxxxxx>:
> On Sun, Jun 20, 2010 at 11:45 PM, Carlos Becker <carlosbecker@xxxxxxxxx> wrote:
>> I think that the examples found
>> in http://eigen.tuxfamily.org/dox/TutorialCore.html are quite useful, does
>> anyone know in which .dox file they are found?
>
> in eigen/doc/C01_TutorialCore.dox
>
> thanks for your work though I don't have time to check it now for the feedbacks.
>
> gael
>
>
>
Title: Eigen: Tutorial page 1 - the Matrix class

Tutorial page 1 - the Matrix class

We assume that you have already read the quick "getting started" tutorial.This page is the first one in a much longer multi-page tutorial.

In Eigen, all matrices and vectors are object of the Matrix class. Vectors are just a special case of matrices, with either 1 row or 1 column.

The Matrix class

The Matrix class takes 6 template parameters, but for now it's enough to learn about the 3 first parameters. The 3 remaining parameters have default values, which for now we will leave untouched, and which we discuss below.

The 3 mandatory template parameters of Matrix are:

Matrix<typename Scalar, int RowsAtCompileTime, int ColsAtCompileTime>

We offer a lot of convenience typedefs to cover the usual cases. For example, Matrix4f is a 4x4 matrix of floats. Here is how it is defined by Eigen:

typedef Matrix<float,4,4> Matrix4f;

We discuss below these convenience typedefs.

Vectors

As mentioned above, in Eigen, vectors are just a special case of matrices, with either 1 row or 1 column. The case where they have 1 column is the most common; such vectors are called column-vectors, often abbreviated as just vectors. In the other case where they have 1 row, they are called row-vectors.

For example, the convenience typedef Vector3f is defined as follows by Eigen:

typedef Matrix<float, 3, 1> Vector3f;

and we also offer convenience typedefs for row-vectors, for example:

typedef Matrix<int, 1, 2> RowVector2i;

The special value Dynamic

Of course, Eigen is not limited to matrices whose dimensions are known at compile time. The above-discussed RowsAtCompileTime and ColsAtCompileTime can take the special value Dynamic which indicates that the size is unknown at compile time, so must be handled as a run time variable. In Eigen terminology, such as size is referred to as a dynamic size; while a size that is known at compile time are referred to as a fixed size. For example, the convenience typedef MatrixXd, meaning a matrix of doubles with dynamic size, is defined as follows:

typedef Matrix<double,Dynamic,Dynamic> MatrixXd;

And similarly, we define a self-explanatory typedef VectorXi as follows:

typedef Matrix<int,Dynamic,1> VectorXi;

You can perfectly have e.g. a fixed number of rows with a dynamic number of columns, e.g.

Matrix<float, 3, Dynamic>

Constructors

A default constructor is always available, and always has zero runtime cost. You can do:

Matrix3f a;
MatrixXf b;

Here,

Constructors taking sizes are also available. For matrices, the number of rows is always passed first. For vectors, just pass the vector size. They allocate the array of coefficients with the given size, but don't initialize the coefficients themselves:

MatrixXf a(10,15);
VectorXf b(30);

Here,

In order to offer a uniform API across fixed-size and dynamic-size matrices, it is legal to use these constructors on fixed-size matrices, even if passing the sizes is useless in this case. So this is legal:

Matrix3f a(3,3);

and is a no-operation.

Finally, we also offer some constructors to initialize the coefficients of small fixed-size vectors up to size 4:

Vector2d a(5.0, 6.0);
Vector3d b(5.0, 6.0, 7.0);
Vector4d c(5.0, 6.0, 7.0, 8.0);

Coefficient accessors

The primary coefficient accessors and mutators in Eigen are the overloaded parenthesis operators. For matrices, the row index is always passed first. For vectors, just pass one index. The numbering starts at 0. This example is self-explanatory:

#include <iostream>
#include <Eigen/Dense>

using namespace Eigen;

int main()
{
  MatrixXd m(2,2);
  m(0,0) = 3;
  m(1,0) = 2.5;
  m(0,1) = -1;
  m(1,1) = m(1,0) + m(0,1);
  std::cout << "Here is the matrix m:\n" << m << std::endl;
  VectorXd v(2);
  v(0) = 4;
  v(1) = v(0) - 1;
  std::cout << "Here is the vector v:\n" << v << std::endl;

}

Output:

Here is the matrix m:
  3  -1
2.5 1.5
Here is the vector v:
4
3

Note that the syntax

m(index)

is not restricted to vector, it is also available for general matrices, meaning index-based access in the array of coefficients. This however depends on the matrix's storage order. All Eigen matrices default to column-major storage order, but this can be changed to row-major, see Storage orders.

The operator[] is also overloaded for index-based access in vectors, but keep in mind that C++ doesn't allow operator[] to take more than one argument. We restrict operator[] to vectors, because an awkwardness in the C++ language would make matrix[i,j] compile to the same thing as matrix[j] !

Resizing

Resizing a dynamic-size matrix is done by the resize() method. The current sizes can be retrieved by rows(), cols() and size(). For example:

#include <iostream>
#include <Eigen/Dense>

using namespace Eigen;

int main()
{
  MatrixXd m(2,5);
  m.resize(4,3);
  std::cout << "The matrix m is of size "
            << m.rows() << "x" << m.cols() << std::endl;
  std::cout << "It has " << m.size() << " coefficients" << std::endl;
  VectorXd v(2);
  v.resize(5);
  std::cout << "The vector v is of size " << v.size() << std::endl;
  std::cout << "As a matrix, v is of size "
            << v.rows() << "x" << v.cols() << std::endl;
}

Output:

The matrix m is of size 4x3
It has 12 coefficients
The vector v is of size 5
As a matrix, v is of size 5x1

The resize() method is a no-operation if the actual array size doesn't change; otherwise it is destructive. If you want a conservative variant of resize(), use conservativeResize().

All these methods are still available on fixed-size matrices, for the sake of API uniformity. Of course, you can't actually resize a fixed-size matrix. Trying to change a fixed size to an actually different value will trigger an assertion failure; but the following code is legal:

#include <iostream>
#include <Eigen/Dense>

using namespace Eigen;

int main()
{
  Matrix4d m;
  m.resize(4,4); // no operation
  std::cout << "The matrix m is of size "
            << m.rows() << "x" << m.cols() << std::endl;
}

Output:

The matrix m is of size 4x4

Fixed vs. Dynamic size

When to use fixed sizes (e.g. Matrix4f), when to use dynamic sizes (e.g. MatrixXf) ? The simple answer is: use fixed sizes where you can, use dynamic sizes where you have to. For small sizes, especially for sizes smaller than (roughly) 16, using fixed sizes is hugely beneficial to performance, as it allows Eigen to avoid dynamic memory allocation and to unroll loops. Internally, a fixed-size Eigen matrix is just a plain static array, i.e. doing

 Matrix4f mymatrix; 

really amounts to just doing

 float mymatrix[16]; 

so this really has zero runtime cost. By constrast, the array of a dynamic-size matrix is always allocated on the heap, so doing

 MatrixXf mymatrix(rows,columns); 

amounts to doing

 float *mymatrix = new float[rows*columns]; 

and in addition to that, the MatrixXf object stores its number of rows and columns as member variables.

The limitation of using fixed sizes, of course, is that this is only possible when you know the sizes at compile time. Also, for large enough sizes, say for sizes greater than (roughly) 32, the performance benefit of using fixed sizes becomes negligible. Worse, trying to create a very large matrix using fixed sizes could result in a stack overflow, since Eigen will try to allocate the array as a static array, which by default goes on the stack. Finally, depending on circumstances, Eigen can also be more aggressive trying to vectorize (use SIMD instructions) when dynamic sizes are used, see Vectorization.

Optional template parameters

We mentioned at the beginning of this page that the Matrix class takes 6 template parameters, but so far we only discussed the 3 first parameters. The remaining 3 parameters are optional. Here is the complete list of template parameters:

Matrix<typename Scalar,
       int RowsAtCompileTime,
       int ColsAtCompileTime,
       int Options = 0,
       int MaxRowsAtCompileTime = RowsAtCompileTime,
       int MaxColsAtCompileTime = ColsAtCompileTime>

Convenience typedefs

Let use some wildcards:

The convenience Matrix typedefs are of the forms:

Generated by  doxygen 1.6.2-20100208


Mail converted by MHonArc 2.6.19+ http://listengine.tuxfamily.org/