Repository navigation
ENH,REF: New-style generic sorting ArrayMethod loops - #30328
Conversation
mhvk
left a comment
There was a problem hiding this comment.
@MaanasArora - This looks nice! But I think we should have just two loops, say, npy_sort_loop and npy_argsort_loop, which do the switch for stable/unstable implementations inside themelves. I.e., have these be loops where the context decides everything, including future extensions such as whether to sort ascending/descending, or where to sort NaN.
The nice aspect would then be that in the stringdtype wrappers, you really only need to worry about wrapping, not implementation details like what kind of sort is requested (and no changes will be needed if more sort kinds are implemented).
I guess one small question is whether their name should be more descriptive. Maybe npy_sort_by_comparisons_loop? Or a lamer npy_default_sort_loop?
p.s. Separately, possibly this enables again removing implementations from the header files that you added in the last PR? In follow-up, it might be nice to have the new-style loops be the "real" ones, and old-style implementations just be wrappers (as long as we still need them).
|
Thanks for reviewing @mhvk! That's a really nice idea, I've made just two loops, thanks - though was unsure where to put them so had to write a new c file Replaced its use in StringDType as well - agreed that it is quite nice to have a default loop so that the same logic doesn't have to be replicated everywhere! I tried to remove the implementations from the header, but it seems a bit tricky because of how the files are structured (we use the implementations in |
|
|
||
| #ifdef __cplusplus | ||
| } | ||
| #endif No newline at end of file |
There was a problem hiding this comment.
Fixed, sorry, thanks!
| NPY_NO_EXPORT int npy_default_argsort_loop(PyArrayMethod_Context *context, | ||
| char *const *data, const npy_intp *dimensions, const npy_intp *strides, | ||
| NpyAuxData *transferdata); | ||
|
|
There was a problem hiding this comment.
I'm still a bit confused: in #30266, you added the GENERIC SORT IMPLEMENTATIONS below. WIth the new scheme introduced here, do these still need to be exposed in this header file? If we need them for defining the default (arg)sort loops in a new npy_sort.c file, can we remove them if instead we define the default sort loops in the same file as these generic implementations are defined?
p.s. I realize this may all be a bit pedantic, but I didn't quite like exposing "old" implementations in #30266 and am hoping we can remove them again here! This all in the hope of making it easier to completely remove the old implementations in the (near) future.
There was a problem hiding this comment.
Not pedantic at all, great point! I wished to remove as well. Unfortunately the sort implementations are defined in the files quicksort.cpp and mergesort.cpp - not sure which one the defaults would go in, I guess neither, so we end up with this... I suppose one workaround could be to expose these in a different header file - would that be OK?
Edit: that could be npysort_common.h, I did want to use the new file npysort_common.c, though this seems closer to NumPy core than npysort. I feel like some header is needed simply because these loop implementations are defined in the algorithm-specific files.
There was a problem hiding this comment.
Ah, yes, I see your problem now. Since this header also has the old npy_mergesort (without _impl), probably just best/easiest to stick with what you have here!
There was a problem hiding this comment.
Sounds good, thanks!
| int ret = sort_loop( | ||
| data[0], dimensions[0], context, | ||
| context->descriptors[0]->elsize, &_sort_compare); | ||
| int ret = npy_default_sort_loop(context, data, dimensions, strides, transferdata); |
There was a problem hiding this comment.
Ah, yes, this is what I hoped would be possible! Now StringDType really has to do nothing more than acquire and release the allocator. Nice!
| NPY_NO_EXPORT int npy_default_argsort_loop(PyArrayMethod_Context *context, | ||
| char *const *data, const npy_intp *dimensions, const npy_intp *strides, | ||
| NpyAuxData *transferdata); | ||
|
|
There was a problem hiding this comment.
Ah, yes, I see your problem now. Since this header also has the old npy_mergesort (without _impl), probably just best/easiest to stick with what you have here!
|
This seems all fine to me. Ideally we find this is useful for other implementations as well (and maybe updating the implementation if we find that useful; although we need to keep supporting legacy dtypes for a while -- not forever since adding a sort for an existing legacy user dtype is very possible. A scheme I actually think we may want to extend -- i.e. make dtypes more "mutable" even if it is not ideal, just to make transitioning dtypes to the new API one a step-by-step process). |
|
Thanks! It could be a useful implementation for Scaffolding by wrapping the existing machinery makes a lot of sense! Could definitely make later steps e.g. deprecations smoother at least. |
|
Hmmm, making it public to simplify some implementations may make sense. Although, in that case I am tempted to pass the |
|
Hmm, maybe, but then we don't have the ArrayMethod signature, so some implementations might actually get a bit more complicated? I can already think of |
|
One way to think of this might go to a more general way of registering a ufunc, where there is a default loop that just calls to a C function for every element. Here, that would be |
|
@seberg - the conversation here started to go towards follow-up territory. Shall we put this one in? I don't think it precludes any time of follow up! |
|
Yeah, let's move forward here, thanks Maanas and Marten. |
Implements
PyArrayMethod_StridedLoopwrappers for quicksort and mergesort to align with #29737. These can be used to implement a newsort_compareslot and move to the new API for builtin dtypes in the future. StringDType now wraps these new loops for its sorting implementation.This uses @mhvk's suggestion of using
context->method->static_dataas the location for the (sort) compare function. I think this should be fine since the static data is a private slot and can be evolved if needed, but open to discussion!ping @seberg @mhvk - thanks!