71

The Eigen library can map existing memory into Eigen matrices.

float array[3];
Map<Vector3f>(array, 3).fill(10);
int data[4] = 1, 2, 3, 4;
Matrix2i mat2x2(data);
MatrixXi mat2x2 = Map<Matrix2i>(data);
MatrixXi mat2x2 = Map<MatrixXi>(data, 2, 2);

My question is, how can we get c array (e.g. float[] a) from eigen matrix (e.g. Matrix3f m)? What it the real layout of eigen matrix? Is the real data stored as in normal c array?

outis
  • 75,655
  • 22
  • 151
  • 221
lil
  • 2,527
  • 4
  • 22
  • 15
  • 1
    These aren't standard datatypes. Is "Eigen" the name of the library, or a reference to the mathematical underpinnings? If the latter what library are the types from? Also, C doesn't have template types. Since matrices are 2-dimensional, what exactly do you want in the plain array? A particular row or column, or the entire matrix reshaped to one dimension? – outis Dec 09 '11 at 09:20
  • @outis Eigen refers to a [library](http://eigen.tuxfamily.org/index.php?title=Main_Page). – Christian Rau Dec 09 '11 at 11:47
  • @ChristianRau: it can, but I want to make absolutely sure that that's what lil is referring to. – outis Dec 09 '11 at 11:51
  • @ChristianRau yes, I refer to http://eigen.tuxfamily.org/ – lil Dec 13 '11 at 07:05

7 Answers7

74

You can use the data() member function of the Eigen Matrix class. The layout by default is column-major, not row-major as a multidimensional C array (the layout can be chosen when creating a Matrix object). For sparse matrices the preceding sentence obviously doesn't apply.

Example:

ArrayXf v = ArrayXf::LinSpaced(11, 0.f, 10.f);
// vc is the corresponding C array. Here's how you can use it yourself:
float *vc = v.data();
cout << vc[3] << endl;  // 3.0
// Or you can give it to some C api call that takes a C array:
some_c_api_call(vc, v.size());
// Be careful not to use this pointer after v goes out of scope! If
// you still need the data after this point, you must copy vc. This can
// be done using in the usual C manner, or with Eigen's Map<> class.
janneb
  • 36,249
  • 2
  • 81
  • 97
  • 4
    @Pedro77 For future someone: `Eigen::Matrix vertices_;` – Calle Bergström Sep 09 '18 at 21:43
  • It's weird, but the data() member function is undocumented for some reason. I'm looking here: http://eigen.tuxfamily.org/index.php?title=Special%3ASearch&profile=default&search=%22data%28%29%22&fulltext=Search – enigmaticPhysicist Oct 24 '18 at 02:38
  • @enigmaticPhysicist: http://eigen.tuxfamily.org/dox/classEigen_1_1PlainObjectBase.html#ac54123f62de4c46a9107ff53890b6116 – janneb Oct 24 '18 at 06:29
  • Oh, there it is. Thanks, @janneb. – enigmaticPhysicist Oct 25 '18 at 02:31
  • 1
    A side-note that if the matrix is computed by lazy evaluation, e.g. `Eigen::Matrix::Random()`, `.eval()` must be called first for the matrix to have the `data` function available. E.g. `auto x = Eigen::Matrix::Random().eval(); auto data_ptr = x.data();` – Greg Kramida Jul 28 '22 at 19:35
23

To convert normal data type to eigen matrix type

  double *X; // non-NULL pointer to some data

You can create an nRows x nCols size double matrix using the Map functionality like this:

  MatrixXd eigenX = Map<MatrixXd>( X, nRows, nCols );

To convert eigen matrix type into normal data type

  MatrixXd resultEigen;   // Eigen matrix with some result (non NULL!)
  double *resultC;        // NULL pointer <-- WRONG INFO from the site. resultC must be preallocated!
  Map<MatrixXd>( resultC, resultEigen.rows(), resultEigen.cols() ) =   resultEigen;

In this way you can get in and out from eigen matrix. Full credits goes to http://dovgalecs.com/blog/eigen-how-to-get-in-and-out-data-from-eigen-matrix/

Pedro77
  • 5,176
  • 7
  • 61
  • 91
GPrathap
  • 7,336
  • 7
  • 65
  • 83
  • 4
    The second part makes no sense. How can Eigen::Map magically take a NULL pointer (resultC) and copy data to it?? Indeed, I tried the code above with a sample 2x2 matrix and the Map segfaults, as you'd expect. – eraoul Oct 26 '16 at 20:00
  • 2
    Just ctrl+c ctrl+v from the site using incorrect information! This does not work. Someone can please correct this answer? Same here @eraoul – Pedro77 Apr 02 '17 at 00:37
  • 1
    @eraoul The first part doesn't make sense either. This answer produces wrong results because it does not account for the different storage order in Eigen and C – RHertel Feb 08 '18 at 05:29
  • why is this not possible for the following type of data ``fftw_complex *mat = (fftw_complex*) fftw_malloc((((n)*(n)))* sizeof(fftw_complex)); `` ?? – Jamie Jun 30 '22 at 20:41
8

If the array is two-dimensional, one needs to pay attention to the storage order. By default, Eigen stores matrices in column-major order. However, a row-major order is needed for the direct conversion of an array into an Eigen matrix. If such conversions are performed frequently in the code, it might be helpful to use a corresponding typedef.

using namespace Eigen;
typedef Matrix<int, Dynamic, Dynamic, RowMajor> RowMatrixXi;

With such a definition one can obtain an Eigen matrix from an array in a simple and compact way, while preserving the order of the original array.

From C array to Eigen::Matrix

int nrow = 2, ncol = 3;
int arr[nrow][ncol] =  { {1 ,2, 3},  {4, 5, 6} }; 
Map<RowMatrixXi> eig(&arr[0][0], nrow, ncol);

std::cout << "Eigen matrix:\n" << eig << std::endl;

// Eigen matrix:
// 1 2 3
// 4 5 6

In the opposite direction, the elements of an Eigen matrix can be transferred directly to a C-style array by using Map.

From Eigen::Matrix to C array

int arr2[nrow][ncol];
Map<RowMatrixXi>(&arr2[0][0], nrow, ncol) = eig;

std::cout << "C array:\n";
for (int i = 0; i < nrow; ++i) {
  for (int j = 0; j < ncol; ++j) {
    std::cout << arr2[i][j] << " ";
  }
  std::cout << "\n";
}

// C array:
// 1 2 3 
// 4 5 6 

Note that in this case the original matrix eig does not need to be stored in row-major layout. It is sufficient to specify the row-major order in Map.

RHertel
  • 23,412
  • 5
  • 38
  • 64
3

You need to use the Map function again. Please see the example here: http://forum.kde.org/viewtopic.php?f=74&t=95457

Prashanth
  • 31
  • 1
0

The solution with Map above segfaults when I try it (see comment above).

Instead, here's a solution that works for me, copying the data into a std::vector from an Eigen::Matrix. I pre-allocate space in the vector to store the result of the Map/copy.

Eigen::MatrixXf m(2, 2);
m(0, 0) = 3;
m(1, 0) = 2.5;
m(0, 1) = -1;
m(1, 1) = 0;

cout << m << "\n";

// Output:
//    3  -1
// 2.5   0

// Segfaults with this code: 
//
// float* p = nullptr;
// Eigen::Map<Eigen::MatrixXf>(p, m.rows(), m.cols()) = m;

// Better code, which also copies into a std::vector:

// Note that I initialize vec with the matrix size to begin with:
std::vector<float> vec(m.size());
Eigen::Map<Eigen::MatrixXf>(vec.data(), m.rows(), m.cols()) = m;

for (const auto& x : vec)
  cout << x << ", ";
cout << "\n";

// Output: 3, 2.5, -1, 0
eraoul
  • 1,072
  • 12
  • 19
  • 1
    I just want to point out here that this is expected that the commented out code segfaults. `Map` does not allocate memory, so you're trying to copy data into a `nullptr` essentially. – niosus May 19 '21 at 09:56
0

I tried this : passing the address of the element at (0,0) and iterating forward.

Eigen::Matrix<double, 3, 8> coordinates3d;
coordinates3d <<    0.0,  0.0,  1.0,  1.0,  0.0,  0.0,  1.0,  1.0,
                    0.0,  1.0,  1.0,  0.0,  0.0,  1.0,  1.0,  0.0,
                    1.0,  1.0,  1.0,  1.0,  0.0,  0.0,  0.0,  0.0;
double *p = &coordinates3d(0,0);
std::vector<double> x2y2;
x2y2.assign(p, p + coordinates3d.size());

for(int i=0;i < coordinates3d.size(); i++) {
    std::cout <<x2y2[i];
}

This is the output : 001011111101000010110100 The data is stored row-major it seems

-6
ComplexEigenSolver < MyMatrix > es;
complex<double> *eseig;
es.compute(H);
es.eigenvalues().transpose();
eseig=(complex<double> *)es.eigenvalues().data();