I would like to pass data between Eigen Matrix/Vector and mex arrays. In the following code, I defined a mex array called y_output, which contains a cell array. The variable y_output will be passed to MATLAB. Each element in y_output is a vector but with different lengths. I would like to pass a pointer that points to Eigen vectors to the mex array y_output.
Notice that the data stored in y will be modified with a user-defined function. After calling the function, I would assume that the data stored in y_output will be modified corresponding. However, I cannot directly pass the pointer from y_output to y. Is there any way to make it possible? Thanks!
This question is similar but different from the one at Pass C++ Eigen matrix to Matlab mex output. This question is asking how to pass an array of matrices, while the question in that link is asking how to pass a matrix.
#include "mex.h"
#include "matrix.h"
#include <Eigen>
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
// prhs[0]: a cell array of length T, each element is a vector with different lengths
mwSize T = mxGetNumberOfElements(prhs[0]);
mwSize* n = new mwSize[T];
Eigen::VectorXd* z = new Eigen::VectorXd[T];
for(int t=0; t<T; t++){
n[t] = mxGetNumberOfElements(mxGetCell(prhs[0], t));
z[t] = Eigen::Map<Eigen::VectorXd>(mxGetPr(mxGetCell(prhs[0], t)), n[t]);
}
// create a cell matrix with T rows and one columns
mxArray* y_output = mxCreateCellMatrix(T,1);
// create corresponding Eigen objects
Eigen::VectorXd* y = new Eigen::VectorXd[T]();
Eigen::VectorXd y_temp(n[0]); y_temp.setZero();
for(int t=0; t<T; t++){
mxSetCell(y_output, t, mxCreateDoubleMatrix(n[t], 1, mxREAL));
y[t] = Eigen::VectorXd::Zero(n[t]);
y_temp.resize(n[t]);
Eigen::Map<Eigen::VectorXd> y[t](mxGetPr(mxGetCell(y_output, t)), n[t]); // This is not correct!
}
// Myfun(y, z);
// set output
plhs[0] = y_output;
}
Your solution copies data around both for the input and the output of MyFunc
. It is possible to pass both arguments using a std::vector
of Eigen::Map
objects. The following code is based on your answer. Lines starting with //--
were removed from your code and replaced by the line which follow.
As a sidenote: Avoid allocating arrays with new
(in 99.99% of all cases), but use a std::vector
instead. This takes care of deallocating all resources when the object gets out of scope.
Also, in MyFunc
you don't have to guess the size of y
and z
.
#include "mex.h"
#include "matrix.h"
//-- #include <Eigen> <-- this should be <Eigen/Eigen>, but likely Eigen/Core suffices
// Perhaps you also need to change your include-path
#include <Eigen/Core>
#include <vector>
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
// prhs[0]: a cell array of length T, each element is a vector with different lengths
mwSize T = mxGetNumberOfElements(prhs[0]);
//-- mwSize* n = new mwSize[T];
std::vector<mwSize> n(T);
//-- Eigen::VectorXd* z = new Eigen::VectorXd[T];
std::vector<Eigen::Map<const Eigen::VectorXd> > z; // input vector of Maps
z.reserve(T);
for(int t=0; t<T; t++){
// Note: You don't actually seem to need n[t], except for creating y_output
n[t] = mxGetNumberOfElements(mxGetCell(prhs[0], t));
//-- z[t] = Eigen::Map<Eigen::VectorXd>(mxGetPr(mxGetCell(prhs[0], t)), n[t]);
z.emplace_back(mxGetPr(mxGetCell(prhs[0], t)), n[t]);
}
// create a cell matrix with T rows and one columns
mxArray* y_output = mxCreateCellMatrix(T,1);
// create corresponding Eigen objects
//-- Eigen::VectorXd* y = new Eigen::VectorXd[T]();
std::vector<Eigen::Map<Eigen::VectorXd> > y; // output vector of Maps
y.reserve(T);
// This must be called after setting up y:
//-- Myfun(y, z);
//-- double* ptemp;
for(int t=0; t<T; t++){
mxSetCell(y_output, t, mxCreateDoubleMatrix(n[t], 1, mxREAL));
//-- ptemp = mxGetPr(mxGetCell(y_output, t));
//-- // assign the data stored in y[t] to the contents in y_output.
//-- for(int i=0; i<n[t]; i++){
//-- //mxGetPr(mxGetCell(y_output, t))[i] = y[t](i);
//-- ptemp[i] = y[t](i);
//-- }
y.emplace_back(mxGetPr(mxGetCell(y_output, t)), n[t]);
}
// Now call Myfun, but the function now needs to accept vectors of Eigen::Map, instead of pointers to VectorXd
// It should be possible to keep the Code inside Myfun unchanged
// Myfun(y, z);
//-- ptemp = NULL;
// set output
plhs[0] = y_output;
}