передавать данные между C ++ Eigen Matrix и MATLAB mxArray с помощью массива ячеек - PullRequest
2 голосов
/ 09 марта 2019

Я хотел бы передать данные между Eigen Matrix / Vector и mex массивами.В следующем коде я определил мекс-массив с именем y_output, который содержит массив ячеек.Переменная y_output будет передана в MATLAB.Каждый элемент в y_output является вектором, но разной длины.Я хотел бы передать указатель, который указывает на собственные векторы, в мекс-массив y_output.

Обратите внимание, что данные, хранящиеся в y, будут изменены с помощью пользовательской функции.После вызова функции я бы предположил, что данные, хранящиеся в y_output, будут изменены соответствующим образом.Однако я не могу напрямую передать указатель из y_output в y.Есть ли способ сделать это возможным?Спасибо!

Этот вопрос похож, но отличается от вопроса на Передать матрицу C ++ Eigen в вывод Matlab mex .Этот вопрос спрашивает, как передать массив матриц, в то время как вопрос в этой ссылке спрашивает, как передать матрицу.

#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;

}

Ответы [ 2 ]

1 голос
/ 09 марта 2019

Ваше решение копирует данные как для ввода, так и для вывода MyFunc.Можно передать оба аргумента, используя std::vector из Eigen::Map объектов.Следующий код основан на вашем ответе.Строки, начинающиеся с //--, были удалены из вашего кода и заменены следующей строкой.

Как примечание: избегайте выделения массивов с new (в 99,99% всех случаев), но используйте std::vector вместо.Это обеспечивает освобождение всех ресурсов, когда объект выходит из области видимости.Кроме того, в MyFunc вам не нужно угадывать размер y и 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;

}
0 голосов
/ 09 марта 2019

Я нашел способ достичь того, чего хотел.Важный шаг - сначала вызвать мою собственную функцию, а в конце назначить данные, хранящиеся в y, на y_output.Я включил модифицированный код ниже, чтобы он мог быть полезен всем, кто интересуется.

#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]();


 // 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);
    }


}

ptemp = NULL;


// set output
plhs[0] = y_output;

}
...