[pypy-commit] pypy default: merge ndarray-sort which implementes in-place timsort for numpy numerical ndarrays (not non-native byte order)
mattip
noreply at buildbot.pypy.org
Thu Oct 10 12:48:08 CEST 2013
Author: Matti Picus <matti.picus at gmail.com>
Branch:
Changeset: r67283:000c73872f73
Date: 2013-10-10 13:47 +0300
http://bitbucket.org/pypy/pypy/changeset/000c73872f73/
Log: merge ndarray-sort which implementes in-place timsort for numpy
numerical ndarrays (not non-native byte order)
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):
More information about the pypy-commit
mailing list