Call Matlab in C++ code - using methods in engine.h
Asked Answered
P

3

0

I write a C++ program whose only purpose is to call Matlab code. I have a main routine, which

  1. read data in a file (matrices with high dimension 90000*24) into C++ structures

  2. pass these structures to Matlab code

  3. launch the Matlab routine with these structures in argument

  4. get the output data from Matlab and store them in C++ structures

In 2/, matrices are fields in a Matlab struct. The struct, say MATLAB_STRUCT has several matrix fields, MATLAB_STRUCT.Z1, MATLAB_STRUCT.Z2,... and some float fields MATLAB_STRUCT.flt1,...

What is the correct approach to set C++ matrices (double**) as the fields of the Matlab struct? So far, I came up with this, using engine.h

    mxArray* labcoeffs_array = convertVectorToMxArray(labcoeffs, 
                                                         coeff_nrows, coeff_ncols); 
    const std::string lab_coeff_name = "MATLAB_STRUCT.labCoef";
    engPutVariable(ep, lab_coeff_name.c_str(), labcoeffs_array);

where convertVectorToMxArray is an helper I wrote to convert double** to a mxArray,

inline mxArray *convertVectorToMxArray(double** mat, 
                                              const int nb_rows, const int nb_cols)
{
    mxArray *outputMxArray = mxCreateDoubleMatrix(
        (int) nb_rows,
        (int) nb_cols,
        mxREAL);

    double *data = (double*) mxGetData(outputMxArray);
    for (int r = 0; r < nb_rows; r++)
        for (int c = 0; c < nb_cols; c++)
            data[r + c*nb_rows] = (double)mat[r][c];

    return outputMxArray;
};

But I have seen some other technique for assigning a value to a Matlab struct in the Cpp code (a float value though, not a matrix), imitating the command line syntax in a C++ string:

std::string setStruct = "MATLAB_STRUCT" + "." + "nB" + " = " + str->nB + ";";
matlabExecute(ep, setStruct);

with ep a pointer to a Matlab engine.

  • Is it possible to adapt this approach with command line to assigning a value to a matrix type field of a Matlab struct?

  • what is the best approach to assign a value to a matrix type field of a Matlab struct?

Pygidium answered 6/11, 2014 at 8:28 Comment(0)
P
0

To create a matrix field in a struct, one option is to create a temp variable, and then to assign its value to a field of the struct:

// Create temp variable
mxArray* array = convertVectorToMxArray(mat, nb_rows, nb_cols);  
const std::string temp_name = array_name + "_temp";
int ret = engPutVariable(ep, temp_name.c_str(), array);

// Set variable to struct field
const std::string cmd = std::string(array_name + " = " + temp_name + "; ");
matlabExecute(ep, cmd);

// Delete array
mxDestroyArray(array);
Pygidium answered 14/11, 2014 at 15:27 Comment(0)
M
1

Here is a made-up example similar to what you described:

#include <iostream>
#include <vector>
#include "engine.h"

// create mxArray matrix from an array of data
mxArray* data_to_mxarray(const double *data, int nrows, int ncols)
{
    mxArray *arr = mxCreateDoubleMatrix(nrows, ncols, mxREAL);
    double *x = mxGetPr(arr);
    for (int c=0; c<ncols; c++) {
        for (int r=0; r<nrows; r++) {
            *x = data[r + c*nrows];
            x++;
        }
    }
    return arr;
}

int main()
{
    // step 1: some data
    const char *fieldnames[2] = {"z1", "z2"};
    double z1[] = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0};
    double z2[] = {7.0, 8.0, 9.0, 0.0, 1.0, 2.0};

    // open connection to MATLAB
    Engine *ep = engOpen("");

    // create structure with desired fields
    mxArray *st = mxCreateStructMatrix(1, 1, 2, fieldnames);
    mxSetField(st, 0, "z1", data_to_mxarray(z1,2,3));
    mxSetField(st, 0, "z2", data_to_mxarray(z2,3,2));

    // step 2: pass struct to MATLAB workspace
    engPutVariable(ep, "st", st);

    // for the sake of this example, lets create a fake function
    engEvalString(ep, "my_function = @(x) magic(3);");

    // step 3: call some function with the struct as input
    engEvalString(ep, "out = my_function(st);");

    // step 4: retrieve function output
    mxArray *out = engGetVariable(ep, "out");

    // extract data out of it. This depends on the type of output.
    // Say the result was a numeric array
    double *x = mxGetPr(out);
    size_t len = mxGetNumberOfElements(out);
    std::vector<double> v;
    v.resize(len);
    v.assign(x, x+len);
    for (int i=0; i<v.size(); i++) {
        std::cout << v[i] << std::endl;
    }

    // cleanup
    mxDestroyArray(out);
    mxDestroyArray(st);
    engClose(ep);

    return 0;
}
Myrnamyrobalan answered 9/11, 2014 at 9:47 Comment(0)
D
0

You have already discovered engPutVariable, which is an efficient way to insert variables into the Engine workspace. It can do this for mxArray of any type, not just a double matrix.

mxCreateDoubleMatrix() and mxGetData() are both functions in the "C/C++ Matrix Library API", which is documented here: http://www.mathworks.com/help/matlab/cc-mx-matrix-library.html

Starting from those functions, you can find other functions for dealing with MATLAB struct variables directly from C++, including mxCreateStructMatrix() and mxSetField(). A MATLAB struct variable is a "container" type, meaning each field is itself a MATLAB variable, so you'd set the appropriate field to the double mxArray you've already created.

If you really need to set a field of an existing struct, you can put the variable as a double array as you do currently. Then, the matlabExecute() approach you mention is perfect. It just takes the string that you want MATLAB to execute, which in this case is just "MATLAB_STRUCT.fieldname = existing_variable;"

Duero answered 6/11, 2014 at 14:9 Comment(0)
P
0

To create a matrix field in a struct, one option is to create a temp variable, and then to assign its value to a field of the struct:

// Create temp variable
mxArray* array = convertVectorToMxArray(mat, nb_rows, nb_cols);  
const std::string temp_name = array_name + "_temp";
int ret = engPutVariable(ep, temp_name.c_str(), array);

// Set variable to struct field
const std::string cmd = std::string(array_name + " = " + temp_name + "; ");
matlabExecute(ep, cmd);

// Delete array
mxDestroyArray(array);
Pygidium answered 14/11, 2014 at 15:27 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.