Author: Maciej Fijalkowski <fij...@gmail.com> Branch: Changeset: r67310:d2d8b7ca8251 Date: 2013-10-11 12:01 +0200 http://bitbucket.org/pypy/pypy/changeset/d2d8b7ca8251/
Log: merge diff --git a/lib_pypy/numpypy/__init__.py b/lib_pypy/numpypy/__init__.py --- a/lib_pypy/numpypy/__init__.py +++ b/lib_pypy/numpypy/__init__.py @@ -10,8 +10,35 @@ import os def get_include(): - head, tail = os.path.split(os.path.dirname(os.path.abspath(__file__))) - return os.path.join(head, '../include') + """ + Return the directory that contains the NumPy \\*.h header files. + + Extension modules that need to compile against NumPy should use this + function to locate the appropriate include directory. + + Notes + ----- + When using ``distutils``, for example in ``setup.py``. + :: + + import numpy as np + ... + Extension('extension_name', ... + include_dirs=[np.get_include()]) + ... + + """ + import numpy + if getattr(numpy, 'show_config', None) is None: + # running from numpy source directory + head, tail = os.path.split(os.path.dirname(os.path.abspath(__file__))) + return os.path.join(head, '../include') + else: + # using installed numpy core headers + import numpy.core as core + d = os.path.join(os.path.dirname(core.__file__), 'include') + return d + __all__ = ['__version__', 'get_include'] 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 @@ -52,6 +52,9 @@ .. branch: ndarray-subtype Allow subclassing ndarray, i.e. matrix +.. branch: ndarray-sort +Implement ndarray in-place sorting (for numeric types, no non-native byte order) + .. branch: pypy-pyarray Implement much of numpy's c api in cpyext, allows (slow) access to ndarray from c @@ -87,6 +90,8 @@ .. branch: no-release-gil .. branch: safe-win-mmap .. branch: boolean-indexing-cleanup +.. branch: cpyext-best_base +.. branch: fileops2 .. branch: nobold-backtrace Work on improving UnionError messages and stack trace displays. @@ -103,3 +108,5 @@ .. branch: file-support-in-rpython make open() and friends rpython + + diff --git a/pypy/module/cpyext/test/test_cpyext.py b/pypy/module/cpyext/test/test_cpyext.py --- a/pypy/module/cpyext/test/test_cpyext.py +++ b/pypy/module/cpyext/test/test_cpyext.py @@ -99,7 +99,7 @@ class LeakCheckingTest(object): """Base class for all cpyext tests.""" spaceconfig = dict(usemodules=['cpyext', 'thread', '_rawffi', 'array', - 'itertools', 'rctime', 'binascii']) + 'itertools', 'rctime', 'binascii', 'micronumpy']) spaceconfig['std.withmethodcache'] = True enable_leak_checking = True @@ -196,7 +196,7 @@ assert PyUnicode_GetDefaultEncoding() == 'ascii' class AppTestCpythonExtensionBase(LeakCheckingTest): - + def setup_class(cls): cls.space.getbuiltinmodule("cpyext") from pypy.module.imp.importing import importhook diff --git a/pypy/module/cpyext/test/test_typeobject.py b/pypy/module/cpyext/test/test_typeobject.py --- a/pypy/module/cpyext/test/test_typeobject.py +++ b/pypy/module/cpyext/test/test_typeobject.py @@ -156,7 +156,7 @@ def __init__(self): self.foobar = 32 super(UnicodeSubclass2, self).__init__() - + newobj = UnicodeSubclass2() assert newobj.get_val() == 42 assert newobj.foobar == 32 @@ -358,6 +358,13 @@ assert w_obj is None assert api.PyErr_Occurred() is None + def test_ndarray_ref(self, space, api): + w_obj = space.appexec([], """(): + import numpypy as np + return np.int64(2)""") + ref = make_ref(space, w_obj) + api.Py_DecRef(ref) + class AppTestSlots(AppTestCpythonExtensionBase): def test_some_slots(self): module = self.import_extension('foo', [ @@ -525,7 +532,7 @@ assert type(it) is type(iter([])) assert module.tp_iternext(it) == 1 raises(StopIteration, module.tp_iternext, it) - + def test_bool(self): module = self.import_extension('foo', [ ("newInt", "METH_VARARGS", diff --git a/pypy/module/cpyext/typeobject.py b/pypy/module/cpyext/typeobject.py --- a/pypy/module/cpyext/typeobject.py +++ b/pypy/module/cpyext/typeobject.py @@ -4,7 +4,7 @@ from rpython.rtyper.lltypesystem import rffi, lltype from rpython.rtyper.annlowlevel import llhelper from pypy.interpreter.baseobjspace import W_Root, DescrMismatch -from pypy.objspace.std.typeobject import W_TypeObject +from pypy.objspace.std.typeobject import W_TypeObject, find_best_base from pypy.interpreter.typedef import GetSetProperty from pypy.module.cpyext.api import ( cpython_api, cpython_struct, bootstrap_function, Py_ssize_t, Py_ssize_tP, @@ -574,33 +574,7 @@ def best_base(space, bases_w): if not bases_w: return None - - w_winner = None - w_base = None - for w_base_i in bases_w: - if isinstance(w_base_i, W_ClassObject): - # old-style base - continue - assert isinstance(w_base_i, W_TypeObject) - w_candidate = solid_base(space, w_base_i) - if not w_winner: - w_winner = w_candidate - w_base = w_base_i - elif space.abstract_issubclass_w(w_winner, w_candidate): - pass - elif space.abstract_issubclass_w(w_candidate, w_winner): - w_winner = w_candidate - w_base = w_base_i - else: - raise OperationError( - space.w_TypeError, - space.wrap("multiple bases have instance lay-out conflict")) - if w_base is None: - raise OperationError( - space.w_TypeError, - space.wrap("a new-style class can't have only classic bases")) - - return w_base + return find_best_base(space, bases_w) def inherit_slots(space, pto, w_base): # XXX missing: nearly everything 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 @@ -356,6 +356,10 @@ from pypy.module.micronumpy.arrayimpl.sort import argsort_array return argsort_array(self, space, w_axis) + def sort(self, space, w_axis, w_order): + from pypy.module.micronumpy.arrayimpl.sort import sort_array + return sort_array(self, space, w_axis, w_order) + def base(self): return None diff --git a/pypy/module/micronumpy/arrayimpl/sort.py b/pypy/module/micronumpy/arrayimpl/sort.py --- a/pypy/module/micronumpy/arrayimpl/sort.py +++ b/pypy/module/micronumpy/arrayimpl/sort.py @@ -17,7 +17,7 @@ INT_SIZE = rffi.sizeof(lltype.Signed) -def make_sort_function(space, itemtype, comp_type, count=1): +def make_argsort_function(space, itemtype, comp_type, count=1): TP = itemtype.T step = rffi.sizeof(TP) @@ -137,8 +137,8 @@ else: shape = arr.get_shape() if axis < 0: - axis = len(shape) + axis - 1 - if axis < 0 or axis > len(shape): + axis = len(shape) + axis + if axis < 0 or axis >= len(shape): raise OperationError(space.w_IndexError, space.wrap( "Wrong axis %d" % axis)) iterable_shape = shape[:axis] + [0] + shape[axis + 1:] @@ -162,7 +162,7 @@ return argsort def argsort_array(arr, space, w_axis): - cache = space.fromcache(SortCache) # that populates SortClasses + cache = space.fromcache(ArgSortCache) # that populates ArgSortClasses itemtype = arr.dtype.itemtype for tp in all_types: if isinstance(itemtype, tp[0]): @@ -178,6 +178,166 @@ all_types = [i for i in all_types if not '_mixin_' in i[0].__dict__] all_types = unrolling_iterable(all_types) +def make_sort_function(space, itemtype, comp_type, count=1): + TP = itemtype.T + step = rffi.sizeof(TP) + + class Repr(object): + def __init__(self, stride_size, size, values, start): + self.stride_size = stride_size + self.start = start + self.size = size + self.values = values + + def getitem(self, item): + if count < 2: + v = raw_storage_getitem(TP, self.values, item * self.stride_size + + self.start) + else: + v = [] + for i in range(count): + _v = raw_storage_getitem(TP, self.values, item * self.stride_size + + self.start + step * i) + v.append(_v) + if comp_type == 'int': + v = intmask(v) + elif comp_type == 'float': + v = float(v) + elif comp_type == 'complex': + v = [float(v[0]),float(v[1])] + else: + raise NotImplementedError('cannot reach') + return (v) + + def setitem(self, idx, item): + if count < 2: + raw_storage_setitem(self.values, idx * self.stride_size + + self.start, rffi.cast(TP, item)) + else: + i = 0 + for val in item: + raw_storage_setitem(self.values, idx * self.stride_size + + self.start + i*step, rffi.cast(TP, val)) + i += 1 + + class ArgArrayRepWithStorage(Repr): + def __init__(self, stride_size, size): + start = 0 + values = alloc_raw_storage(size * stride_size, + track_allocation=False) + Repr.__init__(self, stride_size, + size, values, start) + + def __del__(self): + free_raw_storage(self.values, track_allocation=False) + + def arg_getitem(lst, item): + return lst.getitem(item) + + def arg_setitem(lst, item, value): + lst.setitem(item, value) + + def arg_length(lst): + return lst.size + + def arg_getitem_slice(lst, start, stop): + retval = ArgArrayRepWithStorage(lst.stride_size, stop-start) + for i in range(stop-start): + retval.setitem(i, lst.getitem(i+start)) + return retval + + if count < 2: + def arg_lt(a, b): + # handles NAN and INF + return a < b or b != b and a == a + else: + def arg_lt(a, b): + for i in range(count): + if b[i] != b[i] and a[i] == a[i]: + return True + elif b[i] == b[i] and a[i] != a[i]: + return False + for i in range(count): + if a[i] < b[i]: + return True + elif a[i] > b[i]: + return False + # Does numpy do True? + return False + + ArgSort = make_timsort_class(arg_getitem, arg_setitem, arg_length, + arg_getitem_slice, arg_lt) + + def sort(arr, space, w_axis, itemsize): + if w_axis is space.w_None: + # note that it's fine to pass None here as we're not going + # to pass the result around (None is the link to base in slices) + arr = arr.reshape(space, None, [arr.get_size()]) + axis = 0 + elif w_axis is None: + axis = -1 + else: + axis = space.int_w(w_axis) + # create array of indexes + if len(arr.get_shape()) == 1: + r = Repr(itemsize, arr.get_size(), arr.get_storage(), + arr.start) + ArgSort(r).sort() + else: + shape = arr.get_shape() + if axis < 0: + axis = len(shape) + axis + if axis < 0 or axis >= len(shape): + raise OperationError(space.w_IndexError, space.wrap( + "Wrong axis %d" % axis)) + iterable_shape = shape[:axis] + [0] + shape[axis + 1:] + iter = AxisIterator(arr, iterable_shape, axis, False) + stride_size = arr.strides[axis] + axis_size = arr.shape[axis] + while not iter.done(): + r = Repr(stride_size, axis_size, arr.get_storage(), iter.offset) + ArgSort(r).sort() + iter.next() + + return sort + +def sort_array(arr, space, w_axis, w_order): + cache = space.fromcache(SortCache) # that populates SortClasses + itemtype = arr.dtype.itemtype + if not arr.dtype.native: + raise OperationError(space.w_NotImplementedError, + space.wrap("sorting of non-native btyeorder not supported yet")) + for tp in all_types: + if isinstance(itemtype, tp[0]): + return cache._lookup(tp)(arr, space, w_axis, + itemtype.get_element_size()) + # XXX this should probably be changed + raise OperationError(space.w_NotImplementedError, + space.wrap("sorting of non-numeric types " + \ + "'%s' is not implemented" % arr.dtype.get_name(), )) + +all_types = (types.all_float_types + types.all_complex_types + + types.all_int_types) +all_types = [i for i in all_types if not '_mixin_' in i[0].__dict__] +all_types = unrolling_iterable(all_types) + +class ArgSortCache(object): + built = False + + def __init__(self, space): + if self.built: + return + self.built = True + cache = {} + for cls, it in all_types._items: + if it == 'complex': + cache[cls] = make_argsort_function(space, cls, it, 2) + else: + cache[cls] = make_argsort_function(space, cls, it) + self.cache = cache + self._lookup = specialize.memo()(lambda tp : cache[tp[0]]) + + class SortCache(object): built = False 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 @@ -629,9 +629,13 @@ raise OperationError(space.w_NotImplementedError, space.wrap( "setflags not implemented yet")) - def descr_sort(self, space, w_axis=-1, w_kind='quicksort', w_order=None): - raise OperationError(space.w_NotImplementedError, space.wrap( - "sort not implemented yet")) + @unwrap_spec(kind=str) + def descr_sort(self, space, w_axis=None, kind='quicksort', w_order=None): + # happily ignore the kind + # modify the array in-place + if self.is_scalar(): + return + return self.implementation.sort(space, w_axis, w_order) def descr_squeeze(self, space): raise OperationError(space.w_NotImplementedError, space.wrap( @@ -1118,6 +1122,7 @@ conj = interp2app(W_NDimArray.descr_conj), argsort = interp2app(W_NDimArray.descr_argsort), + sort = interp2app(W_NDimArray.descr_sort), astype = interp2app(W_NDimArray.descr_astype), base = GetSetProperty(W_NDimArray.descr_get_base), byteswap = interp2app(W_NDimArray.descr_byteswap), diff --git a/pypy/module/micronumpy/test/test_numarray.py b/pypy/module/micronumpy/test/test_numarray.py --- a/pypy/module/micronumpy/test/test_numarray.py +++ b/pypy/module/micronumpy/test/test_numarray.py @@ -2652,55 +2652,6 @@ assert array([1, 2, 3], '>i2')[::2].tostring() == '\x00\x01\x00\x03' assert array(0, dtype='i2').tostring() == '\x00\x00' - def test_argsort_dtypes(self): - from numpypy import array, arange - assert array(2.0).argsort() == 0 - nnp = self.non_native_prefix - for dtype in ['int', 'float', 'int16', 'float32', 'uint64', - nnp + 'i2', complex]: - a = array([6, 4, -1, 3, 8, 3, 256+20, 100, 101], dtype=dtype) - c = a.copy() - res = a.argsort() - assert (res == [2, 3, 5, 1, 0, 4, 7, 8, 6]).all(), \ - 'a,res,dtype %r,%r,%r' % (a,res,dtype) - assert (a == c).all() # not modified - a = arange(100) - assert (a.argsort() == a).all() - raises(NotImplementedError, 'arange(10,dtype="float16").argsort()') - - def test_argsort_nd(self): - from numpypy import array - a = array([[4, 2], [1, 3]]) - assert (a.argsort() == [[1, 0], [0, 1]]).all() - a = array(range(10) + range(10) + range(10)) - b = a.argsort() - assert (b[:3] == [0, 10, 20]).all() - #trigger timsort 'run' mode which calls arg_getitem_slice - a = array(range(100) + range(100) + range(100)) - b = a.argsort() - assert (b[:3] == [0, 100, 200]).all() - a = array([[[]]]).reshape(3,4,0) - b = a.argsort() - assert b.size == 0 - - def test_argsort_random(self): - from numpypy import array - from _random import Random - rnd = Random(1) - a = array([rnd.random() for i in range(512*2)]).reshape(512,2) - a.argsort() - - def test_argsort_axis(self): - from numpypy import array - a = array([[4, 2], [1, 3]]) - assert (a.argsort(axis=None) == [2, 1, 3, 0]).all() - assert (a.argsort(axis=-1) == [[1, 0], [0, 1]]).all() - assert (a.argsort(axis=0) == [[1, 0], [0, 1]]).all() - assert (a.argsort(axis=1) == [[1, 0], [0, 1]]).all() - a = array([[3, 2, 1], [1, 2, 3]]) - assert (a.argsort(axis=0) == [[1, 0, 0], [0, 1, 1]]).all() - assert (a.argsort(axis=1) == [[2, 1, 0], [0, 1, 2]]).all() - class AppTestRanges(BaseNumpyAppTest): def test_arange(self): diff --git a/pypy/module/micronumpy/test/test_sorting.py b/pypy/module/micronumpy/test/test_sorting.py new file mode 100644 --- /dev/null +++ b/pypy/module/micronumpy/test/test_sorting.py @@ -0,0 +1,322 @@ +from pypy.module.micronumpy.test.test_base import BaseNumpyAppTest + +class AppTestSupport(BaseNumpyAppTest): + def setup_class(cls): + import struct + BaseNumpyAppTest.setup_class.im_func(cls) + cls.w_data = cls.space.wrap(struct.pack('dddd', 1, 2, 3, 4)) + cls.w_fdata = cls.space.wrap(struct.pack('f', 2.3)) + cls.w_float16val = cls.space.wrap('\x00E') # 5.0 in float16 + cls.w_float32val = cls.space.wrap(struct.pack('f', 5.2)) + cls.w_float64val = cls.space.wrap(struct.pack('d', 300.4)) + cls.w_ulongval = cls.space.wrap(struct.pack('L', 12)) + + def test_argsort_dtypes(self): + from numpypy import array, arange + assert array(2.0).argsort() == 0 + nnp = self.non_native_prefix + for dtype in ['int', 'float', 'int16', 'float32', 'uint64', + nnp + 'i2', complex]: + a = array([6, 4, -1, 3, 8, 3, 256+20, 100, 101], dtype=dtype) + c = a.copy() + res = a.argsort() + assert (res == [2, 3, 5, 1, 0, 4, 7, 8, 6]).all(), \ + 'a,res,dtype %r,%r,%r' % (a,res,dtype) + assert (a == c).all() # not modified + a = arange(100) + assert (a.argsort() == a).all() + raises(NotImplementedError, 'arange(10,dtype="float16").argsort()') + + def test_argsort_nd(self): + from numpypy import array + a = array([[4, 2], [1, 3]]) + assert (a.argsort() == [[1, 0], [0, 1]]).all() + a = array(range(10) + range(10) + range(10)) + b = a.argsort() + assert (b[:3] == [0, 10, 20]).all() + #trigger timsort 'run' mode which calls arg_getitem_slice + a = array(range(100) + range(100) + range(100)) + b = a.argsort() + assert (b[:3] == [0, 100, 200]).all() + a = array([[[]]]).reshape(3,4,0) + b = a.argsort() + assert b.size == 0 + + def test_argsort_random(self): + from numpypy import array + from _random import Random + rnd = Random(1) + a = array([rnd.random() for i in range(512*2)]).reshape(512,2) + a.argsort() + + def test_argsort_axis(self): + from numpypy import array + a = array([[4, 2], [1, 3]]) + assert (a.argsort(axis=None) == [2, 1, 3, 0]).all() + assert (a.argsort(axis=-1) == [[1, 0], [0, 1]]).all() + assert (a.argsort(axis=0) == [[1, 0], [0, 1]]).all() + assert (a.argsort(axis=1) == [[1, 0], [0, 1]]).all() + a = array([[3, 2, 1], [1, 2, 3]]) + assert (a.argsort(axis=0) == [[1, 0, 0], [0, 1, 1]]).all() + assert (a.argsort(axis=1) == [[2, 1, 0], [0, 1, 2]]).all() + + def test_sort_dtypes(self): + from numpypy import array, arange + for dtype in ['int', 'float', 'int16', 'float32', 'uint64', + 'i2', complex]: + a = array([6, 4, -1, 3, 8, 3, 256+20, 100, 101], dtype=dtype) + b = array([-1, 3, 3, 4, 6, 8, 100, 101, 256+20], dtype=dtype) + c = a.copy() + a.sort() + assert (a == b).all(), \ + 'a,orig,dtype %r,%r,%r' % (a,c,dtype) + a = arange(100) + c = a.copy() + a.sort() + assert (a == c).all() + + def test_sort_dtypesi_nonnative(self): + from numpypy import array + nnp = self.non_native_prefix + for dtype in [ nnp + 'i2']: + a = array([6, 4, -1, 3, 8, 3, 256+20, 100, 101], dtype=dtype) + b = array([-1, 3, 3, 4, 6, 8, 100, 101, 256+20], dtype=dtype) + c = a.copy() + exc = raises(NotImplementedError, a.sort) + assert exc.value[0].find('supported') >= 0 + #assert (a == b).all(), \ + # 'a,orig,dtype %r,%r,%r' % (a,c,dtype) + + +# tests from numpy/tests/test_multiarray.py + def test_sort_corner_cases(self): + # test ordering for floats and complex containing nans. It is only + # necessary to check the lessthan comparison, so sorts that + # only follow the insertion sort path are sufficient. We only + # test doubles and complex doubles as the logic is the same. + + # check doubles + from numpypy import array, nan, zeros, complex128, arange + from numpy import isnan + a = array([nan, 1, 0]) + b = a.copy() + b.sort() + assert (isnan(b) == isnan(a[::-1])).all() + assert (b[:2] == a[::-1][:2]).all() + + # check complex + a = zeros(9, dtype=complex128) + a.real += [nan, nan, nan, 1, 0, 1, 1, 0, 0] + a.imag += [nan, 1, 0, nan, nan, 1, 0, 1, 0] + b = a.copy() + b.sort() + assert (isnan(b) == isnan(a[::-1])).all() + assert (b[:4] == a[::-1][:4]).all() + + # all c scalar sorts use the same code with different types + # so it suffices to run a quick check with one type. The number + # of sorted items must be greater than ~50 to check the actual + # algorithm because quick and merge sort fall over to insertion + # sort for small arrays. + a = arange(101) + b = a[::-1].copy() + for kind in ['q', 'm', 'h'] : + msg = "scalar sort, kind=%s" % kind + c = a.copy(); + c.sort(kind=kind) + assert (c == a).all(), msg + c = b.copy(); + c.sort(kind=kind) + assert (c == a).all(), msg + + # test complex sorts. These use the same code as the scalars + # but the compare fuction differs. + ai = a*1j + 1 + bi = b*1j + 1 + for kind in ['q', 'm', 'h'] : + msg = "complex sort, real part == 1, kind=%s" % kind + c = ai.copy(); + c.sort(kind=kind) + assert (c == ai).all(), msg + c = bi.copy(); + c.sort(kind=kind) + assert (c == ai).all(), msg + ai = a + 1j + bi = b + 1j + for kind in ['q', 'm', 'h'] : + msg = "complex sort, imag part == 1, kind=%s" % kind + c = ai.copy(); + c.sort(kind=kind) + assert (c == ai).all(), msg + c = bi.copy(); + c.sort(kind=kind) + assert (c == ai).all(), msg + + # check axis handling. This should be the same for all type + # specific sorts, so we only check it for one type and one kind + a = array([[3, 2], [1, 0]]) + b = array([[1, 0], [3, 2]]) + c = array([[2, 3], [0, 1]]) + d = a.copy() + d.sort(axis=0) + assert (d == b).all(), "test sort with axis=0" + d = a.copy() + d.sort(axis=1) + assert (d == c).all(), "test sort with axis=1" + d = a.copy() + d.sort() + assert (d == c).all(), "test sort with default axis" + + def test_sort_corner_cases_string_records(self): + skip('not implemented yet') + from numpypy import array, dtype + # test string sorts. + s = 'aaaaaaaa' + a = array([s + chr(i) for i in range(101)]) + b = a[::-1].copy() + for kind in ['q', 'm', 'h'] : + msg = "string sort, kind=%s" % kind + c = a.copy(); + c.sort(kind=kind) + assert (c == a).all(), msg + c = b.copy(); + c.sort(kind=kind) + assert (c == a).all(), msg + + + # test record array sorts. + dt =dtype([('f', float), ('i', int)]) + a = array([(i, i) for i in range(101)], dtype = dt) + b = a[::-1] + for kind in ['q', 'h', 'm'] : + msg = "object sort, kind=%s" % kind + c = a.copy(); + c.sort(kind=kind) + assert (c == a).all(), msg + c = b.copy(); + c.sort(kind=kind) + assert (c == a).all(), msg + + def test_sort_unicode(self): + from numpypy import array + # test unicode sorts. + s = 'aaaaaaaa' + try: + a = array([s + chr(i) for i in range(101)], dtype=unicode) + b = a[::-1].copy() + except: + skip('unicode type not supported yet') + for kind in ['q', 'm', 'h'] : + msg = "unicode sort, kind=%s" % kind + c = a.copy(); + c.sort(kind=kind) + assert (c == a).all(), msg + c = b.copy(); + c.sort(kind=kind) + assert (c == a).all(), msg + + def test_sort_objects(self): + # test object array sorts. + from numpypy import empty + try: + a = empty((101,), dtype=object) + except: + skip('object type not supported yet') + a[:] = list(range(101)) + b = a[::-1] + for kind in ['q', 'h', 'm'] : + msg = "object sort, kind=%s" % kind + c = a.copy(); + c.sort(kind=kind) + assert (c == a).all(), msg + c = b.copy(); + c.sort(kind=kind) + assert (c == a).all(), msg + + def test_sort_datetime(self): + from numpypy import arange + # test datetime64 sorts. + try: + a = arange(0, 101, dtype='datetime64[D]') + except: + skip('datetime type not supported yet') + b = a[::-1] + for kind in ['q', 'h', 'm'] : + msg = "datetime64 sort, kind=%s" % kind + c = a.copy(); + c.sort(kind=kind) + assert (c == a).all(), msg + c = b.copy(); + c.sort(kind=kind) + assert (c == a).all(), msg + + # test timedelta64 sorts. + a = arange(0, 101, dtype='timedelta64[D]') + b = a[::-1] + for kind in ['q', 'h', 'm'] : + msg = "timedelta64 sort, kind=%s" % kind + c = a.copy(); + c.sort(kind=kind) + assert (c == a).all(), msg + c = b.copy(); + c.sort(kind=kind) + assert (c == a).all(), msg + + def test_sort_order(self): + from numpypy import array, zeros + from sys import byteorder + # Test sorting an array with fields + skip('not implemented yet') + x1 = array([21, 32, 14]) + x2 = array(['my', 'first', 'name']) + x3=array([3.1, 4.5, 6.2]) + r=zeros(3, dtype=[('id','i'),('word','S5'),('number','f')]) + r['id'] = x1 + r['word'] = x2 + r['number'] = x3 + + r.sort(order=['id']) + assert (r['id'] == [14, 21, 32]).all() + assert (r['word'] == ['name', 'my', 'first']).all() + assert max(abs(r['number'] - [6.2, 3.1, 4.5])) < 1e-6 + + r.sort(order=['word']) + assert (r['id'] == [32, 21, 14]).all() + assert (r['word'] == ['first', 'my', 'name']).all() + assert max(abs(r['number'] - [4.5, 3.1, 6.2])) < 1e-6 + + r.sort(order=['number']) + assert (r['id'] == [21, 32, 14]).all() + assert (r['word'] == ['my', 'first', 'name']).all() + assert max(abs(r['number'] - [3.1, 4.5, 6.2])) < 1e-6 + + if byteorder == 'little': + strtype = '>i2' + else: + strtype = '<i2' + mydtype = [('name', 'S5'), ('col2', strtype)] + r = array([('a', 1), ('b', 255), ('c', 3), ('d', 258)], + dtype= mydtype) + r.sort(order='col2') + assert (r['col2'] == [1, 3, 255, 258]).all() + assert (r == array([('a', 1), ('c', 3), ('b', 255), ('d', 258)], + dtype=mydtype)).all() + + +# tests from numpy/tests/test_regression.py + def test_sort_bigendian(self): + skip('not implemented yet') + from numpypy import array, dtype + a = array(range(11),dtype='float64') + c = a.astype(dtype('<f8')) + c.sort() + assert max(abs(a-c)) < 1e-32 + + def test_string_sort_with_zeros(self): + skip('not implemented yet') + from numpypy import fromstring + """Check sort for strings containing zeros.""" + x = fromstring("\x00\x02\x00\x01", dtype="S2") + y = fromstring("\x00\x01\x00\x02", dtype="S2") + x.sort(kind='q') + assert (x == y).all() 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 @@ -1864,7 +1864,6 @@ return interp_boxes.W_StringBox(arr, 0, arr.dtype) def fill(self, storage, width, box, start, stop, offset): - from pypy.module.micronumpy.arrayimpl.concrete import ConcreteArrayNotOwning for i in xrange(start, stop, width): self._store(storage, i, offset, box) @@ -1873,6 +1872,13 @@ class UnicodeType(BaseType, BaseStringType): T = lltype.UniChar + @jit.unroll_safe + def coerce(self, space, dtype, w_item): + if isinstance(w_item, interp_boxes.W_UnicodeBox): + return w_item + raise OperationError(space.w_NotImplementedError, space.wrap( + "coerce (probably from set_item) not implemented for unicode type")) + NonNativeUnicodeType = UnicodeType class VoidType(BaseType, BaseStringType): diff --git a/pypy/objspace/std/floatobject.py b/pypy/objspace/std/floatobject.py --- a/pypy/objspace/std/floatobject.py +++ b/pypy/objspace/std/floatobject.py @@ -1,5 +1,5 @@ import operator -from pypy.interpreter.error import OperationError +from pypy.interpreter.error import OperationError, operationerrfmt from pypy.objspace.std import model, newformat from pypy.objspace.std.floattype import float_typedef, W_AbstractFloatObject from pypy.objspace.std.multimethod import FailedToImplementArgs @@ -424,7 +424,16 @@ x = w_float1.floatval y = w_float2.floatval - return W_FloatObject(_pow(space, x, y)) + try: + result = _pow(space, x, y) + except PowDomainError: + raise operationerrfmt(space.w_ValueError, + "negative number cannot be raised to a " + "fractional power") + return W_FloatObject(result) + +class PowDomainError(ValueError): + """Signals a negative number raised to a fractional power""" def _pow(space, x, y): # Sort out special cases here instead of relying on pow() @@ -478,16 +487,14 @@ "a negative power")) negate_result = False - # special case: "(-1.0) ** bignum" should not raise ValueError, + # special case: "(-1.0) ** bignum" should not raise PowDomainError, # unlike "math.pow(-1.0, bignum)". See http://mail.python.org/ # - pipermail/python-bugs-list/2003-March/016795.html if x < 0.0: if isnan(y): return NAN if math.floor(y) != y: - raise OperationError(space.w_ValueError, - space.wrap("negative number cannot be " - "raised to a fractional power")) + raise PowDomainError # y is an exact integer, albeit perhaps a very large one. # Replace x by its absolute value and remember to negate the # pow result if y is odd. diff --git a/rpython/memory/gc/minimark.py b/rpython/memory/gc/minimark.py --- a/rpython/memory/gc/minimark.py +++ b/rpython/memory/gc/minimark.py @@ -1201,7 +1201,6 @@ # ^^^ a fast path of write-barrier # if source_hdr.tid & GCFLAG_HAS_CARDS != 0: - assert self.card_page_indices > 0 # if source_hdr.tid & GCFLAG_TRACK_YOUNG_PTRS == 0: # The source object may have random young pointers. @@ -1236,6 +1235,7 @@ def manually_copy_card_bits(self, source_addr, dest_addr, length): # manually copy the individual card marks from source to dest + assert self.card_page_indices > 0 bytes = self.card_marking_bytes_for_length(length) # anybyte = 0 diff --git a/rpython/rtyper/lltypesystem/rdict.py b/rpython/rtyper/lltypesystem/rdict.py --- a/rpython/rtyper/lltypesystem/rdict.py +++ b/rpython/rtyper/lltypesystem/rdict.py @@ -820,8 +820,9 @@ entry = entries[i] hash = entries.hash(i) key = entry.key + value = entry.value j = ll_dict_lookup(dic1, key, hash) - _ll_dict_setitem_lookup_done(dic1, key, entry.value, hash, j) + _ll_dict_setitem_lookup_done(dic1, key, value, hash, j) i += 1 ll_update.oopspec = 'dict.update(dic1, dic2)' diff --git a/rpython/rtyper/test/test_rstr.py b/rpython/rtyper/test/test_rstr.py --- a/rpython/rtyper/test/test_rstr.py +++ b/rpython/rtyper/test/test_rstr.py @@ -3,6 +3,7 @@ import py from rpython.flowspace.model import summary +from rpython.annotator.model import AnnotatorError from rpython.rtyper.lltypesystem.lltype import typeOf, Signed, malloc from rpython.rtyper.lltypesystem.rstr import LLHelpers, STR from rpython.rtyper.rstr import AbstractLLHelpers @@ -361,16 +362,16 @@ res = self.interpret(fn, [i, j]) assert res == fn(i, j) - def test_find_TyperError(self): + def test_find_AnnotatorError(self): const = self.const def f(): s = const('abc') s.find(s, 0, -10) - py.test.raises(TyperError, self.interpret, f, ()) + py.test.raises(AnnotatorError, self.interpret, f, ()) def f(): s = const('abc') s.find(s, -10) - py.test.raises(TyperError, self.interpret, f, ()) + py.test.raises(AnnotatorError, self.interpret, f, ()) def test_find_empty_string(self): const = self.const @@ -420,9 +421,8 @@ const = self.const def f(i): return const("abc").rfind(const(''), i) - e = py.test.raises(TyperError, self.interpret, f, [-5]) - assert str(e.value).startswith( - 'str.rfind() start must be proven non-negative') + e = py.test.raises(AnnotatorError, self.interpret, f, [-5]) + assert "rfind: not proven to have non-negative start" in str(e.value) def test_find_char(self): const = self.const @@ -900,16 +900,16 @@ res = self.interpret(fn, []) assert res == 1 - def test_count_TyperError(self): + def test_count_AnnotatorError(self): const = self.const def f(): s = const('abc') s.count(s, 0, -10) - py.test.raises(TyperError, self.interpret, f, ()) + py.test.raises(AnnotatorError, self.interpret, f, ()) def f(): s = const('abc') s.count(s, -10) - py.test.raises(TyperError, self.interpret, f, ()) + py.test.raises(AnnotatorError, self.interpret, f, ()) def test_getitem_exc(self): const = self.const _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit