Re: [Numpy-discussion] Why is the shape of a singleton array the empty tuple?

2010-03-07 Thread Friedrich Romstedt
First, to David's routine:

2010/3/7 David Goldsmith d.l.goldsm...@gmail.com:
 def convert_close(arg):
 arg = N.array(arg)
 if not arg.shape:
 arg = N.array((arg,))
 if arg.size:
 t = N.array([0 if N.allclose(temp, 0) else temp for temp in arg])
 if len(t.shape) - 1:
 return N.squeeze(t)
 else:
 return t
 else:
 return N.array()

Ok, chaps, let's code:

import numpy

def convert_close(ndarray, atol = 1e-5, rtol = 1e-8):
ndarray_abs = abs(ndarray)
mask = (ndarray_abs  atol + rtol * ndarray_abs)
return ndarray * mask

 python -i close.py
 a = numpy.asarray([1e-6])
 convert_close(a)
array([ 0.])
 a = numpy.asarray([1e-6, 1])
 convert_close(a)
array([ 0.,  1.])
 a = numpy.asarray(1e-6)
 convert_close(a)
0.0
 a = numpy.asarray([-1e-6, 1])
 convert_close(a)
array([ 0.,  1.])

It's not as good as Robert's (so far virtual) solution, but :-)



 On Sat, Mar 6, 2010 at 10:26 PM, Ian Mallett geometr...@gmail.com wrote:
 On Sat, Mar 6, 2010 at 9:46 PM, David Goldsmith d.l.goldsm...@gmail.com
 wrote:
 Thanks, Ian.  I already figured out how to make it not so, but I still
 want to understand the design reasoning behind it being so in the first
 place (thus the use of the question why (is it so), not how (to make it
 different)).

