# [Numpy-discussion] s are mutable scalars

Huaiyu Zhu huaiyu_zhu at yahoo.com
Tue Sep 17 00:05:01 CDT 2002

```Some of the choices between rank-0 arrays and new scalar types
might be resolved by enumerating the properties desired of them.

Most properties of rank-0 arrays could be fixed by consistency
requirements alone, using operations that reduce array dimensions.

Let a = ones((2,3,4))
b = sum(a)
c = sum(b)
d = sum(c)

Property 1: the shape of an array is a tuple of integers
a.shape == (2, 3, 4)
b.shape == (3, 4)
c.shape == (4,)
d.shape == ()

Property 2: rank(a) == len(a.shape)
rank(a) == 3 == len(a.shape)
rank(b) == 2 == len(b.shape)
rank(c) == 1 == len(c.shape)
rank(d) == 0 == len(d.shape)

Property 3: len(a) == a.shape[0]
len(a) == 2 == a.shape[0]
len(b) == 3 == b.shape[0]
len(c) == 4 == c.shape[0]
len(d) == Exception == d.shape[0]

# Currently the last is wrong?

Property 4: size(a) == product(a.shape)
size(a) == 24 == product(a.shape)
size(b) == 12 == product(b.shape)
size(c) == 4 == product(c.shape)
size(d) == 1 == product(d.shape)

# Currently the last is wrong

Property 5: rank-0 array behaves as mutable numbers when used as value
array(2)  is similar to 2
array(2.0)  is similar to 2.0
array(2j)  is similar to 2j

# This is a summary of many concrete properties.

Property 6: Indexing reduces rank. Slicing preserves rank.
a[:,:,:].shape = (2, 3, 4)
a[1,:,:].shape = (3, 4)
a[1,1,:].shape = (4,)
a[1,1,1].shape = ()

Property 7: Indexing by tuple of ints gives scalar.
a[1,1,1] == 1
b[1,1] == 2
c[1,] == 6
d[()] == 24

# So rank-0 array indexed by empty tuple should be scalar.
# Currently the last is wrong

Property 8: Indexing by tuple of slices gives array.
a[:,:,:] == ones((2,3,4))
b[:,:] == ones((3,4)) * 2
c[:] == ones((,4)) * 6
d[()] == ones(()) * 24

# So rank-0 array indexed by empty tuple should be rank-0 array.
# Currently the last is wrong

Property 9: Indexing as lvalues
a[1,1,1] = 2
b[1,1] = 2
c[1,] = 2
d[()] = 2

Property 10: Indexing and slicing as lvalues
a[:,:,:] = ones((2, 3, 4))
a[1,:,:] = ones((3, 4))
a[1,1,:] = ones((4,))
a[1,1,1] = ones(())

# But the last is wrong.

Conclusion 1: rank-0 arrays are equivalent to scalars.
See properties 7 and 8.

Conclusion 2: rank-0 arrays are mutable.
See property 9.

Conclusion 3: shape(scalar), size(scalar) are all defined, but len(scalar)
should not be defined.

See conclusion 1 and properties 1, 2, 3, 4.

Conclusion 4: A missing axis is similar to having dimension 1.
See property 4.

Conclusion 5: rank-0 int arrays should be allowed to act as indices.
See property 5.

Conclusion 6: rank-0 arrays should not be hashable except by object id.
See conclusion 2.

Discussions:

- These properties correspond to the current implementation quite well,
except a few rough edges.

- Mutable scalars are useful in their own rights.

- Is there substantial difference in overhead between rank-0 arrays and
scalars?

- How to write literal values?  array(1) is too many characters.

- For rank-1 and rank-0 arrays, Python notation distinguishes:

c[1] vs c[1,]
d[] vs d[()]

Should these be used to handle semantic difference between indexing
and slicing?  Should d[] be syntactically allowed?

Hope these observations help.

Huaiyu

```