[pypy-commit] pypy numpy-fixes: make view actually a view rather than a copy if dtype is same-length

mattip noreply at buildbot.pypy.org
Wed Apr 29 21:28:29 CEST 2015


Author: mattip <matti.picus at gmail.com>
Branch: numpy-fixes
Changeset: r76949:8e4a51fc2b92
Date: 2015-04-28 22:53 +0300
http://bitbucket.org/pypy/pypy/changeset/8e4a51fc2b92/

Log:	make view actually a view rather than a copy if dtype is same-length

diff --git a/pypy/module/micronumpy/concrete.py b/pypy/module/micronumpy/concrete.py
--- a/pypy/module/micronumpy/concrete.py
+++ b/pypy/module/micronumpy/concrete.py
@@ -90,9 +90,13 @@
                               new_shape, self, orig_array)
         return None
 
-    def get_view(self, space, orig_array, dtype, new_shape):
-        strides, backstrides = calc_strides(new_shape, dtype,
+    def get_view(self, space, orig_array, dtype, new_shape, reuse_strides=False):
+        if not reuse_strides:
+            strides, backstrides = calc_strides(new_shape, dtype,
                                                     self.order)
+        else:
+            strides = self.get_strides()
+            backstrides = self.get_backstrides()
         return SliceArray(self.start, strides, backstrides, new_shape,
                           self, orig_array, dtype=dtype)
 
@@ -328,11 +332,7 @@
         return ArrayBuffer(self, readonly)
 
     def astype(self, space, dtype):
-        # we want to create a new array, but must respect the strides
-        # in self. So find a factor of the itemtype.elsize, and use this
-        factor = float(dtype.elsize) / self.dtype.elsize
-        strides = [int(factor*s) for s in self.get_strides()]
-        backstrides = [int(factor*s) for s in self.get_backstrides()]
+        strides, backstrides = calc_strides(self.get_shape(), dtype, self.order)
         impl = ConcreteArray(self.get_shape(), dtype, self.order,
                              strides, backstrides)
         loop.setslice(space, impl.get_shape(), impl, self)
diff --git a/pypy/module/micronumpy/ndarray.py b/pypy/module/micronumpy/ndarray.py
--- a/pypy/module/micronumpy/ndarray.py
+++ b/pypy/module/micronumpy/ndarray.py
@@ -850,7 +850,15 @@
                     raise OperationError(space.w_ValueError, space.wrap(
                         "new type not compatible with array."))
                 # Strides, shape does not change
-                v = impl.astype(space, dtype)
+                if dtype.is_object() != impl.dtype.is_object():
+                    raise oefmt(space.w_ValueError, 'expect trouble in ndarray.view,'
+                        ' target dtype %r but self.dtype %r',dtype, impl.dtype)
+                
+                base = impl.base()
+                if base is None:
+                    base = self
+                v = impl.get_view(space, base, dtype, self.get_shape(),
+                        reuse_strides=True)
                 return wrap_impl(space, w_type, self, v)
             strides = impl.get_strides()
             if dims == 1 or strides[0] <strides[-1]:
diff --git a/pypy/module/micronumpy/test/test_ndarray.py b/pypy/module/micronumpy/test/test_ndarray.py
--- a/pypy/module/micronumpy/test/test_ndarray.py
+++ b/pypy/module/micronumpy/test/test_ndarray.py
@@ -1817,6 +1817,8 @@
         assert exc.value[0] == 'new type not compatible with array.'
         s[...] = 2
         v = s.view(x.__class__)
+        assert v.strides == s.strides
+        assert v.base is s.base
         assert (v == 2).all()
     
     def test_tolist_scalar(self):
@@ -2169,7 +2171,6 @@
 
     def test_astype(self):
         from numpy import array, arange
-        import gc
         b = array(1).astype(float)
         assert b == 1
         assert b.dtype == float
@@ -2186,8 +2187,6 @@
         a = arange(11)[::-1]
         b = a.astype('int32')
         assert (b == a).all()
-        del b
-        gc.collect() 
 
         a = arange(6, dtype='f4').reshape(2,3)
         b = a.T.astype('i4')
diff --git a/pypy/module/micronumpy/test/test_subtype.py b/pypy/module/micronumpy/test/test_subtype.py
--- a/pypy/module/micronumpy/test/test_subtype.py
+++ b/pypy/module/micronumpy/test/test_subtype.py
@@ -72,7 +72,7 @@
 
     def test_subtype_view(self):
         from numpy import ndarray, array
-        class matrix(ndarray):
+        class matrix(ndarray, object):
             def __new__(subtype, data, dtype=None, copy=True):
                 if isinstance(data, matrix):
                     return data
@@ -86,6 +86,11 @@
             b = a.view(s)
             assert b == a
             assert type(b) is type(a)
+        a = matrix(array(range(5)))
+        for s in [matrix, ndarray]:
+            b = ndarray.view(a, s)
+            assert (b == a).all()
+            assert type(b) is s
 
     def test_subtype_like_matrix(self):
         import numpy as np
diff --git a/pypy/module/micronumpy/types.py b/pypy/module/micronumpy/types.py
--- a/pypy/module/micronumpy/types.py
+++ b/pypy/module/micronumpy/types.py
@@ -34,15 +34,20 @@
     _raw_storage_getitem_unaligned = raw_storage_getitem_unaligned
     def raw_storage_setitem_unaligned(storage, offset, value):
         assert offset >=0
-        assert offset < storage._obj.getlength()
+        try:
+            assert offset < storage._obj.getlength()
+        except AttributeError:
+            pass
         return _raw_storage_setitem_unaligned(storage, offset, value) 
 
     def raw_storage_getitem_unaligned(T, storage, offset):
         assert offset >=0
-        assert offset < storage._obj.getlength()
+        try:
+            assert offset < storage._obj.getlength()
+        except AttributeError:
+            pass
         return _raw_storage_getitem_unaligned(T, storage, offset) 
 '''
-
 def simple_unary_op(func):
     specialize.argtype(1)(func)
     @functools.wraps(func)


More information about the pypy-commit mailing list