[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