2

I was wondering if anyone could help me understand the syntax of Matlab engine in C. I am a beginner in C and am trying to call a custom Matlab function in C using Matlab Engine. Research that I have done includes reading the documentation for Matlab API, watching the lecture video from Mathworks, researching on Stack Overflow, reading the example eng.c file in Matlab, and Google.

I have come up with this bit of code that compiles but the output returns zero. The input array also doesn't return an array but an int. I can't find a comprehensive walk through video of how to construct a C script that

  1. takes in a vector
  2. feeds it into a Matlab function and
  3. returns output.

The docs explain making an array very clearly, but I can't find information that walks through in detail reading the array into Matlab, then getting output.

Below, please see the code including comments for what I understand each section of code is doing. The example function add_up just calls the sum function on an array. Any help would be great as I am stuck on why this is returning zero.

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "engine.h"
#define BUFSIZE 256

int main() {

    //Open call to matlab engine
    Engine *ep;

    //Use this conjunction with define BUFSIZe 256 to create double
    //extData is a variable to read external data
    //Number in brackets refer to size
    //We are using double in this case and create the external data using initialization
    double extData[10]={1.0,4.0,7.0,2.0,5.0,8.0,3.0,6.0,9.0,10.0};

    //Next step is to make a pointer of type mxArray 
    //These are pointers to an array of any size or type
    mxArray *pVarNum;
    double *outp;

    //After we make a matrix for the double data initialized above
    //Initialized to 0
    pVarNum=mxCreateDoubleMatrix(1,10,mxREAL);

    //Our array needs to be assigned a variable name for Matlab
    //Workspace
    //const char *myDouble = "T";

    //Our matlab matrix is initialized to zero. We need to use
    //The C memcpy function to get the data from extData to
    //Get the array data using the pointer to pVarNum
    //Use mxGetPr, a mxGet function
    memcpy((void *)(mxGetPr(pVarNum)), (void *)extData,sizeof(extData));

    //Place the variable T into the Matlab workspace
    engPutVariable(ep,"T",pVarNum);

    //Evalute test function
    engEvalString(ep, "out=T+1");

    //Make a pointer to the matlab variable
    outp=engGetVariable(ep,"out");
    //Now make a pointer to the C variable
    printf("%d\n",outp);

    printf("Done!\n");
    mxDestroyArray(pVarNum);

    engClose(ep);

    return EXIT_SUCCESS;

}
Cris Luengo
  • 55,762
  • 10
  • 62
  • 120
Lee
  • 33
  • 3

2 Answers2

2

The engGetVariable function returns an mxArray*, not a double*:

double *outp;
/* ... */
outp = engGetVariable(ep, "out");
printf("%d\n", outp);

This should be:

mxArray *out;
double *outp;
int ii;
/* ... */
out = engGetVariable(ep, "out");
outp = mxGetPr(out);
for (ii = 0; ii < 9; ii++) {
   printf("%f, ", outp[ii]);
}
printf("%f\n", outp[9]);

Note also that the %d formatter in printf prints an int, you need to use %f for a double.

Cris Luengo
  • 55,762
  • 10
  • 62
  • 120
  • Thank you for the response and I appreciate the information. I modified the code as suggested and it will now print 0 if I write printf("%f",output). However, if I try to access the elements of outp in any way, it says that there is a segmentation fault, which I looked up to indicate there's a problem with the pointer memory access. I'm guessing this somehow means that outp is not a double? Everything else in your answer is spot on, it just won't return me a double still. – Lee Jul 23 '18 at 17:51
  • Interesting... Is `out` a NULL pointer, or is `outp` a NULL pointer? `engGetVariable` returns NULL if "the request fails" (which I guess means that the requested variable doesn't exist?), and `mxGetPr` would fail if the `mxArray` doesn't have a real component, or is not numeric. Neither of these happen in this code, as far as I can tell. – Cris Luengo Jul 23 '18 at 18:18
  • Thanks for the quick reply. I checked both the input, pVarNum and out. You are correct that there is a problem with out. It is returning Null, even though pVarNum is not Null. I'm trying to find a way to access the elements of pVarNum to ensure that memcpy worked properly, even though it is exactly copied from the api manual. Any other debugging tips would be appreciated also. – Lee Jul 23 '18 at 19:54
  • pVarNum contains the elements that are in extData. So, the conclusion seems to be that there's a problem with the calculation in Matlab, such that it is returning Null. I'm not sure why it would be since I'm just adding one to each number of the array in the example. – Lee Jul 23 '18 at 20:17
  • @Lee: Check the return value of `engPutVariable` (it's supposed to return "0 if successful and 1 if an error occurs"). If `engEvalString` leads to an error inside MATLAB, it won't tell you (though it should really not fail in your case, as long as `T` exists, which should exist if `engPutVariable` was successful). See [here](https://www.mathworks.com/help/matlab/matlab_external/debugging-matlab-functions-used-in-engine-applications.html) for some ideas on how to debug issues in this case. – Cris Luengo Jul 23 '18 at 20:56
  • Thank you for the debugging tip. It was returning 1, which lead to the solution. I wish I had a better answer for why things ended up working, but below please see the answer segment for how things got resolved. – Lee Jul 23 '18 at 22:31
1

The problem was that engputVariable was returning 1, so Matlab engine wasn't taking in the array. I ended up copying and pasting the exact top segment of code from the Matlab engdemo.c (up to the call for engPutVariable), then continuing with my code. Encoding was in ASCII for the working code file. I think the crucial piece is the initial call to open Matlab with a Null string, although I placed this exact piece of code in the non-working script and it did not lead to engPutVariable working.

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "engine.h"
#define  BUFSIZE 256

int main()

{
    Engine *ep;
    mxArray *T = NULL, *outp = NULL;
    double *out;
    int ii;
    char buffer[BUFSIZE+1];
    double time[10] = { 0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0 };


    if (!(ep = engOpen(""))) {
        fprintf(stderr, "\nCan't start MATLAB engine\n");
        return EXIT_FAILURE;
    }

    T = mxCreateDoubleMatrix(1, 10, mxREAL);
    memcpy((void *)mxGetPr(T), (void *)time, sizeof(time));

    engPutVariable(ep, "T", T);


    //Evalute test function. This is new

    engEvalString(ep, "D=add_up(T);");

    //Make a pointer to the matlab variable
    if((outp=engGetVariable(ep,"D"))==NULL){
        printf("Oops!");
    }
    out= mxGetPr(outp);

    //Now make a pointer to the C variable
    for (ii=0; ii<10; ii++) {
        printf("%f\n", out[ii]);
    }
    printf("%f\n",out[2]);

    printf("Done!\n");
    mxDestroyArray(T);
    mxDestroyArray(outp);
    engClose(ep);

    return EXIT_SUCCESS;

}
Cris Luengo
  • 55,762
  • 10
  • 62
  • 120
Lee
  • 33
  • 3