MATLAB Language
Introduction à l'API MEX
Recherche…
Vérifier le nombre d'entrées / sorties dans un fichier MEX C ++
Dans cet exemple, nous allons écrire un programme de base qui vérifie le nombre d'entrées et de sorties passées à une fonction MEX.
Pour commencer, nous devons créer un fichier C ++ implémentant la "passerelle MEX". C'est la fonction exécutée lorsque le fichier est appelé depuis 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.");
}
}
Tout d'abord, nous incluons l'en mex.h
tête mex.h
qui contient les définitions de toutes les fonctions et types de données requis pour fonctionner avec l'API MEX. Ensuite, nous implémentons la fonction mexFunction
comme indiqué, où sa signature ne doit pas changer, indépendamment des entrées / sorties réellement utilisées. Les paramètres de la fonction sont les suivants:
-
nlhs
: Nombre de sorties demandées. -
*plhs[]
: Tableau contenant toutes les sorties au format API MEX. -
nrhs
: Nombre d'entrées passées. -
*prhs[]
: Tableau contenant toutes les entrées au format API MEX.
Ensuite, nous vérifions le nombre d’arguments entrées / sorties, et si la validation échoue, une erreur est lancée avec la fonction mexErrMsgIdAndTxt
(on attend un somename:iD
identifiant de format somename:iD
, un simple "ID" ne fonctionnera pas).
Une fois le fichier compilé en mex testinputs.cpp
, la fonction peut être appelée dans MATLAB comme:
>> 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.
Entrez une chaîne, modifiez-la en C et affichez-la
Dans cet exemple, nous illustrons la manipulation de chaînes dans MATLAB MEX. Nous allons créer une fonction MEX qui accepte une chaîne en entrée de MATLAB, copier les données dans C-string, les modifier et les reconvertir en mxArray
renvoyées du côté MATLAB.
L'objectif principal de cet exemple est de montrer comment les chaînes peuvent être converties en C / C ++ à partir de MATLAB et vice versa.
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);
}
Les fonctions pertinentes dans cet exemple sont les suivantes:
-
mxIsChar
pour tester si unmxArray
est de typemxCHAR
. -
mxArrayToString
pour copier les données d'une chaînemxArray
dans un tamponchar *
. -
mxCreateString
pour créer une chaînemxArray
partir d'un caractèrechar*
.
En guise de remarque, si vous voulez seulement lire la chaîne et ne pas la modifier, n'oubliez pas de la déclarer en tant que const char*
pour la rapidité et la robustesse.
Enfin, une fois compilé, nous pouvons l'appeler depuis MATLAB comme:
>> mex stringIO.cpp
>> strOut = stringIO('theOneString')
strOut =
TheOneString
>> strOut = stringIO('somethingelse')
strOut=
omethingelse
Passer une matrice 3D de MATLAB à C
Dans cet exemple, nous illustrons comment prendre une double matrice 3D de type réel à partir de MATLAB et la passer à un tableau C double*
.
Les principaux objectifs de cet exemple montrent comment obtenir des données à partir de baies MATLAB MEX et mettre en évidence certains petits détails dans le stockage et la gestion de la 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;
}
Les concepts pertinents à prendre en compte:
Les matrices MATLAB sont toutes 1D en mémoire, quel que soit le nombre de dimensions utilisées dans MATLAB. Cela est également vrai pour la plupart (sinon la totalité) représentation de la matrice principale dans les bibliothèques C / C ++, ce qui permet une optimisation et une exécution plus rapide.
Vous devez copier explicitement les matrices de MATLAB vers C dans une boucle.
Les matrices MATLAB sont stockées dans l'ordre des colonnes, comme dans Fortran, mais C / C ++ et la plupart des langages modernes sont majeurs. Il est important de permuter la matrice d'entrée, sinon les données seront complètement différentes.
Les fonctions pertinentes dans cet exemple sont les suivantes:
-
mxIsDouble
vérifie si l'entrée est de typedouble
. -
mxIsComplex
vérifie si l'entrée est réelle ou imaginaire. -
mxGetData
renvoie un pointeur sur les données réelles du tableau d'entrée.NULL
s'il n'y a pas de données réelles. -
mxGetDimensions
renvoie un pointeur sur un tableaumwSize
, avec la taille de la dimension dans chaque index.
Passer une structure par noms de champs
Cet exemple montre comment lire des entrées de structure de différents types dans MATLAB et les transmettre à des variables de type équivalent C.
Bien qu'il soit possible et facile de comprendre à partir de l'exemple comment charger des champs par des nombres, cela est obtenu en comparant les noms de champs aux chaînes. Ainsi, les champs de la structure peuvent être adressés par leurs noms de champs et les variables peuvent être lues par 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);
}
}
}
La boucle sur i
s'exécute sur tous les champs de la structure, tandis que les parties if(0==strcmp)
comparent le nom du champ matlab à la chaîne donnée. S'il s'agit d'une correspondance, la valeur correspondante est extraite dans une variable C.