[pypy-commit] pypy fortran-order: refactor order handling in nditer

mattip noreply at buildbot.pypy.org
Fri Oct 9 13:51:32 CEST 2015


Author: mattip <matti.picus at gmail.com>
Branch: fortran-order
Changeset: r80078:5ccb2d126b87
Date: 2015-10-09 09:26 +0300
http://bitbucket.org/pypy/pypy/changeset/5ccb2d126b87/

Log:	refactor order handling in nditer

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
@@ -349,7 +349,6 @@
     def __init__(self, space, w_seq, w_flags, w_op_flags, w_op_dtypes,
                  w_casting, w_op_axes, w_itershape, buffersize=0,
                  order=NPY.KEEPORDER):
-        self.order = order
         self.external_loop = False
         self.buffered = False
         self.tracked_index = ''
@@ -377,7 +376,25 @@
                         for w_elem in w_seq_as_list]
         else:
             self.seq = [convert_to_array(space, w_seq)]
-
+        if order == NPY.ANYORDER:
+            # 'A' means "'F' order if all the arrays are Fortran contiguous,
+            #            'C' order otherwise"
+            order = NPY.CORDER
+            for s in self.seq:
+                if s and not(s.get_flags() & NPY.ARRAY_F_CONTIGUOUS):
+                     break
+                else:
+                    order = NPY.FORTRANORDER
+        elif order == NPY.KEEPORDER:
+            # 'K' means "as close to the order the array elements appear in
+            #     memory as possible", so match self.order to seq.order
+            order = NPY.CORDER
+            for s in self.seq:
+                if s and not(s.get_order() == NPY.FORTRANORDER):
+                     break
+                else:
+                    order = NPY.FORTRANORDER
+        self.order = order
         parse_func_flags(space, self, w_flags)
         self.op_flags = parse_op_arg(space, 'op_flags', w_op_flags,
                                      len(self.seq), parse_op_flag)
@@ -488,7 +505,7 @@
                                     space.str_w(self_d.descr_repr(space)),
                                     space.str_w(seq_d.descr_repr(space)),
                                     i, self.casting)
-        elif self.buffered:
+        elif self.buffered and not (self.external_loop and len(self.seq)<2):
             for i in range(len(self.seq)):
                 if i not in outargs:
                     self.seq[i] = self.seq[i].descr_copy(space,
@@ -510,12 +527,19 @@
 
     def get_iter(self, space, i):
         arr = self.seq[i]
-        dtype = self.dtypes[i]
-        shape = self.shape
         imp = arr.implementation
-        backward = is_backward(imp.order, self.order)
         if arr.is_scalar():
             return ConcreteIter(imp, 1, [], [], [], self.op_flags[i], self)
+        shape = self.shape
+        if (self.external_loop and len(self.seq)<2 and self.buffered):
+            # Special case, always return a memory-ordered iterator
+            stride = imp.dtype.elsize
+            backstride = imp.size * stride - stride
+            return ConcreteIter(imp, imp.get_size(), 
+                [support.product(shape)], [stride], [backstride],
+                            self.op_flags[i], self)
+        backward = imp.order != self.order
+        # XXX cleanup needed
         if (abs(imp.strides[0]) < abs(imp.strides[-1]) and not backward) or \
            (abs(imp.strides[0]) > abs(imp.strides[-1]) and backward):
             # flip the strides. Is this always true for multidimension?
diff --git a/pypy/module/micronumpy/test/test_nditer.py b/pypy/module/micronumpy/test/test_nditer.py
--- a/pypy/module/micronumpy/test/test_nditer.py
+++ b/pypy/module/micronumpy/test/test_nditer.py
@@ -114,10 +114,7 @@
         from numpy import nditer, array
 
         a = array([[1, 2], [3, 4]], order="C")
-        try:
-            b = array([[1, 2], [3, 4]], order="F")
-        except (NotImplementedError, ValueError):
-            skip('Fortran order not implemented')
+        b = array([[1, 2], [3, 4]], order="F")
 
         it = nditer([a, b])
         r = list(it)
@@ -161,11 +158,7 @@
         assert r[0][0] == 100
 
         r = []
-        try:
-            it = nditer(a, flags=['buffered'], order='F')
-        except NotImplementedError as e:
-            assert 'unsupported value for order' in str(e)
-            skip('buffered with order="F" requires fortran tmp array creation')
+        it = nditer(a, flags=['buffered'], order='F')
         for x in it:
             r.append(x)
         array_r = array(r)


More information about the pypy-commit mailing list