Author: mattip <[email protected]>
Branch: ufuncapi
Changeset: r74576:27f4ddb2db05
Date: 2014-11-19 00:22 +0200
http://bitbucket.org/pypy/pypy/changeset/27f4ddb2db05/

Log:    refactor and use coalescing to pass a test

diff --git a/pypy/module/micronumpy/iterators.py 
b/pypy/module/micronumpy/iterators.py
--- a/pypy/module/micronumpy/iterators.py
+++ b/pypy/module/micronumpy/iterators.py
@@ -117,11 +117,9 @@
         self.shape_m1 = [s - 1 for s in shape]
         self.strides = strides
         self.backstrides = backstrides
-        self.slice_shape = 1
-        self.slice_stride = -1
-        if strides:
-            self.slice_stride = strides[-1]
-        self.slice_backstride = 1
+        self.slice_shape = []
+        self.slice_stride = []
+        self.slice_backstride = []
         self.slice_operand_type = concrete.SliceArray
 
         ndim = len(shape)
@@ -280,6 +278,6 @@
     def getoperand(self, state, base):
         assert state.iterator is self
         impl = self.slice_operand_type
-        arr = impl(state.offset, [self.slice_stride], [self.slice_backstride],
-                   [self.slice_shape], self.array, self.base)
+        arr = impl(state.offset, self.slice_stride, self.slice_backstride,
+                   self.slice_shape, self.array, self.base)
         return arr
diff --git a/pypy/module/micronumpy/nditer.py b/pypy/module/micronumpy/nditer.py
--- a/pypy/module/micronumpy/nditer.py
+++ b/pypy/module/micronumpy/nditer.py
@@ -200,27 +200,8 @@
                 break
         if can_coalesce:
             for i in range(len(it.iters)):
-                old_iter = it.iters[i][0]
-                shape = [s+1 for s in old_iter.shape_m1]
-                strides = old_iter.strides
-                backstrides = old_iter.backstrides
-                if it.order == 'F':
-                    new_shape = shape[1:]
-                    new_strides = strides[1:]
-                    new_backstrides = backstrides[1:]
-                    _stride = min(strides[0], old_iter.slice_stride)
-                else:
-                    new_shape = shape[:-1]
-                    new_strides = strides[:-1]
-                    new_backstrides = backstrides[:-1]
-                    _stride = old_iter.slice_stride
-                # We always want the "fastest" iterator in external loops
-                _shape = shape[fastest] * old_iter.slice_shape
-                _backstride = (_shape - 1) * _stride
-                new_iter = SliceIter(old_iter.array, old_iter.size / 
shape[fastest],
-                            new_shape, new_strides, new_backstrides,
-                            _shape, _stride, _backstride,
-                            it.op_flags[i], it)
+                new_iter = coalesce_iter(it.iters[i][0], it.op_flags[i], it,
+                                         it.order, fastest)
                 it.iters[i] = (new_iter, new_iter.reset())
             if len(it.shape) > 1:
                 if it.order == 'F':
@@ -229,26 +210,12 @@
                     it.shape = it.shape[:-1]
             else:
                 it.shape = [1]
+
         else:
             break
     # Always coalesce at least one
     for i in range(len(it.iters)):
-        old_iter = it.iters[i][0]
-        shape = [s+1 for s in old_iter.shape_m1]
-        strides = old_iter.strides
-        backstrides = old_iter.backstrides
-        new_shape = shape[:-1]
-        new_strides = strides[:-1]
-        new_backstrides = backstrides[:-1]
-        _shape = shape[-1] * old_iter.slice_shape
-        # use the operand's iterator's rightmost stride,
-        # even if it is not the fastest (for 'F' or swapped axis)
-        _stride = old_iter.slice_stride
-        _backstride = (_shape - 1) * _stride
-        new_iter = SliceIter(old_iter.array, old_iter.size / shape[-1],
-                    new_shape, new_strides, new_backstrides,
-                    _shape, _stride, _backstride,
-                    it.op_flags[i], it)
+        new_iter = coalesce_iter(it.iters[i][0], it.op_flags[i], it, 'C', -1)
         it.iters[i] = (new_iter, new_iter.reset())
     if len(it.shape) > 1:
         if it.order == 'F':
@@ -258,6 +225,43 @@
     else:
         it.shape = [1]
 
