summaryrefslogtreecommitdiff
path: root/numpy/core
diff options
context:
space:
mode:
Diffstat (limited to 'numpy/core')
-rw-r--r--numpy/core/code_generators/generate_umath.py5
-rw-r--r--numpy/core/fromnumeric.py119
-rw-r--r--numpy/core/function_base.py17
-rw-r--r--numpy/core/include/numpy/ufuncobject.h12
-rw-r--r--numpy/core/numeric.py90
-rw-r--r--numpy/core/src/multiarray/common.c3
-rw-r--r--numpy/core/src/multiarray/compiled_base.c224
-rw-r--r--numpy/core/src/multiarray/getset.c12
-rw-r--r--numpy/core/src/umath/ufunc_object.c69
-rw-r--r--numpy/core/tests/test_deprecations.py60
-rw-r--r--numpy/core/tests/test_multiarray.py14
-rw-r--r--numpy/core/tests/test_numeric.py19
-rw-r--r--numpy/core/tests/test_shape_base.py9
-rw-r--r--numpy/core/tests/test_ufunc.py16
-rw-r--r--numpy/core/tests/test_umath.py85
15 files changed, 483 insertions, 271 deletions
diff --git a/numpy/core/code_generators/generate_umath.py b/numpy/core/code_generators/generate_umath.py
index a96437a42..e79cdd4a6 100644
--- a/numpy/core/code_generators/generate_umath.py
+++ b/numpy/core/code_generators/generate_umath.py
@@ -13,6 +13,7 @@ sys.path.pop(0)
Zero = "PyUFunc_Zero"
One = "PyUFunc_One"
None_ = "PyUFunc_None"
+AllOnes = "PyUFunc_MinusOne"
ReorderableNone = "PyUFunc_ReorderableNone"
# Sentinel value to specify using the full type description in the
@@ -493,7 +494,7 @@ defdict = {
TD(flts, f="logaddexp2", astype={'e':'f'})
),
'bitwise_and':
- Ufunc(2, 1, One,
+ Ufunc(2, 1, AllOnes,
docstrings.get('numpy.core.umath.bitwise_and'),
None,
TD(bints),
@@ -507,7 +508,7 @@ defdict = {
TD(O, f='PyNumber_Or'),
),
'bitwise_xor':
- Ufunc(2, 1, None,
+ Ufunc(2, 1, Zero,
docstrings.get('numpy.core.umath.bitwise_xor'),
None,
TD(bints),
diff --git a/numpy/core/fromnumeric.py b/numpy/core/fromnumeric.py
index 52a15e30d..ed5e2410a 100644
--- a/numpy/core/fromnumeric.py
+++ b/numpy/core/fromnumeric.py
@@ -135,20 +135,21 @@ def reshape(a, newshape, order='C'):
newshape : int or tuple of ints
The new shape should be compatible with the original shape. If
an integer, then the result will be a 1-D array of that length.
- One shape dimension can be -1. In this case, the value is inferred
- from the length of the array and remaining dimensions.
+ One shape dimension can be -1. In this case, the value is
+ inferred from the length of the array and remaining dimensions.
order : {'C', 'F', 'A'}, optional
- Read the elements of `a` using this index order, and place the elements
- into the reshaped array using this index order. 'C' means to
- read / write the elements using C-like index order, with the last axis
- index changing fastest, back to the first axis index changing slowest.
- 'F' means to read / write the elements using Fortran-like index order,
- with the first index changing fastest, and the last index changing
- slowest.
- Note that the 'C' and 'F' options take no account of the memory layout
- of the underlying array, and only refer to the order of indexing. 'A'
- means to read / write the elements in Fortran-like index order if `a`
- is Fortran *contiguous* in memory, C-like order otherwise.
+ Read the elements of `a` using this index order, and place the
+ elements into the reshaped array using this index order. 'C'
+ means to read / write the elements using C-like index order,
+ with the last axis index changing fastest, back to the first
+ axis index changing slowest. 'F' means to read / write the
+ elements using Fortran-like index order, with the first index
+ changing fastest, and the last index changing slowest. Note that
+ the 'C' and 'F' options take no account of the memory layout of
+ the underlying array, and only refer to the order of indexing.
+ 'A' means to read / write the elements in Fortran-like index
+ order if `a` is Fortran *contiguous* in memory, C-like order
+ otherwise.
Returns
-------
@@ -560,11 +561,12 @@ def partition(a, kth, axis=-1, kind='introselect', order=None):
"""
Return a partitioned copy of an array.
- Creates a copy of the array with its elements rearranged in such a way that
- the value of the element in kth position is in the position it would be in
- a sorted array. All elements smaller than the kth element are moved before
- this element and all equal or greater are moved behind it. The ordering of
- the elements in the two partitions is undefined.
+ Creates a copy of the array with its elements rearranged in such a
+ way that the value of the element in k-th position is in the
+ position it would be in a sorted array. All elements smaller than
+ the k-th element are moved before this element and all equal or
+ greater are moved behind it. The ordering of the elements in the two
+ partitions is undefined.
.. versionadded:: 1.8.0
@@ -573,23 +575,23 @@ def partition(a, kth, axis=-1, kind='introselect', order=None):
a : array_like
Array to be sorted.
kth : int or sequence of ints
- Element index to partition by. The kth value of the element will be in
- its final sorted position and all smaller elements will be moved before
- it and all equal or greater elements behind it.
- The order all elements in the partitions is undefined.
- If provided with a sequence of kth it will partition all elements
- indexed by kth of them into their sorted position at once.
+ Element index to partition by. The k-th value of the element
+ will be in its final sorted position and all smaller elements
+ will be moved before it and all equal or greater elements behind
+ it. The order all elements in the partitions is undefined. If
+ provided with a sequence of k-th it will partition all elements
+ indexed by k-th of them into their sorted position at once.
axis : int or None, optional
Axis along which to sort. If None, the array is flattened before
sorting. The default is -1, which sorts along the last axis.
kind : {'introselect'}, optional
Selection algorithm. Default is 'introselect'.
order : str or list of str, optional
- When `a` is an array with fields defined, this argument specifies
- which fields to compare first, second, etc. A single field can
- be specified as a string. Not all fields need be specified, but
- unspecified fields will still be used, in the order in which they
- come up in the dtype, to break ties.
+ When `a` is an array with fields defined, this argument
+ specifies which fields to compare first, second, etc. A single
+ field can be specified as a string. Not all fields need be
+ specified, but unspecified fields will still be used, in the
+ order in which they come up in the dtype, to break ties.
Returns
-------
@@ -604,10 +606,11 @@ def partition(a, kth, axis=-1, kind='introselect', order=None):
Notes
-----
- The various selection algorithms are characterized by their average speed,
- worst case performance, work space size, and whether they are stable. A
- stable sort keeps items with the same key in the same relative order. The
- available algorithms have the following properties:
+ The various selection algorithms are characterized by their average
+ speed, worst case performance, work space size, and whether they are
+ stable. A stable sort keeps items with the same key in the same
+ relative order. The available algorithms have the following
+ properties:
================= ======= ============= ============ =======
kind speed worst case work space stable
@@ -616,14 +619,14 @@ def partition(a, kth, axis=-1, kind='introselect', order=None):
================= ======= ============= ============ =======
All the partition algorithms make temporary copies of the data when
- partitioning along any but the last axis. Consequently, partitioning
- along the last axis is faster and uses less space than partitioning
- along any other axis.
+ partitioning along any but the last axis. Consequently,
+ partitioning along the last axis is faster and uses less space than
+ partitioning along any other axis.
- The sort order for complex numbers is lexicographic. If both the real
- and imaginary parts are non-nan then the order is determined by the
- real parts except when they are equal, in which case the order is
- determined by the imaginary parts.
+ The sort order for complex numbers is lexicographic. If both the
+ real and imaginary parts are non-nan then the order is determined by
+ the real parts except when they are equal, in which case the order
+ is determined by the imaginary parts.
Examples
--------
@@ -646,10 +649,10 @@ def partition(a, kth, axis=-1, kind='introselect', order=None):
def argpartition(a, kth, axis=-1, kind='introselect', order=None):
"""
- Perform an indirect partition along the given axis using the algorithm
- specified by the `kind` keyword. It returns an array of indices of the
- same shape as `a` that index data along the given axis in partitioned
- order.
+ Perform an indirect partition along the given axis using the
+ algorithm specified by the `kind` keyword. It returns an array of
+ indices of the same shape as `a` that index data along the given
+ axis in partitioned order.
.. versionadded:: 1.8.0
@@ -658,29 +661,29 @@ def argpartition(a, kth, axis=-1, kind='introselect', order=None):
a : array_like
Array to sort.
kth : int or sequence of ints
- Element index to partition by. The kth element will be in its final
- sorted position and all smaller elements will be moved before it and
- all larger elements behind it.
- The order all elements in the partitions is undefined.
- If provided with a sequence of kth it will partition all of them into
- their sorted position at once.
+ Element index to partition by. The k-th element will be in its
+ final sorted position and all smaller elements will be moved
+ before it and all larger elements behind it. The order all
+ elements in the partitions is undefined. If provided with a
+ sequence of k-th it will partition all of them into their sorted
+ position at once.
axis : int or None, optional
- Axis along which to sort. The default is -1 (the last axis). If None,
- the flattened array is used.
+ Axis along which to sort. The default is -1 (the last axis). If
+ None, the flattened array is used.
kind : {'introselect'}, optional
Selection algorithm. Default is 'introselect'
order : str or list of str, optional
- When `a` is an array with fields defined, this argument specifies
- which fields to compare first, second, etc. A single field can
- be specified as a string, and not all fields need be specified,
- but unspecified fields will still be used, in the order in which
- they come up in the dtype, to break ties.
+ When `a` is an array with fields defined, this argument
+ specifies which fields to compare first, second, etc. A single
+ field can be specified as a string, and not all fields need be
+ specified, but unspecified fields will still be used, in the
+ order in which they come up in the dtype, to break ties.
Returns
-------
index_array : ndarray, int
Array of indices that partition `a` along the specified axis.
- In other words, ``a[index_array]`` yields a sorted `a`.
+ In other words, ``a[index_array]`` yields a partitioned `a`.
See Also
--------
diff --git a/numpy/core/function_base.py b/numpy/core/function_base.py
index 21ca1af01..750fbe838 100644
--- a/numpy/core/function_base.py
+++ b/numpy/core/function_base.py
@@ -1,10 +1,24 @@
from __future__ import division, absolute_import, print_function
+import warnings
+import operator
+
__all__ = ['logspace', 'linspace']
from . import numeric as _nx
from .numeric import result_type, NaN, shares_memory, MAY_SHARE_BOUNDS, TooHardError
+def _index_deprecate(i, stacklevel=2):
+ try:
+ i = operator.index(i)
+ except TypeError:
+ msg = ("object of type {} cannot be safely interpreted as "
+ "an integer.".format(type(i)))
+ i = int(i)
+ stacklevel += 1
+ warnings.warn(msg, DeprecationWarning, stacklevel=stacklevel)
+ return i
+
def linspace(start, stop, num=50, endpoint=True, retstep=False, dtype=None):
"""
@@ -81,7 +95,8 @@ def linspace(start, stop, num=50, endpoint=True, retstep=False, dtype=None):
>>> plt.show()
"""
- num = int(num)
+ # 2016-02-25, 1.12
+ num = _index_deprecate(num)
if num < 0:
raise ValueError("Number of samples, %s, must be non-negative." % num)
div = (num - 1) if endpoint else num
diff --git a/numpy/core/include/numpy/ufuncobject.h b/numpy/core/include/numpy/ufuncobject.h
index 1cca64b75..e03a7a4a5 100644
--- a/numpy/core/include/numpy/ufuncobject.h
+++ b/numpy/core/include/numpy/ufuncobject.h
@@ -251,15 +251,21 @@ typedef struct _tagPyUFuncObject {
#endif
/*
+ * UFunc has unit of 0, and the order of operations can be reordered
+ * This case allows reduction with multiple axes at once.
+ */
+#define PyUFunc_Zero 0
+/*
* UFunc has unit of 1, and the order of operations can be reordered
* This case allows reduction with multiple axes at once.
*/
#define PyUFunc_One 1
/*
- * UFunc has unit of 0, and the order of operations can be reordered
- * This case allows reduction with multiple axes at once.
+ * UFunc has unit of -1, and the order of operations can be reordered
+ * This case allows reduction with multiple axes at once. Intended for
+ * bitwise_and reduction.
*/
-#define PyUFunc_Zero 0
+#define PyUFunc_MinusOne 2
/*
* UFunc has no unit, and the order of operations cannot be reordered.
* This case does not allow reduction with multiple axes at once.
diff --git a/numpy/core/numeric.py b/numpy/core/numeric.py
index 9ddc3c546..551d63a01 100644
--- a/numpy/core/numeric.py
+++ b/numpy/core/numeric.py
@@ -2090,31 +2090,6 @@ def isscalar(num):
else:
return type(num) in ScalarType
-_lkup = {
- '0':'0000',
- '1':'0001',
- '2':'0010',
- '3':'0011',
- '4':'0100',
- '5':'0101',
- '6':'0110',
- '7':'0111',
- '8':'1000',
- '9':'1001',
- 'a':'1010',
- 'b':'1011',
- 'c':'1100',
- 'd':'1101',
- 'e':'1110',
- 'f':'1111',
- 'A':'1010',
- 'B':'1011',
- 'C':'1100',
- 'D':'1101',
- 'E':'1110',
- 'F':'1111',
- 'L':''}
-
def binary_repr(num, width=None):
"""
Return the binary representation of the input number as a string.
@@ -2134,8 +2109,18 @@ def binary_repr(num, width=None):
num : int
Only an integer decimal number can be used.
width : int, optional
- The length of the returned string if `num` is positive, the length of
- the two's complement if `num` is negative.
+ The length of the returned string if `num` is positive, or the length
+ of the two's complement if `num` is negative, provided that `width` is
+ at least a sufficient number of bits for `num` to be represented in the
+ designated form.
+
+ If the `width` value is insufficient, it will be ignored, and `num` will
+ be returned in binary(`num` > 0) or two's complement (`num` < 0) form
+ with its width equal to the minimum number of bits needed to represent
+ the number in the designated form. This behavior is deprecated and will
+ later raise an error.
+
+ .. deprecated:: 1.12.0
Returns
-------
@@ -2146,6 +2131,7 @@ def binary_repr(num, width=None):
--------
base_repr: Return a string representation of a number in the given base
system.
+ bin: Python's built-in binary representation generator of an integer.
Notes
-----
@@ -2169,27 +2155,43 @@ def binary_repr(num, width=None):
The two's complement is returned when the input number is negative and
width is specified:
- >>> np.binary_repr(-3, width=4)
- '1101'
+ >>> np.binary_repr(-3, width=3)
+ '101'
+ >>> np.binary_repr(-3, width=5)
+ '11101'
"""
- # ' <-- unbreak Emacs fontification
- sign = ''
- if num < 0:
+ def warn_if_insufficient(width, binwdith):
+ if width is not None and width < binwidth:
+ warnings.warn(
+ "Insufficient bit width provided. This behavior "
+ "will raise an error in the future.", DeprecationWarning
+ )
+
+ if num == 0:
+ return '0' * (width or 1)
+
+ elif num > 0:
+ binary = bin(num)[2:]
+ binwidth = len(binary)
+ outwidth = (binwidth if width is None
+ else max(binwidth, width))
+ warn_if_insufficient(width, binwidth)
+ return binary.zfill(outwidth)
+
+ else:
if width is None:
- sign = '-'
- num = -num
+ return '-' + bin(-num)[2:]
+
else:
- # replace num with its 2-complement
- num = 2**width + num
- elif num == 0:
- return '0'*(width or 1)
- ostr = hex(num)
- bin = ''.join([_lkup[ch] for ch in ostr[2:]])
- bin = bin.lstrip('0')
- if width is not None:
- bin = bin.zfill(width)
- return sign + bin
+ poswidth = len(bin(-num)[2:])
+ twocomp = 2**(poswidth + 1) + num
+
+ binary = bin(twocomp)[2:]
+ binwidth = len(binary)
+ outwidth = max(binwidth, width)
+ warn_if_insufficient(width, binwidth)
+ return '1' * (outwidth - binwidth) + binary
def base_repr(number, base=2, padding=0):
"""
diff --git a/numpy/core/src/multiarray/common.c b/numpy/core/src/multiarray/common.c
index c216daa95..bd566b77b 100644
--- a/numpy/core/src/multiarray/common.c
+++ b/numpy/core/src/multiarray/common.c
@@ -476,6 +476,9 @@ PyArray_DTypeFromObjectHelper(PyObject *obj, int maxdims,
* __len__ is not defined.
*/
if (maxdims == 0 || !PySequence_Check(obj) || PySequence_Size(obj) < 0) {
+ // clear any PySequence_Size error, which corrupts further calls to it
+ PyErr_Clear();
+
if (*out_dtype == NULL || (*out_dtype)->type_num != NPY_OBJECT) {
Py_XDECREF(*out_dtype);
*out_dtype = PyArray_DescrFromType(NPY_OBJECT);
diff --git a/numpy/core/src/multiarray/compiled_base.c b/numpy/core/src/multiarray/compiled_base.c
index 932b94f15..711a0ab91 100644
--- a/numpy/core/src/multiarray/compiled_base.c
+++ b/numpy/core/src/multiarray/compiled_base.c
@@ -302,193 +302,111 @@ arr_digitize(PyObject *NPY_UNUSED(self), PyObject *args, PyObject *kwds)
}
/*
- * Insert values from an input array into an output array, at positions
- * indicated by a mask. If the arrays are of dtype object (indicated by
- * the objarray flag), take care of reference counting.
- *
- * This function implements the copying logic of arr_insert() defined
- * below.
- */
-static void
-arr_insert_loop(char *mptr, char *vptr, char *input_data, char *zero,
- char *avals_data, int melsize, int delsize, int objarray,
- int totmask, int numvals, int nd, npy_intp *instrides,
- npy_intp *inshape)
-{
- int mindx, rem_indx, indx, i, copied;
-
- /*
- * Walk through mask array, when non-zero is encountered
- * copy next value in the vals array to the input array.
- * If we get through the value array, repeat it as necessary.
- */
- copied = 0;
- for (mindx = 0; mindx < totmask; mindx++) {
- if (memcmp(mptr,zero,melsize) != 0) {
- /* compute indx into input array */
- rem_indx = mindx;
- indx = 0;
- for (i = nd - 1; i > 0; --i) {
- indx += (rem_indx % inshape[i]) * instrides[i];
- rem_indx /= inshape[i];
- }
- indx += rem_indx * instrides[0];
- /* fprintf(stderr, "mindx = %d, indx=%d\n", mindx, indx); */
- /* Copy value element over to input array */
- memcpy(input_data+indx,vptr,delsize);
- if (objarray) {
- Py_INCREF(*((PyObject **)vptr));
- }
- vptr += delsize;
- copied += 1;
- /* If we move past value data. Reset */
- if (copied >= numvals) {
- vptr = avals_data;
- copied = 0;
- }
- }
- mptr += melsize;
- }
-}
-
-/*
* Returns input array with values inserted sequentially into places
* indicated by the mask
*/
NPY_NO_EXPORT PyObject *
arr_insert(PyObject *NPY_UNUSED(self), PyObject *args, PyObject *kwdict)
{
- PyObject *mask = NULL, *vals = NULL;
- PyArrayObject *ainput = NULL, *amask = NULL, *avals = NULL, *tmp = NULL;
- int numvals, totmask, sameshape;
- char *input_data, *mptr, *vptr, *zero = NULL;
- int melsize, delsize, nd, objarray, k;
- npy_intp *instrides, *inshape;
+ char *src, *dest;
+ npy_bool *mask_data;
+ PyArray_Descr *dtype;
+ PyArray_CopySwapFunc *copyswap;
+ PyObject *array0, *mask0, *values0;
+ PyArrayObject *array, *mask, *values;
+ npy_intp i, j, chunk, nm, ni, nv;
static char *kwlist[] = {"input", "mask", "vals", NULL};
+ NPY_BEGIN_THREADS_DEF;
+ values = mask = NULL;
- if (!PyArg_ParseTupleAndKeywords(args, kwdict, "O&OO", kwlist,
- PyArray_Converter, &ainput,
- &mask, &vals)) {
- goto fail;
+ if (!PyArg_ParseTupleAndKeywords(args, kwdict, "O!OO:place", kwlist,
+ &PyArray_Type, &array0, &mask0, &values0)) {
+ return NULL;
}
- amask = (PyArrayObject *)PyArray_FROM_OF(mask, NPY_ARRAY_CARRAY);
- if (amask == NULL) {
+ array = (PyArrayObject *)PyArray_FromArray((PyArrayObject *)array0, NULL,
+ NPY_ARRAY_CARRAY | NPY_ARRAY_UPDATEIFCOPY);
+ if (array == NULL) {
goto fail;
}
- /* Cast an object array */
- if (PyArray_DESCR(amask)->type_num == NPY_OBJECT) {
- tmp = (PyArrayObject *)PyArray_Cast(amask, NPY_INTP);
- if (tmp == NULL) {
- goto fail;
- }
- Py_DECREF(amask);
- amask = tmp;
- }
- sameshape = 1;
- if (PyArray_NDIM(amask) == PyArray_NDIM(ainput)) {
- for (k = 0; k < PyArray_NDIM(amask); k++) {
- if (PyArray_DIMS(amask)[k] != PyArray_DIMS(ainput)[k]) {
- sameshape = 0;
- }
- }
- }
- else {
- /* Test to see if amask is 1d */
- if (PyArray_NDIM(amask) != 1) {
- sameshape = 0;
- }
- else if ((PyArray_SIZE(ainput)) != PyArray_SIZE(amask)) {
- sameshape = 0;
- }
- }
- if (!sameshape) {
- PyErr_SetString(PyExc_TypeError,
- "mask array must be 1-d or same shape as input array");
+ ni = PyArray_SIZE(array);
+ dest = PyArray_DATA(array);
+ chunk = PyArray_DESCR(array)->elsize;
+ mask = (PyArrayObject *)PyArray_FROM_OTF(mask0, NPY_BOOL,
+ NPY_ARRAY_CARRAY | NPY_ARRAY_FORCECAST);
+ if (mask == NULL) {
goto fail;
}
- avals = (PyArrayObject *)PyArray_FromObject(vals,
- PyArray_DESCR(ainput)->type_num, 0, 1);
- if (avals == NULL) {
+ nm = PyArray_SIZE(mask);
+ if (nm != ni) {
+ PyErr_SetString(PyExc_ValueError,
+ "place: mask and data must be "
+ "the same size");
goto fail;
}
- numvals = PyArray_SIZE(avals);
- nd = PyArray_NDIM(ainput);
- input_data = PyArray_DATA(ainput);
- mptr = PyArray_DATA(amask);
- melsize = PyArray_DESCR(amask)->elsize;
- vptr = PyArray_DATA(avals);
- delsize = PyArray_DESCR(avals)->elsize;
- zero = PyArray_Zero(amask);
- if (zero == NULL) {
+
+ mask_data = PyArray_DATA(mask);
+ dtype = PyArray_DESCR(array);
+ Py_INCREF(dtype);
+
+ values = (PyArrayObject *)PyArray_FromAny(values0, dtype,
+ 0, 0, NPY_ARRAY_CARRAY, NULL);
+ if (values == NULL) {
goto fail;
}
- objarray = (PyArray_DESCR(ainput)->type_num == NPY_OBJECT);
- if (!numvals) {
- /* nothing to insert! fail unless none of mask is true */
- const char *iter = mptr;
- const char *const last = iter + PyArray_NBYTES(amask);
- while (iter != last && !memcmp(iter, zero, melsize)) {
- iter += melsize;
+ nv = PyArray_SIZE(values); /* zero if null array */
+ if (nv <= 0) {
+ npy_bool allFalse = 1;
+ i = 0;
+
+ while (allFalse && i < ni) {
+ if (mask_data[i]) {
+ allFalse = 0;
+ } else {
+ i++;
+ }
}
- if (iter != last) {
+ if (!allFalse) {
PyErr_SetString(PyExc_ValueError,
- "Cannot insert from an empty array!");
+ "Cannot insert from an empty array!");
goto fail;
+ } else {
+ Py_XDECREF(values);
+ Py_XDECREF(mask);
+ Py_RETURN_NONE;
}
- goto finish;
}
- /* Handle zero-dimensional case separately */
- if (nd == 0) {
- if (memcmp(mptr,zero,melsize) != 0) {
- /* Copy value element over to input array */
- memcpy(input_data,vptr,delsize);
- if (objarray) {
- Py_INCREF(*((PyObject **)vptr));
+ src = PyArray_DATA(values);
+ j = 0;
+
+ copyswap = PyArray_DESCR(array)->f->copyswap;
+ NPY_BEGIN_THREADS_DESCR(PyArray_DESCR(array));
+ for (i = 0; i < ni; i++) {
+ if (mask_data[i]) {
+ if (j >= nv) {
+ j = 0;
}
- }
- Py_DECREF(amask);
- Py_DECREF(avals);
- PyDataMem_FREE(zero);
- Py_DECREF(ainput);
- Py_RETURN_NONE;
- }
- totmask = (int) PyArray_SIZE(amask);
- instrides = PyArray_STRIDES(ainput);
- inshape = PyArray_DIMS(ainput);
- if (objarray) {
- /* object array, need to refcount, can't release the GIL */
- arr_insert_loop(mptr, vptr, input_data, zero, PyArray_DATA(avals),
- melsize, delsize, objarray, totmask, numvals, nd,
- instrides, inshape);
- }
- else {
- /* No increfs take place in arr_insert_loop, so release the GIL */
- NPY_BEGIN_ALLOW_THREADS;
- arr_insert_loop(mptr, vptr, input_data, zero, PyArray_DATA(avals),
- melsize, delsize, objarray, totmask, numvals, nd,
- instrides, inshape);
- NPY_END_ALLOW_THREADS;
+ copyswap(dest + i*chunk, src + j*chunk, 0, array);
+ j++;
+ }
}
+ NPY_END_THREADS;
-finish:
- Py_DECREF(amask);
- Py_DECREF(avals);
- PyDataMem_FREE(zero);
- Py_DECREF(ainput);
+ Py_XDECREF(values);
+ Py_XDECREF(mask);
+ Py_DECREF(array);
Py_RETURN_NONE;
-fail:
- PyDataMem_FREE(zero);
- Py_XDECREF(ainput);
- Py_XDECREF(amask);
- Py_XDECREF(avals);
+ fail:
+ Py_XDECREF(mask);
+ Py_XDECREF(array);
+ Py_XDECREF(values);
return NULL;
}
diff --git a/numpy/core/src/multiarray/getset.c b/numpy/core/src/multiarray/getset.c
index c2a88e3b9..a49e56b7f 100644
--- a/numpy/core/src/multiarray/getset.c
+++ b/numpy/core/src/multiarray/getset.c
@@ -321,10 +321,6 @@ array_data_get(PyArrayObject *self)
#endif
}
-/*
- * TODO: Given view semantics, I think this function is a really
- * bad idea, and should be removed!
- */
static int
array_data_set(PyArrayObject *self, PyObject *op)
{
@@ -332,6 +328,14 @@ array_data_set(PyArrayObject *self, PyObject *op)
Py_ssize_t buf_len;
int writeable=1;
+ /* 2016-19-02, 1.12 */
+ int ret = DEPRECATE("Assigning the 'data' attribute is an "
+ "inherently unsafe operation and will "
+ "be removed in the future.");
+ if (ret < 0) {
+ return -1;
+ }
+
if (op == NULL) {
PyErr_SetString(PyExc_AttributeError,
"Cannot delete array data");
diff --git a/numpy/core/src/umath/ufunc_object.c b/numpy/core/src/umath/ufunc_object.c
index 9e8c3c985..6eb0aae55 100644
--- a/numpy/core/src/umath/ufunc_object.c
+++ b/numpy/core/src/umath/ufunc_object.c
@@ -79,6 +79,9 @@ static int
assign_reduce_identity_zero(PyArrayObject *result, void *data);
static int
+assign_reduce_identity_minusone(PyArrayObject *result, void *data);
+
+static int
assign_reduce_identity_one(PyArrayObject *result, void *data);
@@ -1948,6 +1951,7 @@ PyUFunc_GeneralizedFunction(PyUFuncObject *ufunc,
npy_intp iter_shape[NPY_MAXARGS];
NpyIter *iter = NULL;
npy_uint32 iter_flags;
+ npy_intp total_problem_size;
/* These parameters come from extobj= or from a TLS global */
int buffersize = 0, errormask = 0;
@@ -2343,6 +2347,16 @@ PyUFunc_GeneralizedFunction(PyUFuncObject *ufunc,
}
}
+ total_problem_size = NpyIter_GetIterSize(iter);
+ if (total_problem_size < 0) {
+ /*
+ * Only used for threading, if negative (this means that it is
+ * larger then ssize_t before axes removal) assume that the actual
+ * problem is large enough to be threaded usefully.
+ */
+ total_problem_size = 1000;
+ }
+
/* Remove all the core output dimensions from the iterator */
for (i = broadcast_ndim; i < iter_ndim; ++i) {
if (NpyIter_RemoveAxis(iter, broadcast_ndim) != NPY_SUCCEED) {
@@ -2384,6 +2398,7 @@ PyUFunc_GeneralizedFunction(PyUFuncObject *ufunc,
NpyIter_IterNextFunc *iternext;
char **dataptr;
npy_intp *count_ptr;
+ NPY_BEGIN_THREADS_DEF;
/* Get the variables needed for the loop */
iternext = NpyIter_GetIterNext(iter, NULL);
@@ -2394,10 +2409,17 @@ PyUFunc_GeneralizedFunction(PyUFuncObject *ufunc,
dataptr = NpyIter_GetDataPtrArray(iter);
count_ptr = NpyIter_GetInnerLoopSizePtr(iter);
+ if (!needs_api && !NpyIter_IterationNeedsAPI(iter)) {
+ NPY_BEGIN_THREADS_THRESHOLDED(total_problem_size);
+ }
do {
inner_dimensions[0] = *count_ptr;
innerloop(dataptr, inner_dimensions, inner_strides, innerloopdata);
} while (iternext(iter));
+
+ if (!needs_api && !NpyIter_IterationNeedsAPI(iter)) {
+ NPY_END_THREADS;
+ }
} else {
/**
* For each output operand, check if it has non-zero size,
@@ -2414,6 +2436,9 @@ PyUFunc_GeneralizedFunction(PyUFuncObject *ufunc,
case PyUFunc_One:
assign_reduce_identity_one(op[i], NULL);
break;
+ case PyUFunc_MinusOne:
+ assign_reduce_identity_minusone(op[i], NULL);
+ break;
case PyUFunc_None:
case PyUFunc_ReorderableNone:
PyErr_Format(PyExc_ValueError,
@@ -2831,6 +2856,19 @@ assign_reduce_identity_one(PyArrayObject *result, void *NPY_UNUSED(data))
}
static int
+assign_reduce_identity_minusone(PyArrayObject *result, void *NPY_UNUSED(data))
+{
+ static PyObject *MinusOne = NULL;
+
+ if (MinusOne == NULL) {
+ if ((MinusOne = PyInt_FromLong(-1)) == NULL) {
+ return -1;
+ }
+ }
+ return PyArray_FillWithScalar(result, MinusOne);
+}
+
+static int
reduce_loop(NpyIter *iter, char **dataptrs, npy_intp *strides,
npy_intp *countptr, NpyIter_IterNextFunc *iternext,
int needs_api, npy_intp skip_first_count, void *data)
@@ -2983,6 +3021,18 @@ PyUFunc_Reduce(PyUFuncObject *ufunc, PyArrayObject *arr, PyArrayObject *out,
assign_identity = NULL;
}
break;
+ case PyUFunc_MinusOne:
+ assign_identity = &assign_reduce_identity_minusone;
+ reorderable = 1;
+ /*
+ * The identity for a dynamic dtype like
+ * object arrays can't be used in general
+ */
+ if (PyArray_ISOBJECT(arr) && PyArray_SIZE(arr) != 0) {
+ assign_identity = NULL;
+ }
+ break;
+
case PyUFunc_None:
reorderable = 0;
break;
@@ -3239,17 +3289,22 @@ PyUFunc_Accumulate(PyUFuncObject *ufunc, PyArrayObject *arr, PyArrayObject *out,
NPY_BEGIN_THREADS_NDITER(iter);
do {
-
dataptr_copy[0] = dataptr[0];
dataptr_copy[1] = dataptr[1];
dataptr_copy[2] = dataptr[0];
/* Copy the first element to start the reduction */
if (otype == NPY_OBJECT) {
+ /*
+ * Input (dataptr[0]) and output (dataptr[1]) may point
+ * to the same memory (i.e. np.add.accumulate(a, out=a)).
+ * In that case need to incref before decref to avoid the
+ * possibility of the reference count being zero temporarily.
+ */
+ Py_XINCREF(*(PyObject **)dataptr_copy[1]);
Py_XDECREF(*(PyObject **)dataptr_copy[0]);
*(PyObject **)dataptr_copy[0] =
*(PyObject **)dataptr_copy[1];
- Py_XINCREF(*(PyObject **)dataptr_copy[0]);
}
else {
memcpy(dataptr_copy[0], dataptr_copy[1], itemsize);
@@ -3302,10 +3357,16 @@ PyUFunc_Accumulate(PyUFuncObject *ufunc, PyArrayObject *arr, PyArrayObject *out,
/* Copy the first element to start the reduction */
if (otype == NPY_OBJECT) {
+ /*
+ * Input (dataptr[0]) and output (dataptr[1]) may point
+ * to the same memory (i.e. np.add.accumulate(a, out=a, axis=0)).
+ * In that case need to incref before decref to avoid the
+ * possibility of the reference count being zero temporarily.
+ */
+ Py_XINCREF(*(PyObject **)dataptr_copy[1]);
Py_XDECREF(*(PyObject **)dataptr_copy[0]);
*(PyObject **)dataptr_copy[0] =
*(PyObject **)dataptr_copy[1];
- Py_XINCREF(*(PyObject **)dataptr_copy[0]);
}
else {
memcpy(dataptr_copy[0], dataptr_copy[1], itemsize);
@@ -5572,6 +5633,8 @@ ufunc_get_identity(PyUFuncObject *ufunc)
return PyInt_FromLong(1);
case PyUFunc_Zero:
return PyInt_FromLong(0);
+ case PyUFunc_MinusOne:
+ return PyInt_FromLong(-1);
}
Py_RETURN_NONE;
}
diff --git a/numpy/core/tests/test_deprecations.py b/numpy/core/tests/test_deprecations.py
index 80a792fbf..7d12ed466 100644
--- a/numpy/core/tests/test_deprecations.py
+++ b/numpy/core/tests/test_deprecations.py
@@ -560,6 +560,66 @@ class TestInvalidOrderParameterInputForFlattenArrayDeprecation(_DeprecationTestC
self.assert_deprecated(x.flatten, args=("FACK",))
+class TestArrayDataAttributeAssignmentDeprecation(_DeprecationTestCase):
+ """Assigning the 'data' attribute of an ndarray is unsafe as pointed
+ out in gh-7093. Eventually, such assignment should NOT be allowed, but
+ in the interests of maintaining backwards compatibility, only a Deprecation-
+ Warning will be raised instead for the time being to give developers time to
+ refactor relevant code.
+ """
+
+ def test_data_attr_assignment(self):
+ a = np.arange(10)
+ b = np.linspace(0, 1, 10)
+
+ self.message = ("Assigning the 'data' attribute is an "
+ "inherently unsafe operation and will "
+ "be removed in the future.")
+ self.assert_deprecated(a.__setattr__, args=('data', b.data))
+
+
+class TestLinspaceInvalidNumParameter(_DeprecationTestCase):
+ """Argument to the num parameter in linspace that cannot be
+ safely interpreted as an integer is deprecated in 1.12.0.
+
+ Argument to the num parameter in linspace that cannot be
+ safely interpreted as an integer should not be allowed.
+ In the interest of not breaking code that passes
+ an argument that could still be interpreted as an integer, a
+ DeprecationWarning will be issued for the time being to give
+ developers time to refactor relevant code.
+ """
+ def test_float_arg(self):
+ # 2016-02-25, PR#7328
+ self.assert_deprecated(np.linspace, args=(0, 10, 2.5))
+
+
+class TestBinaryReprInsufficientWidthParameterForRepresentation(_DeprecationTestCase):
+ """
+ If a 'width' parameter is passed into ``binary_repr`` that is insufficient to
+ represent the number in base 2 (positive) or 2's complement (negative) form,
+ the function used to silently ignore the parameter and return a representation
+ using the minimal number of bits needed for the form in question. Such behavior
+ is now considered unsafe from a user perspective and will raise an error in the future.
+ """
+
+ def test_insufficient_width_positive(self):
+ args = (10,)
+ kwargs = {'width': 2}
+
+ self.message = ("Insufficient bit width provided. This behavior "
+ "will raise an error in the future.")
+ self.assert_deprecated(np.binary_repr, args=args, kwargs=kwargs)
+
+ def test_insufficient_width_negative(self):
+ args = (-5,)
+ kwargs = {'width': 2}
+
+ self.message = ("Insufficient bit width provided. This behavior "
+ "will raise an error in the future.")
+ self.assert_deprecated(np.binary_repr, args=args, kwargs=kwargs)
+
+
class TestTestDeprecated(object):
def test_assert_deprecated(self):
test_case_instance = _DeprecationTestCase()
diff --git a/numpy/core/tests/test_multiarray.py b/numpy/core/tests/test_multiarray.py
index a6c8489ef..14a902b9c 100644
--- a/numpy/core/tests/test_multiarray.py
+++ b/numpy/core/tests/test_multiarray.py
@@ -716,6 +716,20 @@ class TestCreation(TestCase):
assert_raises(ValueError, np.array, C()) # segfault?
+ def test_failed_len_sequence(self):
+ # gh-7393
+ class A(object):
+ def __init__(self, data):
+ self._data = data
+ def __getitem__(self, item):
+ return type(self)(self._data[item])
+ def __len__(self):
+ return len(self._data)
+
+ # len(d) should give 3, but len(d[0]) will fail
+ d = A([1,2,3])
+ assert_equal(len(np.array(d)), 3)
+
class TestStructured(TestCase):
def test_subarray_field_access(self):
diff --git a/numpy/core/tests/test_numeric.py b/numpy/core/tests/test_numeric.py
index e22a5e193..a43ad96b7 100644
--- a/numpy/core/tests/test_numeric.py
+++ b/numpy/core/tests/test_numeric.py
@@ -1021,12 +1021,25 @@ class TestBinaryRepr(TestCase):
def test_zero(self):
assert_equal(np.binary_repr(0), '0')
- def test_large(self):
- assert_equal(np.binary_repr(10736848), '101000111101010011010000')
+ def test_positive(self):
+ assert_equal(np.binary_repr(10), '1010')
+ assert_equal(np.binary_repr(12522),
+ '11000011101010')
+ assert_equal(np.binary_repr(10736848),
+ '101000111101010011010000')
def test_negative(self):
assert_equal(np.binary_repr(-1), '-1')
- assert_equal(np.binary_repr(-1, width=8), '11111111')
+ assert_equal(np.binary_repr(-10), '-1010')
+ assert_equal(np.binary_repr(-12522),
+ '-11000011101010')
+ assert_equal(np.binary_repr(-10736848),
+ '-101000111101010011010000')
+
+ def test_sufficient_width(self):
+ assert_equal(np.binary_repr(0, width=5), '00000')
+ assert_equal(np.binary_repr(10, width=7), '0001010')
+ assert_equal(np.binary_repr(-5, width=7), '1111011')
class TestBaseRepr(TestCase):
diff --git a/numpy/core/tests/test_shape_base.py b/numpy/core/tests/test_shape_base.py
index 0d163c1dc..ac8dc1eea 100644
--- a/numpy/core/tests/test_shape_base.py
+++ b/numpy/core/tests/test_shape_base.py
@@ -120,6 +120,9 @@ class TestAtleast3d(TestCase):
class TestHstack(TestCase):
+ def test_non_iterable(self):
+ assert_raises(TypeError, hstack, 1)
+
def test_0D_array(self):
a = array(1)
b = array(2)
@@ -143,6 +146,9 @@ class TestHstack(TestCase):
class TestVstack(TestCase):
+ def test_non_iterable(self):
+ assert_raises(TypeError, vstack, 1)
+
def test_0D_array(self):
a = array(1)
b = array(2)
@@ -265,6 +271,9 @@ class TestConcatenate(TestCase):
def test_stack():
+ # non-iterable input
+ assert_raises(TypeError, stack, 1)
+
# 0d input
for input_ in [(1, 2, 3),
[np.int32(1), np.int32(2), np.int32(3)],
diff --git a/numpy/core/tests/test_ufunc.py b/numpy/core/tests/test_ufunc.py
index eb0985386..ab8cecff0 100644
--- a/numpy/core/tests/test_ufunc.py
+++ b/numpy/core/tests/test_ufunc.py
@@ -649,6 +649,22 @@ class TestUfunc(TestCase):
assert_equal(np.array([[1]], dtype=object).sum(), 1)
assert_equal(np.array([[[1, 2]]], dtype=object).sum((0, 1)), [1, 2])
+ def test_object_array_accumulate_inplace(self):
+ # Checks that in-place accumulates work, see also gh-7402
+ arr = np.ones(4, dtype=object)
+ arr[:] = [[1] for i in range(4)]
+ # Twice reproduced also for tuples:
+ np.add.accumulate(arr, out=arr)
+ np.add.accumulate(arr, out=arr)
+ assert_array_equal(arr, np.array([[1]*i for i in [1, 3, 6, 10]]))
+
+ # And the same if the axis argument is used
+ arr = np.ones((2, 4), dtype=object)
+ arr[0, :] = [[2] for i in range(4)]
+ np.add.accumulate(arr, out=arr, axis=-1)
+ np.add.accumulate(arr, out=arr, axis=-1)
+ assert_array_equal(arr[0, :], np.array([[2]*i for i in [1, 3, 6, 10]]))
+
def test_object_scalar_multiply(self):
# Tickets #2469 and #4482
arr = np.matrix([1, 2], dtype=object)
diff --git a/numpy/core/tests/test_umath.py b/numpy/core/tests/test_umath.py
index da52e0dde..f0f664a6f 100644
--- a/numpy/core/tests/test_umath.py
+++ b/numpy/core/tests/test_umath.py
@@ -991,6 +991,91 @@ class TestBool(TestCase):
assert_equal(np.bitwise_xor(arg1, arg2), out)
+class TestBitwiseUFuncs(TestCase):
+
+ bitwise_types = [np.dtype(c) for c in '?' + 'bBhHiIlLqQ' + 'O']
+
+ def test_values(self):
+ for dt in self.bitwise_types:
+ zeros = np.array([0], dtype=dt)
+ ones = np.array([-1], dtype=dt)
+ msg = "dt = '%s'" % dt.char
+
+ assert_equal(np.bitwise_not(zeros), ones, err_msg=msg)
+ assert_equal(np.bitwise_not(ones), zeros, err_msg=msg)
+
+ assert_equal(np.bitwise_or(zeros, zeros), zeros, err_msg=msg)
+ assert_equal(np.bitwise_or(zeros, ones), ones, err_msg=msg)
+ assert_equal(np.bitwise_or(ones, zeros), ones, err_msg=msg)
+ assert_equal(np.bitwise_or(ones, ones), ones, err_msg=msg)
+
+ assert_equal(np.bitwise_xor(zeros, zeros), zeros, err_msg=msg)
+ assert_equal(np.bitwise_xor(zeros, ones), ones, err_msg=msg)
+ assert_equal(np.bitwise_xor(ones, zeros), ones, err_msg=msg)
+ assert_equal(np.bitwise_xor(ones, ones), zeros, err_msg=msg)
+
+ assert_equal(np.bitwise_and(zeros, zeros), zeros, err_msg=msg)
+ assert_equal(np.bitwise_and(zeros, ones), zeros, err_msg=msg)
+ assert_equal(np.bitwise_and(ones, zeros), zeros, err_msg=msg)
+ assert_equal(np.bitwise_and(ones, ones), ones, err_msg=msg)
+
+ def test_types(self):
+ for dt in self.bitwise_types:
+ zeros = np.array([0], dtype=dt)
+ ones = np.array([-1], dtype=dt)
+ msg = "dt = '%s'" % dt.char
+
+ assert_(np.bitwise_not(zeros).dtype == dt, msg)
+ assert_(np.bitwise_or(zeros, zeros).dtype == dt, msg)
+ assert_(np.bitwise_xor(zeros, zeros).dtype == dt, msg)
+ assert_(np.bitwise_and(zeros, zeros).dtype == dt, msg)
+
+
+ def test_identity(self):
+ assert_(np.bitwise_or.identity == 0, 'bitwise_or')
+ assert_(np.bitwise_xor.identity == 0, 'bitwise_xor')
+ assert_(np.bitwise_and.identity == -1, 'bitwise_and')
+
+ def test_reduction(self):
+ binary_funcs = (np.bitwise_or, np.bitwise_xor, np.bitwise_and)
+
+ for dt in self.bitwise_types:
+ zeros = np.array([0], dtype=dt)
+ ones = np.array([-1], dtype=dt)
+ for f in binary_funcs:
+ msg = "dt: '%s', f: '%s'" % (dt, f)
+ assert_equal(f.reduce(zeros), zeros, err_msg=msg)
+ assert_equal(f.reduce(ones), ones, err_msg=msg)
+
+ # Test empty reduction, no object dtype
+ for dt in self.bitwise_types[:-1]:
+ # No object array types
+ empty = np.array([], dtype=dt)
+ for f in binary_funcs:
+ msg = "dt: '%s', f: '%s'" % (dt, f)
+ tgt = np.array(f.identity, dtype=dt)
+ res = f.reduce(empty)
+ assert_equal(res, tgt, err_msg=msg)
+ assert_(res.dtype == tgt.dtype, msg)
+
+ # Empty object arrays use the identity. Note that the types may
+ # differ, the actual type used is determined by the assign_identity
+ # function and is not the same as the type returned by the identity
+ # method.
+ for f in binary_funcs:
+ msg = "dt: '%s'" % (f,)
+ empty = np.array([], dtype=object)
+ tgt = f.identity
+ res = f.reduce(empty)
+ assert_equal(res, tgt, err_msg=msg)
+
+ # Non-empty object arrays do not use the identity
+ for f in binary_funcs:
+ msg = "dt: '%s'" % (f,)
+ btype = np.array([True], dtype=object)
+ assert_(type(f.reduce(btype)) is bool, msg)
+
+
class TestInt(TestCase):
def test_logical_not(self):
x = np.ones(10, dtype=np.int16)