[pypy-svn] r46411 - in pypy/dist/pypy/rpython/numpy: . test

simonb at codespeak.net simonb at codespeak.net
Sat Sep 8 00:23:27 CEST 2007


Author: simonb
Date: Sat Sep  8 00:23:25 2007
New Revision: 46411

Modified:
   pypy/dist/pypy/rpython/numpy/rarray.py
   pypy/dist/pypy/rpython/numpy/test/test_array.py
Log:
numpy: less code, more features. that's what we like.

Modified: pypy/dist/pypy/rpython/numpy/rarray.py
==============================================================================
--- pypy/dist/pypy/rpython/numpy/rarray.py	(original)
+++ pypy/dist/pypy/rpython/numpy/rarray.py	Sat Sep  8 00:23:25 2007
@@ -4,12 +4,13 @@
 from pypy.rpython.rlist import AbstractBaseListRepr
 from pypy.rpython.rtuple import AbstractTupleRepr
 from pypy.rpython.error import TyperError
-from pypy.rpython.lltypesystem import lltype, llmemory
+from pypy.rpython.lltypesystem import lltype, llmemory, rtuple
 from pypy.rpython.lltypesystem.rtupletype import TUPLE_TYPE
 from pypy.rpython.rslice import AbstractSliceRepr
 from pypy.rpython.lltypesystem.lltype import \
-    GcArray, GcStruct, Signed, Ptr, Unsigned, Void, FixedSizeArray, Bool,\
+    GcArray, GcStruct, Number, Primitive, Signed, Ptr, Unsigned, Void, FixedSizeArray, Bool,\
     GcForwardReference, malloc, direct_arrayitems, direct_ptradd, nullptr
+from pypy.rpython.lltypesystem.rffi import cast
 from pypy.rpython.lltypesystem.rtuple import TupleRepr
 from pypy.annotation.model import SomeObject, SomeInteger
 from pypy.rpython.numpy.aarray import SomeArray
@@ -98,9 +99,22 @@
             it.coordinates[i] = 0
     ll_iter_reset._always_inline_ = True
 
-    def ll_iter_new(ITER, ao, iter_reset=ll_iter_reset):
+    def ll_iter_new(ITER, ao, target_ao, iter_reset, iter_broadcast_to_shape):
         assert ao.dataptr
-        assert ao.ndim == ndim
+        # Suffix of ao.shape must match target_ao.shape
+        # (suffix starts at the first non-1 entry in ao.shape.)
+        # ao.shape must be no longer than target_ao.shape.
+        assert ao.ndim <= ndim
+        assert target_ao.ndim == ndim
+        # XX check suffix condition here... ?
+        broadcast = ao.ndim < ndim
+        i = 0
+        while not broadcast and i < ao.ndim:
+            if ao.shape[i] == 1 and target_ao.shape[i] > 1:
+                broadcast = True
+            i += 1
+        if broadcast:
+            return iter_broadcast_to_shape(ITER, ao, target_ao, iter_reset)
         it = malloc(ITER)
         it.nd_m1 = ndim - 1
         it.size = ll_mul_list(ao.shape, ndim)
@@ -115,7 +129,7 @@
         return it
     ll_iter_new._always_inline_ = True
 
-    def ll_iter_broadcast_to_shape(ITER, ao, target_ao, iter_reset=ll_iter_reset):
+    def ll_iter_broadcast_to_shape(ITER, ao, target_ao, iter_reset):
         "iterate over <ao> but broadcast to the shape of <target_ao>"
         assert target_ao.ndim == ndim
         delta = j = ndim - ao.ndim
@@ -143,6 +157,9 @@
         return it
     ll_iter_broadcast_to_shape._always_inline_ = True    
     
+    # XXX
+    # I think this is the only function that needs to be 
+    # generated-per-ndim:
     def ll_iter_next(it):
         it.index += 1
         for i in unroll_ndim_rev:
@@ -164,6 +181,8 @@
 
 
 def ll_array_set(it0, it1, iter_next):
+    if it0.size == 0:
+        return # empty LHS..
     assert it0.size == it1.size
     while it0.index < it0.size:
         it0.dataptr[0] = it1.dataptr[0]
@@ -187,25 +206,30 @@
         self.lowleveltype = self.ITER
 
 class ArrayRepr(Repr):
