Convert Eigen Matrix to C array
Asked Answered
T

7

72

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?

Topotype answered 9/12, 2011 at 8:53 Comment(4)
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?Kone
@Kone Eigen refers to a library.Tresa
@ChristianRau: it can, but I want to make absolutely sure that that's what lil is referring to.Kone
@ChristianRau yes, I refer to eigen.tuxfamily.orgTopotype
Z
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.
Zonation answered 9/12, 2011 at 9:59 Comment(5)
@Longtin For future someone: Eigen::Matrix<float, -1, 3, Eigen::RowMajor> vertices_;Skew
It's weird, but the data() member function is undocumented for some reason. I'm looking here: eigen.tuxfamily.org/…Rigsby
@enigmaticPhysicist: eigen.tuxfamily.org/dox/…Zonation
Oh, there it is. Thanks, @janneb.Rigsby
A side-note that if the matrix is computed by lazy evaluation, e.g. Eigen::Matrix<float,2,2>::Random(), .eval() must be called first for the matrix to have the data function available. E.g. auto x = Eigen::Matrix<float,2,2>::Random().eval(); auto data_ptr = x.data();Kleeman
S
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/

Shinny answered 25/4, 2015 at 12:14 Comment(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.Pallette
Just ctrl+c ctrl+v from the site using incorrect information! This does not work. Someone can please correct this answer? Same here @PalletteLongtin
@Pallette 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 CMapes
why is this not possible for the following type of data fftw_complex *mat = (fftw_complex*) fftw_malloc((((n)*(n)))* sizeof(fftw_complex)); ??Roadstead
M
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.

Mapes answered 7/2, 2018 at 19:40 Comment(0)
T
3

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

Tourbillion answered 19/6, 2012 at 11:52 Comment(0)
P
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
Pallette answered 26/10, 2016 at 20:6 Comment(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.Engaging
M
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

Mcmaster answered 27/8, 2020 at 9:7 Comment(0)
P
-6
ComplexEigenSolver < MyMatrix > es;
complex<double> *eseig;
es.compute(H);
es.eigenvalues().transpose();
eseig=(complex<double> *)es.eigenvalues().data();
Photoactinic answered 13/12, 2013 at 3:50 Comment(1)
What does computing the eigenvalues and eigenvectors have to do with this question?Emblements

© 2022 - 2024 — McMap. All rights reserved.