mexme automates the process of writing MEX files. You give mexme a snippet of C which just does numeric computations, as well a list of arguments, and it generates a valid MEX .cpp file. The generated code compiles in Linux (gcc) and in Windows (Visual Studio C++). New in version 1.1, it writes tedious input and output validation code for you. This way you can write a MEX file without manually coding calls to mx* API functions. It's inspired by SciPy's weave function.
Example: translate this piece of (non-vectorizable) .m code that applies a recursive filter into C:
function [y] = myrecursivefilter(x,alpha)
y = zeros(size(x));
y(1) = x(1)*alpha;
for ii = 2:length(x)
y(ii) = y(ii-1)*(1-alpha) + x(ii)*alpha;
end
end
Step 1: Write myrecursivefilter.csnip which does the same thing as the m file:
y[0] = x[0]*alpha;
for(mwSize i = 1; i < x_length; i++) {
y[i] = x[i]*alpha + y[i-1]*(1-alpha);
}
Step 2: Define arguments to your function (in Matlab):
inputargs = [InputNum('x'),...
InputNum('alpha',true,true,'double','alpha > 0 && alpha < 1)]; %scalar
%The last condition
outputarg = OutputNum('y','x_length,1');
Step 3: Generate a fully fledged .c file that can be compiled with mex:
cfile = mexme('myrecursivefilter.csnip',inputargs,outputarg)
writefile('myfilt.c',cfile);
mex myfilt.c
x = randn(1e6,1);
y = myfilt(x,.1);
plot([x,y])
cfile =
/*#include and #define not shown*/
#include "mexmetypecheck.c"
void mexFunction( int nlhs, mxArray *plhs[],
int nrhs, const mxArray *prhs[] )
{
/*Input output boilerplate*/
if(nlhs != 1 || nrhs != 2)
mexErrMsgTxt("Function must be called with 2 arguments and has 1 return values");
const mxArray *x_ptr = prhs[0];
const mwSize x_m = mxGetM(x_ptr);
const mwSize x_n = mxGetN(x_ptr);
const mwSize x_length = x_m == 1 ? x_n : x_m;
const mwSize x_numel = mxGetNumberOfElements(x_ptr);
const int x_ndims = mxGetNumberOfDimensions(x_ptr);
const mwSize *x_size = mxGetDimensions(x_ptr);
const double *x = (double *) mxGetData(x_ptr);
const mxArray *alpha_ptr = prhs[1];
if(mxGetNumberOfElements(alpha_ptr) != 1)
mexErrMsgTxt("Argument alpha (#2) must be scalar");
const double alpha = (double) mxGetScalar(alpha_ptr);
if(!(alpha > 0 && alpha < 1))
mexErrMsgTxt("Argument alpha (#2) did not pass test \"alpha > 0 && alpha < 1\"");
mwSize y_dims[] = {x_length,1};
plhs[0] = mxCreateNumericArray(2,y_dims,mxDOUBLE_CLASS,mxREAL);
mxArray **y_ptr = &plhs[0];
double *y = (double *) mxGetData(*y_ptr);
/*Actual function*/
#include "myfilt.csnip"
}
For every argument that you define, mexme generates extra "magic" variables. For example, if the variable is x, then in C:
x is the data
x_m is the size of the first dimension
x_n is the size of the second dimension
x_length is the length of a vector
x_numel is the number of elements in an array
x_ndims is the numer of dimensions
x_size is equivalent to the Matlab code size(x)
x_ptr is a reference to the mxArray that contains the x data
And if x is complex, x_r and x_i are the real and imaginary components of the data.
mexme currently does not support sparse data or non-numeric types but it does support full numeric arrays of any type (int8, single, double, etc.). |