Psyched
Psyched

Reputation: 43

numpy 2d and 1d addition flat

While using the example from NumPy Book while starting out with NumPy I noted an example:

a = zeros((4, 5))
b = ones(6)
add(b, b, a[1:3, 0:3].flat)
print(a)

returns

array([[0, 0, 0, 0, 0]
       [2, 2, 2, 0, 0]
       [2, 2, 2, 0, 0]
       [0, 0, 0, 0, 0]])

However, when I try this code, it results in the following error:

add(b, b, a[1:3, 0:3].flat)

TypeError: return arrays must be of ArrayType"

Could anyone please shed some light on this problem?

Upvotes: 4

Views: 152

Answers (1)

MSeifert
MSeifert

Reputation: 152587

If you have 2 arguments for numpy.add they are taken as the two operands that are added. If you give 3 arguments the first two are the ones that are added and the third one is the result. Well actually not the result but the array where the result should be saved in.

So you added b with b and wanted to store it in a[1:3, 0:3].flat.

Let's just try to np.add(b, b) which gives

import numpy as np
a = np.zeros((4, 5))
b = np.ones(6)
np.add(b, b)
# returns array([ 2.,  2.,  2.,  2.,  2.,  2.])

So now I tried a[1:3, 0:3].flat which returns <numpy.flatiter at 0x22204e80c10>. This means that it returns an iterator so it's no array. But we don't need an iterator we want an array. There is a method called ravel(). So trying a[1:3, 0:3].ravel() returns:

array([ 0.,  0.,  0.,  0.,  0.,  0.])

so we have an array. Especially the array is also usable for storing the result (same shape!). So I tried:

np.add(b, b, a[1:3, 0:3].ravel())
# array([ 2.,  2.,  2.,  2.,  2.,  2.])

But let's see if a has changed:

a
#array([[ 0.,  0.,  0.,  0.,  0.],
#       [ 0.,  0.,  0.,  0.,  0.],
#       [ 0.,  0.,  0.,  0.,  0.],
#       [ 0.,  0.,  0.,  0.,  0.]])

So a hasn't changed. That's because ravel() only returns a view (assignment would propagate to the unravelled array) if possible otherwise it returns a copy. And saving the result in a copy is rather pointless because the whole point of the out parameter is that the operation is done in-place. I'm only guessing why a copy is made but I think it's because we take a portion out of a bigger array where the portion is not contiguous in the memory.

So I would propose that you don't use the out parameter in this case but use the return of the np.add and store it inside the specified region in a:

a[1:3, 0:3] = np.add(b, b).reshape(2,3) # You need to reshape here!
a
#array([[ 0.,  0.,  0.,  0.,  0.],
#       [ 2.,  2.,  2.,  0.,  0.],
#       [ 2.,  2.,  2.,  0.,  0.],
#       [ 0.,  0.,  0.,  0.,  0.]])

Also a[1:3, 0:3].flat = np.add(b, b) works.

I think the book is either outdated and it worked with an older numpy version or it never worked at all and it was a mistake in the book.

Upvotes: 3

Related Questions