summaryrefslogtreecommitdiff
path: root/numpy/core
diff options
context:
space:
mode:
Diffstat (limited to 'numpy/core')
-rw-r--r--numpy/core/include/numpy/ndarrayobject.h31
-rw-r--r--numpy/core/src/umath/loops.c.src20
-rw-r--r--numpy/core/tests/test_regression.py10
-rw-r--r--numpy/core/tests/test_umath_complex.py134
-rw-r--r--numpy/core/umath_tests.py15
5 files changed, 140 insertions, 70 deletions
diff --git a/numpy/core/include/numpy/ndarrayobject.h b/numpy/core/include/numpy/ndarrayobject.h
index 4e63868f3..ec0fd1ee9 100644
--- a/numpy/core/include/numpy/ndarrayobject.h
+++ b/numpy/core/include/numpy/ndarrayobject.h
@@ -232,9 +232,36 @@ PyArray_DiscardWritebackIfCopy(PyArrayObject *arr)
dict.
*/
-#define NPY_TITLE_KEY(key, value) ((PyTuple_GET_SIZE((value))==3) && \
- (PyTuple_GET_ITEM((value), 2) == (key)))
+static NPY_INLINE int
+NPY_TITLE_KEY_check(PyObject *key, PyObject *value)
+{
+ PyObject *title;
+ if (PyTuple_GET_SIZE(value) != 3) {
+ return 0;
+ }
+ title = PyTuple_GET_ITEM(value, 2);
+ if (key == title) {
+ return 1;
+ }
+#ifdef PYPY_VERSION
+ /*
+ * On PyPy, dictionary keys do not always preserve object identity.
+ * Fall back to comparison by value.
+ */
+ if (PyUnicode_Check(title) && PyUnicode_Check(key)) {
+ return PyUnicode_Compare(title, key) == 0 ? 1 : 0;
+ }
+#if PY_VERSION_HEX < 0x03000000
+ if (PyString_Check(title) && PyString_Check(key)) {
+ return PyObject_Compare(title, key) == 0 ? 1 : 0;
+ }
+#endif
+#endif
+ return 0;
+}
+/* Macro, for backward compat with "if NPY_TITLE_KEY(key, value) { ..." */
+#define NPY_TITLE_KEY(key, value) (NPY_TITLE_KEY_check((key), (value)))
#define DEPRECATE(msg) PyErr_WarnEx(PyExc_DeprecationWarning,msg,1)
#define DEPRECATE_FUTUREWARNING(msg) PyErr_WarnEx(PyExc_FutureWarning,msg,1)
diff --git a/numpy/core/src/umath/loops.c.src b/numpy/core/src/umath/loops.c.src
index a855693a5..8b1c7e703 100644
--- a/numpy/core/src/umath/loops.c.src
+++ b/numpy/core/src/umath/loops.c.src
@@ -30,6 +30,16 @@
*/
#define PW_BLOCKSIZE 128
+
+/*
+ * largest simd vector size in bytes numpy supports
+ * it is currently a extremely large value as it is only used for memory
+ * overlap checks
+ */
+#ifndef NPY_MAX_SIMD_SIZE
+#define NPY_MAX_SIMD_SIZE 1024
+#endif
+
/*
* include vectorized functions and dispatchers
* this file is safe to include also for generic builds
@@ -180,10 +190,12 @@
do { \
/* condition allows compiler to optimize the generic macro */ \
if (IS_BINARY_CONT(tin, tout)) { \
- if (args[2] == args[0]) { \
+ if (abs_ptrdiff(args[2], args[0]) == 0 && \
+ abs_ptrdiff(args[2], args[1]) >= NPY_MAX_SIMD_SIZE) { \
BASE_BINARY_LOOP_INP(tin, tout, op) \
} \
- else if (args[2] == args[1]) { \
+ else if (abs_ptrdiff(args[2], args[1]) == 0 && \
+ abs_ptrdiff(args[2], args[0]) >= NPY_MAX_SIMD_SIZE) { \
BASE_BINARY_LOOP_INP(tin, tout, op) \
} \
else { \
@@ -191,7 +203,7 @@
} \
} \
else if (IS_BINARY_CONT_S1(tin, tout)) { \
- if (args[1] == args[2]) { \
+ if (abs_ptrdiff(args[2], args[1]) == 0) { \
BASE_BINARY_LOOP_S_INP(tin, tout, in1, args[0], in2, ip2, op) \
} \
else { \
@@ -199,7 +211,7 @@
} \
} \
else if (IS_BINARY_CONT_S2(tin, tout)) { \
- if (args[0] == args[2]) { \
+ if (abs_ptrdiff(args[2], args[0]) == 0) { \
BASE_BINARY_LOOP_S_INP(tin, tout, in2, args[1], in1, ip1, op) \
} \
else { \
diff --git a/numpy/core/tests/test_regression.py b/numpy/core/tests/test_regression.py
index fe0adb8cb..b3cb3e610 100644
--- a/numpy/core/tests/test_regression.py
+++ b/numpy/core/tests/test_regression.py
@@ -2332,3 +2332,13 @@ class TestRegression(object):
#va[0] = b'\xff\xff\xff\xff'
#del va
#assert_equal(x, b'\x00\x00\x00\x00')
+
+ def test_structarray_title(self):
+ # The following used to segfault on pypy, due to NPY_TITLE_KEY
+ # not working properly and resulting to double-decref of the
+ # structured array field items:
+ # See: https://bitbucket.org/pypy/pypy/issues/2789
+ for j in range(5):
+ structure = np.array([1], dtype=[(('x', 'X'), np.object_)])
+ structure[0]['x'] = np.array([2])
+ gc.collect()
diff --git a/numpy/core/tests/test_umath_complex.py b/numpy/core/tests/test_umath_complex.py
index 659a8a09e..785ae8c57 100644
--- a/numpy/core/tests/test_umath_complex.py
+++ b/numpy/core/tests/test_umath_complex.py
@@ -35,11 +35,11 @@ class TestCexp(object):
check = check_complex_value
f = np.exp
- yield check, f, 1, 0, np.exp(1), 0, False
- yield check, f, 0, 1, np.cos(1), np.sin(1), False
+ check(f, 1, 0, np.exp(1), 0, False)
+ check(f, 0, 1, np.cos(1), np.sin(1), False)
ref = np.exp(1) * complex(np.cos(1), np.sin(1))
- yield check, f, 1, 1, ref.real, ref.imag, False
+ check(f, 1, 1, ref.real, ref.imag, False)
@platform_skip
def test_special_values(self):
@@ -49,25 +49,25 @@ class TestCexp(object):
f = np.exp
# cexp(+-0 + 0i) is 1 + 0i
- yield check, f, np.PZERO, 0, 1, 0, False
- yield check, f, np.NZERO, 0, 1, 0, False
+ check(f, np.PZERO, 0, 1, 0, False)
+ check(f, np.NZERO, 0, 1, 0, False)
# cexp(x + infi) is nan + nani for finite x and raises 'invalid' FPU
# exception
- yield check, f, 1, np.inf, np.nan, np.nan
- yield check, f, -1, np.inf, np.nan, np.nan
- yield check, f, 0, np.inf, np.nan, np.nan
+ check(f, 1, np.inf, np.nan, np.nan)
+ check(f, -1, np.inf, np.nan, np.nan)
+ check(f, 0, np.inf, np.nan, np.nan)
# cexp(inf + 0i) is inf + 0i
- yield check, f, np.inf, 0, np.inf, 0
+ check(f, np.inf, 0, np.inf, 0)
# cexp(-inf + yi) is +0 * (cos(y) + i sin(y)) for finite y
- yield check, f, -np.inf, 1, np.PZERO, np.PZERO
- yield check, f, -np.inf, 0.75 * np.pi, np.NZERO, np.PZERO
+ check(f, -np.inf, 1, np.PZERO, np.PZERO)
+ check(f, -np.inf, 0.75 * np.pi, np.NZERO, np.PZERO)
# cexp(inf + yi) is +inf * (cos(y) + i sin(y)) for finite y
- yield check, f, np.inf, 1, np.inf, np.inf
- yield check, f, np.inf, 0.75 * np.pi, -np.inf, np.inf
+ check(f, np.inf, 1, np.inf, np.inf)
+ check(f, np.inf, 0.75 * np.pi, -np.inf, np.inf)
# cexp(-inf + inf i) is +-0 +- 0i (signs unspecified)
def _check_ninf_inf(dummy):
@@ -77,7 +77,7 @@ class TestCexp(object):
if z.real != 0 or z.imag != 0:
raise AssertionError(msgform % (z.real, z.imag))
- yield _check_ninf_inf, None
+ _check_ninf_inf(None)
# cexp(inf + inf i) is +-inf + NaNi and raised invalid FPU ex.
def _check_inf_inf(dummy):
@@ -87,7 +87,7 @@ class TestCexp(object):
if not np.isinf(z.real) or not np.isnan(z.imag):
raise AssertionError(msgform % (z.real, z.imag))
- yield _check_inf_inf, None
+ _check_inf_inf(None)
# cexp(-inf + nan i) is +-0 +- 0i
def _check_ninf_nan(dummy):
@@ -97,7 +97,7 @@ class TestCexp(object):
if z.real != 0 or z.imag != 0:
raise AssertionError(msgform % (z.real, z.imag))
- yield _check_ninf_nan, None
+ _check_ninf_nan(None)
# cexp(inf + nan i) is +-inf + nan
def _check_inf_nan(dummy):
@@ -107,18 +107,18 @@ class TestCexp(object):
if not np.isinf(z.real) or not np.isnan(z.imag):
raise AssertionError(msgform % (z.real, z.imag))
- yield _check_inf_nan, None
+ _check_inf_nan(None)
# cexp(nan + yi) is nan + nani for y != 0 (optional: raises invalid FPU
# ex)
- yield check, f, np.nan, 1, np.nan, np.nan
- yield check, f, np.nan, -1, np.nan, np.nan
+ check(f, np.nan, 1, np.nan, np.nan)
+ check(f, np.nan, -1, np.nan, np.nan)
- yield check, f, np.nan, np.inf, np.nan, np.nan
- yield check, f, np.nan, -np.inf, np.nan, np.nan
+ check(f, np.nan, np.inf, np.nan, np.nan)
+ check(f, np.nan, -np.inf, np.nan, np.nan)
# cexp(nan + nani) is nan + nani
- yield check, f, np.nan, np.nan, np.nan, np.nan
+ check(f, np.nan, np.nan, np.nan, np.nan)
# TODO This can be xfail when the generator functions are got rid of.
@pytest.mark.skip(reason="cexp(nan + 0I) is wrong on most platforms")
@@ -274,24 +274,28 @@ class TestClog(object):
for i in range(len(xa)):
assert_almost_equal(np.log(xa[i].conj()), ya[i].conj())
+
class TestCsqrt(object):
def test_simple(self):
# sqrt(1)
- yield check_complex_value, np.sqrt, 1, 0, 1, 0
+ check_complex_value(np.sqrt, 1, 0, 1, 0)
# sqrt(1i)
- yield check_complex_value, np.sqrt, 0, 1, 0.5*np.sqrt(2), 0.5*np.sqrt(2), False
+ rres = 0.5*np.sqrt(2)
+ ires = rres
+ check_complex_value(np.sqrt, 0, 1, rres, ires, False)
# sqrt(-1)
- yield check_complex_value, np.sqrt, -1, 0, 0, 1
+ check_complex_value(np.sqrt, -1, 0, 0, 1)
def test_simple_conjugate(self):
ref = np.conj(np.sqrt(complex(1, 1)))
def f(z):
return np.sqrt(np.conj(z))
- yield check_complex_value, f, 1, 1, ref.real, ref.imag, False
+
+ check_complex_value(f, 1, 1, ref.real, ref.imag, False)
#def test_branch_cut(self):
# _check_branch_cut(f, -1, 0, 1, -1)
@@ -304,29 +308,29 @@ class TestCsqrt(object):
f = np.sqrt
# csqrt(+-0 + 0i) is 0 + 0i
- yield check, f, np.PZERO, 0, 0, 0
- yield check, f, np.NZERO, 0, 0, 0
+ check(f, np.PZERO, 0, 0, 0)
+ check(f, np.NZERO, 0, 0, 0)
# csqrt(x + infi) is inf + infi for any x (including NaN)
- yield check, f, 1, np.inf, np.inf, np.inf
- yield check, f, -1, np.inf, np.inf, np.inf
+ check(f, 1, np.inf, np.inf, np.inf)
+ check(f, -1, np.inf, np.inf, np.inf)
- yield check, f, np.PZERO, np.inf, np.inf, np.inf
- yield check, f, np.NZERO, np.inf, np.inf, np.inf
- yield check, f, np.inf, np.inf, np.inf, np.inf
- yield check, f, -np.inf, np.inf, np.inf, np.inf
- yield check, f, -np.nan, np.inf, np.inf, np.inf
+ check(f, np.PZERO, np.inf, np.inf, np.inf)
+ check(f, np.NZERO, np.inf, np.inf, np.inf)
+ check(f, np.inf, np.inf, np.inf, np.inf)
+ check(f, -np.inf, np.inf, np.inf, np.inf)
+ check(f, -np.nan, np.inf, np.inf, np.inf)
# csqrt(x + nani) is nan + nani for any finite x
- yield check, f, 1, np.nan, np.nan, np.nan
- yield check, f, -1, np.nan, np.nan, np.nan
- yield check, f, 0, np.nan, np.nan, np.nan
+ check(f, 1, np.nan, np.nan, np.nan)
+ check(f, -1, np.nan, np.nan, np.nan)
+ check(f, 0, np.nan, np.nan, np.nan)
# csqrt(-inf + yi) is +0 + infi for any finite y > 0
- yield check, f, -np.inf, 1, np.PZERO, np.inf
+ check(f, -np.inf, 1, np.PZERO, np.inf)
# csqrt(inf + yi) is +inf + 0i for any finite y > 0
- yield check, f, np.inf, 1, np.inf, np.PZERO
+ check(f, np.inf, 1, np.inf, np.PZERO)
# csqrt(-inf + nani) is nan +- infi (both +i infi are valid)
def _check_ninf_nan(dummy):
@@ -337,16 +341,16 @@ class TestCsqrt(object):
if not (np.isnan(z.real) and np.isinf(z.imag)):
raise AssertionError(msgform % (z.real, z.imag))
- yield _check_ninf_nan, None
+ _check_ninf_nan(None)
# csqrt(+inf + nani) is inf + nani
- yield check, f, np.inf, np.nan, np.inf, np.nan
+ check(f, np.inf, np.nan, np.inf, np.nan)
# csqrt(nan + yi) is nan + nani for any finite y (infinite handled in x
# + nani)
- yield check, f, np.nan, 0, np.nan, np.nan
- yield check, f, np.nan, 1, np.nan, np.nan
- yield check, f, np.nan, np.nan, np.nan, np.nan
+ check(f, np.nan, 0, np.nan, np.nan)
+ check(f, np.nan, 1, np.nan, np.nan)
+ check(f, np.nan, np.nan, np.nan, np.nan)
# XXX: check for conj(csqrt(z)) == csqrt(conj(z)) (need to fix branch
# cuts first)
@@ -425,21 +429,21 @@ class TestCabs(object):
# cabs(+-nan + nani) returns nan
x.append(np.nan)
y.append(np.nan)
- yield check_real_value, np.abs, np.nan, np.nan, np.nan
+ check_real_value(np.abs, np.nan, np.nan, np.nan)
x.append(np.nan)
y.append(-np.nan)
- yield check_real_value, np.abs, -np.nan, np.nan, np.nan
+ check_real_value(np.abs, -np.nan, np.nan, np.nan)
# According to C99 standard, if exactly one of the real/part is inf and
# the other nan, then cabs should return inf
x.append(np.inf)
y.append(np.nan)
- yield check_real_value, np.abs, np.inf, np.nan, np.inf
+ check_real_value(np.abs, np.inf, np.nan, np.inf)
x.append(-np.inf)
y.append(np.nan)
- yield check_real_value, np.abs, -np.inf, np.nan, np.inf
+ check_real_value(np.abs, -np.inf, np.nan, np.inf)
# cabs(conj(z)) == conj(cabs(z)) (= cabs(z))
def f(a):
@@ -451,7 +455,7 @@ class TestCabs(object):
xa = np.array(x, dtype=complex)
for i in range(len(xa)):
ref = g(x[i], y[i])
- yield check_real_value, f, x[i], y[i], ref
+ check_real_value(f, x[i], y[i], ref)
class TestCarg(object):
def test_simple(self):
@@ -494,31 +498,32 @@ class TestCarg(object):
def test_special_values(self):
# carg(-np.inf +- yi) returns +-pi for finite y > 0
- yield check_real_value, ncu._arg, -np.inf, 1, np.pi, False
- yield check_real_value, ncu._arg, -np.inf, -1, -np.pi, False
+ check_real_value(ncu._arg, -np.inf, 1, np.pi, False)
+ check_real_value(ncu._arg, -np.inf, -1, -np.pi, False)
# carg(np.inf +- yi) returns +-0 for finite y > 0
- yield check_real_value, ncu._arg, np.inf, 1, np.PZERO, False
- yield check_real_value, ncu._arg, np.inf, -1, np.NZERO, False
+ check_real_value(ncu._arg, np.inf, 1, np.PZERO, False)
+ check_real_value(ncu._arg, np.inf, -1, np.NZERO, False)
# carg(x +- np.infi) returns +-pi/2 for finite x
- yield check_real_value, ncu._arg, 1, np.inf, 0.5 * np.pi, False
- yield check_real_value, ncu._arg, 1, -np.inf, -0.5 * np.pi, False
+ check_real_value(ncu._arg, 1, np.inf, 0.5 * np.pi, False)
+ check_real_value(ncu._arg, 1, -np.inf, -0.5 * np.pi, False)
# carg(-np.inf +- np.infi) returns +-3pi/4
- yield check_real_value, ncu._arg, -np.inf, np.inf, 0.75 * np.pi, False
- yield check_real_value, ncu._arg, -np.inf, -np.inf, -0.75 * np.pi, False
+ check_real_value(ncu._arg, -np.inf, np.inf, 0.75 * np.pi, False)
+ check_real_value(ncu._arg, -np.inf, -np.inf, -0.75 * np.pi, False)
# carg(np.inf +- np.infi) returns +-pi/4
- yield check_real_value, ncu._arg, np.inf, np.inf, 0.25 * np.pi, False
- yield check_real_value, ncu._arg, np.inf, -np.inf, -0.25 * np.pi, False
+ check_real_value(ncu._arg, np.inf, np.inf, 0.25 * np.pi, False)
+ check_real_value(ncu._arg, np.inf, -np.inf, -0.25 * np.pi, False)
# carg(x + yi) returns np.nan if x or y is nan
- yield check_real_value, ncu._arg, np.nan, 0, np.nan, False
- yield check_real_value, ncu._arg, 0, np.nan, np.nan, False
+ check_real_value(ncu._arg, np.nan, 0, np.nan, False)
+ check_real_value(ncu._arg, 0, np.nan, np.nan, False)
+
+ check_real_value(ncu._arg, np.nan, np.inf, np.nan, False)
+ check_real_value(ncu._arg, np.inf, np.nan, np.nan, False)
- yield check_real_value, ncu._arg, np.nan, np.inf, np.nan, False
- yield check_real_value, ncu._arg, np.inf, np.nan, np.nan, False
def check_real_value(f, x1, y1, x, exact=True):
z1 = np.array([complex(x1, y1)])
@@ -527,6 +532,7 @@ def check_real_value(f, x1, y1, x, exact=True):
else:
assert_almost_equal(f(z1), x)
+
def check_complex_value(f, x1, y1, x2, y2, exact=True):
z1 = np.array([complex(x1, y1)])
z2 = complex(x2, y2)
diff --git a/numpy/core/umath_tests.py b/numpy/core/umath_tests.py
new file mode 100644
index 000000000..28e325b98
--- /dev/null
+++ b/numpy/core/umath_tests.py
@@ -0,0 +1,15 @@
+"""
+Shim for _umath_tests to allow a deprecation period for the new name.
+
+"""
+from __future__ import division, absolute_import, print_function
+
+import warnings
+
+# 2018-04-04, numpy 1.15.0
+warnings.warn(("numpy.core.umath_tests is an internal NumPy "
+ "module and should not be imported. It will "
+ "be removed in a future NumPy release."),
+ category=DeprecationWarning, stacklevel=2)
+
+from ._umath_tests import *