+    def make_types(cls, ndim, ITEM):
+        DATA_PTR = Ptr(FixedSizeArray(ITEM, 1))
+        ITEMARRAY = GcArray(ITEM, hints={'nolength':True})
+        INDEXARRAY = FixedSizeArray(NPY_INTP, ndim)
+        STRUCT = GcStruct("array",
+            ("data", Ptr(ITEMARRAY)), # pointer to raw data buffer 
+            ("dataptr", DATA_PTR), # pointer to first element
+            ("ndim", Signed), # number of dimensions
+            ("shape", INDEXARRAY), # size in each dimension
+            ("strides", INDEXARRAY), # elements to jump to get to the
+                                     # next element in each dimension 
+        )
+        ARRAY = Ptr(STRUCT)
+        return ARRAY, INDEXARRAY
+    make_types = classmethod(make_types)
+
     def __init__(self, rtyper, s_array):
         self.s_array = s_array
         self.s_value = s_array.get_item_type()
         self.ndim = s_array.ndim
-        self.item_repr = rtyper.getrepr(self.s_value) # XX rename r_item XX
-        self.ITEM = self.item_repr.lowleveltype
-        ITEMARRAY = GcArray(self.ITEM, hints={'nolength':True})
-        self.INDEXARRAY = FixedSizeArray(NPY_INTP, self.ndim)
+        self.r_item = rtyper.getrepr(self.s_value)
+        self.ITEM = self.r_item.lowleveltype
         self.itemsize = sizeof(self.ITEM)
-        DATA_PTR = Ptr(FixedSizeArray(self.ITEM, 1))
-        self.STRUCT = GcStruct("array",
-            ("data", Ptr(ITEMARRAY)), # pointer to raw data buffer 
-            ("dataptr", DATA_PTR), # pointer to first element
-            ("ndim", Signed), # number of dimensions
-            ("shape", self.INDEXARRAY), # size in each dimension
-            ("strides", self.INDEXARRAY), # elements to jump to get to the
-                                          # next element in each dimension 
-        )
-        self.ARRAY = Ptr(self.STRUCT)
+        self.ARRAY, self.INDEXARRAY = self.make_types(self.ndim, self.ITEM)
         self.lowleveltype = self.ARRAY
         self.ITER = ARRAY_ITER(self.ARRAY, self.INDEXARRAY)
 
@@ -283,96 +307,6 @@
         cARRAY = hop.inputconst(Void, hop.r_result.ARRAY.TO)
         return hop.gendirectcall(ll_add, cARRAY, v_arr1, v_arr2)
 
-
-#class __extend__(pairtype(ArrayRepr, Repr)): # <------ USE THIS ??
-class __extend__(pairtype(ArrayRepr, IntegerRepr)):
-    def rtype_setitem((r_array, r_int), hop):
-        assert r_array.ndim == 1, "NotImplemented"
-        v_array, v_index, v_item = hop.inputargs(r_array, Signed, r_array.item_repr)
-        return hop.gendirectcall(ll_setitem1, v_array, v_index, v_item)
-
-    def rtype_getitem((r_array, r_int), hop):
-        assert r_array.ndim == 1, "NotImplemented"
-        v_array, v_index = hop.inputargs(r_array, Signed)
-        return hop.gendirectcall(ll_getitem1, v_array, v_index)
-
-def gen_get_view_slc(r_array, r_slc, hop): # XX method on the pair type ?
-    ndim = r_array.ndim
-    rslice = hop.rtyper.type_system.rslice
-    def ll_get_view_slc(ARRAY, ao, slc):
-        array = ll_allocate(ARRAY, ndim)
-        dataptr = direct_arrayitems(ao.data)
-        src_i = 0
-        tgt_i = 0
-        if r_slc == rslice.startonly_slice_repr:
-            start = slc
-            size = ao.shape[src_i]
-            if start > size:
-                start = size
-            size -= start
-            dataptr = direct_ptradd(dataptr, start*ao.strides[src_i])
-            array.shape[tgt_i] = size
-            array.strides[tgt_i] = ao.strides[src_i]
-            tgt_i += 1
-        elif r_slc == rslice.startstop_slice_repr:
-            start = slc.start
-            stop = slc.stop
-            size = ao.shape[src_i]
-            if start > size:
-                start = size
-            dataptr = direct_ptradd(dataptr, start*ao.strides[src_i])
-            if stop < size:
-                size = stop
-            size -= start
-            if size < 0:
-                size = 0
-            array.shape[tgt_i] = size
-            array.strides[tgt_i] = ao.strides[src_i]
-            tgt_i += 1
-        else:
-            assert 0
-        src_i += 1
-        # consume the rest of ndim as if we found more slices
-        while tgt_i < ndim:
-            array.shape[tgt_i] = ao.shape[src_i]
-            array.strides[tgt_i] = ao.strides[src_i]
-            tgt_i += 1
-            src_i += 1
-        assert tgt_i == ndim
-        array.dataptr = dataptr
-        array.data = ao.data # keep a ref
-        return array
-    return ll_get_view_slc
-            
-class __extend__(pairtype(ArrayRepr, AbstractSliceRepr)):
-    def rtype_setitem((r_array, r_slc), hop):
-        r_item = hop.args_r[2]
-        v_array, v_slc, v_item = hop.inputargs(r_array, r_slc, r_item)
-        cITER = hop.inputconst(Void, r_array.ITER.TO)
-        cARRAY = hop.inputconst(Void, r_array.ARRAY.TO)
-        iter_new, iter_reset, iter_broadcast, iter_next = gen_iter_funcs(r_array.ndim)        
-        cnext = hop.inputconst(Void, iter_next)
-        creset = hop.inputconst(Void, iter_reset)
-## Blech... it would be nice to reuse gen_get_view
-##            r_tuple = TupleRepr(hop.rtyper, [r_item]) # XX how to get this from rtyper ?
-##            get_view = gen_get_view(r_array, r_tuple, hop)
-##            # make a v_tuple here... 
-##            v_view = hop.gendirectcall(get_view, cARRAY, v_array, v_tuple)
-        get_view = gen_get_view_slc(r_array, r_slc, hop)
-        v_view = hop.gendirectcall(get_view, cARRAY, v_array, v_slc)
-        v_it0 = hop.gendirectcall(iter_new, cITER, v_view, creset)
-        if isinstance(r_item, ArrayRepr):
-            if r_array.ndim == r_item.ndim:
-                v_it1 = hop.gendirectcall(iter_new, cITER, v_item, creset)
-            else:
-                v_it1 = hop.gendirectcall(iter_broadcast, cITER, v_item, v_array, creset)
-            assert r_array.ndim >= r_item.ndim
-            return hop.gendirectcall(ll_array_set, v_it0, v_it1, cnext)
-        elif isinstance(r_item, FloatRepr):
-            # setitem from scalar
-            return hop.gendirectcall(ll_array_set1, v_item, v_it0, cnext)
-        else:
-            raise TypeError("can't setitem from %s"%r_item)
         
 def gen_getset_item(ndim):
     unrolling_dims = unrolling_iterable(range(ndim))
