MATLAB Language
Wprowadzenie do MEX API
Szukaj…
Sprawdź liczbę wejść / wyjść w pliku CEX MEX
W tym przykładzie napiszemy podstawowy program, który sprawdza liczbę wejść i wyjść przekazanych do funkcji MEX.
Na początek musimy utworzyć plik C ++ implementujący „bramę MEX”. Jest to funkcja wykonywana, gdy plik jest wywoływany z 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.");
}
}
Najpierw mex.h
nagłówek mex.h
który zawiera definicje wszystkich wymaganych funkcji i typów danych do pracy z MEX API. Następnie implementujemy funkcję mexFunction
jak pokazano, gdzie jej podpis nie może się zmienić, niezależnie od faktycznie używanych wejść / wyjść. Parametry funkcji są następujące:
-
nlhs
: liczba żądanych wyników. -
*plhs[]
: Tablica zawierająca wszystkie dane wyjściowe w formacie MEX API. -
nrhs
: liczba przekazanych danych wejściowych. -
*prhs[]
: Tablica zawierająca wszystkie dane wejściowe w formacie MEX API.
Następnie sprawdzamy liczbę argumentów wejścia / wyjścia, a jeśli sprawdzanie poprawności się nie powiedzie, za pomocą funkcji mexErrMsgIdAndTxt
jest błąd (oczekuje on mexErrMsgIdAndTxt
somename:iD
formatu somename:iD
, prosty „ID” nie zadziała).
Po skompilowaniu pliku jako mex testinputs.cpp
, funkcję można wywołać w MATLAB jako:
>> 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.
Wprowadź ciąg, zmodyfikuj go w C i wyślij go
W tym przykładzie przedstawiamy manipulację ciągiem znaków w MATLAB MEX. Utworzymy funkcję MEX, która akceptuje ciąg jako dane wejściowe z MATLAB, kopiuje dane do ciągu C, modyfikuje je i konwertuje z powrotem na mxArray
zwrócone po stronie MATLAB.
Głównym celem tego przykładu jest pokazanie, w jaki sposób ciągi znaków można przekonwertować do C / C ++ z MATLAB i odwrotnie.
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);
}
Odpowiednie funkcje w tym przykładzie to:
-
mxIsChar
aby sprawdzić, czymxArray
jest typumxCHAR
. -
mxArrayToString
aby skopiować dane ciągumxArray
do buforachar *
. -
mxCreateString
aby utworzyć ciągmxArray
zchar*
.
Na marginesie, jeśli chcesz tylko czytać ciąg, a nie go modyfikować, pamiętaj, aby zadeklarować go jako const char*
dla szybkości i niezawodności.
Wreszcie po skompilowaniu możemy wywołać go z MATLAB jako:
>> mex stringIO.cpp
>> strOut = stringIO('theOneString')
strOut =
TheOneString
>> strOut = stringIO('somethingelse')
strOut=
omethingelse
Przekaż matrycę 3D z MATLAB do C.
W tym przykładzie pokazujemy, jak pobrać podwójną macierz 3D typu rzeczywistego z MATLAB i przekazać ją do tablicy C double*
.
Głównym celem tego przykładu jest pokazanie, jak uzyskać dane z tablic MATLAB MEX oraz zwrócić uwagę na małe szczegóły dotyczące przechowywania i obsługi matrycy.
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;
}
Istotne pojęcia, o których należy pamiętać:
Matryce MATLAB są w pamięci 1D, bez względu na to, ile wymiarów mają, gdy są używane w MATLAB. Dotyczy to również większości (jeśli nie wszystkich) reprezentacji macierzy głównej w bibliotekach C / C ++, ponieważ pozwala to na optymalizację i szybsze wykonanie.
Musisz jawnie skopiować macierze z MATLAB do C w pętli.
Matryce MATLAB są przechowywane w porządku głównym kolumny, podobnie jak w Fortran, ale C / C ++ i większość współczesnych języków jest rzędem głównym. Ważne jest, aby permutować macierz wejściową, w przeciwnym razie dane będą wyglądać zupełnie inaczej.
Odpowiednimi funkcjami w tym przykładzie są:
-
mxIsDouble
sprawdza, czy dane wejściowe są typudouble
. -
mxIsComplex
sprawdza, czy dane wejściowe są rzeczywiste, czy wymyślone. -
mxGetData
zwraca wskaźnik do rzeczywistych danych w tablicy wejściowej.NULL
jeśli nie ma prawdziwych danych. -
mxGetDimensions
zwraca wskaźnik do tablicymwSize
, z rozmiarem wymiaru w każdym indeksie.
Przekazywanie struktury według nazw pól
Ten przykład ilustruje, jak czytać wpisy struktur różnego typu z MATLAB i przekazywać je do zmiennych typu równoważnego C.
O ile na przykład można ładować pola według liczb, to jest to możliwe poprzez porównanie nazw pól z ciągami znaków. W ten sposób pola struct mogą być adresowane przez ich nazwy pól, a zmienne mogą być odczytywane przez 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);
}
}
}
Pętla nad i
biegnie przez każde pole w podanej strukturze, podczas gdy części if(0==strcmp)
porównują nazwę pola if(0==strcmp)
z podanym łańcuchem. Jeśli jest to dopasowanie, odpowiednia wartość jest wyodrębniana do zmiennej C.