[pypy-commit] pypy numppy-flatitter: more tests

mattip noreply at buildbot.pypy.org
Fri Jan 27 10:43:32 CET 2012


Author: mattip
Branch: numppy-flatitter
Changeset: r51843:794461ec9ef3
Date: 2012-01-27 11:24 +0200
http://bitbucket.org/pypy/pypy/changeset/794461ec9ef3/

Log:	more tests

diff --git a/pypy/module/micronumpy/test/test_iter.py b/pypy/module/micronumpy/test/test_iter.py
--- a/pypy/module/micronumpy/test/test_iter.py
+++ b/pypy/module/micronumpy/test/test_iter.py
@@ -1,12 +1,132 @@
 import py
 from pypy.module.micronumpy.interp_iter import ViewIterator
 
+# This is both a test and a mini-tutorial on iterators, strides, and
+# memory layout. It assumes you are familiar with the terms, see
+# http://docs.scipy.org/doc/numpy/reference/arrays.ndarray.html
+# for a more gentle introduction.
+#
+# Given an array x: x.shape == [5,6],
+#
+# At which byte in x.data does the item x[3,4] begin?
+# if x.strides==[1,5]:
+#     pData = x.pData + (x.start + 3*1 + 4*5)*sizeof(x.pData[0])
+#     pData = x.pData + (x.start + 24) * sizeof(x.pData[0])
+# so the offset of the element is 24 elements after the first
+#
+# What is the next element in x after coordinates [3,4]?
+# if x.order =='C':
+#    next == [3,5] => offset is 28
+# if x.order =='F':
+#    next == [4,4] => offset is 24
+# so for the strides [1,5] x is 'F' contiguous
+# likewise, for the strides [6,1] x would be 'C' contiguous.
+# 
+# Iterators have an internal representation of the current coordinates
+# (indices), the array, strides, and backstrides. A short digression to
+# explain backstrides: what is the coordinate and offset after [3,5] in
+# the example above?
+# if x.order == 'C':
+#    next == [4,0] => offset is 4
+# if x.order == 'F':
+#    next == [4,5] => offset is 25
+# Note that in 'C' order we stepped BACKWARDS 24 while 'overflowing' a
+# shape dimension
+#   which is back 25 and forward 1,
+#   which is x.strides[1] * (x.shape[1] - 1) + x.strides[0]
+# so if we precalculate the overflow backstride as 
+# [x.strides[i] * (x.shape[i] - 1) for i in range(len(x.shape))]
+# we can go faster.
+# All the calculations happen in next()
+#
+# next_step_x() tries to do the iteration for a number of steps at once,
+# but then we cannot gaurentee that we only overflow one single shape 
+# dimension, perhaps we could overflow times in one big step.
+#
+
 class TestIterDirect(object):
-    def test_viewiterator(self):
-        i = ViewIterator(0, [5, 1], [10, 4], [3, 5])
+    def test_C_viewiterator(self):
+        #Let's get started, simple iteration in C order with
+        #contiguous layout => strides[-1] is 1
+        start = 0
+        shape = [3, 5] 
+        strides = [5, 1]
+        backstrides = [x * (y - 1) for x,y in zip(strides, shape)]
+        assert backstrides == [10, 4]
+        i = ViewIterator(start, strides, backstrides, shape)
         i = i.next(2)
         i = i.next(2)
         i = i.next(2)
         assert i.offset == 3
         assert not i.done()
         assert i.indices == [0,3]
+        #cause a dimension overflow
+        i = i.next(2)
+        i = i.next(2)
+        assert i.offset == 5
+        assert i.indices == [1,0]
+
+        #Now what happens if the array is transposed? strides[-1] != 1
+        # therefore layout is non-contiguous
+        strides = [1, 3]
+        backstrides = [x * (y - 1) for x,y in zip(strides, shape)]
+        assert backstrides == [2, 12]
+        i = ViewIterator(start, strides, backstrides, shape)
+        i = i.next(2)
+        i = i.next(2)
+        i = i.next(2)
+        assert i.offset == 9
+        assert not i.done()
+        assert i.indices == [0,3]
+        #cause a dimension overflow
+        i = i.next(2)
+        i = i.next(2)
+        assert i.offset == 1
+        assert i.indices == [1,0]
+
+    def test_C_viewiterator_step(self):
+        #iteration in C order with #contiguous layout => strides[-1] is 1
+        #skip less than the shape
+        start = 0
+        shape = [3, 5] 
+        strides = [5, 1]
+        backstrides = [x * (y - 1) for x,y in zip(strides, shape)]
+        assert backstrides == [10, 4]
+        i = ViewIterator(start, strides, backstrides, shape)
+        i = i.next_skip_x(2,2)
+        i = i.next_skip_x(2,2)
+        i = i.next_skip_x(2,2)
+        assert i.offset == 6
+        assert not i.done()
+        assert i.indices == [1,1]
+        #And for some big skips
+        i = i.next_skip_x(2,5)
+        assert i.offset == 11
+        assert i.indices == [2,1]
+        i = i.next_skip_x(2,5)
+        # Note: the offset does not overflow but recycles,
+        # this is good for broadcast
+        assert i.offset == 1
+        assert i.indices == [0,1]
+        assert i.done()
+
+        #Now what happens if the array is transposed? strides[-1] != 1
+        # therefore layout is non-contiguous
+        strides = [1, 3]
+        backstrides = [x * (y - 1) for x,y in zip(strides, shape)]
+        assert backstrides == [2, 12]
+        i = ViewIterator(start, strides, backstrides, shape)
+        i = i.next_skip_x(2,2)
+        i = i.next_skip_x(2,2)
+        i = i.next_skip_x(2,2)
+        assert i.offset == 4
+        assert i.indices == [1,1]
+        assert not i.done()
+        i = i.next_skip_x(2,5)
+        assert i.offset == 5
+        assert i.indices == [2,1]
+        assert not i.done()
+        i = i.next_skip_x(2,5)
+        assert i.indices == [0,1]
+        assert i.offset == 3
+        assert i.done()


More information about the pypy-commit mailing list