MCPcopy Create free account
hub / github.com/numpy/numpy / get_initial_from_ufunc

Function get_initial_from_ufunc

numpy/core/src/umath/legacy_array_method.c:265–327  ·  view source on GitHub ↗

* The default `get_reduction_initial` attempts to look up the identity * from the calling ufunc. This might fail, so we only call it when necessary. * * For internal number dtypes, we can easily cache it, so do so after the * first call by overriding the function with `copy_cache_initial`. * This path is not publicly available. That could be added, and for a * custom initial getter it shou

Source from the content-addressed store, hash-verified

263 * custom initial getter it should be static/compile time data anyway.
264 */
265static int
266get_initial_from_ufunc(
267 PyArrayMethod_Context *context, npy_bool reduction_is_empty,
268 char *initial)
269{
270 if (context->caller == NULL
271 || !PyObject_TypeCheck(context->caller, &PyUFunc_Type)) {
272 /* Impossible in NumPy 1.24; guard in case it becomes possible. */
273 PyErr_SetString(PyExc_ValueError,
274 "getting initial failed because it can only done for legacy "
275 "ufunc loops when the ufunc is provided.");
276 return -1;
277 }
278 npy_bool reorderable;
279 PyObject *identity_obj = PyUFunc_GetDefaultIdentity(
280 (PyUFuncObject *)context->caller, &reorderable);
281 if (identity_obj == NULL) {
282 return -1;
283 }
284 if (identity_obj == Py_None) {
285 /* UFunc has no idenity (should not happen) */
286 Py_DECREF(identity_obj);
287 return 0;
288 }
289 if (PyTypeNum_ISUNSIGNED(context->descriptors[1]->type_num)
290 && PyLong_CheckExact(identity_obj)) {
291 /*
292 * This is a bit of a hack until we have truly loop specific
293 * identities. Python -1 cannot be cast to unsigned so convert
294 * it to a NumPy scalar, but we use -1 for bitwise functions to
295 * signal all 1s.
296 * (A builtin identity would not overflow here, although we may
297 * unnecessary convert 0 and 1.)
298 */
299 Py_SETREF(identity_obj, PyObject_CallFunctionObjArgs(
300 (PyObject *)&PyLongArrType_Type, identity_obj, NULL));
301 if (identity_obj == NULL) {
302 return -1;
303 }
304 }
305 else if (context->descriptors[0]->type_num == NPY_OBJECT
306 && !reduction_is_empty) {
307 /* Allows `sum([object()])` to work, but use 0 when empty. */
308 Py_DECREF(identity_obj);
309 return 0;
310 }
311
312 int res = PyArray_Pack(context->descriptors[0], initial, identity_obj);
313 Py_DECREF(identity_obj);
314 if (res < 0) {
315 return -1;
316 }
317
318 if (PyTypeNum_ISNUMBER(context->descriptors[0]->type_num)) {
319 /* For numbers we can cache to avoid going via Python ints */
320 memcpy(context->method->legacy_initial, initial,
321 context->descriptors[0]->elsize);
322 context->method->get_reduction_initial = &copy_cached_initial;

Callers

nothing calls this directly

Calls 2

PyArray_PackFunction · 0.85

Tested by

no test coverage detected