Create an Eigen Matrix from a C array
Asked Answered
M

3

6

What I would like to do essentially is implement this function:

template<typename T>
Matrix<T, Dynamic, Dynamic, ColMajor>* dataToEigen(T* const data, const int rows, const int cols);

without copying any data. I know the standard way to accomplish something like this is with a Map, but I have several issues with this approach.

  1. I don't want to rewrite the rest of my code to accept Maps as inputs (without copying the Map into a temporary matrix, that is). I know I could do this by generalizing my functions to take MatrixBase objects as inputs, but I've defined specific Matrix templates in my inputs for a reason - if my function takes a Matrix<T, Dynamic, Dynamic, ColMajor>, then it's because only matrices of that type should be used as inputs.

  2. Ideally, I'd like the created Matrix to take ownership of the data pointer, so I can just manage the Matrix via shared_ptr and not have to touch the original data pointer again.

My initial thought was that I could do something like create an uninitialized dynamically sized Matrix object, and then just set the object's dimensions and data pointer, but this doesn't seem to be possible in the Eigen API. Does anyone know of any workarounds?

Mccalla answered 4/6, 2013 at 18:46 Comment(0)
F
3

There is little chance that Eigen::Matrix will ever be allowed to directly wrap external buffers, and there are many good reasons for that including ABI compatibility, API consistency across dynamically and statically allocated matrices.

An ugly workaround would be to define a struct with the same layout as MatrixX_:

template<typename T> struct Foo {
  T* data;
  DenseIndex rows, cols;
  Matrix<T, Dynamic, Dynamic, ColMajor>& asMatrix() {
    return reinterpret_cast<Matrix<T, Dynamic, Dynamic, ColMajor>&>(*this);
  }
};

Another solution would be to move to the devel branch (pretty stable), and use the new Ref<> class that was designed to solve your exact problem, and more. Its documentation should be enough to use it properly. The only difficulty is that you be able to easily templatize the scalar type because Ref<> is not a base class of Matrix or Map, and so you will have to either call your fonction by specifying the scalar type explicitly, or create the Ref<> copy yourself:

foo<T>(M);
foo(Ref<MatrixXd>(M));
Francinefrancis answered 4/6, 2013 at 23:26 Comment(2)
Your ugly workaround seems to be the simplest solution, but isn't that fairly dangerous? I'm not too worried at the moment about actual compiled code being portable, but is there any guarantee Foo and a templated MatrixX would end up with the same in-memory arrangement? As for the second option, it sounds like I could rewrite my methods to look something like: template<typename T> void Foo(const Ref<const Matrix<T, Dynamic, Dynamic, ColMajor> >) and this would allow them to accept both Matrix<T, Dynamic, Dynamic, ColMajor> and Map<Matrix<T, Dynamic, Dynamic, ColMajor>> inputs?Mccalla
The memory layout is guaranteed (ABI compatibility across Eigen versions). For Ref<> yes, that's how to use it. The problem is that it is less convenient when partially defined with template parameter because Matrix or Map do not inherit Ref<> and therefore the compiler won't be allowed to implicitly instantiate the right template arguments. So you either have to explicitly provide it, or explicitly do the conversion to Ref<>, or if you're concerned by only 2 or 3 scalar types, you can also make have the 2-3 overloads calls the generic version (cleanest solution).Francinefrancis
G
0

Creating Eigen matrix from raw C/C++ array? And the length of array is runtime-determined? You may just take my example:

float dotproduct_eigen(size_t len, float* va, float* vb)
{
    Eigen::Map<Eigen::Matrix<float, 1, Eigen::Dynamic, Eigen::RowMajor>> vva(va, len);
    Eigen::Map<Eigen::Matrix<float, 1, Eigen::Dynamic, Eigen::RowMajor>> vvb(vb, len);
    float res = vva.dot(vvb);
    return res;
}
Glycoside answered 14/2, 2021 at 14:3 Comment(0)
M
-1

I think the solution is as easy as the following:

float **data = new float[numRows][numCols];
MatrixXf M(numRows,numCols);
M.data() = data;

By default, the data in a Matrix is organised Column Major, so if you want your matrix to access the float** data in a Row Major order, you could transpose the matrix after the assignment.

Machine answered 1/7, 2013 at 10:21 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.