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

Reply via email to