[Numpy-discussion] Learning "strides"

Sasha ndarray at mac.com
Fri Feb 3 10:10:02 EST 2006


On Feb 2, 2006, at 10:02 PM, Travis Oliphant wrote:
>>
>> Please let me know if you plan to change PyArray_CheckStrides so that
>> we don't duplicate effort.
>>
>>
> I won't do anything with it in the near future.
>

Attached patch deals with negative strides and prohibits zero
strides.  I think we can agree that this is the right behavior while
zero-stride semantics are being discussed.   Since I am touching C-
API, I would like you to take a look before I commit. Also I am not
sure "self->data - new->data" is always the right was to compute
offset in array_strides_set .

-- sasha
-------------- next part --------------
Index: numpy/core/include/numpy/arrayobject.h
===================================================================
--- numpy/core/include/numpy/arrayobject.h	(revision 2053)
+++ numpy/core/include/numpy/arrayobject.h	(working copy)
@@ -74,7 +74,7 @@
 #define PY_SUCCEED 1
 
 	/* Helpful to distinguish what is installed */
-#define NDARRAY_VERSION 0x00090403
+#define NDARRAY_VERSION 0x00090404
 
 	/* Some platforms don't define bool, long long, or long double.
 	   Handle that here.
Index: numpy/core/src/arrayobject.c
===================================================================
--- numpy/core/src/arrayobject.c	(revision 2053)
+++ numpy/core/src/arrayobject.c	(working copy)
@@ -3517,7 +3517,7 @@
 */
 /*OBJECT_API*/
 static Bool
-PyArray_CheckStrides(int elsize, int nd, intp numbytes, 
+PyArray_CheckStrides(int elsize, int nd, intp numbytes, intp offset,
 		     intp *dims, intp *newstrides)
 {
 	int i;
@@ -3526,7 +3526,17 @@
 		numbytes = PyArray_MultiplyList(dims, nd) * elsize;
 	
 	for (i=0; i<nd; i++) {
-		if (newstrides[i]*(dims[i]-1)+elsize > numbytes) {
+		intp stride = newstrides[i];
+		if (stride > 0) {
+			if (offset + stride*(dims[i]-1)+elsize > numbytes) {
+				return FALSE;
+			}
+		}
+		else if (stride < 0) {
+			if (offset + stride*dims[i] < 0) {
+				return FALSE;
+			}
+		} else {
 			return FALSE;
 		}
 	}
@@ -4064,10 +4074,8 @@
                 }
         }
         else {  /* buffer given -- use it */
-		buffer.len -= offset;
-		buffer.ptr += offset;
                 if (dims.len == 1 && dims.ptr[0] == -1) {
-                        dims.ptr[0] = buffer.len / itemsize;
+                        dims.ptr[offset] = buffer.len / itemsize;
                 }
                 else if (buffer.len < itemsize*                 \
                          PyArray_MultiplyList(dims.ptr, dims.len)) {
@@ -4084,7 +4092,7 @@
 				goto fail;
 			}
 			if (!PyArray_CheckStrides(itemsize, strides.len, 
-						  buffer.len,
+						  buffer.len, offset,
 						  dims.ptr, strides.ptr)) {
 				PyErr_SetString(PyExc_ValueError, 
 						"strides is incompatible "\
@@ -4104,7 +4112,7 @@
 			PyArray_NewFromDescr(subtype, descr,
 					     dims.len, dims.ptr,
 					     strides.ptr,
-					     (char *)buffer.ptr, 
+					     offset + (char *)buffer.ptr, 
 					     buffer.flags, NULL); 
                 if (ret == NULL) {descr=NULL; goto fail;}
                 PyArray_UpdateFlags(ret, UPDATE_ALL_FLAGS);
@@ -4222,7 +4230,8 @@
 	numbytes = PyArray_MultiplyList(new->dimensions, 
 					new->nd)*new->descr->elsize;
 	
-	if (!PyArray_CheckStrides(self->descr->elsize, self->nd, numbytes, 
+	if (!PyArray_CheckStrides(self->descr->elsize, self->nd, numbytes,
+				  self->data - new->data,
 				  self->dimensions, newstrides.ptr)) {
 		PyErr_SetString(PyExc_ValueError, "strides is not "\
 				"compatible with available memory");
Index: numpy/core/tests/test_multiarray.py
===================================================================
--- numpy/core/tests/test_multiarray.py	(revision 2053)
+++ numpy/core/tests/test_multiarray.py	(working copy)
@@ -62,6 +62,34 @@
         assert_equal(self.one.dtype.str[1], 'i')
         assert_equal(self.three.dtype.str[1], 'f')
 
+    def check_stridesattr(self):
+        x = self.one
+        def make_array(size, offset, strides):
+            return ndarray([size], buffer=x,
+                           offset=offset*x.itemsize,
+                           strides=strides*x.itemsize)
+        assert_equal(make_array(4, 4, -1), array([4, 3, 2, 1]))
+        self.failUnlessRaises(ValueError, make_array, 4, 4, -2)
+        self.failUnlessRaises(ValueError, make_array, 4, 3, -1)
+        self.failUnlessRaises(ValueError, make_array, 8, 3, 1)
+        self.failUnlessRaises(ValueError, make_array, 8, 3, 0)
+
+    def check_set_stridesattr(self):
+        x = self.one
+        def make_array(size, offset, strides):
+            try:
+                r = ndarray([size], buffer=x, offset=offset*x.itemsize)
+            except:
+                pass
+            r.strides = strides=strides*x.itemsize
+            return r
+        assert_equal(make_array(4, 4, -1), array([4, 3, 2, 1]))
+        self.failUnlessRaises(ValueError, make_array, 4, 4, -2)
+        self.failUnlessRaises(ValueError, make_array, 4, 3, -1)
+        self.failUnlessRaises(ValueError, make_array, 8, 3, 1)
+        self.failUnlessRaises(ValueError, make_array, 8, 3, 0)
+
+
 class test_dtypedescr(ScipyTestCase):
     def check_construction(self):
         d1 = dtype('i4')



More information about the NumPy-Discussion mailing list