[Numpy-discussion] Multiple assignment confusion
Perry Greenfield
perry at stsci.edu
Mon Nov 17 08:44:23 CST 2003
Benjamin Schwartz wrote:
> I am trying to interchange two pieces of an array. Here is my demo code:
>
> >>> from Numeric import *
> >>> a=array([.7,.1,.1,.1])
> >>> a=multiply.outer(a,a)
> >>> a=multiply.outer(a,a)
> >>> sum(sum(sum(sum(a))))
> 1.0000000000000002
> >>> a[1,0],a[1,1]=a[1,1],a[1,0]
> >>> sum(sum(sum(sum(a))))
> 0.93999999999999972
>
> So a is a four-dimensional array that sums to 1, but when I attempt to
> switch two 2-d sub-arrays of it I just end up duplicating one of them,
> shown by a change in the value of the sum (to .94). Is this behavior
> deliberate? It certainly seems to break Python's tuple-assignment model.
>
> What I would ideally like to do is perform this swap without more than
> two-elements'-worth of temporary storage. I.e. perform it as a pure
> reference swap or switch each pair of elements one by one, reusing
> temporary space. Is this possible with Numeric (or Numarray?)?
>
> Curious,
> Ben
>
I believe that this is simply a reflection of the fact that subarrays
(for Numeric and numarray) are views into the original array rather than
copies. A simpler example illustrates the same problem:
>>> a = reshape(arange(4), (2,2))
>>> a
array([[0, 1],
[2, 3]])
>>> a[0],a[1]=a[1],a[0]
>>> a
array([[2, 3],
[2, 3]])
>>>
Even though the right side of the assignment is stored
effectively in temporary variables, what is stored are views into
the original array, not copies of the subarrays. When the first
assignment is made to a[0] (=a[1]), the data in the reference
a[0] on the right hand side has changed as well since it views
exactly the same data. When it comes time to set a[1] it will be
copying from the updated a[0] and thus the duplication.
This doesn't happen for a list since one is essentially rebinding
the element in a list to another object. In other words, for this
case:
>>> b = [[0,1],[2,3]]
>>> b[0],b[1]=b[1],b[0]
>>> b
[[2, 3], [0, 1]]
>>>
assigning to b[0] is rebinding that list element away from the list
[0,1] to the list [2,3]; changing what the elements b refer to in no
way changes the contents of either of the lists that b contained.
Numeric arrays have a coupling across dimensions that doesn't exist
for lists since nested lists are analogous to arrays of pointers to
pointers whereas Numeric arrays are just multidimensional arrays with
no indirection involved.
The above behavior could be avoided if subarrays always produced
copies. This issue was given a great deal of discussion and thought
for numarray and for various reasons it was decided not to change
the behavior of slices and subarray references.
As to whether it is possible to switch subarray contents with only
using one or two temporary storage elements efficiently, offhand I
don't believe so, but I haven't given it much thought (and don't have
the time to) but perhaps someone else knows of an existing mechanism
to do so. Nothing prevents writing an extension to provide such
capability.
Perry Greenfield
More information about the Numpy-discussion
mailing list