An introduction to MEX files

Matlab is widely used by researchers, mainly because it makes fast and easy to code anything related to numerical computing, especially matrix manipulation. It’s quite efficient for matrix and vector operations. However, in some cases, it’s awfully slow. This generally happens when you have a big for loop (or worse, nested for loops), to perform on a matrix some process that you cannot express as matrix operations.

For these cases, you can use Matlab EXecutables: MEX files. It allows you to code a function in C, C++, or Fortran, (lower-level and more efficient languages) and use it in Matlab as if it was a built-in function. Actually, most of Matlab built-in functions are made this way!

Setup

I will only talk about C code here, but the main ideas are the same for C++ and Fortran. I assume you have Matlab installed, as well as a C compiler. I personally use gcc on GNU/Linux.

Open Matlab, and type in the command window mex -setup. Then give the path to your C compiler.

After that, create a file called testmex.c, and copy-paste the following code in it (we’ll see what it does later).

Example

#include <mex.h>

void
mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
  /* Print in Matlab */
  mexPrintf("You are in a MEX file!\n");
  mexPrintf("You provided %d input variables.\n", nrhs);
  mexPrintf("You are waiting for %d output variable.\n", nlhs);

  /* Get input variables */
  double *a = mxGetPr(prhs[0]);
  double *b = mxGetPr(prhs[1]);

  /* Get dimensions of the first input variable */
  const mwSize *dim_a = mxGetDimensions(prhs[0]);
  uint nb_row_a = dim_a[0];
  uint nb_col_a = dim_a[1];

  /* Initialize output, the same size as a */
  plhs[0] = mxCreateDoubleMatrix(nb_row_a, nb_col_a, mxREAL);
  double *c = mxGetPr(plhs[0]);

  /* Compute things */
  for (uint j = 0; j < nb_col_a; ++j)
    for (uint i = 0; i < nb_row_a; ++i)
      c[i+j*nb_row_a] = a[i+j*nb_row_a] + b[i+j*nb_row_a];

}

This function computes the sum of the two input matrices. To use it, you have to compile it with MEX. Type in the Matlab command window:

mex testmex.c
a = rand(3,5)
b = rand(3,5)
c = testmex(a,b)

If it works, your setup should be ok! Let’s see how this function works.

Details

With MEX, your C code doesn’t need a main. The entry point to your code is the mexFunction.

void
mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])

Its parameters can seem a bit weird. lhs and rhs stand for left-hand side and right-hand side, and correspond to the output and the input of the function.

To remember than left is output and right is input, think about how you call functions in Matlab: c = testmex(a,b). It actually makes sense!

nlhs and nrhs are the number of output matrices (in our example, 1) and input matrices (in our example, 2). They correspond to the sizes of the arrays plhs and prhs.

plhs and prhs are arrays of Matlab matrices. The type of a Matlab matrix is mxArray.

To actually perform operations on a matrix, you have to get the pointer to its values. This is done with the function mxgetPr:

  double *a = mxGetPr(prhs[0]);

With a, you can access and modify the values of the matrix prhs[0], that is, the matrix passed as first argument.

Note that it is only a pointer to double values, so you cannot access directly a given cell of the matrix. Before, you need its dimensions:

  const mwSize *dim_a = mxGetDimensions(prhs[0]);
  uint nb_row_a = dim_a[0];
  uint nb_col_a = dim_a[1];

You can then access a[i][j] with a[i+j*nb_row_a].

To initialize the output, you have to create a new matrix, and to get the pointer to its values:

  plhs[0] = mxCreateDoubleMatrix(nb_row_a, nb_col_a, mxREAL);
  double *c = mxGetPr(plhs[0]);

You can now play around with these matrices, and do anything you can do with standard C code! MEX files are generally used to rewrite bottleneck operations as small C/C++ methods, for efficiency. However, you can perfectly use them for big projects.

For more examples, see the official documentation

Remarks

Note the unusual order of my nested for loops. The reason is that in Matlab, unlike in C or Python, matrices follow the column-major order: they are stored in a way that elements of a given column are contiguous in memory, so it is significantly faster to traverse them column after column.