Author: Alex Gaynor <[email protected]>
Branch: numpy-dtype-alt
Changeset: r46341:23225085fd60
Date: 2011-08-06 17:29 -0700
http://bitbucket.org/pypy/pypy/changeset/23225085fd60/
Log: Started implementing dtypes, currently fails due to some mess with
casting to and from VOIDP.
diff --git a/pypy/module/micronumpy/__init__.py
b/pypy/module/micronumpy/__init__.py
--- a/pypy/module/micronumpy/__init__.py
+++ b/pypy/module/micronumpy/__init__.py
@@ -7,6 +7,8 @@
interpleveldefs = {
'array': 'interp_numarray.SingleDimArray',
+ 'dtype': 'interp_dtype.W_Dtype',
+
'zeros': 'interp_numarray.zeros',
'empty': 'interp_numarray.zeros',
'ones': 'interp_numarray.ones',
diff --git a/pypy/module/micronumpy/interp_dtype.py
b/pypy/module/micronumpy/interp_dtype.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/micronumpy/interp_dtype.py
@@ -0,0 +1,124 @@
+from pypy.interpreter.baseobjspace import Wrappable
+from pypy.interpreter.gateway import interp2app
+from pypy.interpreter.typedef import TypeDef, interp_attrproperty
+from pypy.rlib.unroll import unrolling_iterable
+from pypy.rpython.lltypesystem import lltype, rffi
+
+
+SIGNEDLTR = "i"
+
+class W_Dtype(Wrappable):
+ aliases = []
+ applevel_types = []
+
+ def __init__(self, space):
+ pass
+
+ def descr__new__(space, w_subtype, w_dtype):
+ if space.isinstance_w(w_dtype, space.w_str):
+ dtype = space.str_w(w_dtype)
+ for alias, dtype_class in dtypes_by_alias:
+ if alias == dtype:
+ return space.fromcache(dtype_class)
+ elif isinstance(space.interpclass_w(w_dtype), W_Dtype):
+ return w_dtype
+ elif space.isinstance_w(w_dtype, space.w_type):
+ for typename, dtype_class in dtypes_by_apptype:
+ if space.is_w(getattr(space, "w_%s" % typename), w_dtype):
+ return space.fromcache(dtype_class)
+ assert False
+
+ def descr_repr(self, space):
+ return space.wrap("dtype('%s')" % self.name)
+
+ def descr_str(self, space):
+ return space.wrap(self.name)
+
+class LowLevelDtype(object):
+ _mixin_ = True
+
+ def erase(self, storage):
+ return rffi.cast(rffi.VOIDP, storage)
+ def unerase(self, storage):
+ return rffi.cast(self.TP, storage)
+
+ def malloc(self, size):
+ # XXX find out why test_zjit explodes with tracking of allocations
+ return self.erase(lltype.malloc(self.TP, size,
+ zero=True, flavor="raw",
+ track_allocation=False, add_memory_pressure=True
+ ))
+
+ def getitem(self, storage, i):
+ return self.unerase(storage)[i]
+
+ def setitem(self, storage, i, item):
+ self.unerase(storage)[i] = item
+
+ def setitem_w(self, space, storage, i, w_item):
+ self.setitem(storage, i, self.unwrap(space, w_item))
+
+
+class W_Int8Dtype(W_Dtype, LowLevelDtype):
+ num = 1
+ kind = SIGNEDLTR
+ aliases = ["int8"]
+
+class W_Int32Dtype(W_Dtype, LowLevelDtype):
+ num = 5
+ kind = SIGNEDLTR
+ aliases = ["i"]
+
+class W_Int64Dtype(W_Dtype, LowLevelDtype):
+ num = 9
+ applevel_types = ["long"]
+
+class W_LongDtype(W_Dtype, LowLevelDtype):
+ num = 7
+ kind = SIGNEDLTR
+ aliases = ["l"]
+ applevel_types = ["int"]
+
+class W_BoolDtype(W_Dtype, LowLevelDtype):
+ num = 0
+ name = "bool"
+ aliases = ["?"]
+ applevel_types = ["bool"]
+ TP = lltype.Array(lltype.Bool, hints={'nolength': True})
+
+ def unwrap(self, space, w_item):
+ return space.is_true(w_item)
+
+class W_Float64Dtype(W_Dtype, LowLevelDtype):
+ num = 12
+ applevel_types = ["float"]
+ TP = lltype.Array(lltype.Float, hints={'nolength': True})
+
+ def unwrap(self, space, w_item):
+ return space.float_w(space.float(w_item))
+
+
+ALL_DTYPES = [
+ W_Int8Dtype, W_Int32Dtype, W_Int64Dtype, W_LongDtype, W_BoolDtype,
W_Float64Dtype
+]
+
+dtypes_by_alias = unrolling_iterable([
+ (alias, dtype)
+ for dtype in ALL_DTYPES
+ for alias in dtype.aliases
+])
+dtypes_by_apptype = unrolling_iterable([
+ (apptype, dtype)
+ for dtype in ALL_DTYPES
+ for apptype in dtype.applevel_types
+])
+
+W_Dtype.typedef = TypeDef("dtype",
+ __new__ = interp2app(W_Dtype.descr__new__.im_func),
+
+ __repr__ = interp2app(W_Dtype.descr_repr),
+ __str__ = interp2app(W_Dtype.descr_str),
+
+ num = interp_attrproperty("num", cls=W_Dtype),
+ kind = interp_attrproperty("kind", cls=W_Dtype),
+)
\ No newline at end of file
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
@@ -1,17 +1,17 @@
+import math
+
from pypy.interpreter.baseobjspace import Wrappable
from pypy.interpreter.error import OperationError, operationerrfmt
-from pypy.interpreter.gateway import interp2app, unwrap_spec
+from pypy.interpreter.gateway import interp2app, unwrap_spec, NoneNotWrapped
from pypy.interpreter.typedef import TypeDef, GetSetProperty
+from pypy.module.micronumpy import interp_ufuncs, interp_dtype
from pypy.module.micronumpy.interp_support import Signature
-from pypy.module.micronumpy import interp_ufuncs
from pypy.objspace.std.floatobject import float2string as float2string_orig
from pypy.rlib import jit
from pypy.rlib.rfloat import DTSF_STR_PRECISION
from pypy.rpython.lltypesystem import lltype
from pypy.tool.sourcetools import func_with_new_name
-import math
-TP = lltype.Array(lltype.Float, hints={'nolength': True})
numpy_driver = jit.JitDriver(greens = ['signature'],
reds = ['result_size', 'i', 'self', 'result'])
@@ -45,6 +45,20 @@
arr.force_if_needed()
del self.invalidates[:]
+ def descr__new__(space, w_subtype, w_size_or_iterable,
w_dtype=NoneNotWrapped):
+ if w_dtype is None:
+ w_dtype = space.w_float
+ dtype = space.interp_w(interp_dtype.W_Dtype,
+ space.call_function(space.gettypefor(interp_dtype.W_Dtype),
w_dtype)
+ )
+ l = space.listview(w_size_or_iterable)
+ arr = SingleDimArray(len(l), dtype=dtype)
+ i = 0
+ for w_elem in l:
+ dtype.setitem_w(space, arr.storage, i, w_elem)
+ i += 1
+ return arr
+
def _unaryop_impl(w_ufunc):
def impl(self, space):
return w_ufunc(space, self)
@@ -206,7 +220,7 @@
raise NotImplementedError
def descr_copy(self, space):
- return new_numarray(space, self)
+ return space.call_function(space.gettypefor(BaseArray), self)
def descr_get_shape(self, space):
return space.newtuple([self.descr_len(space)])
@@ -242,18 +256,18 @@
self.find_size())
if step == 0:
# Single index
- self.get_concrete().setitem(start, space.float_w(w_value))
+ self.get_concrete().setitem(space, start, w_value)
else:
concrete = self.get_concrete()
if isinstance(w_value, BaseArray):
- # for now we just copy if setting part of an array from
+ # for now we just copy if setting part of an array from
# part of itself. can be improved.
if (concrete.get_root_storage() ==
w_value.get_concrete().get_root_storage()):
- w_value = new_numarray(space, w_value)
+ w_value = space.call_function(space.gettypefor(BaseArray),
w_value)
else:
w_value = convert_to_array(space, w_value)
- concrete.setslice(space, start, stop, step,
+ concrete.setslice(space, start, stop, step,
slice_length, w_value)
def descr_mean(self, space):
@@ -266,7 +280,7 @@
slice_driver1.jit_merge_point(signature=source.signature,
step=step, stop=stop, i=i, j=j, source=source,
dest=dest)
- dest.storage[i] = source.eval(j)
+ dest.dtype.setitem(dest.storage, i, source.eval(j))
j += 1
i += step
@@ -277,7 +291,7 @@
slice_driver2.jit_merge_point(signature=source.signature,
step=step, stop=stop, i=i, j=j, source=source,
dest=dest)
- dest.storage[i] = source.eval(j)
+ dest.dtype.setitem(dest.storage, i, source.eval(j))
j += 1
i += step
@@ -286,7 +300,7 @@
return w_obj
elif space.issequence_w(w_obj):
# Convert to array.
- return new_numarray(space, w_obj)
+ return space.call_function(space.gettypefor(BaseArray), w_obj)
else:
# If it's a scalar
return FloatWrapper(space.float_w(w_obj))
@@ -305,6 +319,9 @@
def find_size(self):
raise ValueError
+ def find_dtype(self):
+ raise ValueError
+
def eval(self, i):
return self.float_value
@@ -325,12 +342,12 @@
i = 0
signature = self.signature
result_size = self.find_size()
- result = SingleDimArray(result_size)
+ result = SingleDimArray(result_size, self.find_dtype())
while i < result_size:
numpy_driver.jit_merge_point(signature=signature,
result_size=result_size, i=i,
self=self, result=result)
- result.storage[i] = self.eval(i)
+ result.dtype.setitem(result.storage, i, self.eval(i))
i += 1
return result
@@ -354,6 +371,11 @@
return self.forced_result.find_size()
return self._find_size()
+ def find_dtype(self):
+ if self.forced_result is not None:
+ return self.forced_result.find_dtype()
+ return self._find_dtype()
+
class Call1(VirtualArray):
_immutable_fields_ = ["function", "values"]
@@ -369,6 +391,9 @@
def _find_size(self):
return self.values.find_size()
+ def _find_dtype(self):
+ return self.values.find_dtype()
+
def _eval(self, i):
return self.function(self.values.eval(i))
@@ -399,6 +424,27 @@
lhs, rhs = self.left.eval(i), self.right.eval(i)
return self.function(lhs, rhs)
+ def _find_dtype(self):
+ lhs_dtype = None
+ rhs_dtype = None
+ try:
+ lhs_dtype = self.left.find_dtype()
+ except ValueError:
+ pass
+ try:
+ rhs_dtype = self.right.find_dtype()
+ except ValueError:
+ pass
+ if lhs_dtype is not None and rhs_dtype is not None:
+ assert lhs_dtype is rhs_dtype
+ return lhs_dtype
+ elif lhs_dtype is not None:
+ return lhs_dtype
+ elif rhs_dtype is not None:
+ return rhs_dtype
+ else:
+ raise ValueError
+
class ViewArray(BaseArray):
"""
Class for representing views of arrays, they will reflect changes of parent
@@ -422,9 +468,9 @@
def eval(self, i):
return self.parent.eval(self.calc_index(i))
- @unwrap_spec(item=int, value=float)
- def setitem(self, item, value):
- return self.parent.setitem(self.calc_index(item), value)
+ @unwrap_spec(item=int)
+ def setitem(self, space, item, w_value):
+ return self.parent.setitem(space, self.calc_index(item), w_value)
def descr_len(self, space):
return space.wrap(self.find_size())
@@ -456,6 +502,9 @@
def find_size(self):
return self.size
+ def find_dtype(self):
+ return self.parent.find_dtype()
+
def setslice(self, space, start, stop, step, slice_length, arr):
start = self.calc_index(start)
if stop != -1:
@@ -473,13 +522,11 @@
class SingleDimArray(BaseArray):
signature = Signature()
- def __init__(self, size):
+ def __init__(self, size, dtype):
BaseArray.__init__(self)
self.size = size
- self.storage = lltype.malloc(TP, size, zero=True,
- flavor='raw', track_allocation=False,
- add_memory_pressure=True)
- # XXX find out why test_zjit explodes with trackign of allocations
+ self.dtype = dtype
+ self.storage = dtype.malloc(size)
def get_concrete(self):
return self
@@ -490,15 +537,18 @@
def find_size(self):
return self.size
+ def find_dtype(self):
+ return self.dtype
+
def eval(self, i):
- return self.storage[i]
+ return self.dtype.getitem(self.storage, i)
def descr_len(self, space):
return space.wrap(self.size)
- def setitem(self, item, value):
+ def setitem(self, space, item, w_value):
self.invalidated()
- self.storage[item] = value
+ self.dtype.setitem_w(space, self.storage, item, w_value)
def setslice(self, space, start, stop, step, slice_length, arr):
if step > 0:
@@ -509,32 +559,20 @@
def __del__(self):
lltype.free(self.storage, flavor='raw', track_allocation=False)
-def new_numarray(space, w_size_or_iterable):
- l = space.listview(w_size_or_iterable)
- arr = SingleDimArray(len(l))
- i = 0
- for w_elem in l:
- arr.storage[i] = space.float_w(space.float(w_elem))
- i += 1
- return arr
-
-def descr_new_numarray(space, w_type, w_size_or_iterable):
- return space.wrap(new_numarray(space, w_size_or_iterable))
-
@unwrap_spec(size=int)
def zeros(space, size):
- return space.wrap(SingleDimArray(size))
+ return space.wrap(SingleDimArray(size,
dtype=space.fromcache(interp_dtype.W_Float64Dtype)))
@unwrap_spec(size=int)
def ones(space, size):
- arr = SingleDimArray(size)
+ arr = SingleDimArray(size,
dtype=space.fromcache(interp_dtype.W_Float64Dtype))
for i in xrange(size):
- arr.storage[i] = 1.0
+ arr.dtype.setitem(arr.storage, i, 1.0)
return space.wrap(arr)
BaseArray.typedef = TypeDef(
'numarray',
- __new__ = interp2app(descr_new_numarray),
+ __new__ = interp2app(BaseArray.descr__new__.im_func),
copy = interp2app(BaseArray.descr_copy),
shape = GetSetProperty(BaseArray.descr_get_shape),
diff --git a/pypy/module/micronumpy/interp_support.py
b/pypy/module/micronumpy/interp_support.py
--- a/pypy/module/micronumpy/interp_support.py
+++ b/pypy/module/micronumpy/interp_support.py
@@ -1,7 +1,8 @@
+from pypy.interpreter.error import OperationError
+from pypy.interpreter.gateway import unwrap_spec
+from pypy.module.micronumpy.interp_dtype import W_Float64Dtype
from pypy.rlib.rstruct.runpack import runpack
from pypy.rpython.lltypesystem import lltype, rffi
-from pypy.interpreter.error import OperationError
-from pypy.interpreter.gateway import unwrap_spec
FLOAT_SIZE = rffi.sizeof(lltype.Float)
@@ -17,14 +18,14 @@
raise OperationError(space.w_ValueError, space.wrap(
"string length %d not divisable by %d" % (length, FLOAT_SIZE)))
- a = SingleDimArray(number)
+ a = SingleDimArray(number, dtype=space.fromcache(W_Float64Dtype))
start = 0
end = FLOAT_SIZE
i = 0
while i < number:
part = s[start:end]
- a.storage[i] = runpack('d', part)
+ a.dtype.setitem(a.storage, i, runpack('d', part))
i += 1
start += FLOAT_SIZE
end += FLOAT_SIZE
diff --git a/pypy/module/micronumpy/test/test_base.py
b/pypy/module/micronumpy/test/test_base.py
--- a/pypy/module/micronumpy/test/test_base.py
+++ b/pypy/module/micronumpy/test/test_base.py
@@ -1,13 +1,15 @@
from pypy.conftest import gettestobjspace
+from pypy.module.micronumpy.interp_dtype import W_Float64Dtype
from pypy.module.micronumpy.interp_numarray import SingleDimArray, FloatWrapper
+
class BaseNumpyAppTest(object):
def setup_class(cls):
cls.space = gettestobjspace(usemodules=('micronumpy',))
class TestSignature(object):
def test_binop_signature(self, space):
- ar = SingleDimArray(10)
+ ar = SingleDimArray(10, dtype=space.fromcache(W_Float64Dtype))
v1 = ar.descr_add(space, ar)
v2 = ar.descr_add(space, FloatWrapper(2.0))
assert v1.signature is not v2.signature
@@ -17,7 +19,7 @@
assert v1.signature is v4.signature
def test_slice_signature(self, space):
- ar = SingleDimArray(10)
+ ar = SingleDimArray(10, dtype=space.fromcache(W_Float64Dtype))
v1 = ar.descr_getitem(space, space.wrap(slice(1, 5, 1)))
v2 = ar.descr_getitem(space, space.wrap(slice(4, 6, 1)))
assert v1.signature is v2.signature
diff --git a/pypy/module/micronumpy/test/test_dtypes.py
b/pypy/module/micronumpy/test/test_dtypes.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/micronumpy/test/test_dtypes.py
@@ -0,0 +1,37 @@
+import py
+
+from pypy.module.micronumpy.test.test_base import BaseNumpyAppTest
+
+
+class AppTestDtypes(BaseNumpyAppTest):
+ def test_dtype(self):
+ from numpy import dtype
+
+ d = dtype('l')
+ assert d.num == 7
+ assert d.kind == 'i'
+ assert dtype('int8').num == 1
+ assert dtype(d) is d
+
+ def test_dtype_with_types(self):
+ from numpy import dtype
+
+ assert dtype(bool).num == 0
+ assert dtype(int).num == 7
+ assert dtype(long).num == 9
+ assert dtype(float).num == 12
+
+ def test_repr_str(self):
+ from numpy import dtype
+
+ d = dtype('?')
+ assert repr(d) == "dtype('bool')"
+ assert str(d) == "bool"
+
+ def test_bool_array(self):
+ from numpy import array
+
+ a = array([0, 1, 2, 2.5], dtype='?')
+ assert a[0] is False
+ for i in xrange(1, 4):
+ assert a[i] is True
diff --git a/pypy/module/micronumpy/test/test_zjit.py
b/pypy/module/micronumpy/test/test_zjit.py
--- a/pypy/module/micronumpy/test/test_zjit.py
+++ b/pypy/module/micronumpy/test/test_zjit.py
@@ -1,11 +1,13 @@
from pypy.jit.metainterp.test.support import LLJitMixin
-from pypy.rpython.test.test_llinterp import interpret
+from pypy.module.micronumpy.compile import numpy_compile
+from pypy.module.micronumpy.interp_dtype import W_Float64Dtype
from pypy.module.micronumpy.interp_numarray import (SingleDimArray, Signature,
FloatWrapper, Call2, SingleDimSlice, add, mul, Call1)
from pypy.module.micronumpy.interp_ufuncs import negative
-from pypy.module.micronumpy.compile import numpy_compile
+from pypy.rlib.nonconst import NonConstant
from pypy.rlib.objectmodel import specialize
-from pypy.rlib.nonconst import NonConstant
+from pypy.rpython.test.test_llinterp import interpret
+
class FakeSpace(object):
w_ValueError = None
@@ -23,12 +25,14 @@
class TestNumpyJIt(LLJitMixin):
def setup_class(cls):
cls.space = FakeSpace()
+ cls.float64_dtype = W_Float64Dtype(cls.space)
def test_add(self):
def f(i):
- ar = SingleDimArray(i)
+ ar = SingleDimArray(i, dtype=self.float64_dtype)
v = Call2(add, ar, ar, Signature())
- return v.get_concrete().storage[3]
+ concrete = v.get_concrete()
+ return concrete.dtype.getitem(concrete.storage, 3)
result = self.meta_interp(f, [5], listops=True, backendopt=True)
self.check_loops({'getarrayitem_raw': 2, 'float_add': 1,
@@ -40,7 +44,7 @@
def f(i):
ar = SingleDimArray(i)
v = Call2(add, ar, FloatWrapper(4.5), Signature())
- return v.get_concrete().storage[3]
+ return v.dtype.getitem(v.get_concrete().storage, 3)
result = self.meta_interp(f, [5], listops=True, backendopt=True)
self.check_loops({"getarrayitem_raw": 1, "float_add": 1,
@@ -88,7 +92,7 @@
result = self.meta_interp(f, [5], listops=True, backendopt=True)
self.check_loops({"getarrayitem_raw": 2, "float_add": 1,
"float_gt": 1, "int_add": 1,
- "int_lt": 1, "guard_true": 1,
+ "int_lt": 1, "guard_true": 1,
"guard_false": 1, "jump": 1})
assert result == f(5)
@@ -269,10 +273,10 @@
assert x.size == 10
assert x.storage[0] == 0
assert x.storage[1] == ((1 + 1) * 1.2) / 1.2 - 1
-
+
def test_translation(self):
# we import main to check if the target compiles
from pypy.translator.goal.targetnumpystandalone import main
from pypy.rpython.annlowlevel import llstr
-
+
interpret(main, [llstr('af+'), 100])
diff --git a/pypy/rlib/rerased.py b/pypy/rlib/rerased.py
--- a/pypy/rlib/rerased.py
+++ b/pypy/rlib/rerased.py
@@ -117,6 +117,10 @@
return erase, unerase
+def new_static_erasing_pair(name):
+ erase, unerase = new_erasing_pair(name)
+ return staticmethod(erase), staticmethod(unerase)
+
# ---------- implementation-specific ----------
_______________________________________________
pypy-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit