[pypy-commit] pypy missing-ndarray-attributes: implement diagonal. I wonder if the jit would help here

fijal noreply at buildbot.pypy.org
Wed Oct 31 18:00:32 CET 2012


Author: Maciej Fijalkowski <fijall at gmail.com>
Branch: missing-ndarray-attributes
Changeset: r58650:e28b7a70729c
Date: 2012-10-31 18:59 +0200
http://bitbucket.org/pypy/pypy/changeset/e28b7a70729c/

Log:	implement diagonal. I wonder if the jit would help here

diff --git a/pypy/module/micronumpy/interp_arrayops.py b/pypy/module/micronumpy/interp_arrayops.py
--- a/pypy/module/micronumpy/interp_arrayops.py
+++ b/pypy/module/micronumpy/interp_arrayops.py
@@ -173,12 +173,24 @@
 
 def diagonal(space, arr, offset, axis1, axis2):
     shape = arr.get_shape()
+    shapelen = len(shape)
+    if offset < 0:
+        offset = -offset
+        axis1, axis2 = axis2, axis1
     size = min(shape[axis1], shape[axis2] - offset)
     dtype = arr.dtype
-    if len(shape) == 2:
+    if axis1 < axis2:
+        shape = (shape[:axis1] + shape[axis1 + 1:axis2] +
+                 shape[axis2 + 1:] + [size])
+    else:
+        shape = (shape[:axis2] + shape[axis2 + 1:axis1] +
+                 shape[axis1 + 1:] + [size])
+    out = W_NDimArray.from_shape(shape, dtype)
+    if size == 0:
+        return out
+    if shapelen == 2:
         # simple case
-        out = W_NDimArray.from_shape([size], dtype)
         loop.diagonal_simple(space, arr, out, offset, axis1, axis2, size)
-        return out
     else:
-        xxx
+        loop.diagonal_array(space, arr, out, offset, axis1, axis2, shape)
+    return out
diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py
--- a/pypy/module/micronumpy/interp_numarray.py
+++ b/pypy/module/micronumpy/interp_numarray.py
@@ -439,6 +439,9 @@
             raise operationerrfmt(space.w_ValueError,
                  "axis1(=%d) and axis2(=%d) must be withing range (ndim=%d)",
                                   axis1, axis2, len(self.get_shape()))
+        if axis1 == axis2:
+            raise OperationError(space.w_ValueError, space.wrap(
+                "axis1 and axis2 cannot be the same"))
         return interp_arrayops.diagonal(space, self.implementation, offset,
                                         axis1, axis2)
     
diff --git a/pypy/module/micronumpy/loop.py b/pypy/module/micronumpy/loop.py
--- a/pypy/module/micronumpy/loop.py
+++ b/pypy/module/micronumpy/loop.py
@@ -9,7 +9,7 @@
 from pypy.rlib import jit
 from pypy.rpython.lltypesystem import lltype, rffi
 from pypy.module.micronumpy.base import W_NDimArray
-from pypy.module.micronumpy.iter import PureShapeIterator
+from pypy.module.micronumpy.iter import PureShapeIterator, ConcreteArrayIterator
 from pypy.module.micronumpy import constants
 from pypy.module.micronumpy.support import int_w
 
@@ -598,3 +598,21 @@
         out_iter.setitem(arr.getitem_index(space, index))
         i += 1
         out_iter.next()
+
+def diagonal_array(space, arr, out, offset, axis1, axis2, shape):
+    out_iter = out.create_iter()
+    iter = PureShapeIterator(shape, [])
+    shapelen = len(shape)
+    while not iter.done():
+        last_index = iter.indexes[-1]
+        if axis1 < axis2:
+            indexes = (iter.indexes[:axis1] + [last_index] +
+                       iter.indexes[axis1:axis2 - 1] + [last_index + offset] +
+                       iter.indexes[axis2 - 1:shapelen - 1])
+        else:
+            indexes = (iter.indexes[:axis2] + [last_index + offset] +
+                       iter.indexes[axis2:axis1 - 1] + [last_index] +
+                       iter.indexes[axis1 - 1:shapelen - 1])
+        out_iter.setitem(arr.getitem_index(space, indexes))
+        iter.next()
+        out_iter.next()
diff --git a/pypy/module/micronumpy/test/test_numarray.py b/pypy/module/micronumpy/test/test_numarray.py
--- a/pypy/module/micronumpy/test/test_numarray.py
+++ b/pypy/module/micronumpy/test/test_numarray.py
@@ -2114,9 +2114,27 @@
         from _numpypy import array
         a = array([[1, 2], [3, 4], [5, 6]])
         raises(ValueError, 'array([1, 2]).diagonal()')
+        raises(ValueError, 'a.diagonal(0, 0, 0)')
+        raises(ValueError, 'a.diagonal(0, 0, 13)')
         assert (a.diagonal() == [1, 4]).all()
         assert (a.diagonal(1) == [2]).all()
 
+    def test_diagonal_axis(self):
+        from _numpypy import arange
+        a = arange(12).reshape(2, 3, 2)
+        assert (a.diagonal(0, 0, 1) == [[0, 8], [1, 9]]).all()
+        assert a.diagonal(3, 0, 1).shape == (2, 0)
+        assert (a.diagonal(1, 0, 1) == [[2, 10], [3, 11]]).all()         
+        assert (a.diagonal(0, 2, 1) == [[0, 3], [6, 9]]).all()        
+        assert (a.diagonal(2, 2, 1) == [[4], [10]]).all()        
+        assert (a.diagonal(1, 2, 1) == [[2, 5], [8, 11]]).all()        
+
+    def test_diagonal_axis_neg_ofs(self):
+        from _numpypy import arange
+        a = arange(12).reshape(2, 3, 2)
+        assert (a.diagonal(-1, 0, 1) == [[6], [7]]).all()
+        assert a.diagonal(-2, 0, 1).shape == (2, 0)
+
 class AppTestSupport(BaseNumpyAppTest):
     def setup_class(cls):
         import struct


More information about the pypy-commit mailing list