Author: mattip <matti.pi...@gmail.com> Branch: Changeset: r80082:26b886602ace Date: 2015-10-09 14:51 +0300 http://bitbucket.org/pypy/pypy/changeset/26b886602ace/
Log: merge fortran-order into default 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 @@ -60,3 +60,7 @@ .. branch: callfamily Refactorings of annotation and rtyping of function calls. + +.. branch: fortran-order + +Allow creation of fortran-ordered ndarrays diff --git a/pypy/module/cpyext/ndarrayobject.py b/pypy/module/cpyext/ndarrayobject.py --- a/pypy/module/cpyext/ndarrayobject.py +++ b/pypy/module/cpyext/ndarrayobject.py @@ -12,6 +12,7 @@ from pypy.module.micronumpy.descriptor import get_dtype_cache, W_Dtype from pypy.module.micronumpy.concrete import ConcreteArray from pypy.module.micronumpy import ufuncs +import pypy.module.micronumpy.constants as NPY from rpython.rlib.rawstorage import RAW_STORAGE_PTR from pypy.interpreter.typedef import TypeDef from pypy.interpreter.baseobjspace import W_Root @@ -203,12 +204,12 @@ return shape, dtype def simple_new(space, nd, dims, typenum, - order='C', owning=False, w_subtype=None): + order=NPY.CORDER, owning=False, w_subtype=None): shape, dtype = get_shape_and_dtype(space, nd, dims, typenum) return W_NDimArray.from_shape(space, shape, dtype) def simple_new_from_data(space, nd, dims, typenum, data, - order='C', owning=False, w_subtype=None): + order=NPY.CORDER, owning=False, w_subtype=None): shape, dtype = get_shape_and_dtype(space, nd, dims, typenum) storage = rffi.cast(RAW_STORAGE_PTR, data) return W_NDimArray.from_shape_and_storage(space, shape, storage, dtype, @@ -238,7 +239,7 @@ raise OperationError(space.w_NotImplementedError, space.wrap("strides must be NULL")) - order = 'C' if flags & NPY_C_CONTIGUOUS else 'F' + order = NPY.CORDER if flags & NPY_C_CONTIGUOUS else NPY.FORTRANORDER owning = True if flags & NPY_OWNDATA else False w_subtype = None diff --git a/pypy/module/cpyext/test/test_ndarrayobject.py b/pypy/module/cpyext/test/test_ndarrayobject.py --- a/pypy/module/cpyext/test/test_ndarrayobject.py +++ b/pypy/module/cpyext/test/test_ndarrayobject.py @@ -4,16 +4,17 @@ from rpython.rtyper.lltypesystem import rffi, lltype from pypy.module.micronumpy.ndarray import W_NDimArray from pypy.module.micronumpy.descriptor import get_dtype_cache +import pypy.module.micronumpy.constants as NPY def scalar(space): dtype = get_dtype_cache(space).w_float64dtype return W_NDimArray.new_scalar(space, dtype, space.wrap(10.)) -def array(space, shape, order='C'): +def array(space, shape, order=NPY.CORDER): dtype = get_dtype_cache(space).w_float64dtype return W_NDimArray.from_shape(space, shape, dtype, order=order) -def iarray(space, shape, order='C'): +def iarray(space, shape, order=NPY.CORDER): dtype = get_dtype_cache(space).w_int64dtype return W_NDimArray.from_shape(space, shape, dtype, order=order) @@ -32,8 +33,8 @@ def test_FLAGS(self, space, api): s = array(space, [10]) - c = array(space, [10, 5, 3], order='C') - f = array(space, [10, 5, 3], order='F') + c = array(space, [10, 5, 3], order=NPY.CORDER) + f = array(space, [10, 5, 3], order=NPY.FORTRANORDER) assert api._PyArray_FLAGS(s) & 0x0001 assert api._PyArray_FLAGS(s) & 0x0002 assert api._PyArray_FLAGS(c) & 0x0001 diff --git a/pypy/module/micronumpy/arrayops.py b/pypy/module/micronumpy/arrayops.py --- a/pypy/module/micronumpy/arrayops.py +++ b/pypy/module/micronumpy/arrayops.py @@ -108,7 +108,8 @@ w_axis = space.wrap(0) if space.is_none(w_axis): args_w = [w_arg.reshape(space, - space.newlist([w_arg.descr_get_size(space)])) + space.newlist([w_arg.descr_get_size(space)]), + w_arg.get_order()) for w_arg in args_w] w_axis = space.wrap(0) dtype = args_w[0].get_dtype() @@ -140,7 +141,7 @@ dtype = find_result_type(space, args_w, []) # concatenate does not handle ndarray subtypes, it always returns a ndarray - res = W_NDimArray.from_shape(space, shape, dtype, 'C') + res = W_NDimArray.from_shape(space, shape, dtype, NPY.CORDER) chunks = [Chunk(0, i, 1, i) for i in shape] axis_start = 0 for arr in args_w: diff --git a/pypy/module/micronumpy/base.py b/pypy/module/micronumpy/base.py --- a/pypy/module/micronumpy/base.py +++ b/pypy/module/micronumpy/base.py @@ -38,7 +38,8 @@ self.implementation = implementation @staticmethod - def from_shape(space, shape, dtype, order='C', w_instance=None, zero=True): + def from_shape(space, shape, dtype, order=NPY.CORDER, + w_instance=None, zero=True): from pypy.module.micronumpy import concrete, descriptor, boxes from pypy.module.micronumpy.strides import calc_strides if len(shape) > NPY.MAXDIMS: @@ -59,8 +60,9 @@ @staticmethod def from_shape_and_storage(space, shape, storage, dtype, storage_bytes=-1, - order='C', owning=False, w_subtype=None, - w_base=None, writable=True, strides=None, start=0): + order=NPY.CORDER, owning=False, w_subtype=None, + w_base=None, writable=True, strides=None, + start=0): from pypy.module.micronumpy import concrete from pypy.module.micronumpy.strides import (calc_strides, calc_backstrides) 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 @@ -56,6 +56,9 @@ jit.hint(len(backstrides), promote=True) return backstrides + def get_flags(self): + return self.flags + def getitem(self, index): return self.dtype.read(self, index, 0) @@ -89,17 +92,18 @@ def get_storage_size(self): return self.size - def reshape(self, orig_array, new_shape): + def reshape(self, orig_array, new_shape, order=NPY.ANYORDER): # Since we got to here, prod(new_shape) == self.size + order = support.get_order_as_CF(self.order, order) new_strides = None if self.size == 0: - new_strides, _ = calc_strides(new_shape, self.dtype, self.order) + new_strides, _ = calc_strides(new_shape, self.dtype, order) else: if len(self.get_shape()) == 0: new_strides = [self.dtype.elsize] * len(new_shape) else: new_strides = calc_new_strides(new_shape, self.get_shape(), - self.get_strides(), self.order) + self.get_strides(), order) if new_strides is None or len(new_strides) != len(new_shape): return None if new_strides is not None: @@ -303,10 +307,11 @@ return SliceArray(self.start, strides, backstrides, shape, self, orig_array) - def copy(self, space): + def copy(self, space, order=NPY.ANYORDER): + order = support.get_order_as_CF(self.order, order) strides, backstrides = calc_strides(self.get_shape(), self.dtype, - self.order) - impl = ConcreteArray(self.get_shape(), self.dtype, self.order, strides, + order) + impl = ConcreteArray(self.get_shape(), self.dtype, order, strides, backstrides) return loop.setslice(space, self.get_shape(), impl, self) @@ -360,12 +365,12 @@ # but make the array storage contiguous in memory shape = self.get_shape() strides = self.get_strides() - if order not in ('C', 'F'): - raise oefmt(space.w_ValueError, "Unknown order %s in astype", order) + if order not in (NPY.KEEPORDER, NPY.FORTRANORDER, NPY.CORDER): + raise oefmt(space.w_ValueError, "Unknown order %d in astype", order) if len(strides) == 0: t_strides = [] backstrides = [] - elif order != self.order: + elif order in (NPY.FORTRANORDER, NPY.CORDER): t_strides, backstrides = calc_strides(shape, dtype, order) else: indx_array = range(len(strides)) @@ -378,6 +383,7 @@ t_strides[i] = base base *= shape[i] backstrides = calc_backstrides(t_strides, shape) + order = support.get_order_as_CF(self.order, order) impl = ConcreteArray(shape, dtype, order, t_strides, backstrides) loop.setslice(space, impl.get_shape(), impl, self) return impl @@ -429,6 +435,8 @@ self.shape = shape # already tested for overflow in from_shape_and_storage self.size = support.product(shape) * dtype.elsize + if order not in (NPY.CORDER, NPY.FORTRANORDER): + raise oefmt(dtype.itemtype.space.w_ValueError, "ConcreteArrayNotOwning but order is not 0,1 rather %d", order) self.order = order self.dtype = dtype self.strides = strides @@ -562,6 +570,8 @@ self.parent = parent self.storage = parent.storage self.gcstruct = parent.gcstruct + if parent.order not in (NPY.CORDER, NPY.FORTRANORDER): + raise oefmt(dtype.itemtype.space.w_ValueError, "SliceArray but parent order is not 0,1 rather %d", parent.order) self.order = parent.order self.dtype = dtype try: @@ -602,13 +612,13 @@ s = self.get_strides()[0] // dtype.elsize except IndexError: s = 1 - if self.order == 'C': + if self.order != NPY.FORTRANORDER: new_shape.reverse() for sh in new_shape: strides.append(s * dtype.elsize) backstrides.append(s * (sh - 1) * dtype.elsize) s *= max(1, sh) - if self.order == 'C': + if self.order != NPY.FORTRANORDER: strides.reverse() backstrides.reverse() new_shape.reverse() diff --git a/pypy/module/micronumpy/converters.py b/pypy/module/micronumpy/converters.py --- a/pypy/module/micronumpy/converters.py +++ b/pypy/module/micronumpy/converters.py @@ -77,9 +77,8 @@ elif order.startswith('K') or order.startswith('k'): return NPY.KEEPORDER else: - raise OperationError(space.w_TypeError, space.wrap( - "order not understood")) - + raise oefmt(space.w_TypeError, "Unknown order: '%s'", order) + return -1 def multi_axis_converter(space, w_axis, ndim): if space.is_none(w_axis): 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 @@ -5,10 +5,10 @@ from rpython.rtyper.lltypesystem import lltype, rffi from pypy.module.micronumpy import descriptor, loop, support -from pypy.module.micronumpy.base import ( +from pypy.module.micronumpy.base import (wrap_impl, W_NDimArray, convert_to_array, W_NumpyObject) -from pypy.module.micronumpy.converters import shape_converter -from . import constants as NPY +from pypy.module.micronumpy.converters import shape_converter, order_converter +import pypy.module.micronumpy.constants as NPY from .casting import scalar2dtype @@ -101,13 +101,8 @@ dtype = descriptor.decode_w_dtype(space, w_dtype) if space.is_none(w_order): - order = 'C' - else: - order = space.str_w(w_order) - if order == 'K': - order = 'C' - if order != 'C': # or order != 'F': - raise oefmt(space.w_ValueError, "Unknown order: %s", order) + w_order = space.wrap('C') + npy_order = order_converter(space, w_order, NPY.CORDER) if isinstance(w_object, W_NDimArray): if (dtype is None or w_object.get_dtype() is dtype): @@ -126,7 +121,7 @@ copy = True if copy: shape = w_object.get_shape() - w_arr = W_NDimArray.from_shape(space, shape, dtype, order=order) + w_arr = W_NDimArray.from_shape(space, shape, dtype, order=npy_order) if support.product(shape) == 1: w_arr.set_scalar_value(dtype.coerce(space, w_object.implementation.getitem(0))) @@ -151,7 +146,7 @@ if dtype is None or (dtype.is_str_or_unicode() and dtype.elsize < 1): dtype = find_dtype_for_seq(space, elems_w, dtype) - w_arr = W_NDimArray.from_shape(space, shape, dtype, order=order) + w_arr = W_NDimArray.from_shape(space, shape, dtype, order=npy_order) if support.product(shape) == 1: # safe from overflow since from_shape checks w_arr.set_scalar_value(dtype.coerce(space, elems_w[0])) else: @@ -268,6 +263,7 @@ def _zeros_or_empty(space, w_shape, w_dtype, w_order, zero): + order = order_converter(space, w_order, NPY.CORDER) dtype = space.interp_w(descriptor.W_Dtype, space.call_function(space.gettypefor(descriptor.W_Dtype), w_dtype)) if dtype.is_str_or_unicode() and dtype.elsize < 1: @@ -281,7 +277,7 @@ support.product_check(shape) except OverflowError: raise oefmt(space.w_ValueError, "array is too big.") - return W_NDimArray.from_shape(space, shape, dtype=dtype, zero=zero) + return W_NDimArray.from_shape(space, shape, dtype, order, zero=zero) def empty(space, w_shape, w_dtype=None, w_order=None): return _zeros_or_empty(space, w_shape, w_dtype, w_order, zero=False) @@ -293,6 +289,7 @@ @unwrap_spec(subok=bool) def empty_like(space, w_a, w_dtype=None, w_order=None, subok=True): w_a = convert_to_array(space, w_a) + npy_order = order_converter(space, w_order, w_a.get_order()) if space.is_none(w_dtype): dtype = w_a.get_dtype() else: @@ -300,7 +297,16 @@ space.call_function(space.gettypefor(descriptor.W_Dtype), w_dtype)) if dtype.is_str_or_unicode() and dtype.elsize < 1: dtype = descriptor.variable_dtype(space, dtype.char + '1') + if npy_order in (NPY.KEEPORDER, NPY.ANYORDER): + # Try to copy the stride pattern + impl = w_a.implementation.astype(space, dtype, NPY.KEEPORDER) + if subok: + w_type = space.type(w_a) + else: + w_type = None + return wrap_impl(space, w_type, w_a, impl) return W_NDimArray.from_shape(space, w_a.get_shape(), dtype=dtype, + order=npy_order, w_instance=w_a if subok else None, zero=False) 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 @@ -680,7 +680,7 @@ def tostring(space, arr): builder = StringBuilder() iter, state = arr.create_iter() - w_res_str = W_NDimArray.from_shape(space, [1], arr.get_dtype(), order='C') + w_res_str = W_NDimArray.from_shape(space, [1], arr.get_dtype()) itemsize = arr.get_dtype().elsize with w_res_str.implementation as storage: res_str_casted = rffi.cast(rffi.CArrayPtr(lltype.Char), 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 @@ -97,11 +97,15 @@ self.fill(space, self.get_dtype().coerce(space, w_value)) def descr_tostring(self, space, w_order=None): - order = order_converter(space, w_order, NPY.CORDER) - if order == NPY.FORTRANORDER: - raise OperationError(space.w_NotImplementedError, space.wrap( - "unsupported value for order")) - return space.wrap(loop.tostring(space, self)) + try: + order = order_converter(space, w_order, NPY.CORDER) + except: + raise oefmt(space.w_TypeError, "order not understood") + order = support.get_order_as_CF(self.get_order(), order) + arr = self + if order != arr.get_order(): + arr = W_NDimArray(self.implementation.transpose(self, None)) + return space.wrap(loop.tostring(space, arr)) def getitem_filter(self, space, arr): if arr.ndims() > 1 and arr.get_shape() != self.get_shape(): @@ -365,11 +369,13 @@ return self.implementation.getitem(self.implementation.start) def descr_copy(self, space, w_order=None): - order = order_converter(space, w_order, NPY.KEEPORDER) - if order == NPY.FORTRANORDER: - raise OperationError(space.w_NotImplementedError, space.wrap( - "unsupported value for order")) - copy = self.implementation.copy(space) + if w_order is None: + order = NPY.KEEPORDER + elif space.isinstance_w(w_order, space.w_int): + order = space.int_w(w_order) + else: + order = order_converter(space, w_order, NPY.KEEPORDER) + copy = self.implementation.copy(space, order) w_subtype = space.type(self) return wrap_impl(space, w_subtype, self, copy) @@ -392,15 +398,15 @@ 'array does not have imaginary part to set') self.implementation.set_imag(space, self, w_value) - def reshape(self, space, w_shape): + def reshape(self, space, w_shape, order): new_shape = get_shape_from_iterable(space, self.get_size(), w_shape) - new_impl = self.implementation.reshape(self, new_shape) + new_impl = self.implementation.reshape(self, new_shape, order) if new_impl is not None: return wrap_impl(space, space.type(self), self, new_impl) # Create copy with contiguous data - arr = self.descr_copy(space) + arr = self.descr_copy(space, space.wrap(order)) if arr.get_size() > 0: - new_implementation = arr.implementation.reshape(self, new_shape) + new_implementation = arr.implementation.reshape(self, new_shape, order) if new_implementation is None: raise oefmt(space.w_ValueError, 'could not reshape array of size %d to shape %s', @@ -434,16 +440,13 @@ if order == NPY.KEEPORDER: raise OperationError(space.w_ValueError, space.wrap( "order 'K' is not permitted for reshaping")) - if order != NPY.CORDER and order != NPY.ANYORDER: - raise OperationError(space.w_NotImplementedError, space.wrap( - "unsupported value for order")) if len(args_w) == 1: if space.is_none(args_w[0]): return self.descr_view(space) w_shape = args_w[0] else: w_shape = space.newtuple(args_w) - return self.reshape(space, w_shape) + return self.reshape(space, w_shape, order) def descr_get_transpose(self, space, axes=None): return W_NDimArray(self.implementation.transpose(self, axes)) @@ -514,20 +517,8 @@ return space.newlist(l_w) def descr_ravel(self, space, w_order=None): - if space.is_none(w_order): - order = 'C' - else: - order = space.str_w(w_order) - if order == 'K' and is_c_contiguous(self.implementation): - for s in self.implementation.get_strides(): - if s < 0: - break - else: - order = 'C' - if order != 'C': - raise OperationError(space.w_NotImplementedError, space.wrap( - "order != 'C' only partially implemented")) - return self.reshape(space, space.wrap(-1)) + order = order_converter(space, w_order, self.get_order()) + return self.reshape(space, space.wrap(-1), order) @unwrap_spec(w_axis=WrappedDefault(None), w_out=WrappedDefault(None), @@ -541,14 +532,15 @@ space.wrap("axis unsupported for compress")) arr = self else: - arr = self.reshape(space, space.wrap(-1)) + arr = self.reshape(space, space.wrap(-1), self.get_order()) index = convert_to_array(space, w_obj) return arr.getitem_filter(space, index) def descr_flatten(self, space, w_order=None): + order = order_converter(space, w_order, self.get_order()) if self.is_scalar(): # scalars have no storage - return self.reshape(space, space.wrap(1)) + return self.reshape(space, space.wrap(1), order) w_res = self.descr_ravel(space, w_order) if w_res.implementation.storage == self.implementation.storage: return w_res.descr_copy(space) @@ -631,7 +623,7 @@ space.newtuple([space.wrap(addr), space.w_False])) space.setitem_str(w_d, 'shape', self.descr_get_shape(space)) space.setitem_str(w_d, 'typestr', self.get_dtype().descr_get_str(space)) - if self.implementation.order == 'C': + if self.implementation.order == NPY.CORDER: # Array is contiguous, no strides in the interface. strides = space.w_None else: @@ -690,8 +682,9 @@ "according to the rule %s", space.str_w(self.get_dtype().descr_repr(space)), space.str_w(new_dtype.descr_repr(space)), casting) - order = support.get_order_as_CF(self.get_order(), order) - if (not copy and new_dtype == self.get_dtype() and order == self.get_order() + order = order_converter(space, space.wrap(order), self.get_order()) + if (not copy and new_dtype == self.get_dtype() + and (order in (NPY.KEEPORDER, NPY.ANYORDER) or order == self.get_order()) and (subok or type(self) is W_NDimArray)): return self impl = self.implementation @@ -972,7 +965,7 @@ raise OperationError(space.w_ValueError, space.wrap( "new type not compatible with array.")) # Adapt the smallest dim to the new itemsize - if self.get_order() == 'F': + if self.get_order() == NPY.FORTRANORDER: minstride = strides[0] mini = 0 else: @@ -1136,7 +1129,7 @@ matches = True if dtype != out.get_dtype(): matches = False - elif not out.implementation.order == "C": + elif not out.implementation.order == NPY.CORDER: matches = False elif out.ndims() != len(out_shape): matches = False @@ -1195,7 +1188,7 @@ out = out_converter(space, w_out) if space.is_none(w_axis): w_axis = space.wrap(0) - arr = self.reshape(space, space.wrap(-1)) + arr = self.reshape(space, space.wrap(-1), self.get_order()) else: arr = self ufunc = getattr(ufuncs.get(space), ufunc_name) @@ -1408,10 +1401,6 @@ strides=strides) order = order_converter(space, w_order, NPY.CORDER) - if order == NPY.CORDER: - order = 'C' - else: - order = 'F' if space.is_w(w_subtype, space.gettypefor(W_NDimArray)): return W_NDimArray.from_shape(space, shape, dtype, order) strides, backstrides = calc_strides(shape, dtype.base, order) @@ -1448,7 +1437,7 @@ raise OperationError(space.w_ValueError, space.wrap( "subtype must be a subtype of ndarray, not a class instance")) return W_NDimArray.from_shape_and_storage(space, shape, storage, dtype, - buf_len, 'C', False, w_subtype, + buf_len, NPY.CORDER, False, w_subtype, strides=strides) else: return W_NDimArray.from_shape_and_storage(space, shape, storage, dtype, 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 @@ -11,6 +11,8 @@ shape_agreement, shape_agreement_multiple) from pypy.module.micronumpy.casting import (find_binop_result_dtype, can_cast_array, can_cast_type) +import pypy.module.micronumpy.constants as NPY +from pypy.module.micronumpy.converters import order_converter def parse_op_arg(space, name, w_op_flags, n, parse_one_arg): @@ -142,14 +144,13 @@ 'Iterator flag EXTERNAL_LOOP cannot be used if an index or ' 'multi-index is being tracked') - -def is_backward(imp, order): - if order == 'K' or (order == 'C' and imp.order == 'C'): +def is_backward(imp_order, order): + if imp_order == order: return False - elif order == 'F' and imp.order == 'C': + if order == NPY.KEEPORDER: + return False + else: return True - else: - raise NotImplementedError('not implemented yet') class OperandIter(ArrayIter): @@ -234,7 +235,7 @@ continue assert isinstance(op_it, ArrayIter) indx = len(op_it.strides) - if it.order == 'F': + if it.order == NPY.FORTRANORDER: indx = len(op_it.array.strides) - indx assert indx >=0 astrides = op_it.array.strides[indx:] @@ -250,7 +251,7 @@ it.order) it.iters[i] = (new_iter, new_iter.reset()) if len(it.shape) > 1: - if it.order == 'F': + if it.order == NPY.FORTRANORDER: it.shape = it.shape[1:] else: it.shape = it.shape[:-1] @@ -261,10 +262,10 @@ break # Always coalesce at least one for i in range(len(it.iters)): - new_iter = coalesce_iter(it.iters[i][0], it.op_flags[i], it, 'C') + new_iter = coalesce_iter(it.iters[i][0], it.op_flags[i], it, NPY.CORDER) it.iters[i] = (new_iter, new_iter.reset()) if len(it.shape) > 1: - if it.order == 'F': + if it.order == NPY.FORTRANORDER: it.shape = it.shape[1:] else: it.shape = it.shape[:-1] @@ -287,7 +288,7 @@ return old_iter strides = old_iter.strides backstrides = old_iter.backstrides - if order == 'F': + if order == NPY.FORTRANORDER: new_shape = shape[1:] new_strides = strides[1:] new_backstrides = backstrides[1:] @@ -346,8 +347,8 @@ class W_NDIter(W_NumpyObject): _immutable_fields_ = ['ndim', ] def __init__(self, space, w_seq, w_flags, w_op_flags, w_op_dtypes, - w_casting, w_op_axes, w_itershape, buffersize=0, order='K'): - self.order = order + w_casting, w_op_axes, w_itershape, buffersize=0, + order=NPY.KEEPORDER): self.external_loop = False self.buffered = False self.tracked_index = '' @@ -375,7 +376,25 @@ for w_elem in w_seq_as_list] else: self.seq = [convert_to_array(space, w_seq)] - + if order == NPY.ANYORDER: + # 'A' means "'F' order if all the arrays are Fortran contiguous, + # 'C' order otherwise" + order = NPY.CORDER + for s in self.seq: + if s and not(s.get_flags() & NPY.ARRAY_F_CONTIGUOUS): + break + else: + order = NPY.FORTRANORDER + elif order == NPY.KEEPORDER: + # 'K' means "as close to the order the array elements appear in + # memory as possible", so match self.order to seq.order + order = NPY.CORDER + for s in self.seq: + if s and not(s.get_order() == NPY.FORTRANORDER): + break + else: + order = NPY.FORTRANORDER + self.order = order parse_func_flags(space, self, w_flags) self.op_flags = parse_op_arg(space, 'op_flags', w_op_flags, len(self.seq), parse_op_flag) @@ -439,12 +458,15 @@ str(self.shape)) if self.tracked_index != "": - if self.order == "K": - self.order = self.seq[0].implementation.order + order = self.order + if order == NPY.KEEPORDER: + order = self.seq[0].implementation.order if self.tracked_index == "multi": backward = False else: - backward = self.order != self.tracked_index + backward = (( + order == NPY.CORDER and self.tracked_index != 'C') or ( + order == NPY.FORTRANORDER and self.tracked_index != 'F')) self.index_iter = IndexIterator(self.shape, backward=backward) # handle w_op_dtypes part 2: copy where needed if possible @@ -456,7 +478,6 @@ self.dtypes[i] = seq_d elif self_d != seq_d: impl = self.seq[i].implementation - order = support.get_order_as_CF(impl.order, self.order) if self.buffered or 'r' in self.op_flags[i].tmp_copy: if not can_cast_array( space, self.seq[i], self_d, self.casting): @@ -466,7 +487,7 @@ space.str_w(seq_d.descr_repr(space)), space.str_w(self_d.descr_repr(space)), self.casting) - + order = support.get_order_as_CF(impl.order, self.order) new_impl = impl.astype(space, self_d, order).copy(space) self.seq[i] = W_NDimArray(new_impl) else: @@ -484,7 +505,7 @@ space.str_w(self_d.descr_repr(space)), space.str_w(seq_d.descr_repr(space)), i, self.casting) - elif self.buffered: + elif self.buffered and not (self.external_loop and len(self.seq)<2): for i in range(len(self.seq)): if i not in outargs: self.seq[i] = self.seq[i].descr_copy(space, @@ -506,12 +527,19 @@ def get_iter(self, space, i): arr = self.seq[i] - dtype = self.dtypes[i] - shape = self.shape imp = arr.implementation - backward = is_backward(imp, self.order) if arr.is_scalar(): return ConcreteIter(imp, 1, [], [], [], self.op_flags[i], self) + shape = self.shape + if (self.external_loop and len(self.seq)<2 and self.buffered): + # Special case, always return a memory-ordered iterator + stride = imp.dtype.elsize + backstride = imp.size * stride - stride + return ConcreteIter(imp, imp.get_size(), + [support.product(shape)], [stride], [backstride], + self.op_flags[i], self) + backward = imp.order != self.order + # XXX cleanup needed if (abs(imp.strides[0]) < abs(imp.strides[-1]) and not backward) or \ (abs(imp.strides[0]) > abs(imp.strides[-1]) and backward): # flip the strides. Is this always true for multidimension? @@ -704,13 +732,15 @@ @unwrap_spec(w_flags=WrappedDefault(None), w_op_flags=WrappedDefault(None), - w_op_dtypes=WrappedDefault(None), order=str, + w_op_dtypes=WrappedDefault(None), w_order=WrappedDefault(None), w_casting=WrappedDefault(None), w_op_axes=WrappedDefault(None), - w_itershape=WrappedDefault(None), buffersize=int) + w_itershape=WrappedDefault(None), w_buffersize=WrappedDefault(0)) def descr_new_nditer(space, w_subtype, w_seq, w_flags, w_op_flags, w_op_dtypes, - w_casting, w_op_axes, w_itershape, buffersize=0, order='K'): + w_casting, w_op_axes, w_itershape, w_buffersize, w_order): + npy_order = order_converter(space, w_order, NPY.KEEPORDER) + buffersize = space.int_w(w_buffersize) return W_NDIter(space, w_seq, w_flags, w_op_flags, w_op_dtypes, w_casting, w_op_axes, - w_itershape, buffersize, order) + w_itershape, buffersize, npy_order) W_NDIter.typedef = TypeDef('numpy.nditer', __new__ = interp2app(descr_new_nditer), 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 @@ -310,14 +310,14 @@ backstrides = [] s = 1 shape_rev = shape[:] - if order == 'C': + if order in [NPY.CORDER, NPY.ANYORDER]: shape_rev.reverse() for sh in shape_rev: slimit = max(sh, 1) strides.append(s * dtype.elsize) backstrides.append(s * (slimit - 1) * dtype.elsize) s *= slimit - if order == 'C': + if order in [NPY.CORDER, NPY.ANYORDER]: strides.reverse() backstrides.reverse() return strides, backstrides @@ -345,7 +345,7 @@ last_step = 1 oldI = 0 new_strides = [] - if order == 'F': + if order == NPY.FORTRANORDER: for i in range(len(old_shape)): steps.append(old_strides[i] / last_step) last_step *= old_shape[i] @@ -365,7 +365,7 @@ if oldI < len(old_shape): cur_step = steps[oldI] n_old_elems_to_use *= old_shape[oldI] - elif order == 'C': + else: for i in range(len(old_shape) - 1, -1, -1): steps.insert(0, old_strides[i] / last_step) last_step *= old_shape[i] 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 @@ -7,6 +7,7 @@ from pypy.interpreter.typedef import GetSetProperty from pypy.objspace.std.typeobject import W_TypeObject from pypy.objspace.std.objspace import StdObjSpace +from pypy.module.micronumpy import constants as NPY def issequence_w(space, w_obj): from pypy.module.micronumpy.base import W_NDimArray @@ -176,15 +177,11 @@ return space.is_true(space.gt(w_priority_r, w_priority_l)) def get_order_as_CF(proto_order, req_order): - if req_order == 'C': - return 'C' - elif req_order == 'F': - return 'F' - elif req_order == 'K': - return proto_order - elif req_order == 'A': - return proto_order - + if req_order == NPY.CORDER: + return NPY.CORDER + elif req_order == NPY.FORTRANORDER: + return NPY.FORTRANORDER + return proto_order def descr_set_docstring(space, w_obj, w_docstring): if not isinstance(space, StdObjSpace): 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 @@ -6,6 +6,7 @@ from pypy.module.micronumpy.appbridge import get_appbridge_cache from pypy.module.micronumpy.strides import Chunk, new_view, EllipsisChunk from pypy.module.micronumpy.ndarray import W_NDimArray +import pypy.module.micronumpy.constants as NPY from pypy.module.micronumpy.test.test_base import BaseNumpyAppTest @@ -45,20 +46,20 @@ return self.space.newtuple(args_w) def test_strides_f(self): - a = create_array(self.space, [10, 5, 3], MockDtype(), order='F') + a = create_array(self.space, [10, 5, 3], MockDtype(), order=NPY.FORTRANORDER) assert a.strides == [1, 10, 50] assert a.backstrides == [9, 40, 100] def test_strides_c(self): - a = create_array(self.space, [10, 5, 3], MockDtype(), order='C') + a = create_array(self.space, [10, 5, 3], MockDtype(), order=NPY.CORDER) assert a.strides == [15, 3, 1] assert a.backstrides == [135, 12, 2] - a = create_array(self.space, [1, 0, 7], MockDtype(), order='C') + a = create_array(self.space, [1, 0, 7], MockDtype(), order=NPY.CORDER) assert a.strides == [7, 7, 1] assert a.backstrides == [0, 0, 6] def test_create_slice_f(self): - a = create_array(self.space, [10, 5, 3], MockDtype(), order='F') + a = create_array(self.space, [10, 5, 3], MockDtype(), order=NPY.FORTRANORDER) s = create_slice(self.space, a, [Chunk(3, 0, 0, 1)]) assert s.start == 3 assert s.strides == [10, 50] @@ -77,7 +78,7 @@ assert s.shape == [10, 3] def test_create_slice_c(self): - a = create_array(self.space, [10, 5, 3], MockDtype(), order='C') + a = create_array(self.space, [10, 5, 3], MockDtype(), order=NPY.CORDER) s = create_slice(self.space, a, [Chunk(3, 0, 0, 1)]) assert s.start == 45 assert s.strides == [3, 1] @@ -97,7 +98,7 @@ assert s.shape == [10, 3] def test_slice_of_slice_f(self): - a = create_array(self.space, [10, 5, 3], MockDtype(), order='F') + a = create_array(self.space, [10, 5, 3], MockDtype(), order=NPY.FORTRANORDER) s = create_slice(self.space, a, [Chunk(5, 0, 0, 1)]) assert s.start == 5 s2 = create_slice(self.space, s, [Chunk(3, 0, 0, 1)]) @@ -114,7 +115,7 @@ assert s2.start == 1 * 15 + 2 * 3 def test_slice_of_slice_c(self): - a = create_array(self.space, [10, 5, 3], MockDtype(), order='C') + a = create_array(self.space, [10, 5, 3], MockDtype(), order=NPY.CORDER) s = create_slice(self.space, a, [Chunk(5, 0, 0, 1)]) assert s.start == 15 * 5 s2 = create_slice(self.space, s, [Chunk(3, 0, 0, 1)]) @@ -131,14 +132,14 @@ assert s2.start == 1 * 15 + 2 * 3 def test_negative_step_f(self): - a = create_array(self.space, [10, 5, 3], MockDtype(), order='F') + a = create_array(self.space, [10, 5, 3], MockDtype(), order=NPY.FORTRANORDER) s = create_slice(self.space, a, [Chunk(9, -1, -2, 5)]) assert s.start == 9 assert s.strides == [-2, 10, 50] assert s.backstrides == [-8, 40, 100] def test_negative_step_c(self): - a = create_array(self.space, [10, 5, 3], MockDtype(), order='C') + a = create_array(self.space, [10, 5, 3], MockDtype(), order=NPY.CORDER) s = create_slice(self.space, a, [Chunk(9, -1, -2, 5)]) assert s.start == 135 assert s.strides == [-30, 3, 1] @@ -155,17 +156,17 @@ def test_calc_new_strides(self): from pypy.module.micronumpy.strides import calc_new_strides - assert calc_new_strides([2, 4], [4, 2], [4, 2], "C") == [8, 2] - assert calc_new_strides([2, 4, 3], [8, 3], [1, 16], 'F') == [1, 2, 16] - assert calc_new_strides([2, 3, 4], [8, 3], [1, 16], 'F') is None - assert calc_new_strides([24], [2, 4, 3], [48, 6, 1], 'C') is None - assert calc_new_strides([24], [2, 4, 3], [24, 6, 2], 'C') == [2] - assert calc_new_strides([105, 1], [3, 5, 7], [35, 7, 1],'C') == [1, 1] - assert calc_new_strides([1, 105], [3, 5, 7], [35, 7, 1],'C') == [105, 1] - assert calc_new_strides([1, 105], [3, 5, 7], [35, 7, 1],'F') is None - assert calc_new_strides([1, 1, 1, 105, 1], [15, 7], [7, 1],'C') == \ + assert calc_new_strides([2, 4], [4, 2], [4, 2], NPY.CORDER) == [8, 2] + assert calc_new_strides([2, 4, 3], [8, 3], [1, 16], NPY.FORTRANORDER) == [1, 2, 16] + assert calc_new_strides([2, 3, 4], [8, 3], [1, 16], NPY.FORTRANORDER) is None + assert calc_new_strides([24], [2, 4, 3], [48, 6, 1], NPY.CORDER) is None + assert calc_new_strides([24], [2, 4, 3], [24, 6, 2], NPY.CORDER) == [2] + assert calc_new_strides([105, 1], [3, 5, 7], [35, 7, 1],NPY.CORDER) == [1, 1] + assert calc_new_strides([1, 105], [3, 5, 7], [35, 7, 1],NPY.CORDER) == [105, 1] + assert calc_new_strides([1, 105], [3, 5, 7], [35, 7, 1],NPY.FORTRANORDER) is None + assert calc_new_strides([1, 1, 1, 105, 1], [15, 7], [7, 1],NPY.CORDER) == \ [105, 105, 105, 1, 1] - assert calc_new_strides([1, 1, 105, 1, 1], [7, 15], [1, 7],'F') == \ + assert calc_new_strides([1, 1, 105, 1, 1], [7, 15], [1, 7],NPY.FORTRANORDER) == \ [1, 1, 1, 105, 105] def test_find_shape(self): @@ -444,6 +445,8 @@ b = np.empty_like(A((2, 3)), subok=False) assert b.shape == (2, 3) assert type(b) is np.ndarray + b = np.empty_like(np.array(3.0), order='A') + assert type(b) is np.ndarray def test_size(self): from numpy import array,arange,cos @@ -534,10 +537,10 @@ assert (b == a).all() b = a.copy(order='A') assert (b == a).all() - import sys - if '__pypy__' in sys.builtin_module_names: - raises(NotImplementedError, a.copy, order='F') - raises(NotImplementedError, a.copy, order=True) + b = a.copy(order='F') + assert (b == a).all() + b = a.copy(order=True) + assert (b == a).all() def test_iterator_init(self): from numpy import array @@ -918,9 +921,11 @@ assert a.reshape((0,), order='A').shape == (0,) raises(TypeError, a.reshape, (0,), badarg="C") raises(ValueError, a.reshape, (0,), order="K") - import sys - if '__pypy__' in sys.builtin_module_names: - raises(NotImplementedError, a.reshape, (0,), order='F') + b = a.reshape((0,), order='F') + assert b.shape == (0,) + a = array(range(24), 'uint8') + assert a.reshape([2, 3, 4], order=True).strides ==(1, 2, 6) + assert a.reshape([2, 3, 4], order=False).strides ==(12, 4, 1) def test_slice_reshape(self): from numpy import zeros, arange @@ -2676,11 +2681,11 @@ assert a[1][2][1] == 15 def test_create_order(self): - import sys, numpy as np + import numpy as np for order in [False, True, 'C', 'F']: a = np.empty((2, 3), float, order=order) assert a.shape == (2, 3) - if order in [True, 'F'] and '__pypy__' not in sys.builtin_module_names: + if order in [True, 'F']: assert a.flags['F'] assert not a.flags['C'] else: @@ -3577,10 +3582,7 @@ assert a.tostring(order) == '\x01\x02\x03\x04' import sys for order in (True, 'F'): - if '__pypy__' in sys.builtin_module_names: - raises(NotImplementedError, a.tostring, order) - else: - assert a.tostring(order) == '\x01\x03\x02\x04' + assert a.tostring(order) == '\x01\x03\x02\x04' assert array(2.2-1.1j, dtype='>c16').tostring() == \ '@\x01\x99\x99\x99\x99\x99\x9a\xbf\xf1\x99\x99\x99\x99\x99\x9a' assert array(2.2-1.1j, dtype='<c16').tostring() == \ diff --git a/pypy/module/micronumpy/test/test_nditer.py b/pypy/module/micronumpy/test/test_nditer.py --- a/pypy/module/micronumpy/test/test_nditer.py +++ b/pypy/module/micronumpy/test/test_nditer.py @@ -114,14 +114,11 @@ from numpy import nditer, array a = array([[1, 2], [3, 4]], order="C") - try: - b = array([[1, 2], [3, 4]], order="F") - except (NotImplementedError, ValueError): - skip('Fortran order not implemented') + b = array([[1, 2], [3, 4]], order="F") it = nditer([a, b]) - - assert list(it) == zip(range(1, 5), range(1, 5)) + r = list(it) + assert r == zip(range(1, 5), range(1, 5)) def test_interface(self): from numpy import arange, nditer, zeros @@ -161,11 +158,7 @@ assert r[0][0] == 100 r = [] - try: - it = nditer(a, flags=['buffered'], order='F') - except NotImplementedError as e: - assert 'unsupported value for order' in str(e) - skip('buffered with order="F" requires fortran tmp array creation') + it = nditer(a, flags=['buffered'], order='F') for x in it: r.append(x) array_r = array(r) 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 @@ -668,9 +668,9 @@ for dt_in, dt_out in self.dtypes: if can_cast_to(dtype, dt_in) and dt_out == dt_in: return dt_in - raise ValueError( + raise oefmt(space.w_ValueError, "could not find a matching type for %s.accumulate, " - "requested type has type code '%s'" % (self.name, dtype.char)) + "requested type has type code '%s'", self.name, dtype.char) @jit.unroll_safe _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit