summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCharles Harris <charlesr.harris@gmail.com>2014-02-15 16:38:43 -0700
committerCharles Harris <charlesr.harris@gmail.com>2014-02-15 16:38:43 -0700
commit2868dc4a0513f58eafc013f3ba3d84ae07113199 (patch)
tree04649bc8cda222eeb06a893070e2b3e9699758a8
parente246cc79de16d54ce9b127d5faf625adb6da5f0b (diff)
parentab04e1ae0e8eca717bc7e42f3b0a60c9ff764289 (diff)
downloadnumpy-2868dc4a0513f58eafc013f3ba3d84ae07113199.tar.gz
Merge pull request #4105 from seberg/deprecate-boolean-math
DEP: Deprecate boolean math operations
-rw-r--r--numpy/core/code_generators/generate_umath.py2
-rw-r--r--numpy/core/numeric.py7
-rw-r--r--numpy/core/src/umath/ufunc_type_resolution.c46
-rw-r--r--numpy/core/src/umath/ufunc_type_resolution.h7
-rw-r--r--numpy/core/tests/test_defchararray.py6
-rw-r--r--numpy/core/tests/test_deprecations.py23
-rw-r--r--numpy/core/tests/test_numeric.py7
-rw-r--r--numpy/core/tests/test_regression.py5
-rw-r--r--numpy/ma/core.py10
-rw-r--r--numpy/ma/extras.py4
-rw-r--r--numpy/ma/tests/test_core.py4
-rw-r--r--numpy/testing/tests/test_utils.py8
-rw-r--r--numpy/testing/utils.py11
13 files changed, 129 insertions, 11 deletions
diff --git a/numpy/core/code_generators/generate_umath.py b/numpy/core/code_generators/generate_umath.py
index e02cb8709..e3c9cf28b 100644
--- a/numpy/core/code_generators/generate_umath.py
+++ b/numpy/core/code_generators/generate_umath.py
@@ -369,7 +369,7 @@ defdict = {
'negative':
Ufunc(1, 1, None,
docstrings.get('numpy.core.umath.negative'),
- 'PyUFunc_SimpleUnaryOperationTypeResolver',
+ 'PyUFunc_NegativeTypeResolver',
TD(bints+flts+timedeltaonly),
TD(cmplx, f='neg'),
TD(O, f='PyNumber_Negative'),
diff --git a/numpy/core/numeric.py b/numpy/core/numeric.py
index 39e5a4cd5..3b8e52e71 100644
--- a/numpy/core/numeric.py
+++ b/numpy/core/numeric.py
@@ -2139,6 +2139,11 @@ def allclose(a, b, rtol=1.e-5, atol=1.e-8):
x = array(a, copy=False, ndmin=1)
y = array(b, copy=False, ndmin=1)
+ # make sure y is an inexact type to avoid abs(MIN_INT); will cause
+ # casting of x later.
+ dtype = multiarray.result_type(y, 1.)
+ y = array(y, dtype=dtype, copy=False)
+
xinf = isinf(x)
yinf = isinf(y)
if any(xinf) or any(yinf):
@@ -2154,7 +2159,7 @@ def allclose(a, b, rtol=1.e-5, atol=1.e-8):
# ignore invalid fpe's
with errstate(invalid='ignore'):
- r = all(less_equal(abs(x-y), atol + rtol * abs(y)))
+ r = all(less_equal(abs(x - y), atol + rtol * abs(y)))
return r
diff --git a/numpy/core/src/umath/ufunc_type_resolution.c b/numpy/core/src/umath/ufunc_type_resolution.c
index 12d8e406b..ffdb15bbe 100644
--- a/numpy/core/src/umath/ufunc_type_resolution.c
+++ b/numpy/core/src/umath/ufunc_type_resolution.c
@@ -367,6 +367,34 @@ PyUFunc_SimpleUnaryOperationTypeResolver(PyUFuncObject *ufunc,
return 0;
}
+
+NPY_NO_EXPORT int
+PyUFunc_NegativeTypeResolver(PyUFuncObject *ufunc,
+ NPY_CASTING casting,
+ PyArrayObject **operands,
+ PyObject *type_tup,
+ PyArray_Descr **out_dtypes)
+{
+ int ret;
+ ret = PyUFunc_SimpleUnaryOperationTypeResolver(ufunc, casting, operands,
+ type_tup, out_dtypes);
+ if (ret < 0) {
+ return ret;
+ }
+
+ /* The type resolver would have upcast already */
+ if (out_dtypes[0]->type_num == NPY_BOOL) {
+ if (DEPRECATE("numpy boolean negative (the unary `-` operator) is "
+ "deprecated, use the bitwise_xor (the `^` operator) "
+ "or the logical_xor function instead.") < 0) {
+ return -1;
+ }
+ }
+
+ return ret;
+}
+
+
/*
* The ones_like function shouldn't really be a ufunc, but while it
* still is, this provides type resolution that always forces UNSAFE
@@ -762,8 +790,22 @@ PyUFunc_SubtractionTypeResolver(PyUFuncObject *ufunc,
/* Use the default when datetime and timedelta are not involved */
if (!PyTypeNum_ISDATETIME(type_num1) && !PyTypeNum_ISDATETIME(type_num2)) {
- return PyUFunc_SimpleBinaryOperationTypeResolver(ufunc, casting,
- operands, type_tup, out_dtypes);
+ int ret;
+ ret = PyUFunc_SimpleBinaryOperationTypeResolver(ufunc, casting,
+ operands, type_tup, out_dtypes);
+ if (ret < 0) {
+ return ret;
+ }
+
+ /* The type resolver would have upcast already */
+ if (out_dtypes[0]->type_num == NPY_BOOL) {
+ if (DEPRECATE("numpy boolean subtract (the binary `-` operator) is "
+ "deprecated, use the bitwise_xor (the `^` operator) "
+ "or the logical_xor function instead.") < 0) {
+ return -1;
+ }
+ }
+ return ret;
}
if (type_num1 == NPY_TIMEDELTA) {
diff --git a/numpy/core/src/umath/ufunc_type_resolution.h b/numpy/core/src/umath/ufunc_type_resolution.h
index a1241827e..a1e28d75b 100644
--- a/numpy/core/src/umath/ufunc_type_resolution.h
+++ b/numpy/core/src/umath/ufunc_type_resolution.h
@@ -16,6 +16,13 @@ PyUFunc_SimpleUnaryOperationTypeResolver(PyUFuncObject *ufunc,
PyArray_Descr **out_dtypes);
NPY_NO_EXPORT int
+PyUFunc_NegativeTypeResolver(PyUFuncObject *ufunc,
+ NPY_CASTING casting,
+ PyArrayObject **operands,
+ PyObject *type_tup,
+ PyArray_Descr **out_dtypes);
+
+NPY_NO_EXPORT int
PyUFunc_OnesLikeTypeResolver(PyUFuncObject *ufunc,
NPY_CASTING casting,
PyArrayObject **operands,
diff --git a/numpy/core/tests/test_defchararray.py b/numpy/core/tests/test_defchararray.py
index fe0e02a6d..2b45ba4bc 100644
--- a/numpy/core/tests/test_defchararray.py
+++ b/numpy/core/tests/test_defchararray.py
@@ -128,9 +128,9 @@ class TestWhitespace(TestCase):
assert_(all(self.A == self.B))
assert_(all(self.A >= self.B))
assert_(all(self.A <= self.B))
- assert_(all(negative(self.A > self.B)))
- assert_(all(negative(self.A < self.B)))
- assert_(all(negative(self.A != self.B)))
+ assert_(not any(self.A > self.B))
+ assert_(not any(self.A < self.B))
+ assert_(not any(self.A != self.B))
class TestChar(TestCase):
def setUp(self):
diff --git a/numpy/core/tests/test_deprecations.py b/numpy/core/tests/test_deprecations.py
index 41f1cf744..f7fbb94e5 100644
--- a/numpy/core/tests/test_deprecations.py
+++ b/numpy/core/tests/test_deprecations.py
@@ -343,5 +343,28 @@ class TestMultipleEllipsisDeprecation(_DeprecationTestCase):
assert_raises(IndexError, a.__getitem__, ((Ellipsis, ) * 3,))
+class TestBooleanSubtractDeprecations(_DeprecationTestCase):
+ """Test deprecation of boolean `-`. While + and * are well
+ defined, - is not and even a corrected form seems to have
+ no real uses.
+
+ The deprecation process was started in NumPy 1.9.
+ """
+ message = r"numpy boolean .* \(the .* `-` operator\) is deprecated, " \
+ "use the bitwise"
+
+ def test_operator_deprecation(self):
+ array = np.array([True])
+ generic = np.bool_(True)
+
+ # Minus operator/subtract ufunc:
+ self.assert_deprecated(operator.sub, args=(array, array))
+ self.assert_deprecated(operator.sub, args=(generic, generic))
+
+ # Unary minus/negative ufunc:
+ self.assert_deprecated(operator.neg, args=(array,))
+ self.assert_deprecated(operator.neg, args=(generic,))
+
+
if __name__ == "__main__":
run_module_suite()
diff --git a/numpy/core/tests/test_numeric.py b/numpy/core/tests/test_numeric.py
index ac341468c..12a39a522 100644
--- a/numpy/core/tests/test_numeric.py
+++ b/numpy/core/tests/test_numeric.py
@@ -1420,6 +1420,13 @@ class TestAllclose(object):
assert_array_equal(y, array([0, inf]))
+ def test_min_int(self):
+ # Could make problems because of abs(min_int) == min_int
+ min_int = np.iinfo(np.int_).min
+ a = np.array([min_int], dtype=np.int_)
+ assert_(allclose(a, a))
+
+
class TestIsclose(object):
rtol = 1e-5
atol = 1e-8
diff --git a/numpy/core/tests/test_regression.py b/numpy/core/tests/test_regression.py
index 2bcb2b185..e6eb0791d 100644
--- a/numpy/core/tests/test_regression.py
+++ b/numpy/core/tests/test_regression.py
@@ -447,7 +447,10 @@ class TestRegression(TestCase):
res1 = getattr(arr, func_meth)()
res2 = getattr(np, func)(arr2)
if res1 is None:
- assert_(abs(arr-res2).max() < 1e-8, func)
+ res1 = arr
+
+ if res1.dtype.kind in 'uib':
+ assert_((res1 == res2).all(), func)
else:
assert_(abs(res1-res2).max() < 1e-8, func)
diff --git a/numpy/ma/core.py b/numpy/ma/core.py
index e4116fbd8..e1ae02331 100644
--- a/numpy/ma/core.py
+++ b/numpy/ma/core.py
@@ -6926,6 +6926,13 @@ def allclose (a, b, masked_equal=True, rtol=1e-5, atol=1e-8):
"""
x = masked_array(a, copy=False)
y = masked_array(b, copy=False)
+
+ # make sure y is an inexact type to avoid abs(MIN_INT); will cause
+ # casting of x later.
+ dtype = np.result_type(y, 1.)
+ if y.dtype != dtype:
+ y = masked_array(y, dtype=dtype, copy=False)
+
m = mask_or(getmask(x), getmask(y))
xinf = np.isinf(masked_array(x, copy=False, mask=m)).filled(False)
# If we have some infs, they should fall at the same place.
@@ -6937,13 +6944,16 @@ def allclose (a, b, masked_equal=True, rtol=1e-5, atol=1e-8):
atol + rtol * umath.absolute(y)),
masked_equal)
return np.all(d)
+
if not np.all(filled(x[xinf] == y[xinf], masked_equal)):
return False
x = x[~xinf]
y = y[~xinf]
+
d = filled(umath.less_equal(umath.absolute(x - y),
atol + rtol * umath.absolute(y)),
masked_equal)
+
return np.all(d)
#..............................................................................
diff --git a/numpy/ma/extras.py b/numpy/ma/extras.py
index 058bde710..c2d105584 100644
--- a/numpy/ma/extras.py
+++ b/numpy/ma/extras.py
@@ -540,7 +540,7 @@ def average(a, axis=None, weights=None, returned=False):
else:
if weights is None:
n = add.reduce(a, axis)
- d = umath.add.reduce((-mask), axis=axis, dtype=float)
+ d = umath.add.reduce((~mask), axis=axis, dtype=float)
else:
w = filled(weights, 0.0)
wsh = w.shape
@@ -1735,7 +1735,7 @@ def _ezclump(mask):
#def clump_masked(a):
if mask.ndim > 1:
mask = mask.ravel()
- idx = (mask[1:] - mask[:-1]).nonzero()
+ idx = (mask[1:] ^ mask[:-1]).nonzero()
idx = idx[0] + 1
slices = [slice(left, right)
for (left, right) in zip(itertools.chain([0], idx),
diff --git a/numpy/ma/tests/test_core.py b/numpy/ma/tests/test_core.py
index 8d8e1c947..19f13a8c4 100644
--- a/numpy/ma/tests/test_core.py
+++ b/numpy/ma/tests/test_core.py
@@ -1995,6 +1995,10 @@ class TestMaskedArrayMethods(TestCase):
a[0] = 0
self.assertTrue(allclose(a, 0, masked_equal=True))
+ # Test that the function works for MIN_INT integer typed arrays
+ a = masked_array([np.iinfo(np.int_).min], dtype=np.int_)
+ self.assertTrue(allclose(a, a))
+
def test_allany(self):
# Checks the any/all methods/functions.
x = np.array([[0.13, 0.26, 0.90],
diff --git a/numpy/testing/tests/test_utils.py b/numpy/testing/tests/test_utils.py
index 94fc4d655..5956a4294 100644
--- a/numpy/testing/tests/test_utils.py
+++ b/numpy/testing/tests/test_utils.py
@@ -53,6 +53,9 @@ class _GenericTest(object):
a = np.array([1, 1], dtype=np.object)
self._test_equal(a, 1)
+ def test_array_likes(self):
+ self._test_equal([1, 2, 3], (1, 2, 3))
+
class TestArrayEqual(_GenericTest, unittest.TestCase):
def setUp(self):
self._assert_func = assert_array_equal
@@ -373,6 +376,11 @@ class TestAssertAllclose(unittest.TestCase):
assert_allclose(6, 10, rtol=0.5)
self.assertRaises(AssertionError, assert_allclose, 10, 6, rtol=0.5)
+ def test_min_int(self):
+ a = np.array([np.iinfo(np.int_).min], dtype=np.int_)
+ # Should not raise:
+ assert_allclose(a, a)
+
class TestArrayAlmostEqualNulp(unittest.TestCase):
@dec.knownfailureif(True, "Github issue #347")
diff --git a/numpy/testing/utils.py b/numpy/testing/utils.py
index 2a99fe5cb..97908c7e8 100644
--- a/numpy/testing/utils.py
+++ b/numpy/testing/utils.py
@@ -793,7 +793,7 @@ def assert_array_almost_equal(x, y, decimal=6, err_msg='', verbose=True):
y: array([ 1. , 2.33333, 5. ])
"""
- from numpy.core import around, number, float_
+ from numpy.core import around, number, float_, result_type, array
from numpy.core.numerictypes import issubdtype
from numpy.core.fromnumeric import any as npany
def compare(x, y):
@@ -810,13 +810,22 @@ def assert_array_almost_equal(x, y, decimal=6, err_msg='', verbose=True):
y = y[~yinfid]
except (TypeError, NotImplementedError):
pass
+
+ # make sure y is an inexact type to avoid abs(MIN_INT); will cause
+ # casting of x later.
+ dtype = result_type(y, 1.)
+ y = array(y, dtype=dtype, copy=False)
z = abs(x-y)
+
if not issubdtype(z.dtype, number):
z = z.astype(float_) # handle object arrays
+
return around(z, decimal) <= 10.0**(-decimal)
+
assert_array_compare(compare, x, y, err_msg=err_msg, verbose=verbose,
header=('Arrays are not almost equal to %d decimals' % decimal))
+
def assert_array_less(x, y, err_msg='', verbose=True):
"""
Raise an assertion if two array_like objects are not ordered by less than.