[Numpy-discussion] A case for rank-0 arrays
oliphant.travis at ieee.org
Thu Feb 23 21:34:01 CST 2006
>The main criticism of supporting both scalars and rank-0 arrays is
>that it is "unpythonic" in the sense that it provides two almost
>equivalent ways to achieve the same result. However, I am now
>convinced that this is the case where practicality beats purity.
I think most of us agree that both will be with us for the indefinite
>The situation with ndarrays is somewhat similar. A rank-N array is
>very similar to a function with N arguments, where each argument has a
>finite domain (i-th domain of a is range(a.shape[i])). A rank-0 array
>is just a function with no arguments and as such it is quite different
>from a scalar.
I can buy this view. Nicely done.
>Just as a function with no arguments cannot be
>replaced by a constant in the case when a value returned may change
>during the run of the program, rank-0 array cannot be replaced by an
>array scalar because it is mutable. (See
>http://projects.scipy.org/scipy/numpy/wiki/ZeroRankArray for use
>Rather than trying to hide rank-0 arrays from the end-user and treat
>it as an implementation artifact, I believe numpy should emphasize the
>difference between rank-0 arrays and scalars and have clear rules on
>when to use what.
I agree. The problem is what should the rules be. Right now, there are
no clear rules other than rank-0 arrays --- DONT.
You make a case that we should not be so hard on rank-0 arrays.
>Here are three suggestions:
>1. Probably the most controversial question is what getitem should
>return. I believe that most of the confusion comes from the fact that
>the same syntax implements two different operations: indexing and
>projection (for the lack of better name). Using the analogy between
>ndarrays and functions, indexing is just the application of the
>function to its arguments and projection is the function projection
>((f, x) -> lambda (*args): f(x, *args)).
>The problem is that the same syntax results in different operations
>depending on the rank of the array.
>>>>x = ones((2,2))
>>>>y = ones(2)
>then x is projection and type(x) is ndarray, but y is
>indexing and type(y) is int32. Similarly, y[1,...] is indexing,
>while x[1,...] is projection.
>I propose to change numpy rules so that if ellipsis is present inside
>, the operation is always projection and both y[1,...] and
>x[1,1,...] return zero-rank arrays. Note that I have previously
>rejected Francesc's idea that x[...] and x[()] should have different
>meaning for zero-rank arrays. I was wrong.
I think this is a good and clear rule. And it seems like we may be
Anybody want to implement it?
>2. Another source of ambiguity is the various "reduce" operations such
>as sum or max. Using the previous example, type(x.sum(axis=0)) is
>ndarray, but type(y.sum(axis=0)) is int32. I propose two changes:
> a. Make x.sum(axis) return ndarray unless axis is None, making
>type(y.sum(axis=0)) is ndarray true in the example.
Hmm... I'm not sure. y.sum(axis=0) is the default spelling of sum(y).
Thus, this would cause all old code to return a rank-0 array.
Most people who write sum(y) want a scalar, not a "function with 0
> b. Allow axis to be a sequence of ints and make
>x.sum(axis=range(rank(x))) return rank-0 array according to the rule
So, this would sum over multiple axes? I guess I'm not opposed to
something like that, but I'm not really excited about it either. Would
that make sense for all methods that take the axis= argument?
> c. Make x.sum() raise an error for rank-0 arrays and scalars, but
>allow x.sum(axis=()) to return x. This will make numpy sum consistent
>with the built-in sum that does not work on scalars.
I don't think I like this at all.
This proposal has more far-reaching implications (and would require more
code changes --- though the axis= arguments do have a converter function
and so would not be as painful as one might imagine).
In short, I don't feel as enthused about portion 2 of your proposal.
>3. This is a really small change currently
>I propose to make shape=() valid in ndarray constructor.
I think we need more thinking about rank-0 arrays before doing something
like proposal 2. However, 1 and 3 seem simple enough to move forward
More information about the Numpy-discussion