diff options
Diffstat (limited to 'numpy/core')
-rw-r--r-- | numpy/core/include/numpy/ndarrayobject.h | 31 | ||||
-rw-r--r-- | numpy/core/src/umath/loops.c.src | 20 | ||||
-rw-r--r-- | numpy/core/tests/test_regression.py | 10 | ||||
-rw-r--r-- | numpy/core/tests/test_umath_complex.py | 134 | ||||
-rw-r--r-- | numpy/core/umath_tests.py | 15 |
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 * |