-
-
Notifications
You must be signed in to change notification settings - Fork 10.9k
ENH: Provide a hook for gufuncs to process core dimensions. #26908
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
a3f61e1
7ab2434
aedce12
a8dcfa8
ee89a1f
e71f7ae
30418e0
0586b38
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
The field `process_core_dims_func` is added to the PyUFuncObject. This is a pointer to a function typedef'd as typedef int (PyUFunc_ProcessCoreDimsFunc)( struct _tagPyUFuncObject *ufunc, npy_intp *core_dim_sizes); The author of a gufunc can set the field with a function that they implement. The function will be called when the gufunc is called. (The actual call is in the internal function _get_coredim_sizes.) The user-defined function can set an exception and return an error status if any of the core dimensions in `core_dim_sizes` do not satisfy the assumptions of the gufunc. The user-defined function can also *set* the value of core dimensions that are passed in as -1, meaning the correspond out parameter was not given. This allows calculations such pairwise distances (which generates m*(m-1)/2 output values for an input with shape (m, n)) and full convolution (generates m + n - 1 output values from two inputs with shapes m and n) to be implemented as gufuncs with automatic allocation of the output with the correct shape. The output shape is computed and set in the user-defined function.
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -65,6 +65,9 @@ typedef int (PyUFunc_TypeResolutionFunc)( | |
PyObject *type_tup, | ||
PyArray_Descr **out_dtypes); | ||
|
||
typedef int (PyUFunc_ProcessCoreDimsFunc)( | ||
struct _tagPyUFuncObject *ufunc, | ||
npy_intp *core_dim_sizes); | ||
|
||
typedef struct _tagPyUFuncObject { | ||
PyObject_HEAD | ||
|
@@ -191,6 +194,10 @@ typedef struct _tagPyUFuncObject { | |
/* A PyListObject of `(tuple of DTypes, ArrayMethod/Promoter)` */ | ||
PyObject *_loops; | ||
#endif | ||
#if NPY_FEATURE_VERSION >= NPY_2_1_API_VERSION | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just noticed, but just noting to not forget: |
||
/* User defined function to process core dimensions of a gufunc. */ | ||
PyUFunc_ProcessCoreDimsFunc *process_core_dims_func; | ||
#endif | ||
} PyUFuncObject; | ||
|
||
#include "arrayobject.h" | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1590,6 +1590,13 @@ _get_coredim_sizes(PyUFuncObject *ufunc, PyArrayObject **op, | |
} | ||
} | ||
|
||
if (ufunc->process_core_dims_func != NULL) { | ||
int status = ufunc->process_core_dims_func(ufunc, core_dim_sizes); | ||
if (status != 0) { | ||
return -1; | ||
} | ||
} | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So one thing we do not do here is sanity check the output. I.e. if the To be clear, I think that is OK, but it should be documented. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It is easy enough to pass a copy to There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think it matters, just occured to me that we should document that you may only validate (raise an error) or fill in There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I wavered a bit about whether or not to test, but in the end, making a mistake in the processing here is no different from making a mistake in the actual function that gets called - one can get a core dump regardless. So, agreed with @seberg that a check after the call is not needed. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. OK, I won't add the check! |
||
/* | ||
* Make sure no core dimension is unspecified. | ||
*/ | ||
|
@@ -4689,6 +4696,8 @@ PyUFunc_FromFuncAndDataAndSignatureAndIdentity(PyUFuncGenericFunction *func, voi | |
/* Type resolution and inner loop selection functions */ | ||
ufunc->type_resolver = &PyUFunc_DefaultTypeResolver; | ||
|
||
ufunc->process_core_dims_func = NULL; | ||
|
||
ufunc->op_flags = NULL; | ||
ufunc->_loops = NULL; | ||
if (nin + nout != 0) { | ||
|
Uh oh!
There was an error while loading. Please reload this page.