[Numpy-discussion] Notes on transitioning to numarray.

Tim Hochberg tim.hochberg at ieee.org
Mon Nov 10 08:28:02 CST 2003

[There is a html version of this not at 

Numeric to numarray Conversion Notes

I finally bit the bullet over the last few days and moved my current
project from using Numeric to using  numarray. This was a reasonably
large undertaking, involving the modification of in excess of thirty
modules. For the most part it went smoothly, requiring only the
replacement of ``import Numeric`` with ``import numarray`` [1]_.
However, in the course of the move I ran into several bugs, as well
as quite a few things that may be bugs or may be deliberate changes
from Numeric. I took some notes as the conversion progressed which I
will attempt to render here in some halfway decipherable form.

There are still some interoperability issues with Numeric and numarray,
not all of which I took the time to track down. In many cases, I solved
problems that cropped up in the conversion simply by converting some more
of the code and thus reducing the amount of mixed operations. The ones that
I did track down are reported below.

I'm using numarray 0.7 with Python 2.3 on Windows XP.

.. [1] Actually, to be strictly accurate, I replaced ``import Numeric as 
np`` with ``import numarray as na`` and
        then replaced ``np`` with ``na``.


The following few things are almost certainly bugs. I haven't had
time to dig into them in any depth, but I have tried to reduce them
each to a small failing case:

    1. Copying a slice of an array onto a different slice of the same
    array fails.
    >>> y = na.arange(4)
    >>> y[1:] = y[:-1]
    >>> y # Should be array([0, 0, 1, 2])
    array([0, 0, 0, 0])
    2. ``sqrt``, ``Power``, `and ``**`` all fail on complex zero (0j).
    >>> y = na.arange(4) + 0j
    >>> na.sqrt(y)
    Warning: Encountered invalid numeric result(s)  in sqrt
    Warning: Encountered divide by zero(s)  in sqrt
    Warning: Encountered invalid numeric result(s)  in not_equal
    Warning: Encountered invalid numeric result(s)  in not_equal
    array([-1.#IND    -1.#INDj,  1.        +0.j    ,  1.41421356+0.j    ,
            1.73205081+0.j    ])
    And similarly for ``power`` and ``**``. Note that in addition to
    the warnings, the value for the sqrt(0j) is incorrect.
    3. Mixing arrays and lists in the constructor of array can cause
    it to fail:
    >>> a = na.array([na.array([])]*3)
    Traceback (most recent call last):
      File "<stdin>", line 1, in ?
      File "C:\Python23\lib\site-packages\numarray\numarraycore.py", 
line 288, in array
        return fromlist(sequence, type, shape)
      File "C:\Python23\lib\site-packages\numarray\numarraycore.py", 
line 175, in fromlist
        arr = _gen.concatenate(l)
      File "C:\Python23\Lib\site-packages\numarray\generic.py", line 
1008, in concatenate
        return _concat(arrs)
      File "C:\Python23\Lib\site-packages\numarray\generic.py", line 
998, in _concat
    libnumarray.error: copy4bytes: access beyond buffer. offset=3 

    ``shape`` fails in the same way. Probably other functions as well.
    4. ``linear_algebra.determinant`` returns a length-1 vector when it 
should return a scalar.
    (Actually, I believe it sometimes returns a scalar and sometimes a 
length-1 vector, but
    I can't find a test case to reproduce that).
    >>> a = na.reshape(na.arange(4), (2,2))
    >>> la.determinant(a)
    5. Assigning a Numeric slice to a numarray array fails:
    >>> a = na.arange(3)
    >>> b = Numeric.arange(3)
    >>> a[:] = b
    Traceback (most recent call last):
      File "<stdin>", line 1, in ?
      File "C:\Python23\Lib\site-packages\numarray\generic.py", line 
505, in _slicedIndexing
    TypeError: argument is not array or number

Probable Bugs

Now on to things that are probably bugs, but it's possible that they
represent deliberate changes from Numeric's behavior.

    6. numarray.dot doesn't accept scalars, Numeric.dot does.
    >>> na.dot(1,1)
    Traceback (most recent call last):
      File "<stdin>", line 1, in ?
      File "C:\Python23\lib\site-packages\numarray\numarraycore.py", 
line 939, in dot
        return ufunc.innerproduct(a, _gen.swapaxes(inputarray(b), -1, -2))
      File "C:\Python23\lib\site-packages\numarray\ufunc.py", line 1892, 
in innerproduct
        if a._shape[-1] != b._shape[-1]:
    IndexError: tuple index out of range

    7. na.searchsorted does not accept scalars for its second argument. 
It always
    takes and returns vectors.
    >>> na.searchsorted(na.arange(5), 1.5)
    Traceback (most recent call last):
      File "<stdin>", line 1, in ?
      File "C:\Python23\lib\site-packages\numarray\ufunc.py", line 1821, 
in searchsorted
        outarr = _nc.NumArray(shape=len(values), type=Long)
    ValueError: Rank-0 array has no length.
    >>> na.searchsorted(na.arange(5), [1.5])

    8. add.reduce takes dim as a keyword argument instead of axis. It is 
documented_ to take axis.
    I imagine this applies to other opp.reduce methods as well.
    .. _documented: 

    9. ``where`` and probably other functions do not appear to use 
asarray on all of their
    arguments. As a result, nonnumarray sequences are not directly 
usable in these functions as
    they are in their Numeric equivalents. In particular, lists, tuples 
and Numeric arrays do
    not work:
    >>> na.where([0,1,1,0], na.arange(4), [-99,-99,-99,-99])
    Traceback (most recent call last):
      File "<stdin>", line 1, in ?
      File "C:\Python23\Lib\site-packages\numarray\generic.py", line 
970, in where
        return choose(ufunc.not_equal(condition, 0), (y,x), out)
      File "C:\Python23\lib\site-packages\numarray\ufunc.py", line 1446, 
in __call__
        computation_mode, woutarr, cfunc, ufargs = \
      File "C:\Python23\lib\site-packages\numarray\ufunc.py", line 1462, 
in _setup
        convType = _maxPopType(in2)
      File "C:\Python23\lib\site-packages\numarray\ufunc.py", line 1401, 
in _maxPopType
        raise TypeError( "Type of '%s' not supported" % repr(x) )
    TypeError: Type of '[-99, -99, -99, -99]' not supported

    10. ``take`` now requires a keyword argument for axis. Attempting 
the to specify the axis
    with a nonkeyword arg results in strange behavior. The docs don't 
appear to describe
    this behavior:
    >>> a = na.reshape(na.arange(9), (3,3))
    >>> a
    array([[0, 1, 2],
           [3, 4, 5],
           [6, 7, 8]])
    >>> na.take(a, [0,1], 1)
    array([1, 4])
    >>> na.take(a, [0,1], axis=1)
    array([[0, 1],
           [3, 4],
           [6, 7]])

    11. ``argmax`` returns shape () arrays instead of scalars when used 
on 1D arrays. These cannot be used
    to index lists

    >>> a = na.arange(9)
    >>> i = na.argmax(a)
    >>> a[i]
    >>> range(9)[i]
    Traceback (most recent call last):
      File "<stdin>", line 1, in ?
    TypeError: list indices must be integers
    >>> i

Non Bugs

These are some things that would probably not be considered bugs, but 
that I'd like to mention
because they either tripped me up or made the conversion and thus my 
life over the last few
days more difficult than it needed to be. Let the whining begin.

    12. ``anArray.conjugate()`` acts in place. 
``aComplexNumber.conjugate()`` returns a new
    number. This seems like a very bad state of affairs. 
``anArray.conjugate()`` should be
    >>> zarray = na.arange(4) * 1j
    >>> zarray
    array([ 0.+0.j,  0.+1.j,  0.+2.j,  0.+3.j])
    >>> zarray.conjugate()
    >>> zarray
    array([ 0.+0.j,  0.-1.j,  0.-2.j,  0.-3.j])
    >>> z = 1+1j
    >>> z.conjugate()
    >>> z

    13. ``Error.popMode`` should raise an error if the last mode is 
popped off the stack.
    Currently the error gets raised the next time a numeric operation is 
used which may
    be far away from the inadvertent pop.

    >>> na.Error.popMode() # Error should be here
    _NumErrorMode(overflow='warn', underflow='warn', 
dividebyzero='warn', invalid='warn')
    >>> zarray /= 0 # Not here.
    Traceback (most recent call last):
      File "<stdin>", line 1, in ?
      File "C:\Python23\lib\site-packages\numarray\numarraycore.py", 
line 704, in __idiv__
        ufunc.divide(self, operand, self)
      File "C:\Python23\lib\site-packages\numarray\ufunc.py", line 120, 
in handleError
        modes = Error.getMode()
      File "C:\Python23\lib\site-packages\numarray\ufunc.py", line 99, 
in getMode
        return l[-1]
    IndexError: list index out of range

    14. I'm of the opinion that the underflow behavior should default to 
'ignore' not 'warn'.
    Nine times out of ten that's what one wants, and a default that you 
have to override most
    of the time is not a good default. It's possible that this opinion 
may be based on floating
    point naivet, but it's mine and I'm sticking to it for the time being.
    15. Now we're getting to very minor things: Argmax's behavior has 
changed, so that in the
    case of ties, you will get different results than with Numeric. 
Perhaps ``>`` became ``>=``?
    >>> a = na.array([0,1,0,1])
    >>> na.argmax(a)
    >>> np.argmax(a)

    16. ``array_repr`` no longer supports the ``suppress_small`` argument.
    17. ``take`` is really only useful for array types in numarray. In 
Numeric it was sometimes
    useful for choosing stuff from lists of objects. My impression is 
that numarray doesn't try
    to support objects; that's probably OK since Numeric's support was 
pretty iffy.

    18. The fact that array comparison return booleans in numarray broke 
some of my code because I
    do some comparisons and then sum the results. In numarray these get 
summed as Int8 and thus overflow.
    I don't consider this a problem, I just thought I'd mention it in 
case someone else runs into it.


Tim Hochberg


More information about the Numpy-discussion mailing list