8000 Merge pull request #2694 from seberg/cflags2 · numpy/numpy@a890a85 · GitHub
[go: up one dir, main page]

Skip to content

Commit a890a85

Browse files
committed
Merge pull request #2694 from seberg/cflags2
ENH: Make 1-dimensional axes not matter for contiguous flags
2 parents c5ccca9 + 02ebf8b commit a890a85

File tree

13 files changed

+154
-177
lines changed

13 files changed

+154
-177
lines changed

numpy/core/include/numpy/ndarraytypes.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -756,8 +756,9 @@ typedef int (PyArray_FinalizeFunc)(PyArrayObject *, PyObject *);
756756
#define NPY_ARRAY_F_CONTIGUOUS 0x0002
757757

758758
/*
759-
* Note: all 0-d arrays are C_CONTIGUOUS and F_CONTIGUOUS. If a
760-
* 1-d array is C_CONTIGUOUS it is also F_CONTIGUOUS
759+
* Note: all 0-d arrays are C_CONTIGUOUS and F_CONTIGUOUS. An N-d
760+
* array that is C_CONTIGUOUS is also F_CONTIGUOUS if only
761+
* one axis has a dimension different from one (ie. a 1x3x1 array).
761762
*/
762763

763764
/*
@@ -1370,7 +1371,7 @@ PyArrayNeighborhoodIter_Next2D(PyArrayNeighborhoodIterObject* iter);
13701371
PyArray_CHKFLAGS(m, NPY_ARRAY_F_CONTIGUOUS))
13711372

13721373
#define PyArray_ISFORTRAN(m) (PyArray_CHKFLAGS(m, NPY_ARRAY_F_CONTIGUOUS) && \
1373-
(PyArray_NDIM(m) > 1))
1374+
(!PyArray_CHKFLAGS(m, NPY_ARRAY_C_CONTIGUOUS)))
13741375

13751376
#define PyArray_FORTRAN_IF(m) ((PyArray_CHKFLAGS(m, NPY_ARRAY_F_CONTIGUOUS) ? \
13761377
NPY_ARRAY_F_CONTIGUOUS : 0))

numpy/core/numeric.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -538,7 +538,7 @@ def require(a, dtype=None, requirements=None):
538538
def isfortran(a):
539539
"""
540540
Returns True if array is arranged in Fortran-order in memory
541-
and dimension > 1.
541+
and not C-order.
542542
543543
Parameters
544544
----------
@@ -584,7 +584,7 @@ def isfortran(a):
584584
>>> np.isfortran(b)
585585
True
586586
587-
1-D arrays always evaluate as False.
587+
C-ordered arrays evaluate as False even if they are also FORTRAN-ordered.
588588
589589
>>> np.isfortran(np.array([1, 2], order='FORTRAN'))
590590
False

numpy/core/src/multiarray/convert.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -265,8 +265,8 @@ PyArray_ToString(PyArrayObject *self, NPY_ORDER order)
265265
*/
266266

