Поиск…


Проверить количество входов / выходов в MEX-файле C ++

В этом примере мы напишем базовую программу, которая проверяет количество входов и выходов, переданных MEX-функции.

В качестве отправной точки нам нужно создать файл C ++, реализующий «шлюз MEX». Это функция, выполняемая при вызове файла из MATLAB.

testinputs.cpp

// MathWorks provided header file
#include "mex.h"

// gateway function
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
    // This function will error if number of inputs its not 3 or 4
    // This function will error if number of outputs is more than 1

    // Check inputs:
    if (nrhs < 3 || nrhs > 4) {
        mexErrMsgIdAndTxt("Testinputs:ErrorIdIn",
            "Invalid number of inputs to MEX file.");
    }

    // Check outputs:
    if (nlhs > 1) {
        mexErrMsgIdAndTxt("Testinputs:ErrorIdOut",
                "Invalid number of outputs to MEX file.");
    }
}

Во-первых, мы mex.h заголовок mex.h который содержит определения всех необходимых функций и типов данных для работы с API MEX. Затем мы реализуем функцию mexFunction как показано на рисунке, где ее подпись не должна меняться независимо от реально используемых входов / выходов. Параметры функции следующие:

  • nlhs : количество запрошенных результатов.
  • *plhs[] : массив, содержащий все выходы в формате API MEX.
  • nrhs : Количество пропущенных данных.
  • *prhs[] : массив, содержащий все входы в формате MEX API.

Затем мы проверяем количество аргументов ввода / вывода, и если проверка не выполняется, возникает ошибка с использованием функции mexErrMsgIdAndTxt (она ожидает идентификатор имени somename:iD , простой «ID» не будет работать).


После того как файл скомпилирован как mex testinputs.cpp , функцию можно вызвать в MATLAB как:

>> testinputs(2,3)
Error using testinputs. Invalid number of inputs to MEX file.

>> testinputs(2,3,5)

>> [~,~] = testinputs(2,3,3)
Error using testinputs. Invalid number of outputs to MEX file.

Введите строку, измените ее на C и выведите ее

В этом примере мы иллюстрируем манипуляции с строками в MATLAB MEX. Мы создадим MEX-функцию, которая принимает строку как входную информацию от MATLAB, скопирует данные в C-строку, mxArray ее и преобразует обратно в mxArray возвращенный стороне MATLAB.

Основная цель этого примера - показать, как строки могут быть преобразованы в C / C ++ из MATLAB и наоборот.

stringIO.cpp

#include "mex.h"
#include <cstring>

void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
    // check number of arguments
    if (nrhs != 1 || nlhs > 1) {
        mexErrMsgIdAndTxt("StringIO:WrongNumArgs", "Wrong number of arguments.");
    }

    // check if input is a string
    if (mxIsChar(prhs[0])) {
        mexErrMsgIdAndTxt("StringIO:TypeError", "Input is not a string");
    }

    // copy characters data from mxArray to a C-style string (null-terminated)
    char *str = mxArrayToString(prhs[0]);

    // manipulate the string in some way
    if (strcmp("theOneString", str) == 0) {
        str[0] = 'T';  // capitalize first letter
    } else {
        str[0] = ' ';  // do something else?
    }

    // return the new modified string
    plhs[0] = mxCreateString(str);

    // free allocated memory
    mxFree(str);
}

Соответствующие функции в этом примере:

  • mxIsChar чтобы проверить, имеет mxArray mxCHAR тип mxCHAR .
  • mxArrayToString для копирования данных строки mxArray в буфер char * .
  • mxCreateString для создания строки mxArray из char* .

В качестве примечания, если вы хотите только прочитать строку и не изменять ее, не забудьте объявить ее как const char* для скорости и надежности.


Наконец, после компиляции мы можем назвать это из MATLAB следующим образом:

>> mex stringIO.cpp

>> strOut = stringIO('theOneString')
strOut = 
TheOneString

>> strOut = stringIO('somethingelse')
strOut=
omethingelse

Передайте трехмерную матрицу от MATLAB до C

В этом примере мы проиллюстрируем, как взять двойную трехмерную матрицу реального типа из MATLAB и передать ее в массив C double* .

Основные цели этого примера - показать, как получить данные из массивов MATLAB MEX и выделить некоторые мелкие детали в хранении и обработке матриц.

matrixIn.cpp

#include "mex.h"

