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

北城余情 提交于 2019-12-10 11:56:24

问题


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?


回答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;
}



回答2:


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




回答3:


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


来源:https://stackoverflow.com/questions/26774830/call-matlab-in-c-code-using-methods-in-engine-h

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!