267267
numbytes = PyArray_NBYTES(self);
268-
if ((PyArray_ISCONTIGUOUS(self) && (order == NPY_CORDER))
269-
|| (PyArray_ISFORTRAN(self) && (order == NPY_FORTRANORDER))) {
268+
if ((PyArray_IS_C_CONTIGUOUS(self) && (order == NPY_CORDER))
269+
|| (PyArray_IS_F_CONTIGUOUS(self) && (order == NPY_FORTRANORDER))) {
270270
ret = PyBytes_FromStringAndSize(PyArray_DATA(self), (Py_ssize_t) numbytes);
271271
}
272272
else {

numpy/core/src/multiarray/ctors.c

Lines changed: 30 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1112,7 +1112,6 @@ PyArray_NewLikeArray(PyArrayObject *prototype, NPY_ORDER order,
11121112
int idim;
11131113

11141114
PyArray_CreateSortedStridePerm(PyArray_NDIM(prototype),
1115-
PyArray_SHAPE(prototype),
11161115
PyArray_STRIDES(prototype),
11171116
strideperm);
11181117

@@ -1825,9 +1824,6 @@ PyArray_FromArray(PyArrayObject *arr, PyArray_Descr *newtype, int flags)
18251824
}
18261825

18271826
arrflags = PyArray_FLAGS(arr);
1828-
if (PyArray_NDIM(arr) <= 1 && (flags & NPY_ARRAY_F_CONTIGUOUS)) {
1829-
flags |= NPY_ARRAY_C_CONTIGUOUS;
1830-
}
18311827
/* If a guaranteed copy was requested */
18321828
copy = (flags & NPY_ARRAY_ENSURECOPY) ||
18331829
/* If C contiguous was requested, and arr is not */
@@ -1837,9 +1833,8 @@ PyArray_FromArray(PyArrayObject *arr, PyArray_Descr *newtype, int flags)
18371833
((flags & NPY_ARRAY_ALIGNED) &&
18381834
(!(arrflags & NPY_ARRAY_ALIGNED))) ||
18391835
/* If a Fortran contiguous array was requested, and arr is not */
1840-
(PyArray_NDIM(arr) > 1 &&
1841-
((flags & NPY_ARRAY_F_CONTIGUOUS) &&
1842-
(!(arrflags & NPY_ARRAY_F_CONTIGUOUS)))) ||
1836+
((flags & NPY_ARRAY_F_CONTIGUOUS) &&
1837+
(!(arrflags & NPY_ARRAY_F_CONTIGUOUS))) ||
18431838
/* If a writeable array was requested, and arr is not */
18441839
((flags & NPY_ARRAY_WRITEABLE) &&
18451840
(!(arrflags & NPY_ARRAY_WRITEABLE))) ||
@@ -3570,14 +3565,33 @@ _array_fill_strides(npy_intp *strides, npy_intp *dims, int nd, size_t itemsize,
35703565
int inflag, int *objflags)
35713566
{
35723567
int i;
3568+
npy_bool not_cf_contig = 0;
3569+
npy_bool nod = 0; /* A dim != 1 was found */
3570+
3571+
/* Check if new array is both F- and C-contiguous */
3572+
for (i = 0; i < nd; i++) {
3573+
if (dims[i] != 1) {
3574+
if (nod) {
3575+
not_cf_contig = 1;
3576+
break;
3577+
}
3578+
nod = 1;
3579+
}
3580+
}
3581+
35733582
/* Only make Fortran strides if not contiguous as well */
35743583
if ((inflag & (NPY_ARRAY_F_CONTIGUOUS|NPY_ARRAY_C_CONTIGUOUS)) ==
35753584
NPY_ARRAY_F_CONTIGUOUS) {
35763585
for (i = 0; i < nd; i++) {
35773586
strides[i] = itemsize;
3578-
itemsize *= dims[i] ? dims[i] : 1;
3587+
if (dims[i]) {
3588+
itemsize *= dims[i];
3589+
}
3590+
else {
3591+
not_cf_contig = 0;
3592+
}
35793593
}
3580-
if (nd > 1) {
3594+
if (not_cf_contig) {
35813595
*objflags = ((*objflags)|NPY_ARRAY_F_CONTIGUOUS) &
35823596
~NPY_ARRAY_C_CONTIGUOUS;
35833597
}
@@ -3588,9 +3602,14 @@ _array_fill_strides(npy_intp *strides, npy_intp *dims, int nd, size_t itemsize,
35883602
else {
35893603
for (i = nd - 1; i >= 0; i--) {
35903604
strides[i] = itemsize;
3591-
itemsize *= dims[i] ? dims[i] : 1;
3605+
if (dims[i]) {
3606+
itemsize *= dims[i];
3607+
}
3608+
else {
3609+
not_cf_contig = 0;
3610+
}
35923611
}
3593-
if (nd > 1) {
3612+
if (not_cf_contig) {
35943613
*objflags = ((*objflags)|NPY_ARRAY_C_CONTIGUOUS) &
35953614
~NPY_ARRAY_F_CONTIGUOUS;
35963615
}

numpy/core/src/multiarray/dtype_transfer.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3921,7 +3921,7 @@ PyArray_PrepareOneRawArrayIter(int ndim, npy_intp *shape,
39213921
}
39223922

39233923
/* Sort the axes based on the destination strides */
3924-
PyArray_CreateSortedStridePerm(ndim, shape, F987 strides, strideperm);
3924+
PyArray_CreateSortedStridePerm(ndim, strides, strideperm);
39253925
for (i = 0; i < ndim; ++i) {
39263926
int iperm = strideperm[ndim - i - 1].perm;
39273927
out_shape[i] = shape[iperm];
@@ -4051,7 +4051,7 @@ PyArray_PrepareTwoRawArrayIter(int ndim, npy_intp *shape,
40514051
}
40524052

40534053
/* Sort the axes based on the destination strides */
4054-
PyArray_CreateSortedStridePerm(ndim, shape, stridesA, strideperm);
4054+
PyArray_CreateSortedStridePerm(ndim, stridesA, strideperm);
40554055
for (i = 0; i < ndim; ++i) {
40564056
int iperm = strideperm[ndim - i - 1].perm;
40574057
out_shape[i] = shape[iperm];
@@ -4185,7 +4185,7 @@ PyArray_PrepareThreeRawArrayIter(int ndim, npy_intp *shape,
41854185
}
41864186

41874187
/* Sort the axes based on the destination strides */
4188-
PyArray_CreateSortedStridePerm(ndim, shape, stridesA, strideperm);
4188+
PyArray_CreateSortedStridePerm(ndim, stridesA, strideperm);
41894189
for (i = 0; i < ndim; ++i) {
41904190
int iperm = strideperm[ndim - i - 1].perm;
41914191
out_shape[i] = shape[iperm];

numpy/core/src/multiarray/flagsobject.c

Lines changed: 34 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,8 @@
1515

1616
#include "common.h"
1717

18-
static int
19-
_IsContiguous(PyArrayObject *ap);
20-
21-
static int
22-
_IsFortranContiguous(PyArrayObject *ap);
18+
static void
19+
_UpdateContiguousFlags(PyArrayObject *ap);
2320

2421
/*NUMPY_API
2522
*
@@ -62,28 +59,9 @@ PyArray_NewFlagsObject(PyObject *obj)
6259
NPY_NO_EXPORT void
6360
PyArray_UpdateFlags(PyArrayObject *ret, int flagmask)
6461
{
65-
66-
if (flagmask & NPY_ARRAY_F_CONTIGUOUS) {
67-
if (_IsFortranContiguous(ret)) {
68-
PyArray_ENABLEFLAGS(ret, NPY_ARRAY_F_CONTIGUOUS);
69-
if (PyArray_NDIM(ret) > 1) {
70-
PyArray_CLEARFLAGS(ret, NPY_ARRAY_C_CONTIGUOUS);
71-
}
72-
}
73-
else {
74-
PyArray_CLEARFLAGS(ret, NPY_ARRAY_F_CONTIGUOUS);
75-
}
76-
}
77-
if (flagmask & NPY_ARRAY_C_CONTIGUOUS) {
78-
if (_IsContiguous(ret)) {
79-
PyArray_ENABLEFLAGS(ret, NPY_ARRAY_C_CONTIGUOUS);
80-
if (PyArray_NDIM(ret) > 1) {
81-
PyArray_CLEARFLAGS(ret, NPY_ARRAY_F_CONTIGUOUS);
82-
}
83-
}
84-
else {
85-
PyArray_CLEARFLAGS(ret, NPY_ARRAY_C_CONTIGUOUS);
86-
}
62+
/* Always update both, as its not trivial to guess one from the other */
63+
if (flagmask & (NPY_ARRAY_F_CONTIGUOUS | NPY_ARRAY_C_CONTIGUOUS)) {
64+
_UpdateContiguousFlags(ret);
8765
}
8866
if (flagmask & NPY_ARRAY_ALIGNED) {
8967
if (_IsAligned(ret)) {
@@ -110,66 +88,56 @@ PyArray_UpdateFlags(PyArrayObject *ret, int flagmask)
11088

11189
/*
11290
* Check whether the given array is stored contiguously
113-
* (row-wise) in memory.
91+
* in memory. And update the passed in ap flags apropriately.
11492
*
115-
* 0-strided arrays are not contiguous (even if dimension == 1)
93+
* A dimension == 1 stride is ignored for contiguous flags and a 0-sized array
94+
* is always both C- and F-Contiguous. 0-strided arrays are not contiguous.
11695
*/
117-
static int
118-
_IsContiguous(PyArrayObject *ap)
96+
static void
97+
_UpdateContiguousFlags(PyArrayObject *ap)
11998
{
12099
npy_intp sd;
121100
npy_intp dim;
122101
int i;
102+
npy_bool is_c_contig = 1;
123103

124-
if (PyArray_NDIM(ap) == 0) {
125-
return 1;
126-
}
127104
sd = PyArray_DESCR(ap)->elsize;
128-
if (PyArray_NDIM(ap) == 1) {
129-
return PyArray_DIMS(ap)[0] == 1 || sd == PyArray_STRIDES(ap)[0];
130-
}
131105
for (i = PyArray_NDIM(ap) - 1; i >= 0; --i) {
132106
dim = PyArray_DIMS(ap)[i];
133107
/* contiguous by definition */
134108
if (dim == 0) {
135-
return 1;
109+
PyArray_ENABLEFLAGS(ap, NPY_ARRAY_C_CONTIGUOUS);
110+
PyArray_ENABLEFLAGS(ap, NPY_ARRAY_F_CONTIGUOUS);
111+
return;
136112
}
137-
if (PyArray_STRIDES(ap)[i] != sd) {
138-
return 0;
113+
if (dim != 1) {
114+
if (PyArray_STRIDES(ap)[i] != sd) {
115+
is_c_contig = 0;
116+
}
117+
sd *= dim;
139118
}
140-
sd *= dim;
141119
}
142-
return 1;
143-
}
144-
145-
146-
/* 0-strided arrays are not contiguous (even if dimension == 1) */
147-
static int
148-
_IsFortranContiguous(PyArrayObject *ap)
149-
{
150-
npy_intp sd;
151-
npy_intp dim;
152-
int i;
153-
154-
if (PyArray_NDIM(ap) == 0) {
155-
return 1;
120+
if (is_c_contig) {
121+
PyArray_ENABLEFLAGS(ap, NPY_ARRAY_C_CONTIGUOUS);
156122
}
157-
sd = PyArray_DESCR(ap)->elsize;
158-
if (PyArray_NDIM(ap) == 1) {
159-
return PyArray_DIMS(ap)[0] == 1 || sd == PyArray_STRIDES(ap)[0];
123+
else {
124+
PyArray_CLEARFLAGS(ap, NPY_ARRAY_C_CONTIGUOUS);
160125
}
126+
127+
/* check if fortran contiguous */
128+
sd = PyArray_DESCR(ap)->elsize;
161129
for (i = 0; i < PyArray_NDIM(ap); ++i) {
162130
dim = PyArray_DIMS(ap)[i];
163-
/* fortran contiguous by definition */
164-
if (dim == 0) {
165-
return 1;
166-
}
167-
if (PyArray_STRIDES(ap)[i] != sd) {
168-
return 0;
131+
if (dim != 1) {
132+
if (PyArray_STRIDES(ap)[i] != sd) {
133+
PyArray_CLEARFLAGS(ap, NPY_ARRAY_F_CONTIGUOUS);
134+
return;
135+
}
136+
sd *= dim;
169137
}
170-
sd *= dim;
171138
}
172-
return 1;
139+
PyArray_ENABLEFLAGS(ap, NPY_ARRAY_F_CONTIGUOUS);
140+
return;
173141
}
174142

175143
static void

numpy/core/src/multiarray/multiarraymodule.c

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1517,26 +1517,18 @@ PyArray_EquivTypenums(int typenum1, int typenum2)
15171517
/*** END C-API FUNCTIONS **/
15181518

15191519
static PyObject *
1520-
_prepend_ones(PyArrayObject *arr, int nd, int ndmin, NPY_ORDER order)
1520+
_prepend_ones(PyArrayObject *arr, int nd, int ndmin)
15211521
{
15221522
npy_intp newdims[NPY_MAXDIMS];
15231523
npy_intp newstrides[NPY_MAXDIMS];
1524-
npy_intp newstride;
15251524
int i, k, num;
15261525
PyArrayObject *ret;
15271526
PyArray_Descr *dtype;
15281527

1529-
if (order == NPY_FORTRANORDER || PyArray_ISFORTRAN(arr) || PyArray_NDIM(arr) == 0) {
1530-
newstride = PyArray_DESCR(arr)->elsize;
1531-
}
1532-
else {
1533-
newstride = PyArray_STRIDES(arr)[0] * PyArray_DIMS(arr)[0];
1534-
}
1535-
15361528
num = ndmin - nd;
15371529
for (i = 0; i < num; i++) {
15381530
newdims[i] = 1;
1539-
newstrides[i] = newstride;
1531+
newstrides[i] = PyArray_DESCR(arr)->elsize;
15401532
}
15411533
for (i = num; i < ndmin; i++) {
15421534
k = i - num;
@@ -1566,8 +1558,8 @@ _prepend_ones(PyArrayObject *arr, int nd, int ndmin, NPY_ORDER order)
15661558
#define STRIDING_OK(op, order) \
15671559
((order) == NPY_ANYORDER || \
15681560
(order) == NPY_KEEPORDER || \
1569-
((order) == NPY_CORDER && PyArray_ISCONTIGUOUS(op)) || \
1570-
((order) == NPY_FORTRANORDER && PyArray_ISFORTRAN(op)))
1561+
((order) == NPY_CORDER && PyArray_IS_C_CONTIGUOUS(op)) || \
1562+
((order) == NPY_FORTRANORDER && PyArray_IS_F_CONTIGUOUS(op)))
15711563

15721564
static PyObject *
15731565
_array_fromobject(PyObject *NPY_UNUSED(ignored), PyObject *args, PyObject *kws)
@@ -1677,7 +1669,7 @@ _array_fromobject(PyObject *NPY_UNUSED(ignored), PyObject *args, PyObject *kws)
16771669
* create a new array from the same data with ones in the shape
16781670
* steals a reference to ret
16791671
*/
1680-
return _prepend_ones(ret, nd, ndmin, order);
1672+
return _prepend_ones(ret, nd, ndmin);
16811673

16821674
clean_type:
16831675
Py_XDECREF(type);

0 commit comments

Comments
 (0)
0