void mexFunction(int  nlhs , mxArray *plhs[],
        int nrhs, mxArray const *prhs[]){
   // check amount of inputs
   if (nrhs!=1) {
        mexErrMsgIdAndTxt("matrixIn:InvalidInput", "Invalid number of inputs to MEX file.");
    }
   
   // check type of input
   if( !mxIsDouble(prhs[0]) || mxIsComplex(prhs[0])){
        mexErrMsgIdAndTxt("matrixIn:InvalidType",  "Input matrix must be a double, non-complex array.");
   }
   
   // extract the data
   double const * const matrixAux= static_cast<double const *>(mxGetData(prhs[0]));

   // Get matrix size
   const mwSize *sizeInputMatrix= mxGetDimensions(prhs[0]);

   // allocate array in C. Note: its 1D array, not 3D even if our input is 3D
   double*  matrixInC= (double*)malloc(sizeInputMatrix[0] *sizeInputMatrix[1] *sizeInputMatrix[2]* sizeof(double));

  
   // MATLAB is column major, not row major (as C). We need to reorder the numbers
   // Basically permutes dimensions   

   // NOTE: the ordering of the loops is optimized for fastest memory access! 
   // This improves the speed in about 300% 

    const int size0 = sizeInputMatrix[0]; // Const makes compiler optimization kick in
    const int size1 = sizeInputMatrix[1];
    const int size2 = sizeInputMatrix[2];
    
    for (int j = 0; j < size2; j++)
    {
        int jOffset = j*size0*size1; // this saves re-computation time
        for (int k = 0; k < size0; k++)
        {
            int kOffset = k*size1; // this saves re-computation time
            for (int i = 0; i < size1; i++)
            {
                int iOffset = i*size0; 
                matrixInC[i + jOffset + kOffset] = matrixAux[iOffset + jOffset + k];
            }
        }
    }

    // we are done!

    // Use your C matrix here

    // free memory
    free(matrixInC);
    return;
}

Соответствующие концепции, которые необходимо знать:

  • Матрицы MATLAB все 1D в памяти, независимо от того, сколько измерений они имеют при использовании в MATLAB. Это также справедливо для большинства (если не всех) основных матричных представлений в библиотеках C / C ++, что позволяет оптимизировать и ускорить выполнение.

  • Вам нужно явно скопировать матрицы из MATLAB в C в цикле.

  • Матрицы MATLAB хранятся в главном порядке столбцов, как в Fortran, но C / C ++ и большинство современных языков являются основными. Важно переставить входную матрицу, иначе данные будут выглядеть совершенно иначе.

Соответствующая функция в этом примере:

  • mxIsDouble проверяет, является ли вход double .
  • mxIsComplex проверяет, является ли вход реальным или мнимым.
  • mxGetData возвращает указатель на реальные данные во входном массиве. NULL если реальных данных нет.
  • mxGetDimensions возвращает указатель на массив mwSize с размером измерения в каждом индексе.

Передача структуры по именам полей

В этом примере показано, как читать записи типа MATLAB с различными типами и передавать их переменным типа C.

Хотя из примера можно легко и легко вычислить, как загружать поля по номерам, это достигается путем сравнения имен полей со строками. Таким образом, поля struct могут быть адресованы их именами полей, а переменные в нем могут быть прочитаны C.

structIn.c

#include "mex.h"
#include <string.h> // strcmp


void mexFunction (int nlhs, mxArray *plhs[],
                  int nrhs, const mxArray *prhs[])
{
  // helpers
  double* double_ptr;
  unsigned int i; // loop variable
  
  // to be read variables
  bool optimal;
  int randomseed;
  unsigned int desiredNodes;

  if (!mxIsStruct(prhs[0])) {
    mexErrMsgTxt("First argument has to be a parameter struct!");
  }
  for (i=0; i<mxGetNumberOfFields(prhs[0]); i++) {
    if (0==strcmp(mxGetFieldNameByNumber(prhs[0],i),"randomseed")) {
      mxArray *p = mxGetFieldByNumber(prhs[0],0,i);
      randomseed = *mxGetPr(p);
    }
    if (0==strcmp(mxGetFieldNameByNumber(prhs[0],i),"optimal")) {
      mxArray *p = mxGetFieldByNumber(prhs[0],0,i);
      optimal = (bool)*mxGetPr(p);
    }
    if (0==strcmp(mxGetFieldNameByNumber(prhs[0],i),"numNodes")) {
      mxArray *p = mxGetFieldByNumber(prhs[0],0,i);
      desiredNodes = *mxGetPr(p);
    }
  }
}

Цикл над i пробегает все поля в данной структуре, а if(0==strcmp) сравнивают имя поля matlab с данной строкой. Если это совпадение, соответствующее значение извлекается в переменную C.



Modified text is an extract of the original Stack Overflow Documentation
Лицензировано согласно CC BY-SA 3.0
Не связан с Stack Overflow