Hello all.
I'm trying to figure out a (simple) way to wrap extension functions using Numeric and swig. I want to use swig because I find the method described i ch. 12 of the user manual a bit too elaborate.
The problem I'm facing with swig is that I cannot figure out a way to pass arrays to the functions expecting double pointers as input. Say, for example, that I want to wrap daxpy:
1. I put the function call interface into a swig file:
void daxpy(int* n,double* a, double* x,int* incx, double* y, int* incy)
2. I want the function call visible to python to be something like:
x = Numeric.arange(0.0,10.0) y = a[:] a = 1.0 daxpy(a,x,y)
3. To achieve 2. I make a python function that does the real call to daxpy:
def daxpy(a,x,y): <Do consistency checking between x and y>
n = len(x) d_x = GetDataPointer(x) inc_x = <x's incrment> . . . daxpy_c(n,a,d_x,inc_x,d_y,inc_y)
(daxpy_c is the real daxpy)
The problem I'm facing is that I cannot grab the internal data pointer from Numeric arrays and pass it to a function. Is there a simple way to do that without having to write a wrapper function in c for every function I want to use?
How should I write the function GetDataPointer()?
Any hints is greatly appreciated.
Best regards, Roy.
The Computer Center, University of Tromsø, N-9037 TROMSØ, Norway. phone:+47 77 64 41 07, fax:+47 77 64 41 00 Roy Dragseth, High Perfomance Computing System Administrator Direct call: +47 77 64 62 56. email: royd@cc.uit.no
* Roy Dragseth
[snip Numeric and swig questions about how to give a numpy array to a swigged c function]
Any hints is greatly appreciated.
I've done this a few times. What you need to do is help swig understand that a numpy array is input and how to treat this as a C array. With swig you can do this with a typemap. Here's an example:
we can create a swig interface file like
%module exPyC
%{ #include <Python.h> #include <arrayobject.h> /* Remember this one */ #include <math.h> %}
%init %{ import_array() /* Initial function for NumPy */ %}
%typemap(python,in) double * { PyArrayObject *py_arr;
/* first check if it is a NumPy array */ if (!PyArray_Check($source)) { PyErr_SetString(PyExc_TypeError, "Not a NumPy array"); return NULL; }
if (PyArray_ObjectType($source,0) != PyArray_DOUBLE) { PyErr_SetString(PyExc_ValueError, "Array must be of type double"); return NULL; }
/* check that array is 1D */ py_arr = PyArray_ContiguousFromObject($source, PyArray_DOUBLE, 1, 1);
/* set a double pointer to the NumPy allocated memory */ $target = py_arr->data; } /* end of typemap */
%inline %{
void arrayArg(double *arr, int n) { int i;
for (i = 0; i < n; i++) { arr[i] = f(i*1.0/n); } } %}
Now, compile your extension, and test
import exPyC import Numeric a = Numeric.zeros(10,'d') a
array([ 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.])
exPyC.arrayArg(a,10) a
array([ 0. , 0.00996671, 0.0394695 , 0.08733219, 0.15164665, 0.22984885, 0.31882112, 0.41501643, 0.51459976, 0.61360105])
You can also get rid of the length argument with a typemap(python,ignore), see the swig docs. For more info about the safety checks in the typemap check the numpy docs.
Lykke til! :-)
HTH, Roger