@@ -449,11 +383,52 @@
         return array
     return ll_get_view
             
+def convert_int_to_tuple(r_int, v_int, llops):
+    # int -> (int,)
+    r_tuple = TupleRepr(llops.rtyper, [r_int]) # XX get this from rtyper cache ?
+    v_tuple = rtuple.newtuple(llops, r_tuple, [v_int])
+    return r_tuple, v_tuple
+
+def convert_slice_to_tuple(r_slc, v_slc, llops):
+    # slice -> (slice,)
+    r_tuple = TupleRepr(llops.rtyper, [r_slc]) # XX get this from rtyper cache ?
+    v_tuple = rtuple.newtuple(llops, r_tuple, [v_slc])
+    return r_tuple, v_tuple
+
+def convert_list_to_array(r_list, v_list, llops):
+    # [...] -> array([...])
+    from pypy.rpython.rmodel import inputconst
+    ITEM = r_list.item_repr.lowleveltype
+    ARRAY, _ = ArrayRepr.make_types(1, ITEM)
+    cARRAY = inputconst(Void, ARRAY.TO)
+    v_array = llops.gendirectcall(ll_build_from_list, cARRAY, v_list) # XX does a copy :P
+    #v_array = llops.gendirectcall(ll_build_alias_to_list, cARRAY, v_list) # nice idea...
+    return v_array
+
+def convert_scalar_to_array(ITEM, v_item, llops):
+    # x -> array([x])
+    from pypy.rpython.rmodel import inputconst
+    ARRAY, _ = ArrayRepr.make_types(1, ITEM)
+    cARRAY = inputconst(Void, ARRAY.TO)
+    cITEM = inputconst(Void, ITEM)
+    v_casted = llops.genop("cast_primitive", [v_item], ITEM)
+    v_array = llops.gendirectcall(ll_build_from_scalar, cARRAY, v_casted)
+    return v_array
+
+class __extend__(pairtype(ArrayRepr, Repr)):
+    def rtype_getitem((r_array, r_key), hop):
+
+        v_array, v_key = hop.inputargs(r_array, r_key)
+        if isinstance(r_key, IntegerRepr):
+            r_tuple, v_tuple = convert_int_to_tuple(r_key, v_key, hop.llops)
+        elif isinstance(r_key, AbstractSliceRepr):
+            r_tuple, v_tuple = convert_slice_to_tuple(r_key, v_key, hop.llops)
+        elif isinstance(r_key, TupleRepr):
+            r_tuple, v_tuple = r_key, v_key
+        else:
+            raise TyperError("bad key: %s"%r_key)
 
