[Matrix-SIG] Creative slicing

Gary Strangman Gary Strangman <strang@NMR.MGH.Harvard.EDU>
Thu, 9 Sep 1999 19:35:06 -0400 (EDT)


> Try this code. It is not general for the number of dimensions, but
> general for the length of the dimensions. Perhaps it is a start...

<snip>

A good start indeed.  Thanks!  I just thought I'd pass along the following
code to any others who might be interested.  (In the FWIW category, I
agree that this kind of slicing would be an excellent addition to the
NumPy core.)

> x=arange(10*4*5)
> x.shape = (10,4,5) 
> y = ones((4,5))*2
> y[0,0]=3
> y[0,1]=4
> y[1,0]=5
> y.shape = (4,5)   # filled with ints in the 0-9 range 
>  
> # These lines need to be adapted for more dimensions
> yi,xi=indices(y.shape)
> linindex = y*product(x.shape[1:])+yi*y.shape[-2]+xi

This wasn't quite right ... but very close (an off-by-one error, probably
a mail typo).  Instead use ... 

linindex = y*(product(x.shape[1:]))+yi*y.shape[1]+xi

> z=take(ravel(x),ravel(linindex))
> z.shape=(4,5)

Starting from your idea, I modified the code to work in the N-D case. 
It's not exactly pretty (and I didn't bother to find a way around the
for-loop) but it seems to work.  This general type of workaround is not
going to be fast for large arrays ... which is what would make it nice to
have such a function ... a[indices] = vals ... in the numpy core. ;-)

Gary

<------CUT BELOW------>

def elementslice(a, indexarray, dimension=0):
    """
Usage:   elementslice(a, indexarray, dimension=0)
Returns: a[indices] along 'dimension', resulting shape = indices.shape
"""
    if dimension <> 0:  # for convenience, put operating dimension first
        newdims = range(len(a.shape))
        del newdims[dimension]
        newdims = [dimension] + newdims
        a = N.transpose(a,newdims)
    else:
        newdims = a.shape
    ind = N.indices(indexarray.shape)
    linindex = indexarray*N.product(a.shape[1:])  # get offsets for 1st dim
    for i in range(len(ind)-1):  # for remaining dims but one, add in offsets
        multindices = N.product(indexarray.shape[i+1:])
        linindex = linindex + ind[i]*multindices
    linindex = linindex + ind[-1]                 # add in last dim's offsets
    slice = N.take(N.ravel(a),N.ravel(linindex))  # get vals from ravel'd array
    return N.reshape(slice,indexarray.shape)      # reshape properly


--------------------------------------------------------------
Gary Strangman, PhD           |  Neural Systems Group
Office: 617-724-0662          |  Massachusetts General Hospital
Home:   xxx-xxx-xxxx          |  13th Street, Bldg 149, Room 9103
strang at nmr.mgh.harvard.edu |  Charlestown, MA  02129
http://www.nmr.mgh.harvard.edu/Neural_Systems_Group/gary/