Saturday, September 3, 2011

SWIG and numpy

I've been looking into C/C++ interface creator known as SWIG for use with a molecular dynamics program that is in the works. It is nice in that from an interface file, that you can create entirely by hand or just use a standard header file, you can create a python module that looks and feels like python, but is really some nifty C that you've written. There are some drawbacks of course in that if a function returns a pointer, it is actually a wrapped object that can be passed to other wrapped functions, but will have little use in python without some other work. Of course for the purposes of this post I would like these pointers to be an array of floating point numbers, or a numpy array. Wouldn't it be great if you could easily pass numpy arrays back and forth to C/C++ without having to deal with writing your own wrapper using Python.h?

Well you can with a little gem called numpy.i which is a SWIG interface wrapper for the numpy array. With it, you specify certain arguments you want to be treated as numpy arrays and it does so automatically.
So on with the example. I have two C functions which fill an array sequentially and can take the dot product of two arrays. They are found below in two files

Let's now provide a python interface to these using SWIG. Here, we specify the python module name and the functions that make up the module's functions. Then we include the numpy.i interface. Next, we have to say how we want our C arguments treated. The details of what's written in the file can be found here but I have used most of the common ones: modifying an array in place, taking an input array, and returning an array as output. NOTE: the far right section of the line matches verbatim to the arguments in the C code. The interface file is as follows:

Then, we need to build the module and test. To make this module we used a script (which will not be the case for future SWIG posts). I'm not sure of the details here, but it is listed for your information.

After that, let's build with `python build` and run some speed tests. For example,


Numpy says: 3.33332833333e+17
SWIG says: 3.33332833333e+17
Time of numpy: 0.0032000541687
Time of SWIG: 0.00278091430664

Wahoo, we are actually slightly faster than the built-in numpy dot product with just a little bit of work. Next time, moving on to SWIGing classes and incorporating numpy with them as well.