diff options
Diffstat (limited to 'numpy')
-rw-r--r-- | numpy/core/include/numpy/npy_common.h | 8 | ||||
-rw-r--r-- | numpy/core/setup.py | 10 | ||||
-rw-r--r-- | numpy/core/setup_common.py | 5 | ||||
-rw-r--r-- | numpy/core/src/multiarray/buffer.c | 115 | ||||
-rw-r--r-- | numpy/core/src/multiarray/einsum.c.src | 6 | ||||
-rw-r--r-- | numpy/core/src/npysort/selection.c.src | 8 | ||||
-rw-r--r-- | numpy/core/src/private/ufunc_override.h | 172 | ||||
-rw-r--r-- | numpy/core/src/umath/loops.c.src | 3 | ||||
-rw-r--r-- | numpy/core/src/umath/simd.inc.src | 26 | ||||
-rw-r--r-- | numpy/core/tests/test_multiarray.py | 78 | ||||
-rw-r--r-- | numpy/core/tests/test_scalarmath.py | 47 | ||||
-rw-r--r-- | numpy/core/tests/test_umath.py | 8 | ||||
-rw-r--r-- | numpy/lib/npyio.py | 27 |
13 files changed, 388 insertions, 125 deletions
diff --git a/numpy/core/include/numpy/npy_common.h b/numpy/core/include/numpy/npy_common.h index 62ffa4006..08582bf79 100644 --- a/numpy/core/include/numpy/npy_common.h +++ b/numpy/core/include/numpy/npy_common.h @@ -18,6 +18,14 @@ #define NPY_GCC_UNROLL_LOOPS #endif +#if defined HAVE_XMMINTRIN_H && defined HAVE__MM_LOAD_PS +#define NPY_HAVE_SSE_INTRINSICS +#endif + +#if defined HAVE_EMMINTRIN_H && defined HAVE__MM_LOAD_PD +#define NPY_HAVE_SSE2_INTRINSICS +#endif + /* * give a hint to the compiler which branch is more likely or unlikely * to occur, e.g. rare error cases: diff --git a/numpy/core/setup.py b/numpy/core/setup.py index 1c8cea4f7..576b7d5ff 100644 --- a/numpy/core/setup.py +++ b/numpy/core/setup.py @@ -165,8 +165,14 @@ def check_math_capabilities(config, moredefs, mathlibs): if config.check_func("", decl=False, call=False, headers=[h]): moredefs.append((fname2def(h).replace(".", "_"), 1)) - for f, args in OPTIONAL_INTRINSICS: - if config.check_func(f, decl=False, call=True, call_args=args): + for tup in OPTIONAL_INTRINSICS: + headers = None + if len(tup) == 2: + f, args = tup + else: + f, args, headers = tup[0], tup[1], [tup[2]] + if config.check_func(f, decl=False, call=True, call_args=args, + headers=headers): moredefs.append((fname2def(f), 1)) for dec, fn in OPTIONAL_GCC_ATTRIBUTES: diff --git a/numpy/core/setup_common.py b/numpy/core/setup_common.py index 1f3e6b44e..bad3607fa 100644 --- a/numpy/core/setup_common.py +++ b/numpy/core/setup_common.py @@ -107,7 +107,8 @@ OPTIONAL_HEADERS = [ "emmintrin.h", # SSE2 ] -# optional gcc compiler builtins and their call arguments +# optional gcc compiler builtins and their call arguments and optional a +# required header # call arguments are required as the compiler will do strict signature checking OPTIONAL_INTRINSICS = [("__builtin_isnan", '5.'), ("__builtin_isinf", '5.'), @@ -115,6 +116,8 @@ OPTIONAL_INTRINSICS = [("__builtin_isnan", '5.'), ("__builtin_bswap32", '5u'), ("__builtin_bswap64", '5u'), ("__builtin_expect", '5, 0'), + ("_mm_load_ps", '(float*)0', "xmmintrin.h"), # SSE + ("_mm_load_pd", '(double*)0', "emmintrin.h"), # SSE2 ] # gcc function attributes diff --git a/numpy/core/src/multiarray/buffer.c b/numpy/core/src/multiarray/buffer.c index 3ae3c7d0d..975891b3a 100644 --- a/numpy/core/src/multiarray/buffer.c +++ b/numpy/core/src/multiarray/buffer.c @@ -767,11 +767,18 @@ NPY_NO_EXPORT PyBufferProcs array_as_buffer = { * Convert PEP 3118 format string to PyArray_Descr */ +static int +_descriptor_from_pep3118_format_fast(char *s, PyObject **result); + +static int +_pep3118_letter_to_type(char letter, int native, int complex); + NPY_NO_EXPORT PyArray_Descr* _descriptor_from_pep3118_format(char *s) { char *buf, *p; int in_name = 0; + int obtained; PyObject *descr; PyObject *str; PyObject *_numpy_internal; @@ -780,6 +787,12 @@ _descriptor_from_pep3118_format(char *s) return PyArray_DescrNewFromType(NPY_BYTE); } + /* Fast path */ + obtained = _descriptor_from_pep3118_format_fast(s, &descr); + if (obtained) { + return (PyArray_Descr*)descr; + } + /* Strip whitespace, except from field names */ buf = malloc(strlen(s) + 1); if (buf == NULL) { @@ -828,3 +841,105 @@ _descriptor_from_pep3118_format(char *s) } return (PyArray_Descr*)descr; } + +/* + * Fast path for parsing buffer strings corresponding to simple types. + * + * Currently, this deals only with single-element data types. + */ + +static int +_descriptor_from_pep3118_format_fast(char *s, PyObject **result) +{ + PyArray_Descr *descr; + + int is_standard_size = 0; + char byte_order = '='; + int is_complex = 0; + + int type_num = NPY_BYTE; + int item_seen = 0; + + for (; *s != '\0'; ++s) { + is_complex = 0; + switch (*s) { + case '@': + case '^': + /* ^ means no alignment; doesn't matter for a single element */ + byte_order = '='; + is_standard_size = 0; + break; + case '<': + byte_order = '<'; + is_standard_size = 1; + break; + case '>': + case '!': + byte_order = '>'; + is_standard_size = 1; + break; + case '=': + byte_order = '='; + is_standard_size = 1; + break; + case 'Z': + is_complex = 1; + ++s; + default: + if (item_seen) { + /* Not a single-element data type */ + return 0; + } + type_num = _pep3118_letter_to_type(*s, !is_standard_size, + is_complex); + if (type_num < 0) { + /* Something unknown */ + return 0; + } + item_seen = 1; + break; + } + } + + if (!item_seen) { + return 0; + } + + descr = PyArray_DescrFromType(type_num); + if (byte_order == '=') { + *result = (PyObject*)descr; + } + else { + *result = (PyObject*)PyArray_DescrNewByteorder(descr, byte_order); + Py_DECREF(descr); + } + + return 1; +} + +static int +_pep3118_letter_to_type(char letter, int native, int complex) +{ + switch (letter) + { + case '?': return NPY_BOOL; + case 'b': return NPY_BYTE; + case 'B': return NPY_UBYTE; + case 'h': return native ? NPY_SHORT : NPY_INT16; + case 'H': return native ? NPY_USHORT : NPY_UINT16; + case 'i': return native ? NPY_INT : NPY_INT32; + case 'I': return native ? NPY_UINT : NPY_UINT32; + case 'l': return native ? NPY_LONG : NPY_INT32; + case 'L': return native ? NPY_ULONG : NPY_UINT32; + case 'q': return native ? NPY_LONGLONG : NPY_INT64; + case 'Q': return native ? NPY_ULONGLONG : NPY_UINT64; + case 'e': return NPY_HALF; + case 'f': return complex ? NPY_CFLOAT : NPY_FLOAT; + case 'd': return complex ? NPY_CDOUBLE : NPY_DOUBLE; + case 'g': return native ? (complex ? NPY_CLONGDOUBLE : NPY_LONGDOUBLE) : -1; + default: + /* Other unhandled cases */ + return -1; + } + return -1; +} diff --git a/numpy/core/src/multiarray/einsum.c.src b/numpy/core/src/multiarray/einsum.c.src index 56b1ce746..7a94c9305 100644 --- a/numpy/core/src/multiarray/einsum.c.src +++ b/numpy/core/src/multiarray/einsum.c.src @@ -14,16 +14,16 @@ #define NPY_NO_DEPRECATED_API NPY_API_VERSION #define _MULTIARRAYMODULE +#include <numpy/npy_common.h> #include <numpy/arrayobject.h> #include <numpy/halffloat.h> #include <npy_pycompat.h> -#include <npy_config.h> #include <ctype.h> #include "convert.h" -#ifdef HAVE_XMMINTRIN_H +#ifdef NPY_HAVE_SSE_INTRINSICS #define EINSUM_USE_SSE1 1 #else #define EINSUM_USE_SSE1 0 @@ -32,7 +32,7 @@ /* * TODO: Only some SSE2 for float64 is implemented. */ -#ifdef HAVE_EMMINTRIN_H +#ifdef NPY_HAVE_SSE2_INTRINSICS #define EINSUM_USE_SSE2 1 #else #define EINSUM_USE_SSE2 0 diff --git a/numpy/core/src/npysort/selection.c.src b/numpy/core/src/npysort/selection.c.src index b11753367..073b5847f 100644 --- a/numpy/core/src/npysort/selection.c.src +++ b/numpy/core/src/npysort/selection.c.src @@ -176,12 +176,8 @@ static npy_intp @name@median5_@suff@( } } else { - if (@TYPE@_LT(v[IDX(2)], v[IDX(1)])) { - return 1; - } - else { - return 2; - } + /* v[1] and v[2] swapped into order above */ + return 2; } } diff --git a/numpy/core/src/private/ufunc_override.h b/numpy/core/src/private/ufunc_override.h index 5c3cbdb12..af7f6e46e 100644 --- a/numpy/core/src/private/ufunc_override.h +++ b/numpy/core/src/private/ufunc_override.h @@ -11,6 +11,9 @@ * routine returning something other than `NotImplemented` determines the * result. If all of the `__numpy_ufunc__` operations returns `NotImplemented`, * a `TypeError` is raised. + * + * Returns 0 on success and 1 on exception. On success, *result contains the + * result of the operation, if any. If *result is NULL, there is no override. */ static int PyUFunc_CheckOverride(PyObject *ufunc, char *method, @@ -21,31 +24,36 @@ PyUFunc_CheckOverride(PyObject *ufunc, char *method, int i; int override_pos; /* Position of override in args.*/ int j; - int pos_in_with_override; /* Position of override in with_override.*/ int nargs = PyTuple_GET_SIZE(args); int noa = 0; /* Number of overriding args.*/ - int normalized = 0; /* Is normalized flag.*/ PyObject *obj; PyObject *other_obj; - PyObject *override_args; - PyObject *method_name = PyUString_FromString(method); + PyObject *method_name = NULL; PyObject *normal_args = NULL; /* normal_* holds normalized arguments. */ PyObject *normal_kwds = NULL; - PyObject *override_obj = NULL; /* overriding object */ - PyObject *numpy_ufunc = NULL; /* the __numpy_ufunc__ method */ PyObject *with_override[NPY_MAXARGS]; + /* Pos of each override in args */ int with_override_pos[NPY_MAXARGS]; - /* Checks */ + /* + * Check inputs + */ if (!PyTuple_Check(args)) { + PyErr_SetString(PyExc_ValueError, + "Internal Numpy error: call to PyUFunc_CheckOverride " + "with non-tuple"); goto fail; } + if (PyTuple_GET_SIZE(args) > NPY_MAXARGS) { + PyErr_SetString(PyExc_ValueError, + "Internal Numpy error: too many arguments in call " + "to PyUFunc_CheckOverride"); goto fail; } @@ -63,12 +71,48 @@ PyUFunc_CheckOverride(PyObject *ufunc, char *method, /* No overrides, bail out.*/ if (noa == 0) { - Py_DECREF(method_name); + *result = NULL; return 0; } + /* + * Normalize ufunc arguments. + */ + normal_args = PyTuple_GetSlice(args, 0, nin); + if (normal_args == NULL) { + goto fail; + } + + /* Build new kwds */ + if (kwds && PyDict_CheckExact(kwds)) { + normal_kwds = PyDict_Copy(kwds); + } + else { + normal_kwds = PyDict_New(); + } + if (normal_kwds == NULL) { + goto fail; + } + + /* If we have more args than nin, the last one must be `out`.*/ + if (nargs > nin) { + obj = PyTuple_GET_ITEM(args, nargs - 1); + PyDict_SetItemString(normal_kwds, "out", obj); + } + + method_name = PyUString_FromString(method); + if (method_name == NULL) { + goto fail; + } + + /* + * Call __numpy_ufunc__ functions in correct order + */ while (1) { - obj = NULL; + PyObject *numpy_ufunc; + PyObject *override_args; + PyObject *override_obj; + override_obj = NULL; *result = NULL; @@ -78,10 +122,10 @@ PyUFunc_CheckOverride(PyObject *ufunc, char *method, if (obj == NULL) { continue; } + /* Get the first instance of an overriding arg.*/ override_pos = with_override_pos[i]; override_obj = obj; - pos_in_with_override = i; /* Check for sub-types to the right of obj. */ for (j = i + 1; j < noa; j++) { @@ -93,103 +137,67 @@ PyUFunc_CheckOverride(PyObject *ufunc, char *method, break; } } + /* override_obj had no subtypes to the right. */ if (override_obj) { + with_override[i] = NULL; /* We won't call this one again */ break; } } - /* No good override_obj */ + + /* Check if there is a method left to call */ if (!override_obj) { - break; + /* No acceptable override found. */ + PyErr_SetString(PyExc_TypeError, + "__numpy_ufunc__ not implemented for this type."); + goto fail; } - /* - * Normalize the ufuncs arguments. Returns a tuple of - * (args, kwds). - * - * Test with and without kwds. - */ - if (!normalized) { - PyObject *out_arg; - - /* If we have more args than nin, the last one must be `out`.*/ - if (nargs > nin) { - out_arg = PyTuple_GET_ITEM(args, nargs - 1); - - /* Build new args.*/ - normal_args = PyTuple_GetSlice(args, 0, nin); - - /* Build new kwds with out arg.*/ - if (kwds && PyDict_CheckExact(kwds)) { - normal_kwds = PyDict_Copy(kwds); - PyDict_SetItemString(normal_kwds, "out", out_arg); - } - else { - normal_kwds = PyDict_New(); - PyDict_SetItemString(normal_kwds, "out", out_arg); - } - normalized = 1; - } - else { - /* Copy args */ - normal_args = PyTuple_GetSlice(args, 0, nin); - if (kwds && PyDict_CheckExact(kwds)) { - normal_kwds = PyDict_Copy(kwds); - } - else { - normal_kwds = PyDict_New(); - } + /* Call the override */ + numpy_ufunc = PyObject_GetAttrString(override_obj, + "__numpy_ufunc__"); + if (numpy_ufunc == NULL) { + goto fail; + } - normalized = 1; - } + override_args = Py_BuildValue("OOiO", ufunc, method_name, + override_pos, normal_args); + if (override_args == NULL) { + Py_DECREF(numpy_ufunc); + goto fail; } - /* Calculate a result if we have a override. */ - if (override_obj) { - numpy_ufunc = PyObject_GetAttrString(override_obj, - "__numpy_ufunc__"); - override_args = Py_BuildValue("OOiO", ufunc, method_name, - override_pos, normal_args); - *result = PyObject_Call(numpy_ufunc, override_args, normal_kwds); + *result = PyObject_Call(numpy_ufunc, override_args, normal_kwds); - Py_DECREF(numpy_ufunc); - Py_DECREF(override_args); + Py_DECREF(numpy_ufunc); + Py_DECREF(override_args); - /* Remove this arg if it gives not implemented */ - if (*result == Py_NotImplemented) { - with_override[pos_in_with_override] = NULL; - Py_DECREF(*result); - continue; - } - /* Good result. */ - else { - break; - } + if (*result == NULL) { + /* Exception occurred */ + goto fail; + } + else if (*result == Py_NotImplemented) { + /* Try the next one */ + Py_DECREF(*result); + continue; } - - /* All overrides checked. */ else { + /* Good result. */ break; } } - /* No acceptable override found. */ - if (!*result) { - PyErr_SetString(PyExc_TypeError, - "__numpy_ufunc__ not implemented for this type."); - Py_XDECREF(normal_args); - Py_XDECREF(normal_kwds); - goto fail; - } + /* Override found, return it. */ - Py_DECREF(method_name); + Py_XDECREF(method_name); Py_XDECREF(normal_args); Py_XDECREF(normal_kwds); return 0; fail: - Py_DECREF(method_name); + Py_XDECREF(method_name); + Py_XDECREF(normal_args); + Py_XDECREF(normal_kwds); return 1; - } #endif diff --git a/numpy/core/src/umath/loops.c.src b/numpy/core/src/umath/loops.c.src index d1fc58ffa..a444d37c3 100644 --- a/numpy/core/src/umath/loops.c.src +++ b/numpy/core/src/umath/loops.c.src @@ -10,6 +10,7 @@ #define NO_IMPORT_ARRAY #endif +#include "numpy/npy_common.h" #include "numpy/arrayobject.h" #include "numpy/ufuncobject.h" #include "numpy/npy_math.h" @@ -564,7 +565,7 @@ NPY_NO_EXPORT void BOOL_@kind@(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)) { if(IS_BINARY_REDUCE) { -#ifdef HAVE_EMMINTRIN_H +#ifdef NPY_HAVE_SSE2_INTRINSICS /* * stick with our variant for more reliable performance, only known * platform which outperforms it by ~20% is an i7 with glibc 2.17 diff --git a/numpy/core/src/umath/simd.inc.src b/numpy/core/src/umath/simd.inc.src index e1fe6c5b5..e274e0596 100644 --- a/numpy/core/src/umath/simd.inc.src +++ b/numpy/core/src/umath/simd.inc.src @@ -16,10 +16,10 @@ #define __NPY_SIMD_INC #include "lowlevel_strided_loops.h" -#include "npy_config.h" +#include "numpy/npy_common.h" /* for NO_FLOATING_POINT_SUPPORT */ #include "numpy/ufuncobject.h" -#ifdef HAVE_EMMINTRIN_H +#ifdef NPY_HAVE_SSE2_INTRINSICS #include <emmintrin.h> #endif #include <assert.h> @@ -140,7 +140,7 @@ static const npy_int32 fanout_4[] = { * #name = unary, unary, unary_reduce, unary_reduce# */ -#if @vector@ && defined HAVE_EMMINTRIN_H +#if @vector@ && defined NPY_HAVE_SSE2_INTRINSICS /* prototypes */ static void @@ -151,7 +151,7 @@ sse2_@func@_@TYPE@(@type@ *, @type@ *, const npy_intp n); static NPY_INLINE int run_@name@_simd_@func@_@TYPE@(char **args, npy_intp *dimensions, npy_intp *steps) { -#if @vector@ && defined HAVE_EMMINTRIN_H +#if @vector@ && defined NPY_HAVE_SSE2_INTRINSICS if (@check@(sizeof(@type@), 16)) { sse2_@func@_@TYPE@((@type@*)args[1], (@type@*)args[0], dimensions[0]); return 1; @@ -167,7 +167,7 @@ run_@name@_simd_@func@_@TYPE@(char **args, npy_intp *dimensions, npy_intp *steps * # kind = add, subtract, multiply, divide# */ -#if @vector@ && defined HAVE_EMMINTRIN_H +#if @vector@ && defined NPY_HAVE_SSE2_INTRINSICS /* prototypes */ static void @@ -185,7 +185,7 @@ sse2_binary_scalar2_@kind@_@TYPE@(@type@ * op, @type@ * ip1, @type@ * ip2, static NPY_INLINE int run_binary_simd_@kind@_@TYPE@(char **args, npy_intp *dimensions, npy_intp *steps) { -#if @vector@ && defined HAVE_EMMINTRIN_H +#if @vector@ && defined NPY_HAVE_SSE2_INTRINSICS @type@ * ip1 = (@type@ *)args[0]; @type@ * ip2 = (@type@ *)args[1]; @type@ * op = (@type@ *)args[2]; @@ -216,7 +216,7 @@ run_binary_simd_@kind@_@TYPE@(char **args, npy_intp *dimensions, npy_intp *steps * #simd = 1, 1, 1, 1, 1, 1, 0, 0# */ -#if @vector@ && @simd@ && defined HAVE_EMMINTRIN_H +#if @vector@ && @simd@ && defined NPY_HAVE_SSE2_INTRINSICS /* prototypes */ static void @@ -234,7 +234,7 @@ sse2_binary_scalar2_@kind@_@TYPE@(npy_bool * op, @type@ * ip1, @type@ * ip2, static NPY_INLINE int run_binary_simd_@kind@_@TYPE@(char **args, npy_intp *dimensions, npy_intp *steps) { -#if @vector@ && @simd@ && defined HAVE_EMMINTRIN_H +#if @vector@ && @simd@ && defined NPY_HAVE_SSE2_INTRINSICS @type@ * ip1 = (@type@ *)args[0]; @type@ * ip2 = (@type@ *)args[1]; npy_bool * op = (npy_bool *)args[2]; @@ -278,7 +278,7 @@ sse2_binary_@kind@_BOOL(npy_bool * op, npy_bool * ip1, npy_bool * ip2, static NPY_INLINE int run_binary_simd_@kind@_BOOL(char **args, npy_intp *dimensions, npy_intp *steps) { -#if defined HAVE_EMMINTRIN_H +#if defined NPY_HAVE_SSE2_INTRINSICS if (sizeof(npy_bool) == 1 && IS_BLOCKABLE_BINARY(sizeof(npy_bool), 16)) { sse2_binary_@kind@_BOOL((npy_bool*)args[2], (npy_bool*)args[0], (npy_bool*)args[1], dimensions[0]); @@ -295,7 +295,7 @@ sse2_reduce_@kind@_BOOL(npy_bool * op, npy_bool * ip, npy_intp n); static NPY_INLINE int run_reduce_simd_@kind@_BOOL(char **args, npy_intp *dimensions, npy_intp *steps) { -#if defined HAVE_EMMINTRIN_H +#if defined NPY_HAVE_SSE2_INTRINSICS if (sizeof(npy_bool) == 1 && IS_BLOCKABLE_REDUCE(sizeof(npy_bool), 16)) { sse2_reduce_@kind@_BOOL((npy_bool*)args[0], (npy_bool*)args[1], dimensions[0]); @@ -317,7 +317,7 @@ sse2_@kind@_BOOL(npy_bool *, npy_bool *, const npy_intp n); static NPY_INLINE int run_unary_simd_@kind@_BOOL(char **args, npy_intp *dimensions, npy_intp *steps) { -#if defined HAVE_EMMINTRIN_H +#if defined NPY_HAVE_SSE2_INTRINSICS if (sizeof(npy_bool) == 1 && IS_BLOCKABLE_UNARY(sizeof(npy_bool), 16)) { sse2_@kind@_BOOL((npy_bool*)args[1], (npy_bool*)args[0], dimensions[0]); return 1; @@ -328,7 +328,7 @@ run_unary_simd_@kind@_BOOL(char **args, npy_intp *dimensions, npy_intp *steps) /**end repeat**/ -#ifdef HAVE_EMMINTRIN_H +#ifdef NPY_HAVE_SSE2_INTRINSICS /* * Vectorized operations @@ -843,6 +843,6 @@ sse2_@kind@_BOOL(@type@ * op, @type@ * ip, const npy_intp n) /**end repeat**/ -#endif /* HAVE_EMMINTRIN_H */ +#endif /* NPY_HAVE_SSE2_INTRINSICS */ #endif diff --git a/numpy/core/tests/test_multiarray.py b/numpy/core/tests/test_multiarray.py index 33e3bdcab..012fa0cab 100644 --- a/numpy/core/tests/test_multiarray.py +++ b/numpy/core/tests/test_multiarray.py @@ -1141,6 +1141,17 @@ class TestMethods(TestCase): assert_array_equal(d[np.argpartition(d, -6, kind=k)], np.partition(d, 41, kind=k)) + # median of 3 killer, O(n^2) on pure median 3 pivot quickselect + # exercises the median of median of 5 code used to keep O(n) + d = np.arange(1000000) + x = np.roll(d, d.size // 2) + mid = x.size // 2 + 1 + assert_equal(np.partition(x, mid)[mid], mid) + d = np.arange(1000001) + x = np.roll(d, d.size // 2 + 1) + mid = x.size // 2 + 1 + assert_equal(np.partition(x, mid)[mid], mid) + # equal elements d = np.arange((47)) % 7 tgt = np.sort(np.arange((47)) % 7) @@ -3239,6 +3250,29 @@ class TestNewBufferProtocol(object): x = np.array(half_list, dtype='<e') self._check_roundtrip(x) + def test_roundtrip_single_types(self): + for typ in np.typeDict.values(): + dtype = np.dtype(typ) + + if dtype.char in 'Mm': + # datetimes cannot be used in buffers + continue + if dtype.char == 'V': + # skip void + continue + + x = np.zeros(4, dtype=dtype) + self._check_roundtrip(x) + + if dtype.char not in 'qQgG': + dt = dtype.newbyteorder('<') + x = np.zeros(4, dtype=dt) + self._check_roundtrip(x) + + dt = dtype.newbyteorder('>') + x = np.zeros(4, dtype=dt) + self._check_roundtrip(x) + def test_export_simple_1d(self): x = np.array([1, 2, 3, 4, 5], dtype='i') y = memoryview(x) @@ -3407,6 +3441,7 @@ class TestArrayAttributeDeletion(object): for s in attr: assert_raises(AttributeError, delattr, a, s) + def test_array_interface(): # Test scalar coercion within the array interface class Foo(object): @@ -3629,5 +3664,48 @@ class TestArrayPriority(TestCase): assert_(isinstance(res4, PriorityNdarray)) +class TestConversion(TestCase): + def test_array_scalar_relational_operation(self): + #All integer + for dt1 in np.typecodes['AllInteger']: + assert_(1 > np.array(0, dtype=dt1), "type %s failed" % (dt1,)) + assert_(not 1 < np.array(0, dtype=dt1), "type %s failed" % (dt1,)) + + for dt2 in np.typecodes['AllInteger']: + assert_(np.array(1, dtype=dt1) > np.array(0, dtype=dt2), + "type %s and %s failed" % (dt1, dt2)) + assert_(not np.array(1, dtype=dt1) < np.array(0, dtype=dt2), + "type %s and %s failed" % (dt1, dt2)) + + #Unsigned integers + for dt1 in 'BHILQP': + assert_(-1 < np.array(1, dtype=dt1), "type %s failed" % (dt1,)) + assert_(not -1 > np.array(1, dtype=dt1), "type %s failed" % (dt1,)) + assert_(-1 != np.array(1, dtype=dt1), "type %s failed" % (dt1,)) + + #unsigned vs signed + for dt2 in 'bhilqp': + assert_(np.array(1, dtype=dt1) > np.array(-1, dtype=dt2), + "type %s and %s failed" % (dt1, dt2)) + assert_(not np.array(1, dtype=dt1) < np.array(-1, dtype=dt2), + "type %s and %s failed" % (dt1, dt2)) + assert_(np.array(1, dtype=dt1) != np.array(-1, dtype=dt2), + "type %s and %s failed" % (dt1, dt2)) + + #Signed integers and floats + for dt1 in 'bhlqp' + np.typecodes['Float']: + assert_(1 > np.array(-1, dtype=dt1), "type %s failed" % (dt1,)) + assert_(not 1 < np.array(-1, dtype=dt1), "type %s failed" % (dt1,)) + assert_(-1 == np.array(-1, dtype=dt1), "type %s failed" % (dt1,)) + + for dt2 in 'bhlqp' + np.typecodes['Float']: + assert_(np.array(1, dtype=dt1) > np.array(-1, dtype=dt2), + "type %s and %s failed" % (dt1, dt2)) + assert_(not np.array(1, dtype=dt1) < np.array(-1, dtype=dt2), + "type %s and %s failed" % (dt1, dt2)) + assert_(np.array(-1, dtype=dt1) == np.array(-1, dtype=dt2), + "type %s and %s failed" % (dt1, dt2)) + + if __name__ == "__main__": run_module_suite() diff --git a/numpy/core/tests/test_scalarmath.py b/numpy/core/tests/test_scalarmath.py index a4cc5e711..a3d1200ca 100644 --- a/numpy/core/tests/test_scalarmath.py +++ b/numpy/core/tests/test_scalarmath.py @@ -139,7 +139,6 @@ class TestConversion(TestCase): a = np.array(l[:3], dtype=np.uint64) assert_equal([int(_m) for _m in a], li[:3]) - def test_iinfo_long_values(self): for code in 'bBhH': res = np.array(np.iinfo(code).max + 1, dtype=code) @@ -156,16 +155,56 @@ class TestConversion(TestCase): tgt = np.iinfo(code).max assert_(res == tgt) - def test_int_raise_behaviour(self): - - def Overflow_error_func(dtype): + def Overflow_error_func(dtype): res = np.typeDict[dtype](np.iinfo(dtype).max + 1) for code in 'lLqQ': assert_raises(OverflowError, Overflow_error_func, code) + def test_numpy_scalar_relational_operators(self): + #All integer + for dt1 in np.typecodes['AllInteger']: + assert_(1 > np.array(0, dtype=dt1)[()], "type %s failed" % (dt1,)) + assert_(not 1 < np.array(0, dtype=dt1)[()], "type %s failed" % (dt1,)) + + for dt2 in np.typecodes['AllInteger']: + assert_(np.array(1, dtype=dt1)[()] > np.array(0, dtype=dt2)[()], + "type %s and %s failed" % (dt1, dt2)) + assert_(not np.array(1, dtype=dt1)[()] < np.array(0, dtype=dt2)[()], + "type %s and %s failed" % (dt1, dt2)) + + #Unsigned integers + for dt1 in 'BHILQP': + assert_(-1 < np.array(1, dtype=dt1)[()], "type %s failed" % (dt1,)) + assert_(not -1 > np.array(1, dtype=dt1)[()], "type %s failed" % (dt1,)) + assert_(-1 != np.array(1, dtype=dt1)[()], "type %s failed" % (dt1,)) + + #unsigned vs signed + for dt2 in 'bhilqp': + assert_(np.array(1, dtype=dt1)[()] > np.array(-1, dtype=dt2)[()], + "type %s and %s failed" % (dt1, dt2)) + assert_(not np.array(1, dtype=dt1)[()] < np.array(-1, dtype=dt2)[()], + "type %s and %s failed" % (dt1, dt2)) + assert_(np.array(1, dtype=dt1)[()] != np.array(-1, dtype=dt2)[()], + "type %s and %s failed" % (dt1, dt2)) + + #Signed integers and floats + for dt1 in 'bhlqp' + np.typecodes['Float']: + assert_(1 > np.array(-1, dtype=dt1)[()], "type %s failed" % (dt1,)) + assert_(not 1 < np.array(-1, dtype=dt1)[()], "type %s failed" % (dt1,)) + assert_(-1 == np.array(-1, dtype=dt1)[()], "type %s failed" % (dt1,)) + + for dt2 in 'bhlqp' + np.typecodes['Float']: + assert_(np.array(1, dtype=dt1)[()] > np.array(-1, dtype=dt2)[()], + "type %s and %s failed" % (dt1, dt2)) + assert_(not np.array(1, dtype=dt1)[()] < np.array(-1, dtype=dt2)[()], + "type %s and %s failed" % (dt1, dt2)) + assert_(np.array(-1, dtype=dt1)[()] == np.array(-1, dtype=dt2)[()], + "type %s and %s failed" % (dt1, dt2)) + + #class TestRepr(TestCase): # def test_repr(self): # for t in types: diff --git a/numpy/core/tests/test_umath.py b/numpy/core/tests/test_umath.py index 61f084a01..1fc59f5fd 100644 --- a/numpy/core/tests/test_umath.py +++ b/numpy/core/tests/test_umath.py @@ -1051,6 +1051,14 @@ class TestSpecialMethods(TestCase): assert_equal(res4['out'], 'out_arg') assert_equal(res5['out'], 'out_arg') + def test_ufunc_override_exception(self): + class A(object): + def __numpy_ufunc__(self, *a, **kwargs): + raise ValueError("oops") + a = A() + for func in [np.divide, np.dot]: + assert_raises(ValueError, func, a, a) + class TestChoose(TestCase): def test_mixed(self): c = np.array([True, True]) diff --git a/numpy/lib/npyio.py b/numpy/lib/npyio.py index 6873a4785..888bf4370 100644 --- a/numpy/lib/npyio.py +++ b/numpy/lib/npyio.py @@ -138,19 +138,19 @@ class NpzFile(object): archive provided on construction. `NpzFile` is used to load files in the NumPy ``.npz`` data archive - format. It assumes that files in the archive have a ".npy" extension, + format. It assumes that files in the archive have a ``.npy`` extension, other files are ignored. The arrays and file strings are lazily loaded on either getitem access using ``obj['key']`` or attribute lookup using - ``obj.f.key``. A list of all files (without ".npy" extensions) can + ``obj.f.key``. A list of all files (without ``.npy`` extensions) can be obtained with ``obj.files`` and the ZipFile object itself using ``obj.zip``. Attributes ---------- files : list of str - List of all files in the archive with a ".npy" extension. + List of all files in the archive with a ``.npy`` extension. zip : ZipFile instance The ZipFile object initialized with the zipped archive. f : BagObj instance @@ -270,7 +270,7 @@ class NpzFile(object): yield (f, self[f]) def keys(self): - """Return files in the archive with a ".npy" extension.""" + """Return files in the archive with a ``.npy`` extension.""" return self.files def iterkeys(self): @@ -283,7 +283,7 @@ class NpzFile(object): def load(file, mmap_mode=None): """ - Load an array(s) or pickled objects from .npy, .npz, or pickled files. + Load arrays or pickled objects from ``.npy``, ``.npz`` or pickled files. Parameters ---------- @@ -301,7 +301,7 @@ def load(file, mmap_mode=None): Returns ------- result : array, tuple, dict, etc. - Data stored in the file. For '.npz' files, the returned instance of + Data stored in the file. For ``.npz`` files, the returned instance of NpzFile class must be closed to avoid leaking file descriptors. Raises @@ -457,9 +457,9 @@ def savez(file, *args, **kwds): Save several arrays into a single file in uncompressed ``.npz`` format. If arguments are passed in with no keywords, the corresponding variable - names, in the .npz file, are 'arr_0', 'arr_1', etc. If keyword arguments - are given, the corresponding variable names, in the ``.npz`` file will - match the keyword names. + names, in the ``.npz`` file, are 'arr_0', 'arr_1', etc. If keyword + arguments are given, the corresponding variable names, in the ``.npz`` + file will match the keyword names. Parameters ---------- @@ -484,7 +484,7 @@ def savez(file, *args, **kwds): -------- save : Save a single array to a binary file in NumPy format. savetxt : Save an array to a file as plain text. - savez_compressed : Save several arrays into a compressed .npz file format + savez_compressed : Save several arrays into a compressed ``.npz`` archive Notes ----- @@ -540,7 +540,7 @@ def savez_compressed(file, *args, **kwds): Parameters ---------- file : str - File name of .npz file. + File name of ``.npz`` file. args : Arguments Function arguments. kwds : Keyword arguments @@ -548,7 +548,7 @@ def savez_compressed(file, *args, **kwds): See Also -------- - numpy.savez : Save several arrays into an uncompressed .npz file format + numpy.savez : Save several arrays into an uncompressed ``.npz`` file format """ _savez(file, args, kwds, True) @@ -923,7 +923,8 @@ def savetxt(fname, X, fmt='%.18e', delimiter=' ', newline='\n', header='', See Also -------- save : Save an array to a binary file in NumPy ``.npy`` format - savez : Save several arrays into a ``.npz`` compressed archive + savez : Save several arrays into an uncompressed ``.npz`` archive + savez_compressed : Save several arrays into a compressed ``.npz`` archive Notes ----- |