Skip to content

Commit

Permalink
MAINT: Align masked with normal ufunc loops
Browse files Browse the repository at this point in the history
This removes the ability to specialize masked inner loops (for now)
as was already noted in NEP 41 and NEP 43.

The masked array is now passed in as the last argument to use the
identical signature and avoid duplicating the code unnecessary.

This is part of the longer process to refactor ufuncs to NEP 43
and split out, to keep the diff's shorter (or at least easier
to read).
  • Loading branch information
seberg committed Jun 17, 2021
1 parent 7d8fada commit fa4a2cc
Show file tree
Hide file tree
Showing 5 changed files with 156 additions and 298 deletions.
14 changes: 14 additions & 0 deletions doc/release/upcoming_changes/19259.c_api.rst
@@ -0,0 +1,14 @@
Masked inner-loops cannot be customized anymore
-----------------------------------------------
The masked inner-loop selector is now never used. A warning
will be given in the unlikely event that it was customized.

We do not expect that any code uses this. If you do use it,
you must unset unset the selector on newer NumPy version.
Please also contact the NumPy developers, we do anticipate
providing a new, more specific, mechanism.

This change will not affect the results of operations, since
the fallback (which is always used internally) will handle
the operation equivalently, the customization was a planned
feature to allow for faster masked operation.
35 changes: 6 additions & 29 deletions numpy/core/include/numpy/ufuncobject.h
Expand Up @@ -66,27 +66,14 @@ typedef int (PyUFunc_TypeResolutionFunc)(
PyArray_Descr **out_dtypes);

/*
* Given an array of DTypes as returned by the PyUFunc_TypeResolutionFunc,
* and an array of fixed strides (the array will contain NPY_MAX_INTP for
* strides which are not necessarily fixed), returns an inner loop
* with associated auxiliary data.
*
* For backwards compatibility, there is a variant of the inner loop
* selection which returns an inner loop irrespective of the strides,
* and with a void* static auxiliary data instead of an NpyAuxData *
* dynamically allocatable auxiliary data.
* Legacy loop selector. (This should NOT normally be used and we can expect
* that only the `PyUFunc_DefaultLegacyInnerLoopSelector` is ever set).
* However, unlike the masked version, it probably still works.
*
* ufunc: The ufunc object.
* dtypes: An array which has been populated with dtypes,
* in most cases by the type resolution function
* for the same ufunc.
* fixed_strides: For each input/output, either the stride that
* will be used every time the function is called
* or NPY_MAX_INTP if the stride might change or
* is not known ahead of time. The loop selection
* function may use this stride to pick inner loops
* which are optimized for contiguous or 0-stride
* cases.
* out_innerloop: Should be populated with the correct ufunc inner
* loop for the given type.
* out_innerloopdata: Should be populated with the void* data to
Expand All @@ -101,15 +88,7 @@ typedef int (PyUFunc_LegacyInnerLoopSelectionFunc)(
PyUFuncGenericFunction *out_innerloop,
void **out_innerloopdata,
int *out_needs_api);
typedef int (PyUFunc_MaskedInnerLoopSelectionFunc)(
struct _tagPyUFuncObject *ufunc,
PyArray_Descr **dtypes,
PyArray_Descr *mask_dtype,
npy_intp *fixed_strides,
npy_intp fixed_mask_stride,
PyUFunc_MaskedStridedInnerLoopFunc **out_innerloop,
NpyAuxData **out_innerloopdata,
int *out_needs_api);


typedef struct _tagPyUFuncObject {
PyObject_HEAD
Expand Down Expand Up @@ -199,10 +178,8 @@ typedef struct _tagPyUFuncObject {
#else
void *reserved2;
#endif
/*
* A function which returns a masked inner loop for the ufunc.
*/
PyUFunc_MaskedInnerLoopSelectionFunc *masked_inner_loop_selector;
/* Was previously the `PyUFunc_MaskedInnerLoopSelectionFunc` */
void *_always_null_previously_masked_innerloop_selector;

/*
* List of flags for each operand when ufunc is called by nditer object.
Expand Down

0 comments on commit fa4a2cc

Please sign in to comment.