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

simonb at codespeak.net simonb at codespeak.net
Thu Sep 13 18:21:32 CEST 2007


Author: simonb
Date: Thu Sep 13 18:21:29 2007
New Revision: 46540

Modified:
   pypy/dist/pypy/rpython/numpy/aarray.py
   pypy/dist/pypy/rpython/numpy/rarray.py
   pypy/dist/pypy/rpython/numpy/test/test_array.py
Log:
get inplace operators working, also plays nice with coercion rules

Modified: pypy/dist/pypy/rpython/numpy/aarray.py
==============================================================================
--- pypy/dist/pypy/rpython/numpy/aarray.py	(original)
+++ pypy/dist/pypy/rpython/numpy/aarray.py	Thu Sep 13 18:21:29 2007
@@ -88,48 +88,63 @@
             return SomeArray(typecode, self.ndim)
         raise AnnotatorError()
 
-class __extend__(pairtype(SomeArray, SomeArray)):
+def unify_scalar_tp(item1, item2):
+    typecode = None
+    if float in (item1.knowntype, item2.knowntype):
+        typecode = 'd'
+    else:
+        item_knowntype = rarithmetic.compute_restype(item1.knowntype, item2.knowntype)
+        for typecode, s_item in SomeArray.typecode_to_item.items():
+            if s_item.knowntype == item_knowntype:
+                break
+    if typecode is None:
+        raise AnnotatorError()
+    return typecode
 
-    def add((s_arr1, s_arr2)):
-        item1 = s_arr1.get_item_type()
-        item2 = s_arr2.get_item_type()
-        typecode = None
-        if float in (item1.knowntype, item2.knowntype):
-            typecode = 'd'
+class __extend__(pairtype(SomeArray, SomeObject)):
+    def add((s_arr, s_other)):
+        item1 = s_arr.get_item_type()
+        ndim = s_arr.ndim
+        if isinstance(s_other, SomeArray):
+            item2 = s_other.get_item_type()
+            ndim = max(ndim, s_other.ndim)
+        elif isinstance(s_other, SomeList):
+            item2 = s_other.listdef.listitem.s_value
+        elif isinstance(s_other, SomeFloat):
+            item2 = s_other
         else:
-            item_knowntype = rarithmetic.compute_restype(item1.knowntype, item2.knowntype)
-            for typecode, s_item in SomeArray.typecode_to_item.items():
-                if s_item.knowntype == item_knowntype:
-                    break
-        if typecode is None:
-            raise AnnotatorError()
-        ndim = max(s_arr1.ndim, s_arr2.ndim)
-        return SomeArray(typecode, s_arr1.ndim)
-
-    # union ?
+            raise AnnotatorError("cannot operate with %s"%s_other)
+        typecode = unify_scalar_tp(item1, item2)
+        return SomeArray(typecode, ndim)
     sub = mul = div = add
 
-class __extend__(pairtype(SomeArray, SomeFloat)):
-    def add((s_arr, s_flt)):
-        item = s_arr.get_item_type()
-        typecode = None
-        if float in (item.knowntype, s_flt.knowntype):
-            typecode = 'd'
-        else:
-            item_knowntype = rarithmetic.compute_restype(item.knowntype, s_flt.knowntype)
-            for typecode, s_item in SomeArray.typecode_to_item.items():
-                if s_item.knowntype == item_knowntype:
-                    break
-        if typecode is None:
-            raise AnnotatorError()
-        return SomeArray(typecode, s_arr.ndim)
-    # union ?
-    sub = mul = div = add
+    def inplace_add((s_arr, s_other)):
+        if isinstance(s_other, SomeArray):
+            # This can only work if s_other is broadcastable to s_arr
+            if s_other.ndim > s_arr.ndim:
+                raise AnnotatorError("invalid return array shape")
+        elif isinstance(s_other, SomeList):
+            item2 = s_other.listdef.listitem.s_value
+            if not isinstance(item2, SomeFloat):
+                raise AnnotatorError("cannot operate with list of %s"%item2)
+        elif not isinstance(s_other, SomeFloat):
+            raise AnnotatorError("cannot operate with %s"%s_other)
+        return s_arr
+    inplace_sub = inplace_mul = inplace_div = inplace_add
 
 class __extend__(pairtype(SomeFloat, SomeArray)):
     def add((s_flt, s_arr)):
         return pair(s_arr, s_flt).add()
-    # union ?
+    sub = mul = div = add
+
+    def inplace_add((s_flt, s_arr)):
+        # This involves promoting the type of the lhs
+        raise AnnotatorError()
+    inplace_sub = inplace_mul = inplace_div = inplace_add
+
+class __extend__(pairtype(SomeList, SomeArray)):
+    def add((s_lst, s_arr)):
+        return pair(s_arr, s_lst).add()
     sub = mul = div = add
 
 class __extend__(pairtype(SomeArray, SomeTuple)):
@@ -183,6 +198,12 @@
         s_tuple = SomeTuple([s_index])
         return pair(s_array, s_tuple).getitem()
 
+def build_annotation_from_scalar(s_value):
+    key = type(s_value), s_value.knowntype
+    typecode = numpy_typedict[key]
+    ndim = 1
+    return SomeArray(typecode, ndim)
+
 class ArrayCallEntry(ExtRegistryEntry):
     _about_ = numpy.array
 

Modified: pypy/dist/pypy/rpython/numpy/rarray.py
==============================================================================
--- pypy/dist/pypy/rpython/numpy/rarray.py	(original)
+++ pypy/dist/pypy/rpython/numpy/rarray.py	Thu Sep 13 18:21:29 2007
@@ -311,7 +311,6 @@
         hop.gendirectcall(ll_array_set, cITEM, v_it0, v_it1)
         return v_result
 
-
     def get_ndim(self, hop, v_array):
         cname = inputconst(Void, 'ndim')
         return hop.llops.genop('getfield', [v_array, cname], resulttype=Signed)
@@ -343,10 +342,14 @@
         key = self.__class__, self.typecode, self.ndim
         return key
 
+#______________________________________________________________________________
+
 def ll_array_binop(it0, it1, it2, binop):
     debug_assert(it0.size == it1.size, "it0.size == it1.size")
     debug_assert(it1.size == it2.size, "it0.size == it1.size")
     while it0.index < it0.size:
+        # We don't need a cast here, because it0.dataptr[0] is always
+        # big enough to contain the result.
         it0.dataptr[0] = binop(it1.dataptr[0], it2.dataptr[0])
         it0.ll_next()
         it1.ll_next()
@@ -358,7 +361,6 @@
     # from the largest of the two args:
     v_array0 = hop.gendirectcall(ll_build_like2, cARRAY, v_array1, v_array2)
     iter_new, iter_broadcast = gen_iter_funcs(r_array0.ndim)
-    iter_new._annenforceargs_ = [None, None, None, None]
     cITER0 = hop.inputconst(Void, r_array0.ITER.TO)
     cITER1 = hop.inputconst(Void, r_array0.build_ITER_for(r_array1))
     cITER2 = hop.inputconst(Void, r_array0.build_ITER_for(r_array2))
@@ -375,15 +377,18 @@
     v_array1, v_array2 = hop.inputargs(r_array1, r_array2)
 
     if isinstance(r_array1.lowleveltype, Primitive):
-        r_array1, v_array1 = convert_scalar_to_array(r_array0, v_array1, hop.llops)
+        r_array1, v_array1 = convert_scalar_to_array(r_array1, v_array1, hop.llops)
+    elif isinstance(r_array1, AbstractBaseListRepr):
+        r_array1, v_array1 = convert_list_to_array(r_array1, v_array1, hop.llops)
     elif not isinstance(r_array1, ArrayRepr):
         raise TyperError("can't operate with %s"%r_array1)
 
     if isinstance(r_array2.lowleveltype, Primitive):
-        r_array2, v_array2 = convert_scalar_to_array(r_array0, v_array2, hop.llops)
+        r_array2, v_array2 = convert_scalar_to_array(r_array2, v_array2, hop.llops)
+    elif isinstance(r_array2, AbstractBaseListRepr):
+        r_array2, v_array2 = convert_list_to_array(r_array2, v_array2, hop.llops)
     elif not isinstance(r_array2, ArrayRepr):
         raise TyperError("can't operate with %s"%r_array2)
-    print "rtype_binop", binop, binop(2,3)
     return _rtype_binop(r_array0, r_array1, r_array2, v_array1, v_array2, hop, binop)
 
 for tp in (pairtype(ArrayRepr, ArrayRepr),
@@ -395,6 +400,55 @@
                               (lambda a,b:a/b, "rtype_div")):
         setattr(tp, methname, lambda self, hop, binop=binop : rtype_binop(self, hop, binop))
 
+#______________________________________________________________________________
+
+def ll_array_inplace_binop(ITEM, it0, it1, binop):
+    debug_assert(it0.size == it1.size, "it0.size == it1.size")
+    while it0.index < it0.size:
+        it0.dataptr[0] = cast_primitive(ITEM, binop(it0.dataptr[0], it1.dataptr[0]))
+        it0.ll_next()
+        it1.ll_next()
+
+def _rtype_inplace_binop(r_array0, r_array1, r_array2, v_array1, v_array2, hop, binop):
+    iter_new, iter_broadcast = gen_iter_funcs(r_array1.ndim)
+    cITEM = hop.inputconst(Void, r_array1.ITEM)
+    cITER1 = hop.inputconst(Void, r_array1.ITER.TO)
+    cITER2 = hop.inputconst(Void, r_array1.build_ITER_for(r_array2))
+    cbroadcast = hop.inputconst(Void, iter_broadcast)
+    v_it1 = hop.gendirectcall(iter_new, cITER1, v_array1, v_array1, cbroadcast)
+    v_it2 = hop.gendirectcall(iter_new, cITER2, v_array2, v_array1, cbroadcast)
+    cbinop = hop.inputconst(Void, binop)
+    hop.gendirectcall(ll_array_inplace_binop, cITEM, v_it1, v_it2, cbinop)
+    return v_array1
+
+def rtype_inplace_binop((r_array1, r_array2), hop, binop):
+    r_array0 = hop.r_result
+    v_array1, v_array2 = hop.inputargs(r_array1, r_array2)
+
+    if isinstance(r_array1.lowleveltype, Primitive):
+        raise TyperError("can't operate with %s"%r_array1)
+    elif not isinstance(r_array1, ArrayRepr):
+        raise TyperError("can't operate with %s"%r_array1)
+
+    if isinstance(r_array2.lowleveltype, Primitive):
+        r_array2, v_array2 = convert_scalar_to_array(r_array2, v_array2, hop.llops)
+    elif isinstance(r_array2, AbstractBaseListRepr):
+        r_array2, v_array2 = convert_list_to_array(r_array2, v_array2, hop.llops)
+    elif not isinstance(r_array2, ArrayRepr):
+        raise TyperError("can't operate with %s"%r_array2)
+    return _rtype_inplace_binop(r_array0, r_array1, r_array2, v_array1, v_array2, hop, binop)
+
+for tp in (pairtype(ArrayRepr, ArrayRepr),
+           pairtype(ArrayRepr, Repr),
+           pairtype(Repr, ArrayRepr)):
+    for (binop, methname) in ((lambda a,b:a+b, "rtype_inplace_add"),
+                              (lambda a,b:a-b, "rtype_inplace_sub"),
+                              (lambda a,b:a*b, "rtype_inplace_mul"),
+                              (lambda a,b:a/b, "rtype_inplace_div")):
+        setattr(tp, methname, lambda self, hop, binop=binop : rtype_inplace_binop(self, hop, binop))
+
+#______________________________________________________________________________
+
 def gen_getset_item(ndim):
     unrolling_dims = unrolling_iterable(range(ndim))
     def ll_get_item(ARRAY, ao, tpl):
@@ -498,9 +552,10 @@
     #v_array = llops.gendirectcall(ll_build_alias_to_list, cARRAY, v_list) # nice idea...
     return r_array, v_array
 
-def convert_scalar_to_array(r_array, v_item, llops):
+def convert_scalar_to_array(r_item, v_item, llops):
     # x -> array([x])
-    s_array = r_array.s_array.get_one_dim()
+    s_item = lltype_to_annotation(r_item.lowleveltype)
+    s_array = aarray.build_annotation_from_scalar(s_item)
     r_array = llops.rtyper.getrepr(s_array)
     from pypy.rpython.rmodel import inputconst
     cARRAY = inputconst(Void, r_array.ARRAY.TO)
@@ -568,7 +623,7 @@
                 source_ndim = r_item.ndim
             elif isinstance(r_item.lowleveltype, Primitive):
                 # "broadcast" a scalar
-                r_item, v_item = convert_scalar_to_array(r_view, v_item, hop.llops)
+                r_item, v_item = convert_scalar_to_array(r_item, v_item, hop.llops)
                 source_ndim = 1
             elif isinstance(r_item, AbstractBaseListRepr):
                 r_item, v_item = convert_list_to_array(r_item, v_item, hop.llops)

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	Thu Sep 13 18:21:29 2007
@@ -116,6 +116,17 @@
         s = a.build_types(f, [])
         assert s.typecode == 'i'
 
+    def test_annotate_array_add_list(self):
+        def f():
+            a1 = numpy.array([1,2])
+            a2 = [3., 4.]
+            return a1 + a2
+
+        t = TranslationContext()
+        a = t.buildannotator()
+        s = a.build_types(f, [])
+        assert s.typecode == 'd'
+
     def test_annotate_array_add_coerce(self):
         def f():
             a1 = numpy.array([1,2])
@@ -127,7 +138,7 @@
         s = a.build_types(f, [])
         assert s.typecode == 'd'
 
-    def test_annotate_array_add_2(self):
+    def test_annotate_array_add_scalar(self):
         def f():
             a = numpy.array([1,2])
             a = a + 3
