[Numpy-discussion] NumPy re-factoring project
Charles R Harris
charlesr.harris at gmail.com
Thu Jun 10 21:02:20 EDT 2010
On Thu, Jun 10, 2010 at 6:27 PM, Sturla Molden <sturla at molden.no> wrote:
> Den 11.06.2010 00:57, skrev David Cournapeau:
>
> Do you have the code for this ? That's something I wanted to do, but
> never took the time to do. Faster generic iterator would be nice, but
> very hard to do in general.
>
>
>
>
>
> /* this computes the start adress for every vector along a dimension
> (axis) of an ndarray */
>
> typedef PyArrayObject ndarray;
>
> inline char *datapointer(ndarray *a, npy_intp *indices)
> {
> char *data = a->data;
> int i;
> npy_intp j;
> for (i=0; i < a->nd; i++) {
> j = indices[i];
> data += j * a->strides[i];
> }
> return data;
> }
>
> static double ** _get_axis_pointer(npy_intp *indices, int axis,
> ndarray *a, double **axis_ptr_array, int dim)
> {
> /* recursive axis pointer search for 4 dimensions or more */
> npy_intp i;
> double *axis_ptr;
> if (dim == a->nd) {
> /* done recursing dimensions,
> compute address of this axis */
> axis_ptr = (double *) datapointer(a, indices);
> *axis_ptr_array = axis_ptr;
> return (axis_ptr_array + 1);
> } else if (dim == axis) {
> /* use first element only */
> indices[dim] = 0;
> axis_ptr_array = _get_axis_pointer(indices, axis, a,
> axis_ptr_array, dim+1);
> return axis_ptr_array;
> } else {
> /* iterate range of indices */
> npy_intp length = a->dimensions[dim];
> for (i=0; i < length; i++) {
> indices[dim] = i;
> axis_ptr_array = _get_axis_pointer(indices, axis, a,
> axis_ptr_array, dim+1);
> }
> return axis_ptr_array;
> }
> }
>
>
> static double **get_axis_pointers(ndarray *a, int axis, npy_intp *count)
> {
> npy_intp indices[NPY_MAXDIMS];
> double **out, **tmp;
> npy_intp i, j;
> j = 1;
> for (i=0; i < a->nd; i++) {
> if (i != axis)
> j *= a->dimensions[i];
> }
> *count = j;
>
> out = (double **) malloc(*count * sizeof(double*));
> if (out == NULL) {
> *count = 0;
> return NULL;
> }
> tmp = out;
> switch (a->nd) {
> /* for one dimension we just return the data pointer */
> case 1:
> *tmp = (double *)a->data;
> break;
> /* specialized for two dimensions */
> case 2:
> switch (axis) {
> case 0:
> for (i=0; i<a->dimensions[1]; i++)
> *tmp++ = (double *)(a->data + i*a->strides[1]);
> break;
>
> case 1:
> for (i=0; i<a->dimensions[0]; i++)
> *tmp++ = (double *)(a->data + i*a->strides[0]);
> break;
> }
> break;
> /* specialized for three dimensions */
> case 3:
> switch (axis) {
> case 0:
> for (i=0; i<a->dimensions[1]; i++)
> for (j=0; j<a->dimensions[2]; j++)
> *tmp++ = (double *)(a->data + i*a->strides[1] +
> j*a->strides[2]);
> break;
> case 1:
> for (i=0; i<a->dimensions[0]; i++)
> for (j=0; j<a->dimensions[2]; j++)
> *tmp++ = (double *)(a->data + i*a->strides[0] +
> j*a->strides[2]);
> break;
>
> case 2:
> for (i=0; i<a->dimensions[0]; i++)
> for (j=0; j<a->dimensions[1]; j++)
> *tmp++ = (double *)(a->data + i*a->strides[0] +
> j*a->strides[1]);
>
> }
> break;
> /* four or more dimensions: use recursion */
> default:
> for (i=0; i<a->nd; i++) indices[i] = 0;
> _get_axis_pointer(indices, axis, a, out, 0);
>
> }
> done:
> return out;
>
> }
>
>
> Another thing I did when reimplementing lfilter was "copy-in copy-out"
> for strided arrays.
>
>
> What is copy-in copy out ? I am not familiar with this term ?
>
>
>
>
> Strided memory access is slow. So it often helps to make a temporary copy
> that are contiguous.
>
>
But for an initial refactoring it probably falls in the category of
premature optimization. Another thing to avoid on the first go around is
micro-optimization, as it tends to complicate the code and often doesn't do
much for performance.
<snip>
Chuck
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/numpy-discussion/attachments/20100610/39a10e21/attachment.html>
More information about the NumPy-Discussion
mailing list