-class __extend__(pairtype(ArrayRepr, AbstractTupleRepr)):
-    def rtype_getitem((r_array, r_tpl), hop):
-        v_array, v_tuple = hop.inputargs(r_array, r_tpl)
-        ndim = get_view_ndim(r_array, r_tpl)
+        ndim = get_view_ndim(r_array, r_tuple)
         if ndim == 0:
             # return a scalar
             cARRAY = hop.inputconst(Void, r_array.ARRAY.TO)
@@ -463,12 +438,20 @@
         ARRAY = r_result.ARRAY
         assert dim_of_ARRAY(ARRAY) == ndim
         cARRAY = hop.inputconst(Void, ARRAY.TO)
-        ll_get_view = gen_get_view(r_array, r_tpl, hop)
+        ll_get_view = gen_get_view(r_array, r_tuple, hop)
         return hop.gendirectcall(ll_get_view, cARRAY, v_array, v_tuple)
 
-    def rtype_setitem((r_array, r_tuple), hop):
+    def rtype_setitem((r_array, r_key), hop):
         r_item = hop.args_r[2]
-        v_array, v_tuple, v_item = hop.inputargs(r_array, r_tuple, r_item)
+        v_array, v_key, v_item = hop.inputargs(r_array, r_key, r_item)
+        if isinstance(r_key, IntegerRepr):
+            r_tuple, v_tuple = convert_int_to_tuple(r_key, v_key, hop.llops)
+        elif isinstance(r_key, AbstractSliceRepr):
+            r_tuple, v_tuple = convert_slice_to_tuple(r_key, v_key, hop.llops)
+        elif isinstance(r_key, TupleRepr):
+            r_tuple, v_tuple = r_key, v_key
+        else:
+            raise TyperError("bad key: %s"%r_key)
         ndim = get_view_ndim(r_array, r_tuple)
         assert len(r_tuple.items_r) <= r_array.ndim
         if ndim == 0:
@@ -477,7 +460,7 @@
             cARRAY = hop.inputconst(Void, r_array.ARRAY.TO)
             get_item, set_item = gen_getset_item(r_array.ndim)
             return hop.gendirectcall(set_item, cARRAY, v_array, v_tuple, v_item)
-        elif isinstance(r_item, ArrayRepr):
+        else:
             s_view = SomeArray(r_array.s_array.typecode, ndim)
             r_view = hop.rtyper.getrepr(s_view)
             cARRAY = hop.inputconst(Void, r_view.ARRAY.TO)
@@ -485,17 +468,24 @@
             v_view = hop.gendirectcall(get_view, cARRAY, v_array, v_tuple)
             iter_new, iter_reset, iter_broadcast, iter_next = gen_iter_funcs(ndim)        
             creset = hop.inputconst(Void, iter_reset)
+            cbroadcast = hop.inputconst(Void, iter_broadcast)
             cnext = hop.inputconst(Void, iter_next)
             cITER = hop.inputconst(Void, r_view.ITER.TO)
-            v_it0 = hop.gendirectcall(iter_new, cITER, v_view, creset)
-            assert r_item.ndim <= ndim
-            if ndim == r_item.ndim:
-                v_it1 = hop.gendirectcall(iter_new, cITER, v_item, creset)
+            v_it0 = hop.gendirectcall(iter_new, cITER, v_view, v_view, creset, cbroadcast)
+            if isinstance(r_item, ArrayRepr):
+                source_ndim = r_item.ndim
+            elif isinstance(r_item.lowleveltype, Primitive):
+                # "broadcast" a scalar
+                v_item = convert_scalar_to_array(r_view.ITEM, v_item, hop.llops)
+                source_ndim = 1
+            elif isinstance(r_item, AbstractBaseListRepr):
+                v_item = convert_list_to_array(r_item, v_item, hop.llops)
+                source_ndim = 1
             else:
-                v_it1 = hop.gendirectcall(iter_broadcast, cITER, v_item, v_view, creset)
+                raise TypeError("bad item: %s"%r_item)
+            assert source_ndim <= ndim
+            v_it1 = hop.gendirectcall(iter_new, cITER, v_item, v_view, creset, cbroadcast)
             return hop.gendirectcall(ll_array_set, v_it0, v_it1, cnext) 
-        else:
-            assert 0
 
 
 class __extend__(pairtype(ArrayRepr, ArrayRepr)):
