[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