<br><br><div><span class="gmail_quote">On 1/6/07, <b class="gmail_sendername">Travis Oliphant</b> <<a href="mailto:oliphant@ee.byu.edu">oliphant@ee.byu.edu</a>> wrote:</span><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
Timothy Hochberg wrote:<br>><br>><br>><br>> On 1/6/07, *Robert Kern* < <a href="mailto:robert.kern@gmail.com">robert.kern@gmail.com</a><br>> <mailto:<a href="mailto:robert.kern@gmail.com">robert.kern@gmail.com
</a>>> wrote:<br>><br>>     Sean R. Lynch wrote:<br>><br>>     >>>> x = zeros((3,))<br>>     >>>> x[array([0, 1, 1])] += array([1, 1, 1])<br>>     >>>> x<br>>     > array([ 1.,  1.,  0.])
<br>>     ><br>>     > If this worked the way I was hoping, the output would be [1 2 0]<br>>     because<br>>     > it would add to element 1 twice due to its duplication in the<br>>     advanced<br>
>     > selection array.<br>>     ><br>>     > Is the current behavior intentional or is it an accident of<br>>     > implementation?<br>><br>>     It is an unavoidable consequence of the way Python interprets that
<br>>     code and the<br>>     way numpy arrays are fundamentally implemented. See Travis<br>>     Oliphant's, Tim<br>>     Hochberg's and my posts in the thread "Histograms via indirect<br>>     index arrays" for
<br>>     more details.<br>><br>>     <a href="http://projects.scipy.org/pipermail/numpy-discussion/2006-March/thread.html#6877">http://projects.scipy.org/pipermail/numpy-discussion/2006-March/thread.html#6877</a>
<br>><br>><br>> Do we have to revisit that thread? I seem to recall it getting kind of<br>> cranky. To avoid reliving that, I will attempt dredge up the relevant<br>> issue:<br>><br>> "a[indx]+=b" should be the same as "a[indx]=a[indx]+b". All else
<br>> follow from that. If staring at that for a while doesn't enlighten<br>> you, then you will have to read that thread.<br>><br>> [ I suspect that in theory we could make the += form behave as you<br>> expect, but that would break the identity above, which would confuse a
<br>> bunch of people]<br>><br><br>I don't think we could make it work as he expects (and not radically<br>change NumPy itself so that other operations are very different) because<br>of the limitations of Python.
<br><br>The point was that it is too complicated to do any differently (and is<br>probably impossible).</blockquote><div><br>Oh, you really shouldn't use words like "impossible" unless you want someone to figure out how to do it. Some people view that as a challenge ;-)
<br><br>It appears like it is possible, although it requires a certain amount dubious hackery. Basically, you need a hidden tag on arrays that keeps track of whether that array was the result of an inplace op and what kind. This gets combined with a little 
sys.getrefcount magic to determine if the object in question is a temporary. Below is a sketch of how it probably could be accomplished. Not that I necessarily think it's a good idea, particularly since the implementation is so dicey.
<br><br>Oh, it's quite possible there are some corner and not so corner cases that leak through too.<br><br>    import numpy as np<br>    import sys<br>    <br>    class BecauseImContrary(np.ndarray):<br>        """Super hacktastic way to get repeated values to work
<br>        <br>        >>> a = np.arange(5).view(BecauseImContrary)<br>        >>> indices = [0, 1, 0, 2]<br>        <br>        # The basic test case, does repeated adds work.<br>        >>> a1 = 
a.copy()<br>        >>> a1[indices] += 1<br>        >>> print a1<br>        [2 2 3 3 4]<br>        <br>        # Now some tests to make sure it doesn't add things when it shouldn't<br>        >>> a1 = 
a.copy()<br>        >>> a1[indices] = a1[indices] + 1<br>        >>> print a1<br>        [1 2 3 3 4]<br>        >>> def nested(x):<br>        ...     y = np.ones_like(x)<br>        ...     y += 998
<br>        ...     return y<br>        >>> hasattr(nested(a1), '_iop')<br>        False<br>        >>> a[indices] = a[indices]<br>        >>> print a<br>        [0 1 2 3 4]<br>        >>> a1 = 
a.copy()<br>        >>> a1 += 1<br>        >>> print a1<br>        [1 2 3 4 5]<br>        <br>        """<br>        def __iadd__(self, other):<br>            result = np.ndarray.__iadd__(self, other)
<br>            count = sys.getrefcount(self)<br>            assert count >= 6<br>            if count == 6:<br>                result._iop = 'add'<br>            return result<br>        def __setitem__(self, key, value):
<br>            count = sys.getrefcount(value)<br>            assert count >= 5<br>            # Only works for 1D indices, cause I'm lazy.<br>            if count == 5 and hasattr(value, '_iop') and isinstance(key, (
np.ndarray, list)):<br>                key = np.asarray(key)<br>                for i in key:<br>                    self[i] = 0<br>                value = np.ones_like(key) * value<br>                for i, x in zip(key, value):
<br>                    self[i] += x<br>            else:<br>                np.ndarray.__setitem__(self, key, value)<br>             <br>    if __name__ == '__main__':<br>        import doctest, scratch<br>        
doctest.testmod(scratch)<br> </div><br></div><br>