[Matrix-SIG] QUERY: Array indexing

Tim Peters tim_one@email.msn.com
Fri, 12 Mar 1999 02:29:13 -0500

[Perry Stoll, locates an old timbot gather/scatter tutorial]

[Frank Horowitz chews & chews, but is still hungry]
> Thanks for that "incomparable Tim Peters" citation; that's a fascinating
> thread (have I sucked up enough yet? :-).

No.  Keep going!  We'll let you know when it's enough <wink>.

> My applications require local references in the array (somewhat akin to
> finite difference/convolution templates) but the operations I need to
> perform are more general than multiply-and-sum, hence I can't use the
> recent n-d convolve routines from Travis Oliphant (or was it someone
> else; senility is obviously setting in...)
> My approach to date has been to build shifted/rolled versions of the
> array, and operate with them (code available upon request, if anyone is
> silly enough to want it :-).  Obviously, this comes at a severe cost in
> memory ...

I don't know the best way to approach this in NumPy, perhaps because I
haven't yet installed it <wink>.  In straight Python I do stuff like this by
writing thin wrapper classes that leave the original matrices alone, merely
permuting the *indices* in __setitem__/__getitem__  (instead of physically
permuting the *data*).  For example, if your need to transpose a 2D array,
just swap the indices in the wrappers before passing them on to the actual
(still untransposed) array.

Here's an overly simplistic but complete example:

class VectorRotate:
    def __init__(self, data, shift):
        """Make data act as if it had been rotated left by shift slots"""
        self.x = data
        self.n = len(data)
        self.shift = shift

    def __getitem__(self, i):
        return self.x[(i + self.shift) % self.n]

    def __setitem__(self, i, val):
        self.x[(i + self.shift) % self.n] = val

    def __len__(self):
        return self.n

    def getdata(self):
        return self.x

vec = range(10)
print vec
r = VectorRotate(vec, 3)
r[0] = "hmm!"
for i in range(len(r)):
    print i, r[i]
print r.getdata()

That prints:

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
0 hmm!
1 4
2 5
3 6
4 7
5 8
6 9
7 0
8 1
9 2
[0, 1, 2, 'hmm!', 4, 5, 6, 7, 8, 9]

If you want to get really fancy, you can define arbitrarily complex
N-dimensional "mapping objects" independent of specific matrices, and
manipulate them for their own sake, reluctantly applying them to actual
matrices when deadlines get too close <wink>.

> It seems to me that something like this gather operation would do the
> trick, with one hell of a lot less memory thrashing, but I can't quite
> fathom the idiom for generating an indexing sequence that says something
> like "one over in the plus X direction at the same time as one over in the
> negative Z direction" .

If the above was suggestive enough, I expect you'll find this kind of thing
easier than gather/scatter.  Yes?

> ...
> Wisdom anyone? (Tim? :-)

Sorry, you didn't suck up enough to get a wise answer!

although-you're-off-to-a-fine-start-ly y'rs  - tim