From 79d22dcef7947347660cbb953cb54ee3b38822f5 Mon Sep 17 00:00:00 2001 From: Sebastian Berg Date: Thu, 21 Mar 2013 14:23:21 +0100 Subject: [PATCH 1/4] BLD: Add NPY_RELAXED_STRIDES_CHECKING flag This flag will toggle to a new definition for the contiguous flags where only the memory layout is forced to be correct. As a particular example this means that np.ones((3,1)) can be both C and F-Contiguous and its stride[-1] can be arbitrary but the array still contiguous. The flag will also make most new arrays be created with MAX_INTP as stride so that unsafe usage of the stride will surface more commonly. --- numpy/core/bscript | 7 +++++++ numpy/core/setup.py | 9 +++++++++ 2 files changed, 16 insertions(+) diff --git a/numpy/core/bscript b/numpy/core/bscript index 3d9b84018f8e..3a2bb23401ea 100644 --- a/numpy/core/bscript +++ b/numpy/core/bscript @@ -31,6 +31,7 @@ from setup_common \ MANDATORY_FUNCS, C_ABI_VERSION, C_API_VERSION ENABLE_SEPARATE_COMPILATION = (os.environ.get('NPY_SEPARATE_COMPILATION', "1") != "0") +NPY_RELAXED_STRIDES_CHECKING = (os.environ.get('NPY_RELAXED_STRIDES_CHECKING', "0") != "0") NUMPYCONFIG_SYM = [] @@ -39,6 +40,12 @@ if ENABLE_SEPARATE_COMPILATION: NUMPYCONFIG_SYM.append(('DEFINE_NPY_ENABLE_SEPARATE_COMPILATION', '#define NPY_ENABLE_SEPARATE_COMPILATION 1')) else: NUMPYCONFIG_SYM.append(('DEFINE_NPY_ENABLE_SEPARATE_COMPILATION', '')) + +if NPY_RELAXED_STRIDES_CHECKING: + NUMPYCONFIG_SYM.append(('DEFINE_NPY_RELAXED_STRIDES_CHECKING', '#define NPY_RELAXED_STRIDES_CHECKING 1')) +else: + NUMPYCONFIG_SYM.append(('DEFINE_NPY_RELAXED_STRIDES_CHECKING', '')) + NUMPYCONFIG_SYM.append(('VISIBILITY_HIDDEN', '__attribute__((visibility("hidden")))')) NUMPYCONFIG_SYM.append(('NPY_ABI_VERSION', '0x%.8X' % C_ABI_VERSION)) diff --git a/numpy/core/setup.py b/numpy/core/setup.py index 37f649e6b016..c6501212659f 100644 --- a/numpy/core/setup.py +++ b/numpy/core/setup.py @@ -15,6 +15,9 @@ # Set to True to enable multiple file compilations (experimental) ENABLE_SEPARATE_COMPILATION = (os.environ.get('NPY_SEPARATE_COMPILATION', "1") != "0") +# Set to True to enable relaxed strides checking. This (mostly) means +# that `strides[dim]` is ignored if `shape[dim] == 1` when setting flags. +NPY_RELAXED_STRIDES_CHECKING = (os.environ.get('NPY_RELAXED_STRIDES_CHECKING', "0") != "0") # XXX: ugly, we use a class to avoid calling twice some expensive functions in # config.h/numpyconfig.h. I don't see a better way because distutils force @@ -435,6 +438,9 @@ def generate_config_h(ext, build_dir): if ENABLE_SEPARATE_COMPILATION: moredefs.append(('ENABLE_SEPARATE_COMPILATION', 1)) + if NPY_RELAXED_STRIDES_CHECKING: + moredefs.append(('NPY_RELAXED_STRIDES_CHECKING', 1)) + # Get long double representation if sys.platform != 'darwin': rep = check_long_double_representation(config_cmd) @@ -532,6 +538,9 @@ def generate_numpyconfig_h(ext, build_dir): if ENABLE_SEPARATE_COMPILATION: moredefs.append(('NPY_ENABLE_SEPARATE_COMPILATION', 1)) + if NPY_RELAXED_STRIDES_CHECKING: + moredefs.append(('NPY_RELAXED_STRIDES_CHECKING', 1)) + # Check wether we can use inttypes (C99) formats if config_cmd.check_decl('PRIdPTR', headers = ['inttypes.h']): moredefs.append(('NPY_USE_C99_FORMATS', 1)) From 3a4ed02bca07d0995aedc8846b7aeac7af3bf310 Mon Sep 17 00:00:00 2001 From: Sebastian Berg Date: Thu, 21 Mar 2013 16:34:44 +0100 Subject: [PATCH 2/4] ENH: Relax aligned flag for shape[i] <= 1 In this case, either the dimensions stride will never be used to access an element, so that it does not matter to the data alignment, or the array has a size of 0 and is thus never unaligned. Relaxed align flag is only active if NPY_RELAXED_STRIDES_CHECKING was set during compile time. --- numpy/core/src/multiarray/common.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/numpy/core/src/multiarray/common.c b/numpy/core/src/multiarray/common.c index f27de491f6f9..f0a6a761c062 100644 --- a/numpy/core/src/multiarray/common.c +++ b/numpy/core/src/multiarray/common.c @@ -628,8 +628,20 @@ _IsAligned(PyArrayObject *ap) } ptr = (npy_intp) PyArray_DATA(ap); aligned = (ptr % alignment) == 0; + for (i = 0; i < PyArray_NDIM(ap); i++) { +#if NPY_RELAXED_STRIDES_CHECKING + if (PyArray_DIM(ap, i) > 1) { + /* if shape[i] == 1, the stride is never used */ + aligned &= ((PyArray_STRIDES(ap)[i] % alignment) == 0); + } + else if (PyArray_DIM(ap, i) == 0) { + /* an array with zero elements is always aligned */ + return 1; + } +#else /* not NPY_RELAXED_STRIDES_CHECKING */ aligned &= ((PyArray_STRIDES(ap)[i] % alignment) == 0); +#endif /* not NPY_RELAXED_STRIDES_CHECKING */ } return aligned != 0; } From 7af1c6701673187b7d895b7646204d774bffc557 Mon Sep 17 00:00:00 2001 From: Sebastian Berg Date: Mon, 25 Mar 2013 16:21:18 +0100 Subject: [PATCH 3/4] API: Implement new flags API with NPY_RELAXED_STRIDES_CHECKING This largly reverts the changes to the flags setting api making the newer preferable unsafe flags setting available through the NPY_RELAXED_STRIDES_CHECKING eviroment variable. This variable is meant for testing if code will stop working when the flags definition is changed. The old definition is modified in some details to previously to enforce safer strides (which was not the case before). This means that ndim==1 size==1 arrays are not necessarily considered contiguous. Also empty arrays are not considered contiguous in some cases that were contiguous before, and the rule that an array can only be both C and F-contiguous if it is one (or zero) dimensional is relaxed, as it is incorrect for size <= 1 arrays. --- numpy/core/include/numpy/ndarraytypes.h | 12 +++-- numpy/core/src/multiarray/ctors.c | 22 ++++++++ numpy/core/src/multiarray/flagsobject.c | 56 ++++++++++++++++++-- numpy/core/src/multiarray/multiarraymodule.c | 19 +++++-- numpy/core/src/multiarray/shape.c | 13 +++-- numpy/core/tests/test_api.py | 42 ++++++++++----- numpy/core/tests/test_multiarray.py | 4 +- numpy/core/tests/test_regression.py | 7 +++ 8 files changed, 148 insertions(+), 27 deletions(-) diff --git a/numpy/core/include/numpy/ndarraytypes.h b/numpy/core/include/numpy/ndarraytypes.h index 05bac8a1ff98..7cc37bff8007 100644 --- a/numpy/core/include/numpy/ndarraytypes.h +++ b/numpy/core/include/numpy/ndarraytypes.h @@ -753,9 +753,15 @@ typedef int (PyArray_FinalizeFunc)(PyArrayObject *, PyObject *); #define NPY_ARRAY_F_CONTIGUOUS 0x0002 /* - * 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). + * Note: all 0-d arrays are C_CONTIGUOUS and F_CONTIGUOUS. If a + * 1-d array is C_CONTIGUOUS it is also F_CONTIGUOUS. Arrays with + * more then one dimension can be C_CONTIGUOUS and F_CONTIGUOUS + * at the same time if they have either zero or one element. + * If NPY_RELAXED_STRIDES_CHECKING is set, a higher dimensional + * array is always C_CONTIGUOUS and F_CONTIGUOUS if it has zero elements + * and the array is contiguous if ndarray.squeeze() is contiguous. + * I.e. dimensions for which `ndarray.shape[dimension] == 1` are + * ignored. */ /* diff --git a/numpy/core/src/multiarray/ctors.c b/numpy/core/src/multiarray/ctors.c index bdf2e6e2b42b..f366a34b188c 100644 --- a/numpy/core/src/multiarray/ctors.c +++ b/numpy/core/src/multiarray/ctors.c @@ -3560,6 +3560,7 @@ _array_fill_strides(npy_intp *strides, npy_intp *dims, int nd, size_t itemsize, int inflag, int *objflags) { int i; +#if NPY_RELAXED_STRIDES_CHECKING npy_bool not_cf_contig = 0; npy_bool nod = 0; /* A dim != 1 was found */ @@ -3573,6 +3574,7 @@ _array_fill_strides(npy_intp *strides, npy_intp *dims, int nd, size_t itemsize, nod = 1; } } +#endif /* NPY_RELAXED_STRIDES_CHECKING */ /* Only make Fortran strides if not contiguous as well */ if ((inflag & (NPY_ARRAY_F_CONTIGUOUS|NPY_ARRAY_C_CONTIGUOUS)) == @@ -3582,11 +3584,21 @@ _array_fill_strides(npy_intp *strides, npy_intp *dims, int nd, size_t itemsize, if (dims[i]) { itemsize *= dims[i]; } +#if NPY_RELAXED_STRIDES_CHECKING else { not_cf_contig = 0; } + if (dims[i] == 1) { + /* For testing purpose only */ + strides[i] = NPY_MAX_INTP; + } +#endif /* NPY_RELAXED_STRIDES_CHECKING */ } +#if NPY_RELAXED_STRIDES_CHECKING if (not_cf_contig) { +#else /* not NPY_RELAXED_STRIDES_CHECKING */ + if ((nd > 1) && ((strides[0] != strides[nd-1]) || (dims[nd-1] > 1))) { +#endif /* not NPY_RELAXED_STRIDES_CHECKING */ *objflags = ((*objflags)|NPY_ARRAY_F_CONTIGUOUS) & ~NPY_ARRAY_C_CONTIGUOUS; } @@ -3600,11 +3612,21 @@ _array_fill_strides(npy_intp *strides, npy_intp *dims, int nd, size_t itemsize, if (dims[i]) { itemsize *= dims[i]; } +#if NPY_RELAXED_STRIDES_CHECKING else { not_cf_contig = 0; } + if (dims[i] == 1) { + /* For testing purpose only */ + strides[i] = NPY_MAX_INTP; + } +#endif /* NPY_RELAXED_STRIDES_CHECKING */ } +#if NPY_RELAXED_STRIDES_CHECKING if (not_cf_contig) { +#else /* not NPY_RELAXED_STRIDES_CHECKING */ + if ((nd > 1) && ((strides[0] != strides[nd-1]) || (dims[0] > 1))) { +#endif /* not NPY_RELAXED_STRIDES_CHECKING */ *objflags = ((*objflags)|NPY_ARRAY_C_CONTIGUOUS) & ~NPY_ARRAY_F_CONTIGUOUS; } diff --git a/numpy/core/src/multiarray/flagsobject.c b/numpy/core/src/multiarray/flagsobject.c index ef04bdb201e0..0ad5c908a3bc 100644 --- a/numpy/core/src/multiarray/flagsobject.c +++ b/numpy/core/src/multiarray/flagsobject.c @@ -90,8 +90,33 @@ PyArray_UpdateFlags(PyArrayObject *ret, int flagmask) * Check whether the given array is stored contiguously * in memory. And update the passed in ap flags apropriately. * - * 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. + * The traditional rule is that for an array to be flagged as C contiguous, + * the following must hold: + * + * strides[-1] == itemsize + * strides[i] == shape[i+1] * strides[i + 1] + * + * And for an array to be flagged as F contiguous, the obvious reversal: + * + * strides[0] == itemsize + * strides[i] == shape[i - 1] * strides[i - 1] + * + * According to these rules, a 0- or 1-dimensional array is either both + * C- and F-contiguous, or neither; and an array with 2+ dimensions + * can be C- or F- contiguous, or neither, but not both. Though there + * there are exceptions for arrays with zero or one item, in the first + * case the check is relaxed up to and including the first dimension + * with shape[i] == 0. In the second case `strides == itemsize` will + * can be true for all dimensions and both flags are set. + * + * When NPY_RELAXED_STRIDES_CHECKING is set, we use a more accurate + * definition of C- and F-contiguity, in which all 0-sized arrays are + * contiguous (regardless of dimensionality), and if shape[i] == 1 + * then we ignore strides[i] (since it has no affect on memory layout). + * With these new rules, it is possible for e.g. a 10x1 array to be both + * C- and F-contiguous -- but, they break downstream code which assumes + * that for contiguous arrays strides[-1] (resp. strides[0]) always + * contains the itemsize. */ static void _UpdateContiguousFlags(PyArrayObject *ap) @@ -101,9 +126,10 @@ _UpdateContiguousFlags(PyArrayObject *ap) int i; npy_bool is_c_contig = 1; - sd = PyArray_DESCR(ap)->elsize; + sd = PyArray_ITEMSIZE(ap); for (i = PyArray_NDIM(ap) - 1; i >= 0; --i) { dim = PyArray_DIMS(ap)[i]; +#if NPY_RELAXED_STRIDES_CHECKING /* contiguous by definition */ if (dim == 0) { PyArray_ENABLEFLAGS(ap, NPY_ARRAY_C_CONTIGUOUS); @@ -116,6 +142,17 @@ _UpdateContiguousFlags(PyArrayObject *ap) } sd *= dim; } +#else /* not NPY_RELAXED_STRIDES_CHECKING */ + if (PyArray_STRIDES(ap)[i] != sd) { + is_c_contig = 0; + break; + } + /* contiguous, if it got this far */ + if (dim == 0) { + break; + } + sd *= dim; +#endif /* not NPY_RELAXED_STRIDES_CHECKING */ } if (is_c_contig) { PyArray_ENABLEFLAGS(ap, NPY_ARRAY_C_CONTIGUOUS); @@ -125,9 +162,10 @@ _UpdateContiguousFlags(PyArrayObject *ap) } /* check if fortran contiguous */ - sd = PyArray_DESCR(ap)->elsize; + sd = PyArray_ITEMSIZE(ap); for (i = 0; i < PyArray_NDIM(ap); ++i) { dim = PyArray_DIMS(ap)[i]; +#if NPY_RELAXED_STRIDES_CHECKING if (dim != 1) { if (PyArray_STRIDES(ap)[i] != sd) { PyArray_CLEARFLAGS(ap, NPY_ARRAY_F_CONTIGUOUS); @@ -135,6 +173,16 @@ _UpdateContiguousFlags(PyArrayObject *ap) } sd *= dim; } +#else /* not NPY_RELAXED_STRIDES_CHECKING */ + if (PyArray_STRIDES(ap)[i] != sd) { + PyArray_CLEARFLAGS(ap, NPY_ARRAY_F_CONTIGUOUS); + return; + } + if (dim == 0) { + break; + } + sd *= dim; +#endif /* not NPY_RELAXED_STRIDES_CHECKING */ } PyArray_ENABLEFLAGS(ap, NPY_ARRAY_F_CONTIGUOUS); return; diff --git a/numpy/core/src/multiarray/multiarraymodule.c b/numpy/core/src/multiarray/multiarraymodule.c index f8ade57da146..dd6d4400360f 100644 --- a/numpy/core/src/multiarray/multiarraymodule.c +++ b/numpy/core/src/multiarray/multiarraymodule.c @@ -1510,20 +1510,31 @@ PyArray_EquivTypenums(int typenum1, int typenum2) } /*** END C-API FUNCTIONS **/ - +/* + * NPY_RELAXED_STRIDES_CHECKING: If the strides logic is changed, the + * order specific stride setting is not necessary. + */ static PyObject * -_prepend_ones(PyArrayObject *arr, int nd, int ndmin) +_prepend_ones(PyArrayObject *arr, int nd, int ndmin, NPY_ORDER order) { 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] = PyArray_DESCR(arr)->elsize; + newstrides[i] = newstride; } for (i = num; i < ndmin; i++) { k = i - num; @@ -1664,7 +1675,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); + return _prepend_ones(ret, nd, ndmin, order); clean_type: Py_XDECREF(type); diff --git a/numpy/core/src/multiarray/shape.c b/numpy/core/src/multiarray/shape.c index 4223e49f6ad3..67ee4b04bfa9 100644 --- a/numpy/core/src/multiarray/shape.c +++ b/numpy/core/src/multiarray/shape.c @@ -214,9 +214,11 @@ PyArray_Newshape(PyArrayObject *self, PyArray_Dims *newdims, * 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. + * NPY_RELAXED_STRIDES_CHECKING: size check is unnecessary when set. */ - if ((order == NPY_CORDER && !PyArray_IS_C_CONTIGUOUS(self)) || - (order == NPY_FORTRANORDER && !PyArray_IS_F_CONTIGUOUS(self))) { + if ((PyArray_SIZE(self) > 1) && + ((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); @@ -1102,7 +1104,9 @@ build_shape_string(npy_intp n, npy_intp *vals) * 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. + * the aligned flag (and in the future the contiguous flags), + * may need explicite update. + * (check also NPY_RELAXED_STRIDES_CHECKING) * * For example, this can be used to remove the reduction axes * from a reduction result once its computation is complete. @@ -1125,4 +1129,7 @@ PyArray_RemoveAxesInPlace(PyArrayObject *arr, npy_bool *flags) /* The final number of dimensions */ fa->nd = idim_out; + + /* May not be necessary for NPY_RELAXED_STRIDES_CHECKING (see comment) */ + PyArray_UpdateFlags(arr, NPY_ARRAY_C_CONTIGUOUS | NPY_ARRAY_F_CONTIGUOUS); } diff --git a/numpy/core/tests/test_api.py b/numpy/core/tests/test_api.py index 484b6afbd0a9..e919e0ae4609 100644 --- a/numpy/core/tests/test_api.py +++ b/numpy/core/tests/test_api.py @@ -7,6 +7,9 @@ from numpy.testing.utils import WarningManager import warnings +# Switch between new behaviour when NPY_RELAXED_STRIDES_CHECKING is set. +NPY_RELAXED_STRIDES_CHECKING = np.ones((10,1), order='C').flags.f_contiguous + def test_fastCopyAndTranspose(): # 0D array a = np.array(2) @@ -149,10 +152,13 @@ def check_copy_result(x, y, ccontig, fcontig, strides=False): 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) + # This check is impossible only because + # NPY_RELAXED_STRIDES_CHECKING changes the strides actively + if not NPY_RELAXED_STRIDES_CHECKING: + 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) @@ -206,7 +212,8 @@ def check_copy_result(x, y, ccontig, fcontig, strides=False): def test_contiguous_flags(): a = np.ones((4,4,1))[::2,:,:] - a.strides = a.strides[:2] + (-123,) + if NPY_RELAXED_STRIDES_CHECKING: + a.strides = a.strides[:2] + (-123,) b = np.ones((2,2,1,2,2)).swapaxes(3,4) def check_contig(a, ccontig, fcontig): @@ -216,8 +223,12 @@ def check_contig(a, ccontig, 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) + if NPY_RELAXED_STRIDES_CHECKING: + check_contig(np.empty((2,2,0,2,2)), True, True) + check_contig(np.array([[[1],[2]]], order='F'), True, True) + else: + check_contig(np.empty((2,2,0,2,2)), True, False) + check_contig(np.array([[[1],[2]]], order='F'), False, True) check_contig(np.empty((2,2)), True, False) check_contig(np.empty((2,2), order='F'), False, True) @@ -226,11 +237,18 @@ def check_contig(a, ccontig, fcontig): 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) + if NPY_RELAXED_STRIDES_CHECKING: + # 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) + else: + # Check slicing update of flags: + check_contig(a[0], True, False) + # Would be nice if this was C-Contiguous: + check_contig(a[None,0,...,None], False, False) + check_contig(b[0,0,0,...], False, True) # Test ravel and squeeze. check_contig(a.ravel(), True, True) diff --git a/numpy/core/tests/test_multiarray.py b/numpy/core/tests/test_multiarray.py index 25cc8ced84a5..b457c4773896 100644 --- a/numpy/core/tests/test_multiarray.py +++ b/numpy/core/tests/test_multiarray.py @@ -2764,7 +2764,9 @@ def test_export_record(self): assert_equal(y.format, 'T{b:a:=h:b:i:c:l:d:^q:dx:B:e:@H:f:=I:g:L:h:^Q:hx:=f:i:d:j:^g:k:=Zf:ix:Zd:jx:^Zg:kx:4s:l:=4w:m:3x:n:?:o:@e:p:}') else: assert_equal(y.format, 'T{b:a:=h:b:i:c:q:d:^q:dx:B:e:@H:f:=I:g:Q:h:^Q:hx:=f:i:d:j:^g:k:=Zf:ix:Zd:jx:^Zg:kx:4s:l:=4w:m:3x:n:?:o:@e:p:}') - assert_equal(y.strides, (sz,)) + # Cannot test if NPY_RELAXED_STRIDES_CHECKING changes the strides + if not (np.ones(1).strides[0] == np.iinfo(np.intp).max): + assert_equal(y.strides, (sz,)) assert_equal(y.itemsize, sz) def test_export_subarray(self): diff --git a/numpy/core/tests/test_regression.py b/numpy/core/tests/test_regression.py index 95df4a1131ac..e87df62b757e 100644 --- a/numpy/core/tests/test_regression.py +++ b/numpy/core/tests/test_regression.py @@ -547,6 +547,9 @@ def test_reshape_zero_size(self, level=rlevel): a = np.ones((0,2)) a.shape = (-1,2) + # Cannot test if NPY_RELAXED_STRIDES_CHECKING changes the strides. + # With NPY_RELAXED_STRIDES_CHECKING the test becomes superfluous. + @dec.skipif(np.ones(1).strides[0] == np.iinfo(np.intp).max) def test_reshape_trailing_ones_strides(self): # Github issue gh-2949, bad strides for trailing ones of new shape a = np.zeros(12, dtype=np.int32)[::2] # not contiguous @@ -799,6 +802,10 @@ def test_copy_detection_corner_case(self, level=rlevel): """Ticket #658""" np.indices((0,3,4)).T.reshape(-1,3) + # Cannot test if NPY_RELAXED_STRIDES_CHECKING changes the strides. + # With NPY_RELAXED_STRIDES_CHECKING the test becomes superfluous, + # 0-sized reshape itself is tested elsewhere. + @dec.skipif(np.ones(1).strides[0] == np.iinfo(np.intp).max) def test_copy_detection_corner_case2(self, level=rlevel): """Ticket #771: strides are not set correctly when reshaping 0-sized arrays""" From 507b09e523e11610ea7f9bf3350b2258120ab0d2 Mon Sep 17 00:00:00 2001 From: Sebastian Berg Date: Tue, 2 Apr 2013 20:01:57 +0200 Subject: [PATCH 4/4] TST: Add NPY_RELAXED_STRIDES_CHECKING to Travis --- .travis.yml | 6 +++++- tools/test-installed-numpy.py | 13 ++++++++++++- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 6cf83d8f983f..6949be4bcf97 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,8 +10,12 @@ matrix: include: - python: 2.7 env: NPY_SEPARATE_COMPILATION=0 - - python: 3.2 + - python: 3.3 env: NPY_SEPARATE_COMPILATION=0 + - python: 2.7 + env: NPY_RELAXED_STRIDES_CHECKING=1 + - python: 3.3 + env: NPY_RELAXED_STRIDES_CHECKING=1 before_install: - uname -a - free -m diff --git a/tools/test-installed-numpy.py b/tools/test-installed-numpy.py index ac917b05f4f9..e9c374e9b593 100644 --- a/tools/test-installed-numpy.py +++ b/tools/test-installed-numpy.py @@ -12,7 +12,7 @@ # But, python2.4's -m switch only works with top-level modules, not modules # that are inside packages. So, once we drop 2.4 support, maybe... -import sys +import sys, os # In case we are run from the source directory, we don't want to import numpy # from there, we want to import the installed version: sys.path.pop(0) @@ -35,6 +35,17 @@ (options, args) = parser.parse_args() import numpy + +# Check that NPY_RELAXED_STRIDES_CHECKING is active when set. +# The same flags check is also used in the tests to switch behavior. +if (os.environ.get('NPY_RELAXED_STRIDES_CHECKING', "0") != "0"): + if not numpy.ones((10,1), order='C').flags.f_contiguous: + print('NPY_RELAXED_STRIDES_CHECKING set, but not active.') + sys.exit(1) +elif numpy.ones((10,1), order='C').flags.f_contiguous: + print('NPY_RELAXED_STRIDES_CHECKING not set, but active.') + sys.exit(1) + result = numpy.test(options.mode, verbose=options.verbose, extra_argv=args,