Author: mattip <[email protected]>
Branch: ufuncapi
Changeset: r74576:27f4ddb2db05
Date: 2014-11-19 00:22 +0200
http://bitbucket.org/pypy/pypy/changeset/27f4ddb2db05/
Log: refactor and use coalescing to pass a test
diff --git a/pypy/module/micronumpy/iterators.py
b/pypy/module/micronumpy/iterators.py
--- a/pypy/module/micronumpy/iterators.py
+++ b/pypy/module/micronumpy/iterators.py
@@ -117,11 +117,9 @@
self.shape_m1 = [s - 1 for s in shape]
self.strides = strides
self.backstrides = backstrides
- self.slice_shape = 1
- self.slice_stride = -1
- if strides:
- self.slice_stride = strides[-1]
- self.slice_backstride = 1
+ self.slice_shape = []
+ self.slice_stride = []
+ self.slice_backstride = []
self.slice_operand_type = concrete.SliceArray
ndim = len(shape)
@@ -280,6 +278,6 @@
def getoperand(self, state, base):
assert state.iterator is self
impl = self.slice_operand_type
- arr = impl(state.offset, [self.slice_stride], [self.slice_backstride],
- [self.slice_shape], self.array, self.base)
+ arr = impl(state.offset, self.slice_stride, self.slice_backstride,
+ self.slice_shape, self.array, self.base)
return arr
diff --git a/pypy/module/micronumpy/nditer.py b/pypy/module/micronumpy/nditer.py
--- a/pypy/module/micronumpy/nditer.py
+++ b/pypy/module/micronumpy/nditer.py
@@ -200,27 +200,8 @@
break
if can_coalesce:
for i in range(len(it.iters)):
- old_iter = it.iters[i][0]
- shape = [s+1 for s in old_iter.shape_m1]
- strides = old_iter.strides
- backstrides = old_iter.backstrides
- if it.order == 'F':
- new_shape = shape[1:]
- new_strides = strides[1:]
- new_backstrides = backstrides[1:]
- _stride = min(strides[0], old_iter.slice_stride)
- else:
- new_shape = shape[:-1]
- new_strides = strides[:-1]
- new_backstrides = backstrides[:-1]
- _stride = old_iter.slice_stride
- # We always want the "fastest" iterator in external loops
- _shape = shape[fastest] * old_iter.slice_shape
- _backstride = (_shape - 1) * _stride
- new_iter = SliceIter(old_iter.array, old_iter.size /
shape[fastest],
- new_shape, new_strides, new_backstrides,
- _shape, _stride, _backstride,
- it.op_flags[i], it)
+ new_iter = coalesce_iter(it.iters[i][0], it.op_flags[i], it,
+ it.order, fastest)
it.iters[i] = (new_iter, new_iter.reset())
if len(it.shape) > 1:
if it.order == 'F':
@@ -229,26 +210,12 @@
it.shape = it.shape[:-1]
else:
it.shape = [1]
+
else:
break
# Always coalesce at least one
for i in range(len(it.iters)):
- old_iter = it.iters[i][0]
- shape = [s+1 for s in old_iter.shape_m1]
- strides = old_iter.strides
- backstrides = old_iter.backstrides
- new_shape = shape[:-1]
- new_strides = strides[:-1]
- new_backstrides = backstrides[:-1]
- _shape = shape[-1] * old_iter.slice_shape
- # use the operand's iterator's rightmost stride,
- # even if it is not the fastest (for 'F' or swapped axis)
- _stride = old_iter.slice_stride
- _backstride = (_shape - 1) * _stride
- new_iter = SliceIter(old_iter.array, old_iter.size / shape[-1],
- new_shape, new_strides, new_backstrides,
- _shape, _stride, _backstride,
- it.op_flags[i], it)
+ new_iter = coalesce_iter(it.iters[i][0], it.op_flags[i], it, 'C', -1)
it.iters[i] = (new_iter, new_iter.reset())
if len(it.shape) > 1:
if it.order == 'F':
@@ -258,6 +225,43 @@
else:
it.shape = [1]
+
+def coalesce_iter(old_iter, op_flags, it, order, fastest=-1, flat=True):
+ '''
+ We usually iterate through an array one value at a time.
+ But after coalesce(), getoperand() will return a slice by removing
+ the fastest varying dimension from the beginning or end of the shape.
+ XXX - what happens on swapaxis arrays?
+ If flat is true, then the slice will be 1d, otherwise stack up the shape of
+ the fastest varying dimension in the slice, so an iterator of a 'C' array
+ of shape (2,4,3) after two calls to coalesce will iterate 2 times over a
slice
+ of shape (4,3) by setting the offset to the beginning of the data at each
iteration
+ '''
+ shape = [s+1 for s in old_iter.shape_m1]
+ strides = old_iter.strides
+ backstrides = old_iter.backstrides
+ if order == 'F':
+ new_shape = shape[1:]
+ new_strides = strides[1:]
+ new_backstrides = backstrides[1:]
+ _stride = old_iter.slice_stride + [strides[0]]
+ else:
+ new_shape = shape[:-1]
+ new_strides = strides[:-1]
+ new_backstrides = backstrides[:-1]
+ # use the operand's iterator's rightmost stride,
+ # even if it is not the fastest (for 'F' or swapped axis)
+ _stride = [strides[-1]] + old_iter.slice_stride
+ _shape = [shape[fastest]] + old_iter.slice_shape
+ _backstride = [(_shape[fastest] - 1) * _stride[0]] +
old_iter.slice_backstride
+ if flat:
+ _shape = [support.product(_shape)]
+ _stride = [min(_stride)]
+ _backstride = [(shape[0] - 1) * _stride[0]]
+ return SliceIter(old_iter.array, old_iter.size / shape[fastest],
+ new_shape, new_strides, new_backstrides,
+ _shape, _stride, _backstride, op_flags, it)
+
class IndexIterator(object):
def __init__(self, shape, backward=False):
self.shape = shape
diff --git a/pypy/module/micronumpy/ufuncs.py b/pypy/module/micronumpy/ufuncs.py
--- a/pypy/module/micronumpy/ufuncs.py
+++ b/pypy/module/micronumpy/ufuncs.py
@@ -9,7 +9,7 @@
from pypy.module.micronumpy import boxes, descriptor, loop, constants as NPY
from pypy.module.micronumpy.base import convert_to_array, W_NDimArray
from pypy.module.micronumpy.ctors import numpify
-from pypy.module.micronumpy.nditer import W_NDIter
+from pypy.module.micronumpy.nditer import W_NDIter, coalesce_iter
from pypy.module.micronumpy.strides import shape_agreement
from pypy.module.micronumpy.support import _parse_signature
from rpython.rlib.rawstorage import (raw_storage_setitem, free_raw_storage,
@@ -698,7 +698,7 @@
# TODO parse and handle subok
# TODO handle flags, op_flags
- w_flags = space.w_None #space.newlist([space.wrap('external_loop')])
+ w_flags = space.w_None # NOT 'external_loop', we do coalescing by
core_num_dims
w_op_flags = space.newtuple([space.wrap(['readonly'])] * len(inargs) +
\
[space.wrap(['readwrite'])] * len(outargs))
w_op_dtypes = space.w_None
@@ -706,14 +706,25 @@
w_itershape = space.newlist([space.wrap(i) for i in iter_shape])
w_op_axes = space.w_None
- # mimic NpyIter_AdvancedNew with a nditer
if self.stack_inputs:
+ # mimic NpyIter_AdvancedNew with a nditer
nd_it = W_NDIter(space, space.newlist(inargs + outargs), w_flags,
w_op_flags, w_op_dtypes, w_casting, w_op_axes,
w_itershape)
- # XXX coalesce each iterators, according to inner_dimensions
+ # coalesce each iterators, according to inner_dimensions
+ if nd_it.order == 'F':
+ fastest = 0
+ else:
+ fastest = -1
+ for i in range(len(inargs) + len(outargs)):
+ for j in range(self.core_num_dims[i]):
+ new_iter = coalesce_iter(nd_it.iters[i][0],
nd_it.op_flags[i],
+ nd_it, nd_it.order, fastest, flat=False)
+ nd_it.iters[i] = (new_iter, new_iter.reset())
+ # do the iteration
while not nd_it.done:
+ # XXX jit me
for it, st in nd_it.iters:
if not it.done(st):
break
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit