[pypy-commit] pypy numpy-record-dtypes: boring. Add support for dtypes. A lot of refactoring, not too much of

fijal noreply at buildbot.pypy.org
Sat Feb 18 17:35:39 CET 2012


Author: Maciej Fijalkowski <fijall at gmail.com>
Branch: numpy-record-dtypes
Changeset: r52611:2f1522449cee
Date: 2012-02-18 18:35 +0200
http://bitbucket.org/pypy/pypy/changeset/2f1522449cee/

Log:	boring. Add support for dtypes. A lot of refactoring, not too much
	of actual code.

diff --git a/pypy/module/micronumpy/interp_iter.py b/pypy/module/micronumpy/interp_iter.py
--- a/pypy/module/micronumpy/interp_iter.py
+++ b/pypy/module/micronumpy/interp_iter.py
@@ -49,17 +49,58 @@
 
 # structures to describe slicing
 
-class Chunk(object):
+class BaseChunk(object):
+    pass
+
+class RecordChunk(BaseChunk):
+    def __init__(self, name):
+        self.name = name
+
+    def apply(self, arr):
+        from pypy.module.micronumpy.interp_numarray import W_NDimSlice
+
+        arr = arr.get_concrete()
+        ofs, subdtype = arr.dtype.fields[self.name]
+        # strides backstrides are identical, ofs only changes start
+        return W_NDimSlice(arr.start + ofs, arr.strides[:], arr.backstrides[:],
+                           arr.shape[:], arr, subdtype)
+
+class Chunks(BaseChunk):
+    def __init__(self, l):
+        self.l = l
+
+    @jit.unroll_safe
+    def extend_shape(self, old_shape):
+        shape = []
+        i = -1
+        for i, c in enumerate(self.l):
+            if c.step != 0:
+                shape.append(c.lgt)
+        s = i + 1
+        assert s >= 0
+        return shape[:] + old_shape[s:]
+
+    def apply(self, space, arr):
+        from pypy.module.micronumpy.interp_numarray import W_NDimSlice,\
+             VirtualSlice, ConcreteArray
+
+        shape = self.extend_shape(arr.shape)
+        if not isinstance(arr, ConcreteArray):
+            return VirtualSlice(arr, self, shape)
+        r = calculate_slice_strides(arr.shape, arr.start, arr.strides,
+                                    arr.backstrides, self.l)
+        _, start, strides, backstrides = r
+        return W_NDimSlice(start, strides[:], backstrides[:],
+                           shape[:], arr)
+
+
+class Chunk(BaseChunk):
     def __init__(self, start, stop, step, lgt):
         self.start = start
         self.stop = stop
         self.step = step
         self.lgt = lgt
 
-    def extend_shape(self, shape):
-        if self.step != 0:
-            shape.append(self.lgt)
-
     def __repr__(self):
         return 'Chunk(%d, %d, %d, %d)' % (self.start, self.stop, self.step,
                                           self.lgt)
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
@@ -13,7 +13,7 @@
 from pypy.tool.sourcetools import func_with_new_name
 from pypy.rlib.rstring import StringBuilder
 from pypy.module.micronumpy.interp_iter import (ArrayIterator,
-    SkipLastAxisIterator, Chunk, ViewIterator)
+    SkipLastAxisIterator, Chunks, Chunk, ViewIterator, RecordChunk)
 from pypy.module.micronumpy.appbridge import get_appbridge_cache
 
 
@@ -328,11 +328,18 @@
 
     @jit.unroll_safe
     def _prepare_slice_args(self, space, w_idx):
+        if space.isinstance_w(w_idx, space.w_str):
+            idx = space.str_w(w_idx)
+            dtype = self.find_dtype()
+            if not dtype.is_record_type() or idx not in dtype.fields:
+                raise OperationError(space.w_ValueError, space.wrap(
+                    "field named %s not defined" % idx))
+            return RecordChunk(idx)
         if (space.isinstance_w(w_idx, space.w_int) or
             space.isinstance_w(w_idx, space.w_slice)):
-            return [Chunk(*space.decode_index4(w_idx, self.shape[0]))]
-        return [Chunk(*space.decode_index4(w_item, self.shape[i])) for i, w_item in
-                enumerate(space.fixedview(w_idx))]
+            return Chunks([Chunk(*space.decode_index4(w_idx, self.shape[0]))])
+        return Chunks([Chunk(*space.decode_index4(w_item, self.shape[i])) for i, w_item in
+                enumerate(space.fixedview(w_idx))])
 
     def count_all_true(self):
         sig = self.find_sig()
@@ -375,6 +382,17 @@
             frame.next(shapelen)
         return res
 
+    def descr_getitem(self, space, w_idx):
+        if (isinstance(w_idx, BaseArray) and w_idx.shape == self.shape and
+            w_idx.find_dtype().is_bool_type()):
+            return self.getitem_filter(space, w_idx)
+        if self._single_item_result(space, w_idx):
+            concrete = self.get_concrete()
+            item = concrete._index_of_single_item(space, w_idx)
+            return concrete.getitem(item)
+        chunks = self._prepare_slice_args(space, w_idx)
+        return chunks.apply(self)
+
     def setitem_filter(self, space, idx, val):
         size = idx.count_all_true()
         arr = SliceArray([size], self.dtype, self, val)
@@ -392,17 +410,6 @@
             frame.next_first(shapelen)
             idxi = idxi.next(shapelen)
 
-    def descr_getitem(self, space, w_idx):
-        if (isinstance(w_idx, BaseArray) and w_idx.shape == self.shape and
-            w_idx.find_dtype().is_bool_type()):
-            return self.getitem_filter(space, w_idx)
-        if self._single_item_result(space, w_idx):
-            concrete = self.get_concrete()
-            item = concrete._index_of_single_item(space, w_idx)
-            return concrete.getitem(item)
-        chunks = self._prepare_slice_args(space, w_idx)
-        return self.create_slice(chunks)
-
     def descr_setitem(self, space, w_idx, w_value):
         self.invalidated()
         if (isinstance(w_idx, BaseArray) and w_idx.shape == self.shape and
@@ -419,26 +426,9 @@
         if not isinstance(w_value, BaseArray):
             w_value = convert_to_array(space, w_value)
         chunks = self._prepare_slice_args(space, w_idx)
-        view = self.create_slice(chunks).get_concrete()
+        view = chunks.apply(self).get_concrete()
         view.setslice(space, w_value)
 
-    @jit.unroll_safe
-    def create_slice(self, chunks):
-        shape = []
-        i = -1
-        for i, chunk in enumerate(chunks):
-            chunk.extend_shape(shape)
-        s = i + 1
-        assert s >= 0
-        shape += self.shape[s:]
-        if not isinstance(self, ConcreteArray):
-            return VirtualSlice(self, chunks, shape)
-        r = calculate_slice_strides(self.shape, self.start, self.strides,
-                                    self.backstrides, chunks)
-        _, start, strides, backstrides = r
-        return W_NDimSlice(start, strides[:], backstrides[:],
-                           shape[:], self)
-
     def descr_reshape(self, space, args_w):
         """reshape(...)
         a.reshape(shape)
@@ -741,7 +731,7 @@
     def force_if_needed(self):
         if self.forced_result is None:
             concr = self.child.get_concrete()
-            self.forced_result = concr.create_slice(self.chunks)
+            self.forced_result = self.chunks.apply(concr)
 
     def _del_sources(self):
         self.child = None
@@ -1020,13 +1010,15 @@
 
 
 class W_NDimSlice(ViewArray):
-    def __init__(self, start, strides, backstrides, shape, parent):
+    def __init__(self, start, strides, backstrides, shape, parent, dtype=None):
         assert isinstance(parent, ConcreteArray)
         if isinstance(parent, W_NDimSlice):
             parent = parent.parent
         self.strides = strides
         self.backstrides = backstrides
-        ViewArray.__init__(self, shape, parent.dtype, parent.order, parent)
+        if dtype is None:
+            dtype = parent.dtype
+        ViewArray.__init__(self, shape, dtype, parent.order, parent)
         self.start = start
 
     def create_iter(self, transforms=None):
@@ -1231,7 +1223,7 @@
     for arr in args_w:
         chunks[axis] = Chunk(axis_start, axis_start + arr.shape[axis], 1,
                              arr.shape[axis])
-        res.create_slice(chunks).setslice(space, arr)
+        chunks.apply(res).setslice(space, arr)
         axis_start += arr.shape[axis]
     return res
 
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
@@ -1815,7 +1815,18 @@
         assert a[1]['y'] == 2
 
     def test_views(self):
-        skip("xx")
+        from _numpypy import array
+        a = array([(1, 2), (3, 4)], dtype=[('x', int), ('y', float)])
+        raises(ValueError, 'array([1])["x"]')
+        raises(ValueError, 'a["z"]')
+        assert a['x'][1] == 3
+        assert a['y'][1] == 4
+        a['x'][0] = 15
+        assert a['x'][0] == 15
+        b = a['x'] + a['y']
+        print b, a
+        assert (b == [15+2, 3+4]).all()
+        assert b.dtype == float
 
     def test_creation(self):
         from _numpypy import array


More information about the pypy-commit mailing list