module
Interfacing with raw buffers: the Map classContents
This page explains how to work with "raw" C/C++ arrays. This can be useful in a variety of contexts, particularly when "importing" vectors and matrices from other libraries into Eigen.
Introduction
Occasionally you may have a pre-defined array of numbers that you want to use within Eigen as a vector or matrix. While one option is to make a copy of the data, most commonly you probably want to re-use this memory as an Eigen type. Fortunately, this is very easy with the Map class.
Map types and declaring Map variables
A Map object has a type defined by its Eigen equivalent: Map<Matrix<typename Scalar, int RowsAtCompileTime, int ColsAtCompileTime> >
Note that, in this default case, a Map requires just a single template parameter.
To construct a Map variable, you need two other pieces of information: a pointer to the region of memory defining the array of coefficients, and the desired shape of the matrix or vector. For example, to define a matrix of float
with sizes determined at compile time, you might do the following: Map<MatrixXf> mf(pf,rows,columns);
where pf
is a float
*
pointing to the array of memory. A fixed-size read-only vector of integers might be declared as Map<const Vector4i> mi(pi);
where pi
is an int
*
. In this case the size does not have to be passed to the constructor, because it is already specified by the Matrix/Array type.
Note that Map does not have a default constructor; you must pass a pointer to initialize the object. However, you can work around this requirement (see Changing the mapped array).
Map is flexible enough to accommodate a variety of different data representations. There are two other (optional) template parameters:
Map<typename MatrixType, int MapOptions, typename StrideType>
MapOptions
specifies whether the pointer isAligned
, orUnaligned
. The default isUnaligned
.StrideType
allows you to specify a custom layout for the memory array, using the Stride class. One example would be to specify that the data array is organized in row-major format:Example: Output: int array[8]; for(int i = 0; i < 8; ++i) array[i] = i; cout << "Column-major:\n" << Map<Matrix<int,2,4> >(array) << endl; cout << "Row-major:\n" << Map<Matrix<int,2,4,RowMajor> >(array) << endl; cout << "Row-major using stride:\n" << Map<Matrix<int,2,4>, Unaligned, Stride<1,4> >(array) << endl;
Column-major: 0 2 4 6 1 3 5 7 Row-major: 0 1 2 3 4 5 6 7 Row-major using stride: 0 1 2 3 4 5 6 7
However, Stride is even more flexible than this; for details, see the documentation for the Map and Stride classes.
Using Map variables
You can use a Map object just like any other Eigen type:
Example: | Output: |
---|---|
typedef Matrix<float,1,Dynamic> MatrixType; typedef Map<MatrixType> MapType; typedef Map<const MatrixType> MapTypeConst; // a read-only map const int n_dims = 5; MatrixType m1(n_dims), m2(n_dims); m1.setRandom(); m2.setRandom(); float *p = &m2(0); // get the address storing the data for m2 MapType m2map(p,m2.size()); // m2map shares data with m2 MapTypeConst m2mapconst(p,m2.size()); // a read-only accessor for m2 cout << "m1: " << m1 << endl; cout << "m2: " << m2 << endl; cout << "Squared euclidean distance: " << (m1-m2).squaredNorm() << endl; cout << "Squared euclidean distance, using map: " << (m1-m2map).squaredNorm() << endl; m2map(3) = 7; // this will change m2, since they share the same array cout << "Updated m2: " << m2 << endl; cout << "m2 coefficient 2, constant accessor: " << m2mapconst(2) << endl; /* m2mapconst(2) = 5; */ // this yields a compile-time error | m1: 0.68 -0.211 0.566 0.597 0.823 m2: -0.605 -0.33 0.536 -0.444 0.108 Squared euclidean distance: 3.26 Squared euclidean distance, using map: 3.26 Updated m2: -0.605 -0.33 0.536 7 0.108 m2 coefficient 2, constant accessor: 0.536 |
All Eigen functions are written to accept Map objects just like other Eigen types. However, when writing your own functions taking Eigen types, this does not happen automatically: a Map type is not identical to its Dense equivalent. See Writing Functions Taking Eigen Types as Parameters for details.
Changing the mapped array
It is possible to change the array of a Map object after declaration, using the C++ "placement new" syntax:
Example: | Output: |
---|---|
int data[] = {1,2,3,4,5,6,7,8,9}; Map<RowVectorXi> v(data,4); cout << "The mapped vector v is: " << v << "\n"; new (&v) Map<RowVectorXi>(data+4,5); cout << "Now v is: " << v << "\n"; | The mapped vector v is: 1 2 3 4 Now v is: 5 6 7 8 9 |
Despite appearances, this does not invoke the memory allocator, because the syntax specifies the location for storing the result.
This syntax makes it possible to declare a Map object without first knowing the mapped array's location in memory:
Map<Matrix3f> A(NULL); // don't try to use this matrix yet! VectorXf b(n_matrices); for (int i = 0; i < n_matrices; i++) { new (&A) Map<Matrix3f>(get_matrix_pointer(i)); b(i) = A.trace(); }