diff options
-rw-r--r-- | doc/release/1.10.0-notes.rst | 15 | ||||
-rw-r--r-- | numpy/build_utils/src/apple_sgemv_fix.c | 12 | ||||
-rw-r--r-- | numpy/core/_internal.py | 75 | ||||
-rw-r--r-- | numpy/core/src/multiarray/arraytypes.c.src | 38 | ||||
-rw-r--r-- | numpy/core/src/multiarray/mapping.c | 179 | ||||
-rw-r--r-- | numpy/core/src/multiarray/nditer_pywrap.c | 14 | ||||
-rw-r--r-- | numpy/core/src/npysort/heapsort.c.src | 25 | ||||
-rw-r--r-- | numpy/core/src/npysort/mergesort.c.src | 16 | ||||
-rw-r--r-- | numpy/core/src/npysort/quicksort.c.src | 25 | ||||
-rw-r--r-- | numpy/core/src/private/npy_sort.h | 324 | ||||
-rw-r--r-- | numpy/core/tests/test_indexing.py | 4 | ||||
-rw-r--r-- | numpy/core/tests/test_multiarray.py | 72 | ||||
-rw-r--r-- | numpy/core/tests/test_records.py | 5 | ||||
-rw-r--r-- | numpy/ma/core.py | 260 | ||||
-rw-r--r-- | numpy/ma/tests/test_core.py | 35 | ||||
-rw-r--r-- | numpy/ma/tests/test_subclassing.py | 40 |
16 files changed, 654 insertions, 485 deletions
diff --git a/doc/release/1.10.0-notes.rst b/doc/release/1.10.0-notes.rst index 50b1aa0b8..2318e522e 100644 --- a/doc/release/1.10.0-notes.rst +++ b/doc/release/1.10.0-notes.rst @@ -94,6 +94,16 @@ provided in the 'out' keyword argument, and it would be used as the first output for ufuncs with multiple outputs, is deprecated, and will result in a `DeprecationWarning` now and an error in the future. +byte-array indices now raises an IndexError +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Indexing an ndarray using a byte-string in Python 3 now raises an IndexError +instead of a ValueError. + +Masked arrays containing objects with arrays +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +For such (rare) masked arrays, getting a single masked item no longer returns a +corrupted masked array, but a fully masked version of the item. + New Features ============ @@ -252,8 +262,9 @@ object arrays that were generated on Python 2. MaskedArray support for more complicated base classes ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Built-in assumptions that the baseclass behaved like a plain array are being -removed. In particalur, setting and getting elements and ranges will respect -baseclass overrides of ``__setitem__`` and ``__getitem__``. +removed. In particular, setting and getting elements and ranges will respect +baseclass overrides of ``__setitem__`` and ``__getitem__``, and arithmetic +will respect overrides of ``__add__``, ``__sub__``, etc. Changes ======= diff --git a/numpy/build_utils/src/apple_sgemv_fix.c b/numpy/build_utils/src/apple_sgemv_fix.c index 558343477..ffdfb81f7 100644 --- a/numpy/build_utils/src/apple_sgemv_fix.c +++ b/numpy/build_utils/src/apple_sgemv_fix.c @@ -97,29 +97,27 @@ static void loadlib() veclib = dlopen(VECLIB_FILE, RTLD_LOCAL | RTLD_FIRST); if (!veclib) { veclib = NULL; - sprintf(errormsg,"Failed to open vecLib from location '%s'.", VECLIB_FILE); + snprintf(errormsg, sizeof(errormsg), + "Failed to open vecLib from location '%s'.", VECLIB_FILE); Py_FatalError(errormsg); /* calls abort() and dumps core */ } /* resolve Fortran SGEMV from Accelerate */ accelerate_sgemv = (fortran_sgemv_t*) dlsym(veclib, "sgemv_"); if (!accelerate_sgemv) { unloadlib(); - sprintf(errormsg,"Failed to resolve symbol 'sgemv_'."); - Py_FatalError(errormsg); + Py_FatalError("Failed to resolve symbol 'sgemv_'."); } /* resolve cblas_sgemv from Accelerate */ accelerate_cblas_sgemv = (cblas_sgemv_t*) dlsym(veclib, "cblas_sgemv"); if (!accelerate_cblas_sgemv) { unloadlib(); - sprintf(errormsg,"Failed to resolve symbol 'cblas_sgemv'."); - Py_FatalError(errormsg); + Py_FatalError("Failed to resolve symbol 'cblas_sgemv'."); } /* resolve cblas_sgemm from Accelerate */ accelerate_cblas_sgemm = (cblas_sgemm_t*) dlsym(veclib, "cblas_sgemm"); if (!accelerate_cblas_sgemm) { unloadlib(); - sprintf(errormsg,"Failed to resolve symbol 'cblas_sgemm'."); - Py_FatalError(errormsg); + Py_FatalError("Failed to resolve symbol 'cblas_sgemm'."); } } diff --git a/numpy/core/_internal.py b/numpy/core/_internal.py index e80c22dfe..a20bf10e4 100644 --- a/numpy/core/_internal.py +++ b/numpy/core/_internal.py @@ -10,7 +10,10 @@ import re import sys import warnings -from numpy.compat import asbytes, bytes +from numpy.compat import asbytes, bytes, basestring +from .multiarray import dtype, array, ndarray +import ctypes +from .numerictypes import object_ if (sys.byteorder == 'little'): _nbo = asbytes('<') @@ -18,7 +21,6 @@ else: _nbo = asbytes('>') def _makenames_list(adict, align): - from .multiarray import dtype allfields = [] fnames = list(adict.keys()) for fname in fnames: @@ -52,7 +54,6 @@ def _makenames_list(adict, align): # a dictionary without "names" and "formats" # fields is used as a data-type descriptor. def _usefields(adict, align): - from .multiarray import dtype try: names = adict[-1] except KeyError: @@ -130,7 +131,6 @@ def _array_descr(descriptor): # so don't remove the name here, or you'll # break backward compatibilty. def _reconstruct(subtype, shape, dtype): - from .multiarray import ndarray return ndarray.__new__(subtype, shape, dtype) @@ -194,12 +194,10 @@ def _commastring(astr): return result def _getintp_ctype(): - from .multiarray import dtype val = _getintp_ctype.cache if val is not None: return val char = dtype('p').char - import ctypes if (char == 'i'): val = ctypes.c_int elif char == 'l': @@ -224,7 +222,6 @@ class _missing_ctypes(object): class _ctypes(object): def __init__(self, array, ptr=None): try: - import ctypes self._ctypes = ctypes except ImportError: self._ctypes = _missing_ctypes() @@ -287,23 +284,55 @@ def _newnames(datatype, order): return tuple(list(order) + nameslist) raise ValueError("unsupported order value: %s" % (order,)) -# Given an array with fields and a sequence of field names -# construct a new array with just those fields copied over -def _index_fields(ary, fields): - from .multiarray import empty, dtype, array +def _index_fields(ary, names): + """ Given a structured array and a sequence of field names + construct new array with just those fields. + + Parameters + ---------- + ary : ndarray + Structured array being subscripted + names : string or list of strings + Either a single field name, or a list of field names + + Returns + ------- + sub_ary : ndarray + If `names` is a single field name, the return value is identical to + ary.getfield, a writeable view into `ary`. If `names` is a list of + field names the return value is a copy of `ary` containing only those + fields. This is planned to return a view in the future. + + Raises + ------ + ValueError + If `ary` does not contain a field given in `names`. + + """ dt = ary.dtype - names = [name for name in fields if name in dt.names] - formats = [dt.fields[name][0] for name in fields if name in dt.names] - offsets = [dt.fields[name][1] for name in fields if name in dt.names] + #use getfield to index a single field + if isinstance(names, basestring): + try: + return ary.getfield(dt.fields[names][0], dt.fields[names][1]) + except KeyError: + raise ValueError("no field of name %s" % names) + + for name in names: + if name not in dt.fields: + raise ValueError("no field of name %s" % name) - view_dtype = {'names':names, 'formats':formats, 'offsets':offsets, 'itemsize':dt.itemsize} - view = ary.view(dtype=view_dtype) + formats = [dt.fields[name][0] for name in names] + offsets = [dt.fields[name][1] for name in names] + + view_dtype = {'names': names, 'formats': formats, + 'offsets': offsets, 'itemsize': dt.itemsize} + + # return copy for now (future plan to return ary.view(dtype=view_dtype)) + copy_dtype = {'names': view_dtype['names'], + 'formats': view_dtype['formats']} + return array(ary.view(dtype=view_dtype), dtype=copy_dtype, copy=True) - # Return a copy for now until behavior is fully deprecated - # in favor of returning view - copy_dtype = {'names':view_dtype['names'], 'formats':view_dtype['formats']} - return array(view, dtype=copy_dtype, copy=True) def _get_all_field_offsets(dtype, base_offset=0): """ Returns the types and offsets of all fields in a (possibly structured) @@ -363,8 +392,6 @@ def _check_field_overlap(new_fields, old_fields): If the new fields are incompatible with the old fields """ - from .numerictypes import object_ - from .multiarray import dtype #first go byte by byte and check we do not access bytes not in old_fields new_bytes = set() @@ -527,8 +554,6 @@ _pep3118_standard_map = { _pep3118_standard_typechars = ''.join(_pep3118_standard_map.keys()) def _dtype_from_pep3118(spec, byteorder='@', is_subdtype=False): - from numpy.core.multiarray import dtype - fields = {} offset = 0 explicit_name = False @@ -694,8 +719,6 @@ def _dtype_from_pep3118(spec, byteorder='@', is_subdtype=False): def _add_trailing_padding(value, padding): """Inject the specified number of padding bytes at the end of a dtype""" - from numpy.core.multiarray import dtype - if value.fields is None: vfields = {'f0': (value, 0)} else: diff --git a/numpy/core/src/multiarray/arraytypes.c.src b/numpy/core/src/multiarray/arraytypes.c.src index c19d31a0d..307f9a0c0 100644 --- a/numpy/core/src/multiarray/arraytypes.c.src +++ b/numpy/core/src/multiarray/arraytypes.c.src @@ -726,7 +726,7 @@ VOID_setitem(PyObject *op, char *ip, PyArrayObject *ap) PyObject *tup; int savedflags; - res = -1; + res = 0; /* get the names from the fields dictionary*/ names = descr->names; n = PyTuple_GET_SIZE(names); @@ -2297,9 +2297,13 @@ STRING_nonzero (char *ip, PyArrayObject *ap) int len = PyArray_DESCR(ap)->elsize; int i; npy_bool nonz = NPY_FALSE; + npy_bool seen_null = NPY_FALSE; for (i = 0; i < len; i++) { - if (!Py_STRING_ISSPACE(*ip)) { + if (*ip == '\0') { + seen_null = NPY_TRUE; + } + else if (seen_null || !Py_STRING_ISSPACE(*ip)) { nonz = NPY_TRUE; break; } @@ -2320,6 +2324,7 @@ UNICODE_nonzero (npy_ucs4 *ip, PyArrayObject *ap) int len = PyArray_DESCR(ap)->elsize >> 2; int i; npy_bool nonz = NPY_FALSE; + npy_bool seen_null = NPY_FALSE; char *buffer = NULL; if ((!PyArray_ISNOTSWAPPED(ap)) || (!PyArray_ISALIGNED(ap))) { @@ -2335,7 +2340,10 @@ UNICODE_nonzero (npy_ucs4 *ip, PyArrayObject *ap) } for (i = 0; i < len; i++) { - if (!PyArray_UCS4_ISSPACE(*ip)) { + if (*ip == '\0') { + seen_null = NPY_TRUE; + } + else if (seen_null || !PyArray_UCS4_ISSPACE(*ip)) { nonz = NPY_TRUE; break; } @@ -3964,14 +3972,14 @@ static PyArray_ArrFuncs _Py@NAME@_ArrFuncs = { (PyArray_FillWithScalarFunc*)NULL, #if @sort@ { - (PyArray_SortFunc *)quicksort_@suff@, - (PyArray_SortFunc *)heapsort_@suff@, - (PyArray_SortFunc *)mergesort_@suff@ + quicksort_@suff@, + heapsort_@suff@, + mergesort_@suff@ }, { - (PyArray_ArgSortFunc *)aquicksort_@suff@, - (PyArray_ArgSortFunc *)aheapsort_@suff@, - (PyArray_ArgSortFunc *)amergesort_@suff@ + aquicksort_@suff@, + aheapsort_@suff@, + amergesort_@suff@ }, #else { @@ -4106,14 +4114,14 @@ static PyArray_ArrFuncs _Py@NAME@_ArrFuncs = { (PyArray_FillWithScalarFunc*)@from@_fillwithscalar, #if @sort@ { - (PyArray_SortFunc *)quicksort_@suff@, - (PyArray_SortFunc *)heapsort_@suff@, - (PyArray_SortFunc *)mergesort_@suff@ + quicksort_@suff@, + heapsort_@suff@, + mergesort_@suff@ }, { - (PyArray_ArgSortFunc *)aquicksort_@suff@, - (PyArray_ArgSortFunc *)aheapsort_@suff@, - (PyArray_ArgSortFunc *)amergesort_@suff@ + aquicksort_@suff@, + aheapsort_@suff@, + amergesort_@suff@ }, #else { diff --git a/numpy/core/src/multiarray/mapping.c b/numpy/core/src/multiarray/mapping.c index 604f5390f..de9a2d444 100644 --- a/numpy/core/src/multiarray/mapping.c +++ b/numpy/core/src/multiarray/mapping.c @@ -215,6 +215,7 @@ prepare_index(PyArrayObject *self, PyObject *index, } for (i = 0; i < n; i++) { PyObject *tmp_obj = PySequence_GetItem(index, i); + /* if getitem fails (unusual) treat this as a single index */ if (tmp_obj == NULL) { PyErr_Clear(); make_tuple = 0; @@ -772,8 +773,8 @@ prepare_index(PyArrayObject *self, PyObject *index, if (indices[i].value != PyArray_DIM(self, used_ndim)) { static PyObject *warning; - char *err_msg[174]; - sprintf(err_msg, + char err_msg[174]; + PyOS_snprintf(err_msg, sizeof(err_msg), "boolean index did not match indexed array along " "dimension %d; dimension is %" NPY_INTP_FMT " but corresponding boolean dimension is %" NPY_INTP_FMT, @@ -1361,6 +1362,52 @@ array_subscript_asarray(PyArrayObject *self, PyObject *op) return PyArray_EnsureAnyArray(array_subscript(self, op)); } +NPY_NO_EXPORT int +obj_is_string_or_stringlist(PyObject *op) +{ +#if defined(NPY_PY3K) + if (PyUnicode_Check(op)) { +#else + if (PyString_Check(op) || PyUnicode_Check(op)) { +#endif + return 1; + } + else if (PySequence_Check(op) && !PyTuple_Check(op)) { + int seqlen, i; + PyObject *obj = NULL; + seqlen = PySequence_Size(op); + + /* quit if we come across a 0-d array (seqlen==-1) or a 0-len array */ + if (seqlen == -1) { + PyErr_Clear(); + return 0; + } + if (seqlen == 0) { + return 0; + } + + for (i = 0; i < seqlen; i++) { + obj = PySequence_GetItem(op, i); + if (obj == NULL) { + /* only happens for strange sequence objects. Silently fail */ + PyErr_Clear(); + return 0; + } + +#if defined(NPY_PY3K) + if (!PyUnicode_Check(obj)) { +#else + if (!PyString_Check(obj) && !PyUnicode_Check(obj)) { +#endif + Py_DECREF(obj); + return 0; + } + Py_DECREF(obj); + } + return 1; + } + return 0; +} /* * General function for indexing a NumPy array with a Python object. @@ -1382,76 +1429,26 @@ array_subscript(PyArrayObject *self, PyObject *op) PyArrayMapIterObject * mit = NULL; - /* Check for multiple field access */ - if (PyDataType_HASFIELDS(PyArray_DESCR(self))) { - /* Check for single field access */ - /* - * TODO: Moving this code block into the HASFIELDS, means that - * string integers temporarily work as indices. - */ - if (PyString_Check(op) || PyUnicode_Check(op)) { - PyObject *temp, *obj; - - if (PyDataType_HASFIELDS(PyArray_DESCR(self))) { - obj = PyDict_GetItem(PyArray_DESCR(self)->fields, op); - if (obj != NULL) { - PyArray_Descr *descr; - int offset; - PyObject *title; - - if (PyArg_ParseTuple(obj, "Oi|O", &descr, &offset, &title)) { - Py_INCREF(descr); - return PyArray_GetField(self, descr, offset); - } - } - } + /* return fields if op is a string index */ + if (PyDataType_HASFIELDS(PyArray_DESCR(self)) && + obj_is_string_or_stringlist(op)) { + PyObject *obj; + static PyObject *indexfunc = NULL; + npy_cache_pyfunc("numpy.core._internal", "_index_fields", &indexfunc); + if (indexfunc == NULL) { + return NULL; + } - temp = op; - if (PyUnicode_Check(op)) { - temp = PyUnicode_AsUnicodeEscapeString(op); - } - PyErr_Format(PyExc_ValueError, - "field named %s not found", - PyBytes_AsString(temp)); - if (temp != op) { - Py_DECREF(temp); - } + obj = PyObject_CallFunction(indexfunc, "OO", self, op); + if (obj == NULL) { return NULL; } - else if (PySequence_Check(op) && !PyTuple_Check(op)) { - int seqlen, i; - PyObject *obj; - seqlen = PySequence_Size(op); - for (i = 0; i < seqlen; i++) { - obj = PySequence_GetItem(op, i); - if (!PyString_Check(obj) && !PyUnicode_Check(obj)) { - Py_DECREF(obj); - break; - } - Py_DECREF(obj); - } - /* - * Extract multiple fields if all elements in sequence - * are either string or unicode (i.e. no break occurred). - */ - fancy = ((seqlen > 0) && (i == seqlen)); - if (fancy) { - PyObject *_numpy_internal; - _numpy_internal = PyImport_ImportModule("numpy.core._internal"); - if (_numpy_internal == NULL) { - return NULL; - } - obj = PyObject_CallMethod(_numpy_internal, - "_index_fields", "OO", self, op); - Py_DECREF(_numpy_internal); - if (obj == NULL) { - return NULL; - } - PyArray_ENABLEFLAGS((PyArrayObject*)obj, NPY_ARRAY_WARN_ON_WRITE); - return obj; - } + /* warn if writing to a copy. copies will have no base */ + if (PyArray_BASE((PyArrayObject*)obj) == NULL) { + PyArray_ENABLEFLAGS((PyArrayObject*)obj, NPY_ARRAY_WARN_ON_WRITE); } + return obj; } /* Prepare the indices */ @@ -1783,35 +1780,39 @@ array_assign_subscript(PyArrayObject *self, PyObject *ind, PyObject *op) return -1; } - /* Single field access */ - if (PyDataType_HASFIELDS(PyArray_DESCR(self))) { - if (PyString_Check(ind) || PyUnicode_Check(ind)) { - PyObject *obj; - - obj = PyDict_GetItem(PyArray_DESCR(self)->fields, ind); - if (obj != NULL) { - PyArray_Descr *descr; - int offset; - PyObject *title; + /* field access */ + if (PyDataType_HASFIELDS(PyArray_DESCR(self)) && + obj_is_string_or_stringlist(ind)) { + PyObject *obj; + static PyObject *indexfunc = NULL; - if (PyArg_ParseTuple(obj, "Oi|O", &descr, &offset, &title)) { - Py_INCREF(descr); - return PyArray_SetField(self, descr, offset, op); - } - } #if defined(NPY_PY3K) - PyErr_Format(PyExc_ValueError, - "field named %S not found", - ind); + if (!PyUnicode_Check(ind)) { #else - PyErr_Format(PyExc_ValueError, - "field named %s not found", - PyString_AsString(ind)); + if (!PyString_Check(ind) && !PyUnicode_Check(ind)) { #endif + PyErr_SetString(PyExc_ValueError, + "multi-field assignment is not supported"); + } + + npy_cache_pyfunc("numpy.core._internal", "_index_fields", &indexfunc); + if (indexfunc == NULL) { + return -1; + } + + obj = PyObject_CallFunction(indexfunc, "OO", self, ind); + if (obj == NULL) { return -1; } - } + if (PyArray_CopyObject((PyArrayObject*)obj, op) < 0) { + Py_DECREF(obj); + return -1; + } + Py_DECREF(obj); + + return 0; + } /* Prepare the indices */ index_type = prepare_index(self, ind, indices, &index_num, diff --git a/numpy/core/src/multiarray/nditer_pywrap.c b/numpy/core/src/multiarray/nditer_pywrap.c index 77c45434f..25e48ba05 100644 --- a/numpy/core/src/multiarray/nditer_pywrap.c +++ b/numpy/core/src/multiarray/nditer_pywrap.c @@ -2227,6 +2227,14 @@ npyiter_seq_ass_slice(NewNpyArrayIterObject *self, Py_ssize_t ilow, return 0; } +/* Py3 changes PySlice_GetIndices' first argument's type to PyObject* */ +#ifdef NPY_PY3K +# define slice_getindices PySlice_GetIndices +#else +# define slice_getindices(op, nop, start, end, step) \ + PySlice_GetIndices((PySliceObject *)op, nop, start, end, step) +#endif + static PyObject * npyiter_subscript(NewNpyArrayIterObject *self, PyObject *op) { @@ -2253,8 +2261,7 @@ npyiter_subscript(NewNpyArrayIterObject *self, PyObject *op) } else if (PySlice_Check(op)) { Py_ssize_t istart = 0, iend = 0, istep = 0; - if (PySlice_GetIndices((PySliceObject *)op, - NpyIter_GetNOp(self->iter), + if (slice_getindices(op, NpyIter_GetNOp(self->iter), &istart, &iend, &istep) < 0) { return NULL; } @@ -2303,8 +2310,7 @@ npyiter_ass_subscript(NewNpyArrayIterObject *self, PyObject *op, } else if (PySlice_Check(op)) { Py_ssize_t istart = 0, iend = 0, istep = 0; - if (PySlice_GetIndices((PySliceObject *)op, - NpyIter_GetNOp(self->iter), + if (slice_getindices(op, NpyIter_GetNOp(self->iter), &istart, &iend, &istep) < 0) { return -1; } diff --git a/numpy/core/src/npysort/heapsort.c.src b/numpy/core/src/npysort/heapsort.c.src index 88f7978cc..c2e3b63cb 100644 --- a/numpy/core/src/npysort/heapsort.c.src +++ b/numpy/core/src/npysort/heapsort.c.src @@ -61,13 +61,13 @@ */ int -heapsort_@suff@(@type@ *start, npy_intp n, void *NOT_USED) +heapsort_@suff@(void *start, npy_intp n, void *NOT_USED) { @type@ tmp, *a; npy_intp i,j,l; /* The array needs to be offset by one for heapsort indexing */ - a = start - 1; + a = (@type@ *)start - 1; for (l = n>>1; l > 0; --l) { tmp = a[l]; @@ -112,8 +112,9 @@ heapsort_@suff@(@type@ *start, npy_intp n, void *NOT_USED) int -aheapsort_@suff@(@type@ *v, npy_intp *tosort, npy_intp n, void *NOT_USED) +aheapsort_@suff@(void *vv, npy_intp *tosort, npy_intp n, void *NOT_USED) { + @type@ *v = vv; npy_intp *a, i,j,l, tmp; /* The arrays need to be offset by one for heapsort indexing */ a = tosort - 1; @@ -177,11 +178,12 @@ aheapsort_@suff@(@type@ *v, npy_intp *tosort, npy_intp n, void *NOT_USED) */ int -heapsort_@suff@(@type@ *start, npy_intp n, PyArrayObject *arr) +heapsort_@suff@(void *start, npy_intp n, void *varr) { + PyArrayObject *arr = varr; size_t len = PyArray_ITEMSIZE(arr)/sizeof(@type@); @type@ *tmp = malloc(PyArray_ITEMSIZE(arr)); - @type@ *a = start - len; + @type@ *a = (@type@ *)start - len; npy_intp i, j, l; if (tmp == NULL) { @@ -230,8 +232,10 @@ heapsort_@suff@(@type@ *start, npy_intp n, PyArrayObject *arr) int -aheapsort_@suff@(@type@ *v, npy_intp *tosort, npy_intp n, PyArrayObject *arr) +aheapsort_@suff@(void *vv, npy_intp *tosort, npy_intp n, void *varr) { + @type@ *v = vv; + PyArrayObject *arr = varr; size_t len = PyArray_ITEMSIZE(arr)/sizeof(@type@); npy_intp *a, i,j,l, tmp; @@ -288,12 +292,13 @@ aheapsort_@suff@(@type@ *v, npy_intp *tosort, npy_intp n, PyArrayObject *arr) int -npy_heapsort(char *start, npy_intp num, PyArrayObject *arr) +npy_heapsort(void *start, npy_intp num, void *varr) { + PyArrayObject *arr = varr; npy_intp elsize = PyArray_ITEMSIZE(arr); PyArray_CompareFunc *cmp = PyArray_DESCR(arr)->f->compare; char *tmp = malloc(elsize); - char *a = start - elsize; + char *a = (char *)start - elsize; npy_intp i, j, l; if (tmp == NULL) { @@ -344,8 +349,10 @@ npy_heapsort(char *start, npy_intp num, PyArrayObject *arr) int -npy_aheapsort(char *v, npy_intp *tosort, npy_intp n, PyArrayObject *arr) +npy_aheapsort(void *vv, npy_intp *tosort, npy_intp n, void *varr) { + char *v = vv; + PyArrayObject *arr = varr; npy_intp elsize = PyArray_ITEMSIZE(arr); PyArray_CompareFunc *cmp = PyArray_DESCR(arr)->f->compare; npy_intp *a, i, j, l, tmp; diff --git a/numpy/core/src/npysort/mergesort.c.src b/numpy/core/src/npysort/mergesort.c.src index 406be66d0..fc82e2135 100644 --- a/numpy/core/src/npysort/mergesort.c.src +++ b/numpy/core/src/npysort/mergesort.c.src @@ -104,7 +104,7 @@ mergesort0_@suff@(@type@ *pl, @type@ *pr, @type@ *pw) int -mergesort_@suff@(@type@ *start, npy_intp num, void *NOT_USED) +mergesort_@suff@(void *start, npy_intp num, void *NOT_USED) { @type@ *pl, *pr, *pw; @@ -167,7 +167,7 @@ amergesort0_@suff@(npy_intp *pl, npy_intp *pr, @type@ *v, npy_intp *pw) int -amergesort_@suff@(@type@ *v, npy_intp *tosort, npy_intp num, void *NOT_USED) +amergesort_@suff@(void *v, npy_intp *tosort, npy_intp num, void *NOT_USED) { npy_intp *pl, *pr, *pw; @@ -246,8 +246,9 @@ mergesort0_@suff@(@type@ *pl, @type@ *pr, @type@ *pw, @type@ *vp, size_t len) int -mergesort_@suff@(@type@ *start, npy_intp num, PyArrayObject *arr) +mergesort_@suff@(void *start, npy_intp num, void *varr) { + PyArrayObject *arr = varr; size_t elsize = PyArray_ITEMSIZE(arr); size_t len = elsize / sizeof(@type@); @type@ *pl, *pr, *pw, *vp; @@ -321,8 +322,9 @@ amergesort0_@suff@(npy_intp *pl, npy_intp *pr, @type@ *v, npy_intp *pw, size_t l int -amergesort_@suff@(@type@ *v, npy_intp *tosort, npy_intp num, PyArrayObject *arr) +amergesort_@suff@(void *v, npy_intp *tosort, npy_intp num, void *varr) { + PyArrayObject *arr = varr; size_t elsize = PyArray_ITEMSIZE(arr); size_t len = elsize / sizeof(@type@); npy_intp *pl, *pr, *pw; @@ -396,8 +398,9 @@ npy_mergesort0(char *pl, char *pr, char *pw, char *vp, npy_intp elsize, int -npy_mergesort(char *start, npy_intp num, PyArrayObject *arr) +npy_mergesort(void *start, npy_intp num, void *varr) { + PyArrayObject *arr = varr; npy_intp elsize = PyArray_ITEMSIZE(arr); PyArray_CompareFunc *cmp = PyArray_DESCR(arr)->f->compare; char *pl = start; @@ -465,8 +468,9 @@ npy_amergesort0(npy_intp *pl, npy_intp *pr, char *v, npy_intp *pw, int -npy_amergesort(char *v, npy_intp *tosort, npy_intp num, PyArrayObject *arr) +npy_amergesort(void *v, npy_intp *tosort, npy_intp num, void *varr) { + PyArrayObject *arr = varr; npy_intp elsize = PyArray_ITEMSIZE(arr); PyArray_CompareFunc *cmp = PyArray_DESCR(arr)->f->compare; npy_intp *pl, *pr, *pw; diff --git a/numpy/core/src/npysort/quicksort.c.src b/numpy/core/src/npysort/quicksort.c.src index 5334aca76..91b5e67f5 100644 --- a/numpy/core/src/npysort/quicksort.c.src +++ b/numpy/core/src/npysort/quicksort.c.src @@ -61,11 +61,11 @@ */ int -quicksort_@suff@(@type@ *start, npy_intp num, void *NOT_USED) +quicksort_@suff@(void *start, npy_intp num, void *NOT_USED) { @type@ vp; @type@ *pl = start; - @type@ *pr = start + num - 1; + @type@ *pr = pl + num - 1; @type@ *stack[PYA_QS_STACK]; @type@ **sptr = stack; @type@ *pm, *pi, *pj, *pk; @@ -126,8 +126,9 @@ quicksort_@suff@(@type@ *start, npy_intp num, void *NOT_USED) int -aquicksort_@suff@(@type@ *v, npy_intp* tosort, npy_intp num, void *NOT_USED) +aquicksort_@suff@(void *vv, npy_intp* tosort, npy_intp num, void *NOT_USED) { + @type@ *v = vv; @type@ vp; npy_intp *pl = tosort; npy_intp *pr = tosort + num - 1; @@ -208,12 +209,13 @@ aquicksort_@suff@(@type@ *v, npy_intp* tosort, npy_intp num, void *NOT_USED) */ int -quicksort_@suff@(@type@ *start, npy_intp num, PyArrayObject *arr) +quicksort_@suff@(void *start, npy_intp num, void *varr) { + PyArrayObject *arr = varr; const size_t len = PyArray_ITEMSIZE(arr)/sizeof(@type@); @type@ *vp = malloc(PyArray_ITEMSIZE(arr)); @type@ *pl = start; - @type@ *pr = start + (num - 1)*len; + @type@ *pr = pl + (num - 1)*len; @type@ *stack[PYA_QS_STACK], **sptr = stack, *pm, *pi, *pj, *pk; if (vp == NULL) { @@ -279,8 +281,10 @@ quicksort_@suff@(@type@ *start, npy_intp num, PyArrayObject *arr) int -aquicksort_@suff@(@type@ *v, npy_intp* tosort, npy_intp num, PyArrayObject *arr) +aquicksort_@suff@(void *vv, npy_intp* tosort, npy_intp num, void *varr) { + @type@ *v = vv; + PyArrayObject *arr = varr; size_t len = PyArray_ITEMSIZE(arr)/sizeof(@type@); @type@ *vp; npy_intp *pl = tosort; @@ -355,13 +359,14 @@ aquicksort_@suff@(@type@ *v, npy_intp* tosort, npy_intp num, PyArrayObject *arr) int -npy_quicksort(char *start, npy_intp num, PyArrayObject *arr) +npy_quicksort(void *start, npy_intp num, void *varr) { + PyArrayObject *arr = varr; npy_intp elsize = PyArray_ITEMSIZE(arr); PyArray_CompareFunc *cmp = PyArray_DESCR(arr)->f->compare; char *vp = malloc(elsize); char *pl = start; - char *pr = start + (num - 1)*elsize; + char *pr = pl + (num - 1)*elsize; char *stack[PYA_QS_STACK]; char **sptr = stack; char *pm, *pi, *pj, *pk; @@ -439,8 +444,10 @@ npy_quicksort(char *start, npy_intp num, PyArrayObject *arr) int -npy_aquicksort(char *v, npy_intp* tosort, npy_intp num, PyArrayObject *arr) +npy_aquicksort(void *vv, npy_intp* tosort, npy_intp num, void *varr) { + char *v = vv; + PyArrayObject *arr = varr; npy_intp elsize = PyArray_ITEMSIZE(arr); PyArray_CompareFunc *cmp = PyArray_DESCR(arr)->f->compare; char *vp; diff --git a/numpy/core/src/private/npy_sort.h b/numpy/core/src/private/npy_sort.h index 85630b2df..511d71b01 100644 --- a/numpy/core/src/private/npy_sort.h +++ b/numpy/core/src/private/npy_sort.h @@ -10,187 +10,187 @@ #define NPY_ECOMP 2 -int quicksort_bool(npy_bool *vec, npy_intp cnt, void *null); -int heapsort_bool(npy_bool *vec, npy_intp cnt, void *null); -int mergesort_bool(npy_bool *vec, npy_intp cnt, void *null); -int aquicksort_bool(npy_bool *vec, npy_intp *ind, npy_intp cnt, void *null); -int aheapsort_bool(npy_bool *vec, npy_intp *ind, npy_intp cnt, void *null); -int amergesort_bool(npy_bool *vec, npy_intp *ind, npy_intp cnt, void *null); +int quicksort_bool(void *vec, npy_intp cnt, void *null); +int heapsort_bool(void *vec, npy_intp cnt, void *null); +int mergesort_bool(void *vec, npy_intp cnt, void *null); +int aquicksort_bool(void *vec, npy_intp *ind, npy_intp cnt, void *null); +int aheapsort_bool(void *vec, npy_intp *ind, npy_intp cnt, void *null); +int amergesort_bool(void *vec, npy_intp *ind, npy_intp cnt, void *null); -int quicksort_byte(npy_byte *vec, npy_intp cnt, void *null); -int heapsort_byte(npy_byte *vec, npy_intp cnt, void *null); -int mergesort_byte(npy_byte *vec, npy_intp cnt, void *null); -int aquicksort_byte(npy_byte *vec, npy_intp *ind, npy_intp cnt, void *null); -int aheapsort_byte(npy_byte *vec, npy_intp *ind, npy_intp cnt, void *null); -int amergesort_byte(npy_byte *vec, npy_intp *ind, npy_intp cnt, void *null); - - -int quicksort_ubyte(npy_ubyte *vec, npy_intp cnt, void *null); -int heapsort_ubyte(npy_ubyte *vec, npy_intp cnt, void *null); -int mergesort_ubyte(npy_ubyte *vec, npy_intp cnt, void *null); -int aquicksort_ubyte(npy_ubyte *vec, npy_intp *ind, npy_intp cnt, void *null); -int aheapsort_ubyte(npy_ubyte *vec, npy_intp *ind, npy_intp cnt, void *null); -int amergesort_ubyte(npy_ubyte *vec, npy_intp *ind, npy_intp cnt, void *null); +int quicksort_byte(void *vec, npy_intp cnt, void *null); +int heapsort_byte(void *vec, npy_intp cnt, void *null); +int mergesort_byte(void *vec, npy_intp cnt, void *null); +int aquicksort_byte(void *vec, npy_intp *ind, npy_intp cnt, void *null); +int aheapsort_byte(void *vec, npy_intp *ind, npy_intp cnt, void *null); +int amergesort_byte(void *vec, npy_intp *ind, npy_intp cnt, void *null); + + +int quicksort_ubyte(void *vec, npy_intp cnt, void *null); +int heapsort_ubyte(void *vec, npy_intp cnt, void *null); +int mergesort_ubyte(void *vec, npy_intp cnt, void *null); +int aquicksort_ubyte(void *vec, npy_intp *ind, npy_intp cnt, void *null); +int aheapsort_ubyte(void *vec, npy_intp *ind, npy_intp cnt, void *null); +int amergesort_ubyte(void *vec, npy_intp *ind, npy_intp cnt, void *null); -int quicksort_short(npy_short *vec, npy_intp cnt, void *null); -int heapsort_short(npy_short *vec, npy_intp cnt, void *null); -int mergesort_short(npy_short *vec, npy_intp cnt, void *null); -int aquicksort_short(npy_short *vec, npy_intp *ind, npy_intp cnt, void *null); -int aheapsort_short(npy_short *vec, npy_intp *ind, npy_intp cnt, void *null); -int amergesort_short(npy_short *vec, npy_intp *ind, npy_intp cnt, void *null); - - -int quicksort_ushort(npy_ushort *vec, npy_intp cnt, void *null); -int heapsort_ushort(npy_ushort *vec, npy_intp cnt, void *null); -int mergesort_ushort(npy_ushort *vec, npy_intp cnt, void *null); -int aquicksort_ushort(npy_ushort *vec, npy_intp *ind, npy_intp cnt, void *null); -int aheapsort_ushort(npy_ushort *vec, npy_intp *ind, npy_intp cnt, void *null); -int amergesort_ushort(npy_ushort *vec, npy_intp *ind, npy_intp cnt, void *null); +int quicksort_short(void *vec, npy_intp cnt, void *null); +int heapsort_short(void *vec, npy_intp cnt, void *null); +int mergesort_short(void *vec, npy_intp cnt, void *null); +int aquicksort_short(void *vec, npy_intp *ind, npy_intp cnt, void *null); +int aheapsort_short(void *vec, npy_intp *ind, npy_intp cnt, void *null); +int amergesort_short(void *vec, npy_intp *ind, npy_intp cnt, void *null); + + +int quicksort_ushort(void *vec, npy_intp cnt, void *null); +int heapsort_ushort(void *vec, npy_intp cnt, void *null); +int mergesort_ushort(void *vec, npy_intp cnt, void *null); +int aquicksort_ushort(void *vec, npy_intp *ind, npy_intp cnt, void *null); +int aheapsort_ushort(void *vec, npy_intp *ind, npy_intp cnt, void *null); +int amergesort_ushort(void *vec, npy_intp *ind, npy_intp cnt, void *null); -int quicksort_int(npy_int *vec, npy_intp cnt, void *null); -int heapsort_int(npy_int *vec, npy_intp cnt, void *null); -int mergesort_int(npy_int *vec, npy_intp cnt, void *null); -int aquicksort_int(npy_int *vec, npy_intp *ind, npy_intp cnt, void *null); -int aheapsort_int(npy_int *vec, npy_intp *ind, npy_intp cnt, void *null); -int amergesort_int(npy_int *vec, npy_intp *ind, npy_intp cnt, void *null); - - -int quicksort_uint(npy_uint *vec, npy_intp cnt, void *null); -int heapsort_uint(npy_uint *vec, npy_intp cnt, void *null); -int mergesort_uint(npy_uint *vec, npy_intp cnt, void *null); -int aquicksort_uint(npy_uint *vec, npy_intp *ind, npy_intp cnt, void *null); -int aheapsort_uint(npy_uint *vec, npy_intp *ind, npy_intp cnt, void *null); -int amergesort_uint(npy_uint *vec, npy_intp *ind, npy_intp cnt, void *null); +int quicksort_int(void *vec, npy_intp cnt, void *null); +int heapsort_int(void *vec, npy_intp cnt, void *null); +int mergesort_int(void *vec, npy_intp cnt, void *null); +int aquicksort_int(void *vec, npy_intp *ind, npy_intp cnt, void *null); +int aheapsort_int(void *vec, npy_intp *ind, npy_intp cnt, void *null); +int amergesort_int(void *vec, npy_intp *ind, npy_intp cnt, void *null); + + +int quicksort_uint(void *vec, npy_intp cnt, void *null); +int heapsort_uint(void *vec, npy_intp cnt, void *null); +int mergesort_uint(void *vec, npy_intp cnt, void *null); +int aquicksort_uint(void *vec, npy_intp *ind, npy_intp cnt, void *null); +int aheapsort_uint(void *vec, npy_intp *ind, npy_intp cnt, void *null); +int amergesort_uint(void *vec, npy_intp *ind, npy_intp cnt, void *null); -int quicksort_long(npy_long *vec, npy_intp cnt, void *null); -int heapsort_long(npy_long *vec, npy_intp cnt, void *null); -int mergesort_long(npy_long *vec, npy_intp cnt, void *null); -int aquicksort_long(npy_long *vec, npy_intp *ind, npy_intp cnt, void *null); -int aheapsort_long(npy_long *vec, npy_intp *ind, npy_intp cnt, void *null); -int amergesort_long(npy_long *vec, npy_intp *ind, npy_intp cnt, void *null); - - -int quicksort_ulong(npy_ulong *vec, npy_intp cnt, void *null); -int heapsort_ulong(npy_ulong *vec, npy_intp cnt, void *null); -int mergesort_ulong(npy_ulong *vec, npy_intp cnt, void *null); -int aquicksort_ulong(npy_ulong *vec, npy_intp *ind, npy_intp cnt, void *null); -int aheapsort_ulong(npy_ulong *vec, npy_intp *ind, npy_intp cnt, void *null); -int amergesort_ulong(npy_ulong *vec, npy_intp *ind, npy_intp cnt, void *null); +int quicksort_long(void *vec, npy_intp cnt, void *null); +int heapsort_long(void *vec, npy_intp cnt, void *null); +int mergesort_long(void *vec, npy_intp cnt, void *null); +int aquicksort_long(void *vec, npy_intp *ind, npy_intp cnt, void *null); +int aheapsort_long(void *vec, npy_intp *ind, npy_intp cnt, void *null); +int amergesort_long(void *vec, npy_intp *ind, npy_intp cnt, void *null); + + +int quicksort_ulong(void *vec, npy_intp cnt, void *null); +int heapsort_ulong(void *vec, npy_intp cnt, void *null); +int mergesort_ulong(void *vec, npy_intp cnt, void *null); +int aquicksort_ulong(void *vec, npy_intp *ind, npy_intp cnt, void *null); +int aheapsort_ulong(void *vec, npy_intp *ind, npy_intp cnt, void *null); +int amergesort_ulong(void *vec, npy_intp *ind, npy_intp cnt, void *null); -int quicksort_longlong(npy_longlong *vec, npy_intp cnt, void *null); -int heapsort_longlong(npy_longlong *vec, npy_intp cnt, void *null); -int mergesort_longlong(npy_longlong *vec, npy_intp cnt, void *null); -int aquicksort_longlong(npy_longlong *vec, npy_intp *ind, npy_intp cnt, void *null); -int aheapsort_longlong(npy_longlong *vec, npy_intp *ind, npy_intp cnt, void *null); -int amergesort_longlong(npy_longlong *vec, npy_intp *ind, npy_intp cnt, void *null); - - -int quicksort_ulonglong(npy_ulonglong *vec, npy_intp cnt, void *null); -int heapsort_ulonglong(npy_ulonglong *vec, npy_intp cnt, void *null); -int mergesort_ulonglong(npy_ulonglong *vec, npy_intp cnt, void *null); -int aquicksort_ulonglong(npy_ulonglong *vec, npy_intp *ind, npy_intp cnt, void *null); -int aheapsort_ulonglong(npy_ulonglong *vec, npy_intp *ind, npy_intp cnt, void *null); -int amergesort_ulonglong(npy_ulonglong *vec, npy_intp *ind, npy_intp cnt, void *null); - - -int quicksort_half(npy_ushort *vec, npy_intp cnt, void *null); -int heapsort_half(npy_ushort *vec, npy_intp cnt, void *null); -int mergesort_half(npy_ushort *vec, npy_intp cnt, void *null); -int aquicksort_half(npy_ushort *vec, npy_intp *ind, npy_intp cnt, void *null); -int aheapsort_half(npy_ushort *vec, npy_intp *ind, npy_intp cnt, void *null); -int amergesort_half(npy_ushort *vec, npy_intp *ind, npy_intp cnt, void *null); - - -int quicksort_float(npy_float *vec, npy_intp cnt, void *null); -int heapsort_float(npy_float *vec, npy_intp cnt, void *null); -int mergesort_float(npy_float *vec, npy_intp cnt, void *null); -int aquicksort_float(npy_float *vec, npy_intp *ind, npy_intp cnt, void *null); -int aheapsort_float(npy_float *vec, npy_intp *ind, npy_intp cnt, void *null); -int amergesort_float(npy_float *vec, npy_intp *ind, npy_intp cnt, void *null); - - -int quicksort_double(npy_double *vec, npy_intp cnt, void *null); -int heapsort_double(npy_double *vec, npy_intp cnt, void *null); -int mergesort_double(npy_double *vec, npy_intp cnt, void *null); -int aquicksort_double(npy_double *vec, npy_intp *ind, npy_intp cnt, void *null); -int aheapsort_double(npy_double *vec, npy_intp *ind, npy_intp cnt, void *null); -int amergesort_double(npy_double *vec, npy_intp *ind, npy_intp cnt, void *null); +int quicksort_longlong(void *vec, npy_intp cnt, void *null); +int heapsort_longlong(void *vec, npy_intp cnt, void *null); +int mergesort_longlong(void *vec, npy_intp cnt, void *null); +int aquicksort_longlong(void *vec, npy_intp *ind, npy_intp cnt, void *null); +int aheapsort_longlong(void *vec, npy_intp *ind, npy_intp cnt, void *null); +int amergesort_longlong(void *vec, npy_intp *ind, npy_intp cnt, void *null); + + +int quicksort_ulonglong(void *vec, npy_intp cnt, void *null); +int heapsort_ulonglong(void *vec, npy_intp cnt, void *null); +int mergesort_ulonglong(void *vec, npy_intp cnt, void *null); +int aquicksort_ulonglong(void *vec, npy_intp *ind, npy_intp cnt, void *null); +int aheapsort_ulonglong(void *vec, npy_intp *ind, npy_intp cnt, void *null); +int amergesort_ulonglong(void *vec, npy_intp *ind, npy_intp cnt, void *null); + + +int quicksort_half(void *vec, npy_intp cnt, void *null); +int heapsort_half(void *vec, npy_intp cnt, void *null); +int mergesort_half(void *vec, npy_intp cnt, void *null); +int aquicksort_half(void *vec, npy_intp *ind, npy_intp cnt, void *null); +int aheapsort_half(void *vec, npy_intp *ind, npy_intp cnt, void *null); +int amergesort_half(void *vec, npy_intp *ind, npy_intp cnt, void *null); + + +int quicksort_float(void *vec, npy_intp cnt, void *null); +int heapsort_float(void *vec, npy_intp cnt, void *null); +int mergesort_float(void *vec, npy_intp cnt, void *null); +int aquicksort_float(void *vec, npy_intp *ind, npy_intp cnt, void *null); +int aheapsort_float(void *vec, npy_intp *ind, npy_intp cnt, void *null); +int amergesort_float(void *vec, npy_intp *ind, npy_intp cnt, void *null); + + +int quicksort_double(void *vec, npy_intp cnt, void *null); +int heapsort_double(void *vec, npy_intp cnt, void *null); +int mergesort_double(void *vec, npy_intp cnt, void *null); +int aquicksort_double(void *vec, npy_intp *ind, npy_intp cnt, void *null); +int aheapsort_double(void *vec, npy_intp *ind, npy_intp cnt, void *null); +int amergesort_double(void *vec, npy_intp *ind, npy_intp cnt, void *null); -int quicksort_longdouble(npy_longdouble *vec, npy_intp cnt, void *null); -int heapsort_longdouble(npy_longdouble *vec, npy_intp cnt, void *null); -int mergesort_longdouble(npy_longdouble *vec, npy_intp cnt, void *null); -int aquicksort_longdouble(npy_longdouble *vec, npy_intp *ind, npy_intp cnt, void *null); -int aheapsort_longdouble(npy_longdouble *vec, npy_intp *ind, npy_intp cnt, void *null); -int amergesort_longdouble(npy_longdouble *vec, npy_intp *ind, npy_intp cnt, void *null); - - -int quicksort_cfloat(npy_cfloat *vec, npy_intp cnt, void *null); -int heapsort_cfloat(npy_cfloat *vec, npy_intp cnt, void *null); -int mergesort_cfloat(npy_cfloat *vec, npy_intp cnt, void *null); -int aquicksort_cfloat(npy_cfloat *vec, npy_intp *ind, npy_intp cnt, void *null); -int aheapsort_cfloat(npy_cfloat *vec, npy_intp *ind, npy_intp cnt, void *null); -int amergesort_cfloat(npy_cfloat *vec, npy_intp *ind, npy_intp cnt, void *null); +int quicksort_longdouble(void *vec, npy_intp cnt, void *null); +int heapsort_longdouble(void *vec, npy_intp cnt, void *null); +int mergesort_longdouble(void *vec, npy_intp cnt, void *null); +int aquicksort_longdouble(void *vec, npy_intp *ind, npy_intp cnt, void *null); +int aheapsort_longdouble(void *vec, npy_intp *ind, npy_intp cnt, void *null); +int amergesort_longdouble(void *vec, npy_intp *ind, npy_intp cnt, void *null); + + +int quicksort_cfloat(void *vec, npy_intp cnt, void *null); +int heapsort_cfloat(void *vec, npy_intp cnt, void *null); +int mergesort_cfloat(void *vec, npy_intp cnt, void *null); +int aquicksort_cfloat(void *vec, npy_intp *ind, npy_intp cnt, void *null); +int aheapsort_cfloat(void *vec, npy_intp *ind, npy_intp cnt, void *null); +int amergesort_cfloat(void *vec, npy_intp *ind, npy_intp cnt, void *null); -int quicksort_cdouble(npy_cdouble *vec, npy_intp cnt, void *null); -int heapsort_cdouble(npy_cdouble *vec, npy_intp cnt, void *null); -int mergesort_cdouble(npy_cdouble *vec, npy_intp cnt, void *null); -int aquicksort_cdouble(npy_cdouble *vec, npy_intp *ind, npy_intp cnt, void *null); -int aheapsort_cdouble(npy_cdouble *vec, npy_intp *ind, npy_intp cnt, void *null); -int amergesort_cdouble(npy_cdouble *vec, npy_intp *ind, npy_intp cnt, void *null); - - -int quicksort_clongdouble(npy_clongdouble *vec, npy_intp cnt, void *null); -int heapsort_clongdouble(npy_clongdouble *vec, npy_intp cnt, void *null); -int mergesort_clongdouble(npy_clongdouble *vec, npy_intp cnt, void *null); -int aquicksort_clongdouble(npy_clongdouble *vec, npy_intp *ind, npy_intp cnt, void *null); -int aheapsort_clongdouble(npy_clongdouble *vec, npy_intp *ind, npy_intp cnt, void *null); -int amergesort_clongdouble(npy_clongdouble *vec, npy_intp *ind, npy_intp cnt, void *null); +int quicksort_cdouble(void *vec, npy_intp cnt, void *null); +int heapsort_cdouble(void *vec, npy_intp cnt, void *null); +int mergesort_cdouble(void *vec, npy_intp cnt, void *null); +int aquicksort_cdouble(void *vec, npy_intp *ind, npy_intp cnt, void *null); +int aheapsort_cdouble(void *vec, npy_intp *ind, npy_intp cnt, void *null); +int amergesort_cdouble(void *vec, npy_intp *ind, npy_intp cnt, void *null); + + +int quicksort_clongdouble(void *vec, npy_intp cnt, void *null); +int heapsort_clongdouble(void *vec, npy_intp cnt, void *null); +int mergesort_clongdouble(void *vec, npy_intp cnt, void *null); +int aquicksort_clongdouble(void *vec, npy_intp *ind, npy_intp cnt, void *null); +int aheapsort_clongdouble(void *vec, npy_intp *ind, npy_intp cnt, void *null); +int amergesort_clongdouble(void *vec, npy_intp *ind, npy_intp cnt, void *null); -int quicksort_string(npy_char *vec, npy_intp cnt, PyArrayObject *arr); -int heapsort_string(npy_char *vec, npy_intp cnt, PyArrayObject *arr); -int mergesort_string(npy_char *vec, npy_intp cnt, PyArrayObject *arr); -int aquicksort_string(npy_char *vec, npy_intp *ind, npy_intp cnt, PyArrayObject *arr); -int aheapsort_string(npy_char *vec, npy_intp *ind, npy_intp cnt, PyArrayObject *arr); -int amergesort_string(npy_char *vec, npy_intp *ind, npy_intp cnt, PyArrayObject *arr); - - -int quicksort_unicode(npy_ucs4 *vec, npy_intp cnt, PyArrayObject *arr); -int heapsort_unicode(npy_ucs4 *vec, npy_intp cnt, PyArrayObject *arr); -int mergesort_unicode(npy_ucs4 *vec, npy_intp cnt, PyArrayObject *arr); -int aquicksort_unicode(npy_ucs4 *vec, npy_intp *ind, npy_intp cnt, PyArrayObject *arr); -int aheapsort_unicode(npy_ucs4 *vec, npy_intp *ind, npy_intp cnt, PyArrayObject *arr); -int amergesort_unicode(npy_ucs4 *vec, npy_intp *ind, npy_intp cnt, PyArrayObject *arr); +int quicksort_string(void *vec, npy_intp cnt, void *arr); +int heapsort_string(void *vec, npy_intp cnt, void *arr); +int mergesort_string(void *vec, npy_intp cnt, void *arr); +int aquicksort_string(void *vec, npy_intp *ind, npy_intp cnt, void *arr); +int aheapsort_string(void *vec, npy_intp *ind, npy_intp cnt, void *arr); +int amergesort_string(void *vec, npy_intp *ind, npy_intp cnt, void *arr); + + +int quicksort_unicode(void *vec, npy_intp cnt, void *arr); +int heapsort_unicode(void *vec, npy_intp cnt, void *arr); +int mergesort_unicode(void *vec, npy_intp cnt, void *arr); +int aquicksort_unicode(void *vec, npy_intp *ind, npy_intp cnt, void *arr); +int aheapsort_unicode(void *vec, npy_intp *ind, npy_intp cnt, void *arr); +int amergesort_unicode(void *vec, npy_intp *ind, npy_intp cnt, void *arr); -int quicksort_datetime(npy_datetime *vec, npy_intp cnt, void *null); -int heapsort_datetime(npy_datetime *vec, npy_intp cnt, void *null); -int mergesort_datetime(npy_datetime *vec, npy_intp cnt, void *null); -int aquicksort_datetime(npy_datetime *vec, npy_intp *ind, npy_intp cnt, void *null); -int aheapsort_datetime(npy_datetime *vec, npy_intp *ind, npy_intp cnt, void *null); -int amergesort_datetime(npy_datetime *vec, npy_intp *ind, npy_intp cnt, void *null); - - -int quicksort_timedelta(npy_timedelta *vec, npy_intp cnt, void *null); -int heapsort_timedelta(npy_timedelta *vec, npy_intp cnt, void *null); -int mergesort_timedelta(npy_timedelta *vec, npy_intp cnt, void *null); -int aquicksort_timedelta(npy_timedelta *vec, npy_intp *ind, npy_intp cnt, void *null); -int aheapsort_timedelta(npy_timedelta *vec, npy_intp *ind, npy_intp cnt, void *null); -int amergesort_timedelta(npy_timedelta *vec, npy_intp *ind, npy_intp cnt, void *null); +int quicksort_datetime(void *vec, npy_intp cnt, void *null); +int heapsort_datetime(void *vec, npy_intp cnt, void *null); +int mergesort_datetime(void *vec, npy_intp cnt, void *null); +int aquicksort_datetime(void *vec, npy_intp *ind, npy_intp cnt, void *null); +int aheapsort_datetime(void *vec, npy_intp *ind, npy_intp cnt, void *null); +int amergesort_datetime(void *vec, npy_intp *ind, npy_intp cnt, void *null); + + +int quicksort_timedelta(void *vec, npy_intp cnt, void *null); +int heapsort_timedelta(void *vec, npy_intp cnt, void *null); +int mergesort_timedelta(void *vec, npy_intp cnt, void *null); +int aquicksort_timedelta(void *vec, npy_intp *ind, npy_intp cnt, void *null); +int aheapsort_timedelta(void *vec, npy_intp *ind, npy_intp cnt, void *null); +int amergesort_timedelta(void *vec, npy_intp *ind, npy_intp cnt, void *null); -int npy_quicksort(char *vec, npy_intp cnt, PyArrayObject *arr); -int npy_heapsort(char *vec, npy_intp cnt, PyArrayObject *arr); -int npy_mergesort(char *vec, npy_intp cnt, PyArrayObject *arr); -int npy_aquicksort(char *vec, npy_intp *ind, npy_intp cnt, PyArrayObject *arr); -int npy_aheapsort(char *vec, npy_intp *ind, npy_intp cnt, PyArrayObject *arr); -int npy_amergesort(char *vec, npy_intp *ind, npy_intp cnt, PyArrayObject *arr); +int npy_quicksort(void *vec, npy_intp cnt, void *arr); +int npy_heapsort(void *vec, npy_intp cnt, void *arr); +int npy_mergesort(void *vec, npy_intp cnt, void *arr); +int npy_aquicksort(void *vec, npy_intp *ind, npy_intp cnt, void *arr); +int npy_aheapsort(void *vec, npy_intp *ind, npy_intp cnt, void *arr); +int npy_amergesort(void *vec, npy_intp *ind, npy_intp cnt, void *arr); #endif diff --git a/numpy/core/tests/test_indexing.py b/numpy/core/tests/test_indexing.py index e55c212b7..d412c44fb 100644 --- a/numpy/core/tests/test_indexing.py +++ b/numpy/core/tests/test_indexing.py @@ -409,6 +409,10 @@ class TestIndexing(TestCase): arr = np.arange(10) assert_array_equal(arr[SequenceLike()], arr[SequenceLike(),]) + # also test that field indexing does not segfault + # for a similar reason, by indexing a structured array + arr = np.zeros((1,), dtype=[('f1', 'i8'), ('f2', 'i8')]) + assert_array_equal(arr[SequenceLike()], arr[SequenceLike(),]) class TestFieldIndexing(TestCase): def test_scalar_return_type(self): diff --git a/numpy/core/tests/test_multiarray.py b/numpy/core/tests/test_multiarray.py index e6911d0e3..ac645f013 100644 --- a/numpy/core/tests/test_multiarray.py +++ b/numpy/core/tests/test_multiarray.py @@ -3484,7 +3484,7 @@ class TestRecord(TestCase): assert_raises(ValueError, dt.__getitem__, asbytes('a')) x = np.array([(1,), (2,), (3,)], dtype=dt) - assert_raises(ValueError, x.__getitem__, asbytes('a')) + assert_raises(IndexError, x.__getitem__, asbytes('a')) y = x[0] assert_raises(IndexError, y.__getitem__, asbytes('a')) @@ -3517,8 +3517,8 @@ class TestRecord(TestCase): if is_py3: funcs = (str,) # byte string indexing fails gracefully - assert_raises(ValueError, a.__setitem__, asbytes('f1'), 1) - assert_raises(ValueError, a.__getitem__, asbytes('f1')) + assert_raises(IndexError, a.__setitem__, asbytes('f1'), 1) + assert_raises(IndexError, a.__getitem__, asbytes('f1')) assert_raises(IndexError, a['f1'].__setitem__, asbytes('sf1'), 1) assert_raises(IndexError, a['f1'].__getitem__, asbytes('sf1')) else: @@ -3564,7 +3564,7 @@ class TestRecord(TestCase): def test_field_names_deprecation(self): - def collect_warning_types(f, *args, **kwargs): + def collect_warnings(f, *args, **kwargs): with warnings.catch_warnings(record=True) as log: warnings.simplefilter("always") f(*args, **kwargs) @@ -3585,20 +3585,19 @@ class TestRecord(TestCase): # All the different functions raise a warning, but not an error, and # 'a' is not modified: - assert_equal(collect_warning_types(a[['f1', 'f2']].__setitem__, 0, (10, 20)), + assert_equal(collect_warnings(a[['f1', 'f2']].__setitem__, 0, (10, 20)), [FutureWarning]) assert_equal(a, b) # Views also warn subset = a[['f1', 'f2']] subset_view = subset.view() - assert_equal(collect_warning_types(subset_view['f1'].__setitem__, 0, 10), + assert_equal(collect_warnings(subset_view['f1'].__setitem__, 0, 10), [FutureWarning]) # But the write goes through: assert_equal(subset['f1'][0], 10) - # Only one warning per multiple field indexing, though (even if there are - # multiple views involved): - assert_equal(collect_warning_types(subset['f1'].__setitem__, 0, 10), - []) + # Only one warning per multiple field indexing, though (even if there + # are multiple views involved): + assert_equal(collect_warnings(subset['f1'].__setitem__, 0, 10), []) def test_record_hash(self): a = np.array([(1, 2), (1, 2)], dtype='i1,i2') @@ -3616,11 +3615,18 @@ class TestRecord(TestCase): a = np.array([(1, 2), (1, 2)], dtype='i1,i2') self.assertRaises(TypeError, hash, a[0]) + def test_empty_structure_creation(self): + # make sure these do not raise errors (gh-5631) + array([()], dtype={'names': [], 'formats': [], + 'offsets': [], 'itemsize': 12}) + array([(), (), (), (), ()], dtype={'names': [], 'formats': [], + 'offsets': [], 'itemsize': 12}) + class TestView(TestCase): def test_basic(self): x = np.array([(1, 2, 3, 4), (5, 6, 7, 8)], - dtype=[('r', np.int8), ('g', np.int8), - ('b', np.int8), ('a', np.int8)]) + dtype=[('r', np.int8), ('g', np.int8), + ('b', np.int8), ('a', np.int8)]) # We must be specific about the endianness here: y = x.view(dtype='<i4') # ... and again without the keyword. @@ -5731,5 +5737,47 @@ class TestArrayPriority(TestCase): assert_(isinstance(f(b, a), self.Other), msg) +class TestBytestringArrayNonzero(TestCase): + + def test_empty_bstring_array_is_falsey(self): + self.assertFalse(np.array([''], dtype=np.str)) + + def test_whitespace_bstring_array_is_falsey(self): + a = np.array(['spam'], dtype=np.str) + a[0] = ' \0\0' + self.assertFalse(a) + + def test_all_null_bstring_array_is_falsey(self): + a = np.array(['spam'], dtype=np.str) + a[0] = '\0\0\0\0' + self.assertFalse(a) + + def test_null_inside_bstring_array_is_truthy(self): + a = np.array(['spam'], dtype=np.str) + a[0] = ' \0 \0' + self.assertTrue(a) + + +class TestUnicodeArrayNonzero(TestCase): + + def test_empty_ustring_array_is_falsey(self): + self.assertFalse(np.array([''], dtype=np.unicode)) + + def test_whitespace_ustring_array_is_falsey(self): + a = np.array(['eggs'], dtype=np.unicode) + a[0] = ' \0\0' + self.assertFalse(a) + + def test_all_null_ustring_array_is_falsey(self): + a = np.array(['eggs'], dtype=np.unicode) + a[0] = '\0\0\0\0' + self.assertFalse(a) + + def test_null_inside_ustring_array_is_truthy(self): + a = np.array(['eggs'], dtype=np.unicode) + a[0] = ' \0 \0' + self.assertTrue(a) + + if __name__ == "__main__": run_module_suite() diff --git a/numpy/core/tests/test_records.py b/numpy/core/tests/test_records.py index 52cfd1868..4924d4471 100644 --- a/numpy/core/tests/test_records.py +++ b/numpy/core/tests/test_records.py @@ -235,6 +235,11 @@ class TestRecord(TestCase): rec[0].x = 1 assert_equal(rec[0].x, np.ones(5)) + def test_missing_field(self): + # https://github.com/numpy/numpy/issues/4806 + arr = np.zeros((3,), dtype=[('x', int), ('y', int)]) + assert_raises(ValueError, lambda: arr[['nofield']]) + def test_find_duplicate(): l1 = [1, 2, 3, 4, 5, 6] assert_(np.rec.find_duplicate(l1) == []) diff --git a/numpy/ma/core.py b/numpy/ma/core.py index 877d07e02..703580d27 100644 --- a/numpy/ma/core.py +++ b/numpy/ma/core.py @@ -880,14 +880,10 @@ class _MaskedUnaryOperation: except TypeError: pass # Transform to - if isinstance(a, MaskedArray): - subtype = type(a) - else: - subtype = MaskedArray - result = result.view(subtype) - result._mask = m - result._update_from(a) - return result + masked_result = result.view(get_masked_subclass(a)) + masked_result._mask = m + masked_result._update_from(result) + return masked_result # def __str__ (self): return "Masked version of %s. [Invalid values are masked]" % str(self.f) @@ -928,8 +924,12 @@ class _MaskedBinaryOperation: def __call__ (self, a, b, *args, **kwargs): "Execute the call behavior." # Get the data, as ndarray - (da, db) = (getdata(a, subok=False), getdata(b, subok=False)) - # Get the mask + (da, db) = (getdata(a), getdata(b)) + # Get the result + with np.errstate(): + np.seterr(divide='ignore', invalid='ignore') + result = self.f(da, db, *args, **kwargs) + # Get the mask for the result (ma, mb) = (getmask(a), getmask(b)) if ma is nomask: if mb is nomask: @@ -940,12 +940,6 @@ class _MaskedBinaryOperation: m = umath.logical_or(ma, getmaskarray(b)) else: m = umath.logical_or(ma, mb) - # Get the result - with np.errstate(divide='ignore', invalid='ignore'): - result = self.f(da, db, *args, **kwargs) - # check it worked - if result is NotImplemented: - return NotImplemented # Case 1. : scalar if not result.ndim: if m: @@ -953,28 +947,26 @@ class _MaskedBinaryOperation: return result # Case 2. : array # Revert result to da where masked - if m is not nomask: - np.copyto(result, da, casting='unsafe', where=m) + if m is not nomask and m.any(): + # any errors, just abort; impossible to guarantee masked values + try: + np.copyto(result, 0, casting='unsafe', where=m) + # avoid using "*" since this may be overlaid + masked_da = umath.multiply(m, da) + # only add back if it can be cast safely + if np.can_cast(masked_da.dtype, result.dtype, casting='safe'): + result += masked_da + except: + pass # Transforms to a (subclass of) MaskedArray - result = result.view(get_masked_subclass(a, b)) - result._mask = m - # Update the optional info from the inputs - if isinstance(b, MaskedArray): - if isinstance(a, MaskedArray): - result._update_from(a) - else: - result._update_from(b) - elif isinstance(a, MaskedArray): - result._update_from(a) - return result - + masked_result = result.view(get_masked_subclass(a, b)) + masked_result._mask = m + masked_result._update_from(result) + return masked_result def reduce(self, target, axis=0, dtype=None): """Reduce `target` along the given `axis`.""" - if isinstance(target, MaskedArray): - tclass = type(target) - else: - tclass = MaskedArray + tclass = get_masked_subclass(target) m = getmask(target) t = filled(target, self.filly) if t.shape == (): @@ -982,24 +974,30 @@ class _MaskedBinaryOperation: if m is not nomask: m = make_mask(m, copy=1) m.shape = (1,) + if m is nomask: - return self.f.reduce(t, axis).view(tclass) - t = t.view(tclass) - t._mask = m - tr = self.f.reduce(getdata(t), axis, dtype=dtype or t.dtype) - mr = umath.logical_and.reduce(m, axis) - tr = tr.view(tclass) - if mr.ndim > 0: - tr._mask = mr - return tr - elif mr: - return masked - return tr + tr = self.f.reduce(t, axis) + mr = nomask + else: + tr = self.f.reduce(t, axis, dtype=dtype or t.dtype) + mr = umath.logical_and.reduce(m, axis) - def outer (self, a, b): + if not tr.shape: + if mr: + return masked + else: + return tr + masked_tr = tr.view(tclass) + masked_tr._mask = mr + masked_tr._update_from(tr) + return masked_tr + + def outer(self, a, b): """Return the function applied to the outer product of a and b. """ + (da, db) = (getdata(a), getdata(b)) + d = self.f.outer(da, db) ma = getmask(a) mb = getmask(b) if ma is nomask and mb is nomask: @@ -1010,31 +1008,28 @@ class _MaskedBinaryOperation: m = umath.logical_or.outer(ma, mb) if (not m.ndim) and m: return masked - (da, db) = (getdata(a), getdata(b)) - d = self.f.outer(da, db) - # check it worked - if d is NotImplemented: - return NotImplemented if m is not nomask: np.copyto(d, da, where=m) - if d.shape: - d = d.view(get_masked_subclass(a, b)) - d._mask = m - return d + if not d.shape: + return d + masked_d = d.view(get_masked_subclass(a, b)) + masked_d._mask = m + masked_d._update_from(d) + return masked_d - def accumulate (self, target, axis=0): + def accumulate(self, target, axis=0): """Accumulate `target` along `axis` after filling with y fill value. """ - if isinstance(target, MaskedArray): - tclass = type(target) - else: - tclass = MaskedArray + tclass = get_masked_subclass(target) t = filled(target, self.filly) - return self.f.accumulate(t, axis).view(tclass) + result = self.f.accumulate(t, axis) + masked_result = result.view(tclass) + masked_result._update_from(result) + return masked_result - def __str__ (self): + def __str__(self): return "Masked version of " + str(self.f) @@ -1074,19 +1069,15 @@ class _DomainedBinaryOperation: def __call__(self, a, b, *args, **kwargs): "Execute the call behavior." - # Get the data and the mask - (da, db) = (getdata(a, subok=False), getdata(b, subok=False)) - (ma, mb) = (getmask(a), getmask(b)) + # Get the data + (da, db) = (getdata(a), getdata(b)) # Get the result with np.errstate(divide='ignore', invalid='ignore'): result = self.f(da, db, *args, **kwargs) - # check it worked - if result is NotImplemented: - return NotImplemented - # Get the mask as a combination of ma, mb and invalid + # Get the mask as a combination of the source masks and invalid m = ~umath.isfinite(result) - m |= ma - m |= mb + m |= getmask(a) + m |= getmask(b) # Apply the domain domain = ufunc_domain.get(self.f, None) if domain is not None: @@ -1097,18 +1088,23 @@ class _DomainedBinaryOperation: return masked else: return result - # When the mask is True, put back da - np.copyto(result, da, casting='unsafe', where=m) - result = result.view(get_masked_subclass(a, b)) - result._mask = m - if isinstance(b, MaskedArray): - if isinstance(a, MaskedArray): - result._update_from(a) - else: - result._update_from(b) - elif isinstance(a, MaskedArray): - result._update_from(a) - return result + # When the mask is True, put back da if possible + # any errors, just abort; impossible to guarantee masked values + try: + np.copyto(result, 0, casting='unsafe', where=m) + # avoid using "*" since this may be overlaid + masked_da = umath.multiply(m, da) + # only add back if it can be cast safely + if np.can_cast(masked_da.dtype, result.dtype, casting='safe'): + result += masked_da + except: + pass + + # Transforms to a (subclass of) MaskedArray + masked_result = result.view(get_masked_subclass(a, b)) + masked_result._mask = m + masked_result._update_from(result) + return masked_result def __str__ (self): return "Masked version of " + str(self.f) @@ -1361,7 +1357,7 @@ def getmaskarray(arr): """ mask = getmask(arr) if mask is nomask: - mask = make_mask_none(np.shape(arr), getdata(arr).dtype) + mask = make_mask_none(np.shape(arr), getattr(arr, 'dtype', None)) return mask def is_mask(m): @@ -3050,6 +3046,7 @@ class MaskedArray(ndarray): # mask of being reshaped if it hasn't been set up properly yet... # So it's easier to stick to the current version _mask = self._mask + # Did we extract a single item? if not getattr(dout, 'ndim', False): # A record ................ if isinstance(dout, np.void): @@ -3061,6 +3058,11 @@ class MaskedArray(ndarray): # Just a scalar............ elif _mask is not nomask and _mask[indx]: return masked + elif self.dtype.type is np.object_ and self.dtype is not dout.dtype: + # self contains an object array of arrays (yes, that happens). + # If masked, turn into a MaskedArray, with everything masked. + if _mask is not nomask and _mask[indx]: + return MaskedArray(dout, mask=True) else: # Force dout to MA ........ dout = dout.view(type(self)) @@ -3179,8 +3181,8 @@ class MaskedArray(ndarray): """Set the mask. """ - idtype = ndarray.__getattribute__(self, 'dtype') - current_mask = ndarray.__getattribute__(self, '_mask') + idtype = self.dtype + current_mask = self._mask if mask is masked: mask = True # Make sure the mask is set @@ -3258,7 +3260,7 @@ class MaskedArray(ndarray): A record is masked when all the fields are masked. """ - _mask = ndarray.__getattribute__(self, '_mask').view(ndarray) + _mask = self._mask.view(ndarray) if _mask.dtype.names is None: return _mask return np.all(flatten_structured_array(_mask), axis= -1) @@ -3695,7 +3697,7 @@ class MaskedArray(ndarray): return masked omask = getattr(other, '_mask', nomask) if omask is nomask: - check = ndarray.__eq__(self.filled(0), other) + check = self.filled(0).__eq__(other) try: check = check.view(type(self)) check._mask = self._mask @@ -3704,7 +3706,7 @@ class MaskedArray(ndarray): return check else: odata = filled(other, 0) - check = ndarray.__eq__(self.filled(0), odata).view(type(self)) + check = self.filled(0).__eq__(odata).view(type(self)) if self._mask is nomask: check._mask = omask else: @@ -3728,7 +3730,7 @@ class MaskedArray(ndarray): return masked omask = getattr(other, '_mask', nomask) if omask is nomask: - check = ndarray.__ne__(self.filled(0), other) + check = self.filled(0).__ne__(other) try: check = check.view(type(self)) check._mask = self._mask @@ -3737,7 +3739,7 @@ class MaskedArray(ndarray): return check else: odata = filled(other, 0) - check = ndarray.__ne__(self.filled(0), odata).view(type(self)) + check = self.filled(0).__ne__(odata).view(type(self)) if self._mask is nomask: check._mask = omask else: @@ -3756,34 +3758,38 @@ class MaskedArray(ndarray): return check # def __add__(self, other): - "Add other to self, and return a new masked array." + "Add self to other, and return a new masked array." if self._delegate_binop(other): return NotImplemented return add(self, other) # def __radd__(self, other): "Add other to self, and return a new masked array." - return add(self, other) + # In analogy with __rsub__ and __rdiv__, use original order: + # we get here from `other + self`. + return add(other, self) # def __sub__(self, other): - "Subtract other to self, and return a new masked array." + "Subtract other from self, and return a new masked array." if self._delegate_binop(other): return NotImplemented return subtract(self, other) # def __rsub__(self, other): - "Subtract other to self, and return a new masked array." + "Subtract self from other, and return a new masked array." return subtract(other, self) # def __mul__(self, other): - "Multiply other by self, and return a new masked array." + "Multiply self by other, and return a new masked array." if self._delegate_binop(other): return NotImplemented return multiply(self, other) # def __rmul__(self, other): "Multiply other by self, and return a new masked array." - return multiply(self, other) + # In analogy with __rsub__ and __rdiv__, use original order: + # we get here from `other * self`. + return multiply(other, self) # def __div__(self, other): "Divide other into self, and return a new masked array." @@ -3798,7 +3804,7 @@ class MaskedArray(ndarray): return true_divide(self, other) # def __rtruediv__(self, other): - "Divide other into self, and return a new masked array." + "Divide self into other, and return a new masked array." return true_divide(other, self) # def __floordiv__(self, other): @@ -3808,7 +3814,7 @@ class MaskedArray(ndarray): return floor_divide(self, other) # def __rfloordiv__(self, other): - "Divide other into self, and return a new masked array." + "Divide self into other, and return a new masked array." return floor_divide(other, self) # def __pow__(self, other): @@ -3818,7 +3824,7 @@ class MaskedArray(ndarray): return power(self, other) # def __rpow__(self, other): - "Raise self to the power other, masking the potential NaNs/Infs" + "Raise other to the power self, masking the potential NaNs/Infs" return power(other, self) #............................................ def __iadd__(self, other): @@ -3831,10 +3837,8 @@ class MaskedArray(ndarray): else: if m is not nomask: self._mask += m - ndarray.__iadd__( - self._data, - np.where(self._mask, self.dtype.type(0), getdata(other)) - ) + self._data.__iadd__(np.where(self._mask, self.dtype.type(0), + getdata(other))) return self #.... def __isub__(self, other): @@ -3846,10 +3850,8 @@ class MaskedArray(ndarray): self._mask += m elif m is not nomask: self._mask += m - ndarray.__isub__( - self._data, - np.where(self._mask, self.dtype.type(0), getdata(other)) - ) + self._data.__isub__(np.where(self._mask, self.dtype.type(0), + getdata(other))) return self #.... def __imul__(self, other): @@ -3861,10 +3863,8 @@ class MaskedArray(ndarray): self._mask += m elif m is not nomask: self._mask += m - ndarray.__imul__( - self._data, - np.where(self._mask, self.dtype.type(1), getdata(other)) - ) + self._data.__imul__(np.where(self._mask, self.dtype.type(1), + getdata(other))) return self #.... def __idiv__(self, other): @@ -3879,10 +3879,8 @@ class MaskedArray(ndarray): other_data = np.where(dom_mask, fval, other_data) # self._mask = mask_or(self._mask, new_mask) self._mask |= new_mask - ndarray.__idiv__( - self._data, - np.where(self._mask, self.dtype.type(1), other_data) - ) + self._data.__idiv__(np.where(self._mask, self.dtype.type(1), + other_data)) return self #.... def __ifloordiv__(self, other): @@ -3897,10 +3895,8 @@ class MaskedArray(ndarray): other_data = np.where(dom_mask, fval, other_data) # self._mask = mask_or(self._mask, new_mask) self._mask |= new_mask - ndarray.__ifloordiv__( - self._data, - np.where(self._mask, self.dtype.type(1), other_data) - ) + self._data.__ifloordiv__(np.where(self._mask, self.dtype.type(1), + other_data)) return self #.... def __itruediv__(self, other): @@ -3915,10 +3911,8 @@ class MaskedArray(ndarray): other_data = np.where(dom_mask, fval, other_data) # self._mask = mask_or(self._mask, new_mask) self._mask |= new_mask - ndarray.__itruediv__( - self._data, - np.where(self._mask, self.dtype.type(1), other_data) - ) + self._data.__itruediv__(np.where(self._mask, self.dtype.type(1), + other_data)) return self #... def __ipow__(self, other): @@ -3926,10 +3920,8 @@ class MaskedArray(ndarray): other_data = getdata(other) other_mask = getmask(other) with np.errstate(divide='ignore', invalid='ignore'): - ndarray.__ipow__( - self._data, - np.where(self._mask, self.dtype.type(1), other_data) - ) + self._data.__ipow__(np.where(self._mask, self.dtype.type(1), + other_data)) invalid = np.logical_not(np.isfinite(self._data)) if invalid.any(): if self._mask is not nomask: @@ -4614,7 +4606,7 @@ class MaskedArray(ndarray): <type 'numpy.int64'> """ - _mask = ndarray.__getattribute__(self, '_mask') + _mask = self._mask newmask = _check_mask_axis(_mask, axis) # No explicit output if out is None: @@ -4742,7 +4734,7 @@ class MaskedArray(ndarray): array([ 2., 12.]) """ - _mask = ndarray.__getattribute__(self, '_mask') + _mask = self._mask newmask = _check_mask_axis(_mask, axis) # No explicit output if out is None: @@ -5258,7 +5250,7 @@ class MaskedArray(ndarray): Returns the minimum filling value for a given datatype. """ - _mask = ndarray.__getattribute__(self, '_mask') + _mask = self._mask newmask = _check_mask_axis(_mask, axis) if fill_value is None: fill_value = minimum_fill_value(self) @@ -5357,7 +5349,7 @@ class MaskedArray(ndarray): Returns the maximum filling value for a given datatype. """ - _mask = ndarray.__getattribute__(self, '_mask') + _mask = self._mask newmask = _check_mask_axis(_mask, axis) if fill_value is None: fill_value = maximum_fill_value(self) @@ -5682,7 +5674,7 @@ class MaskedArray(ndarray): """ (_, shp, typ, isf, raw, msk, flv) = state - ndarray.__setstate__(self, (shp, typ, isf, raw)) + super(MaskedArray, self).__setstate__((shp, typ, isf, raw)) self._mask.__setstate__((shp, make_mask_descr(typ), isf, msk)) self.fill_value = flv # diff --git a/numpy/ma/tests/test_core.py b/numpy/ma/tests/test_core.py index 909c27c90..2bf782724 100644 --- a/numpy/ma/tests/test_core.py +++ b/numpy/ma/tests/test_core.py @@ -685,6 +685,18 @@ class TestMaskedArray(TestCase): finally: masked_print_option.set_display(ini_display) + def test_object_with_array(self): + mx1 = masked_array([1.], mask=[True]) + mx2 = masked_array([1., 2.]) + mx = masked_array([mx1, mx2], mask=[False, True]) + assert mx[0] is mx1 + assert mx[1] is not mx2 + assert np.all(mx[1].data == mx2.data) + assert np.all(mx[1].mask) + # check that we return a view. + mx[1].data[0] = 0. + assert mx2[0] == 0. + #------------------------------------------------------------------------------ class TestMaskedArrayArithmetic(TestCase): @@ -1754,6 +1766,29 @@ class TestUfuncs(TestCase): assert_(me * a == "My mul") assert_(a * me == "My rmul") + # and that __array_priority__ is respected + class MyClass2(object): + __array_priority__ = 100 + + def __mul__(self, other): + return "Me2mul" + + def __rmul__(self, other): + return "Me2rmul" + + def __rdiv__(self, other): + return "Me2rdiv" + + __rtruediv__ = __rdiv__ + + me_too = MyClass2() + assert_(a.__mul__(me_too) is NotImplemented) + assert_(all(multiply.outer(a, me_too) == "Me2rmul")) + assert_(a.__truediv__(me_too) is NotImplemented) + assert_(me_too * a == "Me2mul") + assert_(a * me_too == "Me2rmul") + assert_(a / me_too == "Me2rdiv") + #------------------------------------------------------------------------------ class TestMaskedArrayInPlaceArithmetics(TestCase): diff --git a/numpy/ma/tests/test_subclassing.py b/numpy/ma/tests/test_subclassing.py index 07fc8fdd6..2e98348e6 100644 --- a/numpy/ma/tests/test_subclassing.py +++ b/numpy/ma/tests/test_subclassing.py @@ -24,18 +24,27 @@ class SubArray(np.ndarray): # in the dictionary `info`. def __new__(cls,arr,info={}): x = np.asanyarray(arr).view(cls) - x.info = info + x.info = info.copy() return x def __array_finalize__(self, obj): - self.info = getattr(obj, 'info', {}) + if callable(getattr(super(SubArray, self), + '__array_finalize__', None)): + super(SubArray, self).__array_finalize__(obj) + self.info = getattr(obj, 'info', {}).copy() return def __add__(self, other): - result = np.ndarray.__add__(self, other) - result.info.update({'added':result.info.pop('added', 0)+1}) + result = super(SubArray, self).__add__(other) + result.info['added'] = result.info.get('added', 0) + 1 return result + def __iadd__(self, other): + result = super(SubArray, self).__iadd__(other) + result.info['iadded'] = result.info.get('iadded', 0) + 1 + return result + + subarray = SubArray @@ -47,11 +56,6 @@ class MSubArray(SubArray, MaskedArray): _data.info = subarr.info return _data - def __array_finalize__(self, obj): - MaskedArray.__array_finalize__(self, obj) - SubArray.__array_finalize__(self, obj) - return - def _get_series(self): _view = self.view(MaskedArray) _view._sharedmask = False @@ -82,8 +86,11 @@ class MMatrix(MaskedArray, np.matrix,): mmatrix = MMatrix -# also a subclass that overrides __str__, __repr__ and __setitem__, disallowing +# Also a subclass that overrides __str__, __repr__ and __setitem__, disallowing # setting to non-class values (and thus np.ma.core.masked_print_option) +# and overrides __array_wrap__, updating the info dict, to check that this +# doesn't get destroyed by MaskedArray._update_from. But this one also needs +# its own iterator... class CSAIterator(object): """ Flat iterator object that uses its own setter/getter @@ -150,6 +157,13 @@ class ComplicatedSubArray(SubArray): y = self.ravel() y[:] = value + def __array_wrap__(self, obj, context=None): + obj = super(ComplicatedSubArray, self).__array_wrap__(obj, context) + if context is not None and context[0] is np.multiply: + obj.info['multiplied'] = obj.info.get('multiplied', 0) + 1 + + return obj + class TestSubclassing(TestCase): # Test suite for masked subclasses of ndarray. @@ -218,6 +232,12 @@ class TestSubclassing(TestCase): self.assertTrue(isinstance(z, MSubArray)) self.assertTrue(isinstance(z._data, SubArray)) self.assertTrue(z._data.info['added'] > 0) + # Test that inplace methods from data get used (gh-4617) + ym += 1 + self.assertTrue(isinstance(ym, MaskedArray)) + self.assertTrue(isinstance(ym, MSubArray)) + self.assertTrue(isinstance(ym._data, SubArray)) + self.assertTrue(ym._data.info['iadded'] > 0) # ym._set_mask([1, 0, 0, 0, 1]) assert_equal(ym._mask, [1, 0, 0, 0, 1]) |