summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCharles Harris <charlesr.harris@gmail.com>2012-07-09 21:26:31 -0600
committerCharles Harris <charlesr.harris@gmail.com>2012-07-11 13:04:57 -0600
commit5be7e01a6d67f2adeb167a280986547773dc3ce0 (patch)
tree744f4b3eff6b62fed02913596347d8bebcb66c3e
parent286a15f77dbc657e2dfceb0bab35e4891e62b4f7 (diff)
downloadnumpy-5be7e01a6d67f2adeb167a280986547773dc3ce0.tar.gz
ENH: Add generic sorts for quicksort, heapsort, and mergesort.
These all have the same signature as the c qsort apart from an error return that is needed for memory allocation errors. With these functions the different kinds of sorts are made available for types that don't have type specific sorts. This fixes the np.unique bug introduced in 1.6.2 where record arrays and such didn't have mergesort. It also allows lexsort to work with all array types.
-rw-r--r--numpy/core/src/multiarray/item_selection.c87
-rw-r--r--numpy/core/src/npysort/heapsort.c.src67
-rw-r--r--numpy/core/src/npysort/mergesort.c.src85
-rw-r--r--numpy/core/src/npysort/npysort_common.h53
-rw-r--r--numpy/core/src/npysort/quicksort.c.src50
-rw-r--r--numpy/core/src/private/npy_sort.h9
-rw-r--r--numpy/core/tests/test_multiarray.py67
7 files changed, 361 insertions, 57 deletions
diff --git a/numpy/core/src/multiarray/item_selection.c b/numpy/core/src/multiarray/item_selection.c
index 977580d70..76b26d266 100644
--- a/numpy/core/src/multiarray/item_selection.c
+++ b/numpy/core/src/multiarray/item_selection.c
@@ -890,7 +890,7 @@ _new_argsort(PyArrayObject *op, int axis, NPY_SORTKIND which)
static PyArrayObject *global_obj;
static int
-qsortCompare (const void *a, const void *b)
+sortCompare (const void *a, const void *b)
{
return PyArray_DESCR(global_obj)->f->compare(a,b,global_obj);
}
@@ -954,7 +954,9 @@ PyArray_Sort(PyArrayObject *op, int axis, NPY_SORTKIND which)
PyArrayObject *ap = NULL, *store_arr = NULL;
char *ip;
int i, n, m, elsize, orign;
- int axis_orig=axis;
+ int res = 0;
+ int axis_orig = axis;
+ int (*sort)(void *, size_t, size_t, npy_comparator);
n = PyArray_NDIM(op);
if ((n == 0) || (PyArray_SIZE(op) == 1)) {
@@ -975,13 +977,30 @@ PyArray_Sort(PyArrayObject *op, int axis, NPY_SORTKIND which)
if (PyArray_DESCR(op)->f->sort[which] != NULL) {
return _new_sort(op, axis, which);
}
- if ((which != NPY_QUICKSORT)
- || PyArray_DESCR(op)->f->compare == NULL) {
+
+ if (PyArray_DESCR(op)->f->compare == NULL) {
PyErr_SetString(PyExc_TypeError,
- "desired sort not supported for this type");
+ "type does not have compare function");
return -1;
}
+ switch (which) {
+ case NPY_QUICKSORT :
+ sort = npy_quicksort;
+ break;
+ case NPY_HEAPSORT :
+ sort = npy_heapsort;
+ break;
+ case NPY_MERGESORT :
+ sort = npy_mergesort;
+ break;
+ default:
+ PyErr_SetString(PyExc_TypeError,
+ "requested sort kind is not supported");
+ goto fail;
+ }
+
+
SWAPAXES2(op);
ap = (PyArrayObject *)PyArray_FromAny((PyObject *)op,
@@ -1001,13 +1020,26 @@ PyArray_Sort(PyArrayObject *op, int axis, NPY_SORTKIND which)
store_arr = global_obj;
global_obj = ap;
for (ip = PyArray_DATA(ap), i = 0; i < n; i++, ip += elsize*m) {
- qsort(ip, m, elsize, qsortCompare);
+ res = sort(ip, m, elsize, sortCompare);
+ if (res < 0) {
+ break;
+ }
}
global_obj = store_arr;
if (PyErr_Occurred()) {
goto fail;
}
+ else if (res == -NPY_ENOMEM) {
+ PyErr_NoMemory();
+ goto fail;
+ }
+ else if (res == -NPY_ECOMP) {
+ PyErr_SetString(PyExc_TypeError,
+ "sort comparison failed");
+ goto fail;
+ }
+
finish:
Py_DECREF(ap); /* Should update op if needed */
@@ -1045,6 +1077,8 @@ PyArray_ArgSort(PyArrayObject *op, int axis, NPY_SORTKIND which)
npy_intp i, j, n, m, orign;
int argsort_elsize;
char *store_ptr;
+ int res = 0;
+ int (*sort)(void *, size_t, size_t, npy_comparator);
n = PyArray_NDIM(op);
if ((n == 0) || (PyArray_SIZE(op) == 1)) {
@@ -1071,14 +1105,32 @@ PyArray_ArgSort(PyArrayObject *op, int axis, NPY_SORTKIND which)
return (PyObject *)ret;
}
- if ((which != NPY_QUICKSORT) || PyArray_DESCR(op2)->f->compare == NULL) {
+ if (PyArray_DESCR(op2)->f->compare == NULL) {
PyErr_SetString(PyExc_TypeError,
- "requested sort not available for type");
+ "type does not have compare function");
Py_DECREF(op2);
op = NULL;
goto fail;
}
+ switch (which) {
+ case NPY_QUICKSORT :
+ sort = npy_quicksort;
+ break;
+ case NPY_HEAPSORT :
+ sort = npy_heapsort;
+ break;
+ case NPY_MERGESORT :
+ sort = npy_mergesort;
+ break;
+ default:
+ PyErr_SetString(PyExc_TypeError,
+ "requested sort kind is not supported");
+ Py_DECREF(op2);
+ op = NULL;
+ goto fail;
+ }
+
/* ap will contain the reference to op2 */
SWAPAXES(ap, op2);
op = (PyArrayObject *)PyArray_ContiguousFromAny((PyObject *)ap,
@@ -1109,11 +1161,27 @@ PyArray_ArgSort(PyArrayObject *op, int axis, NPY_SORTKIND which)
for (j = 0; j < m; j++) {
ip[j] = j;
}
- qsort((char *)ip, m, sizeof(npy_intp), argsort_static_compare);
+ res = sort((char *)ip, m, sizeof(npy_intp), argsort_static_compare);
+ if (res < 0) {
+ break;
+ }
}
global_data = store_ptr;
global_obj = store;
+ if (PyErr_Occurred()) {
+ goto fail;
+ }
+ else if (res == -NPY_ENOMEM) {
+ PyErr_NoMemory();
+ goto fail;
+ }
+ else if (res == -NPY_ECOMP) {
+ PyErr_SetString(PyExc_TypeError,
+ "sort comparison failed");
+ goto fail;
+ }
+
finish:
Py_DECREF(op);
SWAPBACK(op, ret);
@@ -1123,7 +1191,6 @@ PyArray_ArgSort(PyArrayObject *op, int axis, NPY_SORTKIND which)
Py_XDECREF(op);
Py_XDECREF(ret);
return NULL;
-
}
diff --git a/numpy/core/src/npysort/heapsort.c.src b/numpy/core/src/npysort/heapsort.c.src
index 7fd7c2fd1..6a8c79f7a 100644
--- a/numpy/core/src/npysort/heapsort.c.src
+++ b/numpy/core/src/npysort/heapsort.c.src
@@ -182,7 +182,7 @@ heapsort_@suff@(@type@ *start, npy_intp n, PyArrayObject *arr)
size_t len = PyArray_ITEMSIZE(arr)/sizeof(@type@);
@type@ *tmp = malloc(PyArray_ITEMSIZE(arr));
@type@ *a = start - len;
- npy_intp i,j,l;
+ npy_intp i, j, l;
for (l = n>>1; l > 0; --l) {
@TYPE@_COPY(tmp, a + l*len, len);
@@ -274,3 +274,68 @@ aheapsort_@suff@(@type@ *v, npy_intp *tosort, npy_intp n, PyArrayObject *arr)
}
/**end repeat**/
+
+
+/*
+ *****************************************************************************
+ ** GENERIC SORT **
+ *****************************************************************************
+ */
+
+
+/*
+ * This sort has almost the same signature as libc qsort and is intended to
+ * provide a heapsort for array types that don't have type specific sorts.
+ * The difference in the signature is an error return, as it might be the
+ * case that a memory allocation fails.
+ */
+int
+npy_heapsort(void *base, size_t num, size_t size, npy_comparator cmp)
+{
+ char *tmp = (char *) malloc(size);
+ char *a = (char *) base - size;
+ size_t i, j, l;
+
+ if (tmp == NULL) {
+ return -NPY_ENOMEM;
+ }
+
+ for (l = num >> 1; l > 0; --l) {
+ GENERIC_COPY(tmp, a + l*size, size);
+ for (i = l, j = l << 1; j <= num;) {
+ if (j < num && GENERIC_LT(a + j*size, a + (j+1)*size, cmp))
+ j += 1;
+ if (GENERIC_LT(tmp, a + j*size, cmp)) {
+ GENERIC_COPY(a + i*size, a + j*size, size);
+ i = j;
+ j += j;
+ }
+ else {
+ break;
+ }
+ }
+ GENERIC_COPY(a + i*size, tmp, size);
+ }
+
+ for (; num > 1;) {
+ GENERIC_COPY(tmp, a + num*size, size);
+ GENERIC_COPY(a + num*size, a + size, size);
+ num -= 1;
+ for (i = 1, j = 2; j <= num;) {
+ if (j < num && GENERIC_LT(a + j*size, a + (j+1)*size, cmp))
+ j++;
+ if (GENERIC_LT(tmp, a + j*size, cmp)) {
+ GENERIC_COPY(a + i*size, a + j*size, size);
+ i = j;
+ j += j;
+ }
+ else {
+ break;
+ }
+ }
+ GENERIC_COPY(a + i*size, tmp, size);
+ }
+
+ free(tmp);
+ return 0;
+}
diff --git a/numpy/core/src/npysort/mergesort.c.src b/numpy/core/src/npysort/mergesort.c.src
index 59582deda..a4f6bdb99 100644
--- a/numpy/core/src/npysort/mergesort.c.src
+++ b/numpy/core/src/npysort/mergesort.c.src
@@ -340,3 +340,88 @@ amergesort_@suff@(@type@ *v, npy_intp *tosort, npy_intp num, PyArrayObject *arr)
}
/**end repeat**/
+
+
+/*
+ *****************************************************************************
+ ** GENERIC SORT **
+ *****************************************************************************
+ */
+
+
+static void
+npy_mergesort0(char *pl, char *pr, char *pw, char *vp, size_t size, npy_comparator cmp)
+{
+ char *pi, *pj, *pk, *pm;
+
+ if ((size_t)(pr - pl) > SMALL_MERGESORT*size) {
+ /* merge sort */
+ pm = pl + (((pr - pl)/size) >> 1)*size;
+ npy_mergesort0(pl, pm, pw, vp, size, cmp);
+ npy_mergesort0(pm, pr, pw, vp, size, cmp);
+ GENERIC_COPY(pw, pl, pm - pl);
+ pi = pw + (pm - pl);
+ pj = pw;
+ pk = pl;
+ while (pj < pi && pm < pr) {
+ if (GENERIC_LT(pm, pj, cmp)) {
+ GENERIC_COPY(pk, pm, size);
+ pm += size;
+ }
+ else {
+ GENERIC_COPY(pk, pj, size);
+ pj += size;
+ }
+ pk += size;
+ }
+ GENERIC_COPY(pk, pj, pi - pj);
+ }
+ else {
+ /* insertion sort */
+ for (pi = pl + size; pi < pr; pi += size) {
+ GENERIC_COPY(vp, pi, size);
+ pj = pi;
+ pk = pi - size;
+ while (pj > pl && GENERIC_LT(vp, pk, cmp)) {
+ GENERIC_COPY(pj, pk, size);
+ pj -= size;
+ pk -= size;
+ }
+ GENERIC_COPY(pj, vp, size);
+ }
+ }
+}
+
+
+/*
+ * This sort has almost the same signature as libc qsort and is intended to
+ * provide a mergesort for array types that don't have type specific sorts.
+ * The difference in the signature is an error return, as it might be the
+ * case that a memory allocation fails.
+ */
+int
+npy_mergesort(void *base, size_t num, size_t size, npy_comparator cmp)
+{
+ char *pl, *pr, *pw, *vp;
+ int err = 0;
+
+ pl = (char *)base;
+ pr = pl + num*size;
+ pw = (char *) PyDataMem_NEW((num/2)*size);
+ if (pw == NULL) {
+ err = -NPY_ENOMEM;
+ goto fail_0;
+ }
+ vp = (char *) PyDataMem_NEW(size);
+ if (vp == NULL) {
+ err = -NPY_ENOMEM;
+ goto fail_1;
+ }
+ npy_mergesort0(pl, pr, pw, vp, size, cmp);
+
+ PyDataMem_FREE(vp);
+fail_1:
+ PyDataMem_FREE(pw);
+fail_0:
+ return err;
+}
diff --git a/numpy/core/src/npysort/npysort_common.h b/numpy/core/src/npysort/npysort_common.h
index bc1d278b0..318a80222 100644
--- a/numpy/core/src/npysort/npysort_common.h
+++ b/numpy/core/src/npysort/npysort_common.h
@@ -1,15 +1,9 @@
#ifndef __NPY_SORT_COMMON_H__
#define __NPY_SORT_COMMON_H__
-/*
-#include "Python.h"
-#include "numpy/npy_common.h"
-#include "numpy/npy_math.h"
-#include "npy_config.h"
-*/
+#include <stdlib.h>
#include <numpy/ndarraytypes.h>
-
/*
*****************************************************************************
** SWAP MACROS **
@@ -155,14 +149,17 @@ npy_half_lt_nonan(npy_half h1, npy_half h2)
if (h1&0x8000u) {
if (h2&0x8000u) {
return (h1&0x7fffu) > (h2&0x7fffu);
- } else {
+ }
+ else {
/* Signed zeros are equal, have to check for it */
return (h1 != 0x8000u) || (h2 != 0x0000u);
}
- } else {
+ }
+ else {
if (h2&0x8000u) {
return 0;
- } else {
+ }
+ else {
return (h1&0x7fffu) < (h2&0x7fffu);
}
}
@@ -176,7 +173,8 @@ HALF_LT(npy_half a, npy_half b)
if (npy_half_isnan(b)) {
ret = !npy_half_isnan(a);
- } else {
+ }
+ else {
ret = !npy_half_isnan(a) && npy_half_lt_nonan(a, b);
}
@@ -254,14 +252,6 @@ CLONGDOUBLE_LT(npy_clongdouble a, npy_clongdouble b)
}
-/* The PyObject functions are stubs for later use */
-NPY_INLINE static int
-PyObject_LT(PyObject *pa, PyObject *pb)
-{
- return 0;
-}
-
-
NPY_INLINE static void
STRING_COPY(char *s1, char *s2, size_t len)
{
@@ -333,4 +323,29 @@ UNICODE_LT(npy_ucs4 *s1, npy_ucs4 *s2, size_t len)
return ret;
}
+
+NPY_INLINE static void
+GENERIC_COPY(char *a, char *b, size_t len)
+{
+ memcpy(a, b, len);
+}
+
+
+NPY_INLINE static void
+GENERIC_SWAP(char *a, char *b, size_t len)
+{
+ while(len--) {
+ const char t = *a;
+ *a++ = *b;
+ *b++ = t;
+ }
+}
+
+
+NPY_INLINE static int
+GENERIC_LT(char *a, char *b, int (*cmp)(const void *, const void *))
+{
+ return cmp(a, b) < 0;
+}
+
#endif
diff --git a/numpy/core/src/npysort/quicksort.c.src b/numpy/core/src/npysort/quicksort.c.src
index 68140fe6f..2225887b1 100644
--- a/numpy/core/src/npysort/quicksort.c.src
+++ b/numpy/core/src/npysort/quicksort.c.src
@@ -63,10 +63,12 @@
int
quicksort_@suff@(@type@ *start, npy_intp num, void *NOT_USED)
{
+ @type@ vp;
@type@ *pl = start;
@type@ *pr = start + num - 1;
- @type@ vp;
- @type@ *stack[PYA_QS_STACK], **sptr = stack, *pm, *pi, *pj, *pk;
+ @type@ *stack[PYA_QS_STACK];
+ @type@ **sptr = stack;
+ @type@ *pm, *pi, *pj, *pk;
for (;;) {
while ((pr - pl) > SMALL_QUICKSORT) {
@@ -127,30 +129,30 @@ int
aquicksort_@suff@(@type@ *v, npy_intp* tosort, npy_intp num, void *NOT_USED)
{
@type@ vp;
- npy_intp *pl, *pr;
- npy_intp *stack[PYA_QS_STACK], **sptr=stack, *pm, *pi, *pj, *pk, vi;
-
- pl = tosort;
- pr = tosort + num - 1;
+ npy_intp *pl = tosort;
+ npy_intp *pr = tosort + num - 1;
+ npy_intp *stack[PYA_QS_STACK];
+ npy_intp **sptr = stack;
+ npy_intp *pm, *pi, *pj, *pk, vi;
for (;;) {
while ((pr - pl) > SMALL_QUICKSORT) {
/* quicksort partition */
pm = pl + ((pr - pl) >> 1);
- if (@TYPE@_LT(v[*pm],v[*pl])) INTP_SWAP(*pm,*pl);
- if (@TYPE@_LT(v[*pr],v[*pm])) INTP_SWAP(*pr,*pm);
- if (@TYPE@_LT(v[*pm],v[*pl])) INTP_SWAP(*pm,*pl);
+ if (@TYPE@_LT(v[*pm],v[*pl])) INTP_SWAP(*pm, *pl);
+ if (@TYPE@_LT(v[*pr],v[*pm])) INTP_SWAP(*pr, *pm);
+ if (@TYPE@_LT(v[*pm],v[*pl])) INTP_SWAP(*pm, *pl);
vp = v[*pm];
pi = pl;
pj = pr - 1;
- INTP_SWAP(*pm,*pj);
+ INTP_SWAP(*pm, *pj);
for (;;) {
- do ++pi; while (@TYPE@_LT(v[*pi],vp));
- do --pj; while (@TYPE@_LT(vp,v[*pj]));
+ do ++pi; while (@TYPE@_LT(v[*pi], vp));
+ do --pj; while (@TYPE@_LT(vp, v[*pj]));
if (pi >= pj) {
break;
}
- INTP_SWAP(*pi,*pj);
+ INTP_SWAP(*pi, *pj);
}
pk = pr - 1;
INTP_SWAP(*pi,*pk);
@@ -339,3 +341,23 @@ aquicksort_@suff@(@type@ *v, npy_intp* tosort, npy_intp num, PyArrayObject *arr)
}
/**end repeat**/
+
+
+/*
+ *****************************************************************************
+ ** GENERIC SORT **
+ *****************************************************************************
+ */
+
+
+/*
+ * This sort has almost the same signature as libc qsort and is intended to
+ * supply an error return for compatibility with the other generic sort
+ * kinds.
+ */
+int
+npy_quicksort(void *base, size_t num, size_t size, npy_comparator cmp)
+{
+ qsort(base, num, size, cmp);
+ return 0;
+}
diff --git a/numpy/core/src/private/npy_sort.h b/numpy/core/src/private/npy_sort.h
index 94d831f86..120e7efc2 100644
--- a/numpy/core/src/private/npy_sort.h
+++ b/numpy/core/src/private/npy_sort.h
@@ -6,6 +6,10 @@
#include <numpy/npy_common.h>
#include <numpy/ndarraytypes.h>
+#define NPY_ENOMEM 1
+#define NPY_ECOMP 2
+
+typedef int (*npy_comparator)(const void *, const void *);
int quicksort_bool(npy_bool *vec, npy_intp cnt, void *null);
int heapsort_bool(npy_bool *vec, npy_intp cnt, void *null);
@@ -166,4 +170,9 @@ int aquicksort_unicode(npy_ucs4 *vec, npy_intp *ind, npy_intp cnt, PyArrayObject
int aheapsort_unicode(npy_ucs4 *vec, npy_intp *ind, npy_intp cnt, PyArrayObject *arr);
int amergesort_unicode(npy_ucs4 *vec, npy_intp *ind, npy_intp cnt, PyArrayObject *arr);
+
+int npy_quicksort(void *base, size_t num, size_t size, npy_comparator cmp);
+int npy_heapsort(void *base, size_t num, size_t size, npy_comparator cmp);
+int npy_mergesort(void *base, size_t num, size_t size, npy_comparator cmp);
+
#endif
diff --git a/numpy/core/tests/test_multiarray.py b/numpy/core/tests/test_multiarray.py
index ab4e3e479..fba7a2981 100644
--- a/numpy/core/tests/test_multiarray.py
+++ b/numpy/core/tests/test_multiarray.py
@@ -538,7 +538,7 @@ class TestMethods(TestCase):
c.sort(kind=kind)
assert_equal(c, a, msg)
- # test unicode sort.
+ # test unicode sorts.
s = 'aaaaaaaa'
a = np.array([s + chr(i) for i in range(100)], dtype=np.unicode)
b = a[::-1].copy()
@@ -551,11 +551,11 @@ class TestMethods(TestCase):
c.sort(kind=kind)
assert_equal(c, a, msg)
- # test object array sort.
+ # test object array sorts.
a = np.empty((100,), dtype=np.object)
a[:] = range(100)
b = a[::-1]
- for kind in ['q'] :
+ for kind in ['q', 'h', 'm'] :
msg = "object sort, kind=%s" % kind
c = a.copy();
c.sort(kind=kind)
@@ -564,11 +564,11 @@ class TestMethods(TestCase):
c.sort(kind=kind)
assert_equal(c, a, msg)
- # test record array sort.
+ # test record array sorts.
dt = np.dtype([('f',float),('i',int)])
a = array([(i,i) for i in range(100)], dtype = dt)
b = a[::-1]
- for kind in ['q'] :
+ for kind in ['q', 'h', 'm'] :
msg = "object sort, kind=%s" % kind
c = a.copy();
c.sort(kind=kind)
@@ -577,6 +577,30 @@ class TestMethods(TestCase):
c.sort(kind=kind)
assert_equal(c, a, msg)
+ # test datetime64 sorts.
+ a = np.arange(0, 100, dtype='datetime64[D]')
+ b = a[::-1]
+ for kind in ['q', 'h', 'm'] :
+ msg = "datetime64 sort, kind=%s" % kind
+ c = a.copy();
+ c.sort(kind=kind)
+ assert_equal(c, a, msg)
+ c = b.copy();
+ c.sort(kind=kind)
+ assert_equal(c, a, msg)
+
+ # test timedelta64 sorts.
+ a = np.arange(0, 100, 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_equal(c, a, msg)
+ c = b.copy();
+ c.sort(kind=kind)
+ assert_equal(c, a, 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 = np.array([[3,2],[1,0]])
@@ -591,10 +615,6 @@ class TestMethods(TestCase):
d = a.copy()
d.sort()
assert_equal(d, c, "test sort with default axis")
- # using None is known fail at this point
- # d = a.copy()
- # d.sort(axis=None)
- #assert_equal(d, c, "test sort with axis=None")
def test_sort_order(self):
@@ -681,28 +701,49 @@ class TestMethods(TestCase):
assert_equal(a.copy().argsort(kind=kind), r, msg)
assert_equal(b.copy().argsort(kind=kind), rr, msg)
- # test object array argsort.
+ # test object array argsorts.
a = np.empty((100,), dtype=np.object)
a[:] = range(100)
b = a[::-1]
r = np.arange(100)
rr = r[::-1]
- for kind in ['q'] :
+ for kind in ['q', 'm', 'h'] :
msg = "object argsort, kind=%s" % kind
assert_equal(a.copy().argsort(kind=kind), r, msg)
assert_equal(b.copy().argsort(kind=kind), rr, msg)
- # test structured array sort.
+ # test structured array argsorts.
dt = np.dtype([('f',float),('i',int)])
a = array([(i,i) for i in range(100)], dtype = dt)
b = a[::-1]
r = np.arange(100)
rr = r[::-1]
- for kind in ['q'] :
+ for kind in ['q', 'm', 'h'] :
msg = "structured array argsort, kind=%s" % kind
assert_equal(a.copy().argsort(kind=kind), r, msg)
assert_equal(b.copy().argsort(kind=kind), rr, msg)
+ # test datetime64 argsorts.
+ a = np.arange(0, 100, dtype='datetime64[D]')
+ b = a[::-1]
+ r = np.arange(100)
+ rr = r[::-1]
+ for kind in ['q', 'h', 'm'] :
+ msg = "datetime64 argsort, kind=%s" % kind
+ assert_equal(a.copy().argsort(kind=kind), r, msg)
+ assert_equal(b.copy().argsort(kind=kind), rr, msg)
+
+ # test timedelta64 argsorts.
+ a = np.arange(0, 100, dtype='timedelta64[D]')
+ b = a[::-1]
+ r = np.arange(100)
+ rr = r[::-1]
+ for kind in ['q', 'h', 'm'] :
+ msg = "timedelta64 argsort, kind=%s" % kind
+ assert_equal(a.copy().argsort(kind=kind), r, msg)
+ assert_equal(b.copy().argsort(kind=kind), rr, msg)
+
+
# check axis handling. This should be the same for all type
# specific argsorts, so we only check it for one type and one kind
a = np.array([[3,2],[1,0]])