[Numpy-discussion] Example Usage of Neighborhood Iterator in Cython

eat e.antero.tammi at gmail.com
Mon Oct 17 15:45:46 EDT 2011


Hi,

On Mon, Oct 17, 2011 at 9:19 PM, T J <tjhnson at gmail.com> wrote:

> I recently put together a Cython example which uses the neighborhood
> iterator.  It was trickier than I thought it would be, so I thought to
> share it with the community.  The function takes a 1-dimensional array
> and returns a 2-dimensional array of neighborhoods in the original
> area. This is somewhat similar to the functionality provided by
> segment_axis (http://projects.scipy.org/numpy/ticket/901), but I
> believe this slightly different in that neighborhood can extend to the
> left of the current index (assuming circular boundaries).  Keep in
> mind that this is just an example, and normal usage probably is not
> concerned with creating a new array.
>
> External link:  http://codepad.org/czRIzXQl
>
> --------------
>
> import numpy as np
> cimport numpy as np
>
> cdef extern from "numpy/arrayobject.h":
>
>    ctypedef extern class numpy.flatiter [object PyArrayIterObject]:
>        cdef int nd_m1
>        cdef np.npy_intp index, size
>        cdef np.ndarray ao
>        cdef char *dataptr
>
>    # This isn't exposed to the Python API.
>    # So we can't use the same approach we used to define flatiter
>    ctypedef struct PyArrayNeighborhoodIterObject:
>        int nd_m1
>        np.npy_intp index, size
>        np.PyArrayObject *ao # note the change from np.ndarray
>        char *dataptr
>
>    object PyArray_NeighborhoodIterNew(flatiter it, np.npy_intp* bounds,
>                                       int mode, np.ndarray fill_value)
>    int PyArrayNeighborhoodIter_Next(PyArrayNeighborhoodIterObject *it)
>    int PyArrayNeighborhoodIter_Reset(PyArrayNeighborhoodIterObject *it)
>
>    object PyArray_IterNew(object arr)
>    void PyArray_ITER_NEXT(flatiter it)
>    np.npy_intp PyArray_SIZE(np.ndarray arr)
>
>    cdef enum:
>        NPY_NEIGHBORHOOD_ITER_ZERO_PADDING,
>        NPY_NEIGHBORHOOD_ITER_ONE_PADDING,
>        NPY_NEIGHBORHOOD_ITER_CONSTANT_PADDING,
>        NPY_NEIGHBORHOOD_ITER_CIRCULAR_PADDING,
>        NPY_NEIGHBORHOOD_ITER_MIRROR_PADDING
>
> np.import_array()
>
> def windowed(np.ndarray[np.int_t, ndim=1] arr, bounds):
>
>    cdef flatiter iterx = <flatiter>PyArray_IterNew(<object>arr)
>    cdef np.npy_intp size = PyArray_SIZE(arr)
>    cdef np.npy_intp* boundsPtr = [bounds[0], bounds[1]]
>    cdef int hoodSize = bounds[1] - bounds[0] + 1
>
>    # Create the Python object and keep a reference to it
>    cdef object niterx_ = PyArray_NeighborhoodIterNew(iterx,
>        boundsPtr, NPY_NEIGHBORHOOD_ITER_CIRCULAR_PADDING, None)
>    cdef PyArrayNeighborhoodIterObject *niterx = \
>        <PyArrayNeighborhoodIterObject *>niterx_
>
>    cdef int i,j
>    cdef np.ndarray[np.int_t, ndim=2] hoods
>
>    hoods = np.empty((arr.shape[0], hoodSize), dtype=np.int)
>    for i in range(iterx.size):
>        for j in range(niterx.size):
>            hoods[i,j] = (niterx.dataptr)[0]
>            PyArrayNeighborhoodIter_Next(niterx)
>        PyArray_ITER_NEXT(iterx)
>        PyArrayNeighborhoodIter_Reset(niterx)
>    return hoods
>
> def test():
>    x = np.arange(10)
>    print x
>    print
>    print windowed(x, [-1, 3])
>    print
>    print windowed(x, [-2, 2])
>
>
> ----------
>
> If you run test(), this is what you should see:
>
> [0 1 2 3 4 5 6 7 8 9]
>
> [[9 0 1 2 3]
>  [0 1 2 3 4]
>  [1 2 3 4 5]
>  [2 3 4 5 6]
>  [3 4 5 6 7]
>  [4 5 6 7 8]
>  [5 6 7 8 9]
>  [6 7 8 9 0]
>  [7 8 9 0 1]
>  [8 9 0 1 2]]
>
> [[8 9 0 1 2]
>  [9 0 1 2 3]
>  [0 1 2 3 4]
>  [1 2 3 4 5]
>  [2 3 4 5 6]
>  [3 4 5 6 7]
>  [4 5 6 7 8]
>  [5 6 7 8 9]
>  [6 7 8 9 0]
>  [7 8 9 0 1]]
>
> windowed(x, [0, 2]) is almost like segment_axis(x, 3, 2, end='wrap').
>
Just wondering what are the main benefits, of your approach, comparing to
simple:
In []: a= arange(5)
In []: n= 10
In []: b= arange(n)[:, None]
In []: mod(a+ roll(b, 1), n)
Out[]:
array([[9, 0, 1, 2, 3],
       [0, 1, 2, 3, 4],
       [1, 2, 3, 4, 5],
       [2, 3, 4, 5, 6],
       [3, 4, 5, 6, 7],
       [4, 5, 6, 7, 8],
       [5, 6, 7, 8, 9],
       [6, 7, 8, 9, 0],
       [7, 8, 9, 0, 1],
       [8, 9, 0, 1, 2]])
In []: mod(a+ roll(b, 2), n)
Out[]:
array([[8, 9, 0, 1, 2],
       [9, 0, 1, 2, 3],
       [0, 1, 2, 3, 4],
       [1, 2, 3, 4, 5],
       [2, 3, 4, 5, 6],
       [3, 4, 5, 6, 7],
       [4, 5, 6, 7, 8],
       [5, 6, 7, 8, 9],
       [6, 7, 8, 9, 0],
       [7, 8, 9, 0, 1]])

Regards,
eat

> _______________________________________________
> NumPy-Discussion mailing list
> NumPy-Discussion at scipy.org
> http://mail.scipy.org/mailman/listinfo/numpy-discussion
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/numpy-discussion/attachments/20111017/01d2c44e/attachment.html>


More information about the NumPy-Discussion mailing list