diff options
Diffstat (limited to 'numpy/core')
-rw-r--r-- | numpy/core/_add_newdocs.py | 147 | ||||
-rw-r--r-- | numpy/core/_internal.py | 2 | ||||
-rw-r--r-- | numpy/core/code_generators/ufunc_docstrings.py | 4 | ||||
-rw-r--r-- | numpy/core/fromnumeric.py | 23 | ||||
-rw-r--r-- | numpy/core/include/numpy/ndarrayobject.h | 4 | ||||
-rw-r--r-- | numpy/core/multiarray.py | 18 | ||||
-rw-r--r-- | numpy/core/src/multiarray/convert_datatype.c | 173 | ||||
-rw-r--r-- | numpy/core/src/multiarray/convert_datatype.h | 4 | ||||
-rw-r--r-- | numpy/core/src/multiarray/dragon4.c | 38 | ||||
-rw-r--r-- | numpy/core/src/multiarray/dragon4.h | 38 | ||||
-rw-r--r-- | numpy/core/src/multiarray/item_selection.c | 20 | ||||
-rw-r--r-- | numpy/core/src/npysort/radixsort.c.src | 10 | ||||
-rw-r--r-- | numpy/core/src/umath/ufunc_object.c | 4 | ||||
-rw-r--r-- | numpy/core/src/umath/ufunc_type_resolution.c | 72 | ||||
-rw-r--r-- | numpy/core/tests/test_api.py | 12 | ||||
-rw-r--r-- | numpy/core/tests/test_deprecations.py | 7 | ||||
-rw-r--r-- | numpy/core/tests/test_dtype.py | 16 | ||||
-rw-r--r-- | numpy/core/tests/test_nditer.py | 2 | ||||
-rw-r--r-- | numpy/core/tests/test_numeric.py | 53 |
19 files changed, 451 insertions, 196 deletions
diff --git a/numpy/core/_add_newdocs.py b/numpy/core/_add_newdocs.py index 9f2b67a6b..84339ef23 100644 --- a/numpy/core/_add_newdocs.py +++ b/numpy/core/_add_newdocs.py @@ -936,11 +936,11 @@ add_newdoc('numpy.core.multiarray', 'empty', -------- >>> np.empty([2, 2]) array([[ -9.74499359e+001, 6.69583040e-309], - [ 2.13182611e-314, 3.06959433e-309]]) #random + [ 2.13182611e-314, 3.06959433e-309]]) #uninitialized >>> np.empty([2, 2], dtype=int) array([[-1073741821, -1067949133], - [ 496041986, 19249760]]) #random + [ 496041986, 19249760]]) #uninitialized """) @@ -1041,9 +1041,14 @@ add_newdoc('numpy.core.multiarray', 'fromstring', elements is also ignored. .. deprecated:: 1.14 - If this argument is not provided, `fromstring` falls back on the - behaviour of `frombuffer` after encoding unicode string inputs as - either utf-8 (python 3), or the default encoding (python 2). + Passing ``sep=''``, the default, is deprecated since it will + trigger the deprecated binary mode of this function. This mode + interprets `string` as binary bytes, rather than ASCII text with + decimal numbers, an operation which is better spelt + ``frombuffer(string, dtype, count)``. If `string` contains unicode + text, the binary mode of `fromstring` will first encode it into + bytes using either utf-8 (python 3) or the default encoding + (python 2), neither of which produce sane results. Returns ------- @@ -2699,10 +2704,15 @@ add_newdoc('numpy.core.multiarray', 'ndarray', ('astype', Notes ----- - Starting in NumPy 1.9, astype method now returns an error if the string - dtype to cast to is not long enough in 'safe' casting mode to hold the max - value of integer/float array that is being casted. Previously the casting - was allowed even if the result was truncated. + .. versionchanged:: 1.17.0 + Casting between a simple data type and a structured one is possible only + for "unsafe" casting. Casting to multiple fields is allowed, but + casting from multiple fields is not. + + .. versionchanged:: 1.9.0 + Casting from numeric to string types in 'safe' casting mode requires + that the string dtype length is long enough to store the max + integer/float value converted. Raises ------ @@ -5385,6 +5395,17 @@ add_newdoc('numpy.core.multiarray', 'dtype', ('alignment', More information is available in the C-API section of the manual. + Examples + -------- + + >>> x = np.dtype('i4') + >>> x.alignment + 4 + + >>> x = np.dtype(float) + >>> x.alignment + 8 + """)) add_newdoc('numpy.core.multiarray', 'dtype', ('byteorder', @@ -5431,7 +5452,16 @@ add_newdoc('numpy.core.multiarray', 'dtype', ('byteorder', """)) add_newdoc('numpy.core.multiarray', 'dtype', ('char', - """A unique character code for each of the 21 different built-in types.""")) + """A unique character code for each of the 21 different built-in types. + + Examples + -------- + + >>> x = np.dtype(float) + >>> x.char + 'd' + + """)) add_newdoc('numpy.core.multiarray', 'dtype', ('descr', """ @@ -5442,6 +5472,18 @@ add_newdoc('numpy.core.multiarray', 'dtype', ('descr', Warning: This attribute exists specifically for `__array_interface__`, and is not a datatype description compatible with `np.dtype`. + + Examples + -------- + + >>> x = np.dtype(float) + >>> x.descr + [('', '<f8')] + + >>> dt = np.dtype([('name', np.str_, 16), ('grades', np.float64, (2,))]) + >>> dt.descr + [('name', '<U16'), ('grades', '<f8', (2,))] + """)) add_newdoc('numpy.core.multiarray', 'dtype', ('fields', @@ -5482,6 +5524,18 @@ add_newdoc('numpy.core.multiarray', 'dtype', ('flags', of these flags is in C-API documentation; they are largely useful for user-defined data-types. + The following example demonstrates that operations on this particular + dtype requires Python C-API. + + Examples + -------- + + >>> x = np.dtype([('a', np.int32, 8), ('b', np.float64, 6)]) + >>> x.flags + 16 + >>> np.core.multiarray.NEEDS_PYAPI + 16 + """)) add_newdoc('numpy.core.multiarray', 'dtype', ('hasobject', @@ -5539,6 +5593,7 @@ add_newdoc('numpy.core.multiarray', 'dtype', ('isalignedstruct', field alignment. This flag is sticky, so when combining multiple structs together, it is preserved and produces new dtypes which are also aligned. + """)) add_newdoc('numpy.core.multiarray', 'dtype', ('itemsize', @@ -5548,6 +5603,19 @@ add_newdoc('numpy.core.multiarray', 'dtype', ('itemsize', For 18 of the 21 types this number is fixed by the data-type. For the flexible data-types, this number can be anything. + Examples + -------- + + >>> arr = np.array([[1, 2], [3, 4]]) + >>> arr.dtype + dtype('int64') + >>> arr.itemsize + 8 + + >>> dt = np.dtype([('name', np.str_, 16), ('grades', np.float64, (2,))]) + >>> dt.itemsize + 80 + """)) add_newdoc('numpy.core.multiarray', 'dtype', ('kind', @@ -5568,6 +5636,19 @@ add_newdoc('numpy.core.multiarray', 'dtype', ('kind', V void = ====================== + Examples + -------- + + >>> dt = np.dtype('i4') + >>> dt.kind + 'i' + >>> dt = np.dtype('f8') + >>> dt.kind + 'f' + >>> dt = np.dtype([('field1', 'f8')]) + >>> dt.kind + 'V' + """)) add_newdoc('numpy.core.multiarray', 'dtype', ('name', @@ -5576,6 +5657,16 @@ add_newdoc('numpy.core.multiarray', 'dtype', ('name', Un-sized flexible data-type objects do not have this attribute. + Examples + -------- + + >>> x = np.dtype(float) + >>> x.name + 'float64' + >>> x = np.dtype([('a', np.int32, 8), ('b', np.float64, 6)]) + >>> x.name + 'void640' + """)) add_newdoc('numpy.core.multiarray', 'dtype', ('names', @@ -5599,6 +5690,17 @@ add_newdoc('numpy.core.multiarray', 'dtype', ('num', These are roughly ordered from least-to-most precision. + Examples + -------- + + >>> dt = np.dtype(str) + >>> dt.num + 19 + + >>> dt = np.dtype(float) + >>> dt.num + 12 + """)) add_newdoc('numpy.core.multiarray', 'dtype', ('shape', @@ -5606,6 +5708,17 @@ add_newdoc('numpy.core.multiarray', 'dtype', ('shape', Shape tuple of the sub-array if this data type describes a sub-array, and ``()`` otherwise. + Examples + -------- + + >>> dt = np.dtype(('i4', 4)) + >>> dt.shape + (4,) + + >>> dt = np.dtype(('i4', (2, 3))) + >>> dt.shape + (2, 3) + """)) add_newdoc('numpy.core.multiarray', 'dtype', ('ndim', @@ -5615,6 +5728,20 @@ add_newdoc('numpy.core.multiarray', 'dtype', ('ndim', .. versionadded:: 1.13.0 + Examples + -------- + >>> x = np.dtype(float) + >>> x.ndim + 0 + + >>> x = np.dtype((float, 8)) + >>> x.ndim + 1 + + >>> x = np.dtype(('i4', (3, 4))) + >>> x.ndim + 2 + """)) add_newdoc('numpy.core.multiarray', 'dtype', ('str', diff --git a/numpy/core/_internal.py b/numpy/core/_internal.py index ab5a64a1a..c70718cb6 100644 --- a/numpy/core/_internal.py +++ b/numpy/core/_internal.py @@ -146,7 +146,7 @@ def _reconstruct(subtype, shape, dtype): # format_re was originally from numarray by J. Todd Miller format_re = re.compile(br'(?P<order1>[<>|=]?)' - br'(?P<repeats> *[(]?[ ,0-9L]*[)]? *)' + br'(?P<repeats> *[(]?[ ,0-9]*[)]? *)' br'(?P<order2>[<>|=]?)' br'(?P<dtype>[A-Za-z0-9.?]*(?:\[[a-zA-Z0-9,.]+\])?)') sep_re = re.compile(br'\s*,\s*') diff --git a/numpy/core/code_generators/ufunc_docstrings.py b/numpy/core/code_generators/ufunc_docstrings.py index 2a5646bd7..fb418aadc 100644 --- a/numpy/core/code_generators/ufunc_docstrings.py +++ b/numpy/core/code_generators/ufunc_docstrings.py @@ -2601,8 +2601,8 @@ add_newdoc('numpy.core.umath', 'matmul', For other keyword-only arguments, see the :ref:`ufunc docs <ufuncs.kwargs>`. - ..versionadded:: 1.16 - Now handles ufunc kwargs + .. versionadded:: 1.16 + Now handles ufunc kwargs Returns ------- diff --git a/numpy/core/fromnumeric.py b/numpy/core/fromnumeric.py index f262f8552..08f17aae4 100644 --- a/numpy/core/fromnumeric.py +++ b/numpy/core/fromnumeric.py @@ -1764,17 +1764,17 @@ def nonzero(a): Returns a tuple of arrays, one for each dimension of `a`, containing the indices of the non-zero elements in that dimension. The values in `a` are always tested and returned in - row-major, C-style order. The corresponding non-zero - values can be obtained with:: + row-major, C-style order. - a[nonzero(a)] + To group the indices by element, rather than dimension, use `argwhere`, + which returns a row for each non-zero element. - To group the indices by element, rather than dimension, use:: - - transpose(nonzero(a)) + .. note:: + When called on a zero-d array or scalar, ``nonzero(a)`` is treated + as ``nonzero(atleast1d(a))``. - The result of this is always a 2-D array, with a row for - each non-zero element. + ..deprecated:: 1.17.0 + Use `atleast1d` explicitly if this behavior is deliberate. Parameters ---------- @@ -1795,11 +1795,12 @@ def nonzero(a): Equivalent ndarray method. count_nonzero : Counts the number of non-zero elements in the input array. - + Notes ----- - To obtain the non-zero values, it is recommended to use ``x[x.astype(bool)]`` - which will correctly handle 0-d arrays. + While the nonzero values can be obtained with ``a[nonzero(a)]``, it is + recommended to use ``x[x.astype(bool)]`` or ``x[x != 0]`` instead, which + will correctly handle 0-d arrays. Examples -------- diff --git a/numpy/core/include/numpy/ndarrayobject.h b/numpy/core/include/numpy/ndarrayobject.h index 45f008b1d..2cc7ced35 100644 --- a/numpy/core/include/numpy/ndarrayobject.h +++ b/numpy/core/include/numpy/ndarrayobject.h @@ -233,10 +233,10 @@ static NPY_INLINE int NPY_TITLE_KEY_check(PyObject *key, PyObject *value) { PyObject *title; - if (PyTuple_GET_SIZE(value) != 3) { + if (PyTuple_Size(value) != 3) { return 0; } - title = PyTuple_GET_ITEM(value, 2); + title = PyTuple_GetItem(value, 2); if (key == title) { return 1; } diff --git a/numpy/core/multiarray.py b/numpy/core/multiarray.py index 8006dd9b5..4f2c5b78e 100644 --- a/numpy/core/multiarray.py +++ b/numpy/core/multiarray.py @@ -128,11 +128,11 @@ def empty_like(prototype, dtype=None, order=None, subok=None, shape=None): -------- >>> a = ([1,2,3], [4,5,6]) # a is array-like >>> np.empty_like(a) - array([[-1073741821, -1073741821, 3], # random + array([[-1073741821, -1073741821, 3], # uninitialized [ 0, 0, -1073741821]]) >>> a = np.array([[1., 2., 3.],[4.,5.,6.]]) >>> np.empty_like(a) - array([[ -2.00000715e+000, 1.48219694e-323, -2.00000572e+000], # random + array([[ -2.00000715e+000, 1.48219694e-323, -2.00000572e+000], # uninitialized [ 4.38791518e-305, -2.00000715e+000, 4.17269252e-309]]) """ @@ -496,11 +496,15 @@ def can_cast(from_, to, casting=None): Notes ----- - Starting in NumPy 1.9, can_cast function now returns False in 'safe' - casting mode for integer/float dtype and string dtype if the string dtype - length is not long enough to store the max integer/float value converted - to a string. Previously can_cast in 'safe' mode returned True for - integer/float dtype and a string dtype of any length. + .. versionchanged:: 1.17.0 + Casting between a simple data type and a structured one is possible only + for "unsafe" casting. Casting to multiple fields is allowed, but + casting from multiple fields is not. + + .. versionchanged:: 1.9.0 + Casting from numeric to string types in 'safe' casting mode requires + that the string dtype length is long enough to store the maximum + integer/float value converted. See also -------- diff --git a/numpy/core/src/multiarray/convert_datatype.c b/numpy/core/src/multiarray/convert_datatype.c index c59979e75..025c66013 100644 --- a/numpy/core/src/multiarray/convert_datatype.c +++ b/numpy/core/src/multiarray/convert_datatype.c @@ -679,15 +679,82 @@ NPY_NO_EXPORT npy_bool PyArray_CanCastTypeTo(PyArray_Descr *from, PyArray_Descr *to, NPY_CASTING casting) { - /* Fast path for unsafe casts or basic types */ - if (casting == NPY_UNSAFE_CASTING || - (NPY_LIKELY(from->type_num < NPY_OBJECT) && - NPY_LIKELY(from->type_num == to->type_num) && - NPY_LIKELY(from->byteorder == to->byteorder))) { + /* + * Fast paths for equality and for basic types. + */ + if (from == to || + ((NPY_LIKELY(PyDataType_ISNUMBER(from)) || + PyDataType_ISOBJECT(from)) && + NPY_LIKELY(from->type_num == to->type_num) && + NPY_LIKELY(from->byteorder == to->byteorder))) { return 1; } - /* Equivalent types can be cast with any value of 'casting' */ - else if (PyArray_EquivTypenums(from->type_num, to->type_num)) { + /* + * Cases with subarrays and fields need special treatment. + */ + if (PyDataType_HASFIELDS(from)) { + /* + * If from is a structured data type, then it can be cast to a simple + * non-object one only for unsafe casting *and* if it has a single + * field; recurse just in case the single field is itself structured. + */ + if (!PyDataType_HASFIELDS(to) && !PyDataType_ISOBJECT(to)) { + if (casting == NPY_UNSAFE_CASTING && + PyDict_Size(from->fields) == 1) { + Py_ssize_t ppos = 0; + PyObject *tuple; + PyArray_Descr *field; + PyDict_Next(from->fields, &ppos, NULL, &tuple); + field = (PyArray_Descr *)PyTuple_GET_ITEM(tuple, 0); + /* + * For a subarray, we need to get the underlying type; + * since we already are casting unsafely, we can ignore + * the shape. + */ + if (PyDataType_HASSUBARRAY(field)) { + field = field->subarray->base; + } + return PyArray_CanCastTypeTo(field, to, casting); + } + else { + return 0; + } + } + /* + * Casting from one structured data type to another depends on the fields; + * we pass that case on to the EquivTypenums case below. + * + * TODO: move that part up here? Need to check whether equivalent type + * numbers is an addition constraint that is needed. + * + * TODO/FIXME: For now, always allow structured to structured for unsafe + * casting; this is not correct, but needed since the treatment in can_cast + * below got out of sync with astype; see gh-13667. + */ + if (casting == NPY_UNSAFE_CASTING) { + return 1; + } + } + else if (PyDataType_HASFIELDS(to)) { + /* + * If "from" is a simple data type and "to" has fields, then only + * unsafe casting works (and that works always, even to multiple fields). + */ + return casting == NPY_UNSAFE_CASTING; + } + /* + * Everything else we consider castable for unsafe for now. + * FIXME: ensure what we do here is consistent with "astype", + * i.e., deal more correctly with subarrays and user-defined dtype. + */ + else if (casting == NPY_UNSAFE_CASTING) { + return 1; + } + /* + * Equivalent simple types can be cast with any value of 'casting', but + * we need to be careful about structured to structured. + */ + if (PyArray_EquivTypenums(from->type_num, to->type_num)) { /* For complicated case, use EquivTypes (for now) */ if (PyTypeNum_ISUSERDEF(from->type_num) || from->subarray != NULL) { @@ -1700,46 +1767,22 @@ dtype_kind_to_simplified_ordering(char kind) } } -/*NUMPY_API - * Produces the result type of a bunch of inputs, using the UFunc - * type promotion rules. Use this function when you have a set of - * input arrays, and need to determine an output array dtype. - * - * If all the inputs are scalars (have 0 dimensions) or the maximum "kind" - * of the scalars is greater than the maximum "kind" of the arrays, does - * a regular type promotion. - * - * Otherwise, does a type promotion on the MinScalarType - * of all the inputs. Data types passed directly are treated as array - * types. - * + +/* + * Determine if there is a mix of scalars and arrays/dtypes. + * If this is the case, the scalars should be handled as the minimum type + * capable of holding the value when the maximum "category" of the scalars + * surpasses the maximum "category" of the arrays/dtypes. + * If the scalars are of a lower or same category as the arrays, they may be + * demoted to a lower type within their category (the lowest type they can + * be cast to safely according to scalar casting rules). */ -NPY_NO_EXPORT PyArray_Descr * -PyArray_ResultType(npy_intp narrs, PyArrayObject **arr, - npy_intp ndtypes, PyArray_Descr **dtypes) +NPY_NO_EXPORT int +should_use_min_scalar(npy_intp narrs, PyArrayObject **arr, + npy_intp ndtypes, PyArray_Descr **dtypes) { - npy_intp i; - int use_min_scalar; + int use_min_scalar = 0; - /* If there's just one type, pass it through */ - if (narrs + ndtypes == 1) { - PyArray_Descr *ret = NULL; - if (narrs == 1) { - ret = PyArray_DESCR(arr[0]); - } - else { - ret = dtypes[0]; - } - Py_INCREF(ret); - return ret; - } - - /* - * Determine if there are any scalars, and if so, whether - * the maximum "kind" of the scalars surpasses the maximum - * "kind" of the arrays - */ - use_min_scalar = 0; if (narrs > 0) { int all_scalars; int max_scalar_kind = -1; @@ -1748,7 +1791,7 @@ PyArray_ResultType(npy_intp narrs, PyArrayObject **arr, all_scalars = (ndtypes > 0) ? 0 : 1; /* Compute the maximum "kinds" and whether everything is scalar */ - for (i = 0; i < narrs; ++i) { + for (npy_intp i = 0; i < narrs; ++i) { if (PyArray_NDIM(arr[i]) == 0) { int kind = dtype_kind_to_simplified_ordering( PyArray_DESCR(arr[i])->kind); @@ -1769,7 +1812,7 @@ PyArray_ResultType(npy_intp narrs, PyArrayObject **arr, * If the max scalar kind is bigger than the max array kind, * finish computing the max array kind */ - for (i = 0; i < ndtypes; ++i) { + for (npy_intp i = 0; i < ndtypes; ++i) { int kind = dtype_kind_to_simplified_ordering(dtypes[i]->kind); if (kind > max_array_kind) { max_array_kind = kind; @@ -1781,6 +1824,44 @@ PyArray_ResultType(npy_intp narrs, PyArrayObject **arr, use_min_scalar = 1; } } + return use_min_scalar; +} + + +/*NUMPY_API + * Produces the result type of a bunch of inputs, using the UFunc + * type promotion rules. Use this function when you have a set of + * input arrays, and need to determine an output array dtype. + * + * If all the inputs are scalars (have 0 dimensions) or the maximum "kind" + * of the scalars is greater than the maximum "kind" of the arrays, does + * a regular type promotion. + * + * Otherwise, does a type promotion on the MinScalarType + * of all the inputs. Data types passed directly are treated as array + * types. + * + */ +NPY_NO_EXPORT PyArray_Descr * +PyArray_ResultType(npy_intp narrs, PyArrayObject **arr, + npy_intp ndtypes, PyArray_Descr **dtypes) +{ + npy_intp i; + + /* If there's just one type, pass it through */ + if (narrs + ndtypes == 1) { + PyArray_Descr *ret = NULL; + if (narrs == 1) { + ret = PyArray_DESCR(arr[0]); + } + else { + ret = dtypes[0]; + } + Py_INCREF(ret); + return ret; + } + + int use_min_scalar = should_use_min_scalar(narrs, arr, ndtypes, dtypes); /* Loop through all the types, promoting them */ if (!use_min_scalar) { diff --git a/numpy/core/src/multiarray/convert_datatype.h b/numpy/core/src/multiarray/convert_datatype.h index 653557161..72867ead8 100644 --- a/numpy/core/src/multiarray/convert_datatype.h +++ b/numpy/core/src/multiarray/convert_datatype.h @@ -18,6 +18,10 @@ NPY_NO_EXPORT npy_bool can_cast_scalar_to(PyArray_Descr *scal_type, char *scal_data, PyArray_Descr *to, NPY_CASTING casting); +NPY_NO_EXPORT int +should_use_min_scalar(npy_intp narrs, PyArrayObject **arr, + npy_intp ndtypes, PyArray_Descr **dtypes); + /* * This function calls Py_DECREF on flex_dtype, and replaces it with * a new dtype that has been adapted based on the values in data_dtype diff --git a/numpy/core/src/multiarray/dragon4.c b/numpy/core/src/multiarray/dragon4.c index 8d52672e3..1694596e9 100644 --- a/numpy/core/src/multiarray/dragon4.c +++ b/numpy/core/src/multiarray/dragon4.c @@ -1,31 +1,33 @@ /* * Copyright (c) 2014 Ryan Juckett - * http://www.ryanjuckett.com/ * - * This software is provided 'as-is', without any express or implied - * warranty. In no event will the authors be held liable for any damages - * arising from the use of this software. + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * Permission is granted to anyone to use this software for any purpose, - * including commercial applications, and to alter it and redistribute it - * freely, subject to the following restrictions: + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. * - * 1. The origin of this software must not be misrepresented; you must not - * claim that you wrote the original software. If you use this software - * in a product, an acknowledgment in the product documentation would be - * appreciated but is not required. - * - * 2. Altered source versions must be plainly marked as such, and must not be - * misrepresented as being the original software. - * - * 3. This notice may not be removed or altered from any source - * distribution. + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. */ /* * This file contains a modified version of Ryan Juckett's Dragon4 - * implementation, which has been ported from C++ to C and which has + * implementation, obtained from http://www.ryanjuckett.com, + * which has been ported from C++ to C and which has * modifications specific to printing floats in numpy. + * + * Ryan Juckett's original code was under the Zlib license; he gave numpy + * permission to include it under the MIT license instead. */ #include "dragon4.h" diff --git a/numpy/core/src/multiarray/dragon4.h b/numpy/core/src/multiarray/dragon4.h index 2b8b4cef4..3a99bde6c 100644 --- a/numpy/core/src/multiarray/dragon4.h +++ b/numpy/core/src/multiarray/dragon4.h @@ -1,31 +1,33 @@ /* * Copyright (c) 2014 Ryan Juckett - * http://www.ryanjuckett.com/ * - * This software is provided 'as-is', without any express or implied - * warranty. In no event will the authors be held liable for any damages - * arising from the use of this software. + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * Permission is granted to anyone to use this software for any purpose, - * including commercial applications, and to alter it and redistribute it - * freely, subject to the following restrictions: + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. * - * 1. The origin of this software must not be misrepresented; you must not - * claim that you wrote the original software. If you use this software - * in a product, an acknowledgment in the product documentation would be - * appreciated but is not required. - * - * 2. Altered source versions must be plainly marked as such, and must not be - * misrepresented as being the original software. - * - * 3. This notice may not be removed or altered from any source - * distribution. + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. */ /* * This file contains a modified version of Ryan Juckett's Dragon4 - * implementation, which has been ported from C++ to C and which has + * implementation, obtained from http://www.ryanjuckett.com, + * which has been ported from C++ to C and which has * modifications specific to printing floats in numpy. + * + * Ryan Juckett's original code was under the Zlib license; he gave numpy + * permission to include it under the MIT license instead. */ #ifndef _NPY_DRAGON4_H_ diff --git a/numpy/core/src/multiarray/item_selection.c b/numpy/core/src/multiarray/item_selection.c index a6889ef8f..11c45dce5 100644 --- a/numpy/core/src/multiarray/item_selection.c +++ b/numpy/core/src/multiarray/item_selection.c @@ -2213,8 +2213,26 @@ PyArray_Nonzero(PyArrayObject *self) NpyIter_GetMultiIndexFunc *get_multi_index; char **dataptr; - /* Special case - nonzero(zero_d) is nonzero(atleast1d(zero_d)) */ + /* Special case - nonzero(zero_d) is nonzero(atleast_1d(zero_d)) */ if (ndim == 0) { + char const* msg; + if (PyArray_ISBOOL(self)) { + msg = + "Calling nonzero on 0d arrays is deprecated, as it behaves " + "surprisingly. Use `atleast_1d(cond).nonzero()` if the old " + "behavior was intended. If the context of this warning is of " + "the form `arr[nonzero(cond)]`, just use `arr[cond]`."; + } + else { + msg = + "Calling nonzero on 0d arrays is deprecated, as it behaves " + "surprisingly. Use `atleast_1d(arr).nonzero()` if the old " + "behavior was intended."; + } + if (DEPRECATE(msg) < 0) { + return NULL; + } + static npy_intp const zero_dim_shape[1] = {1}; static npy_intp const zero_dim_strides[1] = {0}; diff --git a/numpy/core/src/npysort/radixsort.c.src b/numpy/core/src/npysort/radixsort.c.src index c1435bd96..c90b06974 100644 --- a/numpy/core/src/npysort/radixsort.c.src +++ b/numpy/core/src/npysort/radixsort.c.src @@ -50,9 +50,10 @@ nth_byte_@suff@(@type@ key, npy_intp l) { radixsort0_@suff@(@type@ *arr, @type@ *aux, npy_intp num) { npy_intp cnt[sizeof(@type@)][1 << 8] = { { 0 } }; - npy_intp i, l; + npy_intp i; + size_t l; @type@ key0 = KEY_OF(arr[0]); - npy_intp ncols = 0; + size_t ncols = 0; npy_ubyte cols[sizeof(@type@)]; for (i = 0; i < num; i++) { @@ -139,9 +140,10 @@ npy_intp* aradixsort0_@suff@(@type@ *arr, npy_intp *aux, npy_intp *tosort, npy_intp num) { npy_intp cnt[sizeof(@type@)][1 << 8] = { { 0 } }; - npy_intp i, l; + npy_intp i; + size_t l; @type@ key0 = KEY_OF(arr[0]); - npy_intp ncols = 0; + size_t ncols = 0; npy_ubyte cols[sizeof(@type@)]; for (i = 0; i < num; i++) { diff --git a/numpy/core/src/umath/ufunc_object.c b/numpy/core/src/umath/ufunc_object.c index 081c06813..cb24f2a70 100644 --- a/numpy/core/src/umath/ufunc_object.c +++ b/numpy/core/src/umath/ufunc_object.c @@ -654,8 +654,8 @@ _parse_signature(PyUFuncObject *ufunc, const char *signature) PyErr_NoMemory(); goto fail; } - for (i = 0; i < len; i++) { - ufunc->core_dim_flags[i] = 0; + for (size_t j = 0; j < len; j++) { + ufunc->core_dim_flags[j] = 0; } i = _next_non_white_space(signature, 0); diff --git a/numpy/core/src/umath/ufunc_type_resolution.c b/numpy/core/src/umath/ufunc_type_resolution.c index 58f915c6e..25dd002ac 100644 --- a/numpy/core/src/umath/ufunc_type_resolution.c +++ b/numpy/core/src/umath/ufunc_type_resolution.c @@ -24,6 +24,7 @@ #include "ufunc_type_resolution.h" #include "ufunc_object.h" #include "common.h" +#include "convert_datatype.h" #include "mem_overlap.h" #if defined(HAVE_CBLAS) @@ -1938,73 +1939,6 @@ type_tuple_userloop_type_resolver(PyUFuncObject *self, return 0; } -/* - * Provides an ordering for the dtype 'kind' character codes, to help - * determine when to use the min_scalar_type function. This groups - * 'kind' into boolean, integer, floating point, and everything else. - */ - -static int -dtype_kind_to_simplified_ordering(char kind) -{ - switch (kind) { - /* Boolean kind */ - case 'b': - return 0; - /* Unsigned int kind */ - case 'u': - /* Signed int kind */ - case 'i': - return 1; - /* Float kind */ - case 'f': - /* Complex kind */ - case 'c': - return 2; - /* Anything else */ - default: - return 3; - } -} - -static int -should_use_min_scalar(PyArrayObject **op, int nop) -{ - int i, use_min_scalar, kind; - int all_scalars = 1, max_scalar_kind = -1, max_array_kind = -1; - - /* - * Determine if there are any scalars, and if so, whether - * the maximum "kind" of the scalars surpasses the maximum - * "kind" of the arrays - */ - use_min_scalar = 0; - if (nop > 1) { - for(i = 0; i < nop; ++i) { - kind = dtype_kind_to_simplified_ordering( - PyArray_DESCR(op[i])->kind); - if (PyArray_NDIM(op[i]) == 0) { - if (kind > max_scalar_kind) { - max_scalar_kind = kind; - } - } - else { - all_scalars = 0; - if (kind > max_array_kind) { - max_array_kind = kind; - } - - } - } - - /* Indicate whether to use the min_scalar_type function */ - if (!all_scalars && max_array_kind >= max_scalar_kind) { - use_min_scalar = 1; - } - } - - return use_min_scalar; -} /* * Does a linear search for the best inner loop of the ufunc. @@ -2030,7 +1964,7 @@ linear_search_type_resolver(PyUFuncObject *self, ufunc_name = ufunc_get_name_cstr(self); - use_min_scalar = should_use_min_scalar(op, nin); + use_min_scalar = should_use_min_scalar(nin, op, 0, NULL); /* If the ufunc has userloops, search for them. */ if (self->userloops) { @@ -2139,7 +2073,7 @@ type_tuple_type_resolver(PyUFuncObject *self, ufunc_name = ufunc_get_name_cstr(self); - use_min_scalar = should_use_min_scalar(op, nin); + use_min_scalar = should_use_min_scalar(nin, op, 0, NULL); /* Fill in specified_types from the tuple or string */ if (PyTuple_Check(type_tup)) { diff --git a/numpy/core/tests/test_api.py b/numpy/core/tests/test_api.py index 9755e7b36..32e2ea537 100644 --- a/numpy/core/tests/test_api.py +++ b/numpy/core/tests/test_api.py @@ -3,8 +3,10 @@ from __future__ import division, absolute_import, print_function import sys import numpy as np +import pytest from numpy.testing import ( - assert_, assert_equal, assert_array_equal, assert_raises, HAS_REFCOUNT + assert_, assert_equal, assert_array_equal, assert_raises, assert_warns, + HAS_REFCOUNT ) # Switch between new behaviour when NPY_RELAXED_STRIDES_CHECKING is set. @@ -289,6 +291,14 @@ def test_array_astype(): a = np.array(1000, dtype='i4') assert_raises(TypeError, a.astype, 'U1', casting='safe') +@pytest.mark.parametrize("t", + np.sctypes['uint'] + np.sctypes['int'] + np.sctypes['float'] +) +def test_array_astype_warning(t): + # test ComplexWarning when casting from complex to float or int + a = np.array(10, dtype=np.complex) + assert_warns(np.ComplexWarning, a.astype, t) + def test_copyto_fromscalar(): a = np.arange(6, dtype='f4').reshape(2, 3) diff --git a/numpy/core/tests/test_deprecations.py b/numpy/core/tests/test_deprecations.py index 346a0038a..6d71fcbd6 100644 --- a/numpy/core/tests/test_deprecations.py +++ b/numpy/core/tests/test_deprecations.py @@ -541,3 +541,10 @@ class TestShape1Fields(_DeprecationTestCase): # 2019-05-20, 1.17.0 def test_shape_1_fields(self): self.assert_deprecated(np.dtype, args=([('a', int, 1)],)) + + +class TestNonZero(_DeprecationTestCase): + # 2019-05-26, 1.17.0 + def test_zerod(self): + self.assert_deprecated(lambda: np.nonzero(np.array(0))) + self.assert_deprecated(lambda: np.nonzero(np.array(1))) diff --git a/numpy/core/tests/test_dtype.py b/numpy/core/tests/test_dtype.py index 8f33a8daf..4031e7362 100644 --- a/numpy/core/tests/test_dtype.py +++ b/numpy/core/tests/test_dtype.py @@ -11,6 +11,7 @@ from numpy.core._rational_tests import rational from numpy.testing import ( assert_, assert_equal, assert_array_equal, assert_raises, HAS_REFCOUNT) from numpy.compat import pickle +from itertools import permutations def assert_dtype_equal(a, b): assert_equal(a, b) @@ -1178,3 +1179,18 @@ class TestFromCTypes(object): self.check(ctypes.c_uint16.__ctype_be__, np.dtype('>u2')) self.check(ctypes.c_uint8.__ctype_le__, np.dtype('u1')) self.check(ctypes.c_uint8.__ctype_be__, np.dtype('u1')) + + all_types = set(np.typecodes['All']) + all_pairs = permutations(all_types, 2) + + @pytest.mark.parametrize("pair", all_pairs) + def test_pairs(self, pair): + """ + Check that np.dtype('x,y') matches [np.dtype('x'), np.dtype('y')] + Example: np.dtype('d,I') -> dtype([('f0', '<f8'), ('f1', '<u4')]) + """ + # gh-5645: check that np.dtype('i,L') can be used + pair_type = np.dtype('{},{}'.format(*pair)) + expected = np.dtype([('f0', pair[0]), ('f1', pair[1])]) + assert_equal(pair_type, expected) + diff --git a/numpy/core/tests/test_nditer.py b/numpy/core/tests/test_nditer.py index 9499bedec..cf66751f8 100644 --- a/numpy/core/tests/test_nditer.py +++ b/numpy/core/tests/test_nditer.py @@ -1864,7 +1864,7 @@ def test_iter_buffered_cast_structured_type(): # make sure multi-field struct type -> simple doesn't work sdt = [('a', 'f4'), ('b', 'i8'), ('d', 'O')] a = np.array([(5.5, 7, 'test'), (8, 10, 11)], dtype=sdt) - assert_raises(ValueError, lambda: ( + assert_raises(TypeError, lambda: ( nditer(a, ['buffered', 'refs_ok'], ['readonly'], casting='unsafe', op_dtypes='i4'))) diff --git a/numpy/core/tests/test_numeric.py b/numpy/core/tests/test_numeric.py index 7b6357fe8..935b84234 100644 --- a/numpy/core/tests/test_numeric.py +++ b/numpy/core/tests/test_numeric.py @@ -899,6 +899,41 @@ class TestTypes(object): # Also test keyword arguments assert_(np.can_cast(from_=np.int32, to=np.int64)) + def test_can_cast_simple_to_structured(self): + # Non-structured can only be cast to structured in 'unsafe' mode. + assert_(not np.can_cast('i4', 'i4,i4')) + assert_(not np.can_cast('i4', 'i4,i2')) + assert_(np.can_cast('i4', 'i4,i4', casting='unsafe')) + assert_(np.can_cast('i4', 'i4,i2', casting='unsafe')) + # Even if there is just a single field which is OK. + assert_(not np.can_cast('i2', [('f1', 'i4')])) + assert_(not np.can_cast('i2', [('f1', 'i4')], casting='same_kind')) + assert_(np.can_cast('i2', [('f1', 'i4')], casting='unsafe')) + # It should be the same for recursive structured or subarrays. + assert_(not np.can_cast('i2', [('f1', 'i4,i4')])) + assert_(np.can_cast('i2', [('f1', 'i4,i4')], casting='unsafe')) + assert_(not np.can_cast('i2', [('f1', '(2,3)i4')])) + assert_(np.can_cast('i2', [('f1', '(2,3)i4')], casting='unsafe')) + + def test_can_cast_structured_to_simple(self): + # Need unsafe casting for structured to simple. + assert_(not np.can_cast([('f1', 'i4')], 'i4')) + assert_(np.can_cast([('f1', 'i4')], 'i4', casting='unsafe')) + assert_(np.can_cast([('f1', 'i4')], 'i2', casting='unsafe')) + # Since it is unclear what is being cast, multiple fields to + # single should not work even for unsafe casting. + assert_(not np.can_cast('i4,i4', 'i4', casting='unsafe')) + # But a single field inside a single field is OK. + assert_(not np.can_cast([('f1', [('x', 'i4')])], 'i4')) + assert_(np.can_cast([('f1', [('x', 'i4')])], 'i4', casting='unsafe')) + # And a subarray is fine too - it will just take the first element + # (arguably not very consistently; might also take the first field). + assert_(not np.can_cast([('f0', '(3,)i4')], 'i4')) + assert_(np.can_cast([('f0', '(3,)i4')], 'i4', casting='unsafe')) + # But a structured subarray with multiple fields should fail. + assert_(not np.can_cast([('f0', ('i4,i4'), (2,))], 'i4', + casting='unsafe')) + def test_can_cast_values(self): # gh-5917 for dt in np.sctypes['int'] + np.sctypes['uint']: @@ -976,12 +1011,24 @@ class TestNonzero(object): assert_equal(np.count_nonzero(np.array([], dtype='?')), 0) assert_equal(np.nonzero(np.array([])), ([],)) + assert_equal(np.count_nonzero(np.array([0])), 0) + assert_equal(np.count_nonzero(np.array([0], dtype='?')), 0) + assert_equal(np.nonzero(np.array([0])), ([],)) + + assert_equal(np.count_nonzero(np.array([1])), 1) + assert_equal(np.count_nonzero(np.array([1], dtype='?')), 1) + assert_equal(np.nonzero(np.array([1])), ([0],)) + + def test_nonzero_zerod(self): assert_equal(np.count_nonzero(np.array(0)), 0) assert_equal(np.count_nonzero(np.array(0, dtype='?')), 0) - assert_equal(np.nonzero(np.array(0)), ([],)) + with assert_warns(DeprecationWarning): + assert_equal(np.nonzero(np.array(0)), ([],)) + assert_equal(np.count_nonzero(np.array(1)), 1) assert_equal(np.count_nonzero(np.array(1, dtype='?')), 1) - assert_equal(np.nonzero(np.array(1)), ([0],)) + with assert_warns(DeprecationWarning): + assert_equal(np.nonzero(np.array(1)), ([0],)) def test_nonzero_onedim(self): x = np.array([1, 0, 2, -1, 0, 0, 8]) @@ -1207,7 +1254,7 @@ class TestNonzero(object): a = np.array([[False], [TrueThenFalse()]]) assert_raises(RuntimeError, np.nonzero, a) - + class TestIndex(object): def test_boolean(self): a = rand(3, 5, 8) |