-
-
Notifications
You must be signed in to change notification settings - Fork 12.2k
BUG: np.asarray does not create new array view when different but compatible type code is passed in the dtype argument (Trac #870) #1468
Description
Original ticket http://projects.scipy.org/numpy/ticket/870 on 2008-08-01 by trac user damian.eads, assigned to @stefanv.
Examining ndarray type codes is common in C extensions before passing array contents to functions expecting int* or long*. The type codes are ideal ensure the contents can be safely casted to int* or long* on the host machine. In some cases, the int and long types are of the same size but their type codes are different. np.asarray(..., dtype='i') should be used to create a new array view with the type code the C type code expected by the C extension; however, it does not appear to work when using it for this purpose.
Problem
I construct X as a C-long array and then I cast it to a C-int array Y (using np.asarray) but the type code does not change. However, when constructing the array from scratch as a C-int (using np.zeros), I get the right type code (ie 5).
Expectation of Behavior
I assumed that when X gets casted to a C-int, no copying should occur but a new array view should be constructed with the C-int type code.
Workaround
Casting from a C-long (type code 7) to a double to a C-int returns an array with the right type code but an ugly double copy occurs.
Recreation
# Construct X as a C-long.
In [16]: X=numpy.zeros((10,10),dtype='l')
# Now cast X to a C-int.
In [17]: Y=numpy.asarray(X, dtype='i')
# Check X and Y's data type; they are the same.
In [18]: X.dtype
Out[18]: dtype('int32')
In [19]: Y.dtype
Out[19]: dtype('int32')
# Their type codes are the same.
In [20]: X.dtype.num
Out[20]: 7
In [21]: Y.dtype.num
Out[21]: 7
# Constructing with dtype='i', gives the right type code.
In [22]: Z=numpy.zeros((10,10),dtype='i')
In [23]: Z.dtype
Out[23]: dtype('int32')
In [24]: Z.dtype.num
Out[24]: 5
Stefan van der Walt observes that the dtype objects are compared for equality but not the type codes. This explains why the asarray function does not create a new view.
In [4]: np.dtype('i') == np.dtype('l')
Out[4]: True
In [5]: np.dtype('i').num == np.dtype('l').num
Out[5]: False
Fix
Check the type codes for equality, not the dtype objects, to decide whether to create a new array view in np.asarray.
summary @seberg:
This is still true, the array fast-paths to do the no-copy behaviour is correct to not copy, but apparently not aggressive enough with creating views, on 64bit linux:
arr = np.array([1, 2, 3, 4], "q")
np.asarray(arr, dtype="l") is arr # True
np.dtype("l").num == np.dtype("q").num # not True
The good news: This really should be a simple fix!