@@ -506,8 +496,8 @@
     def convert_from_to((r_lst, r_array), v, llops):
         if r_lst.listitem is None:
             return NotImplemented
-        if r_lst.item_repr != r_array.item_repr:
-            assert 0, (r_lst, r_array.item_repr)
+        if r_lst.item_repr != r_array.r_item:
+            assert 0, (r_lst, r_array.r_item)
             return NotImplemented
         cARRAY = inputconst(lltype.Void, r_array.lowleveltype.TO) 
         return llops.gendirectcall(ll_build_from_list, cARRAY, v)
@@ -545,6 +535,26 @@
     array.dataptr = direct_arrayitems(array.data)
     return array
 
+def ll_build_alias_to_list(ARRAY, lst):
+    # This should only be used for temporary calculations
+    size = lst.ll_length()
+    array = ll_allocate(ARRAY, 1)
+    array.shape[0] = size
+    array.strides[0] = 1
+    # Well.. this doesn't work (because array.data has nolength ?)
+    array.data = lst.ll_items()
+    array.dataptr = direct_arrayitems(array.data)
+    return array
+
+def ll_build_from_scalar(ARRAY, value):
+    array = ll_allocate(ARRAY, 1)
+    array.shape[0] = 1
+    array.strides[0] = 1
+    array.data = malloc(ARRAY.data.TO, 1)
+    array.dataptr = direct_arrayitems(array.data)
+    array.data[0] = value
+    return array
+
 def ll_build_alias(ARRAY, ao):
     array = ll_allocate(ARRAY, ao.ndim)
     array.data = ao.data # alias data
@@ -554,11 +564,11 @@
     array.dataptr = ao.dataptr
     return array
 
-def ll_setitem1(l, index, item):
-    l.data[index] = item
+def ll_setitem1(array, index, item):
+    array.data[index] = item
 
-def ll_getitem1(l, index):
-    return l.data[index]
+def ll_getitem1(array, index):
+    return array.data[index]
 
 def ll_add(ARRAY, a1, a2):
     size = a1.shape[0]

Modified: pypy/dist/pypy/rpython/numpy/test/test_array.py
==============================================================================
--- pypy/dist/pypy/rpython/numpy/test/test_array.py	(original)
+++ pypy/dist/pypy/rpython/numpy/test/test_array.py	Sat Sep  8 00:23:25 2007
@@ -354,6 +354,16 @@
         assert interpret(f, [0, 0]) == 0
         assert interpret(f, [3, 4]) == 12
 
+    def test_specialize_list_rhs(self):
+        def f():
+            a = numpy.zeros((3,4), dtype='i')
+            a[:] = [3,4,4,2]
+            return a
+        res = interpret(f, [])
+        data = [3,4,4,2]*3
+        for i in range(len(data)):
+            assert res.dataptr[i] == data[i]
+
     def test_specialize_slice_1_0(self):
         def f():
             a = numpy.zeros((12,), dtype='i')
@@ -369,7 +379,7 @@
             assert res.dataptr[i] == data[i]
 
     def test_specialize_slice_1_1(self):
-        py.test.skip('this involves a runtime test to see if we need a broadcast iterator')
+        # This involves a runtime test to see if we need a broadcast iterator
         def f():
             a = numpy.zeros((6,), dtype='i')
             a[:2] = numpy.array([1])
@@ -381,10 +391,9 @@
             assert res.dataptr[i] == data[i]
 
     def test_specialize_slice_2_0(self):
-        py.test.skip('not implemented')
         def f():
             a = numpy.zeros((12,), dtype='i').reshape((3,4))
-            a[:2, 0] = 1
+            a[:2, :1] = 1
             return a
         res = interpret(f, [])
         data = [1,0,0,0,1,0,0,0,0,0,0,0]
@@ -467,7 +476,6 @@
             assert res.dataptr[i] == data[i]
 
     def test_malloc_remove(self):
-        py.test.skip('this test requires _always_inline_ magic hook')
         def f():
             a = numpy.empty((3,), dtype='i')
             b = numpy.array([5,55,555], dtype='i')
@@ -480,8 +488,8 @@
         r.specialize()
         from pypy.translator.backendopt.all import backend_optimizations
         backend_optimizations(t)
-        from pypy.rpython.numpy.rarray import ll_array_unary_op
-        graph = graphof(t, ll_array_unary_op)
+        from pypy.rpython.numpy.rarray import ll_array_set
+        graph = graphof(t, ll_array_set)
         #graph.show()
         from pypy.translator.backendopt.test.test_malloc import TestLLTypeMallocRemoval
         TestLLTypeMallocRemoval.check_malloc_removed(graph)



More information about the Pypy-commit mailing list