1. First from a mathematical point of view (don't be frightened):

When an array has shape ndarray.shape, then the number of elements contained is:

numpy.asarray(ndarray.shape).mul()

When I type now:

 numpy.asarray([]).prod()
1.0

This is the .shape of an scalar ndarray (without any strides), and
therefore such a scalar ndarray holds exactly one item.

Or, for hard-core friends (-:

 numpy.asarray([[]])
array([], shape=(1, 0), dtype=float64)
 numpy.asarray([[]]).prod()
1.0

So, ndarrays without elements yield .prod() == 1.0.  This is sensible,
because the product shall be algorithmically defined as:

def prod(ndarray):
product = 1.0
for item in ndarray.flatten():
product *= item
return product

Thus, the product of nothing is defined to be one to be consistent.

One would end up with the same using a recursive definition of prod()
instead of this iterative one.


2. From programmer's point of view.

You can always write:

ndarray[()].

This means, to give no index at all.  Indeed, writing:

ndarray[1, 2]

is equivalent to writing:

ndarray[(1, 2)]  ,

as keys are always passed as a tuple or a scalar.  Scalar in case of:

ndarray[42]  .

Now, the call:

ndarray[()]

shall return 'something', which is the complete ndarray, because we
didn't indice anything.  For multidimensional arrays:

a = numpy.ndarray([[1, 2], [3, 4]])

the call:

a[0]

shall return:

array([1, 2]).

This is clear.  But now, what to return, if we consume all the indices
available, e.g. when writing:

a[0, 0]  ?

This means, we return the scalar array

array(1)  .

That's another meaning of scalar arrays.  When indicing an ndarray a
with a tuple of length N_key, without slices, the return shape will be
always:

a.shape[N_key:]

This means, using all indices available returns a shape:

a.shape[a.ndim:] == []  ,

i.e., a scalar without shape.


To conclude, everything is consistent when allowing scalar arrays, and
everything breaks down if we don't.  They are some kind of 0, like the
0 in the whole numbers, which the Roman's didn't know of.  It makes
things simpler (and more consistent).  Also it unifies scalars and
arrays to only on kind of type, which is a great deal.

Friedrich
___
NumPy-Discussion mailing list
NumPy-Discussion@scipy.org
http://mail.scipy.org/mailman/listinfo/numpy-discussion


Re: [Numpy-discussion] Why is the shape of a singleton array the empty tuple?

2010-03-07 Thread David Goldsmith
On Sun, Mar 7, 2010 at 4:30 AM, Friedrich Romstedt 
friedrichromst...@gmail.com wrote:

 First, to David's routine:

 2010/3/7 David Goldsmith d.l.goldsm...@gmail.com:
  def convert_close(arg):
  arg = N.array(arg)
  if not arg.shape:
  arg = N.array((arg,))
  if arg.size:
  t = N.array([0 if N.allclose(temp, 0) else temp for temp in arg])
  if len(t.shape) - 1:
  return N.squeeze(t)
  else:
  return t
  else:
  return N.array()

 Ok, chaps, let's code:

 import numpy

 def convert_close(ndarray, atol = 1e-5, rtol = 1e-8):
ndarray_abs = abs(ndarray)
mask = (ndarray_abs  atol + rtol * ndarray_abs)
return ndarray * mask

  python -i close.py
  a = numpy.asarray([1e-6])
  convert_close(a)
 array([ 0.])
  a = numpy.asarray([1e-6, 1])
  convert_close(a)
 array([ 0.,  1.])
  a = numpy.asarray(1e-6)
  convert_close(a)
 0.0
  a = numpy.asarray([-1e-6, 1])
  convert_close(a)
 array([ 0.,  1.])


Great, thanks!

DG
___
NumPy-Discussion mailing list
NumPy-Discussion@scipy.org
http://mail.scipy.org/mailman/listinfo/numpy-discussion


[Numpy-discussion] Why is the shape of a singleton array the empty tuple?

2010-03-06 Thread David Goldsmith
 x = numpy.array(3)
 x
array(3)
 x.shape
()

My question is: why?

DG
___
NumPy-Discussion mailing list
NumPy-Discussion@scipy.org
http://mail.scipy.org/mailman/listinfo/numpy-discussion


Re: [Numpy-discussion] Why is the shape of a singleton array the empty tuple?

2010-03-06 Thread David Goldsmith
On Sat, Mar 6, 2010 at 9:37 PM, Ian Mallett geometr...@gmail.com wrote:

  x = numpy.array(3)
  x
 array(3)
  x.shape
 ()
  y = numpy.array([3])
  y
 array([3])
  y.shape
 (1,)

 Ian


Thanks, Ian.  I already figured out how to make it not so, but I still want
to understand the design reasoning behind it being so in the first place
(thus the use of the question why (is it so), not how (to make it
different)).

DG
___
NumPy-Discussion mailing list
NumPy-Discussion@scipy.org
http://mail.scipy.org/mailman/listinfo/numpy-discussion


Re: [Numpy-discussion] Why is the shape of a singleton array the empty tuple?

2010-03-06 Thread Ian Mallett
On Sat, Mar 6, 2010 at 9:46 PM, David Goldsmith d.l.goldsm...@gmail.comwrote:

 Thanks, Ian.  I already figured out how to make it not so, but I still want
 to understand the design reasoning behind it being so in the first place
 (thus the use of the question why (is it so), not how (to make it
 different)).

Well, I can't help you with that.  I would also ask why this design even
exists?   Equating an array with a single number doesn't make sense to me.
Ian
___
NumPy-Discussion mailing list
NumPy-Discussion@scipy.org
http://mail.scipy.org/mailman/listinfo/numpy-discussion


Re: [Numpy-discussion] Why is the shape of a singleton array the empty tuple?

2010-03-06 Thread David Goldsmith
On Sat, Mar 6, 2010 at 10:26 PM, Ian Mallett geometr...@gmail.com wrote:

 On Sat, Mar 6, 2010 at 9:46 PM, David Goldsmith 
 d.l.goldsm...@gmail.comwrote:

 Thanks, Ian.  I already figured out how to make it not so, but I still
 want to understand the design reasoning behind it being so in the first
 place (thus the use of the question why (is it so), not how (to make it
 different)).

 Well, I can't help you with that.  I would also ask why this design even
 exists?   Equating an array with a single number doesn't make sense to me.
 Ian


Here's an (unintended) use case:

I wanted to convert anything in an array that's close to zero to be zero
(and leave the rest as is), but I want it to be robust so that if it
receives a scalar, it can work w/ that, too.

Here's my (working) code (I'm sure that once Robert sees it, he'll be able
to replace it w/ a one-liner):

def convert_close(arg):
arg = N.array(arg)
if not arg.shape:
arg = N.array((arg,))
if arg.size:
t = N.array([0 if N.allclose(temp, 0) else temp for temp in arg])
if len(t.shape) - 1:
return N.squeeze(t)
else:
return t
else:
return N.array()

At first I wasn't casting arg to be an array upon entry, but I found that
if arg is a scalar, my list comprehension failed, so I had choose _some_
sort of sequence to cast scalars to; since arg will typically be an array
and that's what I wanted to return as well, it seemed most appropriate to
cast incoming scalars to arrays.  So I added the arg = N.array(arg) at the
beginning (N.array(array) = array, and N.array(non-array seq) does the
right thing as well), but the list comprehension still wouldn't work if
arg was a scalar upon entry; after many print statements and much
interactive experimenting, I finally figured out that this is because the
shape of N.array(scalar) is () (and I thence immediately guessed, correctly
of course, that N.array((scalar,)) has shape (1,)).  So I added the if not
arg.shape: to detect and correct for those zero size arrays, and now it
works fine, but I'd still like to know _why_ N.array(scalar).shape == () but
N.array((scalar,)).shape == (1,).  No biggy, just curious.

DG
___
NumPy-Discussion mailing list
NumPy-Discussion@scipy.org
http://mail.scipy.org/mailman/listinfo/numpy-discussion