diff options
-rw-r--r-- | INSTALL.txt | 14 | ||||
-rw-r--r-- | numpy/core/include/numpy/ndarraytypes.h | 11 | ||||
-rw-r--r-- | numpy/core/numeric.py | 4 | ||||
-rw-r--r-- | numpy/core/src/multiarray/convert.c | 4 | ||||
-rw-r--r-- | numpy/core/src/multiarray/ctors.c | 41 | ||||
-rw-r--r-- | numpy/core/src/multiarray/dtype_transfer.c | 6 | ||||
-rw-r--r-- | numpy/core/src/multiarray/flagsobject.c | 100 | ||||
-rw-r--r-- | numpy/core/src/multiarray/multiarraymodule.c | 18 | ||||
-rw-r--r-- | numpy/core/src/multiarray/shape.c | 183 | ||||
-rw-r--r-- | numpy/core/src/private/lowlevel_strided_loops.h | 46 | ||||
-rw-r--r-- | numpy/core/src/umath/reduction.c | 2 | ||||
-rw-r--r-- | numpy/core/tests/test_api.py | 36 | ||||
-rw-r--r-- | numpy/core/tests/test_regression.py | 15 | ||||
-rw-r--r-- | numpy/ma/core.py | 10 | ||||
-rw-r--r-- | numpy/ma/tests/test_core.py | 8 | ||||
-rw-r--r-- | numpy/tests/test_ctypeslib.py | 4 |
16 files changed, 214 insertions, 288 deletions
diff --git a/INSTALL.txt b/INSTALL.txt index d75d4d9d0..d593dc8ee 100644 --- a/INSTALL.txt +++ b/INSTALL.txt @@ -60,7 +60,7 @@ How to check the ABI of blas/lapack/atlas One relatively simple and reliable way to check for the compiler used to build a library is to use ldd on the library. If libg2c.so is a dependency, this -means that g77 has been used. If libgfortran.so is a a dependency, gfortran has +means that g77 has been used. If libgfortran.so is a dependency, gfortran has been used. If both are dependencies, this means both have been used, which is almost always a very bad idea. @@ -74,8 +74,8 @@ You can install the necessary packages for optimized ATLAS with this command: sudo apt-get install libatlas-base-dev -If you have a recent CPU with SIMD suppport (SSE, SSE2, etc...), you should -also install the corresponding package for optimal performances. For example, +If you have a recent CPU with SIMD support (SSE, SSE2, etc...), you should +also install the corresponding package for optimal performance. For example, for SSE2: sudo apt-get install libatlas3gf-sse2 @@ -91,8 +91,8 @@ You can install the necessary packages for optimized ATLAS with this command: sudo apt-get install atlas3-base-dev -If you have a recent CPU with SIMD suppport (SSE, SSE2, etc...), you should -also install the corresponding package for optimal performances. For example, +If you have a recent CPU with SIMD support (SSE, SSE2, etc...), you should +also install the corresponding package for optimal performance. For example, for SSE2: sudo apt-get install atlas3-sse2 @@ -111,7 +111,7 @@ http://mingw-w64.sourceforge.net/ To use the free compilers (mingw-w64), you need to build your own toolchain, as the mingw project only distribute cross-compilers (cross-compilation is not supported by numpy). Since this toolchain is still being worked on, serious -compilers bugs can be expected. binutil 2.19 + gcc 4.3.3 + mingw-w64 runtime +compiler bugs can be expected. binutil 2.19 + gcc 4.3.3 + mingw-w64 runtime gives you a working C compiler (but the C++ is broken). gcc 4.4 will hopefully be able to run natively. @@ -127,7 +127,7 @@ fragile, and often segfault on invalid C code). The main drawback is that no fortran compiler + MS compiler combination has been tested - mingw-w64 gfortran + MS compiler does not work at all (it is unclear whether it ever will). -For python 2.5, you need VS 2005 (MS compiler version 14) targetting +For python 2.5, you need VS 2005 (MS compiler version 14) targeting AMD64 bits, or the Platform SDK v6.0 or below (which gives command line versions of 64 bits target compilers). The PSDK is free. diff --git a/numpy/core/include/numpy/ndarraytypes.h b/numpy/core/include/numpy/ndarraytypes.h index 93d561c7c..c84eb6277 100644 --- a/numpy/core/include/numpy/ndarraytypes.h +++ b/numpy/core/include/numpy/ndarraytypes.h @@ -756,8 +756,9 @@ typedef int (PyArray_FinalizeFunc)(PyArrayObject *, PyObject *); #define NPY_ARRAY_F_CONTIGUOUS 0x0002 /* - * Note: all 0-d arrays are C_CONTIGUOUS and F_CONTIGUOUS. If a - * 1-d array is C_CONTIGUOUS it is also F_CONTIGUOUS + * Note: all 0-d arrays are C_CONTIGUOUS and F_CONTIGUOUS. An N-d + * array that is C_CONTIGUOUS is also F_CONTIGUOUS if only + * one axis has a dimension different from one (ie. a 1x3x1 array). */ /* @@ -1370,7 +1371,7 @@ PyArrayNeighborhoodIter_Next2D(PyArrayNeighborhoodIterObject* iter); PyArray_CHKFLAGS(m, NPY_ARRAY_F_CONTIGUOUS)) #define PyArray_ISFORTRAN(m) (PyArray_CHKFLAGS(m, NPY_ARRAY_F_CONTIGUOUS) && \ - (PyArray_NDIM(m) > 1)) + (!PyArray_CHKFLAGS(m, NPY_ARRAY_C_CONTIGUOUS))) #define PyArray_FORTRAN_IF(m) ((PyArray_CHKFLAGS(m, NPY_ARRAY_F_CONTIGUOUS) ? \ NPY_ARRAY_F_CONTIGUOUS : 0)) @@ -1476,8 +1477,8 @@ PyArray_SETITEM(PyArrayObject *arr, char *itemptr, PyObject *v) /* These macros are deprecated as of NumPy 1.7. */ #define PyArray_NDIM(obj) (((PyArrayObject_fields *)(obj))->nd) -#define PyArray_BYTES(obj) ((char *)(((PyArrayObject_fields *)(obj))->data)) -#define PyArray_DATA(obj) ((void *)(((PyArrayObject_fields *)(obj))->data)) +#define PyArray_BYTES(obj) (((PyArrayObject_fields *)(obj))->data) +#define PyArray_DATA(obj) (((PyArrayObject_fields *)(obj))->data) #define PyArray_DIMS(obj) (((PyArrayObject_fields *)(obj))->dimensions) #define PyArray_STRIDES(obj) (((PyArrayObject_fields *)(obj))->strides) #define PyArray_DIM(obj,n) (PyArray_DIMS(obj)[n]) diff --git a/numpy/core/numeric.py b/numpy/core/numeric.py index 5f0474d3e..0d0babbac 100644 --- a/numpy/core/numeric.py +++ b/numpy/core/numeric.py @@ -538,7 +538,7 @@ def require(a, dtype=None, requirements=None): def isfortran(a): """ Returns True if array is arranged in Fortran-order in memory - and dimension > 1. + and not C-order. Parameters ---------- @@ -584,7 +584,7 @@ def isfortran(a): >>> np.isfortran(b) True - 1-D arrays always evaluate as False. + C-ordered arrays evaluate as False even if they are also FORTRAN-ordered. >>> np.isfortran(np.array([1, 2], order='FORTRAN')) False diff --git a/numpy/core/src/multiarray/convert.c b/numpy/core/src/multiarray/convert.c index 8b646e59b..e3dd78b9f 100644 --- a/numpy/core/src/multiarray/convert.c +++ b/numpy/core/src/multiarray/convert.c @@ -265,8 +265,8 @@ PyArray_ToString(PyArrayObject *self, NPY_ORDER order) */ numbytes = PyArray_NBYTES(self); - if ((PyArray_ISCONTIGUOUS(self) && (order == NPY_CORDER)) - || (PyArray_ISFORTRAN(self) && (order == NPY_FORTRANORDER))) { + if ((PyArray_IS_C_CONTIGUOUS(self) && (order == NPY_CORDER)) + || (PyArray_IS_F_CONTIGUOUS(self) && (order == NPY_FORTRANORDER))) { ret = PyBytes_FromStringAndSize(PyArray_DATA(self), (Py_ssize_t) numbytes); } else { diff --git a/numpy/core/src/multiarray/ctors.c b/numpy/core/src/multiarray/ctors.c index 934f9198f..ef6c40b46 100644 --- a/numpy/core/src/multiarray/ctors.c +++ b/numpy/core/src/multiarray/ctors.c @@ -1112,7 +1112,6 @@ PyArray_NewLikeArray(PyArrayObject *prototype, NPY_ORDER order, int idim; PyArray_CreateSortedStridePerm(PyArray_NDIM(prototype), - PyArray_SHAPE(prototype), PyArray_STRIDES(prototype), strideperm); @@ -1825,9 +1824,6 @@ PyArray_FromArray(PyArrayObject *arr, PyArray_Descr *newtype, int flags) } arrflags = PyArray_FLAGS(arr); - if (PyArray_NDIM(arr) <= 1 && (flags & NPY_ARRAY_F_CONTIGUOUS)) { - flags |= NPY_ARRAY_C_CONTIGUOUS; - } /* If a guaranteed copy was requested */ copy = (flags & NPY_ARRAY_ENSURECOPY) || /* If C contiguous was requested, and arr is not */ @@ -1837,9 +1833,8 @@ PyArray_FromArray(PyArrayObject *arr, PyArray_Descr *newtype, int flags) ((flags & NPY_ARRAY_ALIGNED) && (!(arrflags & NPY_ARRAY_ALIGNED))) || /* If a Fortran contiguous array was requested, and arr is not */ - (PyArray_NDIM(arr) > 1 && - ((flags & NPY_ARRAY_F_CONTIGUOUS) && - (!(arrflags & NPY_ARRAY_F_CONTIGUOUS)))) || + ((flags & NPY_ARRAY_F_CONTIGUOUS) && + (!(arrflags & NPY_ARRAY_F_CONTIGUOUS))) || /* If a writeable array was requested, and arr is not */ ((flags & NPY_ARRAY_WRITEABLE) && (!(arrflags & NPY_ARRAY_WRITEABLE))) || @@ -3570,14 +3565,33 @@ _array_fill_strides(npy_intp *strides, npy_intp *dims, int nd, size_t itemsize, int inflag, int *objflags) { int i; + npy_bool not_cf_contig = 0; + npy_bool nod = 0; /* A dim != 1 was found */ + + /* Check if new array is both F- and C-contiguous */ + for (i = 0; i < nd; i++) { + if (dims[i] != 1) { + if (nod) { + not_cf_contig = 1; + break; + } + nod = 1; + } + } + /* Only make Fortran strides if not contiguous as well */ if ((inflag & (NPY_ARRAY_F_CONTIGUOUS|NPY_ARRAY_C_CONTIGUOUS)) == NPY_ARRAY_F_CONTIGUOUS) { for (i = 0; i < nd; i++) { strides[i] = itemsize; - itemsize *= dims[i] ? dims[i] : 1; + if (dims[i]) { + itemsize *= dims[i]; + } + else { + not_cf_contig = 0; + } } - if (nd > 1) { + if (not_cf_contig) { *objflags = ((*objflags)|NPY_ARRAY_F_CONTIGUOUS) & ~NPY_ARRAY_C_CONTIGUOUS; } @@ -3588,9 +3602,14 @@ _array_fill_strides(npy_intp *strides, npy_intp *dims, int nd, size_t itemsize, else { for (i = nd - 1; i >= 0; i--) { strides[i] = itemsize; - itemsize *= dims[i] ? dims[i] : 1; + if (dims[i]) { + itemsize *= dims[i]; + } + else { + not_cf_contig = 0; + } } - if (nd > 1) { + if (not_cf_contig) { *objflags = ((*objflags)|NPY_ARRAY_C_CONTIGUOUS) & ~NPY_ARRAY_F_CONTIGUOUS; } diff --git a/numpy/core/src/multiarray/dtype_transfer.c b/numpy/core/src/multiarray/dtype_transfer.c index 138275c4c..01cb93562 100644 --- a/numpy/core/src/multiarray/dtype_transfer.c +++ b/numpy/core/src/multiarray/dtype_transfer.c @@ -3921,7 +3921,7 @@ PyArray_PrepareOneRawArrayIter(int ndim, npy_intp *shape, } /* Sort the axes based on the destination strides */ - PyArray_CreateSortedStridePerm(ndim, shape, strides, strideperm); + PyArray_CreateSortedStridePerm(ndim, strides, strideperm); for (i = 0; i < ndim; ++i) { int iperm = strideperm[ndim - i - 1].perm; out_shape[i] = shape[iperm]; @@ -4051,7 +4051,7 @@ PyArray_PrepareTwoRawArrayIter(int ndim, npy_intp *shape, } /* Sort the axes based on the destination strides */ - PyArray_CreateSortedStridePerm(ndim, shape, stridesA, strideperm); + PyArray_CreateSortedStridePerm(ndim, stridesA, strideperm); for (i = 0; i < ndim; ++i) { int iperm = strideperm[ndim - i - 1].perm; out_shape[i] = shape[iperm]; @@ -4185,7 +4185,7 @@ PyArray_PrepareThreeRawArrayIter(int ndim, npy_intp *shape, } /* Sort the axes based on the destination strides */ - PyArray_CreateSortedStridePerm(ndim, shape, stridesA, strideperm); + PyArray_CreateSortedStridePerm(ndim, stridesA, strideperm); for (i = 0; i < ndim; ++i) { int iperm = strideperm[ndim - i - 1].perm; out_shape[i] = shape[iperm]; diff --git a/numpy/core/src/multiarray/flagsobject.c b/numpy/core/src/multiarray/flagsobject.c index faaf264e0..ef04bdb20 100644 --- a/numpy/core/src/multiarray/flagsobject.c +++ b/numpy/core/src/multiarray/flagsobject.c @@ -15,11 +15,8 @@ #include "common.h" -static int -_IsContiguous(PyArrayObject *ap); - -static int -_IsFortranContiguous(PyArrayObject *ap); +static void +_UpdateContiguousFlags(PyArrayObject *ap); /*NUMPY_API * @@ -62,28 +59,9 @@ PyArray_NewFlagsObject(PyObject *obj) NPY_NO_EXPORT void PyArray_UpdateFlags(PyArrayObject *ret, int flagmask) { - - if (flagmask & NPY_ARRAY_F_CONTIGUOUS) { - if (_IsFortranContiguous(ret)) { - PyArray_ENABLEFLAGS(ret, NPY_ARRAY_F_CONTIGUOUS); - if (PyArray_NDIM(ret) > 1) { - PyArray_CLEARFLAGS(ret, NPY_ARRAY_C_CONTIGUOUS); - } - } - else { - PyArray_CLEARFLAGS(ret, NPY_ARRAY_F_CONTIGUOUS); - } - } - if (flagmask & NPY_ARRAY_C_CONTIGUOUS) { - if (_IsContiguous(ret)) { - PyArray_ENABLEFLAGS(ret, NPY_ARRAY_C_CONTIGUOUS); - if (PyArray_NDIM(ret) > 1) { - PyArray_CLEARFLAGS(ret, NPY_ARRAY_F_CONTIGUOUS); - } - } - else { - PyArray_CLEARFLAGS(ret, NPY_ARRAY_C_CONTIGUOUS); - } + /* Always update both, as its not trivial to guess one from the other */ + if (flagmask & (NPY_ARRAY_F_CONTIGUOUS | NPY_ARRAY_C_CONTIGUOUS)) { + _UpdateContiguousFlags(ret); } if (flagmask & NPY_ARRAY_ALIGNED) { if (_IsAligned(ret)) { @@ -110,66 +88,56 @@ PyArray_UpdateFlags(PyArrayObject *ret, int flagmask) /* * Check whether the given array is stored contiguously - * (row-wise) in memory. + * in memory. And update the passed in ap flags apropriately. * - * 0-strided arrays are not contiguous (even if dimension == 1) + * A dimension == 1 stride is ignored for contiguous flags and a 0-sized array + * is always both C- and F-Contiguous. 0-strided arrays are not contiguous. */ -static int -_IsContiguous(PyArrayObject *ap) +static void +_UpdateContiguousFlags(PyArrayObject *ap) { npy_intp sd; npy_intp dim; int i; + npy_bool is_c_contig = 1; - if (PyArray_NDIM(ap) == 0) { - return 1; - } sd = PyArray_DESCR(ap)->elsize; - if (PyArray_NDIM(ap) == 1) { - return PyArray_DIMS(ap)[0] == 1 || sd == PyArray_STRIDES(ap)[0]; - } for (i = PyArray_NDIM(ap) - 1; i >= 0; --i) { dim = PyArray_DIMS(ap)[i]; /* contiguous by definition */ if (dim == 0) { - return 1; + PyArray_ENABLEFLAGS(ap, NPY_ARRAY_C_CONTIGUOUS); + PyArray_ENABLEFLAGS(ap, NPY_ARRAY_F_CONTIGUOUS); + return; } - if (PyArray_STRIDES(ap)[i] != sd) { - return 0; + if (dim != 1) { + if (PyArray_STRIDES(ap)[i] != sd) { + is_c_contig = 0; + } + sd *= dim; } - sd *= dim; } - return 1; -} - - -/* 0-strided arrays are not contiguous (even if dimension == 1) */ -static int -_IsFortranContiguous(PyArrayObject *ap) -{ - npy_intp sd; - npy_intp dim; - int i; - - if (PyArray_NDIM(ap) == 0) { - return 1; + if (is_c_contig) { + PyArray_ENABLEFLAGS(ap, NPY_ARRAY_C_CONTIGUOUS); } - sd = PyArray_DESCR(ap)->elsize; - if (PyArray_NDIM(ap) == 1) { - return PyArray_DIMS(ap)[0] == 1 || sd == PyArray_STRIDES(ap)[0]; + else { + PyArray_CLEARFLAGS(ap, NPY_ARRAY_C_CONTIGUOUS); } + + /* check if fortran contiguous */ + sd = PyArray_DESCR(ap)->elsize; for (i = 0; i < PyArray_NDIM(ap); ++i) { dim = PyArray_DIMS(ap)[i]; - /* fortran contiguous by definition */ - if (dim == 0) { - return 1; - } - if (PyArray_STRIDES(ap)[i] != sd) { - return 0; + if (dim != 1) { + if (PyArray_STRIDES(ap)[i] != sd) { + PyArray_CLEARFLAGS(ap, NPY_ARRAY_F_CONTIGUOUS); + return; + } + sd *= dim; } - sd *= dim; } - return 1; + PyArray_ENABLEFLAGS(ap, NPY_ARRAY_F_CONTIGUOUS); + return; } static void diff --git a/numpy/core/src/multiarray/multiarraymodule.c b/numpy/core/src/multiarray/multiarraymodule.c index 6ad0eb211..1f455f528 100644 --- a/numpy/core/src/multiarray/multiarraymodule.c +++ b/numpy/core/src/multiarray/multiarraymodule.c @@ -1517,26 +1517,18 @@ PyArray_EquivTypenums(int typenum1, int typenum2) /*** END C-API FUNCTIONS **/ static PyObject * -_prepend_ones(PyArrayObject *arr, int nd, int ndmin, NPY_ORDER order) +_prepend_ones(PyArrayObject *arr, int nd, int ndmin) { npy_intp newdims[NPY_MAXDIMS]; npy_intp newstrides[NPY_MAXDIMS]; - npy_intp newstride; int i, k, num; PyArrayObject *ret; PyArray_Descr *dtype; - if (order == NPY_FORTRANORDER || PyArray_ISFORTRAN(arr) || PyArray_NDIM(arr) == 0) { - newstride = PyArray_DESCR(arr)->elsize; - } - else { - newstride = PyArray_STRIDES(arr)[0] * PyArray_DIMS(arr)[0]; - } - num = ndmin - nd; for (i = 0; i < num; i++) { newdims[i] = 1; - newstrides[i] = newstride; + newstrides[i] = PyArray_DESCR(arr)->elsize; } for (i = num; i < ndmin; i++) { k = i - num; @@ -1566,8 +1558,8 @@ _prepend_ones(PyArrayObject *arr, int nd, int ndmin, NPY_ORDER order) #define STRIDING_OK(op, order) \ ((order) == NPY_ANYORDER || \ (order) == NPY_KEEPORDER || \ - ((order) == NPY_CORDER && PyArray_ISCONTIGUOUS(op)) || \ - ((order) == NPY_FORTRANORDER && PyArray_ISFORTRAN(op))) + ((order) == NPY_CORDER && PyArray_IS_C_CONTIGUOUS(op)) || \ + ((order) == NPY_FORTRANORDER && PyArray_IS_F_CONTIGUOUS(op))) static PyObject * _array_fromobject(PyObject *NPY_UNUSED(ignored), PyObject *args, PyObject *kws) @@ -1677,7 +1669,7 @@ _array_fromobject(PyObject *NPY_UNUSED(ignored), PyObject *args, PyObject *kws) * create a new array from the same data with ones in the shape * steals a reference to ret */ - return _prepend_ones(ret, nd, ndmin, order); + return _prepend_ones(ret, nd, ndmin); clean_type: Py_XDECREF(type); diff --git a/numpy/core/src/multiarray/shape.c b/numpy/core/src/multiarray/shape.c index 2dcf53d55..482166598 100644 --- a/numpy/core/src/multiarray/shape.c +++ b/numpy/core/src/multiarray/shape.c @@ -18,10 +18,6 @@ #include "shape.h" static int -_check_ones(PyArrayObject *self, int newnd, - npy_intp* newdims, npy_intp *strides); - -static int _fix_unknown_dimension(PyArray_Dims *newshape, npy_intp s_original); static int @@ -187,6 +183,11 @@ PyArray_Newshape(PyArrayObject *self, PyArray_Dims *newdims, if (order == NPY_ANYORDER) { order = PyArray_ISFORTRAN(self); } + else if (order == NPY_KEEPORDER) { + PyErr_SetString(PyExc_ValueError, + "order 'K' is not permitted for reshaping"); + return NULL; + } /* Quick check to make sure anything actually needs to be done */ if (ndim == PyArray_NDIM(self)) { same = NPY_TRUE; @@ -203,94 +204,48 @@ PyArray_Newshape(PyArrayObject *self, PyArray_Dims *newdims, } /* - * Returns a pointer to an appropriate strides array - * if all we are doing is inserting ones into the shape, - * or removing ones from the shape - * or doing a combination of the two - * In this case we don't need to do anything but update strides and - * dimensions. So, we can handle non single-segment cases. + * fix any -1 dimensions and check new-dimensions against old size */ - i = _check_ones(self, ndim, dimensions, newstrides); - if (i == 0) { - strides = newstrides; + if (_fix_unknown_dimension(newdims, PyArray_SIZE(self)) < 0) { + return NULL; } - flags = PyArray_FLAGS(self); - - if (strides == NULL) { - /* - * we are really re-shaping not just adding ones to the shape somewhere - * fix any -1 dimensions and check new-dimensions against old size - */ - if (_fix_unknown_dimension(newdims, PyArray_SIZE(self)) < 0) { - return NULL; - } - /* - * sometimes we have to create a new copy of the array - * in order to get the right orientation and - * because we can't just re-use the buffer with the - * data in the order it is in. - */ - if (!(PyArray_ISONESEGMENT(self)) || - (((PyArray_CHKFLAGS(self, NPY_ARRAY_C_CONTIGUOUS) && - order == NPY_FORTRANORDER) || - (PyArray_CHKFLAGS(self, NPY_ARRAY_F_CONTIGUOUS) && - order == NPY_CORDER)) && (PyArray_NDIM(self) > 1))) { - int success = 0; - success = _attempt_nocopy_reshape(self, ndim, dimensions, - newstrides, order); - if (success) { - /* no need to copy the array after all */ - strides = newstrides; - } - else { - PyObject *newcopy; - newcopy = PyArray_NewCopy(self, order); - if (newcopy == NULL) { - return NULL; - } - incref = NPY_FALSE; - self = (PyArrayObject *)newcopy; - } + /* + * sometimes we have to create a new copy of the array + * in order to get the right orientation and + * because we can't just re-use the buffer with the + * data in the order it is in. + */ + if ((order == NPY_CORDER && !PyArray_IS_C_CONTIGUOUS(self)) || + (order == NPY_FORTRANORDER && !PyArray_IS_F_CONTIGUOUS(self))) { + int success = 0; + success = _attempt_nocopy_reshape(self, ndim, dimensions, + newstrides, order); + if (success) { + /* no need to copy the array after all */ + strides = newstrides; } - - /* We always have to interpret the contiguous buffer correctly */ - - /* Make sure the flags argument is set. */ - if (ndim > 1) { - if (order == NPY_FORTRANORDER) { - flags &= ~NPY_ARRAY_C_CONTIGUOUS; - flags |= NPY_ARRAY_F_CONTIGUOUS; - } - else { - flags &= ~NPY_ARRAY_F_CONTIGUOUS; - flags |= NPY_ARRAY_C_CONTIGUOUS; + else { + PyObject *newcopy; + newcopy = PyArray_NewCopy(self, order); + if (newcopy == NULL) { + return NULL; } + incref = NPY_FALSE; + self = (PyArrayObject *)newcopy; } } - else if (ndim > 0) { - /* - * replace any 0-valued strides with - * appropriate value to preserve contiguousness - */ + /* We always have to interpret the contiguous buffer correctly */ + + /* Make sure the flags argument is set. */ + flags = PyArray_FLAGS(self); + if (ndim > 1) { if (order == NPY_FORTRANORDER) { - if (dimensions[0] == 1) { - strides[0] = PyArray_DESCR(self)->elsize; - } - for (i = 1; i < ndim; i++) { - if (dimensions[i] == 1) { - strides[i] = strides[i-1] * dimensions[i-1]; - } - } + flags &= ~NPY_ARRAY_C_CONTIGUOUS; + flags |= NPY_ARRAY_F_CONTIGUOUS; } else { - if (dimensions[ndim-1] == 1) { - strides[ndim-1] = PyArray_DESCR(self)->elsize; - } - for (i = ndim - 2; i > -1; i--) { - if (dimensions[i] == 1) { - strides[i] = strides[i+1] * dimensions[i+1]; - } - } + flags &= ~NPY_ARRAY_F_CONTIGUOUS; + flags |= NPY_ARRAY_C_CONTIGUOUS; } } @@ -345,41 +300,6 @@ PyArray_Reshape(PyArrayObject *self, PyObject *shape) return ret; } -/* inserts 0 for strides where dimension will be 1 */ -static int -_check_ones(PyArrayObject *self, int newnd, - npy_intp* newdims, npy_intp *strides) -{ - int nd; - npy_intp *dims; - npy_bool done=NPY_FALSE; - int j, k; - - nd = PyArray_NDIM(self); - dims = PyArray_DIMS(self); - - for (k = 0, j = 0; !done && (j < nd || k < newnd);) { - if ((j<nd) && (k<newnd) && (newdims[k] == dims[j])) { - strides[k] = PyArray_STRIDES(self)[j]; - j++; - k++; - } - else if ((k < newnd) && (newdims[k] == 1)) { - strides[k] = 0; - k++; - } - else if ((j<nd) && (dims[j] == 1)) { - j++; - } - else { - done = NPY_TRUE; - } - } - if (done) { - return -1; - } - return 0; -} static void _putzero(char *optr, PyObject *zero, PyArray_Descr *dtype) @@ -849,7 +769,7 @@ int _npy_stride_sort_item_comparator(const void *a, const void *b) bstride = -bstride; } - if (astride == bstride || astride == 0 || bstride == 0) { + if (astride == bstride) { /* * Make the qsort stable by next comparing the perm order. * (Note that two perm entries will never be equal) @@ -861,9 +781,7 @@ int _npy_stride_sort_item_comparator(const void *a, const void *b) if (astride > bstride) { return -1; } - else { - return 1; - } + return 1; } /*NUMPY_API @@ -874,8 +792,7 @@ int _npy_stride_sort_item_comparator(const void *a, const void *b) * [(2, 12), (0, 4), (1, -2)]. */ NPY_NO_EXPORT void -PyArray_CreateSortedStridePerm(int ndim, npy_intp *shape, - npy_intp *strides, +PyArray_CreateSortedStridePerm(int ndim, npy_intp *strides, npy_stride_sort_item *out_strideperm) { int i; @@ -883,12 +800,7 @@ PyArray_CreateSortedStridePerm(int ndim, npy_intp *shape, /* Set up the strideperm values */ for (i = 0; i < ndim; ++i) { out_strideperm[i].perm = i; - if (shape[i] == 1) { - out_strideperm[i].stride = 0; - } - else { - out_strideperm[i].stride = strides[i]; - } + out_strideperm[i].stride = strides[i]; } /* Sort them */ @@ -1015,10 +927,10 @@ PyArray_Ravel(PyArrayObject *arr, NPY_ORDER order) } } - if (order == NPY_CORDER && PyArray_ISCONTIGUOUS(arr)) { + if (order == NPY_CORDER && PyArray_IS_C_CONTIGUOUS(arr)) { return PyArray_Newshape(arr, &newdim, NPY_CORDER); } - else if (order == NPY_FORTRANORDER && PyArray_ISFORTRAN(arr)) { + else if (order == NPY_FORTRANORDER && PyArray_IS_F_CONTIGUOUS(arr)) { return PyArray_Newshape(arr, &newdim, NPY_FORTRANORDER); } /* For KEEPORDER, check if we can make a flattened view */ @@ -1027,7 +939,7 @@ PyArray_Ravel(PyArrayObject *arr, NPY_ORDER order) npy_intp stride; int i, ndim = PyArray_NDIM(arr); - PyArray_CreateSortedStridePerm(PyArray_NDIM(arr), PyArray_SHAPE(arr), + PyArray_CreateSortedStridePerm(PyArray_NDIM(arr), PyArray_STRIDES(arr), strideperm); stride = strideperm[ndim-1].stride; @@ -1164,6 +1076,8 @@ build_shape_string(npy_intp n, npy_intp *vals) * WARNING: If an axis flagged for removal has a shape equal to zero, * the array will point to invalid memory. The caller must * validate this! + * If an axis flagged for removal has a shape larger then one, + * the arrays contiguous flags may require updating. * * For example, this can be used to remove the reduction axes * from a reduction result once its computation is complete. @@ -1186,7 +1100,4 @@ PyArray_RemoveAxesInPlace(PyArrayObject *arr, npy_bool *flags) /* The final number of dimensions */ fa->nd = idim_out; - - /* Update contiguous flags */ - PyArray_UpdateFlags(arr, NPY_ARRAY_C_CONTIGUOUS | NPY_ARRAY_F_CONTIGUOUS); } diff --git a/numpy/core/src/private/lowlevel_strided_loops.h b/numpy/core/src/private/lowlevel_strided_loops.h index a73dd12cf..94c6a2121 100644 --- a/numpy/core/src/private/lowlevel_strided_loops.h +++ b/numpy/core/src/private/lowlevel_strided_loops.h @@ -552,10 +552,10 @@ PyArray_PrepareThreeRawArrayIter(int ndim, npy_intp *shape, count = PyArray_SIZE(arr), \ data = PyArray_BYTES(arr), \ stride = ((PyArray_NDIM(arr) == 0) ? 0 : \ - (PyArray_CHKFLAGS(arr, NPY_ARRAY_F_CONTIGUOUS) ? \ + ((PyArray_NDIM(arr) == 1) ? \ PyArray_STRIDE(arr, 0) : \ - PyArray_STRIDE(arr, \ - PyArray_NDIM(arr)-1))) + PyArray_ITEMSIZE(arr))) \ + #define PyArray_TRIVIALLY_ITERABLE_PAIR(arr1, arr2) (\ PyArray_TRIVIALLY_ITERABLE(arr1) && \ @@ -575,16 +575,12 @@ PyArray_PrepareThreeRawArrayIter(int ndim, npy_intp *shape, count = ((size1 > size2) || size1 == 0) ? size1 : size2; \ data1 = PyArray_BYTES(arr1); \ data2 = PyArray_BYTES(arr2); \ - stride1 = (size1 == 1 ? 0 : \ - (PyArray_CHKFLAGS(arr1, NPY_ARRAY_F_CONTIGUOUS) ? \ - PyArray_STRIDE(arr1, 0) : \ - PyArray_STRIDE(arr1, \ - PyArray_NDIM(arr1)-1))); \ - stride2 = (size2 == 1 ? 0 : \ - (PyArray_CHKFLAGS(arr2, NPY_ARRAY_F_CONTIGUOUS) ? \ - PyArray_STRIDE(arr2, 0) : \ - PyArray_STRIDE(arr2, \ - PyArray_NDIM(arr2)-1))); \ + stride1 = (size1 == 1 ? 0 : ((PyArray_NDIM(arr1) == 1) ? \ + PyArray_STRIDE(arr1, 0) : \ + PyArray_ITEMSIZE(arr1))); \ + stride2 = (size2 == 1 ? 0 : ((PyArray_NDIM(arr2) == 1) ? \ + PyArray_STRIDE(arr2, 0) : \ + PyArray_ITEMSIZE(arr2))); \ } #define PyArray_TRIVIALLY_ITERABLE_TRIPLE(arr1, arr2, arr3) (\ @@ -620,21 +616,15 @@ PyArray_PrepareThreeRawArrayIter(int ndim, npy_intp *shape, data1 = PyArray_BYTES(arr1); \ data2 = PyArray_BYTES(arr2); \ data3 = PyArray_BYTES(arr3); \ - stride1 = (size1 == 1 ? 0 : \ - (PyArray_CHKFLAGS(arr1, NPY_ARRAY_F_CONTIGUOUS) ? \ - PyArray_STRIDE(arr1, 0) : \ - PyArray_STRIDE(arr1, \ - PyArray_NDIM(arr1)-1))); \ - stride2 = (size2 == 1 ? 0 : \ - (PyArray_CHKFLAGS(arr2, NPY_ARRAY_F_CONTIGUOUS) ? \ - PyArray_STRIDE(arr2, 0) : \ - PyArray_STRIDE(arr2, \ - PyArray_NDIM(arr2)-1))); \ - stride3 = (size3 == 1 ? 0 : \ - (PyArray_CHKFLAGS(arr3, NPY_ARRAY_F_CONTIGUOUS) ? \ - PyArray_STRIDE(arr3, 0) : \ - PyArray_STRIDE(arr3, \ - PyArray_NDIM(arr3)-1))); \ + stride1 = (size1 == 1 ? 0 : ((PyArray_NDIM(arr1) == 1) ? \ + PyArray_STRIDE(arr1, 0) : \ + PyArray_ITEMSIZE(arr1))); \ + stride2 = (size2 == 1 ? 0 : ((PyArray_NDIM(arr2) == 1) ? \ + PyArray_STRIDE(arr2, 0) : \ + PyArray_ITEMSIZE(arr2))); \ + stride3 = (size3 == 1 ? 0 : ((PyArray_NDIM(arr3) == 1) ? \ + PyArray_STRIDE(arr3, 0) : \ + PyArray_ITEMSIZE(arr3))); \ } #endif diff --git a/numpy/core/src/umath/reduction.c b/numpy/core/src/umath/reduction.c index 529d5523a..444682d57 100644 --- a/numpy/core/src/umath/reduction.c +++ b/numpy/core/src/umath/reduction.c @@ -51,7 +51,7 @@ allocate_reduce_result(PyArrayObject *arr, npy_bool *axis_flags, Py_INCREF(dtype); } - PyArray_CreateSortedStridePerm(PyArray_NDIM(arr), PyArray_SHAPE(arr), + PyArray_CreateSortedStridePerm(PyArray_NDIM(arr), PyArray_STRIDES(arr), strideperm); /* Build the new strides and shape */ diff --git a/numpy/core/tests/test_api.py b/numpy/core/tests/test_api.py index 3c365992b..df26dd07a 100644 --- a/numpy/core/tests/test_api.py +++ b/numpy/core/tests/test_api.py @@ -138,9 +138,9 @@ def test_copyto(): assert_raises(TypeError, np.copyto, [1,2,3], [2,3,4]) def test_copy_order(): - a = np.arange(24).reshape(2,3,4) + a = np.arange(24).reshape(2,1,3,4) b = a.copy(order='F') - c = np.arange(24).reshape(2,4,3).swapaxes(1,2) + c = np.arange(24).reshape(2,1,4,3).swapaxes(2,3) def check_copy_result(x, y, ccontig, fcontig, strides=False): assert_(not (x is y)) @@ -202,5 +202,37 @@ def test_copy_order(): res = np.copy(c, order='K') check_copy_result(res, c, ccontig=False, fcontig=False, strides=True) +def test_contiguous_flags(): + a = np.ones((4,4,1))[::2,:,:] + a.strides = a.strides[:2] + (-123,) + b = np.ones((2,2,1,2,2)).swapaxes(3,4) + + def check_contig(a, ccontig, fcontig): + assert_(a.flags.c_contiguous == ccontig) + assert_(a.flags.f_contiguous == fcontig) + + # Check if new arrays are correct: + check_contig(a, False, False) + check_contig(b, False, False) + check_contig(np.empty((2,2,0,2,2)), True, True) + check_contig(np.array([[[1],[2]]], order='F'), True, True) + check_contig(np.empty((2,2)), True, False) + check_contig(np.empty((2,2), order='F'), False, True) + + # Check that np.array creates correct contiguous flags: + check_contig(np.array(a, copy=False), False, False) + check_contig(np.array(a, copy=False, order='C'), True, False) + check_contig(np.array(a, ndmin=4, copy=False, order='F'), False, True) + + # Check slicing update of flags and : + check_contig(a[0], True, True) + check_contig(a[None,::4,...,None], True, True) + check_contig(b[0,0,...], False, True) + check_contig(b[:,:,0:0,:,:], True, True) + + # Test ravel and squeeze. + check_contig(a.ravel(), True, True) + check_contig(np.ones((1,3,1)).squeeze(), True, True) + if __name__ == "__main__": run_module_suite() diff --git a/numpy/core/tests/test_regression.py b/numpy/core/tests/test_regression.py index 8056c2cfc..0f268fce8 100644 --- a/numpy/core/tests/test_regression.py +++ b/numpy/core/tests/test_regression.py @@ -61,6 +61,16 @@ class TestRegression(TestCase): np.zeros([3], order='C') np.zeros([3], int, order='C') + def test_asarray_with_order(self,level=rlevel): + """Check that nothing is done when order='F' and array C/F-contiguous""" + a = np.ones(2) + assert_(a is np.asarray(a, order='F')) + + def test_ravel_with_order(self,level=rlevel): + """Check that ravel works when order='F' and array C/F-contiguous""" + a = np.ones(2) + assert_(not a.ravel('F').flags.owndata) + def test_sort_bigendian(self,level=rlevel): """Ticket #47""" a = np.linspace(0, 10, 11) @@ -511,6 +521,11 @@ class TestRegression(TestCase): a = np.lib.stride_tricks.as_strided(a, shape=(5,), strides=(0,)) assert_(a.reshape(5,1).strides[0] == 0) + def test_reshape_zero_size(self, level=rlevel): + """Github Issue #2700, setting shape failed for 0-sized arrays""" + a = np.ones((0,2)) + a.shape = (-1,2) + def test_repeat_discont(self, level=rlevel): """Ticket #352""" a = np.arange(12).reshape(4,3)[:,2] diff --git a/numpy/ma/core.py b/numpy/ma/core.py index a6f252067..a7e04cd13 100644 --- a/numpy/ma/core.py +++ b/numpy/ma/core.py @@ -2948,12 +2948,10 @@ class MaskedArray(ndarray): # A record ................ if isinstance(dout, np.void): mask = _mask[indx] -# If we can make mvoid a subclass of np.void, that'd be what we'd need -# return mvoid(dout, mask=mask) - if flatten_mask(mask).any(): - dout = mvoid(dout, mask=mask) - else: - return dout + # We should always re-cast to mvoid, otherwise users can + # change masks on rows that already have masked values, but not + # on rows that have no masked values, which is inconsistent. + dout = mvoid(dout, mask=mask) # Just a scalar............ elif _mask is not nomask and _mask[indx]: return masked diff --git a/numpy/ma/tests/test_core.py b/numpy/ma/tests/test_core.py index 58f81b071..48ea6e4f9 100644 --- a/numpy/ma/tests/test_core.py +++ b/numpy/ma/tests/test_core.py @@ -626,7 +626,7 @@ class TestMaskedArray(TestCase): a = masked_array([(1, 2,), (3, 4)], mask=[(0, 0), (1, 0)], dtype=ndtype) # w/o mask f = a[0] - self.assertTrue(isinstance(f, np.void)) + self.assertTrue(isinstance(f, mvoid)) assert_equal((f[0], f['a']), (1, 1)) assert_equal(f['b'], 2) # w/ mask @@ -3443,7 +3443,7 @@ class TestMaskedFields(TestCase): [1, 0, 0, 0, 0, 0, 0, 0, 1, 0]), dtype=[('a', bool), ('b', bool)]) # No mask - self.assertTrue(isinstance(a[1], np.void)) + self.assertTrue(isinstance(a[1], MaskedArray)) # One element masked self.assertTrue(isinstance(a[0], MaskedArray)) assert_equal_records(a[0]._data, a._data[0]) @@ -3503,7 +3503,7 @@ class TestMaskedView(TestCase): assert_equal(test['B'], a['b'][0]) # test = a[-1].view([('A', float), ('B', float)]) - self.assertTrue(not isinstance(test, MaskedArray)) + self.assertTrue(isinstance(test, MaskedArray)) assert_equal(test.dtype.names, ('A', 'B')) assert_equal(test['A'], a['a'][-1]) assert_equal(test['B'], a['b'][-1]) @@ -3523,7 +3523,7 @@ class TestMaskedView(TestCase): assert_equal(test.mask, (1, 0)) # View on 1 unmasked element test = a[-1].view((float, 2)) - self.assertTrue(not isinstance(test, MaskedArray)) + self.assertTrue(isinstance(test, MaskedArray)) assert_equal(test, data[-1]) # def test_view_to_dtype_and_type(self): diff --git a/numpy/tests/test_ctypeslib.py b/numpy/tests/test_ctypeslib.py index e9729a676..ac351191a 100644 --- a/numpy/tests/test_ctypeslib.py +++ b/numpy/tests/test_ctypeslib.py @@ -86,14 +86,14 @@ class TestNdpointer(TestCase): self.assertTrue(p.from_param(np.array(1))) def test_flags(self): - x = np.array([[1,2,3]], order='F') + x = np.array([[1,2],[3,4]], order='F') p = ndpointer(flags='FORTRAN') self.assertTrue(p.from_param(x)) p = ndpointer(flags='CONTIGUOUS') self.assertRaises(TypeError, p.from_param, x) p = ndpointer(flags=x.flags.num) self.assertTrue(p.from_param(x)) - self.assertRaises(TypeError, p.from_param, np.array([[1,2,3]])) + self.assertRaises(TypeError, p.from_param, np.array([[1,2],[3,4]])) if __name__ == "__main__": |