+
+def coalesce_iter(old_iter, op_flags, it, order, fastest=-1, flat=True):
+    '''
+    We usually iterate through an array one value at a time.
+    But after coalesce(), getoperand() will return a slice by removing
+    the fastest varying dimension from the beginning or end of the shape.
+    XXX - what happens on swapaxis arrays?
+    If flat is true, then the slice will be 1d, otherwise stack up the shape of
+    the fastest varying dimension in the slice, so an iterator of a  'C' array 
+    of shape (2,4,3) after two calls to coalesce will iterate 2 times over a 
slice
+    of shape (4,3) by setting the offset to the beginning of the data at each 
iteration
+    '''
+    shape = [s+1 for s in old_iter.shape_m1]
+    strides = old_iter.strides
+    backstrides = old_iter.backstrides
+    if order == 'F':
+        new_shape = shape[1:]
+        new_strides = strides[1:]
+        new_backstrides = backstrides[1:]
+        _stride = old_iter.slice_stride + [strides[0]]
+    else:
+        new_shape = shape[:-1]
+        new_strides = strides[:-1]
+        new_backstrides = backstrides[:-1]
+        # use the operand's iterator's rightmost stride,
+        # even if it is not the fastest (for 'F' or swapped axis)
+        _stride = [strides[-1]] + old_iter.slice_stride
+    _shape = [shape[fastest]]  + old_iter.slice_shape
+    _backstride = [(_shape[fastest] - 1) * _stride[0]] + 
old_iter.slice_backstride
+    if flat:
+        _shape = [support.product(_shape)]
+        _stride = [min(_stride)]
+        _backstride = [(shape[0] - 1) * _stride[0]]
+    return SliceIter(old_iter.array, old_iter.size / shape[fastest],
+                new_shape, new_strides, new_backstrides,
+                _shape, _stride, _backstride, op_flags, it)
+
 class IndexIterator(object):
     def __init__(self, shape, backward=False):
         self.shape = shape
diff --git a/pypy/module/micronumpy/ufuncs.py b/pypy/module/micronumpy/ufuncs.py
--- a/pypy/module/micronumpy/ufuncs.py
+++ b/pypy/module/micronumpy/ufuncs.py
@@ -9,7 +9,7 @@
 from pypy.module.micronumpy import boxes, descriptor, loop, constants as NPY
 from pypy.module.micronumpy.base import convert_to_array, W_NDimArray
 from pypy.module.micronumpy.ctors import numpify
-from pypy.module.micronumpy.nditer import W_NDIter
+from pypy.module.micronumpy.nditer import W_NDIter, coalesce_iter
 from pypy.module.micronumpy.strides import shape_agreement
 from pypy.module.micronumpy.support import _parse_signature
 from rpython.rlib.rawstorage import (raw_storage_setitem, free_raw_storage,
@@ -698,7 +698,7 @@
 
         # TODO parse and handle subok
         # TODO handle flags, op_flags
-        w_flags = space.w_None #space.newlist([space.wrap('external_loop')])
+        w_flags = space.w_None # NOT 'external_loop', we do coalescing by 
core_num_dims
         w_op_flags = space.newtuple([space.wrap(['readonly'])] * len(inargs) + 
\
                                     [space.wrap(['readwrite'])] * len(outargs))
         w_op_dtypes = space.w_None
@@ -706,14 +706,25 @@
         w_itershape = space.newlist([space.wrap(i) for i in iter_shape]) 
         w_op_axes = space.w_None
 
-        # mimic NpyIter_AdvancedNew with a nditer
 
         if self.stack_inputs:
+            # mimic NpyIter_AdvancedNew with a nditer
             nd_it = W_NDIter(space, space.newlist(inargs + outargs), w_flags,
                           w_op_flags, w_op_dtypes, w_casting, w_op_axes,
                           w_itershape)
-            # XXX coalesce each iterators, according to inner_dimensions
+            # coalesce each iterators, according to inner_dimensions
+            if nd_it.order == 'F':
+                fastest = 0
+            else:
+                fastest = -1
+            for i in range(len(inargs) + len(outargs)):
+                for j in range(self.core_num_dims[i]):
+                    new_iter = coalesce_iter(nd_it.iters[i][0], 
nd_it.op_flags[i],
+                                    nd_it, nd_it.order, fastest, flat=False)
+                    nd_it.iters[i] = (new_iter, new_iter.reset())
+            # do the iteration
             while not nd_it.done:
+                # XXX jit me
                 for it, st in nd_it.iters:
                     if not it.done(st):
                         break
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to