can we use matlab engine from a inside a function in C++
2 visualizaciones (últimos 30 días)
Mostrar comentarios más antiguos
shome
el 18 de Nov. de 2015
Editada: James Tursa
el 18 de Nov. de 2015
I compiled a C++ program to sort double values(matlab does the sorting). it works fine. however when i move the code related to matlab computation to a function, it gives erroneous results.
following is the code with both the formats in a single file. when i execute matlab functions from main it works, when i execute the matlab part from a function(call_matlab_processing) it gives random results.
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "engine.h"
#include <iostream>
#include <vector>
#define BUFSIZE 256
int call_matlab_processing(double double_array[], int size_double_array,double * sorted, double * indices_cpp)
{
for (int i=0;i<size_double_array;i++)
{
std::cout << "double array at "<< i << " "<< double_array[i]<<std::endl;
}
Engine *ep;
mxArray *T = NULL, *result = NULL, *indices=NULL;
/*
* Call engOpen with a NULL string. This starts a MATLAB process
* on the current host using the command "matlab".
*/
if (!(ep = engOpen(""))) {
fprintf(stderr, "\nCan't start MATLAB engine\n");
return 1;
}
T = mxCreateDoubleMatrix(1,size_double_array, mxREAL);
memcpy((void *)mxGetPr(T), (void *)double_array, sizeof(double_array));
/** Place the variable T into the MATLAB workspace */
engPutVariable(ep, "T", T);
engEvalString(ep, "[D I] = sort(T,'descend')");
engEvalString(ep, "dlmwrite('myFile.txt',D)");
result = engGetVariable(ep,"D");
indices = engGetVariable(ep,"I");
sorted=(double *)mxGetData(result);
indices_cpp=(double *)mxGetData(indices);
/* for (int i=0;i<10;i++)
{
std::cout << "sorted= " <<*sorted << " indices= " << *indices_cpp <<std::endl;
sorted++;
indices_cpp++;
}*/
mxDestroyArray(T);
mxDestroyArray(result);
mxDestroyArray(indices);
engEvalString(ep, "close;");
engClose(ep);
return 0;
}
int main()
{
int size_double_array=10;
double double_array[10]={ 0, 5, 2, 7, 3, 9, 1, 6, 8, 4 };
double * sorted;
double * indices_cpp;
Engine *ep;
mxArray *T = NULL, *result = NULL, *indices=NULL;
if (!(ep = engOpen(""))) {
fprintf(stderr, "\nCan't start MATLAB engine\n");
return 1;
}
T = mxCreateDoubleMatrix(1,size_double_array, mxREAL);
memcpy((void *)mxGetPr(T), (void *)double_array, sizeof(double_array));
engPutVariable(ep, "T", T);
engEvalString(ep, "[D I] = sort(T,'descend')");
engEvalString(ep, "dlmwrite('myFile.txt',D)");
result = engGetVariable(ep,"D");
indices = engGetVariable(ep,"I");
sorted=(double *)mxGetData(result);
indices_cpp=(double *)mxGetData(indices);
mxDestroyArray(T);
mxDestroyArray(result);
mxDestroyArray(indices);
engEvalString(ep, "close;");
engClose(ep);
// int result=call_matlab_processing(double_array,10,sorted,indices_cpp);
for (int i=0;i<10;i++)
{
std::cout << "sorted= " <<*sorted << " indices= " << *indices_cpp <<std::endl;
sorted++;
indices_cpp++;
}
std::cout << "Done"<< std::endl;
return EXIT_SUCCESS;
}
2 comentarios
Abdelmoumen Bacetti
el 18 de Nov. de 2015
Please, use "{}code" to format your code.
I'm sure if you refer to one of Matlab's examples, you will find a clue.
Respuesta aceptada
James Tursa
el 18 de Nov. de 2015
Editada: James Tursa
el 18 de Nov. de 2015
You have a fundamental flaw in your code. You free the memory behind the pointers that you use downstream in your code. E.g.,
result = engGetVariable(ep,"D"); // <-- Creates the mxArray result, including the data area
indices = engGetVariable(ep,"I"); // <-- Creates the mxArray indices, including the data area
sorted=(double *)mxGetData(result); // <-- Gets pointer to data area of result
indices_cpp=(double *)mxGetData(indices); // <-- Gets pointer to data area of indices
mxDestroyArray(T);
mxDestroyArray(result); // <-- Wipes out result, *and* the memory behind sorted
mxDestroyArray(indices); // <-- Wipes out indices, *and* the memory behind indices_cpp
// So at this point in the code, both of the pointers sorted and indices_cpp are *invalid*
engEvalString(ep, "close;");
engClose(ep);
// Code downstream of here uses *invalid* pointers. Anything can happen.
// Could get lucky good results, or random bad results, or even a program bomb.
// int result=call_matlab_processing(double_array,10,sorted,indices_cpp);
for (int i=0;i<10;i++)
{
std::cout << "sorted= " <<*sorted << " indices= " << *indices_cpp <<std::endl;
sorted++;
indices_cpp++;
}
You need to delay executing these two lines until after you are done using their data areas:
mxDestroyArray(result);
mxDestroyArray(indices);
3 comentarios
James Tursa
el 18 de Nov. de 2015
Can you post the current code you are using that gets the wrong result so I can look at it? To answer your question directly, the answer is YES you can call the MATLAB Engine from inside a function. (Strictly speaking, main is a function also)
James Tursa
el 18 de Nov. de 2015
Editada: James Tursa
el 18 de Nov. de 2015
Oh, I just noticed these lines:
int call_matlab_processing(double double_array[], int size_double_array,double * sorted, double * indices_cpp)
{
:
memcpy((void *)mxGetPr(T), (void *)double_array, sizeof(double_array));
The first argument of the function call_matlab_processing is the variable double_array. It turns out that this variable is of type "pointer to double" (i.e., double * ). I know it looks like you have declared it as an array, but that syntax is misleading. When used in a function argument, the notation
double variable_name[]
is equivalent to the notation
double *variable_name
In fact, even if you had use an explicit size it would have made no difference to the compiler. I.e., this notation in a function argument
double variable_name[10]
is also equivalent to the notation
double *variable_name
That is, the compiler sees that argument as a pointer, not as an array (you can't pass whole arrays in C/C++ function arguments this way). So downstream in your code when you use sizeof(double_array), it is equivalent to doing sizeof(double * ). The result will be either 4 (on 32-bit) or 8 (on 64-bit). So you are definitely not copying all of the elements in that memcpy call. You need to do this instead:
memcpy((void *)mxGetPr(T), (void *)double_array, size_double_array*sizeof(double));
Note that this is entirely different from what you have in main:
double double_array[10]={ 0, 5, 2, 7, 3, 9, 1, 6, 8, 4 };
:
memcpy((void *)mxGetPr(T), (void *)double_array, sizeof(double_array));
Here in main double_array is in fact an array, so sizeof(double_array) will be the full memory for this array, i.e. 10*8 = 80 bytes.
Also, FYI you don't really need the (void *) casts since converting pointers to/from void * is something the C/C++ compiler will automatically do for you.
Más respuestas (0)
Ver también
Categorías
Más información sobre Deploy to C++ Applications Using MATLAB Data API (C++11) en Help Center y File Exchange.
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!