8000 MAINT: Removed duplicated code around `ufunc->identity` · numpy/numpy@31fd25d · GitHub
[go: up one dir, main page]

Skip to content

Commit 31fd25d

Browse files
committed
MAINT: Removed duplicated code around ufunc->identity
There didn't seem to be any value to a `assign_identity` function - all we actually care about is the value to assign. This also fixes #8860 as a side-effect, and paves the way for: * easily adding more values (#7702) * using the identity in more places (#834)
1 parent 2995e6a commit 31fd25d

File tree

3 files changed

+88
-131
lines changed

3 files changed

+88
-131
lines changed

numpy/core/src/umath/reduction.c

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -411,8 +411,8 @@ PyArray_InitializeReduceResult(
411411

412412
/*
413413
* This function executes all the standard NumPy reduction function
414-
* boilerplate code, just calling assign_identity and the appropriate
415-
* inner loop function where necessary.
414+
* boilerplate code, just calling the appropriate inner loop function where
415+
* necessary.
416416
*
417417
* operand : The array to be reduced.
418418
* out : NULL, or the array into which to place the result.
@@ -432,11 +432,11 @@ PyArray_InitializeReduceResult(
10000
432432
* with size one.
433433
* subok : If true, the result uses the subclass of operand, otherwise
434434
* it is always a base class ndarray.
435-
* assign_identity : If NULL, PyArray_InitializeReduceResult is used, otherwise
436-
* this function is called to initialize the result to
435+
* identity : If Py_None, PyArray_InitializeReduceResult is used, otherwise
436+
* this value is used to initialize the result to
437437
* the reduction's unit.
438438
* loop : The loop which does the reduction.
439-
* data : Data which is passed to assign_identity and the inner loop.
439+
* data : Data which is passed to the inner loop.
440440
* buffersize : Buffer size for the iterator. For the default, pass in 0.
441441
* funcname : The name of the reduction function, for error messages.
442442
* errormask : forwarded from _get_bufsize_errmask
@@ -459,7 +459,7 @@ PyUFunc_ReduceWrapper(PyArrayObject *operand, PyArrayObject *out,
459459
npy_bool *axis_flags, int reorderable,
460460
int keepdims,
461461
int subok,
462-
PyArray_AssignReduceIdentityFunc *assign_identity,
462+
PyObject *identity,
463463
PyArray_ReduceLoopFunc *loop,
464464
void *data, npy_intp buffersize, const char *funcname,
465465
int errormask)
@@ -500,7 +500,7 @@ PyUFunc_ReduceWrapper(PyArrayObject *operand, PyArrayObject *out,
500500
* Initialize the result to the reduction unit if possible,
501501
* otherwise copy the initial values and get a view to the rest.
502502
*/
503-
if (assign_identity != NULL) {
503+
if (identity != Py_None) {
504504
/*
505505
* If this reduction is non-reorderable, make sure there are
506506
* only 0 or 1 axes in axis_flags.
@@ -510,7 +510,7 @@ PyUFunc_ReduceWrapper(PyArrayObject *operand, PyArrayObject *out,
510510
goto fail;
511511
}
512512

513-
if (assign_identity(result, data) < 0) {
513+
if (PyArray_FillWithScalar(result, identity) < 0) {
514514
goto fail;
515515
}
516516
op_view = operand;

numpy/core/src/umath/reduction.h

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -109,8 +109,8 @@ typedef int (PyArray_ReduceLoopFunc)(NpyIter *iter,
109109

110110
/*
111111
* This function executes all the standard NumPy reduction function
112-
* boilerplate code, just calling assign_identity and the appropriate
113-
* inner loop function where necessary.
112+
* boilerplate code, just calling the appropriate inner loop function where
113+
* necessary.
114114
*
115115
* operand : The array to be reduced.
116116
* out : NULL, or the array into which to place the result.
@@ -130,11 +130,11 @@ typedef int (PyArray_ReduceLoopFunc)(NpyIter *iter,
130130
* with size one.
131131
* subok : If true, the result uses the subclass of operand, otherwise
132132
* it is always a base class ndarray.
133-
* assign_identity : If NULL, PyArray_InitializeReduceResult is used, otherwise
134-
* this function is called to initialize the result to
133+
* identity : If Py_None, PyArray_InitializeReduceResult is used, otherwise
134+
* this value is used to initialize the result to
135135
* the reduction's unit.
136136
* loop : The loop which does the reduction.
137-
* data : Data which is passed to assign_identity and the inner loop.
137+
* data : Data which is passed to the inner loop.
138138
* buffersize : Buffer size for the iterator. For the default, pass in 0.
139139
* funcname : The name of the reduction function, for error messages.
140140
* errormask : forwarded from _get_bufsize_errmask
@@ -148,7 +148,7 @@ PyUFunc_ReduceWrapper(PyArrayObject *operand, PyArrayObject *out,
148148
npy_bool *axis_flags, int reorderable,
149149
int keepdims,
150150
int subok,
151-
PyArray_AssignReduceIdentityFunc *assign_identity,
151+
PyObject *identity,
152152
PyArray_ReduceLoopFunc *loop,
153153
void *data, npy_intp buffersize, const char *funcname,
154154
int errormask);

numpy/core/src/umath/ufunc_object.c

Lines changed: 74 additions & 117 deletions
Original file line numberDiff line numberDiff line change
@@ -70,16 +70,6 @@
7070
static int
7171
_does_loop_use_arrays(void *data);
7272

73-
static int
74-
assign_reduce_identity_zero(PyArrayObject *result, void *data);
75-
76-
static int
77-
assign_reduce_identity_minusone(PyArrayObject *result, void *data);
78-
79-
static int
80-
assign_reduce_identity_one(PyArrayObject *result, void *data);
81-
82-
8373
/*UFUNC_API*/
8474
NPY_NO_EXPORT int
8575
PyUFunc_getfperr(void)
@@ -1847,6 +1837,42 @@ _get_coredim_sizes(PyUFuncObject *ufunc, PyArrayObject **op,
18471837
return 0;
18481838
}
18491839

1840+
/*
1841+
* Returns a new reference
1842+
* TODO: store a reference in the ufunc object itself, rather than
1843+
* constructing one each time
1844+
*/
1845+
static PyObject *
1846+
_get_identity(PyUFuncObject *ufunc, npy_bool *reorderable) {
1847+
switch(ufunc->identity) {
1848+
case PyUFunc_One:
1849+
*reorderable = 1;
1850+
return PyInt_FromLong(1);
1851+
1852+
case PyUFunc_Zero:
1853+
*reorderable = 1;
1854+
return PyInt_FromLong(0);
1855+
1856+
case PyUFunc_MinusOne:
1857+
*reorderable = 1;
1858+
return PyInt_FromLong(-1);
1859+
1860+
case PyUFunc_ReorderableNone:
1861+
*reorderable = 1;
1862+
Py_RETURN_NONE;
1863+
1864+
case PyUFunc_None:
1865+
*reorderable = 0;
1866+
Py_RETURN_NONE;
1867+
1868+
default:
1869+
PyErr_Format(PyExc_ValueError,
1870+
"ufunc %s has an invalid identity", ufunc_get_name_cstr(ufunc));
1871+
return NULL;
1872+
}
1873+
}
1874+
1875+
18501876
static int
18511877
PyUFunc_GeneralizedFunction(PyUFuncObject *ufunc,
18521878
PyObject *args, PyObject *kwds,
@@ -2249,34 +2275,27 @@ PyUFunc_GeneralizedFunction(PyUFuncObject *ufunc,
22492275
* product of two zero-length arrays will be a scalar,
22502276
* which has size one.
22512277
*/
2278+
npy_bool reorderable;
2279+
PyObject *identity = _get_identity(ufunc, &reorderable);
2280+
if (identity == NULL) {
2281+
retval = -1;
2282+
goto fail;
2283+
}
2284+
22522285
for (i = nin; i < nop; ++i) {
22532286
if (PyArray_SIZE(op[i]) != 0) {
2254-
switch (ufunc->identity) {
2255-
case PyUFunc_Zero:
2256-
assign_reduce_identity_zero(op[i], NULL);
2257-
break;
2258-
case PyUFunc_One:
2259-
assign_reduce_identity_one(op[i], NULL);
2260-
break;
2261-
case PyUFunc_MinusOne:
2262-
assign_reduce_identity_minusone(op[i], NULL);
2263-
break;
2264-
case PyUFunc_None:
2265-
case PyUFunc_ReorderableNone:
2266-
PyErr_Format(PyExc_ValueError,
2267-
"ufunc %s ",
2268-
ufunc_name);
2269-
retval = -1;
2270-
goto fail;
2271-
default:
2272-
PyErr_Format(PyExc_ValueError,
2273-
"ufunc %s has an invalid identity for reduction",
2274-
ufunc_name);
2275-
retval = -1;
2276-
goto fail;
2287+
if (identity == Py_None) {
2288+
PyErr_Format(PyExc_ValueError,
2289+
"ufunc %s ",
2290+
ufunc_name);
2291+
Py_DECREF(identity);
2292+
retval = -1;
2293+
goto fail;
22772294
}
2295+
PyArray_FillWithScalar(op[i], identity);
22782296
}
22792297
}
2298+
Py_DECREF(identity);
22802299
}
22812300

22822301
/* Check whether any errors occurred during the loop */
@@ -2665,31 +2684,6 @@ reduce_type_resolver(PyUFuncObject *ufunc, PyArrayObject *arr,
26652684
return 0;
26662685
}
26672686

2668-
static int
2669-
assign_reduce_identity_zero(PyArrayObject *result, void *NPY_UNUSED(data))
2670-
{
2671-
return PyArray_FillWithScalar(result, PyArrayScalar_False);
2672-
}
2673-
2674-
static int
2675-
assign_reduce_identity_one(PyArrayObject *result, void *NPY_UNUSED(data))
2676-
{
2677-
return PyArray_FillWithScalar(result, PyArrayScalar_True);
2678-
}
2679-
2680-
static int
2681-
assign_reduce_identity_minusone(PyArrayObject *result, void *NPY_UNUSED(data))
2682-
{
2683-
static PyObject *MinusOne = NULL;
2684-
2685-
if (MinusOne == NULL) {
2686-
if ((MinusOne = PyInt_FromLong(-1)) == NULL) {
2687-
return -1;
2688-
}
2689-
}
2690-
return PyArray_FillWithScalar(result, MinusOne);
2691-
}
2692-
26932687
static int
26942688
reduce_loop(NpyIter *iter, char **dataptrs, npy_intp *strides,
26952689
npy_intp *countptr, NpyIter_IterNextFunc *iternext,
@@ -2795,11 +2789,12 @@ static PyArrayObject *
27952789
PyUFunc_Reduce(PyUFuncObject *ufunc, PyArrayObject *arr, PyArrayObject *out,
27962790
int naxes, int *axes, PyArray_Descr *odtype, int keepdims)
27972791
{
2798-
int iaxes, reorderable, ndim;
2792+
int iaxes, ndim;
2793+
npy_bool reorderable;
27992794
npy_bool axis_flags[NPY_MAXDIMS];
28002795
PyArray_Descr *dtype;
28012796
PyArrayObject *result;
2802-
PyArray_AssignReduceIdentityFunc *assign_identity = NULL;
2797+
PyObject *identity = NULL;
28032798
const char *ufunc_name = ufunc_get_name_cstr(ufunc);
28042799
/* These parameters come from a TLS global */
28052800
int buffersize = 0, errormask = 0;
@@ -2820,72 +2815,41 @@ PyUFunc_Reduce(PyUFuncObject *ufunc, PyArrayObject *arr, PyArrayObject *out,
28202815
axis_flags[axis] = 1;
28212816
}
28222817

2823-
switch (ufunc->identity) {
2824-
case PyUFunc_Zero:
2825-
assign_identity = &assign_reduce_identity_zero;
2826-
reorderable = 1;
2827-
/*
2828-
* The identity for a dynamic dtype like
2829-
* object arrays can't be used in general
2830-
*/
2831-
if (PyArray_ISOBJECT(arr) && PyArray_SIZE(arr) != 0) {
2832-
assign_identity = NULL;
2833-
}
2834-
break;
2835-
case PyUFunc_One:
2836-
assign_identity = &assign_reduce_identity_one;
2837-
reorderable = 1;
2838-
/*
2839-
* The identity for a dynamic dtype like
2840-
* object arrays can't be used in general
2841-
*/
2842-
if (PyArray_ISOBJECT(arr) && PyArray_SIZE(arr) != 0) {
2843-
assign_identity = NULL;
2844-
}
2845-
break;
2846-
case PyUFunc_MinusOne:
2847-
assign_identity = &assign_reduce_identity_minusone;
2848-
reorderable = 1;
2849-
/*
2850-
* The identity for a dynamic dtype like
2851-
* object arrays can't be used in general
2852-
*/
2853-
if (PyArray_ISOBJECT(arr) && PyArray_SIZE(arr) != 0) {
2854-
assign_identity = NULL;
2855-
}
2856-
break;
2857-
2858-
case PyUFunc_None:
2859-
reorderable = 0;
2860-
break;
2861-
case PyUFunc_ReorderableNone:
2862-
reorderable = 1;
2863-
break;
2864-
default:
2865-
PyErr_Format(PyExc_ValueError,
2866-
"ufunc %s has an invalid identity for reduction",
2867-
ufunc_name);
2868-
return NULL;
2818+
if (_get_bufsize_errmask(NULL, "reduce", &buffersize, &errormask) < 0) {
2819+
return NULL;
28692820
}
28702821

2871-
if (_get_bufsize_errmask(NULL, "reduce", &buffersize, &errormask) < 0) {
2822+
/* Get the identity */
2823+
identity = _get_identity(ufunc, &reorderable);
2824+
if (identity == NULL) {
28722825
return NULL;
28732826
}
2827+
/*
2828+
* The identity for a dynamic dtype like
2829+
* object arrays can't be used in general
2830+
*/
2831+
if (identity != Py_None && PyArray_ISOBJECT(arr) && PyArray_SIZE(arr) != 0) {
2832+
Py_DECREF(identity);
2833+
identity = Py_None;
2834+
Py_INCREF(identity);
2835+
}
28742836

28752837
/* Get the reduction dtype */
28762838
if (reduce_type_resolver(ufunc, arr, odtype, &dtype) < 0) {
2839+
Py_DECREF(identity);
28772840
return NULL;
28782841
}
28792842

28802843
result = PyUFunc_ReduceWrapper(arr, out, NULL, dtype, dtype,
28812844
NPY_UNSAFE_CASTING,
28822845
axis_flags, reorderable,
28832846
keepdims, 0,
2884-
assign_identity,
2847+
identity,
28852848
reduce_loop,
28862849
ufunc, buffersize, ufunc_name, errormask);
28872850

28882851
Py_DECREF(dtype);
2852+
Py_DECREF(identity);
28892853
return result;
28902854
}
28912855

@@ -5377,15 +5341,8 @@ ufunc_get_name(PyUFuncObject *ufunc)
53775341
static PyObject *
53785342
ufunc_get_identity(PyUFuncObject *ufunc)
53795343
{
5380-
switch(ufunc->identity) {
5381-
case PyUFunc_One:
5382-
return PyInt_FromLong(1);
5383-
case PyUFunc_Zero:
5384-
return PyInt_FromLong(0);
5385-
case PyUFunc_MinusOne:
5386-
return PyInt_FromLong(-1);
5387-
}
5388-
Py_RETURN_NONE;
5344+
npy_bool reorderable;
5345+
return _get_identity(ufunc, &reorderable);
53895346
}
53905347

53915348
static PyObject *

0 commit comments

Comments
 (0)
0