@@ -138,6 +149,38 @@
         s = a.build_types(f, [])
         assert s.typecode == 'i'
 
+    def test_annotate_array_add_scalar_coerce(self):
+        def f():
+            a = numpy.array([1,2])
+            return a + 3.
+
+        t = TranslationContext()
+        a = t.buildannotator()
+        s = a.build_types(f, [])
+        assert s.typecode == 'd'
+
+    def test_annotate_array_inplace_add_list(self):
+        def f():
+            a = numpy.array([1,2,3,4])
+            a += [4,3,2,1]
+            return a
+
+        t = TranslationContext()
+        a = t.buildannotator()
+        s = a.build_types(f, [])
+        assert s.typecode == 'l'
+
+    def test_annotate_array_inplace_mul_coerce(self):
+        def f():
+            a = numpy.array([1,2,3,4])
+            a *= 0.5
+            return a
+
+        t = TranslationContext()
+        a = t.buildannotator()
+        s = a.build_types(f, [])
+        assert s.typecode == 'l'
+
     def test_annotate_array_dtype(self):
         def f():
             a1 = numpy.array([1,2], dtype='d')
@@ -599,12 +642,31 @@
     def test_specialize_array_add_1_1_coerce(self):
         def f():
             a1 = numpy.array([1,2])
-            a2 = numpy.array([6.,9.])
+            a2 = numpy.array([6.5,9.5])
             return a1 + a2
 
         res = interpret(f, [])
-        assert res.data[0] == 7.
-        assert res.data[1] == 11.
+        assert res.data[0] == 7.5
+        assert res.data[1] == 11.5
+
+    def test_specialize_array_add_1_1_coerce_from_list(self):
+        def f():
+            a1 = numpy.array([1,2])
+            a2 = [6.5,9.5]
+            return a1 + a2
+
+        res = interpret(f, [])
+        assert res.data[0] == 7.5
+        assert res.data[1] == 11.5
+
+    def test_specialize_array_add_1_1_coerce_from_scalar(self):
+        def f():
+            a = numpy.array([1,2])
+            return a + 1.5
+
+        res = interpret(f, [])
+        assert res.data[0] == 2.5
+        assert res.data[1] == 3.5
 
     def test_specialize_array_add_2_1(self):
         def f():
@@ -631,6 +693,82 @@
         for i in range(len(data)):
             assert res.dataptr[i] == 5*data[i]
 
+    def test_specialize_array_add_list(self):
+        def f():
+            a = numpy.array([1,2,3,4])
+            a = a + [4,3,2,1]
+            return a
+
+        res = interpret(f, [])
+        for i in range(4):
+            assert res.dataptr[i] == 5
+
+    def test_specialize_array_radd_list(self):
+        def f():
+            a = numpy.array([1,2,3,4])
+            a = [4,3,2,1] + a
+            return a
+
+        res = interpret(f, [])
+        for i in range(4):
+            assert res.dataptr[i] == 5
+
+    def test_specialize_array_inplace_add(self):
+        def f():
+            a = numpy.array([1,2,3,4])
+            a += 1
+            return a
+
+        res = interpret(f, [])
+        data = [1,2,3,4]
+        for i in range(len(data)):
+            assert res.dataptr[i] == data[i] + 1
+
+    def test_specialize_array_inplace_add_list_broadcast(self):
+        def f():
+            a = numpy.array([1,2,3,4]).reshape((2,2))
+            a += [0,1]
+            return a
+
+        res = interpret(f, [])
+        data = [1,3,3,5]
+        for i in range(len(data)):
+            assert res.dataptr[i] == data[i]
+
+    def test_specialize_array_inplace_mul_coerce(self):
+        def f():
+            a = numpy.array([1,2,3,4])
+            a *= numpy.array([0.5])
+            return a
+
+        res = interpret(f, [])
+        data = [1,2,3,4]
+        for i in range(len(data)):
+            assert res.dataptr[i] == data[i]//2
+
+    def test_specialize_array_inplace_mul_coerce_from_list(self):
+        def f():
+            a = numpy.array([1,2])
+            a *= [1.5, 2.5]
+            return a
+
+        res = interpret(f, [])
+        data = [1.0, 5.0]
+        for i in range(len(data)):
+            assert res.dataptr[i] == data[i]
+
+    def test_specialize_array_inplace_mul_coerce_from_scalar(self):
+        def f():
+            a = numpy.array([1,2,3,4])
+            a *= 0.5
+            return a
+
+        res = interpret(f, [])
+        data = [1,2,3,4]
+        for i in range(len(data)):
+            assert res.dataptr[i] == data[i]//2
+
+
 class Test_compile:
     def setup_class(self):
         if not test_c_compile:



More information about the Pypy-commit mailing list