MATLAB Language
Introduzione all'API MEX
Ricerca…
Controllare il numero di ingressi / uscite in un file MEX C ++
In questo esempio scriveremo un programma di base che controlla il numero di input e output passati a una funzione MEX.
Come punto di partenza, dobbiamo creare un file C ++ che implementa il "gateway MEX". Questa è la funzione eseguita quando il file viene chiamato da 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.");
}
}
Innanzitutto, includiamo l'intestazione mex.h
che contiene le definizioni di tutte le funzioni e tipi di dati richiesti per funzionare con l'API MEX. Quindi implementiamo la funzione mexFunction
come mostrato, dove la sua firma non deve cambiare, indipendentemente dagli input / output effettivamente utilizzati. I parametri della funzione sono i seguenti:
-
nlhs
: numero di uscite richieste. -
*plhs[]
: Array che contiene tutti gli output nel formato API MEX. -
nrhs
: numero di input passati. -
*prhs[]
: Array che contiene tutti gli input nel formato API MEX.
Successivamente, controlliamo il numero di argomenti input / output, e se la validazione fallisce, viene generato un errore usando la funzione mexErrMsgIdAndTxt
(si aspetta somename:iD
identificatore di formato somename:iD
, un semplice "ID" non funzionerà).
Una volta che il file è stato compilato come mex testinputs.cpp
, la funzione può essere chiamata in MATLAB come:
>> 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.
Inserisci una stringa, modificala in C e stampala
In questo esempio, illustriamo la manipolazione delle stringhe in MATLAB MEX. Creeremo una funzione MEX che accetta una stringa come input da MATLAB, copia i dati in C-string, li modifica e li converte in mxArray
restituito al lato MATLAB.
L'obiettivo principale di questo esempio è mostrare come le stringhe possono essere convertite in C / C ++ da MATLAB e viceversa.
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);
}
Le funzioni rilevanti in questo esempio sono:
-
mxIsChar
per verificare se unmxArray
è di tipomxCHAR
. -
mxArrayToString
per copiare i dati di una stringamxArray
in un bufferchar *
. -
mxCreateString
per creare una stringamxArray
da unchar*
.
Come nota a margine, se si desidera solo leggere la stringa e non modificarla, ricordarsi di dichiararla come const char*
per velocità e robustezza.
Infine, una volta compilato possiamo chiamarlo da MATLAB come:
>> mex stringIO.cpp
>> strOut = stringIO('theOneString')
strOut =
TheOneString
>> strOut = stringIO('somethingelse')
strOut=
omethingelse
Passa una matrice 3D da MATLAB a C
In questo esempio illustriamo come prendere una doppia matrice 3D di tipo reale da MATLAB e passarla a un double*
array C double*
.
Gli obiettivi principali di questo esempio sono mostrare come ottenere dati dagli array MATLAB MEX e mettere in evidenza alcuni piccoli dettagli nell'archiviazione e gestione della matrice.
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;
}
I concetti rilevanti di cui essere a conoscenza:
Le matrici MATLAB sono tutte 1D in memoria, indipendentemente dal numero di dimensioni che hanno quando vengono utilizzate in MATLAB. Questo vale anche per la maggior parte (se non tutti) la rappresentazione della matrice principale nelle librerie C / C ++, poiché consente l'ottimizzazione e un'esecuzione più rapida.
È necessario copiare esplicitamente le matrici da MATLAB a C in un ciclo.
Le matrici MATLAB sono archiviate nell'ordine delle colonne, come in Fortran, ma C / C ++ e le lingue più moderne sono le righe maggiori. È importante permutare la matrice di input, altrimenti i dati appariranno completamente diversi.
Le funzioni rilevanti in questo esempio sono:
-
mxIsDouble
controlla se l'input è di tipodouble
. -
mxIsComplex
verifica se l'input è reale o immaginario. -
mxGetData
restituisce un puntatore ai dati reali nell'array di input.NULL
se non ci sono dati reali. -
mxGetDimensions
restituisce un puntatore a un arraymwSize
, con la dimensione della dimensione in ogni indice.
Passare una struttura per nome di campo
Questo esempio illustra come leggere le voci struct di tipo vario da MATLAB e passarlo a variabili di tipo C equivalenti.
Mentre è possibile e facile capire dall'esempio come caricare i campi in base ai numeri, è qui ottenuto confrontando i nomi dei campi con le stringhe. Quindi i campi struct possono essere indirizzati con i loro nomi di campo e le variabili in esso possono essere letti da 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);
}
}
}
Il ciclo su i
gira su ogni campo nella struttura specificata, mentre le parti if(0==strcmp)
confrontano il nome del campo MATLAB con la stringa data. Se è una corrispondenza, il valore corrispondente viene estratto in una variabile C.