[PYTHON MATRIX-SIG] NumPy and PIL extension module

viennet@ura1507.univ-paris13.fr viennet@ura1507.univ-paris13.fr
Mon, 5 May 1997 21:47:56 +0100 (WET DST)


Zachary Roadhouse writes:
> 
> Most of what I need the data for will probably require floating point
> values -- this isn't really the big issue for me though.  Could someone
> post how to access and change an array element in an efficient manner in C
> (ie. not a lot of Python overhead)?  The code in multiarraymodule isn't
> well commented so I don't really understand what is going on.
> 

Not well commented, but very readable, a really good job :-)

I'll try to answer, with two useless but illustrative examples:

 - First, your function get a Python object using :
      PyArg_ParseTuple( args, "O", &obj )

 - Then, there is two way to get an array in C:

  1- PyArray_ContiguousFromObject( obj, type, mindim, maxdim ) 

     will try to convert the object to an array of the specified type.
     It returns a contiguous COPY of the array.
     This is the most generic and easy to use way, but it is not
     suitable if you want to modify in place an array.

     Example: to compute the sum of the elements of an array of
    floats. 
/* stupid example: computes the sum of an array 
 */
static PyObject *py_arraysum( PyObject *self, PyObject *args ) {
  PyObject *obj;
  PyArrayObject *arr;
  int nelem, i;
  double *ptr, sum = 0;
  if (!PyArg_ParseTuple( args, "O" , &obj ))
    return NULL;
  /* Get array (contiguous) */
  arr = (PyArrayObject *)PyArray_ContiguousFromObject(obj,PyArray_DOUBLE,1,1);
  if (!arr) {
    PYSETERROR( "can't get contiguous Float array");
    return NULL;
  }
  /* Computes sum */
  nelem = arr->dimensions[0];
  ptr = (double *)arr->data; /* pointer on first elem */
  for (i=0; i < nelem; i++)
    sum += *(ptr++);

  Py_DECREF(arr); /* release our copy */

  return Py_BuildValue("f", sum );
}

Note that this function works for arrays, but also for lists and
tuples, which are converted.

  2- The other solution is to deal directly with the array object,
     without asking NumPy to do the conversion. The usual situation is
     when you know in advance the type of the array you will get, and
     want to avoid any duplication of the data (big array for
     instance), or you want to modify the array in place.
     The main problem is that a NumPy array is not always contiguous;
     the stride[] attribute gives the number of bytes between to
     consecutive rows.

/* another useless example: set an non-contiguous 2D BYTE array to zero
 */
static PyObject *py_arrayzero( PyObject *self, PyObject *args ) {
  PyObject *obj;
  PyArrayObject *arr;
  int i, j;
  unsigned char *ptr;
  if (!PyArg_ParseTuple( args, "O" , &obj ))
    return NULL;
  /* Check that obj is really an 2D array of bytes */
  if (!PyArray_Check(obj)) {
    PYSETERROR("first argument is not an array");
    return NULL;
  }
  /* check type (could also use arr->descr->type_num) */
  if (PyArray_ObjectType(obj,0) != PyArray_UBYTE) {
    PYSETERROR("incorrect array type");
    return NULL;
  }
  arr = (PyArrayObject *)obj;
  if (arr->nd != 2) { /* we are really strict ! */
    PYSETERROR("incorrect number of dims");
    return NULL;
  }
  /* Set elems to zero */
  ptr = (unsigned char *)arr->data;
  for (i=0; i < arr->dimensions[0]; i++) {
    for (j=0; j < arr->dimensions[1]; j++)
      ptr[j] = 0;
    ptr += arr->strides[0]; /* next row */
  }
  
  Py_INCREF(Py_None);
  return Py_None; /* arr has been modified in place, we return None */
}

This function works efficiently for 2D byte arrays, and nothing else. 
This approach is rarely needed, except for truly large arrays. 

It is often better to create a new array and return it. 
The user writes
 A = myfunction(A) 
and not 
 myfunction(A) # modify A in place


I hope to have answered your question.

Emmanuel

-- 
Emmanuel Viennet: <viennet@ura1507.univ-paris13.fr>
LIPN - Institut Galilee - Universite Paris-Nord       
93430 Villetaneuse -  France

_______________
MATRIX-SIG  - SIG on Matrix Math for Python

send messages to: matrix-sig@python.org
administrivia to: matrix-sig-request@python.org
_______________