Author: Maciej Fijalkowski <[email protected]>
Branch: numpy-refactor
Changeset: r56949:c792ce5f9d5c
Date: 2012-08-30 17:16 +0200
http://bitbucket.org/pypy/pypy/changeset/c792ce5f9d5c/
Log: reduce support
diff --git a/pypy/module/micronumpy/arrayimpl/concrete.py
b/pypy/module/micronumpy/arrayimpl/concrete.py
--- a/pypy/module/micronumpy/arrayimpl/concrete.py
+++ b/pypy/module/micronumpy/arrayimpl/concrete.py
@@ -77,6 +77,9 @@
impl = ConcreteArray(self.shape, self.dtype, self.order)
return loop.setslice(impl, self)
+ def get_size(self):
+ return self.size // self.dtype.itemtype.get_element_size()
+
# -------------------- applevel get/setitem -----------------------
@jit.unroll_safe
diff --git a/pypy/module/micronumpy/arrayimpl/scalar.py
b/pypy/module/micronumpy/arrayimpl/scalar.py
--- a/pypy/module/micronumpy/arrayimpl/scalar.py
+++ b/pypy/module/micronumpy/arrayimpl/scalar.py
@@ -41,4 +41,7 @@
scalar = Scalar(self.dtype)
scalar.value = self.value
return scalar
+
+ def get_size(self):
+ return 1
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
@@ -6,6 +6,7 @@
from pypy.module.micronumpy import interp_dtype, interp_ufuncs, support
from pypy.module.micronumpy.arrayimpl import create_implementation,
create_slice
from pypy.module.micronumpy.strides import find_shape_and_elems
+from pypy.module.micronumpy.interp_support import unwrap_axis_arg
from pypy.tool.sourcetools import func_with_new_name
from pypy.rlib import jit
from pypy.rlib.objectmodel import instantiate
@@ -87,7 +88,10 @@
self.implementation.fill(box)
def descr_get_size(self, space):
- return space.wrap(support.product(self.implementation.get_shape()))
+ return space.wrap(self.get_size())
+
+ def get_size(self):
+ return self.implementation.get_size()
def get_scalar_value(self):
return self.implementation.get_scalar_value()
@@ -126,6 +130,39 @@
descr_radd = _binop_right_impl("add")
+ # ----------------------- reduce -------------------------------
+
+ def _reduce_ufunc_impl(ufunc_name, promote_to_largest=False):
+ def impl(self, space, w_axis=None, w_out=None):
+ if space.is_w(w_out, space.w_None) or not w_out:
+ out = None
+ elif not isinstance(w_out, W_NDimArray):
+ raise OperationError(space.w_TypeError, space.wrap(
+ 'output must be an array'))
+ else:
+ out = w_out
+ return getattr(interp_ufuncs.get(space), ufunc_name).reduce(space,
+ self, True, promote_to_largest, w_axis,
+ False, out)
+ return func_with_new_name(impl, "reduce_%s_impl" % ufunc_name)
+
+ descr_sum = _reduce_ufunc_impl("add")
+ descr_sum_promote = _reduce_ufunc_impl("add", True)
+ descr_prod = _reduce_ufunc_impl("multiply", True)
+ descr_max = _reduce_ufunc_impl("maximum")
+ descr_min = _reduce_ufunc_impl("minimum")
+ descr_all = _reduce_ufunc_impl('logical_and')
+ descr_any = _reduce_ufunc_impl('logical_or')
+
+ def descr_mean(self, space, w_axis=None, w_out=None):
+ if space.is_w(w_axis, space.w_None):
+ w_denom = space.wrap(support.product(self.shape))
+ else:
+ axis = unwrap_axis_arg(space, len(self.shape), w_axis)
+ w_denom = space.wrap(self.shape[axis])
+ return space.div(self.descr_sum_promote(space, w_axis, w_out), w_denom)
+
+
@unwrap_spec(offset=int)
def descr_new_array(space, w_subtype, w_shape, w_dtype=None, w_buffer=None,
offset=0, w_strides=None, w_order=None):
@@ -159,6 +196,19 @@
ndim = GetSetProperty(W_NDimArray.descr_get_ndim),
size = GetSetProperty(W_NDimArray.descr_get_size),
+ mean = interp2app(W_NDimArray.descr_mean),
+ sum = interp2app(W_NDimArray.descr_sum),
+ prod = interp2app(W_NDimArray.descr_prod),
+ max = interp2app(W_NDimArray.descr_max),
+ min = interp2app(W_NDimArray.descr_min),
+ #argmax = interp2app(W_NDimArray.descr_argmax),
+ #argmin = interp2app(W_NDimArray.descr_argmin),
+ all = interp2app(W_NDimArray.descr_all),
+ any = interp2app(W_NDimArray.descr_any),
+ #dot = interp2app(W_NDimArray.descr_dot),
+ #var = interp2app(W_NDimArray.descr_var),
+ #std = interp2app(W_NDimArray.descr_std),
+
copy = interp2app(W_NDimArray.descr_copy),
)
diff --git a/pypy/module/micronumpy/interp_ufuncs.py
b/pypy/module/micronumpy/interp_ufuncs.py
--- a/pypy/module/micronumpy/interp_ufuncs.py
+++ b/pypy/module/micronumpy/interp_ufuncs.py
@@ -10,6 +10,12 @@
from pypy.module.micronumpy.strides import shape_agreement
from pypy.module.micronumpy.support import convert_to_array
+def done_if_true(dtype, val):
+ return dtype.itemtype.bool(val)
+
+def done_if_false(dtype, val):
+ return not dtype.itemtype.bool(val)
+
class W_Ufunc(Wrappable):
_attrs_ = ["name", "promote_to_float", "promote_bools", "identity"]
_immutable_fields_ = ["promote_to_float", "promote_bools", "name"]
@@ -135,53 +141,54 @@
def reduce(self, space, w_obj, multidim, promote_to_largest, w_axis,
keepdims=False, out=None):
- from pypy.module.micronumpy.interp_numarray import \
- Scalar, ReduceArray, W_NDimArray
+ from pypy.module.micronumpy.interp_numarray import W_NDimArray
+
if self.argcount != 2:
raise OperationError(space.w_ValueError, space.wrap("reduce only "
"supported for binary functions"))
assert isinstance(self, W_Ufunc2)
obj = convert_to_array(space, w_obj)
- if isinstance(obj, Scalar):
+ obj_shape = obj.get_shape()
+ if obj.is_scalar():
raise OperationError(space.w_TypeError, space.wrap("cannot reduce "
"on a scalar"))
- axis = unwrap_axis_arg(space, len(obj.shape), w_axis)
+ shapelen = len(obj_shape)
+ axis = unwrap_axis_arg(space, shapelen, w_axis)
assert axis>=0
- size = obj.size
+ size = obj.get_size()
if self.comparison_func:
dtype = interp_dtype.get_dtype_cache(space).w_booldtype
else:
dtype = find_unaryop_result_dtype(
- space, obj.find_dtype(),
+ space, obj.get_dtype(),
promote_to_float=self.promote_to_float,
promote_to_largest=promote_to_largest,
promote_bools=True
)
- shapelen = len(obj.shape)
if self.identity is None and size == 0:
raise operationerrfmt(space.w_ValueError, "zero-size array to "
"%s.reduce without identity", self.name)
if shapelen > 1 and axis < shapelen:
if keepdims:
- shape = obj.shape[:axis] + [1] + obj.shape[axis + 1:]
+ shape = obj_shape[:axis] + [1] + obj_shape[axis + 1:]
else:
- shape = obj.shape[:axis] + obj.shape[axis + 1:]
+ shape = obj_shape[:axis] + obj_shape[axis + 1:]
if out:
#Test for shape agreement
- if len(out.shape) > len(shape):
+ if len(out.get_shape()) > len(shape):
raise operationerrfmt(space.w_ValueError,
'output parameter for reduction operation %s' +
' has too many dimensions', self.name)
- elif len(out.shape) < len(shape):
+ elif len(out.get_shape()) < len(shape):
raise operationerrfmt(space.w_ValueError,
'output parameter for reduction operation %s' +
' does not have enough dimensions', self.name)
- elif out.shape != shape:
+ elif out.get_shape() != shape:
raise operationerrfmt(space.w_ValueError,
'output parameter shape mismatch, expecting [%s]' +
' , got [%s]',
",".join([str(x) for x in shape]),
- ",".join([str(x) for x in out.shape]),
+ ",".join([str(x) for x in out.get_shape()]),
)
#Test for dtype agreement, perhaps create an itermediate
#if out.dtype != dtype:
@@ -192,19 +199,17 @@
result = W_NDimArray(shape, dtype)
return self.do_axis_reduce(obj, dtype, axis, result)
if out:
- if len(out.shape)>0:
+ if len(out.get_shape())>0:
raise operationerrfmt(space.w_ValueError, "output parameter "
"for reduction operation %s has too many"
" dimensions",self.name)
- arr = ReduceArray(self.func, self.name, self.identity, obj,
- out.find_dtype())
- val = loop.compute(arr)
- assert isinstance(out, Scalar)
- out.value = val
- else:
- arr = ReduceArray(self.func, self.name, self.identity, obj, dtype)
- val = loop.compute(arr)
- return val
+ dtype = out.get_dtype()
+ res = loop.compute_reduce(obj, dtype, self.func, self.done_func,
+ self.identity)
+ if out:
+ out.set_scalar_value(res)
+ return out
+ return res
def do_axis_reduce(self, obj, dtype, axis, result):
from pypy.module.micronumpy.interp_numarray import AxisReduce
@@ -287,6 +292,12 @@
int_only)
self.func = func
self.comparison_func = comparison_func
+ if name == 'logical_and':
+ self.done_func = done_if_false
+ elif name == 'logical_or':
+ self.done_func = done_if_true
+ else:
+ self.done_func = None
@jit.unroll_safe
def call(self, space, args_w):
diff --git a/pypy/module/micronumpy/loop.py b/pypy/module/micronumpy/loop.py
--- a/pypy/module/micronumpy/loop.py
+++ b/pypy/module/micronumpy/loop.py
@@ -37,81 +37,17 @@
source_iter.next()
return target
-# from pypy.rlib.jit import JitDriver, hint, unroll_safe, promote
-# from pypy.module.micronumpy.interp_iter import ConstantIterator
-
-# class NumpyEvalFrame(object):
-# _virtualizable2_ = ['iterators[*]', 'final_iter', 'arraylist[*]',
-# 'value', 'identity', 'cur_value']
-
-# @unroll_safe
-# def __init__(self, iterators, arrays):
-# self = hint(self, access_directly=True, fresh_virtualizable=True)
-# self.iterators = iterators[:]
-# self.arrays = arrays[:]
-# for i in range(len(self.iterators)):
-# iter = self.iterators[i]
-# if not isinstance(iter, ConstantIterator):
-# self.final_iter = i
-# break
-# else:
-# self.final_iter = -1
-# self.cur_value = None
-# self.identity = None
-
-# def done(self):
-# final_iter = promote(self.final_iter)
-# if final_iter < 0:
-# assert False
-# return self.iterators[final_iter].done()
-
-# @unroll_safe
-# def next(self, shapelen):
-# for i in range(len(self.iterators)):
-# self.iterators[i] = self.iterators[i].next(shapelen)
-
-# @unroll_safe
-# def next_from_second(self, shapelen):
-# """ Don't increase the first iterator
-# """
-# for i in range(1, len(self.iterators)):
-# self.iterators[i] = self.iterators[i].next(shapelen)
-
-# def next_first(self, shapelen):
-# self.iterators[0] = self.iterators[0].next(shapelen)
-
-# def get_final_iter(self):
-# final_iter = promote(self.final_iter)
-# if final_iter < 0:
-# assert False
-# return self.iterators[final_iter]
-
-# def get_printable_location(shapelen, sig):
-# return 'numpy ' + sig.debug_repr() + ' [%d dims]' % (shapelen,)
-
-# numpy_driver = JitDriver(
-# greens=['shapelen', 'sig'],
-# virtualizables=['frame'],
-# reds=['frame', 'arr'],
-# get_printable_location=get_printable_location,
-# name='numpy',
-# )
-
-# class ComputationDone(Exception):
-# def __init__(self, value):
-# self.value = value
-
-# def compute(arr):
-# sig = arr.find_sig()
-# shapelen = len(arr.shape)
-# frame = sig.create_frame(arr)
-# try:
-# while not frame.done():
-# numpy_driver.jit_merge_point(sig=sig,
-# shapelen=shapelen,
-# frame=frame, arr=arr)
-# sig.eval(frame, arr)
-# frame.next(shapelen)
-# return frame.cur_value
-# except ComputationDone, e:
-# return e.value
+def compute_reduce(obj, calc_dtype, func, done_func, identity):
+ obj_iter = obj.create_iter()
+ if identity is None:
+ cur_value = obj_iter.getitem().convert_to(calc_dtype)
+ obj_iter.next()
+ else:
+ cur_value = identity.convert_to(calc_dtype)
+ while not obj_iter.done():
+ rval = obj_iter.getitem().convert_to(calc_dtype)
+ if done_func is not None and done_func(calc_dtype, rval):
+ return rval
+ cur_value = func(calc_dtype, cur_value, rval)
+ obj_iter.next()
+ return cur_value
_______________________________________________
pypy-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit