[pypy-commit] pypy default: merge numpy-fixes which further advances numpy complience
mattip
noreply at buildbot.pypy.org
Wed May 13 17:54:05 CEST 2015
Author: mattip <matti.picus at gmail.com>
Branch:
Changeset: r77309:bdf0f94b1bd2
Date: 2015-05-13 18:53 +0300
http://bitbucket.org/pypy/pypy/changeset/bdf0f94b1bd2/
Log: merge numpy-fixes which further advances numpy complience
diff --git a/pypy/doc/whatsnew-head.rst b/pypy/doc/whatsnew-head.rst
--- a/pypy/doc/whatsnew-head.rst
+++ b/pypy/doc/whatsnew-head.rst
@@ -81,3 +81,11 @@
.. branch: can_cast
Implement np.can_cast, np.min_scalar_type and missing dtype comparison operations.
+
+.. branch: numpy-fixes
+Fix some error related to object dtype, non-contiguous arrays, inplement parts of
+__array_interface__, __array_priority__, __array_wrap__
+
+.. branch: cells-local-stack
+Unify the PyFrame.cells and Pyframe.locals_stack_w lists, making frame objects
+1 or 3 words smaller.
diff --git a/pypy/module/micronumpy/app_numpy.py b/pypy/module/micronumpy/app_numpy.py
--- a/pypy/module/micronumpy/app_numpy.py
+++ b/pypy/module/micronumpy/app_numpy.py
@@ -12,8 +12,8 @@
stop = start
start = 0
if dtype is None:
- test = _numpypy.multiarray.array([start, stop, step, 0])
- dtype = test.dtype
+ # find minimal acceptable dtype but not less than int
+ dtype = _numpypy.multiarray.result_type(start, stop, step, int)
length = math.ceil((float(stop) - start) / step)
length = int(length)
arr = _numpypy.multiarray.empty(length, dtype=dtype)
diff --git a/pypy/module/micronumpy/boxes.py b/pypy/module/micronumpy/boxes.py
--- a/pypy/module/micronumpy/boxes.py
+++ b/pypy/module/micronumpy/boxes.py
@@ -197,6 +197,9 @@
def descr_hash(self, space):
return space.hash(self.item(space))
+ def descr___array_priority__(self, space):
+ return space.wrap(0.0)
+
def descr_index(self, space):
return space.index(self.item(space))
@@ -680,6 +683,8 @@
__hash__ = interp2app(W_GenericBox.descr_hash),
+ __array_priority__ = GetSetProperty(W_GenericBox.descr___array_priority__),
+
tolist = interp2app(W_GenericBox.item),
item = interp2app(W_GenericBox.descr_item),
transpose = interp2app(W_GenericBox.descr_transpose),
diff --git a/pypy/module/micronumpy/compile.py b/pypy/module/micronumpy/compile.py
--- a/pypy/module/micronumpy/compile.py
+++ b/pypy/module/micronumpy/compile.py
@@ -203,6 +203,12 @@
assert isinstance(w_obj, BoolObject)
return bool(w_obj.intval)
+ def gt(self, w_lhs, w_rhs):
+ return BoolObject(self.int_w(w_lhs) > self.int_w(w_rhs))
+
+ def lt(self, w_lhs, w_rhs):
+ return BoolObject(self.int_w(w_lhs) < self.int_w(w_rhs))
+
def is_w(self, w_obj, w_what):
return w_obj is w_what
@@ -235,8 +241,7 @@
def call_method(self, w_obj, s, *args):
# XXX even the hacks have hacks
- return None
- #return getattr(w_obj, 'descr_' + s)(self, *args)
+ return getattr(w_obj, 'descr_' + s)(self, *args)
@specialize.arg(1)
def interp_w(self, tp, what):
diff --git a/pypy/module/micronumpy/concrete.py b/pypy/module/micronumpy/concrete.py
--- a/pypy/module/micronumpy/concrete.py
+++ b/pypy/module/micronumpy/concrete.py
@@ -11,7 +11,7 @@
from pypy.module.micronumpy.iterators import ArrayIter
from pypy.module.micronumpy.strides import (Chunk, Chunks, NewAxisChunk,
RecordChunk, calc_strides, calc_new_strides, shape_agreement,
- calculate_broadcast_strides, calc_backstrides)
+ calculate_broadcast_strides, calc_backstrides, calc_start)
from rpython.rlib.objectmodel import keepalive_until_here
from rpython.rtyper.annlowlevel import cast_gcref_to_instance
from pypy.interpreter.baseobjspace import W_Root
@@ -90,8 +90,9 @@
new_shape, self, orig_array)
return None
- def get_view(self, space, orig_array, dtype, new_shape):
- strides, backstrides = calc_strides(new_shape, dtype,
+ def get_view(self, space, orig_array, dtype, new_shape, strides=None, backstrides=None):
+ if not strides:
+ strides, backstrides = calc_strides(new_shape, dtype,
self.order)
return SliceArray(self.start, strides, backstrides, new_shape,
self, orig_array, dtype=dtype)
@@ -323,15 +324,27 @@
def __exit__(self, typ, value, traceback):
keepalive_until_here(self)
-
+
def get_buffer(self, space, readonly):
return ArrayBuffer(self, readonly)
def astype(self, space, dtype):
- strides, backstrides = calc_strides(self.get_shape(), dtype,
- self.order)
- impl = ConcreteArray(self.get_shape(), dtype, self.order,
- strides, backstrides)
+ # copy the general pattern of the strides
+ # but make the array storage contiguous in memory
+ shape = self.get_shape()
+ strides = self.get_strides()
+ if len(strides) > 0:
+ mins = strides[0]
+ t_elsize = dtype.elsize
+ for s in strides:
+ if s < mins:
+ mins = s
+ t_strides = [s * t_elsize / mins for s in strides]
+ backstrides = calc_backstrides(t_strides, shape)
+ else:
+ t_strides = []
+ backstrides = []
+ impl = ConcreteArray(shape, dtype, self.order, t_strides, backstrides)
loop.setslice(space, impl.get_shape(), impl, self)
return impl
@@ -426,8 +439,9 @@
gcstruct = _create_objectstore(storage, length, dtype.elsize)
else:
storage = dtype.itemtype.malloc(length * dtype.elsize, zero=zero)
+ start = calc_start(shape, strides)
ConcreteArrayNotOwning.__init__(self, shape, dtype, order, strides, backstrides,
- storage)
+ storage, start=start)
self.gcstruct = gcstruct
def __del__(self):
diff --git a/pypy/module/micronumpy/ctors.py b/pypy/module/micronumpy/ctors.py
--- a/pypy/module/micronumpy/ctors.py
+++ b/pypy/module/micronumpy/ctors.py
@@ -124,19 +124,21 @@
copy = True
if copy:
shape = w_object.get_shape()
- elems_w = [None] * w_object.get_size()
- elsize = w_object.get_dtype().elsize
- # TODO - use w_object.implementation without copying to a list
- # unfortunately that causes a union error in translation
- for i in range(w_object.get_size()):
- elems_w[i] = w_object.implementation.getitem(i * elsize)
+ w_arr = W_NDimArray.from_shape(space, shape, dtype, order=order)
+ if support.product(shape) == 1:
+ w_arr.set_scalar_value(dtype.coerce(space,
+ w_object.implementation.getitem(0)))
+ else:
+ loop.setslice(space, shape, w_arr.implementation, w_object.implementation)
+ return w_arr
else:
imp = w_object.implementation
+ w_base = imp.base() or w_object
with imp as storage:
sz = support.product(w_object.get_shape()) * dtype.elsize
return W_NDimArray.from_shape_and_storage(space,
w_object.get_shape(), storage, dtype, storage_bytes=sz,
- w_base=w_object, start=imp.start)
+ w_base=w_base, start=imp.start)
else:
# not an array
shape, elems_w = strides.find_shape_and_elems(space, w_object, dtype)
diff --git a/pypy/module/micronumpy/flatiter.py b/pypy/module/micronumpy/flatiter.py
--- a/pypy/module/micronumpy/flatiter.py
+++ b/pypy/module/micronumpy/flatiter.py
@@ -97,6 +97,8 @@
finally:
self.iter.reset(self.state, mutate=True)
+ def descr___array_wrap__(self, space, obj):
+ return obj
W_FlatIterator.typedef = TypeDef("numpy.flatiter",
base = GetSetProperty(W_FlatIterator.descr_base),
@@ -116,4 +118,5 @@
__le__ = interp2app(W_FlatIterator.descr_le),
__gt__ = interp2app(W_FlatIterator.descr_gt),
__ge__ = interp2app(W_FlatIterator.descr_ge),
+ __array_wrap__ = interp2app(W_NDimArray.descr___array_wrap__),
)
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
@@ -22,9 +22,8 @@
# handle array_priority
# w_lhs and w_rhs could be of different ndarray subtypes. Numpy does:
# 1. if __array_priorities__ are equal and one is an ndarray and the
- # other is a subtype, flip the order
- # 2. elif rhs.__array_priority__ is higher, flip the order
- # Now return the subtype of the first one
+ # other is a subtype, return a subtype
+ # 2. elif rhs.__array_priority__ is higher, return the type of rhs
w_ndarray = space.gettypefor(W_NDimArray)
lhs_type = space.type(w_lhs)
@@ -38,10 +37,15 @@
if not space.is_true(space.issubtype(rhs_type, w_ndarray)):
rhs_type = space.type(w_rhs.base)
rhs_for_subtype = w_rhs.base
+
+ w_highpriority = w_lhs
+ highpriority_subtype = lhs_for_subtype
if space.is_w(lhs_type, w_ndarray) and not space.is_w(rhs_type, w_ndarray):
- lhs_for_subtype = rhs_for_subtype
-
- # TODO handle __array_priorities__ and maybe flip the order
+ highpriority_subtype = rhs_for_subtype
+ w_highpriority = w_rhs
+ if support.is_rhs_priority_higher(space, w_lhs, w_rhs):
+ highpriority_subtype = rhs_for_subtype
+ w_highpriority = w_rhs
if w_lhs.get_size() == 1:
w_left = w_lhs.get_scalar_value().convert_to(space, calc_dtype)
@@ -60,9 +64,11 @@
right_iter.track_index = False
if out is None:
- out = W_NDimArray.from_shape(space, shape, res_dtype,
- w_instance=lhs_for_subtype)
- out_iter, out_state = out.create_iter(shape)
+ w_ret = W_NDimArray.from_shape(space, shape, res_dtype,
+ w_instance=highpriority_subtype)
+ else:
+ w_ret = out
+ out_iter, out_state = w_ret.create_iter(shape)
shapelen = len(shape)
while not out_iter.done(out_state):
call2_driver.jit_merge_point(shapelen=shapelen, func=func,
@@ -76,7 +82,9 @@
out_iter.setitem(out_state, func(calc_dtype, w_left, w_right).convert_to(
space, res_dtype))
out_state = out_iter.next(out_state)
- return out
+ if out is None:
+ w_ret = space.call_method(w_highpriority, '__array_wrap__', w_ret)
+ return w_ret
call1_driver = jit.JitDriver(
name='numpy_call1',
@@ -88,8 +96,10 @@
obj_iter.track_index = False
if out is None:
- out = W_NDimArray.from_shape(space, shape, res_dtype, w_instance=w_obj)
- out_iter, out_state = out.create_iter(shape)
+ w_ret = W_NDimArray.from_shape(space, shape, res_dtype, w_instance=w_obj)
+ else:
+ w_ret = out
+ out_iter, out_state = w_ret.create_iter(shape)
shapelen = len(shape)
while not out_iter.done(out_state):
call1_driver.jit_merge_point(shapelen=shapelen, func=func,
@@ -98,7 +108,9 @@
out_iter.setitem(out_state, func(calc_dtype, elem).convert_to(space, res_dtype))
out_state = out_iter.next(out_state)
obj_state = obj_iter.next(obj_state)
- return out
+ if out is None:
+ w_ret = space.call_method(w_obj, '__array_wrap__', w_ret)
+ return w_ret
call_many_to_one_driver = jit.JitDriver(
name='numpy_call_many_to_one',
@@ -209,7 +221,7 @@
while not target_iter.done(target_state):
setslice_driver.jit_merge_point(shapelen=shapelen, dtype=dtype)
val = source_iter.getitem(source_state)
- if dtype.is_str_or_unicode():
+ if dtype.is_str_or_unicode() or dtype.is_record():
val = dtype.coerce(space, val)
else:
val = val.convert_to(space, dtype)
diff --git a/pypy/module/micronumpy/ndarray.py b/pypy/module/micronumpy/ndarray.py
--- a/pypy/module/micronumpy/ndarray.py
+++ b/pypy/module/micronumpy/ndarray.py
@@ -569,6 +569,11 @@
def fdel___pypy_data__(self, space):
self.w_pypy_data = None
+ __array_priority__ = 0.0
+
+ def descr___array_priority__(self, space):
+ return space.wrap(self.__array_priority__)
+
def descr_argsort(self, space, w_axis=None, w_kind=None, w_order=None):
# happily ignore the kind
# create a contiguous copy of the array
@@ -797,6 +802,7 @@
new_shape = [s for s in cur_shape if s != 1]
if len(cur_shape) == len(new_shape):
return self
+ # XXX need to call __array_wrap__
return wrap_impl(space, space.type(self), self,
self.implementation.get_view(
space, self, self.get_dtype(), new_shape))
@@ -844,28 +850,40 @@
if old_itemsize != new_itemsize:
raise OperationError(space.w_ValueError, space.wrap(
"new type not compatible with array."))
+ strides = None
+ backstrides = None
+ base = self
else:
- if not is_c_contiguous(impl) and not is_f_contiguous(impl):
- if old_itemsize != new_itemsize:
+ base = impl.base()
+ if base is None:
+ base = self
+ strides = impl.get_strides()[:]
+ backstrides = impl.get_backstrides()[:]
+ if old_itemsize != new_itemsize:
+ if not is_c_contiguous(impl) and not is_f_contiguous(impl):
raise OperationError(space.w_ValueError, space.wrap(
"new type not compatible with array."))
- # Strides, shape does not change
- v = impl.astype(space, dtype)
- return wrap_impl(space, w_type, self, v)
- strides = impl.get_strides()
- if dims == 1 or strides[0] <strides[-1]:
- # Column-major, resize first dimension
- if new_shape[0] * old_itemsize % new_itemsize != 0:
+ # Adapt the smallest dim to the new itemsize
+ if self.get_order() == 'F':
+ minstride = strides[0]
+ mini = 0
+ else:
+ minstride = strides[-1]
+ mini = len(strides) - 1
+ for i in range(len(strides)):
+ if strides[i] < minstride:
+ minstride = strides[i]
+ mini = i
+ if new_shape[mini] * old_itemsize % new_itemsize != 0:
raise OperationError(space.w_ValueError, space.wrap(
"new type not compatible with array."))
- new_shape[0] = new_shape[0] * old_itemsize / new_itemsize
- else:
- # Row-major, resize last dimension
- if new_shape[-1] * old_itemsize % new_itemsize != 0:
- raise OperationError(space.w_ValueError, space.wrap(
- "new type not compatible with array."))
- new_shape[-1] = new_shape[-1] * old_itemsize / new_itemsize
- v = impl.get_view(space, self, dtype, new_shape)
+ new_shape[mini] = new_shape[mini] * old_itemsize / new_itemsize
+ strides[mini] = strides[mini] * new_itemsize / old_itemsize
+ backstrides[mini] = strides[mini] * new_shape[mini]
+ if dtype.is_object() != impl.dtype.is_object():
+ raise oefmt(space.w_ValueError, 'expect trouble in ndarray.view,'
+ ' one of target dtype or dtype is object dtype')
+ v = impl.get_view(space, base, dtype, new_shape, strides, backstrides)
w_ret = wrap_impl(space, w_type, self, v)
return w_ret
@@ -928,6 +946,7 @@
return ufunc(self, space, w_other, w_out)
except OperationError, e:
if e.match(space, space.w_ValueError):
+ # and 'operands could not be broadcast together' in str(e.get_w_value(space)):
return space.w_False
raise e
@@ -1048,7 +1067,7 @@
# ----------------------- reduce -------------------------------
- def _reduce_ufunc_impl(ufunc_name, cumulative=False):
+ def _reduce_ufunc_impl(ufunc_name, cumulative=False, bool_result=False):
@unwrap_spec(keepdims=bool)
def impl(self, space, w_axis=None, w_dtype=None, w_out=None, keepdims=False):
if space.is_none(w_out):
@@ -1057,6 +1076,8 @@
raise oefmt(space.w_TypeError, 'output must be an array')
else:
out = w_out
+ if bool_result:
+ w_dtype = descriptor.get_dtype_cache(space).w_booldtype
return getattr(ufuncs.get(space), ufunc_name).reduce(
space, self, w_axis, keepdims, out, w_dtype, cumulative=cumulative)
return func_with_new_name(impl, "reduce_%s_impl_%d" % (ufunc_name, cumulative))
@@ -1065,8 +1086,8 @@
descr_prod = _reduce_ufunc_impl("multiply")
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')
+ descr_all = _reduce_ufunc_impl('logical_and', bool_result=True)
+ descr_any = _reduce_ufunc_impl('logical_or', bool_result=True)
descr_cumsum = _reduce_ufunc_impl('add', cumulative=True)
descr_cumprod = _reduce_ufunc_impl('multiply', cumulative=True)
@@ -1497,6 +1518,7 @@
__array_finalize__ = interp2app(W_NDimArray.descr___array_finalize__),
__array_prepare__ = interp2app(W_NDimArray.descr___array_prepare__),
__array_wrap__ = interp2app(W_NDimArray.descr___array_wrap__),
+ __array_priority__ = GetSetProperty(W_NDimArray.descr___array_priority__),
__array__ = interp2app(W_NDimArray.descr___array__),
)
diff --git a/pypy/module/micronumpy/strides.py b/pypy/module/micronumpy/strides.py
--- a/pypy/module/micronumpy/strides.py
+++ b/pypy/module/micronumpy/strides.py
@@ -429,6 +429,17 @@
n_old_elems_to_use *= old_shape[oldI]
return new_strides[:]
+def calc_start(shape, strides):
+ ''' Strides can be negative for non-contiguous data.
+ Calculate the appropriate positive starting position so
+ the indexing still works properly
+ '''
+ start = 0
+ for i in range(len(shape)):
+ if strides[i] < 0:
+ start -= strides[i] * (shape[i] - 1)
+ return start
+
@jit.unroll_safe
def is_c_contiguous(arr):
shape = arr.get_shape()
diff --git a/pypy/module/micronumpy/support.py b/pypy/module/micronumpy/support.py
--- a/pypy/module/micronumpy/support.py
+++ b/pypy/module/micronumpy/support.py
@@ -152,3 +152,9 @@
def get_storage_as_int(storage, start=0):
return rffi.cast(lltype.Signed, storage) + start
+def is_rhs_priority_higher(space, w_lhs, w_rhs):
+ w_zero = space.wrap(0.0)
+ w_priority_l = space.findattr(w_lhs, space.wrap('__array_priority__')) or w_zero
+ w_priority_r = space.findattr(w_rhs, space.wrap('__array_priority__')) or w_zero
+ # XXX what is better, unwrapping values or space.gt?
+ return space.is_true(space.gt(w_priority_r, w_priority_l))
diff --git a/pypy/module/micronumpy/test/test_complex.py b/pypy/module/micronumpy/test/test_complex.py
--- a/pypy/module/micronumpy/test/test_complex.py
+++ b/pypy/module/micronumpy/test/test_complex.py
@@ -331,6 +331,12 @@
complex(float('nan'), 0)], dtype=complex)) == \
[False, True, True, False, False]).all()
+ def test_sign_for_complex_nan(self):
+ from numpy import array, nan, sign, isnan
+ C = array([nan], dtype=complex)
+ res = sign(C)
+ assert isnan(res.real)
+ assert res.imag == 0+0j
def test_square(self):
from numpy import square
@@ -480,12 +486,16 @@
assert c[i] == max(a[i], b[i])
- def test_abs_overflow(self):
- from numpy import array, absolute, isinf
+ def test_complex_overflow(self):
+ from numpy import array, absolute, isinf, complex128, floor_divide
a = array(complex(1.5e308,1.5e308))
# Prints a RuntimeWarning, but does not raise
b = absolute(a)
assert isinf(b)
+ c = array([1.e+110, 1.e-110], dtype=complex128)
+ d = floor_divide(c**2, c)
+ assert (d == [1.e+110, 0]).all()
+
def test_basic(self):
@@ -592,7 +602,7 @@
# but numpy.raises a TypeError
if '__pypy__' in sys.builtin_module_names:
exct, excm = TypeError, 'readonly attribute'
- else:
+ else :
exct, excm = AttributeError, 'is not writable'
exc = raises(exct, 'c2.real = 10.')
assert excm in exc.value[0]
diff --git a/pypy/module/micronumpy/test/test_iterators.py b/pypy/module/micronumpy/test/test_iterators.py
--- a/pypy/module/micronumpy/test/test_iterators.py
+++ b/pypy/module/micronumpy/test/test_iterators.py
@@ -66,6 +66,29 @@
assert s.offset == 1
assert s._indices == [1,0]
+ def test_one_in_shape(self):
+ strides = [16, 4, 8]
+ shape = [3, 4, 1]
+ backstrides = [x * (y - 1) for x,y in zip(strides, shape)]
+ assert backstrides == [32, 12, 0]
+ i = ArrayIter(MockArray(shape, strides), support.product(shape), shape,
+ strides, backstrides)
+ assert not i.contiguous
+ s = i.reset()
+ for j in range(3):
+ s = i.next(s)
+ assert s.offset == 12
+ assert not i.done(s)
+ assert s._indices == [0, 3, 0]
+ while not i.done(s):
+ old_indices = s._indices[:]
+ old_offset = s.offset
+ s = i.next(s)
+ assert s.offset == 0
+ assert s._indices == [0, 0, 0]
+ assert old_indices == [2, 3, 0]
+ assert old_offset == 44
+
def test_iterator_goto(self):
shape = [3, 5]
strides = [1, 3]
diff --git a/pypy/module/micronumpy/test/test_ndarray.py b/pypy/module/micronumpy/test/test_ndarray.py
--- a/pypy/module/micronumpy/test/test_ndarray.py
+++ b/pypy/module/micronumpy/test/test_ndarray.py
@@ -237,7 +237,7 @@
assert np.WRAP is 1
assert np.RAISE is 2
- def test_ndarray(self):
+ def test_creation(self):
from numpy import ndarray, array, dtype, flatiter
assert type(ndarray) is type
@@ -269,6 +269,12 @@
assert a.flags['C']
assert not a.flags['F']
+ x = array([[0, 2], [1, 1], [2, 0]])
+ y = array(x.T, dtype=float)
+ assert (y == x.T).all()
+ y = array(x.T, copy=False)
+ assert (y == x.T).all()
+
def test_ndmin(self):
from numpy import array
@@ -459,7 +465,7 @@
assert b.dtype is dtype(complex)
def test_arange(self):
- from numpy import arange, dtype
+ from numpy import arange, dtype, array
a = arange(3)
assert (a == [0, 1, 2]).all()
assert a.dtype is dtype(int)
@@ -480,6 +486,9 @@
assert len(a) == 8
assert arange(False, True, True).dtype is dtype(int)
+ a = arange(array([10]))
+ assert a.shape == (10,)
+
def test_copy(self):
from numpy import arange, array
a = arange(5)
@@ -1809,7 +1818,7 @@
y = x.view(dtype='int16')
def test_view_of_slice(self):
- from numpy import empty
+ from numpy import empty, dtype
x = empty([6], 'uint32')
x.fill(0xdeadbeef)
s = x[::3]
@@ -1817,7 +1826,19 @@
assert exc.value[0] == 'new type not compatible with array.'
s[...] = 2
v = s.view(x.__class__)
+ assert v.strides == s.strides
+ assert v.base is s.base
assert (v == 2).all()
+ y = empty([6,6], 'uint32')
+ s = y.swapaxes(0, 1)
+ v = s.view(y.__class__)
+ assert v.strides == (4, 24)
+
+ a = empty([3, 2, 1], dtype='float64')
+ b = a.view(dtype('uint32'))
+ assert b.strides == (16, 8, 4)
+ assert b.shape == (3, 2, 2)
+ b.fill(0xdeadbeef)
def test_tolist_scalar(self):
from numpy import dtype
@@ -2182,8 +2203,13 @@
assert (b == [False, True, True]).all()
assert b.dtype == 'bool'
+ a = arange(11)[::-1]
+ b = a.astype('int32')
+ assert (b == a).all()
+
a = arange(6, dtype='f4').reshape(2,3)
- b = a.astype('i4')
+ b = a.T.astype('i4')
+ assert (a.T.strides == b.strides)
a = array('x').astype('S3').dtype
assert a.itemsize == 3
@@ -2203,6 +2229,12 @@
exc = raises(ValueError, a.astype, 'i8')
assert exc.value.message.startswith('invalid literal for int()')
+ a = arange(5, dtype=complex)
+ b = a.real
+ c = b.astype("int64")
+ assert c.shape == b.shape
+ assert c.strides == (8,)
+
def test_base(self):
from numpy import array
assert array(1).base is None
@@ -3821,6 +3853,14 @@
([4, 5, 6], [5.5, 6.5, 7.5, 8.5, 9.5])], dtype=d)
assert len(list(a[0])) == 2
+
+ mdtype = dtype([('a', bool), ('b', bool), ('c', bool)])
+ a = array([0, 0, 0, 1, 1])
+ # this creates a value of (x, x, x) in b for each x in a
+ b = array(a, dtype=mdtype)
+ assert b.shape == a.shape
+ c = array([(x, x, x) for x in [0, 0, 0, 1, 1]], dtype=mdtype)
+ assert (b == c).all()
def test_3d_record(self):
from numpy import dtype, array
diff --git a/pypy/module/micronumpy/test/test_object_arrays.py b/pypy/module/micronumpy/test/test_object_arrays.py
--- a/pypy/module/micronumpy/test/test_object_arrays.py
+++ b/pypy/module/micronumpy/test/test_object_arrays.py
@@ -52,8 +52,6 @@
import numpy as np
import sys
- if '__pypy__' in sys.builtin_module_names:
- skip('need to refactor use of raw_xxx_op in types to make this work')
a = np.array(["foo"], dtype=object)
b = np.array([1], dtype=object)
d = np.array([complex(1, 10)], dtype=object)
@@ -166,4 +164,3 @@
a = np.array([(1, 'object')], dt)
# Wrong way - should complain about writing buffer to object dtype
raises(ValueError, np.array, [1, 'object'], dt)
-
diff --git a/pypy/module/micronumpy/test/test_subtype.py b/pypy/module/micronumpy/test/test_subtype.py
--- a/pypy/module/micronumpy/test/test_subtype.py
+++ b/pypy/module/micronumpy/test/test_subtype.py
@@ -80,19 +80,46 @@
a = array(range(5))
b = matrix(a)
assert isinstance(b, matrix)
+ assert b.__array_priority__ == 0.0
assert (b == a).all()
a = array(5)[()]
for s in [matrix, ndarray]:
b = a.view(s)
assert b == a
assert type(b) is type(a)
+ a = matrix(array(range(5)))
+ for s in [matrix, ndarray]:
+ b = ndarray.view(a, s)
+ assert (b == a).all()
+ assert type(b) is s
def test_subtype_like_matrix(self):
import numpy as np
arr = np.array([1,2,3])
ret = np.ndarray.__new__(np.ndarray, arr.shape, arr.dtype, buffer=arr)
+ assert ret.__array_priority__ == 0.0
assert (arr == ret).all()
+
+ def test_priority(self):
+ from numpy import ndarray, arange, add
+ class DoReflected(object):
+ __array_priority__ = 10
+ def __radd__(self, other):
+ return 42
+ class A(object):
+ def __add__(self, other):
+ return NotImplemented
+
+
+ a = arange(10)
+ b = DoReflected()
+ c = A()
+ assert c + b == 42
+ assert a.__add__(b) is NotImplemented # not an exception
+ assert b.__radd__(a) == 42
+ assert a + b == 42
+
def test_finalize(self):
#taken from http://docs.scipy.org/doc/numpy/user/basics.subclassing.html#simple-example-adding-an-extra-attribute-to-ndarray
import numpy as np
@@ -276,7 +303,11 @@
def test_array_of_subtype(self):
import numpy as N
- # numpy's matrix class caused an infinite loop
+ # this part of numpy's matrix class causes an infinite loop
+ # on cpython
+ import sys
+ if '__pypy__' not in sys.builtin_module_names:
+ skip('does not pass on cpython')
class matrix(N.ndarray):
def __new__(subtype, data, dtype=None, copy=True):
print('matrix __new__')
@@ -326,7 +357,7 @@
return ret
def __array_finalize__(self, obj):
- print('matrix __array_finalize__')
+ print('matrix __array_finalize__',obj)
self._getitem = False
if (isinstance(obj, matrix) and obj._getitem): return
ndim = self.ndim
@@ -349,7 +380,7 @@
return
def __getitem__(self, index):
- print('matrix __getitem__')
+ print('matrix __getitem__',index)
self._getitem = True
try:
@@ -400,7 +431,7 @@
def test_setstate_no_version(self):
# Some subclasses of ndarray, like MaskedArray, do not use
- # version in __setstare__
+ # version in __setstate__
from numpy import ndarray, array
from pickle import loads, dumps
import sys, new
@@ -593,3 +624,51 @@
a = asarray(fp[5:6][:,4])
assert (a == vals).all()
+ def test__array_wrap__(self):
+ ''' Straight from the documentation of __array_wrap__
+ '''
+ import numpy as np
+
+ class MySubClass(np.ndarray):
+ output = ''
+
+ def __new__(cls, input_array, info=None):
+ obj = np.array(input_array).view(cls)
+ obj.info = info
+ return obj
+
+ def __array_finalize__(self, obj):
+ self.output += 'In __array_finalize__:'
+ self.output += ' self is %s' % repr(self)
+ self.output += ' obj is %s\n' % repr(obj)
+ print self.output
+ if obj is None: return
+ self.info = getattr(obj, 'info', None)
+
+ def __array_wrap__(self, out_arr, context=None):
+ self.output += 'In __array_wrap__:'
+ self.output += ' self is %s' % repr(self)
+ self.output += ' arr is %r\n' % (out_arr,)
+ # then just call the parent
+ ret = np.ndarray.__array_wrap__(self, out_arr, context)
+ print 'wrap',self.output
+ return ret
+
+ obj = MySubClass(np.arange(5), info='spam')
+ assert obj.output.startswith('In __array_finalize')
+ obj.output = ''
+ print 'np.arange(5) + 1'
+ arr2 = np.arange(5) + 1
+ assert len(obj.output) < 1
+ print 'np.add(arr2, obj)'
+ ret = np.add(arr2, obj)
+ assert obj.output.startswith('In __array_wrap')
+ assert 'finalize' not in obj.output
+ assert ret.info == 'spam'
+ print 'np.negative(obj)'
+ ret = np.negative(obj)
+ assert ret.info == 'spam'
+ print 'obj.sum()'
+ ret = obj.sum()
+ print type(ret)
+ assert ret.info == 'spam'
diff --git a/pypy/module/micronumpy/types.py b/pypy/module/micronumpy/types.py
--- a/pypy/module/micronumpy/types.py
+++ b/pypy/module/micronumpy/types.py
@@ -30,7 +30,26 @@
log2e = 1. / log2
log10 = math.log(10)
-
+'''
+if not we_are_translated():
+ _raw_storage_setitem_unaligned = raw_storage_setitem_unaligned
+ _raw_storage_getitem_unaligned = raw_storage_getitem_unaligned
+ def raw_storage_setitem_unaligned(storage, offset, value):
+ assert offset >=0
+ try:
+ assert offset < storage._obj.getlength()
+ except AttributeError:
+ pass
+ return _raw_storage_setitem_unaligned(storage, offset, value)
+
+ def raw_storage_getitem_unaligned(T, storage, offset):
+ assert offset >=0
+ try:
+ assert offset < storage._obj.getlength()
+ except AttributeError:
+ pass
+ return _raw_storage_getitem_unaligned(T, storage, offset)
+'''
def simple_unary_op(func):
specialize.argtype(1)(func)
@functools.wraps(func)
@@ -291,11 +310,15 @@
@raw_binary_op
def logical_and(self, v1, v2):
- return bool(v1) and bool(v2)
+ if bool(v1) and bool(v2):
+ return Bool._True
+ return Bool._False
@raw_binary_op
def logical_or(self, v1, v2):
- return bool(v1) or bool(v2)
+ if bool(v1) or bool(v2):
+ return Bool._True
+ return Bool._False
@raw_unary_op
def logical_not(self, v):
@@ -757,6 +780,8 @@
def sign(self, v):
if v == 0.0:
return 0.0
+ if rfloat.isnan(v):
+ return rfloat.NAN
return rfloat.copysign(1.0, v)
@raw_unary_op
@@ -1324,11 +1349,15 @@
@raw_binary_op
def logical_and(self, v1, v2):
- return self._cbool(v1) and self._cbool(v2)
+ if self._cbool(v1) and self._cbool(v2):
+ return Bool._True
+ return Bool._False
@raw_binary_op
def logical_or(self, v1, v2):
- return self._cbool(v1) or self._cbool(v2)
+ if self._cbool(v1) or self._cbool(v2):
+ return Bool._True
+ return Bool._False
@raw_unary_op
def logical_not(self, v):
@@ -1352,12 +1381,30 @@
@complex_binary_op
def floordiv(self, v1, v2):
- try:
- ab = v1[0]*v2[0] + v1[1]*v2[1]
- bb = v2[0]*v2[0] + v2[1]*v2[1]
- return math.floor(ab/bb), 0.
- except ZeroDivisionError:
- return rfloat.NAN, 0.
+ (r1, i1), (r2, i2) = v1, v2
+ if r2 < 0:
+ abs_r2 = -r2
+ else:
+ abs_r2 = r2
+ if i2 < 0:
+ abs_i2 = -i2
+ else:
+ abs_i2 = i2
+ if abs_r2 >= abs_i2:
+ if abs_r2 == 0.0:
+ return rfloat.NAN, 0.
+ else:
+ ratio = i2 / r2
+ denom = r2 + i2 * ratio
+ rr = (r1 + i1 * ratio) / denom
+ elif rfloat.isnan(r2):
+ rr = rfloat.NAN
+ else:
+ ratio = r2 / i2
+ denom = r2 * ratio + i2
+ assert i2 != 0.0
+ rr = (r1 * ratio + i1) / denom
+ return math.floor(rr), 0.
#complex mod does not exist in numpy
#@simple_binary_op
@@ -1394,15 +1441,17 @@
sign of complex number could be either the point closest to the unit circle
or {-1,0,1}, for compatability with numpy we choose the latter
'''
+ if rfloat.isnan(v[0]) or rfloat.isnan(v[1]):
+ return rfloat.NAN, 0
if v[0] == 0.0:
if v[1] == 0:
- return 0,0
+ return 0, 0
if v[1] > 0:
- return 1,0
- return -1,0
+ return 1, 0
+ return -1, 0
if v[0] > 0:
- return 1,0
- return -1,0
+ return 1, 0
+ return -1, 0
def fmax(self, v1, v2):
if self.ge(v1, v2) or self.isnan(v2):
@@ -1856,14 +1905,14 @@
@raw_binary_op
def logical_and(self, v1, v2):
if self._obool(v1):
- return self.space.bool_w(v2)
- return self.space.bool_w(v1)
+ return self.box(v2)
+ return self.box(v1)
@raw_binary_op
def logical_or(self, v1, v2):
if self._obool(v1):
- return self.space.bool_w(v1)
- return self.space.bool_w(v2)
+ return self.box(v1)
+ return self.box(v2)
@raw_unary_op
def logical_not(self, v):
@@ -2110,11 +2159,15 @@
@str_binary_op
def logical_and(self, v1, v2):
- return bool(v1) and bool(v2)
+ if bool(v1) and bool(v2):
+ return Bool._True
+ return Bool._False
@str_binary_op
def logical_or(self, v1, v2):
- return bool(v1) or bool(v2)
+ if bool(v1) or bool(v2):
+ return Bool._True
+ return Bool._False
@str_unary_op
def logical_not(self, v):
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
@@ -13,7 +13,8 @@
from pypy.module.micronumpy.ctors import numpify
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, product, get_storage_as_int
+from pypy.module.micronumpy.support import (_parse_signature, product,
+ get_storage_as_int, is_rhs_priority_higher)
from rpython.rlib.rawstorage import (raw_storage_setitem, free_raw_storage,
alloc_raw_storage)
from rpython.rtyper.lltypesystem import rffi, lltype
@@ -36,6 +37,21 @@
assert isinstance(w_npyobj, W_NDimArray)
return w_npyobj.get_dtype()
+def _find_array_wrap(*args, **kwds):
+ '''determine an appropriate __array_wrap__ function to call for the outputs.
+ If an output argument is provided, then it is wrapped
+ with its own __array_wrap__ not with the one determined by
+ the input arguments.
+
+ if the provided output argument is already an array,
+ the wrapping function is None (which means no wrapping will
+ be done --- not even PyArray_Return).
+
+ A NULL is placed in output_wrap for outputs that
+ should just have PyArray_Return called.
+ '''
+ raise NotImplementedError()
+
class W_Ufunc(W_Root):
_immutable_fields_ = [
@@ -209,7 +225,7 @@
axis += shapelen
assert axis >= 0
dtype = decode_w_dtype(space, dtype)
- if self.comparison_func:
+ if self.bool_result:
dtype = get_dtype_cache(space).w_booldtype
elif dtype is None:
dtype = find_unaryop_result_dtype(
@@ -225,6 +241,7 @@
raise oefmt(space.w_ValueError,
"zero-size array to reduction operation %s "
"which has no identity", self.name)
+ call__array_wrap__ = True
if shapelen > 1 and axis < shapelen:
temp = None
if cumulative:
@@ -257,6 +274,7 @@
",".join([str(x) for x in shape]),
",".join([str(x) for x in out.get_shape()]),
)
+ call__array_wrap__ = False
dtype = out.get_dtype()
else:
out = W_NDimArray.from_shape(space, shape, dtype,
@@ -265,11 +283,15 @@
if self.identity is not None:
out.fill(space, self.identity.convert_to(space, dtype))
return out
- return loop.do_axis_reduce(space, shape, self.func, obj, dtype,
+ loop.do_axis_reduce(space, shape, self.func, obj, dtype,
axis, out, self.identity, cumulative,
temp)
+ if call__array_wrap__:
+ out = space.call_method(obj, '__array_wrap__', out)
+ return out
if cumulative:
if out:
+ call__array_wrap__ = False
if out.get_shape() != [obj.get_size()]:
raise OperationError(space.w_ValueError, space.wrap(
"out of incompatible size"))
@@ -278,8 +300,11 @@
w_instance=obj)
loop.compute_reduce_cumulative(space, obj, out, dtype, self.func,
self.identity)
+ if call__array_wrap__:
+ out = space.call_method(obj, '__array_wrap__', out)
return out
if out:
+ call__array_wrap__ = False
if out.ndims() > 0:
raise oefmt(space.w_ValueError,
"output parameter for reduction operation %s has "
@@ -292,10 +317,16 @@
return out
if keepdims:
shape = [1] * len(obj_shape)
- out = W_NDimArray.from_shape(space, [1] * len(obj_shape), dtype,
- w_instance=obj)
+ out = W_NDimArray.from_shape(space, shape, dtype, w_instance=obj)
out.implementation.setitem(0, res)
- return out
+ res = out
+ elif not space.is_w(space.type(w_obj), space.gettypefor(W_NDimArray)):
+ # subtypes return a ndarray subtype, not a scalar
+ out = W_NDimArray.from_shape(space, [1], dtype, w_instance=obj)
+ out.implementation.setitem(0, res)
+ res = out
+ if call__array_wrap__:
+ res = space.call_method(obj, '__array_wrap__', res)
return res
def descr_outer(self, space, __args__):
@@ -322,6 +353,32 @@
extobj_w = space.newlist([space.wrap(8192), space.wrap(0), space.w_None])
return extobj_w
+def _has_reflected_op(space, w_obj, op):
+ refops ={ 'add': 'radd',
+ 'subtract': 'rsub',
+ 'multiply': 'rmul',
+ 'divide': 'rdiv',
+ 'true_divide': 'rtruediv',
+ 'floor_divide': 'rfloordiv',
+ 'remainder': 'rmod',
+ 'power': 'rpow',
+ 'left_shift': 'rlshift',
+ 'right_shift': 'rrshift',
+ 'bitwise_and': 'rand',
+ 'bitwise_xor': 'rxor',
+ 'bitwise_or': 'ror',
+ #/* Comparisons */
+ 'equal': 'eq',
+ 'not_equal': 'ne',
+ 'greater': 'lt',
+ 'less': 'gt',
+ 'greater_equal': 'le',
+ 'less_equal': 'ge',
+ }
+ if op not in refops:
+ return False
+ return space.getattr(w_obj, space.wrap('__' + refops[op] + '__')) is not None
+
class W_Ufunc1(W_Ufunc):
_immutable_fields_ = ["func", "bool_result"]
nin = 1
@@ -390,24 +447,25 @@
assert isinstance(w_obj, W_NDimArray)
shape = shape_agreement(space, w_obj.get_shape(), out,
broadcast_down=False)
+ # XXX call __array_wrap__ if out was not provided
return loop.call1(space, shape, self.func, calc_dtype, res_dtype,
w_obj, out)
class W_Ufunc2(W_Ufunc):
- _immutable_fields_ = ["func", "comparison_func", "done_func"]
+ _immutable_fields_ = ["func", "bool_result", "done_func"]
nin = 2
nout = 1
nargs = 3
signature = None
def __init__(self, func, name, promote_to_largest=False, promote_to_float=False,
- promote_bools=False, identity=None, comparison_func=False, int_only=False,
+ promote_bools=False, identity=None, bool_result=False, int_only=False,
allow_bool=True, allow_complex=True, complex_to_float=False):
W_Ufunc.__init__(self, name, promote_to_largest, promote_to_float, promote_bools,
identity, int_only, allow_bool, allow_complex, complex_to_float)
self.func = func
- self.comparison_func = comparison_func
+ self.bool_result = bool_result
if name == 'logical_and':
self.done_func = done_if_false
elif name == 'logical_or':
@@ -432,6 +490,15 @@
else:
[w_lhs, w_rhs] = args_w
w_out = None
+ if not isinstance(w_rhs, W_NDimArray):
+ # numpy implementation detail, useful for things like numpy.Polynomial
+ # FAIL with NotImplemented if the other object has
+ # the __r<op>__ method and has __array_priority__ as
+ # an attribute (signalling it can handle ndarray's)
+ # and is not already an ndarray or a subtype of the same type.
+ r_greater = is_rhs_priority_higher(space, w_lhs, w_rhs)
+ if r_greater and _has_reflected_op(space, w_rhs, self.name):
+ return space.w_NotImplemented
w_lhs = numpify(space, w_lhs)
w_rhs = numpify(space, w_rhs)
w_ldtype = _get_dtype(space, w_lhs)
@@ -439,20 +506,20 @@
if w_ldtype.is_object() or w_rdtype.is_object():
pass
elif w_ldtype.is_str() and w_rdtype.is_str() and \
- self.comparison_func:
+ self.bool_result:
pass
elif (w_ldtype.is_str()) and \
- self.comparison_func and w_out is None:
+ self.bool_result and w_out is None:
if self.name in ('equal', 'less_equal', 'less'):
return space.wrap(False)
return space.wrap(True)
elif (w_rdtype.is_str()) and \
- self.comparison_func and w_out is None:
+ self.bool_result and w_out is None:
if self.name in ('not_equal','less', 'less_equal'):
return space.wrap(True)
return space.wrap(False)
elif w_ldtype.is_flexible() or w_rdtype.is_flexible():
- if self.comparison_func:
+ if self.bool_result:
if self.name == 'equal' or self.name == 'not_equal':
res = w_ldtype.eq(space, w_rdtype)
if not res:
@@ -490,7 +557,7 @@
else:
out = w_out
calc_dtype = out.get_dtype()
- if self.comparison_func:
+ if self.bool_result:
res_dtype = get_dtype_cache(space).w_booldtype
else:
res_dtype = calc_dtype
@@ -613,6 +680,7 @@
assert isinstance(outargs0, W_NDimArray)
res_dtype = outargs0.get_dtype()
new_shape = inargs0.get_shape()
+ # XXX use _find_array_wrap and wrap outargs using __array_wrap__
if len(outargs) < 2:
return loop.call_many_to_one(space, new_shape, func,
res_dtype, inargs, outargs[0])
@@ -705,6 +773,7 @@
for i in range(self.nout):
w_val = space.getitem(outs, space.wrap(i))
outiters[i].descr_setitem(space, space.w_Ellipsis, w_val)
+ # XXX use _find_array_wrap and wrap outargs using __array_wrap__
if len(outargs) > 1:
return space.newtuple([convert_to_array(space, o) for o in outargs])
return outargs[0]
@@ -1121,8 +1190,7 @@
# 'supported', w_obj)
-def ufunc_dtype_caller(space, ufunc_name, op_name, nin, comparison_func,
- bool_result):
+def ufunc_dtype_caller(space, ufunc_name, op_name, nin, bool_result):
def get_op(dtype):
try:
return getattr(dtype.itemtype, op_name)
@@ -1140,7 +1208,7 @@
elif nin == 2:
def impl(res_dtype, lvalue, rvalue):
res = get_op(res_dtype)(lvalue, rvalue)
- if comparison_func:
+ if bool_result:
return dtype_cache.w_booldtype.box(res)
return res
return func_with_new_name(impl, ufunc_name)
@@ -1167,21 +1235,19 @@
("left_shift", "lshift", 2, {"int_only": True}),
("right_shift", "rshift", 2, {"int_only": True}),
- ("equal", "eq", 2, {"comparison_func": True}),
- ("not_equal", "ne", 2, {"comparison_func": True}),
- ("less", "lt", 2, {"comparison_func": True}),
- ("less_equal", "le", 2, {"comparison_func": True}),
- ("greater", "gt", 2, {"comparison_func": True}),
- ("greater_equal", "ge", 2, {"comparison_func": True}),
+ ("equal", "eq", 2, {"bool_result": True}),
+ ("not_equal", "ne", 2, {"bool_result": True}),
+ ("less", "lt", 2, {"bool_result": True}),
+ ("less_equal", "le", 2, {"bool_result": True}),
+ ("greater", "gt", 2, {"bool_result": True}),
+ ("greater_equal", "ge", 2, {"bool_result": True}),
("isnan", "isnan", 1, {"bool_result": True}),
("isinf", "isinf", 1, {"bool_result": True}),
("isfinite", "isfinite", 1, {"bool_result": True}),
- ('logical_and', 'logical_and', 2, {'comparison_func': True,
- 'identity': 1}),
- ('logical_or', 'logical_or', 2, {'comparison_func': True,
- 'identity': 0}),
- ('logical_xor', 'logical_xor', 2, {'comparison_func': True}),
+ ('logical_and', 'logical_and', 2, {'identity': 1}),
+ ('logical_or', 'logical_or', 2, {'identity': 0}),
+ ('logical_xor', 'logical_xor', 2, {'bool_result': True}),
('logical_not', 'logical_not', 1, {'bool_result': True}),
("maximum", "max", 2),
@@ -1263,7 +1329,6 @@
extra_kwargs["identity"] = identity
func = ufunc_dtype_caller(space, ufunc_name, op_name, nin,
- comparison_func=extra_kwargs.get("comparison_func", False),
bool_result=extra_kwargs.get("bool_result", False),
)
if nin == 1:
diff --git a/pypy/module/pypyjit/test_pypy_c/test_micronumpy.py b/pypy/module/pypyjit/test_pypy_c/test_micronumpy.py
--- a/pypy/module/pypyjit/test_pypy_c/test_micronumpy.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_micronumpy.py
@@ -67,11 +67,10 @@
assert loop.match("""
f31 = raw_load(i9, i29, descr=<ArrayF 8>)
guard_not_invalidated(descr=...)
- i32 = cast_float_to_int(f31)
- i33 = int_and(i32, 255)
- guard_true(i33, descr=...)
i34 = getarrayitem_raw(#, #, descr=<ArrayU 1>) # XXX what are these?
guard_value(i34, #, descr=...) # XXX don't appear in
+ i32 = float_ne(f31, 0.000000)
+ guard_true(i32, descr=...)
i35 = getarrayitem_raw(#, #, descr=<ArrayU 1>) # XXX equiv test_zjit
i36 = int_add(i24, 1)
i37 = int_add(i29, i28)
@@ -152,7 +151,7 @@
f86 = float_add(f74, f85)
i87 = int_add(i76, 1)
--TICK--
- jump(p0, p1, p3, p6, p7, p12, p14, f86, p18, i87, i62, p41, i58, p47, i40, i64, i70, descr=...)
+ jump(p0, p1, p6, p7, p8, p11, p13, f86, p17, i87, i62, p42, i58, p48, i41, i64, i70, descr=...)
""")
def test_array_flatiter_next(self):
More information about the pypy-commit
mailing list