Created
May 31, 2018 05:04
-
-
Save mattip/eec3dd590f7012764ff9fb534a986251 to your computer and use it in GitHub Desktop.
diff for gufunc-signature-modification2
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/doc/source/reference/c-api.types-and-structures.rst b/doc/source/reference/c-api.types-and-structures.rst | |
index dcebd1e..e92cb1e 100644 | |
--- a/doc/source/reference/c-api.types-and-structures.rst | |
+++ b/doc/source/reference/c-api.types-and-structures.rst | |
@@ -133,9 +133,9 @@ PyArray_Type | |
is related to this array. There are two use cases: 1) If this array | |
does not own its own memory, then base points to the Python object | |
that owns it (perhaps another array object), 2) If this array has | |
- the (deprecated) :c:data:`NPY_ARRAY_UPDATEIFCOPY` or | |
+ the (deprecated) :c:data:`NPY_ARRAY_UPDATEIFCOPY` or | |
:c:data:NPY_ARRAY_WRITEBACKIFCOPY`: flag set, then this array is | |
- a working copy of a "misbehaved" array. When | |
+ a working copy of a "misbehaved" array. When | |
``PyArray_ResolveWritebackIfCopy`` is called, the array pointed to by base | |
will be updated with the contents of this array. | |
@@ -683,7 +683,9 @@ PyUFunc_Type | |
The core of the ufunc is the :c:type:`PyUFuncObject` which contains all | |
the information needed to call the underlying C-code loops that | |
- perform the actual work. It has the following structure: | |
+ perform the actual work. While it is described here for completeness, it | |
+ should be considered internal to NumPy and manipulated via ``PyUFunc_*`` | |
+ functions. It has the following structure: | |
.. code-block:: c | |
@@ -696,15 +698,29 @@ PyUFunc_Type | |
PyUFuncGenericFunction *functions; | |
void **data; | |
int ntypes; | |
- int reserved1; | |
+ int version; | |
const char *name; | |
char *types; | |
const char *doc; | |
void *ptr; | |
PyObject *obj; | |
PyObject *userloops; | |
+ int core_enabled; | |
+ int core_num_dim_ix; | |
+ int *core_num_dims; | |
+ int *core_dim_ixs; | |
+ int *core_offsets; | |
+ char *core_signature; | |
+ PyUFunc_TypeResolutionFunc *type_resolver; | |
+ PyUFunc_LegacyInnerLoopSelectionFunc *legacy_inner_loop_selector; | |
+ void *reserved2; | |
+ PyUFunc_MaskedInnerLoopSelectionFunc *masked_inner_loop_selector; | |
npy_uint32 *op_flags; | |
npy_uint32 *iter_flags; | |
+ /* new in version 1 */ | |
+ npy_intp *core_dim_sizes; | |
+ npy_uint32 *core_dim_flags; | |
+ | |
} PyUFuncObject; | |
.. c:macro: PyUFuncObject.PyObject_HEAD | |
@@ -764,6 +780,10 @@ PyUFunc_Type | |
specifies how many different 1-d loops (of the builtin data | |
types) are available. | |
+ .. c:member:: int PyUFuncObject.version | |
+ | |
+ The version of this struct, currently set to 1 | |
+ | |
.. c:member:: char *PyUFuncObject.name | |
A string name for the ufunc. This is used dynamically to build | |
@@ -804,6 +824,51 @@ PyUFunc_Type | |
User defined type numbers are always larger than | |
:c:data:`NPY_USERDEF`. | |
+ .. c:member:: int PyUFuncObject.core_enabled | |
+ | |
+ 0 for scalar ufuncs; 1 for generalized ufuncs | |
+ | |
+ .. c:member:: int PyUFuncObject.core_num_dim_ix | |
+ | |
+ Number of distinct core dimension names in the signature | |
+ | |
+ .. c:member:: int *PyUFuncObject.core_num_dims | |
+ | |
+ Number of core dimensions of each argument | |
+ | |
+ .. c:member:: int *PyUFuncObject.core_dim_ixs | |
+ | |
+ Dimension idices in a flattened form; indices of argument ``k`` are | |
+ stored in ``core_dim_ixs[core_offsets[k] : core_offsets[k] + | |
+ core_numdims[k]]`` | |
+ | |
+ .. c:member:: int *PyUFuncObject.core_offsets | |
+ | |
+ Position of 1st core dimension of each argument in ``core_dim_ixs``, | |
+ equivalent to cumsum(``core_num_dims``) | |
+ | |
+ .. c:member:: char *PyUFuncObject.core_signature | |
+ | |
+ Core signature string | |
+ | |
+ .. c:member:: PyUFunc_TypeResolutionFunc *PyUFuncObject.type_resolver | |
+ | |
+ A function which resolves the types and fills an array with the dtypes | |
+ for the inputs and outputs | |
+ | |
+ .. c:member:: PyUFunc_LegacyInnerLoopSelectionFunc *PyUFuncObject.legacy_inner_loop_selector | |
+ | |
+ A function which returns an inner loop written for NumPy 1.6 and earlier | |
+ ufuncs. This is for backwards compatibility, and may be NULL if | |
+ ``inner_loop_selector`` is specified | |
+ | |
+ .. c:member:: void *PyUFuncObject.reserved2 | |
+ | |
+ Not in use | |
+ | |
+ .. c:member:: PyUFunc_MaskedInnerLoopSelectionFunc *PyUFuncObject.masked_inner_loop_selector | |
+ | |
+ Function which returns a masked inner loop for the ufunc | |
.. c:member:: npy_uint32 PyUFuncObject.op_flags | |
@@ -813,6 +878,20 @@ PyUFunc_Type | |
Override the default nditer flags for the ufunc. | |
+ Added in version 1 | |
+ | |
+ .. c:member:: npy_intp *PyUFuncObject.core_dim_sizes | |
+ | |
+ For each distinct core dimension, the possible | |
+ "frozen" size (``-1`` if not frozen) | |
+ | |
+ .. c:member:: npy_uint32 *PyUFuncObject.core_dim_flags | |
+ | |
+ For each distinct core dimension, a set of flags ``OR`` ed together: | |
+ | |
+ - :c:data:`UFUNC_CORE_CAN_IGNORE` if the dim name ends in ``?`` | |
+ - :c:data:`UFUNC_CORE_FROZEN` if the dim is numerical (frozen) | |
+ | |
PyArrayIter_Type | |
---------------- | |
diff --git a/numpy/core/src/umath/_umath_tests.c.src b/numpy/core/src/umath/_umath_tests.c.src | |
index 160d8a4..d0afd53 100644 | |
--- a/numpy/core/src/umath/_umath_tests.c.src | |
+++ b/numpy/core/src/umath/_umath_tests.c.src | |
@@ -530,8 +530,8 @@ static PyMethodDef UMath_TestsMethods[] = { | |
{"test_signature", UMath_Tests_test_signature, METH_VARARGS, | |
"Test signature parsing of ufunc. \n" | |
"Arguments: nin nout signature \n" | |
- "If fails, it returns NULL. Otherwise it will returns 0 for scalar ufunc " | |
- "and 1 for generalized ufunc. \n", | |
+ "If fails, it returns NULL. Otherwise it returns a tuple of ufunc " | |
+ "internals. \n", | |
}, | |
{NULL, NULL, 0, NULL} /* Sentinel */ | |
}; | |
diff --git a/numpy/core/src/umath/ufunc_object.c b/numpy/core/src/umath/ufunc_object.c | |
index 6dae936..1c866a5 100644 | |
--- a/numpy/core/src/umath/ufunc_object.c | |
+++ b/numpy/core/src/umath/ufunc_object.c | |
@@ -2200,19 +2200,20 @@ _parse_axes_arg(PyUFuncObject *ufunc, int core_num_dims[], PyObject *axes, | |
* | |
* Returns 0 on success, and -1 on failure | |
* | |
- * The behavior has been changed in NumPy 1.10.0, and the following | |
+ * The behavior has been changed in NumPy 1.16.0, and the following | |
* requirements must be fulfilled or an error will be raised: | |
* * Arguments, both input and output, must have at least as many | |
* dimensions as the corresponding number of core dimensions. In | |
- * previous versions, 1's were prepended to the shape as needed. | |
+ * versions before 1.10, 1's were prepended to the shape as needed. | |
* * Core dimensions with same labels must have exactly matching sizes. | |
- * In previous versions, core dimensions of size 1 would broadcast | |
+ * In versions before 1.10, core dimensions of size 1 would broadcast | |
* against other core dimensions with the same label. | |
* * All core dimensions must have their size specified by a passed in | |
- * input or output argument. In previous versions, core dimensions in | |
+ * input or output argument. In versions before 1.10, core dimensions in | |
* an output argument that were not specified in an input argument, | |
* and whose size could not be inferred from a passed in output | |
* argument, would have their size set to 1. | |
+ * * Core dimensions may be fixed, new in ufunc->version 1 (NumPy 1.16) | |
*/ | |
static int | |
_get_coredim_sizes(PyUFuncObject *ufunc, PyArrayObject **op, | |
@@ -2223,9 +2224,16 @@ _get_coredim_sizes(PyUFuncObject *ufunc, PyArrayObject **op, | |
int nout = ufunc->nout; | |
int nop = nin + nout; | |
- for (j = 0; j < ufunc->core_num_dim_ix; ++j) { | |
- /* support fixed-size dim names */ | |
- core_dim_sizes[j] = ufunc->core_dim_sizes[j]; | |
+ if (ufunc->version > 0) { | |
+ for (j = 0; j < ufunc->core_num_dim_ix; ++j) { | |
+ /* support fixed-size dim names */ | |
+ core_dim_sizes[j] = ufunc->core_dim_sizes[j]; | |
+ } | |
+ } | |
+ else { | |
+ for (j = 0; j < ufunc->core_num_dim_ix; ++j) { | |
+ core_dim_sizes[j] = UFUNC_CORE_DIM_SIZE_UNSET; | |
+ } | |
} | |
for (i = 0; i < nop; ++i) { | |
if (op[i] != NULL) { | |
@@ -2421,9 +2429,17 @@ PyUFunc_GeneralizedFunction(PyUFuncObject *ufunc, | |
dtypes[i] = NULL; | |
arr_prep[i] = NULL; | |
} | |
+ | |
/* copy per-argument flags, so they can be changed */ | |
- for (idim = 0; idim < ufunc->core_num_dim_ix; ++idim) { | |
- core_dim_flags[idim] = ufunc->core_dim_flags[idim]; | |
+ if (ufunc->version > 0) { | |
+ for (idim = 0; idim < ufunc->core_num_dim_ix; ++idim) { | |
+ core_dim_flags[idim] = ufunc->core_dim_flags[idim]; | |
+ } | |
+ } | |
+ else { | |
+ for (idim = 0; idim < ufunc->core_num_dim_ix; ++idim) { | |
+ core_dim_flags[idim] = 0; | |
+ } | |
} | |
NPY_UF_DBG_PRINT("Getting arguments\n"); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment