MATLAB: How to transfer data from MATLAB to c++ using MEX

mexpca

I use following code to transfer data from c++ to matlab:
void function(vector<vector<double>> mat)
{
size_t rows = mat.size();
size_t cols = mat[0].size();
mxArray* T = mxCreateDoubleMatrix(rows, cols, mxREAL);
double * in_buf = (double *)mxGetPr(T);
for (int i = 0; i<rows; i++)
{
std::memcpy(in_buf + i * cols, &mat[i][0], cols *sizeof(double));
}
}
and pass the mat into matlab function say pca(T)
then
engEvalString(ep, "[coeff , latent] = pca(T);");
my question is how to get the data calculated above and store them in different vectors:
mxArray* coef = engGetVariable(ep, " coeff' ");
mxArray* latent = engGetVariable(ep, " latent' ");
vector<double> latents(rows);
vector<vector<double>> coeff(rows, vector<double>(cols));
memcpy((void *)latents,(void *)mxGetPr(latent), rows *sizeof(double));
memcpy((void *)latents,(void *)mxGetPr(coef), rows *sizeof(double));
I used std::memcpy to do this but it doesn't work ?
Any help will be greatly appreciated.
Regards

Best Answer

Here is some example code for you. It is written as a mex routine but you should be able to adapt the functions to your Engine application. Pay special attention to the fact that due to the different matrix memory ordering (C++ is row based and MATLAB is column based) the conversions are done as transposes in both directions. (Different code could of course be written to transform the memory ordering of the elements so that the sizes remain the same ... but that would entail an element-by-element copy instead of entire row/column at once.)
/* Example code for converting between C++ vector<vector<double>> and mxArray
*
* Because C++ memory is row ordered and MATLAB mxArray memory is column
* ordered, the conversion is done in both directions as the transpose so
* that the memory copies are done as entire rows/colums.
*
* Programmer: James Tursa
*/
/* Includes ----------------------------------------------------------- */
#include "mex.h"
#include <vector>
using namespace std;
// Convert a C++ matrix to an mxArray as the TRANSPOSE
mxArray *vv2mx(vector<vector<double>> mat)
{
size_t rows = mat.size();
size_t cols = mat[0].size();
mxArray *T = mxCreateDoubleMatrix(cols, rows, mxREAL);
double *in_buf = (double *) mxGetData(T);
for (int i = 0; i<rows; i++) {
memcpy( in_buf + i * cols, &mat[i][0], cols *sizeof(double) );
}
return T;
}
// Convert an mxArray to a C++ matrix as the TRANSPOSE
vector<vector<double>> mx2vv(const mxArray *T) {
size_t rows = mxGetN(T);
size_t cols = mxGetM(T);
double *in_buf = (double *) mxGetData(T);
vector<vector<double>> mat(rows, vector<double>(cols));
for (int i = 0; i<rows; i++) {
memcpy( &mat[i][0], in_buf + i * cols, cols *sizeof(double) );
}
return mat;
}
// Display a C++ matrix
void vvdisp(vector<vector<double>> mat)
{
size_t rows = mat.size();
size_t cols = mat[0].size();
for (int i = 0; i<rows; i++) {
for( int j=0; j<cols; j++ ) {
mexPrintf("%f ",mat[i][j]);
}
mexPrintf("\n");
}
return;
}
// Display an mxArray
void mxdisp(const mxArray *T)
{
size_t rows = mxGetM(T);
size_t cols = mxGetN(T);
double *in_buf = (double *) mxGetData(T);
for (int i = 0; i<rows; i++) {
for( int j=0; j<cols; j++ ) {
mexPrintf("%f ",*(in_buf + i + j*rows));
}
mexPrintf("\n");
}
return;
}
/* Gateway ------------------------------------------------------------ */
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
if( nrhs == 0 || !mxIsDouble(prhs[0]) || mxIsSparse(prhs[0]) || mxIsComplex(prhs[0]) ) {
mexErrMsgTxt("Need exactly one full double matrix input");
}
if( nlhs > 1 ) {
mexErrMsgTxt("Too many outputs.");
}
mexPrintf("\nInput matrix:\n");
mxdisp(prhs[0]);
mexPrintf("\nInput matrix as vv:\n");
vector<vector<double>> mat = mx2vv(prhs[0]);
vvdisp(mat);
mexPrintf("\n2*vv:\n");
size_t rows = mat.size();
size_t cols = mat[0].size();
for (int i = 0; i<rows; i++) {
for( int j=0; j<cols; j++ ) {
mat[i][j] *= 2.0;
}
}
vvdisp(mat);
mexPrintf("\nOutput matrix:\n");
plhs[0] = vv2mx(mat);
mxdisp(plhs[0]);
}
And a sample run:
>> mex vectorvector.cpp
Building with 'Microsoft Visual C++ 2013'.
MEX completed successfully.
>> x = reshape(1:6,2,3)
x =
1 3 5
2 4 6
>> vectorvector(x)
Input matrix:
1.000000 3.000000 5.000000
2.000000 4.000000 6.000000
Input matrix as vv:
1.000000 2.000000
3.000000 4.000000
5.000000 6.000000
2*vv:
2.000000 4.000000
6.000000 8.000000
10.000000 12.000000
Output matrix:
2.000000 6.000000 10.000000
4.000000 8.000000 12.000000
ans =
2 6 10
4 8 12