diff --git a/numpy/add_newdocs.py b/numpy/add_newdocs.py index 711b7de524f8..7bd24b45ea06 100644 --- a/numpy/add_newdocs.py +++ b/numpy/add_newdocs.py @@ -3247,17 +3247,21 @@ def luf(lamdaexpr, *args, **kwargs): add_newdoc('numpy.core.multiarray', 'ndarray', ('copy', """ - a.copy(order='C') + a.copy(order='C', maskna=None) Return a copy of the array. Parameters ---------- - order : {'C', 'F', 'A'}, optional - By default, the result is stored in C-contiguous (row-major) order in - memory. If `order` is `F`, the result has 'Fortran' (column-major) - order. If order is 'A' ('Any'), then the result has the same order - as the input. + order : {'C', 'F', 'A', 'K'}, optional + Controls the memory layout of the copy. 'C' means C-order, + 'F' means F-order, 'A' means 'F' if `a` is Fortran contiguous, + 'C' otherwise. 'K' means match the layout of `a` as closely + as possible. + maskna : bool, optional + If specifies, forces the copy to have or to not have an + NA mask. This is a way to remove an NA mask from an array + while making a copy. See also -------- diff --git a/numpy/core/src/multiarray/convert.c b/numpy/core/src/multiarray/convert.c index 5640f197896b..bbadd3847afe 100644 --- a/numpy/core/src/multiarray/convert.c +++ b/numpy/core/src/multiarray/convert.c @@ -515,8 +515,9 @@ PyArray_AssignOne(PyArrayObject *dst, NPY_NO_EXPORT PyObject * PyArray_NewCopy(PyArrayObject *obj, NPY_ORDER order) { - PyArrayObject *ret = (PyArrayObject *)PyArray_NewLikeArray( - obj, order, NULL, 1); + PyArrayObject *ret; + + ret = (PyArrayObject *)PyArray_NewLikeArray(obj, order, NULL, 1); if (ret == NULL) { return NULL; } @@ -528,7 +529,7 @@ PyArray_NewCopy(PyArrayObject *obj, NPY_ORDER order) } } - if (PyArray_CopyInto(ret, obj) == -1) { + if (PyArray_AssignArray(ret, obj, NULL, NPY_UNSAFE_CASTING, 0, NULL) < 0) { Py_DECREF(ret); return NULL; } diff --git a/numpy/core/src/multiarray/ctors.c b/numpy/core/src/multiarray/ctors.c index 03c035615ec3..2b1edd000c74 100644 --- a/numpy/core/src/multiarray/ctors.c +++ b/numpy/core/src/multiarray/ctors.c @@ -1856,16 +1856,7 @@ PyArray_FromAny(PyObject *op, PyArray_Descr *newtype, int min_depth, ret = NULL; } else { - if (PyArray_HASMASKNA((PyArrayObject *)arr) && - (flags & NPY_ARRAY_ALLOWNA) == 0) { - PyErr_SetString(PyExc_ValueError, - "this operation does not support " - "arrays with NA masks"); - ret = NULL; - } - else { - ret = (PyArrayObject *)PyArray_FromArray(arr, newtype, flags); - } + ret = (PyArrayObject *)PyArray_FromArray(arr, newtype, flags); Py_DECREF(arr); } } @@ -1962,13 +1953,12 @@ PyArray_FromArray(PyArrayObject *arr, PyArray_Descr *newtype, int flags) int copy = 0; int arrflags; PyArray_Descr *oldtype; - PyTypeObject *subtype; NPY_CASTING casting = NPY_SAFE_CASTING; oldtype = PyArray_DESCR(arr); - subtype = Py_TYPE(arr); if (newtype == NULL) { - newtype = oldtype; Py_INCREF(oldtype); + newtype = oldtype; + Py_INCREF(oldtype); } itemsize = newtype->elsize; if (itemsize == 0) { @@ -2005,141 +1995,79 @@ PyArray_FromArray(PyArrayObject *arr, PyArray_Descr *newtype, int flags) return NULL; } - /* Don't copy if sizes are compatible */ - if ((flags & NPY_ARRAY_ENSURECOPY) || - PyArray_EquivTypes(oldtype, newtype)) { - arrflags = PyArray_FLAGS(arr); - if (PyArray_NDIM(arr) <= 1 && (flags & NPY_ARRAY_F_CONTIGUOUS)) { - flags |= NPY_ARRAY_C_CONTIGUOUS; - } - copy = (flags & NPY_ARRAY_ENSURECOPY) || - ((flags & NPY_ARRAY_C_CONTIGUOUS) && - (!(arrflags & NPY_ARRAY_C_CONTIGUOUS))) - || ((flags & NPY_ARRAY_ALIGNED) && - (!(arrflags & NPY_ARRAY_ALIGNED))) - || (PyArray_NDIM(arr) > 1 && - ((flags & NPY_ARRAY_F_CONTIGUOUS) && - (!(arrflags & NPY_ARRAY_F_CONTIGUOUS)))) - || ((flags & NPY_ARRAY_WRITEABLE) && - (!(arrflags & NPY_ARRAY_WRITEABLE))); - - if (copy) { - if ((flags & NPY_ARRAY_UPDATEIFCOPY) && - (!PyArray_ISWRITEABLE(arr))) { - Py_DECREF(newtype); - PyErr_SetString(PyExc_ValueError, - "cannot copy back to a read-only array"); - return NULL; - } - if ((flags & NPY_ARRAY_ENSUREARRAY)) { - subtype = &PyArray_Type; - } - ret = (PyArrayObject *) - PyArray_NewFromDescr(subtype, newtype, - PyArray_NDIM(arr), - PyArray_DIMS(arr), - NULL, NULL, - flags & NPY_ARRAY_F_CONTIGUOUS, - (PyObject *)arr); - if (ret == NULL) { - return NULL; - } - - /* Allocate an NA mask if necessary from the input */ - if (PyArray_HASMASKNA(arr)) { - if (PyArray_AllocateMaskNA(ret, 1, 0, 1) < 0) { - Py_DECREF(ret); - return NULL; - } - } - - if (PyArray_CopyInto(ret, arr) < 0) { - Py_DECREF(ret); - return NULL; - } + arrflags = PyArray_FLAGS(arr); + if (PyArray_NDIM(arr) <= 1 && (flags & NPY_ARRAY_F_CONTIGUOUS)) { + flags |= NPY_ARRAY_C_CONTIGUOUS; + } + copy = (flags & NPY_ARRAY_ENSURECOPY) || + ((flags & NPY_ARRAY_C_CONTIGUOUS) && + (!(arrflags & NPY_ARRAY_C_CONTIGUOUS))) + || ((flags & NPY_ARRAY_ALIGNED) && + (!(arrflags & NPY_ARRAY_ALIGNED))) + || (PyArray_NDIM(arr) > 1 && + ((flags & NPY_ARRAY_F_CONTIGUOUS) && + (!(arrflags & NPY_ARRAY_F_CONTIGUOUS)))) + || ((flags & NPY_ARRAY_WRITEABLE) && + (!(arrflags & NPY_ARRAY_WRITEABLE))) || + !PyArray_EquivTypes(oldtype, newtype); - /* Allocate an NA mask if requested but wasn't from the input */ - if ((flags & (NPY_ARRAY_MASKNA | NPY_ARRAY_OWNMASKNA)) != 0 && - !PyArray_HASMASKNA(ret)) { - if (PyArray_AllocateMaskNA(ret, 1, 0, 1) < 0) { - Py_DECREF(ret); - return NULL; - } - } + if (copy) { + NPY_ORDER order = NPY_KEEPORDER; + int subok = 1; - if (flags & NPY_ARRAY_UPDATEIFCOPY) { - /* - * Don't use PyArray_SetBaseObject, because that compresses - * the chain of bases. - */ - Py_INCREF(arr); - ((PyArrayObject_fieldaccess *)ret)->base = (PyObject *)arr; - PyArray_ENABLEFLAGS(ret, NPY_ARRAY_UPDATEIFCOPY); - PyArray_CLEARFLAGS(arr, NPY_ARRAY_WRITEABLE); - } + /* Set the order for the copy being made based on the flags */ + if (flags & NPY_ARRAY_F_CONTIGUOUS) { + order = NPY_FORTRANORDER; } - /* - * If no copy then just increase the reference - * count and return the input - */ - else { - Py_DECREF(newtype); - if ((flags & NPY_ARRAY_ENSUREARRAY) && - !PyArray_CheckExact(arr)) { - PyArray_Descr *dtype = PyArray_DESCR(arr); - Py_INCREF(dtype); - ret = (PyArrayObject *) - PyArray_NewFromDescr(&PyArray_Type, - dtype, - PyArray_NDIM(arr), - PyArray_DIMS(arr), - PyArray_STRIDES(arr), - PyArray_DATA(arr), - PyArray_FLAGS(arr), - NULL); - if (ret == NULL) { - return NULL; - } - if (PyArray_SetBaseObject(ret, (PyObject *)arr)) { - Py_DECREF(ret); - return NULL; - } - } - else { - ret = arr; - } - Py_INCREF(arr); + else if (flags & NPY_ARRAY_C_CONTIGUOUS) { + order = NPY_CORDER; } - } - /* - * The desired output type is different than the input - * array type and copy was not specified - */ - else { if ((flags & NPY_ARRAY_UPDATEIFCOPY) && (!PyArray_ISWRITEABLE(arr))) { Py_DECREF(newtype); PyErr_SetString(PyExc_ValueError, - "cannot copy back to a read-only array B"); + "cannot copy back to a read-only array"); return NULL; } if ((flags & NPY_ARRAY_ENSUREARRAY)) { - subtype = &PyArray_Type; + subok = 0; } - ret = (PyArrayObject *) - PyArray_NewFromDescr(subtype, newtype, - PyArray_NDIM(arr), PyArray_DIMS(arr), - NULL, NULL, - flags & NPY_ARRAY_F_CONTIGUOUS, - (PyObject *)arr); + ret = (PyArrayObject *)PyArray_NewLikeArray(arr, order, + newtype, subok); if (ret == NULL) { return NULL; } - if (PyArray_CastTo(ret, arr) < 0) { + + /* + * Allocate an NA mask if necessary from the input, + * is NAs are being allowed. + */ + if (PyArray_HASMASKNA(arr) && (flags & NPY_ARRAY_ALLOWNA)) { + if (PyArray_AllocateMaskNA(ret, 1, 0, 1) < 0) { + Py_DECREF(ret); + return NULL; + } + } + + /* + * If a ALLOWNA was not enabled, and 'arr' has an NA mask, + * this will raise an error if 'arr' contains any NA values. + */ + if (PyArray_CopyInto(ret, arr) < 0) { Py_DECREF(ret); return NULL; } + + /* Allocate an NA mask if requested but wasn't from the input */ + if ((flags & (NPY_ARRAY_MASKNA | NPY_ARRAY_OWNMASKNA)) != 0 && + !PyArray_HASMASKNA(ret)) { + if (PyArray_AllocateMaskNA(ret, 1, 0, 1) < 0) { + Py_DECREF(ret); + return NULL; + } + } + if (flags & NPY_ARRAY_UPDATEIFCOPY) { /* * Don't use PyArray_SetBaseObject, because that compresses @@ -2151,6 +2079,28 @@ PyArray_FromArray(PyArrayObject *arr, PyArray_Descr *newtype, int flags) PyArray_CLEARFLAGS(arr, NPY_ARRAY_WRITEABLE); } } + /* + * If no copy then just increase the reference + * count and return the input + */ + else { + Py_DECREF(newtype); + if ((flags & NPY_ARRAY_ENSUREARRAY) && + !PyArray_CheckExact(arr)) { + PyArray_Descr *dtype = PyArray_DESCR(arr); + Py_INCREF(dtype); + + ret = (PyArrayObject *)PyArray_View(arr, NULL, &PyArray_Type); + if (ret == NULL) { + return NULL; + } + } + else { + ret = arr; + } + Py_INCREF(arr); + } + return (PyObject *)ret; } diff --git a/numpy/core/src/multiarray/methods.c b/numpy/core/src/multiarray/methods.c index 754d7161fd05..8ea186ead13c 100644 --- a/numpy/core/src/multiarray/methods.c +++ b/numpy/core/src/multiarray/methods.c @@ -1009,14 +1009,53 @@ static PyObject * array_copy(PyArrayObject *self, PyObject *args, PyObject *kwds) { PyArray_ORDER order = NPY_CORDER; - static char *kwlist[] = {"order", NULL}; + PyObject *maskna_in = Py_None; + int maskna = -1; + static char *kwlist[] = {"order", "maskna", NULL}; + PyArrayObject *ret; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O&", kwlist, - PyArray_OrderConverter, &order)) { + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O&O", kwlist, + PyArray_OrderConverter, &order, + &maskna_in)) { return NULL; } - return PyArray_NewCopy(self, order); + /* Treat None the same as not providing the parameter */ + if (maskna_in != Py_None) { + maskna = PyObject_IsTrue(maskna_in); + if (maskna == -1) { + return NULL; + } + } + + /* If maskna=False was passed and self has an NA mask, strip it away */ + if (maskna == 0 && PyArray_HASMASKNA(self)) { + /* An array with no NA mask */ + ret = (PyArrayObject *)PyArray_NewLikeArray(self, order, NULL, 1); + if (ret == NULL) { + return NULL; + } + + /* AssignArray validates that 'self' contains no NA values */ + if (PyArray_AssignArray(ret, self, NULL, NPY_UNSAFE_CASTING, + 0, NULL) < 0) { + Py_DECREF(ret); + return NULL; + } + } + else { + ret = (PyArrayObject *)PyArray_NewCopy(self, order); + + /* Add the NA mask if requested */ + if (ret != NULL && maskna == 1) { + if (PyArray_AllocateMaskNA(ret, 1, 0, 1) < 0) { + Py_DECREF(ret); + return NULL; + } + } + } + + return (PyObject *)ret; } #include diff --git a/numpy/core/src/multiarray/multiarraymodule.c b/numpy/core/src/multiarray/multiarraymodule.c index 566036146975..74ef05d503c2 100644 --- a/numpy/core/src/multiarray/multiarraymodule.c +++ b/numpy/core/src/multiarray/multiarraymodule.c @@ -1610,8 +1610,9 @@ _array_fromobject(PyObject *NPY_UNUSED(ignored), PyObject *args, PyObject *kws) int ndmin = 0, nd; PyArray_Descr *type = NULL; PyArray_Descr *oldtype = NULL; - NPY_ORDER order = NPY_ANYORDER; - int flags = 0, maskna = 0, ownmaskna = 0; + NPY_ORDER order = NPY_KEEPORDER; + int flags = 0, maskna = -1, ownmaskna = 0; + PyObject *maskna_in = Py_None; static char *kwd[]= {"object", "dtype", "copy", "order", "subok", "ndmin", "maskna", "ownmaskna", NULL}; @@ -1621,21 +1622,39 @@ _array_fromobject(PyObject *NPY_UNUSED(ignored), PyObject *args, PyObject *kws) "only 2 non-keyword arguments accepted"); return NULL; } - if(!PyArg_ParseTupleAndKeywords(args, kws, "O|O&O&O&O&iii", kwd, + if(!PyArg_ParseTupleAndKeywords(args, kws, "O|O&O&O&O&iOi", kwd, &op, PyArray_DescrConverter2, &type, PyArray_BoolConverter, ©, PyArray_OrderConverter, &order, PyArray_BoolConverter, &subok, &ndmin, - &maskna, + &maskna_in, &ownmaskna)) { goto clean_type; } + /* + * Treat None the same as not providing the parameter, set + * maskna to -1 (unprovided), 0 (False), or 1 (True). + */ + if (maskna_in != Py_None) { + maskna = PyObject_IsTrue(maskna_in); + if (maskna == -1) { + return NULL; + } + } + /* 'ownmaskna' forces 'maskna' to be True */ if (ownmaskna) { - maskna = 1; + if (maskna == 0) { + PyErr_SetString(PyExc_ValueError, + "cannot specify maskna=False and ownmaskna=True"); + return NULL; + } + else { + maskna = 1; + } } if (ndmin > NPY_MAXDIMS) { @@ -1647,8 +1666,9 @@ _array_fromobject(PyObject *NPY_UNUSED(ignored), PyObject *args, PyObject *kws) /* fast exit if simple call */ if (((subok && PyArray_Check(op)) || (!subok && PyArray_CheckExact(op))) && - ((maskna && PyArray_HASMASKNA((PyArrayObject *)op)) || - (!maskna && !PyArray_HASMASKNA((PyArrayObject *)op)))) { + ((maskna == -1) || + (maskna == 1 && PyArray_HASMASKNA((PyArrayObject *)op)) || + (maskna == 0 && !PyArray_HASMASKNA((PyArrayObject *)op)))) { oparr = (PyArrayObject *)op; if (type == NULL) { if (!copy && STRIDING_OK(oparr, order)) { @@ -1715,14 +1735,25 @@ _array_fromobject(PyObject *NPY_UNUSED(ignored), PyObject *args, PyObject *kws) if (!subok) { flags |= NPY_ARRAY_ENSUREARRAY; } - if (maskna) { - flags |= NPY_ARRAY_MASKNA; + + /* If maskna is the default, allow NA to pass through */ + if (maskna == -1) { + flags |= NPY_ARRAY_ALLOWNA; } - if (ownmaskna) { - flags |= NPY_ARRAY_OWNMASKNA; + /* If maskna is True, force there to be an NA mask */ + else if (maskna == 1) { + flags |= NPY_ARRAY_MASKNA | NPY_ARRAY_ALLOWNA; + if (ownmaskna) { + flags |= NPY_ARRAY_OWNMASKNA; + } } + /* + * Otherwise maskna is False, so we don't specify NPY_ARRAY_ALLOWNA. + * An array with an NA mask will cause a copy into an array + * without an NA mask + */ - flags |= (NPY_ARRAY_FORCECAST | NPY_ARRAY_ALLOWNA); + flags |= NPY_ARRAY_FORCECAST; Py_XINCREF(type); ret = (PyArrayObject *)PyArray_CheckFromAny(op, type, 0, 0, flags, NULL); diff --git a/numpy/core/tests/test_api.py b/numpy/core/tests/test_api.py index 2c98810facad..55d3c4ea8e43 100644 --- a/numpy/core/tests/test_api.py +++ b/numpy/core/tests/test_api.py @@ -240,5 +240,70 @@ def test_copyto_maskna(): assert_equal(a_orig, [[0,3,3],[3,4,12]]) assert_equal(np.isna(a), [[0,1,0],[1,1,1]]) +def test_copy_order(): + a = np.arange(24).reshape(2,3,4) + b = a.copy(order='F') + c = np.arange(24).reshape(2,4,3).swapaxes(1,2) + + def check_copy_result(x, y, ccontig, fcontig, strides=False): + assert_(not (x is y)) + assert_equal(x, y) + assert_equal(res.flags.c_contiguous, ccontig) + assert_equal(res.flags.f_contiguous, fcontig) + if strides: + assert_equal(x.strides, y.strides) + else: + assert_(x.strides != y.strides) + + # Validate the initial state of a, b, and c + assert_(a.flags.c_contiguous) + assert_(not a.flags.f_contiguous) + assert_(not b.flags.c_contiguous) + assert_(b.flags.f_contiguous) + assert_(not c.flags.c_contiguous) + assert_(not c.flags.f_contiguous) + + # Copy with order='C' + res = a.copy(order='C') + check_copy_result(res, a, ccontig=True, fcontig=False, strides=True) + res = b.copy(order='C') + check_copy_result(res, b, ccontig=True, fcontig=False, strides=False) + res = c.copy(order='C') + check_copy_result(res, c, ccontig=True, fcontig=False, strides=False) + res = np.copy(a, order='C') + check_copy_result(res, a, ccontig=True, fcontig=False, strides=True) + res = np.copy(b, order='C') + check_copy_result(res, b, ccontig=True, fcontig=False, strides=False) + res = np.copy(c, order='C') + check_copy_result(res, c, ccontig=True, fcontig=False, strides=False) + + # Copy with order='F' + res = a.copy(order='F') + check_copy_result(res, a, ccontig=False, fcontig=True, strides=False) + res = b.copy(order='F') + check_copy_result(res, b, ccontig=False, fcontig=True, strides=True) + res = c.copy(order='F') + check_copy_result(res, c, ccontig=False, fcontig=True, strides=False) + res = np.copy(a, order='F') + check_copy_result(res, a, ccontig=False, fcontig=True, strides=False) + res = np.copy(b, order='F') + check_copy_result(res, b, ccontig=False, fcontig=True, strides=True) + res = np.copy(c, order='F') + check_copy_result(res, c, ccontig=False, fcontig=True, strides=False) + + # Copy with order='K' + res = a.copy(order='K') + check_copy_result(res, a, ccontig=True, fcontig=False, strides=True) + res = b.copy(order='K') + check_copy_result(res, b, ccontig=False, fcontig=True, strides=True) + res = c.copy(order='K') + check_copy_result(res, c, ccontig=False, fcontig=False, strides=True) + res = np.copy(a, order='K') + check_copy_result(res, a, ccontig=True, fcontig=False, strides=True) + res = np.copy(b, order='K') + check_copy_result(res, b, ccontig=False, fcontig=True, strides=True) + res = np.copy(c, order='K') + check_copy_result(res, c, ccontig=False, fcontig=False, strides=True) + if __name__ == "__main__": run_module_suite() diff --git a/numpy/core/tests/test_maskna.py b/numpy/core/tests/test_maskna.py index 8a644c080d0d..ba10a2ce4ab5 100644 --- a/numpy/core/tests/test_maskna.py +++ b/numpy/core/tests/test_maskna.py @@ -83,6 +83,70 @@ def test_array_maskna_construction(): assert_(a.flags.maskna) assert_equal(np.isna(a), True) +def test_array_maskna_copy(): + a = np.array([1,2,3]) + b = np.array([2,3,4], maskna=True) + c = np.array([3,4,np.NA], maskna=True) + + # Make a copy, adding a mask + res = a.copy(maskna=True) + assert_equal(res, a) + assert_(res.flags.maskna) + assert_(res.flags.ownmaskna) + + res = np.copy(a, maskna=True) + assert_equal(res, a) + assert_(res.flags.maskna) + assert_(res.flags.ownmaskna) + + # Make a copy, removing a mask + res = b.copy(maskna=False) + assert_equal(res, b) + assert_(not res.flags.maskna) + assert_(not res.flags.ownmaskna) + + res = np.copy(b, maskna=False) + assert_equal(res, b) + assert_(not res.flags.maskna) + assert_(not res.flags.ownmaskna) + + # Copy with removing a mask doesn't work if there are NAs + assert_raises(ValueError, c.copy, maskna=False) + assert_raises(ValueError, np.copy, c, maskna=False) + + # Make a copy, preserving non-masked + res = a.copy() + assert_equal(res, a) + assert_(not res.flags.maskna) + assert_(not res.flags.ownmaskna) + + res = np.copy(a) + assert_equal(res, a) + assert_(not res.flags.maskna) + assert_(not res.flags.ownmaskna) + + # Make a copy, preserving masked + res = b.copy() + assert_equal(res, b) + assert_(res.flags.maskna) + assert_(res.flags.ownmaskna) + + res = np.copy(b) + assert_equal(res, b) + assert_(res.flags.maskna) + assert_(res.flags.ownmaskna) + + # Make a copy, preserving masked with an NA + res = c.copy() + assert_array_equal(res, c) + assert_(res.flags.maskna) + assert_(res.flags.ownmaskna) + + res = np.copy(c) + assert_array_equal(res, c) + assert_(res.flags.maskna) + assert_(res.flags.ownmaskna) + def test_array_maskna_repr(): # Test some simple reprs with NA in them a = np.array(np.NA, maskna=True) diff --git a/numpy/lib/function_base.py b/numpy/lib/function_base.py index 411a86955c37..b269d98a1ca5 100644 --- a/numpy/lib/function_base.py +++ b/numpy/lib/function_base.py @@ -778,7 +778,7 @@ def select(condlist, choicelist, default=0): S = S*ones(asarray(pfac).shape, S.dtype) return choose(S, tuple(choicelist)) -def copy(a): +def copy(a, order='C', maskna=None): """ Return an array copy of the given object. @@ -786,6 +786,15 @@ def copy(a): ---------- a : array_like Input data. + order : {'C', 'F', 'A', 'K'}, optional + Controls the memory layout of the copy. 'C' means C-order, + 'F' means F-order, 'A' means 'F' if `a` is Fortran contiguous, + 'C' otherwise. 'K' means match the layout of `a` as closely + as possible. + maskna : bool, optional + If specifies, forces the copy to have or to not have an + NA mask. This is a way to remove an NA mask from an array + while making a copy. Returns ------- @@ -815,7 +824,7 @@ def copy(a): False """ - return array(a, copy=True) + return array(a, order=order, copy=True, maskna=maskna) # Basic operations