Buscar..


Verifique el número de entradas / salidas en un archivo MEX de C ++

En este ejemplo, escribiremos un programa básico que verifique el número de entradas y salidas pasadas a una función MEX.

Como punto de partida, necesitamos crear un archivo C ++ que implemente la "puerta de enlace MEX". Esta es la función que se ejecuta cuando se llama el archivo desde 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.");
    }
}

Primero, incluimos el encabezado mex.h que contiene definiciones de todas las funciones y tipos de datos necesarios para trabajar con la API de MEX. Luego implementamos la función mexFunction como se muestra, donde su firma no debe cambiar, independientemente de las entradas / salidas realmente utilizadas. Los parámetros de la función son los siguientes:

  • nlhs : Número de salidas solicitadas.
  • *plhs[] : Array que contiene todas las salidas en formato de API MEX.
  • nrhs : Número de entradas pasadas.
  • *prhs[] : Array que contiene todas las entradas en formato MEX API.

A continuación, verificamos el número de argumentos de entradas / salidas, y si la validación falla, se produce un error utilizando la función mexErrMsgIdAndTxt (se espera un nombre somename:iD identificador de formato somename:iD , una simple "ID" no funcionará).


Una vez que el archivo se compila como mex testinputs.cpp , se puede llamar a la función en MATLAB como:

>> 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.

Ingrese una cadena, modifíquela en C y envíela

En este ejemplo, ilustramos la manipulación de cadenas en MATLAB MEX. Crearemos una función MEX que acepte una cadena como entrada de MATLAB, copiaremos los datos en la cadena C, la modificaremos y la convertiremos de nuevo a mxArray devuelta al lado de MATLAB.

El objetivo principal de este ejemplo es mostrar cómo se pueden convertir las cadenas a C / C ++ desde MATLAB y 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);
}

Las funciones relevantes en este ejemplo son:

  • mxIsChar para probar si un mxArray es de tipo mxCHAR .
  • mxArrayToString para copiar los datos de una cadena mxArray a un char * buffer.
  • mxCreateString para crear una cadena mxArray partir de un char* .

Como nota al margen, si solo desea leer la cadena y no modificarla, recuerde declararla como const char* por su velocidad y robustez.


Finalmente, una vez compilados lo podemos llamar desde MATLAB como:

>> mex stringIO.cpp

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

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

Pasa una matriz 3D de MATLAB a C

En este ejemplo, ilustramos cómo tomar una matriz 3D doble de tipo real de MATLAB y pasarla a una matriz C double* .

Los principales objetivos de este ejemplo son mostrar cómo obtener datos de matrices MATLAB MEX y resaltar algunos pequeños detalles en el almacenamiento y manejo de matrices.

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;
}

Los conceptos relevantes a tener en cuenta:

  • Las matrices de MATLAB son todas 1D en la memoria, sin importar cuántas dimensiones tengan cuando se usan en MATLAB. Esto también es cierto para la mayoría (si no todas) de la representación de matriz principal en las bibliotecas C / C ++, ya que permite la optimización y la ejecución más rápida.

  • Debe copiar explícitamente matrices de MATLAB a C en un bucle.

  • Las matrices de MATLAB se almacenan en el orden mayor de la columna, como en Fortran, pero C / C ++ y la mayoría de los lenguajes modernos son la fila principal. Es importante permutar la matriz de entrada, de lo contrario los datos se verán completamente diferentes.

La función relevante en este ejemplo es:

  • mxIsDouble comprueba si la entrada es de tipo double .
  • mxIsComplex comprueba si la entrada es real o imaginaria.
  • mxGetData devuelve un puntero a los datos reales en la matriz de entrada. NULL si no hay datos reales.
  • mxGetDimensions devuelve un puntero a una matriz mwSize , con el tamaño de la dimensión en cada índice.

Pasando una estructura por nombre de campo

Este ejemplo ilustra cómo leer las entradas de estructuras de varios tipos de MATLAB y pasarlas a C variables de tipo equivalente.

Si bien es posible y fácil averiguar a partir del ejemplo cómo cargar campos por números, aquí se logra comparando los nombres de los campos con cadenas. Por lo tanto, los campos de estructura pueden direccionarse por sus nombres de campo y las variables en ella pueden leerse por 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);
    }
  }
}

El bucle sobre i ejecuta en todos los campos de la estructura dada, mientras que las partes if(0==strcmp) comparan el nombre del campo matlab con la cadena dada. Si es una coincidencia, el valor correspondiente se extrae a una variable C.



Modified text is an extract of the original Stack Overflow Documentation
Licenciado bajo CC BY-SA 3.0
No afiliado a Stack Overflow