MATLAB Language
Введение в MEX API
Поиск…
Проверить количество входов / выходов в 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.