These notes describe the Numeric compatability functions which enable numarray to utilize a subset of the extensions written for Numeric (NumPy). Not all Numeric C-API features and therefore not all Numeric extensions are currently supported. Users should be able to utilize suitable extensions written for Numeric within the numarray environment by:
Numarray's compatability with Numeric consists of 3 things:
PyArrayObject was discussed in an earlier section. The header file, ``arrayobject.h'' is now fairly minimal, mainly just including libnumarray.h, so needs little discussion. The following section will discuss the Numeric compatible functions.
The basic use of numarrays by Numeric extensions is achieved in the extension function's wrapper code by:
Unlike prior versions of numarray, this version *does* support access to array objects straight out of PyArg_ParseTuple. This is a consequence of a change to the underlying object model, where a class instance has been replaced by PyArrayObject. Nevertheless, the ``right'' way to access arrays is either via the high level interface or via emulated Numeric factory functions. That way, access to other python sequences is supported as well.
The creation of array objects is illustrated by the following of wrapper code for a 2D convolution function:
static PyObject * Py_Convolve2d(PyObject *obj, PyObject *args) { PyObject *okernel, *odata, *oconvolved=Py_None; PyArrayObject *kernel, *data, *convolved; if (!PyArg_ParseTuple(args, "OO|O", &okernel, &odata, &oconvolved)) return PyErr_Format(_Error, "Convove2d: Invalid parameters.");
The first step was simply to get object pointers to the numarray parameters to the convolution function: okernel, odata, and oconvolved. Oconvolved is an optional output parameter, specified with a default value of Py_None which is used when only 2 parameters are supplied at the python level. Each of the ``o'' parameters should be thought of as an arbitrary sequence object, not necessarily an array.
The next step is to call emulation functions which convert sequence objects into PyArrayObjects. In a Numeric extension, these calls map tuples and lists onto Numeric arrays and assert their dimensionality as 2D. The numarray emulation functions first map tuples, lists, and misbehaved numarrays onto well-behaved numarrays. Thus, calls to the emulation factory functions transparently use the numarray high level interface and provide visibility only to aligned and non-byteswapped array objects.
kernel = (PyArrayObject *) PyArray_ContiguousFromObject( okernel, tFloat64, 2, 2); data = (PyArrayObject *) PyArray_ContiguousFromObject( odata, tFloat64, 2, 2); if (!kernel || !data) return NULL;
Extra processing is required to handle the output array convolved, cloning it from data if it was not specified. Code should be supplied, but is not, to verify that convolved and data have the same shape.
if (convolved == Py_None) convolved = (PyArrayObject *) PyArray_FromDims( data->nd, data->dimensions, tFloat64); else convolved = (PyArrayObject *) PyArray_ContiguousFromObject( oconvolved, tFloat64, 2, 2); if (!convolved) return NULL;
After converting all of the input paramters into PyArrayObjects, the actual convolution is performed by a seperate function. This could just as well be done inline:
Convolve2d(kernel, data, convolved);
After processing the arrays, they should be DECREF'ed or returned using PyArray_Return. It is generally not possible to directly return a numarray object using Py_BuildValue because the shadowing of mis-behaved arrays needs to be undone. Calling PyArray_Return destroys any temporary and passes the numarray back to Python.
Py_DECREF(kernel); Py_DECREF(data); if (convolved != Py_None) { Py_DECREF(convolved); Py_INCREF(Py_None); return Py_None; } else return PyArray_Return(convolved); }
Byteswapped or misaligned arrays are handled by a process of shadowing which works like this:
The following functions are currently implemented:
int nd, int *dims, int type) |
An array created with PyArray_FromDims can be used as a temporary or returned using PyArray_Return.
Used as a temporary, calling Py_DECREF deallocates it.
int nd, int *dims, int type, char *data) |
PyObject *op, int type, int min_dim, int max_dim) |
min_dim==max_dim
specifies an exact rank.
min_dim==max_dim==0
specifies any rank.
PyObject *op, int type, int min_dim, int max_dim) |
PyObject *op, int type, int min_dim, int max_dim) |
If 'op' is a byteswapped or misaligned numarray, FromObject creates a temporary copy and the emulation object refers to it.
If 'op' is a nonswapped, aligned numarray, the emulation object refers to it.
If 'op' is some other sequence, it is converted to a numarray and the emulation object refers to that.
PyArrayObject *apr) |
An additional check is (or eventually will be) performed to guarantee that rank-0 arrays are converted to appropriate python scalars.
PyArray_Return has no net effect on the reference count of the underlying numarray.
PyObject **op, char **ptr, int *d1, int typecode) |
PyObject **op, char ***ptr, int *d1, int *d2, int typecode) |
PyObject *op, char *ptr) |
PyObject *op) |
PyObject *op) |
PyArrayObject *op) |
PyArrayObject *op) |
PyArrayObject *op, int type) |
PyArrayObject *op, int type) |
int type) |
T) |
Send comments to the NumArray community.