Bug Summary

File:numpy/core/src/umath/ufunc_object.c
Warning:line 5487, column 11
PyObject ownership leak with reference count of 1

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name ufunc_object.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -analyzer-output=html -analyzer-checker=python -analyzer-disable-checker=deadcode -analyzer-config prune-paths=true,suppress-c++-stdlib=true,suppress-null-return-paths=false,crosscheck-with-z3=true,model-path=/opt/pyrefcon/lib/pyrefcon/models/models -analyzer-config experimental-enable-naive-ctu-analysis=true,ctu-dir=/tmp/pyrefcon/numpy/csa-scan,ctu-index-name=/tmp/pyrefcon/numpy/csa-scan/externalDefMap.txt,ctu-invocation-list=/tmp/pyrefcon/numpy/csa-scan/invocations.yaml,display-ctu-progress=false -setup-static-analyzer -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -target-feature +sse -target-feature +sse2 -target-feature +sse3 -tune-cpu generic -debug-info-kind=limited -dwarf-version=4 -debugger-tuning=gdb -fcoverage-compilation-dir=/tmp/pyrefcon/numpy -resource-dir /opt/pyrefcon/lib/clang/13.0.0 -isystem /opt/pyrefcon/lib/pyrefcon/models/python3.8 -D NDEBUG -D _FORTIFY_SOURCE=2 -D NPY_INTERNAL_BUILD=1 -D HAVE_NPY_CONFIG_H=1 -D _FILE_OFFSET_BITS=64 -D _LARGEFILE_SOURCE=1 -D _LARGEFILE64_SOURCE=1 -I build/src.linux-x86_64-3.8/numpy/core/src/common -I build/src.linux-x86_64-3.8/numpy/core/src/umath -I numpy/core/include -I build/src.linux-x86_64-3.8/numpy/core/include/numpy -I build/src.linux-x86_64-3.8/numpy/distutils/include -I numpy/core/src/common -I numpy/core/src -I numpy/core -I numpy/core/src/npymath -I numpy/core/src/multiarray -I numpy/core/src/umath -I numpy/core/src/npysort -I numpy/core/src/_simd -I build/src.linux-x86_64-3.8/numpy/core/src/common -I build/src.linux-x86_64-3.8/numpy/core/src/npymath -internal-isystem /opt/pyrefcon/lib/clang/13.0.0/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-result -Wsign-compare -Wall -Wformat -Werror=format-security -Wformat -Werror=format-security -Wdate-time -fdebug-compilation-dir=/tmp/pyrefcon/numpy -ferror-limit 19 -fwrapv -pthread -stack-protector 2 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /tmp/pyrefcon/numpy/csa-scan/reports -x c numpy/core/src/umath/ufunc_object.c

numpy/core/src/umath/ufunc_object.c

1/*
2 * Python Universal Functions Object -- Math for all types, plus fast
3 * arrays math
4 *
5 * Full description
6 *
7 * This supports mathematical (and Boolean) functions on arrays and other python
8 * objects. Math on large arrays of basic C types is rather efficient.
9 *
10 * Travis E. Oliphant 2005, 2006 oliphant@ee.byu.edu (oliphant.travis@ieee.org)
11 * Brigham Young University
12 *
13 * based on the
14 *
15 * Original Implementation:
16 * Copyright (c) 1995, 1996, 1997 Jim Hugunin, hugunin@mit.edu
17 *
18 * with inspiration and code from
19 * Numarray
20 * Space Science Telescope Institute
21 * J. Todd Miller
22 * Perry Greenfield
23 * Rick White
24 *
25 */
26#define _UMATHMODULE
27#define _MULTIARRAYMODULE
28#define NPY_NO_DEPRECATED_API0x0000000E NPY_API_VERSION0x0000000E
29
30#include "Python.h"
31#include "stddef.h"
32
33#include "npy_config.h"
34#include "npy_pycompat.h"
35#include "npy_argparse.h"
36
37#include "numpy/arrayobject.h"
38#include "numpy/ufuncobject.h"
39#include "numpy/arrayscalars.h"
40#include "lowlevel_strided_loops.h"
41#include "ufunc_type_resolution.h"
42#include "reduction.h"
43#include "mem_overlap.h"
44
45#include "ufunc_object.h"
46#include "override.h"
47#include "npy_import.h"
48#include "extobj.h"
49#include "common.h"
50#include "dtypemeta.h"
51#include "numpyos.h"
52
53/********** PRINTF DEBUG TRACING **************/
54#define NPY_UF_DBG_TRACING0 0
55
56#if NPY_UF_DBG_TRACING0
57#define NPY_UF_DBG_PRINT(s) {printf("%s", s)__printf_chk (2 - 1, "%s", s);fflush(stdoutstdout);}
58#define NPY_UF_DBG_PRINT1(s, p1) {printf((s), (p1))__printf_chk (2 - 1, (s), (p1));fflush(stdoutstdout);}
59#define NPY_UF_DBG_PRINT2(s, p1, p2) {printf(s, p1, p2)__printf_chk (2 - 1, s, p1, p2);fflush(stdoutstdout);}
60#define NPY_UF_DBG_PRINT3(s, p1, p2, p3) {printf(s, p1, p2, p3)__printf_chk (2 - 1, s, p1, p2, p3);fflush(stdoutstdout);}
61#else
62#define NPY_UF_DBG_PRINT(s)
63#define NPY_UF_DBG_PRINT1(s, p1)
64#define NPY_UF_DBG_PRINT2(s, p1, p2)
65#define NPY_UF_DBG_PRINT3(s, p1, p2, p3)
66#endif
67/**********************************************/
68
69typedef struct {
70 PyObject *in; /* The input arguments to the ufunc, a tuple */
71 PyObject *out; /* The output arguments, a tuple. If no non-None outputs are
72 provided, then this is NULL. */
73} ufunc_full_args;
74
75/* C representation of the context argument to __array_wrap__ */
76typedef struct {
77 PyUFuncObject *ufunc;
78 ufunc_full_args args;
79 int out_i;
80} _ufunc_context;
81
82/* Get the arg tuple to pass in the context argument to __array_wrap__ and
83 * __array_prepare__.
84 *
85 * Output arguments are only passed if at least one is non-None.
86 */
87static PyObject *
88_get_wrap_prepare_args(ufunc_full_args full_args) {
89 if (full_args.out == NULL((void*)0)) {
90 Py_INCREF(full_args.in)_Py_INCREF(((PyObject*)(full_args.in)));
91 return full_args.in;
92 }
93 else {
94 return PySequence_Concat(full_args.in, full_args.out);
95 }
96}
97
98/* ---------------------------------------------------------------- */
99
100static PyObject *
101prepare_input_arguments_for_outer(PyObject *args, PyUFuncObject *ufunc);
102
103
104/*UFUNC_API*/
105NPY_NO_EXPORT__attribute__((visibility("hidden"))) int
106PyUFunc_getfperr(void)
107{
108 /*
109 * non-clearing get was only added in 1.9 so this function always cleared
110 * keep it so just in case third party code relied on the clearing
111 */
112 char param = 0;
113 return npy_clear_floatstatus_barrier(&param);
114}
115
116#define HANDLEIT(NAME, str) {if (retstatus & NPY_FPE_##NAME) { \
117 handle = errmask & UFUNC_MASK_##NAME; \
118 if (handle && \
119 _error_handler(handle >> UFUNC_SHIFT_##NAME, \
120 errobj, str, retstatus, first) < 0) \
121 return -1; \
122 }}
123
124/*UFUNC_API*/
125NPY_NO_EXPORT__attribute__((visibility("hidden"))) int
126PyUFunc_handlefperr(int errmask, PyObject *errobj, int retstatus, int *first)
127{
128 int handle;
129 if (errmask && retstatus) {
130 HANDLEIT(DIVIDEBYZERO, "divide by zero");
131 HANDLEIT(OVERFLOW, "overflow");
132 HANDLEIT(UNDERFLOW, "underflow");
133 HANDLEIT(INVALID, "invalid value");
134 }
135 return 0;
136}
137
138#undef HANDLEIT
139
140
141/*UFUNC_API*/
142NPY_NO_EXPORT__attribute__((visibility("hidden"))) int
143PyUFunc_checkfperr(int errmask, PyObject *errobj, int *first)
144{
145 /* clearing is done for backward compatibility */
146 int retstatus;
147 retstatus = npy_clear_floatstatus_barrier((char*)&retstatus);
148
149 return PyUFunc_handlefperr(errmask, errobj, retstatus, first);
150}
151
152
153/* Checking the status flag clears it */
154/*UFUNC_API*/
155NPY_NO_EXPORT__attribute__((visibility("hidden"))) void
156PyUFunc_clearfperr()
157{
158 char param = 0;
159 npy_clear_floatstatus_barrier(&param);
160}
161
162/*
163 * This function analyzes the input arguments and determines an appropriate
164 * method (__array_prepare__ or __array_wrap__) function to call, taking it
165 * from the input with the highest priority. Return NULL if no argument
166 * defines the method.
167 */
168static PyObject*
169_find_array_method(PyObject *args, PyObject *method_name)
170{
171 int i, n_methods;
172 PyObject *obj;
173 PyObject *with_method[NPY_MAXARGS32], *methods[NPY_MAXARGS32];
174 PyObject *method = NULL((void*)0);
175
176 n_methods = 0;
177 for (i = 0; i < PyTuple_GET_SIZE(args)(((PyVarObject*)((((void) (0)), (PyTupleObject *)(args))))->
ob_size)
; i++) {
178 obj = PyTuple_GET_ITEM(args, i)((((void) (0)), (PyTupleObject *)(args))->ob_item[i]);
179 if (PyArray_CheckExact(obj)(((PyObject*)(obj))->ob_type == &PyArray_Type) || PyArray_IsAnyScalar(obj)((((((PyObject*)(obj))->ob_type) == (&PyGenericArrType_Type
) || PyType_IsSubtype((((PyObject*)(obj))->ob_type), (&
PyGenericArrType_Type)))) || ((((((PyObject*)(obj))->ob_type
) == (&PyFloat_Type) || PyType_IsSubtype((((PyObject*)(obj
))->ob_type), (&PyFloat_Type))) || ((((PyObject*)(obj)
)->ob_type) == (&PyComplex_Type) || PyType_IsSubtype((
((PyObject*)(obj))->ob_type), (&PyComplex_Type))) || (
(((((PyObject*)(obj))->ob_type))->tp_flags & ((1UL <<
24))) != 0) || ((((PyObject*)(obj))->ob_type) == &PyBool_Type
)) || ((((((PyObject*)(obj))->ob_type))->tp_flags &
((1UL << 27))) != 0) || ((((((PyObject*)(obj))->ob_type
))->tp_flags & ((1UL << 28))) != 0)))
) {
180 continue;
181 }
182 method = PyObject_GetAttr(obj, method_name);
183 if (method) {
184 if (PyCallable_Check(method)) {
185 with_method[n_methods] = obj;
186 methods[n_methods] = method;
187 ++n_methods;
188 }
189 else {
190 Py_DECREF(method)_Py_DECREF(((PyObject*)(method)));
191 method = NULL((void*)0);
192 }
193 }
194 else {
195 PyErr_Clear();
196 }
197 }
198 if (n_methods > 0) {
199 /* If we have some methods defined, find the one of highest priority */
200 method = methods[0];
201 if (n_methods > 1) {
202 double maxpriority = PyArray_GetPriority(with_method[0],
203 NPY_PRIORITY0.0);
204 for (i = 1; i < n_methods; ++i) {
205 double priority = PyArray_GetPriority(with_method[i],
206 NPY_PRIORITY0.0);
207 if (priority > maxpriority) {
208 maxpriority = priority;
209 Py_DECREF(method)_Py_DECREF(((PyObject*)(method)));
210 method = methods[i];
211 }
212 else {
213 Py_DECREF(methods[i])_Py_DECREF(((PyObject*)(methods[i])));
214 }
215 }
216 }
217 }
218 return method;
219}
220
221/*
222 * Returns an incref'ed pointer to the proper __array_prepare__/__array_wrap__
223 * method for a ufunc output argument, given the output argument `obj`, and the
224 * method chosen from the inputs `input_method`.
225 */
226static PyObject *
227_get_output_array_method(PyObject *obj, PyObject *method,
228 PyObject *input_method) {
229 if (obj != Py_None(&_Py_NoneStruct)) {
230 PyObject *ometh;
231
232 if (PyArray_CheckExact(obj)(((PyObject*)(obj))->ob_type == &PyArray_Type)) {
233 /*
234 * No need to wrap regular arrays - None signals to not call
235 * wrap/prepare at all
236 */
237 Py_RETURN_NONEreturn _Py_INCREF(((PyObject*)((&_Py_NoneStruct)))), (&
_Py_NoneStruct)
;
238 }
239
240 ometh = PyObject_GetAttr(obj, method);
241 if (ometh == NULL((void*)0)) {
242 PyErr_Clear();
243 }
244 else if (!PyCallable_Check(ometh)) {
245 Py_DECREF(ometh)_Py_DECREF(((PyObject*)(ometh)));
246 }
247 else {
248 /* Use the wrap/prepare method of the output if it's callable */
249 return ometh;
250 }
251 }
252
253 /* Fall back on the input's wrap/prepare */
254 Py_XINCREF(input_method)_Py_XINCREF(((PyObject*)(input_method)));
255 return input_method;
256}
257
258/*
259 * This function analyzes the input arguments
260 * and determines an appropriate __array_prepare__ function to call
261 * for the outputs.
262 *
263 * If an output argument is provided, then it is prepped
264 * with its own __array_prepare__ not with the one determined by
265 * the input arguments.
266 *
267 * if the provided output argument is already an ndarray,
268 * the prepping function is None (which means no prepping will
269 * be done --- not even PyArray_Return).
270 *
271 * A NULL is placed in output_prep for outputs that
272 * should just have PyArray_Return called.
273 */
274static void
275_find_array_prepare(ufunc_full_args args,
276 PyObject **output_prep, int nout)
277{
278 int i;
279 PyObject *prep;
280
281 /*
282 * Determine the prepping function given by the input arrays
283 * (could be NULL).
284 */
285 prep = _find_array_method(args.in, npy_um_str_array_prepare);
286 /*
287 * For all the output arrays decide what to do.
288 *
289 * 1) Use the prep function determined from the input arrays
290 * This is the default if the output array is not
291 * passed in.
292 *
293 * 2) Use the __array_prepare__ method of the output object.
294 * This is special cased for
295 * exact ndarray so that no PyArray_Return is
296 * done in that case.
297 */
298 if (args.out == NULL((void*)0)) {
299 for (i = 0; i < nout; i++) {
300 Py_XINCREF(prep)_Py_XINCREF(((PyObject*)(prep)));
301 output_prep[i] = prep;
302 }
303 }
304 else {
305 for (i = 0; i < nout; i++) {
306 output_prep[i] = _get_output_array_method(
307 PyTuple_GET_ITEM(args.out, i)((((void) (0)), (PyTupleObject *)(args.out))->ob_item[i]), npy_um_str_array_prepare, prep);
308 }
309 }
310 Py_XDECREF(prep)_Py_XDECREF(((PyObject*)(prep)));
311 return;
312}
313
314#define NPY_UFUNC_DEFAULT_INPUT_FLAGS0x00020000 | 0x00100000 | 0x40000000 \
315 NPY_ITER_READONLY0x00020000 | \
316 NPY_ITER_ALIGNED0x00100000 | \
317 NPY_ITER_OVERLAP_ASSUME_ELEMENTWISE0x40000000
318
319#define NPY_UFUNC_DEFAULT_OUTPUT_FLAGS0x00100000 | 0x01000000 | 0x08000000 | 0x02000000 | 0x40000000 \
320 NPY_ITER_ALIGNED0x00100000 | \
321 NPY_ITER_ALLOCATE0x01000000 | \
322 NPY_ITER_NO_BROADCAST0x08000000 | \
323 NPY_ITER_NO_SUBTYPE0x02000000 | \
324 NPY_ITER_OVERLAP_ASSUME_ELEMENTWISE0x40000000
325
326/* Called at module initialization to set the matmul ufunc output flags */
327NPY_NO_EXPORT__attribute__((visibility("hidden"))) int
328set_matmul_flags(PyObject *d)
329{
330 PyObject *matmul = _PyDict_GetItemStringWithError(d, "matmul");
331 if (matmul == NULL((void*)0)) {
332 return -1;
333 }
334 /*
335 * The default output flag NPY_ITER_OVERLAP_ASSUME_ELEMENTWISE allows
336 * perfectly overlapping input and output (in-place operations). While
337 * correct for the common mathematical operations, this assumption is
338 * incorrect in the general case and specifically in the case of matmul.
339 *
340 * NPY_ITER_UPDATEIFCOPY is added by default in
341 * PyUFunc_GeneralizedFunction, which is the variant called for gufuncs
342 * with a signature
343 *
344 * Enabling NPY_ITER_WRITEONLY can prevent a copy in some cases.
345 */
346 ((PyUFuncObject *)matmul)->op_flags[2] = (NPY_ITER_WRITEONLY0x00040000 |
347 NPY_ITER_UPDATEIFCOPY0x00800000 |
348 NPY_UFUNC_DEFAULT_OUTPUT_FLAGS0x00100000 | 0x01000000 | 0x08000000 | 0x02000000 | 0x40000000) &
349 ~NPY_ITER_OVERLAP_ASSUME_ELEMENTWISE0x40000000;
350 return 0;
351}
352
353
354/*
355 * Set per-operand flags according to desired input or output flags.
356 * op_flags[i] for i in input (as determined by ufunc->nin) will be
357 * merged with op_in_flags, perhaps overriding per-operand flags set
358 * in previous stages.
359 * op_flags[i] for i in output will be set to op_out_flags only if previously
360 * unset.
361 * The input flag behavior preserves backward compatibility, while the
362 * output flag behaviour is the "correct" one for maximum flexibility.
363 */
364NPY_NO_EXPORT__attribute__((visibility("hidden"))) void
365_ufunc_setup_flags(PyUFuncObject *ufunc, npy_uint32 op_in_flags,
366 npy_uint32 op_out_flags, npy_uint32 *op_flags)
367{
368 int nin = ufunc->nin;
369 int nout = ufunc->nout;
370 int nop = nin + nout, i;
371 /* Set up the flags */
372 for (i = 0; i < nin; ++i) {
373 op_flags[i] = ufunc->op_flags[i] | op_in_flags;
374 /*
375 * If READWRITE flag has been set for this operand,
376 * then clear default READONLY flag
377 */
378 if (op_flags[i] & (NPY_ITER_READWRITE0x00010000 | NPY_ITER_WRITEONLY0x00040000)) {
379 op_flags[i] &= ~NPY_ITER_READONLY0x00020000;
380 }
381 }
382 for (i = nin; i < nop; ++i) {
383 op_flags[i] = ufunc->op_flags[i] ? ufunc->op_flags[i] : op_out_flags;
384 }
385}
386
387/*
388 * This function analyzes the input arguments
389 * and determines an appropriate __array_wrap__ function to call
390 * for the outputs.
391 *
392 * If an output argument is provided, then it is wrapped
393 * with its own __array_wrap__ not with the one determined by
394 * the input arguments.
395 *
396 * if the provided output argument is already an array,
397 * the wrapping function is None (which means no wrapping will
398 * be done --- not even PyArray_Return).
399 *
400 * A NULL is placed in output_wrap for outputs that
401 * should just have PyArray_Return called.
402 */
403static void
404_find_array_wrap(ufunc_full_args args, npy_bool subok,
405 PyObject **output_wrap, int nin, int nout)
406{
407 int i;
408 PyObject *wrap = NULL((void*)0);
409
410 /*
411 * If a 'subok' parameter is passed and isn't True, don't wrap but put None
412 * into slots with out arguments which means return the out argument
413 */
414 if (!subok) {
415 goto handle_out;
416 }
417
418 /*
419 * Determine the wrapping function given by the input arrays
420 * (could be NULL).
421 */
422 wrap = _find_array_method(args.in, npy_um_str_array_wrap);
423
424 /*
425 * For all the output arrays decide what to do.
426 *
427 * 1) Use the wrap function determined from the input arrays
428 * This is the default if the output array is not
429 * passed in.
430 *
431 * 2) Use the __array_wrap__ method of the output object
432 * passed in. -- this is special cased for
433 * exact ndarray so that no PyArray_Return is
434 * done in that case.
435 */
436handle_out:
437 if (args.out == NULL((void*)0)) {
438 for (i = 0; i < nout; i++) {
439 Py_XINCREF(wrap)_Py_XINCREF(((PyObject*)(wrap)));
440 output_wrap[i] = wrap;
441 }
442 }
443 else {
444 for (i = 0; i < nout; i++) {
445 output_wrap[i] = _get_output_array_method(
446 PyTuple_GET_ITEM(args.out, i)((((void) (0)), (PyTupleObject *)(args.out))->ob_item[i]), npy_um_str_array_wrap, wrap);
447 }
448 }
449
450 Py_XDECREF(wrap)_Py_XDECREF(((PyObject*)(wrap)));
451}
452
453
454/*
455 * Apply the __array_wrap__ function with the given array and content.
456 *
457 * Interprets wrap=None and wrap=NULL as intended by _find_array_wrap
458 *
459 * Steals a reference to obj and wrap.
460 * Pass context=NULL to indicate there is no context.
461 */
462static PyObject *
463_apply_array_wrap(
464 PyObject *wrap, PyArrayObject *obj, _ufunc_context const *context) {
465 if (wrap == NULL((void*)0)) {
466 /* default behavior */
467 return PyArray_Return(obj);
468 }
469 else if (wrap == Py_None(&_Py_NoneStruct)) {
470 Py_DECREF(wrap)_Py_DECREF(((PyObject*)(wrap)));
471 return (PyObject *)obj;
472 }
473 else {
474 PyObject *res;
475 PyObject *py_context = NULL((void*)0);
476
477 /* Convert the context object to a tuple, if present */
478 if (context == NULL((void*)0)) {
479 py_context = Py_None(&_Py_NoneStruct);
480 Py_INCREF(py_context)_Py_INCREF(((PyObject*)(py_context)));
481 }
482 else {
483 PyObject *args_tup;
484 /* Call the method with appropriate context */
485 args_tup = _get_wrap_prepare_args(context->args);
486 if (args_tup == NULL((void*)0)) {
487 goto fail;
488 }
489 py_context = Py_BuildValue("OOi",
490 context->ufunc, args_tup, context->out_i);
491 Py_DECREF(args_tup)_Py_DECREF(((PyObject*)(args_tup)));
492 if (py_context == NULL((void*)0)) {
493 goto fail;
494 }
495 }
496 /* try __array_wrap__(obj, context) */
497 res = PyObject_CallFunctionObjArgs(wrap, obj, py_context, NULL((void*)0));
498 Py_DECREF(py_context)_Py_DECREF(((PyObject*)(py_context)));
499
500 /* try __array_wrap__(obj) if the context argument is not accepted */
501 if (res == NULL((void*)0) && PyErr_ExceptionMatches(PyExc_TypeError)) {
502 PyErr_Clear();
503 res = PyObject_CallFunctionObjArgs(wrap, obj, NULL((void*)0));
504 }
505 Py_DECREF(wrap)_Py_DECREF(((PyObject*)(wrap)));
506 Py_DECREF(obj)_Py_DECREF(((PyObject*)(obj)));
507 return res;
508 fail:
509 Py_DECREF(wrap)_Py_DECREF(((PyObject*)(wrap)));
510 Py_DECREF(obj)_Py_DECREF(((PyObject*)(obj)));
511 return NULL((void*)0);
512 }
513}
514
515
516/*UFUNC_API
517 *
518 * On return, if errobj is populated with a non-NULL value, the caller
519 * owns a new reference to errobj.
520 */
521NPY_NO_EXPORT__attribute__((visibility("hidden"))) int
522PyUFunc_GetPyValues(char *name, int *bufsize, int *errmask, PyObject **errobj)
523{
524 PyObject *ref = get_global_ext_obj();
525
526 return _extract_pyvals(ref, name, bufsize, errmask, errobj);
527}
528
529/* Return the position of next non-white-space char in the string */
530static int
531_next_non_white_space(const char* str, int offset)
532{
533 int ret = offset;
534 while (str[ret] == ' ' || str[ret] == '\t') {
535 ret++;
536 }
537 return ret;
538}
539
540static int
541_is_alpha_underscore(char ch)
542{
543 return (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z') || ch == '_';
544}
545
546static int
547_is_alnum_underscore(char ch)
548{
549 return _is_alpha_underscore(ch) || (ch >= '0' && ch <= '9');
550}
551
552/*
553 * Convert a string into a number
554 */
555static npy_intp
556_get_size(const char* str)
557{
558 char *stop;
559 npy_longlong size = NumPyOS_strtoll(str, &stop, 10);
560
561 if (stop == str || _is_alpha_underscore(*stop)) {
562 /* not a well formed number */
563 return -1;
564 }
565 if (size >= NPY_MAX_INTP9223372036854775807L || size <= NPY_MIN_INTP(-9223372036854775807L -1L)) {
566 /* len(str) too long */
567 return -1;
568 }
569 return size;
570}
571
572/*
573 * Return the ending position of a variable name including optional modifier
574 */
575static int
576_get_end_of_name(const char* str, int offset)
577{
578 int ret = offset;
579 while (_is_alnum_underscore(str[ret])) {
580 ret++;
581 }
582 if (str[ret] == '?') {
583 ret ++;
584 }
585 return ret;
586}
587
588/*
589 * Returns 1 if the dimension names pointed by s1 and s2 are the same,
590 * otherwise returns 0.
591 */
592static int
593_is_same_name(const char* s1, const char* s2)
594{
595 while (_is_alnum_underscore(*s1) && _is_alnum_underscore(*s2)) {
596 if (*s1 != *s2) {
597 return 0;
598 }
599 s1++;
600 s2++;
601 }
602 return !_is_alnum_underscore(*s1) && !_is_alnum_underscore(*s2);
603}
604
605/*
606 * Sets core_num_dim_ix, core_num_dims, core_dim_ixs, core_offsets,
607 * and core_signature in PyUFuncObject "ufunc". Returns 0 unless an
608 * error occurred.
609 */
610static int
611_parse_signature(PyUFuncObject *ufunc, const char *signature)
612{
613 size_t len;
614 char const **var_names;
615 int nd = 0; /* number of dimension of the current argument */
616 int cur_arg = 0; /* index into core_num_dims&core_offsets */
617 int cur_core_dim = 0; /* index into core_dim_ixs */
618 int i = 0;
619 char *parse_error = NULL((void*)0);
620
621 if (signature == NULL((void*)0)) {
622 PyErr_SetString(PyExc_RuntimeError,
623 "_parse_signature with NULL signature");
624 return -1;
625 }
626 len = strlen(signature);
627 ufunc->core_signature = PyArray_mallocPyMem_RawMalloc(sizeof(char) * (len+1));
628 if (ufunc->core_signature) {
629 strcpy(ufunc->core_signature, signature);
630 }
631 /* Allocate sufficient memory to store pointers to all dimension names */
632 var_names = PyArray_mallocPyMem_RawMalloc(sizeof(char const*) * len);
633 if (var_names == NULL((void*)0)) {
634 PyErr_NoMemory();
635 return -1;
636 }
637
638 ufunc->core_enabled = 1;
639 ufunc->core_num_dim_ix = 0;
640 ufunc->core_num_dims = PyArray_mallocPyMem_RawMalloc(sizeof(int) * ufunc->nargs);
641 ufunc->core_offsets = PyArray_mallocPyMem_RawMalloc(sizeof(int) * ufunc->nargs);
642 /* The next three items will be shrunk later */
643 ufunc->core_dim_ixs = PyArray_mallocPyMem_RawMalloc(sizeof(int) * len);
644 ufunc->core_dim_sizes = PyArray_mallocPyMem_RawMalloc(sizeof(npy_intp) * len);
645 ufunc->core_dim_flags = PyArray_mallocPyMem_RawMalloc(sizeof(npy_uint32) * len);
646
647 if (ufunc->core_num_dims == NULL((void*)0) || ufunc->core_dim_ixs == NULL((void*)0) ||
648 ufunc->core_offsets == NULL((void*)0) ||
649 ufunc->core_dim_sizes == NULL((void*)0) ||
650 ufunc->core_dim_flags == NULL((void*)0)) {
651 PyErr_NoMemory();
652 goto fail;
653 }
654 for (size_t j = 0; j < len; j++) {
655 ufunc->core_dim_flags[j] = 0;
656 }
657
658 i = _next_non_white_space(signature, 0);
659 while (signature[i] != '\0') {
660 /* loop over input/output arguments */
661 if (cur_arg == ufunc->nin) {
662 /* expect "->" */
663 if (signature[i] != '-' || signature[i+1] != '>') {
664 parse_error = "expect '->'";
665 goto fail;
666 }
667 i = _next_non_white_space(signature, i + 2);
668 }
669
670 /*
671 * parse core dimensions of one argument,
672 * e.g. "()", "(i)", or "(i,j)"
673 */
674 if (signature[i] != '(') {
675 parse_error = "expect '('";
676 goto fail;
677 }
678 i = _next_non_white_space(signature, i + 1);
679 while (signature[i] != ')') {
680 /* loop over core dimensions */
681 int ix, i_end;
682 npy_intp frozen_size;
683 npy_bool can_ignore;
684
685 if (signature[i] == '\0') {
686 parse_error = "unexpected end of signature string";
687 goto fail;
688 }
689 /*
690 * Is this a variable or a fixed size dimension?
691 */
692 if (_is_alpha_underscore(signature[i])) {
693 frozen_size = -1;
694 }
695 else {
696 frozen_size = (npy_intp)_get_size(signature + i);
697 if (frozen_size <= 0) {
698 parse_error = "expect dimension name or non-zero frozen size";
699 goto fail;
700 }
701 }
702 /* Is this dimension flexible? */
703 i_end = _get_end_of_name(signature, i);
704 can_ignore = (i_end > 0 && signature[i_end - 1] == '?');
705 /*
706 * Determine whether we already saw this dimension name,
707 * get its index, and set its properties
708 */
709 for(ix = 0; ix < ufunc->core_num_dim_ix; ix++) {
710 if (frozen_size > 0 ?
711 frozen_size == ufunc->core_dim_sizes[ix] :
712 _is_same_name(signature + i, var_names[ix])) {
713 break;
714 }
715 }
716 /*
717 * If a new dimension, store its properties; if old, check consistency.
718 */
719 if (ix == ufunc->core_num_dim_ix) {
720 ufunc->core_num_dim_ix++;
721 var_names[ix] = signature + i;
722 ufunc->core_dim_sizes[ix] = frozen_size;
723 if (frozen_size < 0) {
724 ufunc->core_dim_flags[ix] |= UFUNC_CORE_DIM_SIZE_INFERRED0x0002;
725 }
726 if (can_ignore) {
727 ufunc->core_dim_flags[ix] |= UFUNC_CORE_DIM_CAN_IGNORE0x0004;
728 }
729 } else {
730 if (can_ignore && !(ufunc->core_dim_flags[ix] &
731 UFUNC_CORE_DIM_CAN_IGNORE0x0004)) {
732 parse_error = "? cannot be used, name already seen without ?";
733 goto fail;
734 }
735 if (!can_ignore && (ufunc->core_dim_flags[ix] &
736 UFUNC_CORE_DIM_CAN_IGNORE0x0004)) {
737 parse_error = "? must be used, name already seen with ?";
738 goto fail;
739 }
740 }
741 ufunc->core_dim_ixs[cur_core_dim] = ix;
742 cur_core_dim++;
743 nd++;
744 i = _next_non_white_space(signature, i_end);
745 if (signature[i] != ',' && signature[i] != ')') {
746 parse_error = "expect ',' or ')'";
747 goto fail;
748 }
749 if (signature[i] == ',')
750 {
751 i = _next_non_white_space(signature, i + 1);
752 if (signature[i] == ')') {
753 parse_error = "',' must not be followed by ')'";
754 goto fail;
755 }
756 }
757 }
758 ufunc->core_num_dims[cur_arg] = nd;
759 ufunc->core_offsets[cur_arg] = cur_core_dim-nd;
760 cur_arg++;
761 nd = 0;
762
763 i = _next_non_white_space(signature, i + 1);
764 if (cur_arg != ufunc->nin && cur_arg != ufunc->nargs) {
765 /*
766 * The list of input arguments (or output arguments) was
767 * only read partially
768 */
769 if (signature[i] != ',') {
770 parse_error = "expect ','";
771 goto fail;
772 }
773 i = _next_non_white_space(signature, i + 1);
774 }
775 }
776 if (cur_arg != ufunc->nargs) {
777 parse_error = "incomplete signature: not all arguments found";
778 goto fail;
779 }
780 ufunc->core_dim_ixs = PyArray_reallocPyMem_RawRealloc(ufunc->core_dim_ixs,
781 sizeof(int) * cur_core_dim);
782 ufunc->core_dim_sizes = PyArray_reallocPyMem_RawRealloc(
783 ufunc->core_dim_sizes,
784 sizeof(npy_intp) * ufunc->core_num_dim_ix);
785 ufunc->core_dim_flags = PyArray_reallocPyMem_RawRealloc(
786 ufunc->core_dim_flags,
787 sizeof(npy_uint32) * ufunc->core_num_dim_ix);
788
789 /* check for trivial core-signature, e.g. "(),()->()" */
790 if (cur_core_dim == 0) {
791 ufunc->core_enabled = 0;
792 }
793 PyArray_freePyMem_RawFree((void*)var_names);
794 return 0;
795
796fail:
797 PyArray_freePyMem_RawFree((void*)var_names);
798 if (parse_error) {
799 PyErr_Format(PyExc_ValueError,
800 "%s at position %d in \"%s\"",
801 parse_error, i, signature);
802 }
803 return -1;
804}
805
806/*
807 * Checks if 'obj' is a valid output array for a ufunc, i.e. it is
808 * either None or a writeable array, increments its reference count
809 * and stores a pointer to it in 'store'. Returns 0 on success, sets
810 * an exception and returns -1 on failure.
811 */
812static int
813_set_out_array(PyObject *obj, PyArrayObject **store)
814{
815 if (obj == Py_None(&_Py_NoneStruct)) {
816 /* Translate None to NULL */
817 return 0;
818 }
819 if (PyArray_Check(obj)((((PyObject*)(obj))->ob_type) == (&PyArray_Type) || PyType_IsSubtype
((((PyObject*)(obj))->ob_type), (&PyArray_Type)))
) {
820 /* If it's an array, store it */
821 if (PyArray_FailUnlessWriteable((PyArrayObject *)obj,
822 "output array") < 0) {
823 return -1;
824 }
825 Py_INCREF(obj)_Py_INCREF(((PyObject*)(obj)));
826 *store = (PyArrayObject *)obj;
827
828 return 0;
829 }
830 PyErr_SetString(PyExc_TypeError, "return arrays must be of ArrayType");
831
832 return -1;
833}
834
835/********* GENERIC UFUNC USING ITERATOR *********/
836
837/*
838 * Produce a name for the ufunc, if one is not already set
839 * This is used in the PyUFunc_handlefperr machinery, and in error messages
840 */
841NPY_NO_EXPORT__attribute__((visibility("hidden"))) const char*
842ufunc_get_name_cstr(PyUFuncObject *ufunc) {
843 return ufunc->name ? ufunc->name : "<unnamed ufunc>";
844}
845
846
847/*
848 * Converters for use in parsing of keywords arguments.
849 */
850static int
851_subok_converter(PyObject *obj, npy_bool *subok)
852{
853 if (PyBool_Check(obj)((((PyObject*)(obj))->ob_type) == &PyBool_Type)) {
854 *subok = (obj == Py_True((PyObject *) &_Py_TrueStruct));
855 return NPY_SUCCEED1;
856 }
857 else {
858 PyErr_SetString(PyExc_TypeError,
859 "'subok' must be a boolean");
860 return NPY_FAIL0;
861 }
862}
863
864static int
865_keepdims_converter(PyObject *obj, int *keepdims)
866{
867 if (PyBool_Check(obj)((((PyObject*)(obj))->ob_type) == &PyBool_Type)) {
868 *keepdims = (obj == Py_True((PyObject *) &_Py_TrueStruct));
869 return NPY_SUCCEED1;
870 }
871 else {
872 PyErr_SetString(PyExc_TypeError,
873 "'keepdims' must be a boolean");
874 return NPY_FAIL0;
875 }
876}
877
878static int
879_wheremask_converter(PyObject *obj, PyArrayObject **wheremask)
880{
881 /*
882 * Optimization: where=True is the same as no where argument.
883 * This lets us document True as the default.
884 */
885 if (obj == Py_True((PyObject *) &_Py_TrueStruct)) {
886 return NPY_SUCCEED1;
887 }
888 else {
889 PyArray_Descr *dtype = PyArray_DescrFromType(NPY_BOOL);
890 if (dtype == NULL((void*)0)) {
891 return NPY_FAIL0;
892 }
893 /* PyArray_FromAny steals reference to dtype, even on failure */
894 *wheremask = (PyArrayObject *)PyArray_FromAny(obj, dtype, 0, 0, 0, NULL((void*)0));
895 if ((*wheremask) == NULL((void*)0)) {
896 return NPY_FAIL0;
897 }
898 return NPY_SUCCEED1;
899 }
900}
901
902
903/*
904 * Due to the array override, do the actual parameter conversion
905 * only in this step. This function takes the reference objects and
906 * parses them into the desired values.
907 * This function cleans up after itself and NULLs references on error,
908 * however, the caller has to ensure that `out_op[0:nargs]` and `out_whermeask`
909 * are NULL initialized.
910 */
911static int
912convert_ufunc_arguments(PyUFuncObject *ufunc,
913 ufunc_full_args full_args, PyArrayObject **out_op,
914 PyObject *order_obj, NPY_ORDER *out_order,
915 PyObject *casting_obj, NPY_CASTING *out_casting,
916 PyObject *subok_obj, npy_bool *out_subok,
917 PyObject *where_obj, PyArrayObject **out_wheremask, /* PyArray of bool */
918 PyObject *keepdims_obj, int *out_keepdims)
919{
920 int nin = ufunc->nin;
921 int nout = ufunc->nout;
922 int nop = ufunc->nargs;
923 PyObject *obj;
924
925 /* Convert and fill in input arguments */
926 for (int i = 0; i < nin; i++) {
927 obj = PyTuple_GET_ITEM(full_args.in, i)((((void) (0)), (PyTupleObject *)(full_args.in))->ob_item[
i])
;
928
929 if (PyArray_Check(obj)((((PyObject*)(obj))->ob_type) == (&PyArray_Type) || PyType_IsSubtype
((((PyObject*)(obj))->ob_type), (&PyArray_Type)))
) {
930 PyArrayObject *obj_a = (PyArrayObject *)obj;
931 out_op[i] = (PyArrayObject *)PyArray_FromArray(obj_a, NULL((void*)0), 0);
932 }
933 else {
934 out_op[i] = (PyArrayObject *)PyArray_FromAny(obj,
935 NULL((void*)0), 0, 0, 0, NULL((void*)0));
936 }
937
938 if (out_op[i] == NULL((void*)0)) {
939 goto fail;
940 }
941 }
942
943 /* Convert and fill in output arguments */
944 if (full_args.out != NULL((void*)0)) {
945 for (int i = 0; i < nout; i++) {
946 obj = PyTuple_GET_ITEM(full_args.out, i)((((void) (0)), (PyTupleObject *)(full_args.out))->ob_item
[i])
;
947 if (_set_out_array(obj, out_op + i + nin) < 0) {
948 goto fail;
949 }
950 }
951 }
952
953 /*
954 * Convert most arguments manually here, since it is easier to handle
955 * the ufunc override if we first parse only to objects.
956 */
957 if (where_obj && !_wheremask_converter(where_obj, out_wheremask)) {
958 goto fail;
959 }
960 if (keepdims_obj && !_keepdims_converter(keepdims_obj, out_keepdims)) {
961 goto fail;
962 }
963 if (casting_obj && !PyArray_CastingConverter(casting_obj, out_casting)) {
964 goto fail;
965 }
966 if (order_obj && !PyArray_OrderConverter(order_obj, out_order)) {
967 goto fail;
968 }
969 if (subok_obj && !_subok_converter(subok_obj, out_subok)) {
970 goto fail;
971 }
972 return 0;
973
974fail:
975 if (out_wheremask != NULL((void*)0)) {
976 Py_XSETREF(*out_wheremask, NULL)do { PyObject *_py_tmp = ((PyObject*)(*out_wheremask)); (*out_wheremask
) = (((void*)0)); _Py_XDECREF(((PyObject*)(_py_tmp))); } while
(0)
;
977 }
978 for (int i = 0; i < nop; i++) {
979 Py_XSETREF(out_op[i], NULL)do { PyObject *_py_tmp = ((PyObject*)(out_op[i])); (out_op[i]
) = (((void*)0)); _Py_XDECREF(((PyObject*)(_py_tmp))); } while
(0)
;
980 }
981 return -1;
982}
983
984/*
985 * This checks whether a trivial loop is ok,
986 * making copies of scalar and one dimensional operands if that will
987 * help.
988 *
989 * Returns 1 if a trivial loop is ok, 0 if it is not, and
990 * -1 if there is an error.
991 */
992static int
993check_for_trivial_loop(PyUFuncObject *ufunc,
994 PyArrayObject **op,
995 PyArray_Descr **dtype,
996 npy_intp buffersize)
997{
998 npy_intp i, nin = ufunc->nin, nop = nin + ufunc->nout;
999
1000 for (i = 0; i < nop; ++i) {
1001 /*
1002 * If the dtype doesn't match, or the array isn't aligned,
1003 * indicate that the trivial loop can't be done.
1004 */
1005 if (op[i] != NULL((void*)0) &&
1006 (!PyArray_ISALIGNED(op[i])PyArray_CHKFLAGS((op[i]), 0x0100) ||
1007 !PyArray_EquivTypes(dtype[i], PyArray_DESCR(op[i]))
1008 )) {
1009 /*
1010 * If op[j] is a scalar or small one dimensional
1011 * array input, make a copy to keep the opportunity
1012 * for a trivial loop.
1013 */
1014 if (i < nin && (PyArray_NDIM(op[i]) == 0 ||
1015 (PyArray_NDIM(op[i]) == 1 &&
1016 PyArray_DIM(op[i],0) <= buffersize))) {
1017 PyArrayObject *tmp;
1018 Py_INCREF(dtype[i])_Py_INCREF(((PyObject*)(dtype[i])));
1019 tmp = (PyArrayObject *)
1020 PyArray_CastToType(op[i], dtype[i], 0);
1021 if (tmp == NULL((void*)0)) {
1022 return -1;
1023 }
1024 Py_DECREF(op[i])_Py_DECREF(((PyObject*)(op[i])));
1025 op[i] = tmp;
1026 }
1027 else {
1028 return 0;
1029 }
1030 }
1031 }
1032
1033 return 1;
1034}
1035
1036
1037/*
1038 * Calls the given __array_prepare__ function on the operand *op,
1039 * substituting it in place if a new array is returned and matches
1040 * the old one.
1041 *
1042 * This requires that the dimensions, strides and data type remain
1043 * exactly the same, which may be more strict than before.
1044 */
1045static int
1046prepare_ufunc_output(PyUFuncObject *ufunc,
1047 PyArrayObject **op,
1048 PyObject *arr_prep,
1049 ufunc_full_args full_args,
1050 int i)
1051{
1052 if (arr_prep != NULL((void*)0) && arr_prep != Py_None(&_Py_NoneStruct)) {
1053 PyObject *res;
1054 PyArrayObject *arr;
1055 PyObject *args_tup;
1056
1057 /* Call with the context argument */
1058 args_tup = _get_wrap_prepare_args(full_args);
1059 if (args_tup == NULL((void*)0)) {
1060 return -1;
1061 }
1062 res = PyObject_CallFunction(
1063 arr_prep, "O(OOi)", *op, ufunc, args_tup, i);
1064 Py_DECREF(args_tup)_Py_DECREF(((PyObject*)(args_tup)));
1065
1066 if (res == NULL((void*)0)) {
1067 return -1;
1068 }
1069 else if (!PyArray_Check(res)((((PyObject*)(res))->ob_type) == (&PyArray_Type) || PyType_IsSubtype
((((PyObject*)(res))->ob_type), (&PyArray_Type)))
) {
1070 PyErr_SetString(PyExc_TypeError,
1071 "__array_prepare__ must return an "
1072 "ndarray or subclass thereof");
1073 Py_DECREF(res)_Py_DECREF(((PyObject*)(res)));
1074 return -1;
1075 }
1076 arr = (PyArrayObject *)res;
1077
1078 /* If the same object was returned, nothing to do */
1079 if (arr == *op) {
1080 Py_DECREF(arr)_Py_DECREF(((PyObject*)(arr)));
1081 }
1082 /* If the result doesn't match, throw an error */
1083 else if (PyArray_NDIM(arr) != PyArray_NDIM(*op) ||
1084 !PyArray_CompareLists(PyArray_DIMS(arr),
1085 PyArray_DIMS(*op),
1086 PyArray_NDIM(arr)) ||
1087 !PyArray_CompareLists(PyArray_STRIDES(arr),
1088 PyArray_STRIDES(*op),
1089 PyArray_NDIM(arr)) ||
1090 !PyArray_EquivTypes(PyArray_DESCR(arr),
1091 PyArray_DESCR(*op))) {
1092 PyErr_SetString(PyExc_TypeError,
1093 "__array_prepare__ must return an "
1094 "ndarray or subclass thereof which is "
1095 "otherwise identical to its input");
1096 Py_DECREF(arr)_Py_DECREF(((PyObject*)(arr)));
1097 return -1;
1098 }
1099 /* Replace the op value */
1100 else {
1101 Py_DECREF(*op)_Py_DECREF(((PyObject*)(*op)));
1102 *op = arr;
1103 }
1104 }
1105
1106 return 0;
1107}
1108
1109
1110/*
1111 * Check whether a trivial loop is possible and call the innerloop if it is.
1112 * A trivial loop is defined as one where a single strided inner-loop call
1113 * is possible.
1114 *
1115 * This function only supports a single output (due to the overlap check).
1116 * It always accepts 0-D arrays and will broadcast them. The function
1117 * cannot broadcast any other array (as it requires a single stride).
1118 * The function accepts all 1-D arrays, and N-D arrays that are either all
1119 * C- or all F-contiguous.
1120 *
1121 * Returns -2 if a trivial loop is not possible, 0 on success and -1 on error.
1122 */
1123static NPY_INLINEinline int
1124try_trivial_single_output_loop(PyUFuncObject *ufunc,
1125 PyArrayObject *op[], PyArray_Descr *dtypes[],
1126 NPY_ORDER order, PyObject *arr_prep[], ufunc_full_args full_args,
1127 PyUFuncGenericFunction innerloop, void *innerloopdata)
1128{
1129 int nin = ufunc->nin;
1130 int nop = nin + 1;
1131 assert(ufunc->nout == 1)((void) (0));
1132
1133 /* The order of all N-D contiguous operands, can be fixed by `order` */
1134 int operation_order = 0;
1135 if (order == NPY_CORDER) {
1136 operation_order = NPY_ARRAY_C_CONTIGUOUS0x0001;
1137 }
1138 else if (order == NPY_FORTRANORDER) {
1139 operation_order = NPY_ARRAY_F_CONTIGUOUS0x0002;
1140 }
1141
1142 int operation_ndim = 0;
1143 npy_intp *operation_shape = NULL((void*)0);
1144 npy_intp fixed_strides[NPY_MAXARGS32];
1145
1146 for (int iop = 0; iop < nop; iop++) {
1147 if (op[iop] == NULL((void*)0)) {
1148 /* The out argument may be NULL (and only that one); fill later */
1149 assert(iop == nin)((void) (0));
1150 continue;
1151 }
1152
1153 int op_ndim = PyArray_NDIM(op[iop]);
1154
1155 /* Special case 0-D since we can handle broadcasting using a 0-stride */
1156 if (op_ndim == 0) {
1157 fixed_strides[iop] = 0;
1158 continue;
1159 }
1160
1161 /* First non 0-D op: fix dimensions, shape (order is fixed later) */
1162 if (operation_ndim == 0) {
1163 operation_ndim = op_ndim;
1164 operation_shape = PyArray_SHAPE(op[iop]);
1165 }
1166 else if (op_ndim != operation_ndim) {
1167 return -2; /* dimension mismatch (except 0-d ops) */
1168 }
1169 else if (!PyArray_CompareLists(
1170 operation_shape, PyArray_DIMS(op[iop]), op_ndim)) {
1171 return -2; /* shape mismatch */
1172 }
1173
1174 if (op_ndim == 1) {
1175 fixed_strides[iop] = PyArray_STRIDES(op[iop])[0];
1176 }
1177 else {
1178 fixed_strides[iop] = PyArray_ITEMSIZE(op[iop]); /* contiguous */
1179
1180 /* This op must match the operation order (and be contiguous) */
1181 int op_order = (PyArray_FLAGS(op[iop]) &
1182 (NPY_ARRAY_C_CONTIGUOUS0x0001|NPY_ARRAY_F_CONTIGUOUS0x0002));
1183 if (op_order == 0) {
1184 return -2; /* N-dimensional op must be contiguous */
1185 }
1186 else if (operation_order == 0) {
1187 operation_order = op_order; /* op fixes order */
1188 }
1189 else if (operation_order != op_order) {
1190 return -2;
1191 }
1192 }
1193 }
1194
1195 if (op[nin] == NULL((void*)0)) {
1196 Py_INCREF(dtypes[nin])_Py_INCREF(((PyObject*)(dtypes[nin])));
1197 op[nin] = (PyArrayObject *) PyArray_NewFromDescr(&PyArray_Type,
1198 dtypes[nin], operation_ndim, operation_shape,
1199 NULL((void*)0), NULL((void*)0), operation_order==NPY_ARRAY_F_CONTIGUOUS0x0002, NULL((void*)0));
1200 if (op[nin] == NULL((void*)0)) {
1201 return -1;
1202 }
1203 fixed_strides[nin] = dtypes[nin]->elsize;
1204 }
1205 else {
1206 /* If any input overlaps with the output, we use the full path. */
1207 for (int iop = 0; iop < nin; iop++) {
1208 if (!PyArray_EQUIVALENTLY_ITERABLE_OVERLAP_OK(
1209 op[iop], op[nin],
1210 PyArray_TRIVIALLY_ITERABLE_OP_READ1,
1211 PyArray_TRIVIALLY_ITERABLE_OP_NOREAD0)) {
1212 return -2;
1213 }
1214 }
1215 /* Check self-overlap (non 1-D are contiguous, perfect overlap is OK) */
1216 if (operation_ndim == 1 &&
1217 PyArray_STRIDES(op[nin])[0] < PyArray_ITEMSIZE(op[nin]) &&
1218 PyArray_STRIDES(op[nin])[0] != 0) {
1219 return -2;
1220 }
1221 }
1222
1223 /* Call the __prepare_array__ if necessary */
1224 if (prepare_ufunc_output(ufunc, &op[nin],
1225 arr_prep[0], full_args, 0) < 0) {
1226 return -1;
1227 }
1228
1229 /*
1230 * We can use the trivial (single inner-loop call) optimization
1231 * and `fixed_strides` holds the strides for that call.
1232 */
1233 char *data[NPY_MAXARGS32];
1234 npy_intp count = PyArray_MultiplyList(operation_shape, operation_ndim);
1235 int needs_api = 0;
1236 NPY_BEGIN_THREADS_DEFPyThreadState *_save=((void*)0);;
1237
1238 for (int iop = 0; iop < nop; iop++) {
1239 data[iop] = PyArray_BYTES(op[iop]);
1240 needs_api |= PyDataType_REFCHK(dtypes[iop])(((dtypes[iop])->flags & (0x01)) == (0x01));
1241 }
1242
1243 if (!needs_api) {
1244 NPY_BEGIN_THREADS_THRESHOLDED(count)do { if ((count) > 500) { _save = PyEval_SaveThread();} } while
(0);
;
1245 }
1246
1247 innerloop(data, &count, fixed_strides, innerloopdata);
1248
1249 NPY_END_THREADSdo { if (_save) { PyEval_RestoreThread(_save); _save = ((void
*)0);} } while (0);
;
1250 return 0;
1251}
1252
1253
1254static int
1255iterator_loop(PyUFuncObject *ufunc,
1256 PyArrayObject **op,
1257 PyArray_Descr **dtype,
1258 NPY_ORDER order,
1259 npy_intp buffersize,
1260 PyObject **arr_prep,
1261 ufunc_full_args full_args,
1262 PyUFuncGenericFunction innerloop,
1263 void *innerloopdata,
1264 npy_uint32 *op_flags)
1265{
1266 npy_intp i, nin = ufunc->nin, nout = ufunc->nout;
1267 npy_intp nop = nin + nout;
1268 NpyIter *iter;
1269 char *baseptrs[NPY_MAXARGS32];
1270
1271 NpyIter_IterNextFunc *iternext;
1272 char **dataptr;
1273 npy_intp *stride;
1274 npy_intp *count_ptr;
1275 int needs_api;
1276
1277 PyArrayObject **op_it;
1278 npy_uint32 iter_flags;
1279
1280 NPY_BEGIN_THREADS_DEFPyThreadState *_save=((void*)0);;
1281
1282 iter_flags = ufunc->iter_flags |
1283 NPY_ITER_EXTERNAL_LOOP0x00000008 |
1284 NPY_ITER_REFS_OK0x00000020 |
1285 NPY_ITER_ZEROSIZE_OK0x00000040 |
1286 NPY_ITER_BUFFERED0x00000200 |
1287 NPY_ITER_GROWINNER0x00000400 |
1288 NPY_ITER_DELAY_BUFALLOC0x00000800 |
1289 NPY_ITER_COPY_IF_OVERLAP0x00002000;
1290
1291 /* Call the __array_prepare__ functions for already existing output arrays.
1292 * Do this before creating the iterator, as the iterator may UPDATEIFCOPY
1293 * some of them.
1294 */
1295 for (i = 0; i < nout; ++i) {
1296 if (op[nin+i] == NULL((void*)0)) {
1297 continue;
1298 }
1299 if (prepare_ufunc_output(ufunc, &op[nin+i],
1300 arr_prep[i], full_args, i) < 0) {
1301 return -1;
1302 }
1303 }
1304
1305 /*
1306 * Allocate the iterator. Because the types of the inputs
1307 * were already checked, we use the casting rule 'unsafe' which
1308 * is faster to calculate.
1309 */
1310 iter = NpyIter_AdvancedNew(nop, op,
1311 iter_flags,
1312 order, NPY_UNSAFE_CASTING,
1313 op_flags, dtype,
1314 -1, NULL((void*)0), NULL((void*)0), buffersize);
1315 if (iter == NULL((void*)0)) {
1316 return -1;
1317 }
1318
1319 /* Copy any allocated outputs */
1320 op_it = NpyIter_GetOperandArray(iter);
1321 for (i = 0; i < nout; ++i) {
1322 if (op[nin+i] == NULL((void*)0)) {
1323 op[nin+i] = op_it[nin+i];
1324 Py_INCREF(op[nin+i])_Py_INCREF(((PyObject*)(op[nin+i])));
1325
1326 /* Call the __array_prepare__ functions for the new array */
1327 if (prepare_ufunc_output(ufunc, &op[nin+i],
1328 arr_prep[i], full_args, i) < 0) {
1329 NpyIter_Deallocate(iter);
1330 return -1;
1331 }
1332
1333 /*
1334 * In case __array_prepare__ returned a different array, put the
1335 * results directly there, ignoring the array allocated by the
1336 * iterator.
1337 *
1338 * Here, we assume the user-provided __array_prepare__ behaves
1339 * sensibly and doesn't return an array overlapping in memory
1340 * with other operands --- the op[nin+i] array passed to it is newly
1341 * allocated and doesn't have any overlap.
1342 */
1343 baseptrs[nin+i] = PyArray_BYTES(op[nin+i]);
1344 }
1345 else {
1346 baseptrs[nin+i] = PyArray_BYTES(op_it[nin+i]);
1347 }
1348 }
1349
1350 /* Only do the loop if the iteration size is non-zero */
1351 if (NpyIter_GetIterSize(iter) != 0) {
1352 /* Reset the iterator with the base pointers from possible __array_prepare__ */
1353 for (i = 0; i < nin; ++i) {
1354 baseptrs[i] = PyArray_BYTES(op_it[i]);
1355 }
1356 if (NpyIter_ResetBasePointers(iter, baseptrs, NULL((void*)0)) != NPY_SUCCEED1) {
1357 NpyIter_Deallocate(iter);
1358 return -1;
1359 }
1360
1361 /* Get the variables needed for the loop */
1362 iternext = NpyIter_GetIterNext(iter, NULL((void*)0));
1363 if (iternext == NULL((void*)0)) {
1364 NpyIter_Deallocate(iter);
1365 return -1;
1366 }
1367 dataptr = NpyIter_GetDataPtrArray(iter);
1368 stride = NpyIter_GetInnerStrideArray(iter);
1369 count_ptr = NpyIter_GetInnerLoopSizePtr(iter);
1370 needs_api = NpyIter_IterationNeedsAPI(iter);
1371
1372 NPY_BEGIN_THREADS_NDITER(iter)do { if (!NpyIter_IterationNeedsAPI(iter)) { do { if ((NpyIter_GetIterSize
(iter)) > 500) { _save = PyEval_SaveThread();} } while (0)
;; } } while(0)
;
1373
1374 /* Execute the loop */
1375 do {
1376 NPY_UF_DBG_PRINT1("iterator loop count %d\n", (int)*count_ptr);
1377 innerloop(dataptr, count_ptr, stride, innerloopdata);
1378 } while (!(needs_api && PyErr_Occurred()) && iternext(iter));
1379
1380 NPY_END_THREADSdo { if (_save) { PyEval_RestoreThread(_save); _save = ((void
*)0);} } while (0);
;
1381 }
1382 /*
1383 * Currently `innerloop` may leave an error set, in this case
1384 * NpyIter_Deallocate will always return an error as well.
1385 */
1386 if (NpyIter_Deallocate(iter) == NPY_FAIL0) {
1387 return -1;
1388 }
1389 return 0;
1390}
1391
1392/*
1393 * ufunc - the ufunc to call
1394 * trivial_loop_ok - 1 if no alignment, data conversion, etc required
1395 * op - the operands (ufunc->nin + ufunc->nout of them)
1396 * dtypes - the dtype of each operand
1397 * order - the loop execution order/output memory order
1398 * buffersize - how big of a buffer to use
1399 * arr_prep - the __array_prepare__ functions for the outputs
1400 * full_args - the original input, output PyObject *
1401 * op_flags - per-operand flags, a combination of NPY_ITER_* constants
1402 */
1403static int
1404execute_legacy_ufunc_loop(PyUFuncObject *ufunc,
1405 int trivial_loop_ok,
1406 PyArrayObject **op,
1407 PyArray_Descr **dtypes,
1408 NPY_ORDER order,
1409 npy_intp buffersize,
1410 PyObject **arr_prep,
1411 ufunc_full_args full_args,
1412 npy_uint32 *op_flags)
1413{
1414 PyUFuncGenericFunction innerloop;
1415 void *innerloopdata;
1416 int needs_api = 0;
1417
1418 if (ufunc->legacy_inner_loop_selector(ufunc, dtypes,
1419 &innerloop, &innerloopdata, &needs_api) < 0) {
1420 return -1;
1421 }
1422
1423 /* First check for the trivial cases that don't need an iterator */
1424 if (trivial_loop_ok && ufunc->nout == 1) {
1425 int fast_path_result = try_trivial_single_output_loop(ufunc,
1426 op, dtypes, order, arr_prep, full_args,
1427 innerloop, innerloopdata);
1428 if (fast_path_result != -2) {
1429 return fast_path_result;
1430 }
1431 }
1432
1433 /*
1434 * If no trivial loop matched, an iterator is required to
1435 * resolve broadcasting, etc
1436 */
1437 NPY_UF_DBG_PRINT("iterator loop\n");
1438 if (iterator_loop(ufunc, op, dtypes, order,
1439 buffersize, arr_prep, full_args,
1440 innerloop, innerloopdata, op_flags) < 0) {
1441 return -1;
1442 }
1443
1444 return 0;
1445}
1446
1447/*
1448 * nin - number of inputs
1449 * nout - number of outputs
1450 * wheremask - if not NULL, the 'where=' parameter to the ufunc.
1451 * op - the operands (nin + nout of them)
1452 * order - the loop execution order/output memory order
1453 * buffersize - how big of a buffer to use
1454 * arr_prep - the __array_prepare__ functions for the outputs
1455 * innerloop - the inner loop function
1456 * innerloopdata - data to pass to the inner loop
1457 */
1458static int
1459execute_fancy_ufunc_loop(PyUFuncObject *ufunc,
1460 PyArrayObject *wheremask,
1461 PyArrayObject **op,
1462 PyArray_Descr **dtypes,
1463 NPY_ORDER order,
1464 npy_intp buffersize,
1465 PyObject **arr_prep,
1466 ufunc_full_args full_args,
1467 npy_uint32 *op_flags)
1468{
1469 int i, nin = ufunc->nin, nout = ufunc->nout;
1470 int nop = nin + nout;
1471 NpyIter *iter;
1472 int needs_api;
1473
1474 NpyIter_IterNextFunc *iternext;
1475 char **dataptr;
1476 npy_intp *strides;
1477 npy_intp *countptr;
1478
1479 PyArrayObject **op_it;
1480 npy_uint32 iter_flags;
1481
1482 for (i = nin; i < nop; ++i) {
1483 op_flags[i] |= (op[i] != NULL((void*)0) ? NPY_ITER_READWRITE0x00010000 : NPY_ITER_WRITEONLY0x00040000);
1484 }
1485
1486 if (wheremask != NULL((void*)0)) {
1487 op_flags[nop] = NPY_ITER_READONLY0x00020000 | NPY_ITER_ARRAYMASK0x20000000;
1488 }
1489
1490 NPY_UF_DBG_PRINT("Making iterator\n");
1491
1492 iter_flags = ufunc->iter_flags |
1493 NPY_ITER_EXTERNAL_LOOP0x00000008 |
1494 NPY_ITER_REFS_OK0x00000020 |
1495 NPY_ITER_ZEROSIZE_OK0x00000040 |
1496 NPY_ITER_BUFFERED0x00000200 |
1497 NPY_ITER_GROWINNER0x00000400 |
1498 NPY_ITER_COPY_IF_OVERLAP0x00002000;
1499
1500 /*
1501 * Allocate the iterator. Because the types of the inputs
1502 * were already checked, we use the casting rule 'unsafe' which
1503 * is faster to calculate.
1504 */
1505 iter = NpyIter_AdvancedNew(nop + ((wheremask != NULL((void*)0)) ? 1 : 0), op,
1506 iter_flags,
1507 order, NPY_UNSAFE_CASTING,
1508 op_flags, dtypes,
1509 -1, NULL((void*)0), NULL((void*)0), buffersize);
1510 if (iter == NULL((void*)0)) {
1511 return -1;
1512 }
1513
1514 NPY_UF_DBG_PRINT("Made iterator\n");
1515
1516 needs_api = NpyIter_IterationNeedsAPI(iter);
1517
1518 /* Call the __array_prepare__ functions where necessary */
1519 op_it = NpyIter_GetOperandArray(iter);
1520 for (i = nin; i < nop; ++i) {
1521 PyArrayObject *op_tmp, *orig_op_tmp;
1522
1523 /*
1524 * The array can be allocated by the iterator -- it is placed in op[i]
1525 * and returned to the caller, and this needs an extra incref.
1526 */
1527 if (op[i] == NULL((void*)0)) {
1528 op_tmp = op_it[i];
1529 Py_INCREF(op_tmp)_Py_INCREF(((PyObject*)(op_tmp)));
1530 }
1531 else {
1532 op_tmp = op[i];
1533 }
1534
1535 /* prepare_ufunc_output may decref & replace the pointer */
1536 orig_op_tmp = op_tmp;
1537 Py_INCREF(op_tmp)_Py_INCREF(((PyObject*)(op_tmp)));
1538
1539 if (prepare_ufunc_output(ufunc, &op_tmp,
1540 arr_prep[i], full_args, i) < 0) {
1541 NpyIter_Deallocate(iter);
1542 return -1;
1543 }
1544
1545 /* Validate that the prepare_ufunc_output didn't mess with pointers */
1546 if (PyArray_BYTES(op_tmp) != PyArray_BYTES(orig_op_tmp)) {
1547 PyErr_SetString(PyExc_ValueError,
1548 "The __array_prepare__ functions modified the data "
1549 "pointer addresses in an invalid fashion");
1550 Py_DECREF(op_tmp)_Py_DECREF(((PyObject*)(op_tmp)));
1551 NpyIter_Deallocate(iter);
1552 return -1;
1553 }
1554
1555 /*
1556 * Put the updated operand back and undo the DECREF above. If
1557 * COPY_IF_OVERLAP made a temporary copy, the output will be copied
1558 * by UPDATEIFCOPY even if op[i] was changed by prepare_ufunc_output.
1559 */
1560 op[i] = op_tmp;
1561 Py_DECREF(op_tmp)_Py_DECREF(((PyObject*)(op_tmp)));
1562 }
1563
1564 /* Only do the loop if the iteration size is non-zero */
1565 if (NpyIter_GetIterSize(iter) != 0) {
1566 PyUFunc_MaskedStridedInnerLoopFunc *innerloop;
1567 NpyAuxData *innerloopdata;
1568 npy_intp fixed_strides[2*NPY_MAXARGS32];
1569 PyArray_Descr **iter_dtypes;
1570 NPY_BEGIN_THREADS_DEFPyThreadState *_save=((void*)0);;
1571
1572 /*
1573 * Get the inner loop, with the possibility of specialization
1574 * based on the fixed strides.
1575 */
1576 NpyIter_GetInnerFixedStrideArray(iter, fixed_strides);
1577 iter_dtypes = NpyIter_GetDescrArray(iter);
1578 if (ufunc->masked_inner_loop_selector(ufunc, dtypes,
1579 wheremask != NULL((void*)0) ? iter_dtypes[nop]
1580 : iter_dtypes[nop + nin],
1581 fixed_strides,
1582 wheremask != NULL((void*)0) ? fixed_strides[nop]
1583 : fixed_strides[nop + nin],
1584 &innerloop, &innerloopdata, &needs_api) < 0) {
1585 NpyIter_Deallocate(iter);
1586 return -1;
1587 }
1588
1589 /* Get the variables needed for the loop */
1590 iternext = NpyIter_GetIterNext(iter, NULL((void*)0));
1591 if (iternext == NULL((void*)0)) {
1592 NpyIter_Deallocate(iter);
1593 return -1;
1594 }
1595 dataptr = NpyIter_GetDataPtrArray(iter);
1596 strides = NpyIter_GetInnerStrideArray(iter);
1597 countptr = NpyIter_GetInnerLoopSizePtr(iter);
1598 needs_api = NpyIter_IterationNeedsAPI(iter);
1599
1600 NPY_BEGIN_THREADS_NDITER(iter)do { if (!NpyIter_IterationNeedsAPI(iter)) { do { if ((NpyIter_GetIterSize
(iter)) > 500) { _save = PyEval_SaveThread();} } while (0)
;; } } while(0)
;
1601
1602 NPY_UF_DBG_PRINT("Actual inner loop:\n");
1603 /* Execute the loop */
1604 do {
1605 NPY_UF_DBG_PRINT1("iterator loop count %d\n", (int)*countptr);
1606 innerloop(dataptr, strides,
1607 dataptr[nop], strides[nop],
1608 *countptr, innerloopdata);
1609 } while (!(needs_api && PyErr_Occurred()) && iternext(iter));
1610
1611 NPY_END_THREADSdo { if (_save) { PyEval_RestoreThread(_save); _save = ((void
*)0);} } while (0);
;
1612
1613 NPY_AUXDATA_FREE(innerloopdata)do { if ((innerloopdata) != ((void*)0)) { (innerloopdata)->
free(innerloopdata); } } while(0)
;
1614 }
1615
1616 return NpyIter_Deallocate(iter);
1617}
1618
1619
1620/*
1621 * Validate that operands have enough dimensions, accounting for
1622 * possible flexible dimensions that may be absent.
1623 */
1624static int
1625_validate_num_dims(PyUFuncObject *ufunc, PyArrayObject **op,
1626 npy_uint32 *core_dim_flags,
1627 int *op_core_num_dims) {
1628 int i, j;
1629 int nin = ufunc->nin;
1630 int nop = ufunc->nargs;
1631
1632 for (i = 0; i < nop; i++) {
1633 if (op[i] != NULL((void*)0)) {
1634 int op_ndim = PyArray_NDIM(op[i]);
1635
1636 if (op_ndim < op_core_num_dims[i]) {
1637 int core_offset = ufunc->core_offsets[i];
1638 /* We've too few, but some dimensions might be flexible */
1639 for (j = core_offset;
1640 j < core_offset + ufunc->core_num_dims[i]; j++) {
1641 int core_dim_index = ufunc->core_dim_ixs[j];
1642 if ((core_dim_flags[core_dim_index] &
1643 UFUNC_CORE_DIM_CAN_IGNORE0x0004)) {
1644 int i1, j1, k;
1645 /*
1646 * Found a dimension that can be ignored. Flag that
1647 * it is missing, and unflag that it can be ignored,
1648 * since we are doing so already.
1649 */
1650 core_dim_flags[core_dim_index] |= UFUNC_CORE_DIM_MISSING0x00040000;
1651 core_dim_flags[core_dim_index] ^= UFUNC_CORE_DIM_CAN_IGNORE0x0004;
1652 /*
1653 * Reduce the number of core dimensions for all
1654 * operands that use this one (including ours),
1655 * and check whether we're now OK.
1656 */
1657 for (i1 = 0, k=0; i1 < nop; i1++) {
1658 for (j1 = 0; j1 < ufunc->core_num_dims[i1]; j1++) {
1659 if (ufunc->core_dim_ixs[k++] == core_dim_index) {
1660 op_core_num_dims[i1]--;
1661 }
1662 }
1663 }
1664 if (op_ndim == op_core_num_dims[i]) {
1665 break;
1666 }
1667 }
1668 }
1669 if (op_ndim < op_core_num_dims[i]) {
1670 PyErr_Format(PyExc_ValueError,
1671 "%s: %s operand %d does not have enough "
1672 "dimensions (has %d, gufunc core with "
1673 "signature %s requires %d)",
1674 ufunc_get_name_cstr(ufunc),
1675 i < nin ? "Input" : "Output",
1676 i < nin ? i : i - nin, PyArray_NDIM(op[i]),
1677 ufunc->core_signature, op_core_num_dims[i]);
1678 return -1;
1679 }
1680 }
1681 }
1682 }
1683 return 0;
1684}
1685
1686/*
1687 * Check whether any of the outputs of a gufunc has core dimensions.
1688 */
1689static int
1690_has_output_coredims(PyUFuncObject *ufunc) {
1691 int i;
1692 for (i = ufunc->nin; i < ufunc->nin + ufunc->nout; ++i) {
1693 if (ufunc->core_num_dims[i] > 0) {
1694 return 1;
1695 }
1696 }
1697 return 0;
1698}
1699
1700/*
1701 * Check whether the gufunc can be used with axis, i.e., that there is only
1702 * a single, shared core dimension (which means that operands either have
1703 * that dimension, or have no core dimensions). Returns 0 if all is fine,
1704 * and sets an error and returns -1 if not.
1705 */
1706static int
1707_check_axis_support(PyUFuncObject *ufunc) {
1708 if (ufunc->core_num_dim_ix != 1) {
1709 PyErr_Format(PyExc_TypeError,
1710 "%s: axis can only be used with a single shared core "
1711 "dimension, not with the %d distinct ones implied by "
1712 "signature %s.",
1713 ufunc_get_name_cstr(ufunc),
1714 ufunc->core_num_dim_ix,
1715 ufunc->core_signature);
1716 return -1;
1717 }
1718 return 0;
1719}
1720
1721/*
1722 * Check whether the gufunc can be used with keepdims, i.e., that all its
1723 * input arguments have the same number of core dimension, and all output
1724 * arguments have no core dimensions. Returns 0 if all is fine, and sets
1725 * an error and returns -1 if not.
1726 */
1727static int
1728_check_keepdims_support(PyUFuncObject *ufunc) {
1729 int i;
1730 int nin = ufunc->nin, nout = ufunc->nout;
1731 int input_core_dims = ufunc->core_num_dims[0];
1732 for (i = 1; i < nin + nout; i++) {
1733 if (ufunc->core_num_dims[i] != (i < nin ? input_core_dims : 0)) {
1734 PyErr_Format(PyExc_TypeError,
1735 "%s does not support keepdims: its signature %s requires "
1736 "%s %d to have %d core dimensions, but keepdims can only "
1737 "be used when all inputs have the same number of core "
1738 "dimensions and all outputs have no core dimensions.",
1739 ufunc_get_name_cstr(ufunc),
1740 ufunc->core_signature,
1741 i < nin ? "input" : "output",
1742 i < nin ? i : i - nin,
1743 ufunc->core_num_dims[i]);
1744 return -1;
1745 }
1746 }
1747 return 0;
1748}
1749
1750/*
1751 * Interpret a possible axes keyword argument, using it to fill the remap_axis
1752 * array which maps default to actual axes for each operand, indexed as
1753 * as remap_axis[iop][iaxis]. The default axis order has first all broadcast
1754 * axes and then the core axes the gufunc operates on.
1755 *
1756 * Returns 0 on success, and -1 on failure
1757 */
1758static int
1759_parse_axes_arg(PyUFuncObject *ufunc, int op_core_num_dims[], PyObject *axes,
1760 PyArrayObject **op, int broadcast_ndim, int **remap_axis) {
1761 int nin = ufunc->nin;
1762 int nop = ufunc->nargs;
1763 int iop, list_size;
1764
1765 if (!PyList_Check(axes)((((((PyObject*)(axes))->ob_type))->tp_flags & ((1UL
<< 25))) != 0)
) {
1766 PyErr_SetString(PyExc_TypeError, "axes should be a list.");
1767 return -1;
1768 }
1769 list_size = PyList_Size(axes);
1770 if (list_size != nop) {
1771 if (list_size != nin || _has_output_coredims(ufunc)) {
1772 PyErr_Format(PyExc_ValueError,
1773 "axes should be a list with an entry for all "
1774 "%d inputs and outputs; entries for outputs can only "
1775 "be omitted if none of them has core axes.",
1776 nop);
1777 return -1;
1778 }
1779 for (iop = nin; iop < nop; iop++) {
1780 remap_axis[iop] = NULL((void*)0);
1781 }
1782 }
1783 for (iop = 0; iop < list_size; ++iop) {
1784 int op_ndim, op_ncore, op_nbroadcast;
1785 int have_seen_axis[NPY_MAXDIMS32] = {0};
1786 PyObject *op_axes_tuple, *axis_item;
1787 int axis, op_axis;
1788
1789 op_ncore = op_core_num_dims[iop];
1790 if (op[iop] != NULL((void*)0)) {
1791 op_ndim = PyArray_NDIM(op[iop]);
1792 op_nbroadcast = op_ndim - op_ncore;
1793 }
1794 else {
1795 op_nbroadcast = broadcast_ndim;
1796 op_ndim = broadcast_ndim + op_ncore;
1797 }
1798 /*
1799 * Get axes tuple for operand. If not a tuple already, make it one if
1800 * there is only one axis (its content is checked later).
1801 */
1802 op_axes_tuple = PyList_GET_ITEM(axes, iop)(((PyListObject *)(axes))->ob_item[iop]);
1803 if (PyTuple_Check(op_axes_tuple)((((((PyObject*)(op_axes_tuple))->ob_type))->tp_flags &
((1UL << 26))) != 0)
) {
1804 if (PyTuple_Size(op_axes_tuple) != op_ncore) {
1805 if (op_ncore == 1) {
1806 PyErr_Format(PyExc_ValueError,
1807 "axes item %d should be a tuple with a "
1808 "single element, or an integer", iop);
1809 }
1810 else {
1811 PyErr_Format(PyExc_ValueError,
1812 "axes item %d should be a tuple with %d "
1813 "elements", iop, op_ncore);
1814 }
1815 return -1;
1816 }
1817 Py_INCREF(op_axes_tuple)_Py_INCREF(((PyObject*)(op_axes_tuple)));
1818 }
1819 else if (op_ncore == 1) {
1820 op_axes_tuple = PyTuple_Pack(1, op_axes_tuple);
1821 if (op_axes_tuple == NULL((void*)0)) {
1822 return -1;
1823 }
1824 }
1825 else {
1826 PyErr_Format(PyExc_TypeError, "axes item %d should be a tuple",
1827 iop);
1828 return -1;
1829 }
1830 /*
1831 * Now create the remap, starting with the core dimensions, and then
1832 * adding the remaining broadcast axes that are to be iterated over.
1833 */
1834 for (axis = op_nbroadcast; axis < op_ndim; axis++) {
1835 axis_item = PyTuple_GET_ITEM(op_axes_tuple, axis - op_nbroadcast)((((void) (0)), (PyTupleObject *)(op_axes_tuple))->ob_item
[axis - op_nbroadcast])
;
1836 op_axis = PyArray_PyIntAsInt(axis_item);
1837 if (error_converting(op_axis)(((op_axis) == -1) && PyErr_Occurred()) ||
1838 (check_and_adjust_axis(&op_axis, op_ndim) < 0)) {
1839 Py_DECREF(op_axes_tuple)_Py_DECREF(((PyObject*)(op_axes_tuple)));
1840 return -1;
1841 }
1842 if (have_seen_axis[op_axis]) {
1843 PyErr_Format(PyExc_ValueError,
1844 "axes item %d has value %d repeated",
1845 iop, op_axis);
1846 Py_DECREF(op_axes_tuple)_Py_DECREF(((PyObject*)(op_axes_tuple)));
1847 return -1;
1848 }
1849 have_seen_axis[op_axis] = 1;
1850 remap_axis[iop][axis] = op_axis;
1851 }
1852 Py_DECREF(op_axes_tuple)_Py_DECREF(((PyObject*)(op_axes_tuple)));
1853 /*
1854 * Fill the op_nbroadcast=op_ndim-op_ncore axes not yet set,
1855 * using have_seen_axis to skip over entries set above.
1856 */
1857 for (axis = 0, op_axis = 0; axis < op_nbroadcast; axis++) {
1858 while (have_seen_axis[op_axis]) {
1859 op_axis++;
1860 }
1861 remap_axis[iop][axis] = op_axis++;
1862 }
1863 /*
1864 * Check whether we are actually remapping anything. Here,
1865 * op_axis can only equal axis if all broadcast axes were the same
1866 * (i.e., the while loop above was never entered).
1867 */
1868 if (axis == op_axis) {
1869 while (axis < op_ndim && remap_axis[iop][axis] == axis) {
1870 axis++;
1871 }
1872 }
1873 if (axis == op_ndim) {
1874 remap_axis[iop] = NULL((void*)0);
1875 }
1876 } /* end of for(iop) loop over operands */
1877 return 0;
1878}
1879
1880/*
1881 * Simplified version of the above, using axis to fill the remap_axis
1882 * array, which maps default to actual axes for each operand, indexed as
1883 * as remap_axis[iop][iaxis]. The default axis order has first all broadcast
1884 * axes and then the core axes the gufunc operates on.
1885 *
1886 * Returns 0 on success, and -1 on failure
1887 */
1888static int
1889_parse_axis_arg(PyUFuncObject *ufunc, const int core_num_dims[], PyObject *axis,
1890 PyArrayObject **op, int broadcast_ndim, int **remap_axis) {
1891 int nop = ufunc->nargs;
1892 int iop, axis_int;
1893
1894 axis_int = PyArray_PyIntAsInt(axis);
1895 if (error_converting(axis_int)(((axis_int) == -1) && PyErr_Occurred())) {
1896 return -1;
1897 }
1898
1899 for (iop = 0; iop < nop; ++iop) {
1900 int axis, op_ndim, op_axis;
1901
1902 /* _check_axis_support ensures core_num_dims is 0 or 1 */
1903 if (core_num_dims[iop] == 0) {
1904 remap_axis[iop] = NULL((void*)0);
1905 continue;
1906 }
1907 if (op[iop]) {
1908 op_ndim = PyArray_NDIM(op[iop]);
1909 }
1910 else {
1911 op_ndim = broadcast_ndim + 1;
1912 }
1913 op_axis = axis_int; /* ensure we don't modify axis_int */
1914 if (check_and_adjust_axis(&op_axis, op_ndim) < 0) {
1915 return -1;
1916 }
1917 /* Are we actually remapping away from last axis? */
1918 if (op_axis == op_ndim - 1) {
1919 remap_axis[iop] = NULL((void*)0);
1920 continue;
1921 }
1922 remap_axis[iop][op_ndim - 1] = op_axis;
1923 for (axis = 0; axis < op_axis; axis++) {
1924 remap_axis[iop][axis] = axis;
1925 }
1926 for (axis = op_axis; axis < op_ndim - 1; axis++) {
1927 remap_axis[iop][axis] = axis + 1;
1928 }
1929 } /* end of for(iop) loop over operands */
1930 return 0;
1931}
1932
1933#define REMAP_AXIS(iop, axis)((remap_axis != ((void*)0) && remap_axis[iop] != ((void
*)0))? remap_axis[iop][axis] : axis)
((remap_axis != NULL((void*)0) && \
1934 remap_axis[iop] != NULL((void*)0))? \
1935 remap_axis[iop][axis] : axis)
1936
1937/*
1938 * Validate the core dimensions of all the operands, and collect all of
1939 * the labelled core dimensions into 'core_dim_sizes'.
1940 *
1941 * Returns 0 on success, and -1 on failure
1942 *
1943 * The behavior has been changed in NumPy 1.16.0, and the following
1944 * requirements must be fulfilled or an error will be raised:
1945 * * Arguments, both input and output, must have at least as many
1946 * dimensions as the corresponding number of core dimensions. In
1947 * versions before 1.10, 1's were prepended to the shape as needed.
1948 * * Core dimensions with same labels must have exactly matching sizes.
1949 * In versions before 1.10, core dimensions of size 1 would broadcast
1950 * against other core dimensions with the same label.
1951 * * All core dimensions must have their size specified by a passed in
1952 * input or output argument. In versions before 1.10, core dimensions in
1953 * an output argument that were not specified in an input argument,
1954 * and whose size could not be inferred from a passed in output
1955 * argument, would have their size set to 1.
1956 * * Core dimensions may be fixed, new in NumPy 1.16
1957 */
1958static int
1959_get_coredim_sizes(PyUFuncObject *ufunc, PyArrayObject **op,
1960 const int *op_core_num_dims, npy_uint32 *core_dim_flags,
1961 npy_intp *core_dim_sizes, int **remap_axis) {
1962 int i;
1963 int nin = ufunc->nin;
1964 int nout = ufunc->nout;
1965 int nop = nin + nout;
1966
1967 for (i = 0; i < nop; ++i) {
1968 if (op[i] != NULL((void*)0)) {
1969 int idim;
1970 int dim_offset = ufunc->core_offsets[i];
1971 int core_start_dim = PyArray_NDIM(op[i]) - op_core_num_dims[i];
1972 int dim_delta = 0;
1973
1974 /* checked before this routine gets called */
1975 assert(core_start_dim >= 0)((void) (0));
1976
1977 /*
1978 * Make sure every core dimension exactly matches all other core
1979 * dimensions with the same label. Note that flexible dimensions
1980 * may have been removed at this point, if so, they are marked
1981 * with UFUNC_CORE_DIM_MISSING.
1982 */
1983 for (idim = 0; idim < ufunc->core_num_dims[i]; ++idim) {
1984 int core_index = dim_offset + idim;
1985 int core_dim_index = ufunc->core_dim_ixs[core_index];
1986 npy_intp core_dim_size = core_dim_sizes[core_dim_index];
1987 npy_intp op_dim_size;
1988
1989 /* can only happen if flexible; dimension missing altogether */
1990 if (core_dim_flags[core_dim_index] & UFUNC_CORE_DIM_MISSING0x00040000) {
1991 op_dim_size = 1;
1992 dim_delta++; /* for indexing in dimensions */
1993 }
1994 else {
1995 op_dim_size = PyArray_DIM(op[i],
1996 REMAP_AXIS(i, core_start_dim + idim - dim_delta)((remap_axis != ((void*)0) && remap_axis[i] != ((void
*)0))? remap_axis[i][core_start_dim + idim - dim_delta] : core_start_dim
+ idim - dim_delta)
);
1997 }
1998 if (core_dim_sizes[core_dim_index] < 0) {
1999 core_dim_sizes[core_dim_index] = op_dim_size;
2000 }
2001 else if (op_dim_size != core_dim_size) {
2002 PyErr_Format(PyExc_ValueError,
2003 "%s: %s operand %d has a mismatch in its "
2004 "core dimension %d, with gufunc "
2005 "signature %s (size %zd is different "
2006 "from %zd)",
2007 ufunc_get_name_cstr(ufunc), i < nin ? "Input" : "Output",
2008 i < nin ? i : i - nin, idim - dim_delta,
2009 ufunc->core_signature, op_dim_size,
2010 core_dim_sizes[core_dim_index]);
2011 return -1;
2012 }
2013 }
2014 }
2015 }
2016
2017 /*
2018 * Make sure no core dimension is unspecified.
2019 */
2020 for (i = nin; i < nop; ++i) {
2021 int idim;
2022 int dim_offset = ufunc->core_offsets[i];
2023
2024 for (idim = 0; idim < ufunc->core_num_dims[i]; ++idim) {
2025 int core_dim_index = ufunc->core_dim_ixs[dim_offset + idim];
2026
2027 /* check all cases where the size has not yet been set */
2028 if (core_dim_sizes[core_dim_index] < 0) {
2029 /*
2030 * Oops, this dimension was never specified
2031 * (can only happen if output op not given)
2032 */
2033 PyErr_Format(PyExc_ValueError,
2034 "%s: Output operand %d has core dimension %d "
2035 "unspecified, with gufunc signature %s",
2036 ufunc_get_name_cstr(ufunc), i - nin, idim,
2037 ufunc->core_signature);
2038 return -1;
2039 }
2040 }
2041 }
2042
2043 return 0;
2044}
2045
2046/*
2047 * Returns a new reference
2048 * TODO: store a reference in the ufunc object itself, rather than
2049 * constructing one each time
2050 */
2051static PyObject *
2052_get_identity(PyUFuncObject *ufunc, npy_bool *reorderable) {
2053 switch(ufunc->identity) {
2054 case PyUFunc_One1:
2055 *reorderable = 1;
2056 return PyLong_FromLong(1);
2057
2058 case PyUFunc_Zero0:
2059 *reorderable = 1;
2060 return PyLong_FromLong(0);
2061
2062 case PyUFunc_MinusOne2:
2063 *reorderable = 1;
2064 return PyLong_FromLong(-1);
2065
2066 case PyUFunc_ReorderableNone-2:
2067 *reorderable = 1;
2068 Py_RETURN_NONEreturn _Py_INCREF(((PyObject*)((&_Py_NoneStruct)))), (&
_Py_NoneStruct)
;
2069
2070 case PyUFunc_None-1:
2071 *reorderable = 0;
2072 Py_RETURN_NONEreturn _Py_INCREF(((PyObject*)((&_Py_NoneStruct)))), (&
_Py_NoneStruct)
;
2073
2074 case PyUFunc_IdentityValue-3:
2075 *reorderable = 1;
2076 Py_INCREF(ufunc->identity_value)_Py_INCREF(((PyObject*)(ufunc->identity_value)));
2077 return ufunc->identity_value;
2078
2079 default:
2080 PyErr_Format(PyExc_ValueError,
2081 "ufunc %s has an invalid identity", ufunc_get_name_cstr(ufunc));
2082 return NULL((void*)0);
2083 }
2084}
2085
2086/*
2087 * Copy over parts of the ufunc structure that may need to be
2088 * changed during execution. Returns 0 on success; -1 otherwise.
2089 */
2090static int
2091_initialize_variable_parts(PyUFuncObject *ufunc,
2092 int op_core_num_dims[],
2093 npy_intp core_dim_sizes[],
2094 npy_uint32 core_dim_flags[]) {
2095 int i;
2096
2097 for (i = 0; i < ufunc->nargs; i++) {
2098 op_core_num_dims[i] = ufunc->core_num_dims[i];
2099 }
2100 for (i = 0; i < ufunc->core_num_dim_ix; i++) {
2101 core_dim_sizes[i] = ufunc->core_dim_sizes[i];
2102 core_dim_flags[i] = ufunc->core_dim_flags[i];
2103 }
2104 return 0;
2105}
2106
2107static int
2108PyUFunc_GeneralizedFunctionInternal(PyUFuncObject *ufunc, PyArrayObject **op,
2109 ufunc_full_args full_args, PyObject *type_tup, PyObject *extobj,
2110 NPY_CASTING casting, NPY_ORDER order, npy_bool subok,
2111 PyObject *axis, PyObject *axes, int keepdims)
2112{
2113 int nin, nout;
2114 int i, j, idim, nop;
2115 const char *ufunc_name;
2116 int retval;
2117 int needs_api = 0;
2118
2119 PyArray_Descr *dtypes[NPY_MAXARGS32];
2120
2121 /* Use remapped axes for generalized ufunc */
2122 int broadcast_ndim, iter_ndim;
2123 int op_core_num_dims[NPY_MAXARGS32];
2124 int op_axes_arrays[NPY_MAXARGS32][NPY_MAXDIMS32];
2125 int *op_axes[NPY_MAXARGS32];
2126 npy_uint32 core_dim_flags[NPY_MAXARGS32];
2127
2128 npy_uint32 op_flags[NPY_MAXARGS32];
2129 npy_intp iter_shape[NPY_MAXARGS32];
2130 NpyIter *iter = NULL((void*)0);
2131 npy_uint32 iter_flags;
2132 npy_intp total_problem_size;
2133
2134 /* These parameters come from extobj= or from a TLS global */
2135 int buffersize = 0, errormask = 0;
2136
2137 /* The selected inner loop */
2138 PyUFuncGenericFunction innerloop = NULL((void*)0);
2139 void *innerloopdata = NULL((void*)0);
2140 /* The dimensions which get passed to the inner loop */
2141 npy_intp inner_dimensions[NPY_MAXDIMS32+1];
2142 /* The strides which get passed to the inner loop */
2143 npy_intp *inner_strides = NULL((void*)0);
2144
2145 /* The sizes of the core dimensions (# entries is ufunc->core_num_dim_ix) */
2146 npy_intp *core_dim_sizes = inner_dimensions + 1;
2147 int core_dim_ixs_size;
2148 /* swapping around of axes */
2149 int *remap_axis_memory = NULL((void*)0);
2150 int **remap_axis = NULL((void*)0);
2151 /* The __array_prepare__ function to call for each output */
2152 PyObject *arr_prep[NPY_MAXARGS32];
2153
2154 nin = ufunc->nin;
2155 nout = ufunc->nout;
2156 nop = nin + nout;
2157
2158 ufunc_name = ufunc_get_name_cstr(ufunc);
2159
2160 NPY_UF_DBG_PRINT1("\nEvaluating ufunc %s\n", ufunc_name);
2161
2162 /* Initialize all dtypes and __array_prepare__ call-backs to NULL */
2163 for (i = 0; i < nop; ++i) {
2164 dtypes[i] = NULL((void*)0);
2165 arr_prep[i] = NULL((void*)0);
2166 }
2167 /* Initialize possibly variable parts to the values from the ufunc */
2168 retval = _initialize_variable_parts(ufunc, op_core_num_dims,
2169 core_dim_sizes, core_dim_flags);
2170 if (retval < 0) {
2171 goto fail;
2172 }
2173
2174 /*
2175 * If keepdims was passed in (and thus changed from the initial value
2176 * on top), check the gufunc is suitable, i.e., that its inputs share
2177 * the same number of core dimensions, and its outputs have none.
2178 */
2179 if (keepdims != -1) {
2180 retval = _check_keepdims_support(ufunc);
2181 if (retval < 0) {
2182 goto fail;
2183 }
2184 }
2185 if (axis != NULL((void*)0)) {
2186 retval = _check_axis_support(ufunc);
2187 if (retval < 0) {
2188 goto fail;
2189 }
2190 }
2191 /*
2192 * If keepdims is set and true, which means all input dimensions are
2193 * the same, signal that all output dimensions will be the same too.
2194 */
2195 if (keepdims == 1) {
2196 int num_dims = op_core_num_dims[0];
2197 for (i = nin; i < nop; ++i) {
2198 op_core_num_dims[i] = num_dims;
2199 }
2200 }
2201 else {
2202 /* keepdims was not set or was false; no adjustment necessary */
2203 keepdims = 0;
2204 }
2205 /*
2206 * Check that operands have the minimum dimensions required.
2207 * (Just checks core; broadcast dimensions are tested by the iterator.)
2208 */
2209 retval = _validate_num_dims(ufunc, op, core_dim_flags,
2210 op_core_num_dims);
2211 if (retval < 0) {
2212 goto fail;
2213 }
2214 /*
2215 * Figure out the number of iteration dimensions, which
2216 * is the broadcast result of all the non-core dimensions.
2217 * (We do allow outputs to broadcast inputs currently, if they are given.
2218 * This is in line with what normal ufuncs do.)
2219 */
2220 broadcast_ndim = 0;
2221 for (i = 0; i < nop; ++i) {
2222 if (op[i] == NULL((void*)0)) {
2223 continue;
2224 }
2225 int n = PyArray_NDIM(op[i]) - op_core_num_dims[i];
2226 if (n > broadcast_ndim) {
2227 broadcast_ndim = n;
2228 }
2229 }
2230
2231 /* Possibly remap axes. */
2232 if (axes != NULL((void*)0) || axis != NULL((void*)0)) {
2233 assert(!(axes != NULL && axis != NULL))((void) (0));
2234
2235 remap_axis = PyArray_mallocPyMem_RawMalloc(sizeof(remap_axis[0]) * nop);
2236 remap_axis_memory = PyArray_mallocPyMem_RawMalloc(sizeof(remap_axis_memory[0]) *
2237 nop * NPY_MAXDIMS32);
2238 if (remap_axis == NULL((void*)0) || remap_axis_memory == NULL((void*)0)) {
2239 PyErr_NoMemory();
2240 goto fail;
2241 }
2242 for (i=0; i < nop; i++) {
2243 remap_axis[i] = remap_axis_memory + i * NPY_MAXDIMS32;
2244 }
2245 if (axis) {
2246 retval = _parse_axis_arg(ufunc, op_core_num_dims, axis, op,
2247 broadcast_ndim, remap_axis);
2248 }
2249 else {
2250 retval = _parse_axes_arg(ufunc, op_core_num_dims, axes, op,
2251 broadcast_ndim, remap_axis);
2252 }
2253 if(retval < 0) {
2254 goto fail;
2255 }
2256 }
2257
2258 /* Collect the lengths of the labelled core dimensions */
2259 retval = _get_coredim_sizes(ufunc, op, op_core_num_dims, core_dim_flags,
2260 core_dim_sizes, remap_axis);
2261 if(retval < 0) {
2262 goto fail;
2263 }
2264 /*
2265 * Figure out the number of iterator creation dimensions,
2266 * which is the broadcast dimensions + all the core dimensions of
2267 * the outputs, so that the iterator can allocate those output
2268 * dimensions following the rules of order='F', for example.
2269 */
2270 iter_ndim = broadcast_ndim;
2271 for (i = nin; i < nop; ++i) {
2272 iter_ndim += op_core_num_dims[i];
2273 }
2274 if (iter_ndim > NPY_MAXDIMS32) {
2275 PyErr_Format(PyExc_ValueError,
2276 "too many dimensions for generalized ufunc %s",
2277 ufunc_name);
2278 retval = -1;
2279 goto fail;
2280 }
2281
2282 /* Fill in the initial part of 'iter_shape' */
2283 for (idim = 0; idim < broadcast_ndim; ++idim) {
2284 iter_shape[idim] = -1;
2285 }
2286
2287 /* Fill in op_axes for all the operands */
2288 j = broadcast_ndim;
2289 for (i = 0; i < nop; ++i) {
2290 int n;
2291
2292 if (op[i]) {
2293 n = PyArray_NDIM(op[i]) - op_core_num_dims[i];
2294 }
2295 else {
2296 n = broadcast_ndim;
2297 }
2298 /* Broadcast all the unspecified dimensions normally */
2299 for (idim = 0; idim < broadcast_ndim; ++idim) {
2300 if (idim >= broadcast_ndim - n) {
2301 op_axes_arrays[i][idim] =
2302 REMAP_AXIS(i, idim - (broadcast_ndim - n))((remap_axis != ((void*)0) && remap_axis[i] != ((void
*)0))? remap_axis[i][idim - (broadcast_ndim - n)] : idim - (broadcast_ndim
- n))
;
2303 }
2304 else {
2305 op_axes_arrays[i][idim] = -1;
2306 }
2307 }
2308
2309 /*
2310 * Any output core dimensions shape should be ignored, so we add
2311 * it as a Reduce dimension (which can be broadcast with the rest).
2312 * These will be removed before the actual iteration for gufuncs.
2313 */
2314 for (idim = broadcast_ndim; idim < iter_ndim; ++idim) {
2315 op_axes_arrays[i][idim] = NPY_ITER_REDUCTION_AXIS(-1)(-1 + (1 << ((4 * 8) - 2)));
2316 }
2317
2318 /* Except for when it belongs to this output */
2319 if (i >= nin) {
2320 int dim_offset = ufunc->core_offsets[i];
2321 int num_removed = 0;
2322 /*
2323 * Fill in 'iter_shape' and 'op_axes' for the core dimensions
2324 * of this output. Here, we have to be careful: if keepdims
2325 * was used, then the axes are not real core dimensions, but
2326 * are being added back for broadcasting, so their size is 1.
2327 * If the axis was removed, we should skip altogether.
2328 */
2329 if (keepdims) {
2330 for (idim = 0; idim < op_core_num_dims[i]; ++idim) {
2331 iter_shape[j] = 1;
2332 op_axes_arrays[i][j] = REMAP_AXIS(i, n + idim)((remap_axis != ((void*)0) && remap_axis[i] != ((void
*)0))? remap_axis[i][n + idim] : n + idim)
;
2333 ++j;
2334 }
2335 }
2336 else {
2337 for (idim = 0; idim < ufunc->core_num_dims[i]; ++idim) {
2338 int core_index = dim_offset + idim;
2339 int core_dim_index = ufunc->core_dim_ixs[core_index];
2340 if ((core_dim_flags[core_dim_index] &
2341 UFUNC_CORE_DIM_MISSING0x00040000)) {
2342 /* skip it */
2343 num_removed++;
2344 continue;
2345 }
2346 iter_shape[j] = core_dim_sizes[ufunc->core_dim_ixs[core_index]];
2347 op_axes_arrays[i][j] = REMAP_AXIS(i, n + idim - num_removed)((remap_axis != ((void*)0) && remap_axis[i] != ((void
*)0))? remap_axis[i][n + idim - num_removed] : n + idim - num_removed
)
;
2348 ++j;
2349 }
2350 }
2351 }
2352
2353 op_axes[i] = op_axes_arrays[i];
2354 }
2355
2356#if NPY_UF_DBG_TRACING0
2357 printf("iter shapes:")__printf_chk (2 - 1, "iter shapes:");
2358 for (j=0; j < iter_ndim; j++) {
2359 printf(" %ld", iter_shape[j])__printf_chk (2 - 1, " %ld", iter_shape[j]);
2360 }
2361 printf("\n")__printf_chk (2 - 1, "\n");
2362#endif
2363
2364 /* Get the buffersize and errormask */
2365 if (_get_bufsize_errmask(extobj, ufunc_name, &buffersize, &errormask) < 0) {
2366 retval = -1;
2367 goto fail;
2368 }
2369
2370 NPY_UF_DBG_PRINT("Finding inner loop\n");
2371
2372
2373 retval = ufunc->type_resolver(ufunc, casting,
2374 op, type_tup, dtypes);
2375 if (retval < 0) {
2376 goto fail;
2377 }
2378 /*
2379 * We don't write to all elements, and the iterator may make
2380 * UPDATEIFCOPY temporary copies. The output arrays (unless they are
2381 * allocated by the iterator itself) must be considered READWRITE by the
2382 * iterator, so that the elements we don't write to are copied to the
2383 * possible temporary array.
2384 */
2385 _ufunc_setup_flags(ufunc, NPY_ITER_COPY0x00400000 | NPY_UFUNC_DEFAULT_INPUT_FLAGS0x00020000 | 0x00100000 | 0x40000000,
2386 NPY_ITER_UPDATEIFCOPY0x00800000 |
2387 NPY_ITER_WRITEONLY0x00040000 |
2388 NPY_UFUNC_DEFAULT_OUTPUT_FLAGS0x00100000 | 0x01000000 | 0x08000000 | 0x02000000 | 0x40000000,
2389 op_flags);
2390 /* For the generalized ufunc, we get the loop right away too */
2391 retval = ufunc->legacy_inner_loop_selector(ufunc, dtypes,
2392 &innerloop, &innerloopdata, &needs_api);
2393 if (retval < 0) {
2394 goto fail;
2395 }
2396
2397#if NPY_UF_DBG_TRACING0
2398 printf("input types:\n")__printf_chk (2 - 1, "input types:\n");
2399 for (i = 0; i < nin; ++i) {
2400 PyObject_Print((PyObject *)dtypes[i], stdoutstdout, 0);
2401 printf(" ")__printf_chk (2 - 1, " ");
2402 }
2403 printf("\noutput types:\n")__printf_chk (2 - 1, "\noutput types:\n");
2404 for (i = nin; i < nop; ++i) {
2405 PyObject_Print((PyObject *)dtypes[i], stdoutstdout, 0);
2406 printf(" ")__printf_chk (2 - 1, " ");
2407 }
2408 printf("\n")__printf_chk (2 - 1, "\n");
2409#endif
2410
2411 if (subok) {
2412 /*
2413 * Get the appropriate __array_prepare__ function to call
2414 * for each output
2415 */
2416 _find_array_prepare(full_args, arr_prep, nout);
2417 }
2418
2419 /*
2420 * Set up the iterator per-op flags. For generalized ufuncs, we
2421 * can't do buffering, so must COPY or UPDATEIFCOPY.
2422 */
2423
2424 iter_flags = ufunc->iter_flags |
2425 NPY_ITER_MULTI_INDEX0x00000004 |
2426 NPY_ITER_REFS_OK0x00000020 |
2427 NPY_ITER_ZEROSIZE_OK0x00000040 |
2428 NPY_ITER_COPY_IF_OVERLAP0x00002000;
2429
2430 /* Create the iterator */
2431 iter = NpyIter_AdvancedNew(nop, op, iter_flags,
2432 order, NPY_UNSAFE_CASTING, op_flags,
2433 dtypes, iter_ndim,
2434 op_axes, iter_shape, 0);
2435 if (iter == NULL((void*)0)) {
2436 retval = -1;
2437 goto fail;
2438 }
2439
2440 /* Fill in any allocated outputs */
2441 {
2442 PyArrayObject **operands = NpyIter_GetOperandArray(iter);
2443 for (i = nin; i < nop; ++i) {
2444 if (op[i] == NULL((void*)0)) {
2445 op[i] = operands[i];
2446 Py_INCREF(op[i])_Py_INCREF(((PyObject*)(op[i])));
2447 }
2448 }
2449 }
2450 /*
2451 * Set up the inner strides array. Because we're not doing
2452 * buffering, the strides are fixed throughout the looping.
2453 */
2454 core_dim_ixs_size = 0;
2455 for (i = 0; i < nop; ++i) {
2456 core_dim_ixs_size += ufunc->core_num_dims[i];
2457 }
2458 inner_strides = (npy_intp *)PyArray_mallocPyMem_RawMalloc(
2459 NPY_SIZEOF_INTP8 * (nop+core_dim_ixs_size));
2460 if (inner_strides == NULL((void*)0)) {
2461 PyErr_NoMemory();
2462 retval = -1;
2463 goto fail;
2464 }
2465 /* Copy the strides after the first nop */
2466 idim = nop;
2467 for (i = 0; i < nop; ++i) {
2468 /*
2469 * Need to use the arrays in the iterator, not op, because
2470 * a copy with a different-sized type may have been made.
2471 */
2472 PyArrayObject *arr = NpyIter_GetOperandArray(iter)[i];
2473 npy_intp *shape = PyArray_SHAPE(arr);
2474 npy_intp *strides = PyArray_STRIDES(arr);
2475 /*
2476 * Could be negative if flexible dims are used, but not for
2477 * keepdims, since those dimensions are allocated in arr.
2478 */
2479 int core_start_dim = PyArray_NDIM(arr) - op_core_num_dims[i];
2480 int num_removed = 0;
2481 int dim_offset = ufunc->core_offsets[i];
2482
2483 for (j = 0; j < ufunc->core_num_dims[i]; ++j) {
2484 int core_dim_index = ufunc->core_dim_ixs[dim_offset + j];
2485 /*
2486 * Force zero stride when the shape is 1 (always the case for
2487 * for missing dimensions), so that broadcasting works right.
2488 */
2489 if (core_dim_flags[core_dim_index] & UFUNC_CORE_DIM_MISSING0x00040000) {
2490 num_removed++;
2491 inner_strides[idim++] = 0;
2492 }
2493 else {
2494 int remapped_axis = REMAP_AXIS(i, core_start_dim + j - num_removed)((remap_axis != ((void*)0) && remap_axis[i] != ((void
*)0))? remap_axis[i][core_start_dim + j - num_removed] : core_start_dim
+ j - num_removed)
;
2495 if (shape[remapped_axis] != 1) {
2496 inner_strides[idim++] = strides[remapped_axis];
2497 } else {
2498 inner_strides[idim++] = 0;
2499 }
2500 }
2501 }
2502 }
2503
2504 total_problem_size = NpyIter_GetIterSize(iter);
2505 if (total_problem_size < 0) {
2506 /*
2507 * Only used for threading, if negative (this means that it is
2508 * larger then ssize_t before axes removal) assume that the actual
2509 * problem is large enough to be threaded usefully.
2510 */
2511 total_problem_size = 1000;
2512 }
2513
2514 /* Remove all the core output dimensions from the iterator */
2515 for (i = broadcast_ndim; i < iter_ndim; ++i) {
2516 if (NpyIter_RemoveAxis(iter, broadcast_ndim) != NPY_SUCCEED1) {
2517 retval = -1;
2518 goto fail;
2519 }
2520 }
2521 if (NpyIter_RemoveMultiIndex(iter) != NPY_SUCCEED1) {
2522 retval = -1;
2523 goto fail;
2524 }
2525 if (NpyIter_EnableExternalLoop(iter) != NPY_SUCCEED1) {
2526 retval = -1;
2527 goto fail;
2528 }
2529
2530 /*
2531 * The first nop strides are for the inner loop (but only can
2532 * copy them after removing the core axes)
2533 */
2534 memcpy(inner_strides, NpyIter_GetInnerStrideArray(iter),
2535 NPY_SIZEOF_INTP8 * nop);
2536
2537#if 0
2538 printf("strides: ")__printf_chk (2 - 1, "strides: ");
2539 for (i = 0; i < nop+core_dim_ixs_size; ++i) {
2540 printf("%d ", (int)inner_strides[i])__printf_chk (2 - 1, "%d ", (int)inner_strides[i]);
2541 }
2542 printf("\n")__printf_chk (2 - 1, "\n");
2543#endif
2544
2545 /* Start with the floating-point exception flags cleared */
2546 npy_clear_floatstatus_barrier((char*)&iter);
2547
2548 NPY_UF_DBG_PRINT("Executing inner loop\n");
2549
2550 if (NpyIter_GetIterSize(iter) != 0) {
2551 /* Do the ufunc loop */
2552 NpyIter_IterNextFunc *iternext;
2553 char **dataptr;
2554 npy_intp *count_ptr;
2555 NPY_BEGIN_THREADS_DEFPyThreadState *_save=((void*)0);;
2556
2557 /* Get the variables needed for the loop */
2558 iternext = NpyIter_GetIterNext(iter, NULL((void*)0));
2559 if (iternext == NULL((void*)0)) {
2560 retval = -1;
2561 goto fail;
2562 }
2563 dataptr = NpyIter_GetDataPtrArray(iter);
2564 count_ptr = NpyIter_GetInnerLoopSizePtr(iter);
2565 needs_api = NpyIter_IterationNeedsAPI(iter);
2566
2567 if (!needs_api && !NpyIter_IterationNeedsAPI(iter)) {
2568 NPY_BEGIN_THREADS_THRESHOLDED(total_problem_size)do { if ((total_problem_size) > 500) { _save = PyEval_SaveThread
();} } while (0);
;
2569 }
2570 do {
2571 inner_dimensions[0] = *count_ptr;
2572 innerloop(dataptr, inner_dimensions, inner_strides, innerloopdata);
2573 } while (!(needs_api && PyErr_Occurred()) && iternext(iter));
2574
2575 if (!needs_api && !NpyIter_IterationNeedsAPI(iter)) {
2576 NPY_END_THREADSdo { if (_save) { PyEval_RestoreThread(_save); _save = ((void
*)0);} } while (0);
;
2577 }
2578 }
2579
2580 /* Check whether any errors occurred during the loop */
2581 if (PyErr_Occurred() ||
2582 _check_ufunc_fperr(errormask, extobj, ufunc_name) < 0) {
2583 retval = -1;
2584 goto fail;
2585 }
2586
2587 PyArray_freePyMem_RawFree(inner_strides);
2588 if (NpyIter_Deallocate(iter) < 0) {
2589 retval = -1;
2590 }
2591
2592 /* The caller takes ownership of all the references in op */
2593 for (i = 0; i < nop; ++i) {
2594 Py_XDECREF(dtypes[i])_Py_XDECREF(((PyObject*)(dtypes[i])));
2595 Py_XDECREF(arr_prep[i])_Py_XDECREF(((PyObject*)(arr_prep[i])));
2596 }
2597 PyArray_freePyMem_RawFree(remap_axis_memory);
2598 PyArray_freePyMem_RawFree(remap_axis);
2599
2600 NPY_UF_DBG_PRINT1("Returning code %d\n", retval);
2601
2602 return retval;
2603
2604fail:
2605 NPY_UF_DBG_PRINT1("Returning failure code %d\n", retval);
2606 PyArray_freePyMem_RawFree(inner_strides);
2607 NpyIter_Deallocate(iter);
2608 for (i = 0; i < nop; ++i) {
2609 Py_XDECREF(dtypes[i])_Py_XDECREF(((PyObject*)(dtypes[i])));
2610 Py_XDECREF(arr_prep[i])_Py_XDECREF(((PyObject*)(arr_prep[i])));
2611 }
2612 PyArray_freePyMem_RawFree(remap_axis_memory);
2613 PyArray_freePyMem_RawFree(remap_axis);
2614 return retval;
2615}
2616
2617
2618static int
2619PyUFunc_GenericFunctionInternal(PyUFuncObject *ufunc, PyArrayObject **op,
2620 ufunc_full_args full_args, PyObject *type_tup, PyObject *extobj,
2621 NPY_CASTING casting, NPY_ORDER order, npy_bool subok,
2622 PyArrayObject *wheremask)
2623{
2624 int nin, nout;
2625 int i, nop;
2626 const char *ufunc_name;
2627 int retval = -1;
2628 npy_uint32 op_flags[NPY_MAXARGS32];
2629 npy_intp default_op_out_flags;
2630
2631 PyArray_Descr *dtypes[NPY_MAXARGS32];
2632
2633 /* These parameters come from extobj= or from a TLS global */
2634 int buffersize = 0, errormask = 0;
2635
2636 /* The __array_prepare__ function to call for each output */
2637 PyObject *arr_prep[NPY_MAXARGS32];
2638
2639 int trivial_loop_ok = 0;
2640
2641 nin = ufunc->nin;
2642 nout = ufunc->nout;
2643 nop = nin + nout;
2644
2645 ufunc_name = ufunc_get_name_cstr(ufunc);
2646
2647 NPY_UF_DBG_PRINT1("\nEvaluating ufunc %s\n", ufunc_name);
2648
2649 /* Initialize all the dtypes and __array_prepare__ callbacks to NULL */
2650 for (i = 0; i < nop; ++i) {
2651 dtypes[i] = NULL((void*)0);
2652 arr_prep[i] = NULL((void*)0);
2653 }
2654
2655 /* Get the buffersize and errormask */
2656 if (_get_bufsize_errmask(extobj, ufunc_name, &buffersize, &errormask) < 0) {
2657 retval = -1;
2658 goto fail;
2659 }
2660
2661 NPY_UF_DBG_PRINT("Finding inner loop\n");
2662
2663 retval = ufunc->type_resolver(ufunc, casting,
2664 op, type_tup, dtypes);
2665 if (retval < 0) {
2666 goto fail;
2667 }
2668
2669 if (wheremask != NULL((void*)0)) {
2670 /* Set up the flags. */
2671 default_op_out_flags = NPY_ITER_NO_SUBTYPE0x02000000 |
2672 NPY_ITER_WRITEMASKED0x10000000 |
2673 NPY_UFUNC_DEFAULT_OUTPUT_FLAGS0x00100000 | 0x01000000 | 0x08000000 | 0x02000000 | 0x40000000;
2674 _ufunc_setup_flags(ufunc, NPY_UFUNC_DEFAULT_INPUT_FLAGS0x00020000 | 0x00100000 | 0x40000000,
2675 default_op_out_flags, op_flags);
2676 }
2677 else {
2678 /* Set up the flags. */
2679 default_op_out_flags = NPY_ITER_WRITEONLY0x00040000 |
2680 NPY_UFUNC_DEFAULT_OUTPUT_FLAGS0x00100000 | 0x01000000 | 0x08000000 | 0x02000000 | 0x40000000;
2681 _ufunc_setup_flags(ufunc, NPY_UFUNC_DEFAULT_INPUT_FLAGS0x00020000 | 0x00100000 | 0x40000000,
2682 default_op_out_flags, op_flags);
2683 }
2684
2685#if NPY_UF_DBG_TRACING0
2686 printf("input types:\n")__printf_chk (2 - 1, "input types:\n");
2687 for (i = 0; i < nin; ++i) {
2688 PyObject_Print((PyObject *)dtypes[i], stdoutstdout, 0);
2689 printf(" ")__printf_chk (2 - 1, " ");
2690 }
2691 printf("\noutput types:\n")__printf_chk (2 - 1, "\noutput types:\n");
2692 for (i = nin; i < nop; ++i) {
2693 PyObject_Print((PyObject *)dtypes[i], stdoutstdout, 0);
2694 printf(" ")__printf_chk (2 - 1, " ");
2695 }
2696 printf("\n")__printf_chk (2 - 1, "\n");
2697#endif
2698
2699 if (subok) {
2700 /*
2701 * Get the appropriate __array_prepare__ function to call
2702 * for each output
2703 */
2704 _find_array_prepare(full_args, arr_prep, nout);
2705 }
2706
2707 /* Do the ufunc loop */
2708 if (wheremask != NULL((void*)0)) {
2709 NPY_UF_DBG_PRINT("Executing fancy inner loop\n");
2710
2711 if (nop + 1 > NPY_MAXARGS32) {
2712 PyErr_SetString(PyExc_ValueError,
2713 "Too many operands when including where= parameter");
2714 return -1;
2715 }
2716 op[nop] = wheremask;
2717 dtypes[nop] = NULL((void*)0);
2718
2719 /* Set up the flags */
2720
2721 npy_clear_floatstatus_barrier((char*)&ufunc);
2722 retval = execute_fancy_ufunc_loop(ufunc, wheremask,
2723 op, dtypes, order,
2724 buffersize, arr_prep, full_args, op_flags);
2725 }
2726 else {
2727 NPY_UF_DBG_PRINT("Executing legacy inner loop\n");
2728
2729 /*
2730 * This checks whether a trivial loop is ok, making copies of
2731 * scalar and one dimensional operands if that will help.
2732 * Since it requires dtypes, it can only be called after
2733 * ufunc->type_resolver
2734 */
2735 trivial_loop_ok = check_for_trivial_loop(ufunc, op, dtypes, buffersize);
2736 if (trivial_loop_ok < 0) {
2737 goto fail;
2738 }
2739
2740 /* check_for_trivial_loop on half-floats can overflow */
2741 npy_clear_floatstatus_barrier((char*)&ufunc);
2742
2743 retval = execute_legacy_ufunc_loop(ufunc, trivial_loop_ok,
2744 op, dtypes, order,
2745 buffersize, arr_prep, full_args, op_flags);
2746 }
2747 if (retval < 0) {
2748 goto fail;
2749 }
2750
2751 /*
2752 * Check whether any errors occurred during the loop. The loops should
2753 * indicate this in retval, but since the inner-loop currently does not
2754 * report errors, this does not happen in all branches (at this time).
2755 */
2756 if (PyErr_Occurred() ||
2757 _check_ufunc_fperr(errormask, extobj, ufunc_name) < 0) {
2758 retval = -1;
2759 goto fail;
2760 }
2761
2762
2763 /* The caller takes ownership of all the references in op */
2764 for (i = 0; i < nop; ++i) {
2765 Py_XDECREF(dtypes[i])_Py_XDECREF(((PyObject*)(dtypes[i])));
2766 Py_XDECREF(arr_prep[i])_Py_XDECREF(((PyObject*)(arr_prep[i])));
2767 }
2768
2769 NPY_UF_DBG_PRINT("Returning success code 0\n");
2770
2771 return 0;
2772
2773fail:
2774 NPY_UF_DBG_PRINT1("Returning failure code %d\n", retval);
2775 for (i = 0; i < nop; ++i) {
2776 Py_XDECREF(dtypes[i])_Py_XDECREF(((PyObject*)(dtypes[i])));
2777 Py_XDECREF(arr_prep[i])_Py_XDECREF(((PyObject*)(arr_prep[i])));
2778 }
2779
2780 return retval;
2781}
2782
2783
2784/*UFUNC_API*/
2785NPY_NO_EXPORT__attribute__((visibility("hidden"))) int
2786PyUFunc_GenericFunction(PyUFuncObject *NPY_UNUSED(ufunc)(__NPY_UNUSED_TAGGEDufunc) __attribute__ ((__unused__)),
2787 PyObject *NPY_UNUSED(args)(__NPY_UNUSED_TAGGEDargs) __attribute__ ((__unused__)), PyObject *NPY_UNUSED(kwds)(__NPY_UNUSED_TAGGEDkwds) __attribute__ ((__unused__)),
2788 PyArrayObject **NPY_UNUSED(op)(__NPY_UNUSED_TAGGEDop) __attribute__ ((__unused__)))
2789{
2790 /* NumPy 1.21, 2020-03-29 */
2791 PyErr_SetString(PyExc_RuntimeError,
2792 "The `PyUFunc_GenericFunction()` C-API function has been disabled. "
2793 "Please use `PyObject_Call(ufunc, args, kwargs)`, which has "
2794 "identical behaviour but allows subclass and `__array_ufunc__` "
2795 "override handling and only returns the normal ufunc result.");
2796 return -1;
2797}
2798
2799
2800/*
2801 * Given the output type, finds the specified binary op. The
2802 * ufunc must have nin==2 and nout==1. The function may modify
2803 * otype if the given type isn't found.
2804 *
2805 * Returns 0 on success, -1 on failure.
2806 */
2807static int
2808get_binary_op_function(PyUFuncObject *ufunc, int *otype,
2809 PyUFuncGenericFunction *out_innerloop,
2810 void **out_innerloopdata)
2811{
2812 int i;
2813
2814 NPY_UF_DBG_PRINT1("Getting binary op function for type number %d\n",
2815 *otype);
2816
2817 /* If the type is custom and there are userloops, search for it here */
2818 if (ufunc->userloops != NULL((void*)0) && PyTypeNum_ISUSERDEF(*otype)(((*otype) >= NPY_USERDEF) && ((*otype) < NPY_USERDEF
+ NPY_NUMUSERTYPES))
) {
2819 PyObject *key, *obj;
2820 key = PyLong_FromLong(*otype);
2821 if (key == NULL((void*)0)) {
2822 return -1;
2823 }
2824 obj = PyDict_GetItemWithError(ufunc->userloops, key);
2825 Py_DECREF(key)_Py_DECREF(((PyObject*)(key)));
2826 if (obj == NULL((void*)0) && PyErr_Occurred()) {
2827 return -1;
2828 }
2829 else if (obj != NULL((void*)0)) {
2830 PyUFunc_Loop1d *funcdata = PyCapsule_GetPointer(obj, NULL((void*)0));
2831 if (funcdata == NULL((void*)0)) {
2832 return -1;
2833 }
2834 while (funcdata != NULL((void*)0)) {
2835 int *types = funcdata->arg_types;
2836
2837 if (types[0] == *otype && types[1] == *otype &&
2838 types[2] == *otype) {
2839 *out_innerloop = funcdata->func;
2840 *out_innerloopdata = funcdata->data;
2841 return 0;
2842 }
2843
2844 funcdata = funcdata->next;
2845 }
2846 }
2847 }
2848
2849 /* Search for a function with compatible inputs */
2850 for (i = 0; i < ufunc->ntypes; ++i) {
2851 char *types = ufunc->types + i*ufunc->nargs;
2852
2853 NPY_UF_DBG_PRINT3("Trying loop with signature %d %d -> %d\n",
2854 types[0], types[1], types[2]);
2855
2856 if (PyArray_CanCastSafely(*otype, types[0]) &&
2857 types[0] == types[1] &&
2858 (*otype == NPY_OBJECT || types[0] != NPY_OBJECT)) {
2859 /* If the signature is "xx->x", we found the loop */
2860 if (types[2] == types[0]) {
2861 *out_innerloop = ufunc->functions[i];
2862 *out_innerloopdata = ufunc->data[i];
2863 *otype = types[0];
2864 return 0;
2865 }
2866 /*
2867 * Otherwise, we found the natural type of the reduction,
2868 * replace otype and search again
2869 */
2870 else {
2871 *otype = types[2];
2872 break;
2873 }
2874 }
2875 }
2876
2877 /* Search for the exact function */
2878 for (i = 0; i < ufunc->ntypes; ++i) {
2879 char *types = ufunc->types + i*ufunc->nargs;
2880
2881 if (PyArray_CanCastSafely(*otype, types[0]) &&
2882 types[0] == types[1] &&
2883 types[1] == types[2] &&
2884 (*otype == NPY_OBJECT || types[0] != NPY_OBJECT)) {
2885 /* Since the signature is "xx->x", we found the loop */
2886 *out_innerloop = ufunc->functions[i];
2887 *out_innerloopdata = ufunc->data[i];
2888 *otype = types[0];
2889 return 0;
2890 }
2891 }
2892
2893 return -1;
2894}
2895
2896static int
2897reduce_type_resolver(PyUFuncObject *ufunc, PyArrayObject *arr,
2898 PyArray_Descr *odtype, PyArray_Descr **out_dtype)
2899{
2900 int i, retcode;
2901 PyArrayObject *op[3] = {arr, arr, NULL((void*)0)};
2902 PyArray_Descr *dtypes[3] = {NULL((void*)0), NULL((void*)0), NULL((void*)0)};
2903 const char *ufunc_name = ufunc_get_name_cstr(ufunc);
2904 PyObject *type_tup = NULL((void*)0);
2905
2906 *out_dtype = NULL((void*)0);
2907
2908 /*
2909 * If odtype is specified, make a type tuple for the type
2910 * resolution.
2911 */
2912 if (odtype != NULL((void*)0)) {
2913 type_tup = PyTuple_Pack(3, odtype, odtype, Py_None(&_Py_NoneStruct));
2914 if (type_tup == NULL((void*)0)) {
2915 return -1;
2916 }
2917 }
2918
2919 /* Use the type resolution function to find our loop */
2920 retcode = ufunc->type_resolver(
2921 ufunc, NPY_UNSAFE_CASTING,
2922 op, type_tup, dtypes);
2923 Py_DECREF(type_tup)_Py_DECREF(((PyObject*)(type_tup)));
2924 if (retcode == -1) {
2925 return -1;
2926 }
2927 else if (retcode == -2) {
2928 PyErr_Format(PyExc_RuntimeError,
2929 "type resolution returned NotImplemented to "
2930 "reduce ufunc %s", ufunc_name);
2931 return -1;
2932 }
2933
2934 /*
2935 * The first two type should be equivalent. Because of how
2936 * reduce has historically behaved in NumPy, the return type
2937 * could be different, and it is the return type on which the
2938 * reduction occurs.
2939 */
2940 if (!PyArray_EquivTypes(dtypes[0], dtypes[1])) {
2941 for (i = 0; i < 3; ++i) {
2942 Py_DECREF(dtypes[i])_Py_DECREF(((PyObject*)(dtypes[i])));
2943 }
2944 PyErr_Format(PyExc_RuntimeError,
2945 "could not find a type resolution appropriate for "
2946 "reduce ufunc %s", ufunc_name);
2947 return -1;
2948 }
2949
2950 Py_DECREF(dtypes[0])_Py_DECREF(((PyObject*)(dtypes[0])));
2951 Py_DECREF(dtypes[1])_Py_DECREF(((PyObject*)(dtypes[1])));
2952 *out_dtype = dtypes[2];
2953
2954 return 0;
2955}
2956
2957static int
2958reduce_loop(NpyIter *iter, char **dataptrs, npy_intp const *strides,
2959 npy_intp const *countptr, NpyIter_IterNextFunc *iternext,
2960 int needs_api, npy_intp skip_first_count, void *data)
2961{
2962 PyArray_Descr *dtypes[3], **iter_dtypes;
2963 PyUFuncObject *ufunc = (PyUFuncObject *)data;
2964 char *dataptrs_copy[3];
2965 npy_intp strides_copy[3];
2966 npy_bool masked;
2967
2968 /* The normal selected inner loop */
2969 PyUFuncGenericFunction innerloop = NULL((void*)0);
2970 void *innerloopdata = NULL((void*)0);
2971
2972 NPY_BEGIN_THREADS_DEFPyThreadState *_save=((void*)0);;
2973 /* Get the number of operands, to determine whether "where" is used */
2974 masked = (NpyIter_GetNOp(iter) == 3);
2975
2976 /* Get the inner loop */
2977 iter_dtypes = NpyIter_GetDescrArray(iter);
2978 dtypes[0] = iter_dtypes[0];
2979 dtypes[1] = iter_dtypes[1];
2980 dtypes[2] = iter_dtypes[0];
2981 if (ufunc->legacy_inner_loop_selector(ufunc, dtypes,
2982 &innerloop, &innerloopdata, &needs_api) < 0) {
2983 return -1;
2984 }
2985
2986 NPY_BEGIN_THREADS_NDITER(iter)do { if (!NpyIter_IterationNeedsAPI(iter)) { do { if ((NpyIter_GetIterSize
(iter)) > 500) { _save = PyEval_SaveThread();} } while (0)
;; } } while(0)
;
2987
2988 if (skip_first_count > 0) {
2989 do {
2990 npy_intp count = *countptr;
2991
2992 /* Skip any first-visit elements */
2993 if (NpyIter_IsFirstVisit(iter, 0)) {
2994 if (strides[0] == 0) {
2995 --count;
2996 --skip_first_count;
2997 dataptrs[1] += strides[1];
2998 }
2999 else {
3000 skip_first_count -= count;
3001 count = 0;
3002 }
3003 }
3004
3005 /* Turn the two items into three for the inner loop */
3006 dataptrs_copy[0] = dataptrs[0];
3007 dataptrs_copy[1] = dataptrs[1];
3008 dataptrs_copy[2] = dataptrs[0];
3009 strides_copy[0] = strides[0];
3010 strides_copy[1] = strides[1];
3011 strides_copy[2] = strides[0];
3012 innerloop(dataptrs_copy, &count,
3013 strides_copy, innerloopdata);
3014
3015 if (needs_api && PyErr_Occurred()) {
3016 goto finish_loop;
3017 }
3018
3019 /* Jump to the faster loop when skipping is done */
3020 if (skip_first_count == 0) {
3021 if (iternext(iter)) {
3022 break;
3023 }
3024 else {
3025 goto finish_loop;
3026 }
3027 }
3028 } while (iternext(iter));
3029 }
3030
3031 if (needs_api && PyErr_Occurred()) {
3032 goto finish_loop;
3033 }
3034
3035 do {
3036 /* Turn the two items into three for the inner loop */
3037 dataptrs_copy[0] = dataptrs[0];
3038 dataptrs_copy[1] = dataptrs[1];
3039 dataptrs_copy[2] = dataptrs[0];
3040 strides_copy[0] = strides[0];
3041 strides_copy[1] = strides[1];
3042 strides_copy[2] = strides[0];
3043
3044 if (!masked) {
3045 innerloop(dataptrs_copy, countptr,
3046 strides_copy, innerloopdata);
3047 }
3048 else {
3049 npy_intp count = *countptr;
3050 char *maskptr = dataptrs[2];
3051 npy_intp mask_stride = strides[2];
3052 /* Optimization for when the mask is broadcast */
3053 npy_intp n = mask_stride == 0 ? count : 1;
3054 while (count) {
3055 char mask = *maskptr;
3056 maskptr += mask_stride;
3057 while (n < count && mask == *maskptr) {
3058 n++;
3059 maskptr += mask_stride;
3060 }
3061 /* If mask set, apply inner loop on this contiguous region */
3062 if (mask) {
3063 innerloop(dataptrs_copy, &n,
3064 strides_copy, innerloopdata);
3065 }
3066 dataptrs_copy[0] += n * strides[0];
3067 dataptrs_copy[1] += n * strides[1];
3068 dataptrs_copy[2] = dataptrs_copy[0];
3069 count -= n;
3070 n = 1;
3071 }
3072 }
3073 } while (!(needs_api && PyErr_Occurred()) && iternext(iter));
3074
3075finish_loop:
3076 NPY_END_THREADSdo { if (_save) { PyEval_RestoreThread(_save); _save = ((void
*)0);} } while (0);
;
3077
3078 return (needs_api && PyErr_Occurred()) ? -1 : 0;
3079}
3080
3081/*
3082 * The implementation of the reduction operators with the new iterator
3083 * turned into a bit of a long function here, but I think the design
3084 * of this part needs to be changed to be more like einsum, so it may
3085 * not be worth refactoring it too much. Consider this timing:
3086 *
3087 * >>> a = arange(10000)
3088 *
3089 * >>> timeit sum(a)
3090 * 10000 loops, best of 3: 17 us per loop
3091 *
3092 * >>> timeit einsum("i->",a)
3093 * 100000 loops, best of 3: 13.5 us per loop
3094 *
3095 * The axes must already be bounds-checked by the calling function,
3096 * this function does not validate them.
3097 */
3098static PyArrayObject *
3099PyUFunc_Reduce(PyUFuncObject *ufunc, PyArrayObject *arr, PyArrayObject *out,
3100 int naxes, int *axes, PyArray_Descr *odtype, int keepdims,
3101 PyObject *initial, PyArrayObject *wheremask)
3102{
3103 int iaxes, ndim;
3104 npy_bool reorderable;
3105 npy_bool axis_flags[NPY_MAXDIMS32];
3106 PyArray_Descr *dtype;
3107 PyArrayObject *result;
3108 PyObject *identity;
3109 const char *ufunc_name = ufunc_get_name_cstr(ufunc);
3110 /* These parameters come from a TLS global */
3111 int buffersize = 0, errormask = 0;
3112
3113 NPY_UF_DBG_PRINT1("\nEvaluating ufunc %s.reduce\n", ufunc_name);
3114
3115 ndim = PyArray_NDIM(arr);
3116
3117 /* Create an array of flags for reduction */
3118 memset(axis_flags, 0, ndim);
3119 for (iaxes = 0; iaxes < naxes; ++iaxes) {
3120 int axis = axes[iaxes];
3121 if (axis_flags[axis]) {
3122 PyErr_SetString(PyExc_ValueError,
3123 "duplicate value in 'axis'");
3124 return NULL((void*)0);
3125 }
3126 axis_flags[axis] = 1;
3127 }
3128
3129 if (_get_bufsize_errmask(NULL((void*)0), "reduce", &buffersize, &errormask) < 0) {
3130 return NULL((void*)0);
3131 }
3132
3133 /* Get the identity */
3134 identity = _get_identity(ufunc, &reorderable);
3135 if (identity == NULL((void*)0)) {
3136 return NULL((void*)0);
3137 }
3138
3139 /* Get the initial value */
3140 if (initial == NULL((void*)0)) {
3141 initial = identity;
3142
3143 /*
3144 * The identity for a dynamic dtype like
3145 * object arrays can't be used in general
3146 */
3147 if (initial != Py_None(&_Py_NoneStruct) && PyArray_ISOBJECT(arr)((PyArray_TYPE(arr)) == NPY_OBJECT) && PyArray_SIZE(arr)PyArray_MultiplyList(PyArray_DIMS(arr), PyArray_NDIM(arr)) != 0) {
3148 Py_DECREF(initial)_Py_DECREF(((PyObject*)(initial)));
3149 initial = Py_None(&_Py_NoneStruct);
3150 Py_INCREF(initial)_Py_INCREF(((PyObject*)(initial)));
3151 }
3152 } else {
3153 Py_DECREF(identity)_Py_DECREF(((PyObject*)(identity)));
3154 Py_INCREF(initial)_Py_INCREF(((PyObject*)(initial))); /* match the reference count in the if above */
3155 }
3156
3157 /* Get the reduction dtype */
3158 if (reduce_type_resolver(ufunc, arr, odtype, &dtype) < 0) {
3159 Py_DECREF(initial)_Py_DECREF(((PyObject*)(initial)));
3160 return NULL((void*)0);
3161 }
3162
3163 result = PyUFunc_ReduceWrapper(arr, out, wheremask, dtype, dtype,
3164 NPY_UNSAFE_CASTING,
3165 axis_flags, reorderable,
3166 keepdims,
3167 initial,
3168 reduce_loop,
3169 ufunc, buffersize, ufunc_name, errormask);
3170
3171 Py_DECREF(dtype)_Py_DECREF(((PyObject*)(dtype)));
3172 Py_DECREF(initial)_Py_DECREF(((PyObject*)(initial)));
3173 return result;
3174}
3175
3176
3177static PyObject *
3178PyUFunc_Accumulate(PyUFuncObject *ufunc, PyArrayObject *arr, PyArrayObject *out,
3179 int axis, int otype)
3180{
3181 PyArrayObject *op[2];
3182 PyArray_Descr *op_dtypes[2] = {NULL((void*)0), NULL((void*)0)};
3183 int op_axes_arrays[2][NPY_MAXDIMS32];
3184 int *op_axes[2] = {op_axes_arrays[0], op_axes_arrays[1]};
3185 npy_uint32 op_flags[2];
3186 int idim, ndim, otype_final;
3187 int needs_api, need_outer_iterator;
3188
3189 NpyIter *iter = NULL((void*)0), *iter_inner = NULL((void*)0);
3190
3191 /* The selected inner loop */
3192 PyUFuncGenericFunction innerloop = NULL((void*)0);
3193 void *innerloopdata = NULL((void*)0);
3194
3195 const char *ufunc_name = ufunc_get_name_cstr(ufunc);
3196
3197 /* These parameters come from extobj= or from a TLS global */
3198 int buffersize = 0, errormask = 0;
3199
3200 NPY_BEGIN_THREADS_DEFPyThreadState *_save=((void*)0);;
3201
3202 NPY_UF_DBG_PRINT1("\nEvaluating ufunc %s.accumulate\n", ufunc_name);
3203
3204#if 0
3205 printf("Doing %s.accumulate on array with dtype : ", ufunc_name)__printf_chk (2 - 1, "Doing %s.accumulate on array with dtype : "
, ufunc_name)
;
3206 PyObject_Print((PyObject *)PyArray_DESCR(arr), stdoutstdout, 0);
3207 printf("\n")__printf_chk (2 - 1, "\n");
3208#endif
3209
3210 if (_get_bufsize_errmask(NULL((void*)0), "accumulate", &buffersize, &errormask) < 0) {
3211 return NULL((void*)0);
3212 }
3213
3214 /* Take a reference to out for later returning */
3215 Py_XINCREF(out)_Py_XINCREF(((PyObject*)(out)));
3216
3217 otype_final = otype;
3218 if (get_binary_op_function(ufunc, &otype_final,
3219 &innerloop, &innerloopdata) < 0) {
3220 PyArray_Descr *dtype = PyArray_DescrFromType(otype);
3221 PyErr_Format(PyExc_ValueError,
3222 "could not find a matching type for %s.accumulate, "
3223 "requested type has type code '%c'",
3224 ufunc_name, dtype ? dtype->type : '-');
3225 Py_XDECREF(dtype)_Py_XDECREF(((PyObject*)(dtype)));
3226 goto fail;
3227 }
3228
3229 ndim = PyArray_NDIM(arr);
3230
3231 /*
3232 * Set up the output data type, using the input's exact
3233 * data type if the type number didn't change to preserve
3234 * metadata
3235 */
3236 if (PyArray_DESCR(arr)->type_num == otype_final) {
3237 if (PyArray_ISNBO(PyArray_DESCR(arr)->byteorder)((PyArray_DESCR(arr)->byteorder) != '>')) {
3238 op_dtypes[0] = PyArray_DESCR(arr);
3239 Py_INCREF(op_dtypes[0])_Py_INCREF(((PyObject*)(op_dtypes[0])));
3240 }
3241 else {
3242 op_dtypes[0] = PyArray_DescrNewByteorder(PyArray_DESCR(arr),
3243 NPY_NATIVE'=');
3244 }
3245 }
3246 else {
3247 op_dtypes[0] = PyArray_DescrFromType(otype_final);
3248 }
3249 if (op_dtypes[0] == NULL((void*)0)) {
3250 goto fail;
3251 }
3252
3253#if NPY_UF_DBG_TRACING0
3254 printf("Found %s.accumulate inner loop with dtype : ", ufunc_name)__printf_chk (2 - 1, "Found %s.accumulate inner loop with dtype : "
, ufunc_name)
;
3255 PyObject_Print((PyObject *)op_dtypes[0], stdoutstdout, 0);
3256 printf("\n")__printf_chk (2 - 1, "\n");
3257#endif
3258
3259 /* Set up the op_axes for the outer loop */
3260 for (idim = 0; idim < ndim; ++idim) {
3261 op_axes_arrays[0][idim] = idim;
3262 op_axes_arrays[1][idim] = idim;
3263 }
3264
3265 /* The per-operand flags for the outer loop */
3266 op_flags[0] = NPY_ITER_READWRITE0x00010000 |
3267 NPY_ITER_NO_BROADCAST0x08000000 |
3268 NPY_ITER_ALLOCATE0x01000000 |
3269 NPY_ITER_NO_SUBTYPE0x02000000;
3270 op_flags[1] = NPY_ITER_READONLY0x00020000;
3271
3272 op[0] = out;
3273 op[1] = arr;
3274
3275 need_outer_iterator = (ndim > 1);
3276 /* We can't buffer, so must do UPDATEIFCOPY */
3277 if (!PyArray_ISALIGNED(arr)PyArray_CHKFLAGS((arr), 0x0100) || (out && !PyArray_ISALIGNED(out)PyArray_CHKFLAGS((out), 0x0100)) ||
3278 !PyArray_EquivTypes(op_dtypes[0], PyArray_DESCR(arr)) ||
3279 (out &&
3280 !PyArray_EquivTypes(op_dtypes[0], PyArray_DESCR(out)))) {
3281 need_outer_iterator = 1;
3282 }
3283 /* If input and output overlap in memory, use iterator to figure it out */
3284 else if (out != NULL((void*)0) && solve_may_share_memory(out, arr, NPY_MAY_SHARE_BOUNDS0) != 0) {
3285 need_outer_iterator = 1;
3286 }
3287
3288 if (need_outer_iterator) {
3289 int ndim_iter = 0;
3290 npy_uint32 flags = NPY_ITER_ZEROSIZE_OK0x00000040|
3291 NPY_ITER_REFS_OK0x00000020|
3292 NPY_ITER_COPY_IF_OVERLAP0x00002000;
3293 PyArray_Descr **op_dtypes_param = NULL((void*)0);
3294
3295 /*
3296 * The way accumulate is set up, we can't do buffering,
3297 * so make a copy instead when necessary.
3298 */
3299 ndim_iter = ndim;
3300 flags |= NPY_ITER_MULTI_INDEX0x00000004;
3301 /*
3302 * Add some more flags.
3303 *
3304 * The accumulation outer loop is 'elementwise' over the array, so turn
3305 * on NPY_ITER_OVERLAP_ASSUME_ELEMENTWISE. That is, in-place
3306 * accumulate(x, out=x) is safe to do without temporary copies.
3307 */
3308 op_flags[0] |= NPY_ITER_UPDATEIFCOPY0x00800000|NPY_ITER_ALIGNED0x00100000|NPY_ITER_OVERLAP_ASSUME_ELEMENTWISE0x40000000;
3309 op_flags[1] |= NPY_ITER_COPY0x00400000|NPY_ITER_ALIGNED0x00100000|NPY_ITER_OVERLAP_ASSUME_ELEMENTWISE0x40000000;
3310 op_dtypes_param = op_dtypes;
3311 op_dtypes[1] = op_dtypes[0];
3312 NPY_UF_DBG_PRINT("Allocating outer iterator\n");
3313 iter = NpyIter_AdvancedNew(2, op, flags,
3314 NPY_KEEPORDER, NPY_UNSAFE_CASTING,
3315 op_flags,
3316 op_dtypes_param,
3317 ndim_iter, op_axes, NULL((void*)0), 0);
3318 if (iter == NULL((void*)0)) {
3319 goto fail;
3320 }
3321
3322 /* In case COPY or UPDATEIFCOPY occurred */
3323 op[0] = NpyIter_GetOperandArray(iter)[0];
3324 op[1] = NpyIter_GetOperandArray(iter)[1];
3325
3326 if (NpyIter_RemoveAxis(iter, axis) != NPY_SUCCEED1) {
3327 goto fail;
3328 }
3329 if (NpyIter_RemoveMultiIndex(iter) != NPY_SUCCEED1) {
3330 goto fail;
3331 }
3332 }
3333
3334 /* Get the output */
3335 if (out == NULL((void*)0)) {
3336 if (iter) {
3337 op[0] = out = NpyIter_GetOperandArray(iter)[0];
3338 Py_INCREF(out)_Py_INCREF(((PyObject*)(out)));
3339 }
3340 else {
3341 PyArray_Descr *dtype = op_dtypes[0];
3342 Py_INCREF(dtype)_Py_INCREF(((PyObject*)(dtype)));
3343 op[0] = out = (PyArrayObject *)PyArray_NewFromDescr(
3344 &PyArray_Type, dtype,
3345 ndim, PyArray_DIMS(op[1]), NULL((void*)0), NULL((void*)0),
3346 0, NULL((void*)0));
3347 if (out == NULL((void*)0)) {
3348 goto fail;
3349 }
3350
3351 }
3352 }
3353
3354 /*
3355 * If the reduction axis has size zero, either return the reduction
3356 * unit for UFUNC_REDUCE, or return the zero-sized output array
3357 * for UFUNC_ACCUMULATE.
3358 */
3359 if (PyArray_DIM(op[1], axis) == 0) {
3360 goto finish;
3361 }
3362 else if (PyArray_SIZE(op[0])PyArray_MultiplyList(PyArray_DIMS(op[0]), PyArray_NDIM(op[0])
)
== 0) {
3363 goto finish;
3364 }
3365
3366 if (iter && NpyIter_GetIterSize(iter) != 0) {
3367 char *dataptr_copy[3];
3368 npy_intp stride_copy[3];
3369 npy_intp count_m1, stride0, stride1;
3370
3371 NpyIter_IterNextFunc *iternext;
3372 char **dataptr;
3373
3374 int itemsize = op_dtypes[0]->elsize;
3375
3376 /* Get the variables needed for the loop */
3377 iternext = NpyIter_GetIterNext(iter, NULL((void*)0));
3378 if (iternext == NULL((void*)0)) {
3379 goto fail;
3380 }
3381 dataptr = NpyIter_GetDataPtrArray(iter);
3382 needs_api = NpyIter_IterationNeedsAPI(iter);
3383
3384
3385 /* Execute the loop with just the outer iterator */
3386 count_m1 = PyArray_DIM(op[1], axis)-1;
3387 stride0 = 0, stride1 = PyArray_STRIDE(op[1], axis);
3388
3389 NPY_UF_DBG_PRINT("UFunc: Reduce loop with just outer iterator\n");
3390
3391 stride0 = PyArray_STRIDE(op[0], axis);
3392
3393 stride_copy[0] = stride0;
3394 stride_copy[1] = stride1;
3395 stride_copy[2] = stride0;
3396
3397 NPY_BEGIN_THREADS_NDITER(iter)do { if (!NpyIter_IterationNeedsAPI(iter)) { do { if ((NpyIter_GetIterSize
(iter)) > 500) { _save = PyEval_SaveThread();} } while (0)
;; } } while(0)
;
3398
3399 do {
3400 dataptr_copy[0] = dataptr[0];
3401 dataptr_copy[1] = dataptr[1];
3402 dataptr_copy[2] = dataptr[0];
3403
3404 /*
3405 * Copy the first element to start the reduction.
3406 *
3407 * Output (dataptr[0]) and input (dataptr[1]) may point to
3408 * the same memory, e.g. np.add.accumulate(a, out=a).
3409 */
3410 if (otype == NPY_OBJECT) {
3411 /*
3412 * Incref before decref to avoid the possibility of the
3413 * reference count being zero temporarily.
3414 */
3415 Py_XINCREF(*(PyObject **)dataptr_copy[1])_Py_XINCREF(((PyObject*)(*(PyObject **)dataptr_copy[1])));
3416 Py_XDECREF(*(PyObject **)dataptr_copy[0])_Py_XDECREF(((PyObject*)(*(PyObject **)dataptr_copy[0])));
3417 *(PyObject **)dataptr_copy[0] =
3418 *(PyObject **)dataptr_copy[1];
3419 }
3420 else {
3421 memmove(dataptr_copy[0], dataptr_copy[1], itemsize);
3422 }
3423
3424 if (count_m1 > 0) {
3425 /* Turn the two items into three for the inner loop */
3426 dataptr_copy[1] += stride1;
3427 dataptr_copy[2] += stride0;
3428 NPY_UF_DBG_PRINT1("iterator loop count %d\n",
3429 (int)count_m1);
3430 innerloop(dataptr_copy, &count_m1,
3431 stride_copy, innerloopdata);
3432 }
3433 } while (!(needs_api && PyErr_Occurred()) && iternext(iter));
3434
3435 NPY_END_THREADSdo { if (_save) { PyEval_RestoreThread(_save); _save = ((void
*)0);} } while (0);
;
3436 }
3437 else if (iter == NULL((void*)0)) {
3438 char *dataptr_copy[3];
3439 npy_intp stride_copy[3];
3440
3441 int itemsize = op_dtypes[0]->elsize;
3442
3443 /* Execute the loop with no iterators */
3444 npy_intp count = PyArray_DIM(op[1], axis);
3445 npy_intp stride0 = 0, stride1 = PyArray_STRIDE(op[1], axis);
3446
3447 NPY_UF_DBG_PRINT("UFunc: Reduce loop with no iterators\n");
3448
3449 if (PyArray_NDIM(op[0]) != PyArray_NDIM(op[1]) ||
3450 !PyArray_CompareLists(PyArray_DIMS(op[0]),
3451 PyArray_DIMS(op[1]),
3452 PyArray_NDIM(op[0]))) {
3453 PyErr_SetString(PyExc_ValueError,
3454 "provided out is the wrong size "
3455 "for the reduction");
3456 goto fail;
3457 }
3458 stride0 = PyArray_STRIDE(op[0], axis);
3459
3460 stride_copy[0] = stride0;
3461 stride_copy[1] = stride1;
3462 stride_copy[2] = stride0;
3463
3464 /* Turn the two items into three for the inner loop */
3465 dataptr_copy[0] = PyArray_BYTES(op[0]);
3466 dataptr_copy[1] = PyArray_BYTES(op[1]);
3467 dataptr_copy[2] = PyArray_BYTES(op[0]);
3468
3469 /*
3470 * Copy the first element to start the reduction.
3471 *
3472 * Output (dataptr[0]) and input (dataptr[1]) may point to the
3473 * same memory, e.g. np.add.accumulate(a, out=a).
3474 */
3475 if (otype == NPY_OBJECT) {
3476 /*
3477 * Incref before decref to avoid the possibility of the
3478 * reference count being zero temporarily.
3479 */
3480 Py_XINCREF(*(PyObject **)dataptr_copy[1])_Py_XINCREF(((PyObject*)(*(PyObject **)dataptr_copy[1])));
3481 Py_XDECREF(*(PyObject **)dataptr_copy[0])_Py_XDECREF(((PyObject*)(*(PyObject **)dataptr_copy[0])));
3482 *(PyObject **)dataptr_copy[0] =
3483 *(PyObject **)dataptr_copy[1];
3484 }
3485 else {
3486 memmove(dataptr_copy[0], dataptr_copy[1], itemsize);
3487 }
3488
3489 if (count > 1) {
3490 --count;
3491 dataptr_copy[1] += stride1;
3492 dataptr_copy[2] += stride0;
3493
3494 NPY_UF_DBG_PRINT1("iterator loop count %d\n", (int)count);
3495
3496 needs_api = PyDataType_REFCHK(op_dtypes[0])(((op_dtypes[0])->flags & (0x01)) == (0x01));
3497
3498 if (!needs_api) {
3499 NPY_BEGIN_THREADS_THRESHOLDED(count)do { if ((count) > 500) { _save = PyEval_SaveThread();} } while
(0);
;
3500 }
3501
3502 innerloop(dataptr_copy, &count,
3503 stride_copy, innerloopdata);
3504
3505 NPY_END_THREADSdo { if (_save) { PyEval_RestoreThread(_save); _save = ((void
*)0);} } while (0);
;
3506 }
3507 }
3508
3509finish:
3510 Py_XDECREF(op_dtypes[0])_Py_XDECREF(((PyObject*)(op_dtypes[0])));
3511 int res = 0;
3512 if (!NpyIter_Deallocate(iter)) {
3513 res = -1;
3514 }
3515 if (!NpyIter_Deallocate(iter_inner)) {
3516 res = -1;
3517 }
3518 if (res < 0) {
3519 Py_DECREF(out)_Py_DECREF(((PyObject*)(out)));
3520 return NULL((void*)0);
3521 }
3522
3523 return (PyObject *)out;
3524
3525fail:
3526 Py_XDECREF(out)_Py_XDECREF(((PyObject*)(out)));
3527 Py_XDECREF(op_dtypes[0])_Py_XDECREF(((PyObject*)(op_dtypes[0])));
3528
3529 NpyIter_Deallocate(iter);
3530 NpyIter_Deallocate(iter_inner);
3531
3532 return NULL((void*)0);
3533}
3534
3535/*
3536 * Reduceat performs a reduce over an axis using the indices as a guide
3537 *
3538 * op.reduceat(array,indices) computes
3539 * op.reduce(array[indices[i]:indices[i+1]]
3540 * for i=0..end with an implicit indices[i+1]=len(array)
3541 * assumed when i=end-1
3542 *
3543 * if indices[i+1] <= indices[i]+1
3544 * then the result is array[indices[i]] for that value
3545 *
3546 * op.accumulate(array) is the same as
3547 * op.reduceat(array,indices)[::2]
3548 * where indices is range(len(array)-1) with a zero placed in every other sample
3549 * indices = zeros(len(array)*2-1)
3550 * indices[1::2] = range(1,len(array))
3551 *
3552 * output shape is based on the size of indices
3553 */
3554static PyObject *
3555PyUFunc_Reduceat(PyUFuncObject *ufunc, PyArrayObject *arr, PyArrayObject *ind,
3556 PyArrayObject *out, int axis, int otype)
3557{
3558 PyArrayObject *op[3];
3559 PyArray_Descr *op_dtypes[3] = {NULL((void*)0), NULL((void*)0), NULL((void*)0)};
3560 int op_axes_arrays[3][NPY_MAXDIMS32];
3561 int *op_axes[3] = {op_axes_arrays[0], op_axes_arrays[1],
3562 op_axes_arrays[2]};
3563 npy_uint32 op_flags[3];
3564 int idim, ndim, otype_final;
3565 int need_outer_iterator = 0;
3566
3567 NpyIter *iter = NULL((void*)0);
3568
3569 /* The reduceat indices - ind must be validated outside this call */
3570 npy_intp *reduceat_ind;
3571 npy_intp i, ind_size, red_axis_size;
3572 /* The selected inner loop */
3573 PyUFuncGenericFunction innerloop = NULL((void*)0);
3574 void *innerloopdata = NULL((void*)0);
3575
3576 const char *ufunc_name = ufunc_get_name_cstr(ufunc);
3577 char *opname = "reduceat";
3578
3579 /* These parameters come from extobj= or from a TLS global */
3580 int buffersize = 0, errormask = 0;
3581
3582 NPY_BEGIN_THREADS_DEFPyThreadState *_save=((void*)0);;
3583
3584 reduceat_ind = (npy_intp *)PyArray_DATA(ind);
3585 ind_size = PyArray_DIM(ind, 0);
3586 red_axis_size = PyArray_DIM(arr, axis);
3587
3588 /* Check for out-of-bounds values in indices array */
3589 for (i = 0; i < ind_size; ++i) {
3590 if (reduceat_ind[i] < 0 || reduceat_ind[i] >= red_axis_size) {
3591 PyErr_Format(PyExc_IndexError,
3592 "index %" NPY_INTP_FMT"ld" " out-of-bounds in %s.%s [0, %" NPY_INTP_FMT"ld" ")",
3593 reduceat_ind[i], ufunc_name, opname, red_axis_size);
3594 return NULL((void*)0);
3595 }
3596 }
3597
3598 NPY_UF_DBG_PRINT2("\nEvaluating ufunc %s.%s\n", ufunc_name, opname);
3599
3600#if 0
3601 printf("Doing %s.%s on array with dtype : ", ufunc_name, opname)__printf_chk (2 - 1, "Doing %s.%s on array with dtype : ", ufunc_name
, opname)
;
3602 PyObject_Print((PyObject *)PyArray_DESCR(arr), stdoutstdout, 0);
3603 printf("\n")__printf_chk (2 - 1, "\n");
3604 printf("Index size is %d\n", (int)ind_size)__printf_chk (2 - 1, "Index size is %d\n", (int)ind_size);
3605#endif
3606
3607 if (_get_bufsize_errmask(NULL((void*)0), opname, &buffersize, &errormask) < 0) {
3608 return NULL((void*)0);
3609 }
3610
3611 /* Take a reference to out for later returning */
3612 Py_XINCREF(out)_Py_XINCREF(((PyObject*)(out)));
3613
3614 otype_final = otype;
3615 if (get_binary_op_function(ufunc, &otype_final,
3616 &innerloop, &innerloopdata) < 0) {
3617 PyArray_Descr *dtype = PyArray_DescrFromType(otype);
3618 PyErr_Format(PyExc_ValueError,
3619 "could not find a matching type for %s.%s, "
3620 "requested type has type code '%c'",
3621 ufunc_name, opname, dtype ? dtype->type : '-');
3622 Py_XDECREF(dtype)_Py_XDECREF(((PyObject*)(dtype)));
3623 goto fail;
3624 }
3625
3626 ndim = PyArray_NDIM(arr);
3627
3628 /*
3629 * Set up the output data type, using the input's exact
3630 * data type if the type number didn't change to preserve
3631 * metadata
3632 */
3633 if (PyArray_DESCR(arr)->type_num == otype_final) {
3634 if (PyArray_ISNBO(PyArray_DESCR(arr)->byteorder)((PyArray_DESCR(arr)->byteorder) != '>')) {
3635 op_dtypes[0] = PyArray_DESCR(arr);
3636 Py_INCREF(op_dtypes[0])_Py_INCREF(((PyObject*)(op_dtypes[0])));
3637 }
3638 else {
3639 op_dtypes[0] = PyArray_DescrNewByteorder(PyArray_DESCR(arr),
3640 NPY_NATIVE'=');
3641 }
3642 }
3643 else {
3644 op_dtypes[0] = PyArray_DescrFromType(otype_final);
3645 }
3646 if (op_dtypes[0] == NULL((void*)0)) {
3647 goto fail;
3648 }
3649
3650#if NPY_UF_DBG_TRACING0
3651 printf("Found %s.%s inner loop with dtype : ", ufunc_name, opname)__printf_chk (2 - 1, "Found %s.%s inner loop with dtype : ",
ufunc_name, opname)
;
3652 PyObject_Print((PyObject *)op_dtypes[0], stdoutstdout, 0);
3653 printf("\n")__printf_chk (2 - 1, "\n");
3654#endif
3655
3656 /* Set up the op_axes for the outer loop */
3657 for (idim = 0; idim < ndim; ++idim) {
3658 /* Use the i-th iteration dimension to match up ind */
3659 if (idim == axis) {
3660 op_axes_arrays[0][idim] = axis;
3661 op_axes_arrays[1][idim] = -1;
3662 op_axes_arrays[2][idim] = 0;
3663 }
3664 else {
3665 op_axes_arrays[0][idim] = idim;
3666 op_axes_arrays[1][idim] = idim;
3667 op_axes_arrays[2][idim] = -1;
3668 }
3669 }
3670
3671 op[0] = out;
3672 op[1] = arr;
3673 op[2] = ind;
3674
3675 if (out != NULL((void*)0) || ndim > 1 || !PyArray_ISALIGNED(arr)PyArray_CHKFLAGS((arr), 0x0100) ||
3676 !PyArray_EquivTypes(op_dtypes[0], PyArray_DESCR(arr))) {
3677 need_outer_iterator = 1;
3678 }
3679
3680 if (need_outer_iterator) {
3681 npy_uint32 flags = NPY_ITER_ZEROSIZE_OK0x00000040|
3682 NPY_ITER_REFS_OK0x00000020|
3683 NPY_ITER_MULTI_INDEX0x00000004|
3684 NPY_ITER_COPY_IF_OVERLAP0x00002000;
3685
3686 /*
3687 * The way reduceat is set up, we can't do buffering,
3688 * so make a copy instead when necessary using
3689 * the UPDATEIFCOPY flag
3690 */
3691
3692 /* The per-operand flags for the outer loop */
3693 op_flags[0] = NPY_ITER_READWRITE0x00010000|
3694 NPY_ITER_NO_BROADCAST0x08000000|
3695 NPY_ITER_ALLOCATE0x01000000|
3696 NPY_ITER_NO_SUBTYPE0x02000000|
3697 NPY_ITER_UPDATEIFCOPY0x00800000|
3698 NPY_ITER_ALIGNED0x00100000;
3699 op_flags[1] = NPY_ITER_READONLY0x00020000|
3700 NPY_ITER_COPY0x00400000|
3701 NPY_ITER_ALIGNED0x00100000;
3702 op_flags[2] = NPY_ITER_READONLY0x00020000;
3703
3704 op_dtypes[1] = op_dtypes[0];
3705
3706 NPY_UF_DBG_PRINT("Allocating outer iterator\n");
3707 iter = NpyIter_AdvancedNew(3, op, flags,
3708 NPY_KEEPORDER, NPY_UNSAFE_CASTING,
3709 op_flags,
3710 op_dtypes,
3711 ndim, op_axes, NULL((void*)0), 0);
3712 if (iter == NULL((void*)0)) {
3713 goto fail;
3714 }
3715
3716 /* Remove the inner loop axis from the outer iterator */
3717 if (NpyIter_RemoveAxis(iter, axis) != NPY_SUCCEED1) {
3718 goto fail;
3719 }
3720 if (NpyIter_RemoveMultiIndex(iter) != NPY_SUCCEED1) {
3721 goto fail;
3722 }
3723
3724 /* In case COPY or UPDATEIFCOPY occurred */
3725 op[0] = NpyIter_GetOperandArray(iter)[0];
3726 op[1] = NpyIter_GetOperandArray(iter)[1];
3727 op[2] = NpyIter_GetOperandArray(iter)[2];
3728
3729 if (out == NULL((void*)0)) {
3730 out = op[0];
3731 Py_INCREF(out)_Py_INCREF(((PyObject*)(out)));
3732 }
3733 }
3734 /* Allocate the output for when there's no outer iterator */
3735 else if (out == NULL((void*)0)) {
3736 Py_INCREF(op_dtypes[0])_Py_INCREF(((PyObject*)(op_dtypes[0])));
3737 op[0] = out = (PyArrayObject *)PyArray_NewFromDescr(
3738 &PyArray_Type, op_dtypes[0],
3739 1, &ind_size, NULL((void*)0), NULL((void*)0),
3740 0, NULL((void*)0));
3741 if (out == NULL((void*)0)) {
3742 goto fail;
3743 }
3744 }
3745
3746 /*
3747 * If the output has zero elements, return now.
3748 */
3749 if (PyArray_SIZE(op[0])PyArray_MultiplyList(PyArray_DIMS(op[0]), PyArray_NDIM(op[0])
)
== 0) {
3750 goto finish;
3751 }
3752
3753 if (iter && NpyIter_GetIterSize(iter) != 0) {
3754 char *dataptr_copy[3];
3755 npy_intp stride_copy[3];
3756
3757 NpyIter_IterNextFunc *iternext;
3758 char **dataptr;
3759 npy_intp count_m1;
3760 npy_intp stride0, stride1;
3761 npy_intp stride0_ind = PyArray_STRIDE(op[0], axis);
3762
3763 int itemsize = op_dtypes[0]->elsize;
3764 int needs_api = NpyIter_IterationNeedsAPI(iter);
3765
3766 /* Get the variables needed for the loop */
3767 iternext = NpyIter_GetIterNext(iter, NULL((void*)0));
3768 if (iternext == NULL((void*)0)) {
3769 goto fail;
3770 }
3771 dataptr = NpyIter_GetDataPtrArray(iter);
3772
3773 /* Execute the loop with just the outer iterator */
3774 count_m1 = PyArray_DIM(op[1], axis)-1;
3775 stride0 = 0;
3776 stride1 = PyArray_STRIDE(op[1], axis);
3777
3778 NPY_UF_DBG_PRINT("UFunc: Reduce loop with just outer iterator\n");
3779
3780 stride_copy[0] = stride0;
3781 stride_copy[1] = stride1;
3782 stride_copy[2] = stride0;
3783
3784 NPY_BEGIN_THREADS_NDITER(iter)do { if (!NpyIter_IterationNeedsAPI(iter)) { do { if ((NpyIter_GetIterSize
(iter)) > 500) { _save = PyEval_SaveThread();} } while (0)
;; } } while(0)
;
3785
3786 do {
3787
3788 for (i = 0; i < ind_size; ++i) {
3789 npy_intp start = reduceat_ind[i],
3790 end = (i == ind_size-1) ? count_m1+1 :
3791 reduceat_ind[i+1];
3792 npy_intp count = end - start;
3793
3794 dataptr_copy[0] = dataptr[0] + stride0_ind*i;
3795 dataptr_copy[1] = dataptr[1] + stride1*start;
3796 dataptr_copy[2] = dataptr[0] + stride0_ind*i;
3797
3798 /*
3799 * Copy the first element to start the reduction.
3800 *
3801 * Output (dataptr[0]) and input (dataptr[1]) may point
3802 * to the same memory, e.g.
3803 * np.add.reduceat(a, np.arange(len(a)), out=a).
3804 */
3805 if (otype == NPY_OBJECT) {
3806 /*
3807 * Incref before decref to avoid the possibility of
3808 * the reference count being zero temporarily.
3809 */
3810 Py_XINCREF(*(PyObject **)dataptr_copy[1])_Py_XINCREF(((PyObject*)(*(PyObject **)dataptr_copy[1])));
3811 Py_XDECREF(*(PyObject **)dataptr_copy[0])_Py_XDECREF(((PyObject*)(*(PyObject **)dataptr_copy[0])));
3812 *(PyObject **)dataptr_copy[0] =
3813 *(PyObject **)dataptr_copy[1];
3814 }
3815 else {
3816 memmove(dataptr_copy[0], dataptr_copy[1], itemsize);
3817 }
3818
3819 if (count > 1) {
3820 /* Inner loop like REDUCE */
3821 --count;
3822 dataptr_copy[1] += stride1;
3823 NPY_UF_DBG_PRINT1("iterator loop count %d\n",
3824 (int)count);
3825 innerloop(dataptr_copy, &count,
3826 stride_copy, innerloopdata);
3827 }
3828 }
3829 } while (!(needs_api && PyErr_Occurred()) && iternext(iter));
3830
3831 NPY_END_THREADSdo { if (_save) { PyEval_RestoreThread(_save); _save = ((void
*)0);} } while (0);
;
3832 }
3833 else if (iter == NULL((void*)0)) {
3834 char *dataptr_copy[3];
3835 npy_intp stride_copy[3];
3836
3837 int itemsize = op_dtypes[0]->elsize;
3838
3839 npy_intp stride0_ind = PyArray_STRIDE(op[0], axis);
3840
3841 /* Execute the loop with no iterators */
3842 npy_intp stride0 = 0, stride1 = PyArray_STRIDE(op[1], axis);
3843
3844 int needs_api = PyDataType_REFCHK(op_dtypes[0])(((op_dtypes[0])->flags & (0x01)) == (0x01));
3845
3846 NPY_UF_DBG_PRINT("UFunc: Reduce loop with no iterators\n");
3847
3848 stride_copy[0] = stride0;
3849 stride_copy[1] = stride1;
3850 stride_copy[2] = stride0;
3851
3852 if (!needs_api) {
3853 NPY_BEGIN_THREADSdo {_save = PyEval_SaveThread();} while (0);;
3854 }
3855
3856 for (i = 0; i < ind_size; ++i) {
3857 npy_intp start = reduceat_ind[i],
3858 end = (i == ind_size-1) ? PyArray_DIM(arr,axis) :
3859 reduceat_ind[i+1];
3860 npy_intp count = end - start;
3861
3862 dataptr_copy[0] = PyArray_BYTES(op[0]) + stride0_ind*i;
3863 dataptr_copy[1] = PyArray_BYTES(op[1]) + stride1*start;
3864 dataptr_copy[2] = PyArray_BYTES(op[0]) + stride0_ind*i;
3865
3866 /*
3867 * Copy the first element to start the reduction.
3868 *
3869 * Output (dataptr[0]) and input (dataptr[1]) may point to
3870 * the same memory, e.g.
3871 * np.add.reduceat(a, np.arange(len(a)), out=a).
3872 */
3873 if (otype == NPY_OBJECT) {
3874 /*
3875 * Incref before decref to avoid the possibility of the
3876 * reference count being zero temporarily.
3877 */
3878 Py_XINCREF(*(PyObject **)dataptr_copy[1])_Py_XINCREF(((PyObject*)(*(PyObject **)dataptr_copy[1])));
3879 Py_XDECREF(*(PyObject **)dataptr_copy[0])_Py_XDECREF(((PyObject*)(*(PyObject **)dataptr_copy[0])));
3880 *(PyObject **)dataptr_copy[0] =
3881 *(PyObject **)dataptr_copy[1];
3882 }
3883 else {
3884 memmove(dataptr_copy[0], dataptr_copy[1], itemsize);
3885 }
3886
3887 if (count > 1) {
3888 /* Inner loop like REDUCE */
3889 --count;
3890 dataptr_copy[1] += stride1;
3891 NPY_UF_DBG_PRINT1("iterator loop count %d\n",
3892 (int)count);
3893 innerloop(dataptr_copy, &count,
3894 stride_copy, innerloopdata);
3895 }
3896 }
3897
3898 NPY_END_THREADSdo { if (_save) { PyEval_RestoreThread(_save); _save = ((void
*)0);} } while (0);
;
3899 }
3900
3901finish:
3902 Py_XDECREF(op_dtypes[0])_Py_XDECREF(((PyObject*)(op_dtypes[0])));
3903 if (!NpyIter_Deallocate(iter)) {
3904 Py_DECREF(out)_Py_DECREF(((PyObject*)(out)));
3905 return NULL((void*)0);
3906 }
3907
3908 return (PyObject *)out;
3909
3910fail:
3911 Py_XDECREF(out)_Py_XDECREF(((PyObject*)(out)));
3912 Py_XDECREF(op_dtypes[0])_Py_XDECREF(((PyObject*)(op_dtypes[0])));
3913
3914 NpyIter_Deallocate(iter);
3915 return NULL((void*)0);
3916}
3917
3918
3919static npy_bool
3920tuple_all_none(PyObject *tup) {
3921 npy_intp i;
3922 for (i = 0; i < PyTuple_GET_SIZE(tup)(((PyVarObject*)((((void) (0)), (PyTupleObject *)(tup))))->
ob_size)
; ++i) {
3923 if (PyTuple_GET_ITEM(tup, i)((((void) (0)), (PyTupleObject *)(tup))->ob_item[i]) != Py_None(&_Py_NoneStruct)) {
3924 return NPY_FALSE0;
3925 }
3926 }
3927 return NPY_TRUE1;
3928}
3929
3930
3931static int
3932_set_full_args_out(int nout, PyObject *out_obj, ufunc_full_args *full_args)
3933{
3934 if (PyTuple_CheckExact(out_obj)((((PyObject*)(out_obj))->ob_type) == &PyTuple_Type)) {
3935 if (PyTuple_GET_SIZE(out_obj)(((PyVarObject*)((((void) (0)), (PyTupleObject *)(out_obj))))
->ob_size)
!= nout) {
3936 PyErr_SetString(PyExc_ValueError,
3937 "The 'out' tuple must have exactly "
3938 "one entry per ufunc output");
3939 return -1;
3940 }
3941 if (tuple_all_none(out_obj)) {
3942 return 0;
3943 }
3944 else {
3945 Py_INCREF(out_obj)_Py_INCREF(((PyObject*)(out_obj)));
3946 full_args->out = out_obj;
3947 }
3948 }
3949 else if (nout == 1) {
3950 if (out_obj == Py_None(&_Py_NoneStruct)) {
3951 return 0;
3952 }
3953 /* Can be an array if it only has one output */
3954 full_args->out = PyTuple_Pack(1, out_obj);
3955 if (full_args->out == NULL((void*)0)) {
3956 return -1;
3957 }
3958 }
3959 else {
3960 PyErr_SetString(PyExc_TypeError,
3961 nout > 1 ? "'out' must be a tuple of arrays" :
3962 "'out' must be an array or a tuple with "
3963 "a single array");
3964 return -1;
3965 }
3966 return 0;
3967}
3968
3969
3970/*
3971 * Convert function which replaces np._NoValue with NULL.
3972 * As a converter returns 0 on error and 1 on success.
3973 */
3974static int
3975_not_NoValue(PyObject *obj, PyObject **out)
3976{
3977 static PyObject *NoValue = NULL((void*)0);
3978 npy_cache_import("numpy", "_NoValue", &NoValue);
3979 if (NoValue == NULL((void*)0)) {
3980 return 0;
3981 }
3982 if (obj == NoValue) {
3983 *out = NULL((void*)0);
3984 }
3985 else {
3986 *out = obj;
3987 }
3988 return 1;
3989}
3990
3991
3992/* forward declaration */
3993static PyArray_DTypeMeta * _get_dtype(PyObject *dtype_obj);
3994
3995/*
3996 * This code handles reduce, reduceat, and accumulate
3997 * (accumulate and reduce are special cases of the more general reduceat
3998 * but they are handled separately for speed)
3999 */
4000static PyObject *
4001PyUFunc_GenericReduction(PyUFuncObject *ufunc,
4002 PyObject *const *args, Py_ssize_t len_args, PyObject *kwnames, int operation)
4003{
4004 int i, naxes=0, ndim;
4005 int axes[NPY_MAXDIMS32];
4006
4007 ufunc_full_args full_args = {NULL((void*)0), NULL((void*)0)};
4008 PyObject *axes_obj = NULL((void*)0);
4009 PyArrayObject *mp = NULL((void*)0), *wheremask = NULL((void*)0), *ret = NULL((void*)0);
4010 PyObject *op = NULL((void*)0);
4011 PyArrayObject *indices = NULL((void*)0);
4012 PyArray_Descr *otype = NULL((void*)0);
4013 PyArrayObject *out = NULL((void*)0);
4014 int keepdims = 0;
4015 PyObject *initial = NULL((void*)0);
4016 npy_bool out_is_passed_by_position;
4017
4018
4019 static char *_reduce_type[] = {"reduce", "accumulate", "reduceat", NULL((void*)0)};
4020
4021 if (ufunc == NULL((void*)0)) {
4022 PyErr_SetString(PyExc_ValueError, "function not supported");
4023 return NULL((void*)0);
4024 }
4025 if (ufunc->core_enabled) {
4026 PyErr_Format(PyExc_RuntimeError,
4027 "Reduction not defined on ufunc with signature");
4028 return NULL((void*)0);
4029 }
4030 if (ufunc->nin != 2) {
4031 PyErr_Format(PyExc_ValueError,
4032 "%s only supported for binary functions",
4033 _reduce_type[operation]);
4034 return NULL((void*)0);
4035 }
4036 if (ufunc->nout != 1) {
4037 PyErr_Format(PyExc_ValueError,
4038 "%s only supported for functions "
4039 "returning a single value",
4040 _reduce_type[operation]);
4041 return NULL((void*)0);
4042 }
4043
4044 /*
4045 * Perform argument parsing, but start by only extracting. This is
4046 * just to preserve the behaviour that __array_ufunc__ did not perform
4047 * any checks on arguments, and we could change this or change it for
4048 * certain parameters.
4049 */
4050 PyObject *otype_obj = NULL((void*)0), *out_obj = NULL((void*)0), *indices_obj = NULL((void*)0);
4051 PyObject *keepdims_obj = NULL((void*)0), *wheremask_obj = NULL((void*)0);
4052 if (operation == UFUNC_REDUCEAT2) {
4053 NPY_PREPARE_ARGPARSERstatic _NpyArgParserCache __argparse_cache = {-1};
4054
4055 if (npy_parse_arguments("reduceat", args, len_args, kwnames,_npy_parse_arguments("reduceat", &__argparse_cache, args,
len_args, kwnames, "array", ((void*)0), &op, "indices", (
(void*)0), &indices_obj, "|axis", ((void*)0), &axes_obj
, "|dtype", ((void*)0), &otype_obj, "|out", ((void*)0), &
out_obj, ((void*)0), ((void*)0), ((void*)0))
4056 "array", NULL, &op,_npy_parse_arguments("reduceat", &__argparse_cache, args,
len_args, kwnames, "array", ((void*)0), &op, "indices", (
(void*)0), &indices_obj, "|axis", ((void*)0), &axes_obj
, "|dtype", ((void*)0), &otype_obj, "|out", ((void*)0), &
out_obj, ((void*)0), ((void*)0), ((void*)0))
4057 "indices", NULL, &indices_obj,_npy_parse_arguments("reduceat", &__argparse_cache, args,
len_args, kwnames, "array", ((void*)0), &op, "indices", (
(void*)0), &indices_obj, "|axis", ((void*)0), &axes_obj
, "|dtype", ((void*)0), &otype_obj, "|out", ((void*)0), &
out_obj, ((void*)0), ((void*)0), ((void*)0))
4058 "|axis", NULL, &axes_obj,_npy_parse_arguments("reduceat", &__argparse_cache, args,
len_args, kwnames, "array", ((void*)0), &op, "indices", (
(void*)0), &indices_obj, "|axis", ((void*)0), &axes_obj
, "|dtype", ((void*)0), &otype_obj, "|out", ((void*)0), &
out_obj, ((void*)0), ((void*)0), ((void*)0))
4059 "|dtype", NULL, &otype_obj,_npy_parse_arguments("reduceat", &__argparse_cache, args,
len_args, kwnames, "array", ((void*)0), &op, "indices", (
(void*)0), &indices_obj, "|axis", ((void*)0), &axes_obj
, "|dtype", ((void*)0), &otype_obj, "|out", ((void*)0), &
out_obj, ((void*)0), ((void*)0), ((void*)0))
4060 "|out", NULL, &out_obj,_npy_parse_arguments("reduceat", &__argparse_cache, args,
len_args, kwnames, "array", ((void*)0), &op, "indices", (
(void*)0), &indices_obj, "|axis", ((void*)0), &axes_obj
, "|dtype", ((void*)0), &otype_obj, "|out", ((void*)0), &
out_obj, ((void*)0), ((void*)0), ((void*)0))
4061 NULL, NULL, NULL)_npy_parse_arguments("reduceat", &__argparse_cache, args,
len_args, kwnames, "array", ((void*)0), &op, "indices", (
(void*)0), &indices_obj, "|axis", ((void*)0), &axes_obj
, "|dtype", ((void*)0), &otype_obj, "|out", ((void*)0), &
out_obj, ((void*)0), ((void*)0), ((void*)0))
< 0) {
4062 goto fail;
4063 }
4064 /* Prepare inputs for PyUfunc_CheckOverride */
4065 full_args.in = PyTuple_Pack(2, op, indices_obj);
4066 if (full_args.in == NULL((void*)0)) {
4067 goto fail;
4068 }
4069 out_is_passed_by_position = len_args >= 5;
4070 }
4071 else if (operation == UFUNC_ACCUMULATE1) {
4072 NPY_PREPARE_ARGPARSERstatic _NpyArgParserCache __argparse_cache = {-1};
4073
4074 if (npy_parse_arguments("accumulate", args, len_args, kwnames,_npy_parse_arguments("accumulate", &__argparse_cache, args
, len_args, kwnames, "array", ((void*)0), &op, "|axis", (
(void*)0), &axes_obj, "|dtype", ((void*)0), &otype_obj
, "|out", ((void*)0), &out_obj, ((void*)0), ((void*)0), (
(void*)0))
4075 "array", NULL, &op,_npy_parse_arguments("accumulate", &__argparse_cache, args
, len_args, kwnames, "array", ((void*)0), &op, "|axis", (
(void*)0), &axes_obj, "|dtype", ((void*)0), &otype_obj
, "|out", ((void*)0), &out_obj, ((void*)0), ((void*)0), (
(void*)0))
4076 "|axis", NULL, &axes_obj,_npy_parse_arguments("accumulate", &__argparse_cache, args
, len_args, kwnames, "array", ((void*)0), &op, "|axis", (
(void*)0), &axes_obj, "|dtype", ((void*)0), &otype_obj
, "|out", ((void*)0), &out_obj, ((void*)0), ((void*)0), (
(void*)0))
4077 "|dtype", NULL, &otype_obj,_npy_parse_arguments("accumulate", &__argparse_cache, args
, len_args, kwnames, "array", ((void*)0), &op, "|axis", (
(void*)0), &axes_obj, "|dtype", ((void*)0), &otype_obj
, "|out", ((void*)0), &out_obj, ((void*)0), ((void*)0), (
(void*)0))
4078 "|out", NULL, &out_obj,_npy_parse_arguments("accumulate", &__argparse_cache, args
, len_args, kwnames, "array", ((void*)0), &op, "|axis", (
(void*)0), &axes_obj, "|dtype", ((void*)0), &otype_obj
, "|out", ((void*)0), &out_obj, ((void*)0), ((void*)0), (
(void*)0))
4079 NULL, NULL, NULL)_npy_parse_arguments("accumulate", &__argparse_cache, args
, len_args, kwnames, "array", ((void*)0), &op, "|axis", (
(void*)0), &axes_obj, "|dtype", ((void*)0), &otype_obj
, "|out", ((void*)0), &out_obj, ((void*)0), ((void*)0), (
(void*)0))
< 0) {
4080 goto fail;
4081 }
4082 /* Prepare input for PyUfunc_CheckOverride */
4083 full_args.in = PyTuple_Pack(1, op);
4084 if (full_args.in == NULL((void*)0)) {
4085 goto fail;
4086 }
4087 out_is_passed_by_position = len_args >= 4;
4088 }
4089 else {
4090 NPY_PREPARE_ARGPARSERstatic _NpyArgParserCache __argparse_cache = {-1};
4091
4092 if (npy_parse_arguments("reduce", args, len_args, kwnames,_npy_parse_arguments("reduce", &__argparse_cache, args, len_args
, kwnames, "array", ((void*)0), &op, "|axis", ((void*)0),
&axes_obj, "|dtype", ((void*)0), &otype_obj, "|out",
((void*)0), &out_obj, "|keepdims", ((void*)0), &keepdims_obj
, "|initial", &_not_NoValue, &initial, "|where", ((void
*)0), &wheremask_obj, ((void*)0), ((void*)0), ((void*)0))
4093 "array", NULL, &op,_npy_parse_arguments("reduce", &__argparse_cache, args, len_args
, kwnames, "array", ((void*)0), &op, "|axis", ((void*)0),
&axes_obj, "|dtype", ((void*)0), &otype_obj, "|out",
((void*)0), &out_obj, "|keepdims", ((void*)0), &keepdims_obj
, "|initial", &_not_NoValue, &initial, "|where", ((void
*)0), &wheremask_obj, ((void*)0), ((void*)0), ((void*)0))
4094 "|axis", NULL, &axes_obj,_npy_parse_arguments("reduce", &__argparse_cache, args, len_args
, kwnames, "array", ((void*)0), &op, "|axis", ((void*)0),
&axes_obj, "|dtype", ((void*)0), &otype_obj, "|out",
((void*)0), &out_obj, "|keepdims", ((void*)0), &keepdims_obj
, "|initial", &_not_NoValue, &initial, "|where", ((void
*)0), &wheremask_obj, ((void*)0), ((void*)0), ((void*)0))
4095 "|dtype", NULL, &otype_obj,_npy_parse_arguments("reduce", &__argparse_cache, args, len_args
, kwnames, "array", ((void*)0), &op, "|axis", ((void*)0),
&axes_obj, "|dtype", ((void*)0), &otype_obj, "|out",
((void*)0), &out_obj, "|keepdims", ((void*)0), &keepdims_obj
, "|initial", &_not_NoValue, &initial, "|where", ((void
*)0), &wheremask_obj, ((void*)0), ((void*)0), ((void*)0))
4096 "|out", NULL, &out_obj,_npy_parse_arguments("reduce", &__argparse_cache, args, len_args
, kwnames, "array", ((void*)0), &op, "|axis", ((void*)0),
&axes_obj, "|dtype", ((void*)0), &otype_obj, "|out",
((void*)0), &out_obj, "|keepdims", ((void*)0), &keepdims_obj
, "|initial", &_not_NoValue, &initial, "|where", ((void
*)0), &wheremask_obj, ((void*)0), ((void*)0), ((void*)0))
4097 "|keepdims", NULL, &keepdims_obj,_npy_parse_arguments("reduce", &__argparse_cache, args, len_args
, kwnames, "array", ((void*)0), &op, "|axis", ((void*)0),
&axes_obj, "|dtype", ((void*)0), &otype_obj, "|out",
((void*)0), &out_obj, "|keepdims", ((void*)0), &keepdims_obj
, "|initial", &_not_NoValue, &initial, "|where", ((void
*)0), &wheremask_obj, ((void*)0), ((void*)0), ((void*)0))
4098 "|initial", &_not_NoValue, &initial,_npy_parse_arguments("reduce", &__argparse_cache, args, len_args
, kwnames, "array", ((void*)0), &op, "|axis", ((void*)0),
&axes_obj, "|dtype", ((void*)0), &otype_obj, "|out",
((void*)0), &out_obj, "|keepdims", ((void*)0), &keepdims_obj
, "|initial", &_not_NoValue, &initial, "|where", ((void
*)0), &wheremask_obj, ((void*)0), ((void*)0), ((void*)0))
4099 "|where", NULL, &wheremask_obj,_npy_parse_arguments("reduce", &__argparse_cache, args, len_args
, kwnames, "array", ((void*)0), &op, "|axis", ((void*)0),
&axes_obj, "|dtype", ((void*)0), &otype_obj, "|out",
((void*)0), &out_obj, "|keepdims", ((void*)0), &keepdims_obj
, "|initial", &_not_NoValue, &initial, "|where", ((void
*)0), &wheremask_obj, ((void*)0), ((void*)0), ((void*)0))
4100 NULL, NULL, NULL)_npy_parse_arguments("reduce", &__argparse_cache, args, len_args
, kwnames, "array", ((void*)0), &op, "|axis", ((void*)0),
&axes_obj, "|dtype", ((void*)0), &otype_obj, "|out",
((void*)0), &out_obj, "|keepdims", ((void*)0), &keepdims_obj
, "|initial", &_not_NoValue, &initial, "|where", ((void
*)0), &wheremask_obj, ((void*)0), ((void*)0), ((void*)0))
< 0) {
4101 goto fail;
4102 }
4103 /* Prepare input for PyUfunc_CheckOverride */
4104 full_args.in = PyTuple_Pack(1, op);
4105 if (full_args.in == NULL((void*)0)) {
4106 goto fail;
4107 }
4108 out_is_passed_by_position = len_args >= 4;
4109 }
4110
4111 /* Normalize output for PyUFunc_CheckOverride and conversion. */
4112 if (out_is_passed_by_position) {
4113 /* in this branch, out is always wrapped in a tuple. */
4114 if (out_obj != Py_None(&_Py_NoneStruct)) {
4115 full_args.out = PyTuple_Pack(1, out_obj);
4116 if (full_args.out == NULL((void*)0)) {
4117 goto fail;
4118 }
4119 }
4120 }
4121 else if (out_obj) {
4122 if (_set_full_args_out(1, out_obj, &full_args) < 0) {
4123 goto fail;
4124 }
4125 /* Ensure that out_obj is the array, not the tuple: */
4126 if (full_args.out != NULL((void*)0)) {
4127 out_obj = PyTuple_GET_ITEM(full_args.out, 0)((((void) (0)), (PyTupleObject *)(full_args.out))->ob_item
[0])
;
4128 }
4129 }
4130
4131 /* We now have all the information required to check for Overrides */
4132 PyObject *override = NULL((void*)0);
4133 int errval = PyUFunc_CheckOverride(ufunc, _reduce_type[operation],
4134 full_args.in, full_args.out, args, len_args, kwnames, &override);
4135 if (errval) {
4136 return NULL((void*)0);
4137 }
4138 else if (override) {
4139 Py_XDECREF(full_args.in)_Py_XDECREF(((PyObject*)(full_args.in)));
4140 Py_XDECREF(full_args.out)_Py_XDECREF(((PyObject*)(full_args.out)));
4141 return override;
4142 }
4143
4144 /* Finish parsing of all parameters (no matter which reduce-like) */
4145 if (indices_obj) {
4146 PyArray_Descr *indtype = PyArray_DescrFromType(NPY_INTPNPY_LONG);
4147
4148 indices = (PyArrayObject *)PyArray_FromAny(indices_obj,
4149 indtype, 1, 1, NPY_ARRAY_CARRAY(0x0001 | (0x0100 | 0x0400)), NULL((void*)0));
4150 if (indices == NULL((void*)0)) {
4151 goto fail;
4152 }
4153 }
4154 if (otype_obj && otype_obj != Py_None(&_Py_NoneStruct)) {
4155 /* Use `_get_dtype` because `dtype` is a DType and not the instance */
4156 PyArray_DTypeMeta *dtype = _get_dtype(otype_obj);
4157 if (dtype == NULL((void*)0)) {
4158 goto fail;
4159 }
4160 Py_INCREF(dtype->singleton)_Py_INCREF(((PyObject*)(dtype->singleton)));
4161 otype = dtype->singleton;
4162 }
4163 if (out_obj && !PyArray_OutputConverter(out_obj, &out)) {
4164 goto fail;
4165 }
4166 if (keepdims_obj && !PyArray_PythonPyIntFromInt(keepdims_obj, &keepdims)) {
4167 goto fail;
4168 }
4169 if (wheremask_obj && !_wheremask_converter(wheremask_obj, &wheremask)) {
4170 goto fail;
4171 }
4172
4173 /* Ensure input is an array */
4174 mp = (PyArrayObject *)PyArray_FromAny(op, NULL((void*)0), 0, 0, 0, NULL((void*)0));
4175 if (mp == NULL((void*)0)) {
4176 goto fail;
4177 }
4178
4179 ndim = PyArray_NDIM(mp);
4180
4181 /* Check to see that type (and otype) is not FLEXIBLE */
4182 if (PyArray_ISFLEXIBLE(mp)(((PyArray_TYPE(mp)) >=NPY_STRING) && ((PyArray_TYPE
(mp)) <=NPY_VOID))
||
4183 (otype && PyTypeNum_ISFLEXIBLE(otype->type_num)(((otype->type_num) >=NPY_STRING) && ((otype->
type_num) <=NPY_VOID))
)) {
4184 PyErr_Format(PyExc_TypeError,
4185 "cannot perform %s with flexible type",
4186 _reduce_type[operation]);
4187 goto fail;
4188 }
4189
4190 /* Convert the 'axis' parameter into a list of axes */
4191 if (axes_obj == NULL((void*)0)) {
4192 /* apply defaults */
4193 if (ndim == 0) {
4194 naxes = 0;
4195 }
4196 else {
4197 naxes = 1;
4198 axes[0] = 0;
4199 }
4200 }
4201 else if (axes_obj == Py_None(&_Py_NoneStruct)) {
4202 /* Convert 'None' into all the axes */
4203 naxes = ndim;
4204 for (i = 0; i < naxes; ++i) {
4205 axes[i] = i;
4206 }
4207 }
4208 else if (PyTuple_Check(axes_obj)((((((PyObject*)(axes_obj))->ob_type))->tp_flags & (
(1UL << 26))) != 0)
) {
4209 naxes = PyTuple_Size(axes_obj);
4210 if (naxes < 0 || naxes > NPY_MAXDIMS32) {
4211 PyErr_SetString(PyExc_ValueError,
4212 "too many values for 'axis'");
4213 goto fail;
4214 }
4215 for (i = 0; i < naxes; ++i) {
4216 PyObject *tmp = PyTuple_GET_ITEM(axes_obj, i)((((void) (0)), (PyTupleObject *)(axes_obj))->ob_item[i]);
4217 int axis = PyArray_PyIntAsInt(tmp);
4218 if (error_converting(axis)(((axis) == -1) && PyErr_Occurred())) {
4219 goto fail;
4220 }
4221 if (check_and_adjust_axis(&axis, ndim) < 0) {
4222 goto fail;
4223 }
4224 axes[i] = (int)axis;
4225 }
4226 }
4227 else {
4228 /* Try to interpret axis as an integer */
4229 int axis = PyArray_PyIntAsInt(axes_obj);
4230 /* TODO: PyNumber_Index would be good to use here */
4231 if (error_converting(axis)(((axis) == -1) && PyErr_Occurred())) {
4232 goto fail;
4233 }
4234 /*
4235 * As a special case for backwards compatibility in 'sum',
4236 * 'prod', et al, also allow a reduction for scalars even
4237 * though this is technically incorrect.
4238 */
4239 if (ndim == 0 && (axis == 0 || axis == -1)) {
4240 naxes = 0;
4241 }
4242 else if (check_and_adjust_axis(&axis, ndim) < 0) {
4243 goto fail;
4244 }
4245 else {
4246 axes[0] = (int)axis;
4247 naxes = 1;
4248 }
4249 }
4250
4251 /*
4252 * If out is specified it determines otype
4253 * unless otype already specified.
4254 */
4255 if (otype == NULL((void*)0) && out != NULL((void*)0)) {
4256 otype = PyArray_DESCR(out);
4257 Py_INCREF(otype)_Py_INCREF(((PyObject*)(otype)));
4258 }
4259 if (otype == NULL((void*)0)) {
4260 /*
4261 * For integer types --- make sure at least a long
4262 * is used for add and multiply reduction to avoid overflow
4263 */
4264 int typenum = PyArray_TYPE(mp);
4265 if ((PyTypeNum_ISBOOL(typenum)((typenum) == NPY_BOOL) || PyTypeNum_ISINTEGER(typenum)(((typenum) >= NPY_BYTE) && ((typenum) <= NPY_ULONGLONG
))
)
4266 && ((strcmp(ufunc->name,"add") == 0)
4267 || (strcmp(ufunc->name,"multiply") == 0))) {
4268 if (PyTypeNum_ISBOOL(typenum)((typenum) == NPY_BOOL)) {
4269 typenum = NPY_LONG;
4270 }
4271 else if ((size_t)PyArray_DESCR(mp)->elsize < sizeof(long)) {
4272 if (PyTypeNum_ISUNSIGNED(typenum)(((typenum) == NPY_UBYTE) || ((typenum) == NPY_USHORT) || ((typenum
) == NPY_UINT) || ((typenum) == NPY_ULONG) || ((typenum) == NPY_ULONGLONG
))
) {
4273 typenum = NPY_ULONG;
4274 }
4275 else {
4276 typenum = NPY_LONG;
4277 }
4278 }
4279 }
4280 otype = PyArray_DescrFromType(typenum);
4281 }
4282
4283
4284 switch(operation) {
4285 case UFUNC_REDUCE0:
4286 ret = PyUFunc_Reduce(ufunc, mp, out, naxes, axes,
4287 otype, keepdims, initial, wheremask);
4288 Py_XDECREF(wheremask)_Py_XDECREF(((PyObject*)(wheremask)));
4289 break;
4290 case UFUNC_ACCUMULATE1:
4291 if (ndim == 0) {
4292 PyErr_SetString(PyExc_TypeError, "cannot accumulate on a scalar");
4293 goto fail;
4294 }
4295 if (naxes != 1) {
4296 PyErr_SetString(PyExc_ValueError,
4297 "accumulate does not allow multiple axes");
4298 goto fail;
4299 }
4300 ret = (PyArrayObject *)PyUFunc_Accumulate(ufunc, mp, out, axes[0],
4301 otype->type_num);
4302 break;
4303 case UFUNC_REDUCEAT2:
4304 if (ndim == 0) {
4305 PyErr_SetString(PyExc_TypeError, "cannot reduceat on a scalar");
4306 goto fail;
4307 }
4308 if (naxes != 1) {
4309 PyErr_SetString(PyExc_ValueError,
4310 "reduceat does not allow multiple axes");
4311 goto fail;
4312 }
4313 ret = (PyArrayObject *)PyUFunc_Reduceat(ufunc, mp, indices, out,
4314 axes[0], otype->type_num);
4315 Py_DECREF(indices)_Py_DECREF(((PyObject*)(indices)));
4316 break;
4317 }
4318 Py_DECREF(mp)_Py_DECREF(((PyObject*)(mp)));
4319 Py_DECREF(otype)_Py_DECREF(((PyObject*)(otype)));
4320 Py_XDECREF(full_args.in)_Py_XDECREF(((PyObject*)(full_args.in)));
4321 Py_XDECREF(full_args.out)_Py_XDECREF(((PyObject*)(full_args.out)));
4322
4323 if (ret == NULL((void*)0)) {
4324 return NULL((void*)0);
4325 }
4326
4327 /* Wrap and return the output */
4328 {
4329 /* Find __array_wrap__ - note that these rules are different to the
4330 * normal ufunc path
4331 */
4332 PyObject *wrap;
4333 if (out != NULL((void*)0)) {
4334 wrap = Py_None(&_Py_NoneStruct);
4335 Py_INCREF(wrap)_Py_INCREF(((PyObject*)(wrap)));
4336 }
4337 else if (Py_TYPE(op)(((PyObject*)(op))->ob_type) != Py_TYPE(ret)(((PyObject*)(ret))->ob_type)) {
4338 wrap = PyObject_GetAttr(op, npy_um_str_array_wrap);
4339 if (wrap == NULL((void*)0)) {
4340 PyErr_Clear();
4341 }
4342 else if (!PyCallable_Check(wrap)) {
4343 Py_DECREF(wrap)_Py_DECREF(((PyObject*)(wrap)));
4344 wrap = NULL((void*)0);
4345 }
4346 }
4347 else {
4348 wrap = NULL((void*)0);
4349 }
4350 return _apply_array_wrap(wrap, ret, NULL((void*)0));
4351 }
4352
4353fail:
4354 Py_XDECREF(otype)_Py_XDECREF(((PyObject*)(otype)));
4355 Py_XDECREF(mp)_Py_XDECREF(((PyObject*)(mp)));
4356 Py_XDECREF(wheremask)_Py_XDECREF(((PyObject*)(wheremask)));
4357 Py_XDECREF(full_args.in)_Py_XDECREF(((PyObject*)(full_args.in)));
4358 Py_XDECREF(full_args.out)_Py_XDECREF(((PyObject*)(full_args.out)));
4359 return NULL((void*)0);
4360}
4361
4362
4363/*
4364 * Perform a basic check on `dtype`, `sig`, and `signature` since only one
4365 * may be set. If `sig` is used, writes it into `out_signature` (which should
4366 * be set to `signature_obj` so that following code only requires to handle
4367 * `signature_obj`).
4368 *
4369 * Does NOT incref the output! This only copies the borrowed references
4370 * gotten during the argument parsing.
4371 *
4372 * This function does not do any normalization of the input dtype tuples,
4373 * this happens after the array-ufunc override check currently.
4374 */
4375static int
4376_check_and_copy_sig_to_signature(
4377 PyObject *sig_obj, PyObject *signature_obj, PyObject *dtype,
4378 PyObject **out_signature)
4379{
4380 *out_signature = NULL((void*)0);
4381 if (signature_obj != NULL((void*)0)) {
4382 *out_signature = signature_obj;
4383 }
4384
4385 if (sig_obj != NULL((void*)0)) {
4386 if (*out_signature != NULL((void*)0)) {
4387 PyErr_SetString(PyExc_TypeError,
4388 "cannot specify both 'sig' and 'signature'");
4389 *out_signature = NULL((void*)0);
4390 return -1;
4391 }
4392 *out_signature = sig_obj;
4393 }
4394
4395 if (dtype != NULL((void*)0)) {
4396 if (*out_signature != NULL((void*)0)) {
4397 PyErr_SetString(PyExc_TypeError,
4398 "cannot specify both 'signature' and 'dtype'");
4399 return -1;
4400 }
4401 /* dtype needs to be converted, delay after the override check */
4402 }
4403 return 0;
4404}
4405
4406
4407/*
4408 * Note: This function currently lets DType classes pass, but in general
4409 * the class (not the descriptor instance) is the preferred input, so the
4410 * parsing should eventually be adapted to prefer classes and possible
4411 * deprecated instances. (Users should not notice that much, since `np.float64`
4412 * or "float64" usually denotes the DType class rather than the instance.)
4413 */
4414static PyArray_DTypeMeta *
4415_get_dtype(PyObject *dtype_obj) {
4416 if (PyObject_TypeCheck(dtype_obj, &PyArrayDTypeMeta_Type)((((PyObject*)(dtype_obj))->ob_type) == (&PyArrayDTypeMeta_Type
) || PyType_IsSubtype((((PyObject*)(dtype_obj))->ob_type),
(&PyArrayDTypeMeta_Type)))
) {
4417 Py_INCREF(dtype_obj)_Py_INCREF(((PyObject*)(dtype_obj)));
4418 return (PyArray_DTypeMeta *)dtype_obj;
4419 }
4420 else {
4421 PyArray_Descr *descr = NULL((void*)0);
4422 if (!PyArray_DescrConverter(dtype_obj, &descr)) {
4423 return NULL((void*)0);
4424 }
4425 PyArray_DTypeMeta *out = NPY_DTYPE(descr)((PyArray_DTypeMeta *)(((PyObject*)(descr))->ob_type));
4426 if (NPY_UNLIKELY(!out->legacy)__builtin_expect(!!(!out->legacy), 0)) {
4427 /* TODO: this path was unreachable when added. */
4428 PyErr_SetString(PyExc_TypeError,
4429 "Cannot pass a new user DType instance to the `dtype` or "
4430 "`signature` arguments of ufuncs. Pass the DType class "
4431 "instead.");
4432 Py_DECREF(descr)_Py_DECREF(((PyObject*)(descr)));
4433 return NULL((void*)0);
4434 }
4435 else if (NPY_UNLIKELY(out->singleton != descr)__builtin_expect(!!(out->singleton != descr), 0)) {
4436 /* This does not warn about `metadata`, but units is important. */
4437 if (!PyArray_EquivTypes(out->singleton, descr)) {
4438 PyErr_Format(PyExc_TypeError,
4439 "The `dtype` and `signature` arguments to "
4440 "ufuncs only select the general DType and not details "
4441 "such as the byte order or time unit (with rare "
4442 "exceptions see release notes). To avoid this warning "
4443 "please use the scalar types `np.float64`, or string "
4444 "notation.\n"
4445 "In rare cases where the time unit was preserved, "
4446 "either cast the inputs or provide an output array. "
4447 "In the future NumPy may transition to allow providing "
4448 "`dtype=` to denote the outputs `dtype` as well");
4449 Py_DECREF(descr)_Py_DECREF(((PyObject*)(descr)));
4450 return NULL((void*)0);
4451 }
4452 }
4453 Py_INCREF(out)_Py_INCREF(((PyObject*)(out)));
4454 Py_DECREF(descr)_Py_DECREF(((PyObject*)(descr)));
4455 return out;
4456 }
4457}
4458
4459
4460static int
4461_make_new_typetup(
4462 int nop, PyArray_DTypeMeta *signature[], PyObject **out_typetup) {
4463 *out_typetup = PyTuple_New(nop);
4464 if (*out_typetup == NULL((void*)0)) {
4465 return -1;
4466 }
4467
4468 int noncount = 0;
4469 for (int i = 0; i < nop; i++) {
4470 PyObject *item;
4471 if (signature[i] == NULL((void*)0)) {
4472 item = Py_None(&_Py_NoneStruct);
4473 noncount++;
4474 }
4475 else {
4476 if (!signature[i]->legacy || signature[i]->abstract) {
4477 /*
4478 * The legacy type resolution can't deal with these.
4479 * This path will return `None` or so in the future to
4480 * set an error later if the legacy type resolution is used.
4481 */
4482 PyErr_SetString(PyExc_RuntimeError,
4483 "Internal NumPy error: new DType in signature not yet "
4484 "supported. (This should be unreachable code!)");
4485 Py_SETREF(*out_typetup, NULL)do { PyObject *_py_tmp = ((PyObject*)(*out_typetup)); (*out_typetup
) = (((void*)0)); _Py_DECREF(((PyObject*)(_py_tmp))); } while
(0)
;
4486 return -1;
4487 }
4488 item = (PyObject *)signature[i]->singleton;
4489 }
4490 Py_INCREF(item)_Py_INCREF(((PyObject*)(item)));
4491 PyTuple_SET_ITEM(*out_typetup, i, item)PyTuple_SetItem(*out_typetup, i, item);
4492 }
4493 if (noncount == nop) {
4494 /* The whole signature was None, simply ignore type tuple */
4495 Py_DECREF(*out_typetup)_Py_DECREF(((PyObject*)(*out_typetup)));
4496 *out_typetup = NULL((void*)0);
4497 }
4498 return 0;
4499}
4500
4501
4502/*
4503 * Finish conversion parsing of the type tuple. NumPy always only honored
4504 * the type number for passed in descriptors/dtypes.
4505 * The `dtype` argument is interpreted as the first output DType (not
4506 * descriptor).
4507 * Unlike the dtype of an `out` array, it influences loop selection!
4508 *
4509 * NOTE: This function replaces the type tuple if passed in (it steals
4510 * the original reference and returns a new object and reference)!
4511 * The caller must XDECREF the type tuple both on error or success.
4512 *
4513 * The function returns a new, normalized type-tuple.
4514 */
4515static int
4516_get_normalized_typetup(PyUFuncObject *ufunc,
4517 PyObject *dtype_obj, PyObject *signature_obj, PyObject **out_typetup)
4518{
4519 if (dtype_obj == NULL((void*)0) && signature_obj == NULL((void*)0)) {
4520 return 0;
4521 }
4522
4523 int res = -1;
4524 int nin = ufunc->nin, nout = ufunc->nout, nop = nin + nout;
4525 /*
4526 * TODO: `signature` will be the main result in the future and
4527 * not the typetup. (Type tuple construction can be deffered to when
4528 * the legacy fallback is used).
4529 */
4530 PyArray_DTypeMeta *signature[NPY_MAXARGS32];
4531 memset(signature, '\0', sizeof(*signature) * nop);
4532
4533 if (dtype_obj != NULL((void*)0)) {
4534 if (dtype_obj == Py_None(&_Py_NoneStruct)) {
4535 /* If `dtype=None` is passed, no need to do anything */
4536 assert(*out_typetup == NULL)((void) (0));
4537 return 0;
4538 }
4539 if (nout == 0) {
4540 /* This may be allowed (NumPy does not do this)? */
4541 PyErr_SetString(PyExc_TypeError,
4542 "Cannot provide `dtype` when a ufunc has no outputs");
4543 return -1;
4544 }
4545 PyArray_DTypeMeta *dtype = _get_dtype(dtype_obj);
4546 if (dtype == NULL((void*)0)) {
4547 return -1;
4548 }
4549 for (int i = nin; i < nop; i++) {
4550 Py_INCREF(dtype)_Py_INCREF(((PyObject*)(dtype)));
4551 signature[i] = dtype;
4552 }
4553 Py_DECREF(dtype)_Py_DECREF(((PyObject*)(dtype)));
4554 res = _make_new_typetup(nop, signature, out_typetup);
4555 goto finish;
4556 }
4557
4558 assert(signature_obj != NULL)((void) (0));
4559 /* Fill in specified_types from the tuple or string (signature_obj) */
4560 if (PyTuple_Check(signature_obj)((((((PyObject*)(signature_obj))->ob_type))->tp_flags &
((1UL << 26))) != 0)
) {
4561 Py_ssize_t n = PyTuple_GET_SIZE(signature_obj)(((PyVarObject*)((((void) (0)), (PyTupleObject *)(signature_obj
))))->ob_size)
;
4562 if (n == 1 && nop != 1) {
4563 /*
4564 * Special handling, because we deprecate this path. The path
4565 * probably mainly existed since the `dtype=obj` was passed through
4566 * as `(obj,)` and parsed later.
4567 */
4568 if (PyTuple_GET_ITEM(signature_obj, 0)((((void) (0)), (PyTupleObject *)(signature_obj))->ob_item
[0])
== Py_None(&_Py_NoneStruct)) {
4569 PyErr_SetString(PyExc_TypeError,
4570 "a single item type tuple cannot contain None.");
4571 goto finish;
4572 }
4573 if (DEPRECATE("The use of a length 1 tuple for the ufunc "PyErr_WarnEx(PyExc_DeprecationWarning,"The use of a length 1 tuple for the ufunc "
"`signature` is deprecated. Use `dtype` or fill the" "tuple with `None`s."
,1)
4574 "`signature` is deprecated. Use `dtype` or fill the"PyErr_WarnEx(PyExc_DeprecationWarning,"The use of a length 1 tuple for the ufunc "
"`signature` is deprecated. Use `dtype` or fill the" "tuple with `None`s."
,1)
4575 "tuple with `None`s.")PyErr_WarnEx(PyExc_DeprecationWarning,"The use of a length 1 tuple for the ufunc "
"`signature` is deprecated. Use `dtype` or fill the" "tuple with `None`s."
,1)
< 0) {
4576 goto finish;
4577 }
4578 /* Use the same logic as for `dtype=` */
4579 res = _get_normalized_typetup(ufunc,
4580 PyTuple_GET_ITEM(signature_obj, 0)((((void) (0)), (PyTupleObject *)(signature_obj))->ob_item
[0])
, NULL((void*)0), out_typetup);
4581 goto finish;
4582 }
4583 if (n != nop) {
4584 PyErr_Format(PyExc_ValueError,
4585 "a type-tuple must be specified of length %d for ufunc '%s'",
4586 nop, ufunc_get_name_cstr(ufunc));
4587 goto finish;
4588 }
4589 for (int i = 0; i < nop; ++i) {
4590 PyObject *item = PyTuple_GET_ITEM(signature_obj, i)((((void) (0)), (PyTupleObject *)(signature_obj))->ob_item
[i])
;
4591 if (item == Py_None(&_Py_NoneStruct)) {
4592 continue;
4593 }
4594 signature[i] = _get_dtype(item);
4595 if (signature[i] == NULL((void*)0)) {
4596 goto finish;
4597 }
4598 }
4599 }
4600 else if (PyBytes_Check(signature_obj)((((((PyObject*)(signature_obj))->ob_type))->tp_flags &
((1UL << 27))) != 0)
|| PyUnicode_Check(signature_obj)((((((PyObject*)(signature_obj))->ob_type))->tp_flags &
((1UL << 28))) != 0)
) {
4601 PyObject *str_object = NULL((void*)0);
4602
4603 if (PyBytes_Check(signature_obj)((((((PyObject*)(signature_obj))->ob_type))->tp_flags &
((1UL << 27))) != 0)
) {
4604 str_object = PyUnicode_FromEncodedObject(signature_obj, NULL((void*)0), NULL((void*)0));
4605 if (str_object == NULL((void*)0)) {
4606 goto finish;
4607 }
4608 }
4609 else {
4610 Py_INCREF(signature_obj)_Py_INCREF(((PyObject*)(signature_obj)));
4611 str_object = signature_obj;
4612 }
4613
4614 Py_ssize_t length;
4615 const char *str = PyUnicode_AsUTF8AndSize(str_object, &length);
4616 if (str == NULL((void*)0)) {
4617 Py_DECREF(str_object)_Py_DECREF(((PyObject*)(str_object)));
4618 goto finish;
4619 }
4620
4621 if (length != 1 && (length != nin+nout + 2 ||
4622 str[nin] != '-' || str[nin+1] != '>')) {
4623 PyErr_Format(PyExc_ValueError,
4624 "a type-string for %s, %d typecode(s) before and %d after "
4625 "the -> sign", ufunc_get_name_cstr(ufunc), nin, nout);
4626 Py_DECREF(str_object)_Py_DECREF(((PyObject*)(str_object)));
4627 goto finish;
4628 }
4629 if (length == 1 && nin+nout != 1) {
4630 Py_DECREF(str_object)_Py_DECREF(((PyObject*)(str_object)));
4631 if (DEPRECATE("The use of a length 1 string for the ufunc "PyErr_WarnEx(PyExc_DeprecationWarning,"The use of a length 1 string for the ufunc "
"`signature` is deprecated. Use `dtype` attribute or " "pass a tuple with `None`s."
,1)
4632 "`signature` is deprecated. Use `dtype` attribute or "PyErr_WarnEx(PyExc_DeprecationWarning,"The use of a length 1 string for the ufunc "
"`signature` is deprecated. Use `dtype` attribute or " "pass a tuple with `None`s."
,1)
4633 "pass a tuple with `None`s.")PyErr_WarnEx(PyExc_DeprecationWarning,"The use of a length 1 string for the ufunc "
"`signature` is deprecated. Use `dtype` attribute or " "pass a tuple with `None`s."
,1)
< 0) {
4634 goto finish;
4635 }
4636 /* `signature="l"` is the same as `dtype="l"` */
4637 res = _get_normalized_typetup(ufunc, str_object, NULL((void*)0), out_typetup);
4638 goto finish;
4639 }
4640 else {
4641 for (int i = 0; i < nin+nout; ++i) {
4642 npy_intp istr = i < nin ? i : i+2;
4643 PyArray_Descr *descr = PyArray_DescrFromType(str[istr]);
4644 if (descr == NULL((void*)0)) {
4645 Py_DECREF(str_object)_Py_DECREF(((PyObject*)(str_object)));
4646 goto finish;
4647 }
4648 signature[i] = NPY_DTYPE(descr)((PyArray_DTypeMeta *)(((PyObject*)(descr))->ob_type));
4649 Py_INCREF(signature[i])_Py_INCREF(((PyObject*)(signature[i])));
4650 Py_DECREF(descr)_Py_DECREF(((PyObject*)(descr)));
4651 }
4652 Py_DECREF(str_object)_Py_DECREF(((PyObject*)(str_object)));
4653 }
4654 }
4655 else {
4656 PyErr_SetString(PyExc_TypeError,
4657 "the signature object to ufunc must be a string or a tuple.");
4658 goto finish;
4659 }
4660 res = _make_new_typetup(nop, signature, out_typetup);
4661
4662 finish:
4663 for (int i =0; i < nop; i++) {
4664 Py_XDECREF(signature[i])_Py_XDECREF(((PyObject*)(signature[i])));
4665 }
4666 return res;
4667}
4668
4669
4670/*
4671 * Main ufunc call implementation.
4672 *
4673 * This implementation makes use of the "fastcall" way of passing keyword
4674 * arguments and is called directly from `ufunc_generic_vectorcall` when
4675 * Python has `tp_vectorcall` (Python 3.8+).
4676 * If `tp_vectorcall` is not available, the dictionary `kwargs` are unpacked in
4677 * `ufunc_generic_call` with fairly little overhead.
4678 */
4679static PyObject *
4680ufunc_generic_fastcall(PyUFuncObject *ufunc,
4681 PyObject *const *args, Py_ssize_t len_args, PyObject *kwnames,
4682 npy_bool outer)
4683{
4684 PyArrayObject *operands[NPY_MAXARGS32] = {NULL((void*)0)};
4685 PyObject *retobj[NPY_MAXARGS32];
4686 PyObject *wraparr[NPY_MAXARGS32];
4687 PyObject *override = NULL((void*)0);
4688 ufunc_full_args full_args = {NULL((void*)0), NULL((void*)0)};
4689 PyObject *typetup = NULL((void*)0);
4690
4691 int errval;
4692 int nin = ufunc->nin, nout = ufunc->nout, nop = ufunc->nargs;
4693
4694 /*
4695 * Note that the input (and possibly output) arguments are passed in as
4696 * positional arguments. We extract these first and check for `out`
4697 * passed by keyword later.
4698 * Outputs and inputs are stored in `full_args.in` and `full_args.out`
4699 * as tuples (or NULL when no outputs are passed).
4700 */
4701
4702 /* Check number of arguments */
4703 if ((len_args < nin) || (len_args > nop)) {
4704 PyErr_Format(PyExc_TypeError,
4705 "%s() takes from %d to %d positional arguments but "
4706 "%zd were given",
4707 ufunc_get_name_cstr(ufunc) , nin, nop, len_args);
4708 return NULL((void*)0);
4709 }
4710
4711 /* Fetch input arguments. */
4712 full_args.in = PyTuple_New(ufunc->nin);
4713 if (full_args.in == NULL((void*)0)) {
4714 return NULL((void*)0);
4715 }
4716 for (int i = 0; i < ufunc->nin; i++) {
4717 PyObject *tmp = args[i];
4718 Py_INCREF(tmp)_Py_INCREF(((PyObject*)(tmp)));
4719 PyTuple_SET_ITEM(full_args.in, i, tmp)PyTuple_SetItem(full_args.in, i, tmp);
4720 }
4721
4722 /*
4723 * If there are more arguments, they define the out args. Otherwise
4724 * full_args.out is NULL for now, and the `out` kwarg may still be passed.
4725 */
4726 npy_bool out_is_passed_by_position = len_args > nin;
4727 if (out_is_passed_by_position) {
4728 npy_bool all_none = NPY_TRUE1;
4729
4730 full_args.out = PyTuple_New(nout);
4731 if (full_args.out == NULL((void*)0)) {
4732 goto fail;
4733 }
4734 for (int i = nin; i < nop; i++) {
4735 PyObject *tmp;
4736 if (i < (int)len_args) {
4737 tmp = args[i];
4738 if (tmp != Py_None(&_Py_NoneStruct)) {
4739 all_none = NPY_FALSE0;
4740 }
4741 }
4742 else {
4743 tmp = Py_None(&_Py_NoneStruct);
4744 }
4745 Py_INCREF(tmp)_Py_INCREF(((PyObject*)(tmp)));
4746 PyTuple_SET_ITEM(full_args.out, i-nin, tmp)PyTuple_SetItem(full_args.out, i-nin, tmp);
4747 }
4748 if (all_none) {
4749 Py_SETREF(full_args.out, NULL)do { PyObject *_py_tmp = ((PyObject*)(full_args.out)); (full_args
.out) = (((void*)0)); _Py_DECREF(((PyObject*)(_py_tmp))); } while
(0)
;
4750 }
4751 }
4752 else {
4753 full_args.out = NULL((void*)0);
4754 }
4755
4756 /*
4757 * We have now extracted (but not converted) the input arguments.
4758 * To simplify overrides, extract all other arguments (as objects only)
4759 */
4760 PyObject *out_obj = NULL((void*)0), *where_obj = NULL((void*)0);
4761 PyObject *axes_obj = NULL((void*)0), *axis_obj = NULL((void*)0);
4762 PyObject *keepdims_obj = NULL((void*)0), *casting_obj = NULL((void*)0), *order_obj = NULL((void*)0);
4763 PyObject *subok_obj = NULL((void*)0), *signature_obj = NULL((void*)0), *sig_obj = NULL((void*)0);
4764 PyObject *dtype_obj = NULL((void*)0), *extobj = NULL((void*)0);
4765
4766 /* Skip parsing if there are no keyword arguments, nothing left to do */
4767 if (kwnames != NULL((void*)0)) {
4768 if (!ufunc->core_enabled) {
4769 NPY_PREPARE_ARGPARSERstatic _NpyArgParserCache __argparse_cache = {-1};
4770
4771 if (npy_parse_arguments(ufunc->name, args + len_args, 0, kwnames,_npy_parse_arguments(ufunc->name, &__argparse_cache, args
+ len_args, 0, kwnames, "$out", ((void*)0), &out_obj, "$where"
, ((void*)0), &where_obj, "$casting", ((void*)0), &casting_obj
, "$order", ((void*)0), &order_obj, "$subok", ((void*)0),
&subok_obj, "$dtype", ((void*)0), &dtype_obj, "$signature"
, ((void*)0), &signature_obj, "$sig", ((void*)0), &sig_obj
, "$extobj", ((void*)0), &extobj, ((void*)0), ((void*)0),
((void*)0))
4772 "$out", NULL, &out_obj,_npy_parse_arguments(ufunc->name, &__argparse_cache, args
+ len_args, 0, kwnames, "$out", ((void*)0), &out_obj, "$where"
, ((void*)0), &where_obj, "$casting", ((void*)0), &casting_obj
, "$order", ((void*)0), &order_obj, "$subok", ((void*)0),
&subok_obj, "$dtype", ((void*)0), &dtype_obj, "$signature"
, ((void*)0), &signature_obj, "$sig", ((void*)0), &sig_obj
, "$extobj", ((void*)0), &extobj, ((void*)0), ((void*)0),
((void*)0))
4773 "$where", NULL, &where_obj,_npy_parse_arguments(ufunc->name, &__argparse_cache, args
+ len_args, 0, kwnames, "$out", ((void*)0), &out_obj, "$where"
, ((void*)0), &where_obj, "$casting", ((void*)0), &casting_obj
, "$order", ((void*)0), &order_obj, "$subok", ((void*)0),
&subok_obj, "$dtype", ((void*)0), &dtype_obj, "$signature"
, ((void*)0), &signature_obj, "$sig", ((void*)0), &sig_obj
, "$extobj", ((void*)0), &extobj, ((void*)0), ((void*)0),
((void*)0))
4774 "$casting", NULL, &casting_obj,_npy_parse_arguments(ufunc->name, &__argparse_cache, args
+ len_args, 0, kwnames, "$out", ((void*)0), &out_obj, "$where"
, ((void*)0), &where_obj, "$casting", ((void*)0), &casting_obj
, "$order", ((void*)0), &order_obj, "$subok", ((void*)0),
&subok_obj, "$dtype", ((void*)0), &dtype_obj, "$signature"
, ((void*)0), &signature_obj, "$sig", ((void*)0), &sig_obj
, "$extobj", ((void*)0), &extobj, ((void*)0), ((void*)0),
((void*)0))
4775 "$order", NULL, &order_obj,_npy_parse_arguments(ufunc->name, &__argparse_cache, args
+ len_args, 0, kwnames, "$out", ((void*)0), &out_obj, "$where"
, ((void*)0), &where_obj, "$casting", ((void*)0), &casting_obj
, "$order", ((void*)0), &order_obj, "$subok", ((void*)0),
&subok_obj, "$dtype", ((void*)0), &dtype_obj, "$signature"
, ((void*)0), &signature_obj, "$sig", ((void*)0), &sig_obj
, "$extobj", ((void*)0), &extobj, ((void*)0), ((void*)0),
((void*)0))
4776 "$subok", NULL, &subok_obj,_npy_parse_arguments(ufunc->name, &__argparse_cache, args
+ len_args, 0, kwnames, "$out", ((void*)0), &out_obj, "$where"
, ((void*)0), &where_obj, "$casting", ((void*)0), &casting_obj
, "$order", ((void*)0), &order_obj, "$subok", ((void*)0),
&subok_obj, "$dtype", ((void*)0), &dtype_obj, "$signature"
, ((void*)0), &signature_obj, "$sig", ((void*)0), &sig_obj
, "$extobj", ((void*)0), &extobj, ((void*)0), ((void*)0),
((void*)0))
4777 "$dtype", NULL, &dtype_obj,_npy_parse_arguments(ufunc->name, &__argparse_cache, args
+ len_args, 0, kwnames, "$out", ((void*)0), &out_obj, "$where"
, ((void*)0), &where_obj, "$casting", ((void*)0), &casting_obj
, "$order", ((void*)0), &order_obj, "$subok", ((void*)0),
&subok_obj, "$dtype", ((void*)0), &dtype_obj, "$signature"
, ((void*)0), &signature_obj, "$sig", ((void*)0), &sig_obj
, "$extobj", ((void*)0), &extobj, ((void*)0), ((void*)0),
((void*)0))
4778 "$signature", NULL, &signature_obj,_npy_parse_arguments(ufunc->name, &__argparse_cache, args
+ len_args, 0, kwnames, "$out", ((void*)0), &out_obj, "$where"
, ((void*)0), &where_obj, "$casting", ((void*)0), &casting_obj
, "$order", ((void*)0), &order_obj, "$subok", ((void*)0),
&subok_obj, "$dtype", ((void*)0), &dtype_obj, "$signature"
, ((void*)0), &signature_obj, "$sig", ((void*)0), &sig_obj
, "$extobj", ((void*)0), &extobj, ((void*)0), ((void*)0),
((void*)0))
4779 "$sig", NULL, &sig_obj,_npy_parse_arguments(ufunc->name, &__argparse_cache, args
+ len_args, 0, kwnames, "$out", ((void*)0), &out_obj, "$where"
, ((void*)0), &where_obj, "$casting", ((void*)0), &casting_obj
, "$order", ((void*)0), &order_obj, "$subok", ((void*)0),
&subok_obj, "$dtype", ((void*)0), &dtype_obj, "$signature"
, ((void*)0), &signature_obj, "$sig", ((void*)0), &sig_obj
, "$extobj", ((void*)0), &extobj, ((void*)0), ((void*)0),
((void*)0))
4780 "$extobj", NULL, &extobj,_npy_parse_arguments(ufunc->name, &__argparse_cache, args
+ len_args, 0, kwnames, "$out", ((void*)0), &out_obj, "$where"
, ((void*)0), &where_obj, "$casting", ((void*)0), &casting_obj
, "$order", ((void*)0), &order_obj, "$subok", ((void*)0),
&subok_obj, "$dtype", ((void*)0), &dtype_obj, "$signature"
, ((void*)0), &signature_obj, "$sig", ((void*)0), &sig_obj
, "$extobj", ((void*)0), &extobj, ((void*)0), ((void*)0),
((void*)0))
4781 NULL, NULL, NULL)_npy_parse_arguments(ufunc->name, &__argparse_cache, args
+ len_args, 0, kwnames, "$out", ((void*)0), &out_obj, "$where"
, ((void*)0), &where_obj, "$casting", ((void*)0), &casting_obj
, "$order", ((void*)0), &order_obj, "$subok", ((void*)0),
&subok_obj, "$dtype", ((void*)0), &dtype_obj, "$signature"
, ((void*)0), &signature_obj, "$sig", ((void*)0), &sig_obj
, "$extobj", ((void*)0), &extobj, ((void*)0), ((void*)0),
((void*)0))
< 0) {
4782 goto fail;
4783 }
4784 }
4785 else {
4786 NPY_PREPARE_ARGPARSERstatic _NpyArgParserCache __argparse_cache = {-1};
4787
4788 if (npy_parse_arguments(ufunc->name, args + len_args, 0, kwnames,_npy_parse_arguments(ufunc->name, &__argparse_cache, args
+ len_args, 0, kwnames, "$out", ((void*)0), &out_obj, "$axes"
, ((void*)0), &axes_obj, "$axis", ((void*)0), &axis_obj
, "$keepdims", ((void*)0), &keepdims_obj, "$casting", ((void
*)0), &casting_obj, "$order", ((void*)0), &order_obj,
"$subok", ((void*)0), &subok_obj, "$dtype", ((void*)0), &
dtype_obj, "$signature", ((void*)0), &signature_obj, "$sig"
, ((void*)0), &sig_obj, "$extobj", ((void*)0), &extobj
, ((void*)0), ((void*)0), ((void*)0))
4789 "$out", NULL, &out_obj,_npy_parse_arguments(ufunc->name, &__argparse_cache, args
+ len_args, 0, kwnames, "$out", ((void*)0), &out_obj, "$axes"
, ((void*)0), &axes_obj, "$axis", ((void*)0), &axis_obj
, "$keepdims", ((void*)0), &keepdims_obj, "$casting", ((void
*)0), &casting_obj, "$order", ((void*)0), &order_obj,
"$subok", ((void*)0), &subok_obj, "$dtype", ((void*)0), &
dtype_obj, "$signature", ((void*)0), &signature_obj, "$sig"
, ((void*)0), &sig_obj, "$extobj", ((void*)0), &extobj
, ((void*)0), ((void*)0), ((void*)0))
4790 "$axes", NULL, &axes_obj,_npy_parse_arguments(ufunc->name, &__argparse_cache, args
+ len_args, 0, kwnames, "$out", ((void*)0), &out_obj, "$axes"
, ((void*)0), &axes_obj, "$axis", ((void*)0), &axis_obj
, "$keepdims", ((void*)0), &keepdims_obj, "$casting", ((void
*)0), &casting_obj, "$order", ((void*)0), &order_obj,
"$subok", ((void*)0), &subok_obj, "$dtype", ((void*)0), &
dtype_obj, "$signature", ((void*)0), &signature_obj, "$sig"
, ((void*)0), &sig_obj, "$extobj", ((void*)0), &extobj
, ((void*)0), ((void*)0), ((void*)0))
4791 "$axis", NULL, &axis_obj,_npy_parse_arguments(ufunc->name, &__argparse_cache, args
+ len_args, 0, kwnames, "$out", ((void*)0), &out_obj, "$axes"
, ((void*)0), &axes_obj, "$axis", ((void*)0), &axis_obj
, "$keepdims", ((void*)0), &keepdims_obj, "$casting", ((void
*)0), &casting_obj, "$order", ((void*)0), &order_obj,
"$subok", ((void*)0), &subok_obj, "$dtype", ((void*)0), &
dtype_obj, "$signature", ((void*)0), &signature_obj, "$sig"
, ((void*)0), &sig_obj, "$extobj", ((void*)0), &extobj
, ((void*)0), ((void*)0), ((void*)0))
4792 "$keepdims", NULL, &keepdims_obj,_npy_parse_arguments(ufunc->name, &__argparse_cache, args
+ len_args, 0, kwnames, "$out", ((void*)0), &out_obj, "$axes"
, ((void*)0), &axes_obj, "$axis", ((void*)0), &axis_obj
, "$keepdims", ((void*)0), &keepdims_obj, "$casting", ((void
*)0), &casting_obj, "$order", ((void*)0), &order_obj,
"$subok", ((void*)0), &subok_obj, "$dtype", ((void*)0), &
dtype_obj, "$signature", ((void*)0), &signature_obj, "$sig"
, ((void*)0), &sig_obj, "$extobj", ((void*)0), &extobj
, ((void*)0), ((void*)0), ((void*)0))
4793 "$casting", NULL, &casting_obj,_npy_parse_arguments(ufunc->name, &__argparse_cache, args
+ len_args, 0, kwnames, "$out", ((void*)0), &out_obj, "$axes"
, ((void*)0), &axes_obj, "$axis", ((void*)0), &axis_obj
, "$keepdims", ((void*)0), &keepdims_obj, "$casting", ((void
*)0), &casting_obj, "$order", ((void*)0), &order_obj,
"$subok", ((void*)0), &subok_obj, "$dtype", ((void*)0), &
dtype_obj, "$signature", ((void*)0), &signature_obj, "$sig"
, ((void*)0), &sig_obj, "$extobj", ((void*)0), &extobj
, ((void*)0), ((void*)0), ((void*)0))
4794 "$order", NULL, &order_obj,_npy_parse_arguments(ufunc->name, &__argparse_cache, args
+ len_args, 0, kwnames, "$out", ((void*)0), &out_obj, "$axes"
, ((void*)0), &axes_obj, "$axis", ((void*)0), &axis_obj
, "$keepdims", ((void*)0), &keepdims_obj, "$casting", ((void
*)0), &casting_obj, "$order", ((void*)0), &order_obj,
"$subok", ((void*)0), &subok_obj, "$dtype", ((void*)0), &
dtype_obj, "$signature", ((void*)0), &signature_obj, "$sig"
, ((void*)0), &sig_obj, "$extobj", ((void*)0), &extobj
, ((void*)0), ((void*)0), ((void*)0))
4795 "$subok", NULL, &subok_obj,_npy_parse_arguments(ufunc->name, &__argparse_cache, args
+ len_args, 0, kwnames, "$out", ((void*)0), &out_obj, "$axes"
, ((void*)0), &axes_obj, "$axis", ((void*)0), &axis_obj
, "$keepdims", ((void*)0), &keepdims_obj, "$casting", ((void
*)0), &casting_obj, "$order", ((void*)0), &order_obj,
"$subok", ((void*)0), &subok_obj, "$dtype", ((void*)0), &
dtype_obj, "$signature", ((void*)0), &signature_obj, "$sig"
, ((void*)0), &sig_obj, "$extobj", ((void*)0), &extobj
, ((void*)0), ((void*)0), ((void*)0))
4796 "$dtype", NULL, &dtype_obj,_npy_parse_arguments(ufunc->name, &__argparse_cache, args
+ len_args, 0, kwnames, "$out", ((void*)0), &out_obj, "$axes"
, ((void*)0), &axes_obj, "$axis", ((void*)0), &axis_obj
, "$keepdims", ((void*)0), &keepdims_obj, "$casting", ((void
*)0), &casting_obj, "$order", ((void*)0), &order_obj,
"$subok", ((void*)0), &subok_obj, "$dtype", ((void*)0), &
dtype_obj, "$signature", ((void*)0), &signature_obj, "$sig"
, ((void*)0), &sig_obj, "$extobj", ((void*)0), &extobj
, ((void*)0), ((void*)0), ((void*)0))
4797 "$signature", NULL, &signature_obj,_npy_parse_arguments(ufunc->name, &__argparse_cache, args
+ len_args, 0, kwnames, "$out", ((void*)0), &out_obj, "$axes"
, ((void*)0), &axes_obj, "$axis", ((void*)0), &axis_obj
, "$keepdims", ((void*)0), &keepdims_obj, "$casting", ((void
*)0), &casting_obj, "$order", ((void*)0), &order_obj,
"$subok", ((void*)0), &subok_obj, "$dtype", ((void*)0), &
dtype_obj, "$signature", ((void*)0), &signature_obj, "$sig"
, ((void*)0), &sig_obj, "$extobj", ((void*)0), &extobj
, ((void*)0), ((void*)0), ((void*)0))
4798 "$sig", NULL, &sig_obj,_npy_parse_arguments(ufunc->name, &__argparse_cache, args
+ len_args, 0, kwnames, "$out", ((void*)0), &out_obj, "$axes"
, ((void*)0), &axes_obj, "$axis", ((void*)0), &axis_obj
, "$keepdims", ((void*)0), &keepdims_obj, "$casting", ((void
*)0), &casting_obj, "$order", ((void*)0), &order_obj,
"$subok", ((void*)0), &subok_obj, "$dtype", ((void*)0), &
dtype_obj, "$signature", ((void*)0), &signature_obj, "$sig"
, ((void*)0), &sig_obj, "$extobj", ((void*)0), &extobj
, ((void*)0), ((void*)0), ((void*)0))
4799 "$extobj", NULL, &extobj,_npy_parse_arguments(ufunc->name, &__argparse_cache, args
+ len_args, 0, kwnames, "$out", ((void*)0), &out_obj, "$axes"
, ((void*)0), &axes_obj, "$axis", ((void*)0), &axis_obj
, "$keepdims", ((void*)0), &keepdims_obj, "$casting", ((void
*)0), &casting_obj, "$order", ((void*)0), &order_obj,
"$subok", ((void*)0), &subok_obj, "$dtype", ((void*)0), &
dtype_obj, "$signature", ((void*)0), &signature_obj, "$sig"
, ((void*)0), &sig_obj, "$extobj", ((void*)0), &extobj
, ((void*)0), ((void*)0), ((void*)0))
4800 NULL, NULL, NULL)_npy_parse_arguments(ufunc->name, &__argparse_cache, args
+ len_args, 0, kwnames, "$out", ((void*)0), &out_obj, "$axes"
, ((void*)0), &axes_obj, "$axis", ((void*)0), &axis_obj
, "$keepdims", ((void*)0), &keepdims_obj, "$casting", ((void
*)0), &casting_obj, "$order", ((void*)0), &order_obj,
"$subok", ((void*)0), &subok_obj, "$dtype", ((void*)0), &
dtype_obj, "$signature", ((void*)0), &signature_obj, "$sig"
, ((void*)0), &sig_obj, "$extobj", ((void*)0), &extobj
, ((void*)0), ((void*)0), ((void*)0))
< 0) {
4801 goto fail;
4802 }
4803 if (NPY_UNLIKELY((axes_obj != NULL) && (axis_obj != NULL))__builtin_expect(!!((axes_obj != ((void*)0)) && (axis_obj
!= ((void*)0))), 0)
) {
4804 PyErr_SetString(PyExc_TypeError,
4805 "cannot specify both 'axis' and 'axes'");
4806 goto fail;
4807 }
4808 }
4809
4810 /* Handle `out` arguments passed by keyword */
4811 if (out_obj != NULL((void*)0)) {
4812 if (out_is_passed_by_position) {
4813 PyErr_SetString(PyExc_TypeError,
4814 "cannot specify 'out' as both a "
4815 "positional and keyword argument");
4816 goto fail;
4817 }
4818 if (_set_full_args_out(nout, out_obj, &full_args) < 0) {
4819 goto fail;
4820 }
4821 }
4822 /*
4823 * Only one of signature, sig, and dtype should be passed. If `sig`
4824 * was passed, this puts it into `signature_obj` instead (these
4825 * are borrowed references).
4826 */
4827 if (_check_and_copy_sig_to_signature(
4828 sig_obj, signature_obj, dtype_obj, &signature_obj) < 0) {
4829 goto fail;
4830 }
4831 }
4832
4833 char *method;
4834 if (!outer) {
4835 method = "__call__";
4836 }
4837 else {
4838 method = "outer";
4839 }
4840 /* We now have all the information required to check for Overrides */
4841 errval = PyUFunc_CheckOverride(ufunc, method,
4842 full_args.in, full_args.out,
4843 args, len_args, kwnames, &override);
4844 if (errval) {
4845 goto fail;
4846 }
4847 else if (override) {
4848 Py_DECREF(full_args.in)_Py_DECREF(((PyObject*)(full_args.in)));
4849 Py_XDECREF(full_args.out)_Py_XDECREF(((PyObject*)(full_args.out)));
4850 return override;
4851 }
4852
4853 if (outer) {
4854 /* Outer uses special preparation of inputs (expand dims) */
4855 PyObject *new_in = prepare_input_arguments_for_outer(full_args.in, ufunc);
4856 if (new_in == NULL((void*)0)) {
4857 goto fail;
4858 }
4859 Py_SETREF(full_args.in, new_in)do { PyObject *_py_tmp = ((PyObject*)(full_args.in)); (full_args
.in) = (new_in); _Py_DECREF(((PyObject*)(_py_tmp))); } while (
0)
;
4860 }
4861
4862 /*
4863 * Parse the passed `dtype` or `signature` into an array containing
4864 * PyArray_DTypeMeta and/or None.
4865 */
4866 if (_get_normalized_typetup(ufunc, dtype_obj, signature_obj, &typetup) < 0) {
4867 goto fail;
4868 }
4869
4870 NPY_ORDER order = NPY_KEEPORDER;
4871 NPY_CASTING casting = NPY_DEFAULT_ASSIGN_CASTING;
4872 npy_bool subok = NPY_TRUE1;
4873 int keepdims = -1; /* We need to know if it was passed */
4874 PyArrayObject *wheremask = NULL((void*)0);
4875 if (convert_ufunc_arguments(ufunc, full_args, operands,
4876 order_obj, &order,
4877 casting_obj, &casting,
4878 subok_obj, &subok,
4879 where_obj, &wheremask,
4880 keepdims_obj, &keepdims) < 0) {
4881 goto fail;
4882 }
4883
4884 if (!ufunc->core_enabled) {
4885 errval = PyUFunc_GenericFunctionInternal(ufunc, operands,
4886 full_args, typetup, extobj, casting, order, subok,
4887 wheremask);
4888 Py_XDECREF(wheremask)_Py_XDECREF(((PyObject*)(wheremask)));
4889 }
4890 else {
4891 errval = PyUFunc_GeneralizedFunctionInternal(ufunc, operands,
4892 full_args, typetup, extobj, casting, order, subok,
4893 axis_obj, axes_obj, keepdims);
4894 }
4895
4896 if (errval < 0) {
4897 goto fail;
4898 }
4899
4900 /* Free the input references */
4901 for (int i = 0; i < ufunc->nin; i++) {
4902 Py_XSETREF(operands[i], NULL)do { PyObject *_py_tmp = ((PyObject*)(operands[i])); (operands
[i]) = (((void*)0)); _Py_XDECREF(((PyObject*)(_py_tmp))); } while
(0)
;
4903 }
4904
4905 /*
4906 * Use __array_wrap__ on all outputs
4907 * if present on one of the input arguments.
4908 * If present for multiple inputs:
4909 * use __array_wrap__ of input object with largest
4910 * __array_priority__ (default = 0.0)
4911 *
4912 * Exception: we should not wrap outputs for items already
4913 * passed in as output-arguments. These items should either
4914 * be left unwrapped or wrapped by calling their own __array_wrap__
4915 * routine.
4916 *
4917 * For each output argument, wrap will be either
4918 * NULL --- call PyArray_Return() -- default if no output arguments given
4919 * None --- array-object passed in don't call PyArray_Return
4920 * method --- the __array_wrap__ method to call.
4921 */
4922 _find_array_wrap(full_args, subok, wraparr, ufunc->nin, ufunc->nout);
4923
4924 /* wrap outputs */
4925 for (int i = 0; i < ufunc->nout; i++) {
4926 int j = ufunc->nin+i;
4927 _ufunc_context context;
4928 PyObject *wrapped;
4929
4930 context.ufunc = ufunc;
4931 context.args = full_args;
4932 context.out_i = i;
4933
4934 wrapped = _apply_array_wrap(wraparr[i], operands[j], &context);
4935 operands[j] = NULL((void*)0); /* Prevent fail double-freeing this */
4936 if (wrapped == NULL((void*)0)) {
4937 for (int j = 0; j < i; j++) {
4938 Py_DECREF(retobj[j])_Py_DECREF(((PyObject*)(retobj[j])));
4939 }
4940 goto fail;
4941 }
4942
4943 retobj[i] = wrapped;
4944 }
4945
4946 Py_XDECREF(typetup)_Py_XDECREF(((PyObject*)(typetup)));
4947 Py_XDECREF(full_args.in)_Py_XDECREF(((PyObject*)(full_args.in)));
4948 Py_XDECREF(full_args.out)_Py_XDECREF(((PyObject*)(full_args.out)));
4949 if (ufunc->nout == 1) {
4950 return retobj[0];
4951 }
4952 else {
4953 PyTupleObject *ret;
4954
4955 ret = (PyTupleObject *)PyTuple_New(ufunc->nout);
4956 for (int i = 0; i < ufunc->nout; i++) {
4957 PyTuple_SET_ITEM(ret, i, retobj[i])PyTuple_SetItem(ret, i, retobj[i]);
4958 }
4959 return (PyObject *)ret;
4960 }
4961
4962fail:
4963 Py_XDECREF(typetup)_Py_XDECREF(((PyObject*)(typetup)));
4964 Py_XDECREF(full_args.in)_Py_XDECREF(((PyObject*)(full_args.in)));
4965 Py_XDECREF(full_args.out)_Py_XDECREF(((PyObject*)(full_args.out)));
4966 for (int i = 0; i < ufunc->nargs; i++) {
4967 Py_XDECREF(operands[i])_Py_XDECREF(((PyObject*)(operands[i])));
4968 }
4969 return NULL((void*)0);
4970}
4971
4972
4973/*
4974 * TODO: The implementation below can be replaced with PyVectorcall_Call
4975 * when available (should be Python 3.8+).
4976 */
4977static PyObject *
4978ufunc_generic_call(
4979 PyUFuncObject *ufunc, PyObject *args, PyObject *kwds)
4980{
4981 Py_ssize_t len_args = PyTuple_GET_SIZE(args)(((PyVarObject*)((((void) (0)), (PyTupleObject *)(args))))->
ob_size)
;
4982 /*
4983 * Wrapper for tp_call to tp_fastcall, to support both on older versions
4984 * of Python. (and generally simplifying support of both versions in the
4985 * same codebase.
4986 */
4987 if (kwds == NULL((void*)0)) {
4988 return ufunc_generic_fastcall(ufunc,
4989 PySequence_Fast_ITEMS(args)(((((((PyObject*)(args))->ob_type))->tp_flags & ((1UL
<< 25))) != 0) ? ((PyListObject *)(args))->ob_item :
((PyTupleObject *)(args))->ob_item)
, len_args, NULL((void*)0), NPY_FALSE0);
4990 }
4991
4992 PyObject *new_args[NPY_MAXARGS32];
4993 Py_ssize_t len_kwds = PyDict_Size(kwds);
4994
4995 if (NPY_UNLIKELY(len_args + len_kwds > NPY_MAXARGS)__builtin_expect(!!(len_args + len_kwds > 32), 0)) {
4996 /*
4997 * We do not have enough scratch-space, so we have to abort;
4998 * In practice this error should not be seen by users.
4999 */
5000 PyErr_Format(PyExc_ValueError,
5001 "%s() takes from %d to %d positional arguments but "
5002 "%zd were given",
5003 ufunc_get_name_cstr(ufunc) , ufunc->nin, ufunc->nargs, len_args);
5004 return NULL((void*)0);
5005 }
5006
5007 /* Copy args into the scratch space */
5008 for (Py_ssize_t i = 0; i < len_args; i++) {
5009 new_args[i] = PyTuple_GET_ITEM(args, i)((((void) (0)), (PyTupleObject *)(args))->ob_item[i]);
5010 }
5011
5012 PyObject *kwnames = PyTuple_New(len_kwds);
5013
5014 PyObject *key, *value;
5015 Py_ssize_t pos = 0;
5016 Py_ssize_t i = 0;
5017 while (PyDict_Next(kwds, &pos, &key, &value)) {
5018 Py_INCREF(key)_Py_INCREF(((PyObject*)(key)));
5019 PyTuple_SET_ITEM(kwnames, i, key)PyTuple_SetItem(kwnames, i, key);
5020 new_args[i + len_args] = value;
5021 i++;
5022 }
5023
5024 PyObject *res = ufunc_generic_fastcall(ufunc,
5025 new_args, len_args, kwnames, NPY_FALSE0);
5026 Py_DECREF(kwnames)_Py_DECREF(((PyObject*)(kwnames)));
5027 return res;
5028}
5029
5030
5031#if PY_VERSION_HEX((3 << 24) | (8 << 16) | (5 << 8) | (0xF <<
4) | (0 << 0))
>= 0x03080000
5032/*
5033 * Implement vectorcallfunc which should be defined with Python 3.8+.
5034 * In principle this could be backported, but the speed gain seems moderate
5035 * since ufunc calls often do not have keyword arguments and always have
5036 * a large overhead. The only user would potentially be cython probably.
5037 */
5038static PyObject *
5039ufunc_generic_vectorcall(PyObject *ufunc,
5040 PyObject *const *args, size_t len_args, PyObject *kwnames)
5041{
5042 /*
5043 * Unlike METH_FASTCALL, `len_args` may have a flag to signal that
5044 * args[-1] may be (temporarily) used. So normalize it here.
5045 */
5046 return ufunc_generic_fastcall((PyUFuncObject *)ufunc,
5047 args, PyVectorcall_NARGS(len_args), kwnames, NPY_FALSE0);
5048}
5049#endif /* PY_VERSION_HEX >= 0x03080000 */
5050
5051
5052NPY_NO_EXPORT__attribute__((visibility("hidden"))) PyObject *
5053ufunc_geterr(PyObject *NPY_UNUSED(dummy)(__NPY_UNUSED_TAGGEDdummy) __attribute__ ((__unused__)), PyObject *args)
5054{
5055 PyObject *thedict;
5056 PyObject *res;
5057
5058 if (!PyArg_ParseTuple(args, "")) {
5059 return NULL((void*)0);
5060 }
5061 thedict = PyThreadState_GetDict();
5062 if (thedict == NULL((void*)0)) {
5063 thedict = PyEval_GetBuiltins();
5064 }
5065 res = PyDict_GetItemWithError(thedict, npy_um_str_pyvals_name);
5066 if (res == NULL((void*)0) && PyErr_Occurred()) {
5067 return NULL((void*)0);
5068 }
5069 else if (res != NULL((void*)0)) {
5070 Py_INCREF(res)_Py_INCREF(((PyObject*)(res)));
5071 return res;
5072 }
5073 /* Construct list of defaults */
5074 res = PyList_New(3);
5075 if (res == NULL((void*)0)) {
5076 return NULL((void*)0);
5077 }
5078 PyList_SET_ITEM(res, 0, PyLong_FromLong(NPY_BUFSIZE))PyList_SetItem(res, 0, PyLong_FromLong(8192));
5079 PyList_SET_ITEM(res, 1, PyLong_FromLong(UFUNC_ERR_DEFAULT))PyList_SetItem(res, 1, PyLong_FromLong((1 << 0) + (1 <<
3) + (1 << 9)))
;
5080 PyList_SET_ITEM(res, 2, Py_None)PyList_SetItem(res, 2, (&_Py_NoneStruct)); Py_INCREF(Py_None)_Py_INCREF(((PyObject*)((&_Py_NoneStruct))));
5081 return res;
5082}
5083
5084
5085NPY_NO_EXPORT__attribute__((visibility("hidden"))) PyObject *
5086ufunc_seterr(PyObject *NPY_UNUSED(dummy)(__NPY_UNUSED_TAGGEDdummy) __attribute__ ((__unused__)), PyObject *args)
5087{
5088 PyObject *thedict;
5089 int res;
5090 PyObject *val;
5091 static char *msg = "Error object must be a list of length 3";
5092
5093 if (!PyArg_ParseTuple(args, "O:seterrobj", &val)) {
5094 return NULL((void*)0);
5095 }
5096 if (!PyList_CheckExact(val)((((PyObject*)(val))->ob_type) == &PyList_Type) || PyList_GET_SIZE(val)(((void) (0)), (((PyVarObject*)(val))->ob_size)) != 3) {
5097 PyErr_SetString(PyExc_ValueError, msg);
5098 return NULL((void*)0);
5099 }
5100 thedict = PyThreadState_GetDict();
5101 if (thedict == NULL((void*)0)) {
5102 thedict = PyEval_GetBuiltins();
5103 }
5104 res = PyDict_SetItem(thedict, npy_um_str_pyvals_name, val);
5105 if (res < 0) {
5106 return NULL((void*)0);
5107 }
5108#if USE_USE_DEFAULTS1==1
5109 if (ufunc_update_use_defaults() < 0) {
5110 return NULL((void*)0);
5111 }
5112#endif
5113 Py_RETURN_NONEreturn _Py_INCREF(((PyObject*)((&_Py_NoneStruct)))), (&
_Py_NoneStruct)
;
5114}
5115
5116
5117
5118/*UFUNC_API*/
5119NPY_NO_EXPORT__attribute__((visibility("hidden"))) int
5120PyUFunc_ReplaceLoopBySignature(PyUFuncObject *func,
5121 PyUFuncGenericFunction newfunc,
5122 const int *signature,
5123 PyUFuncGenericFunction *oldfunc)
5124{
5125 int i, j;
5126 int res = -1;
5127 /* Find the location of the matching signature */
5128 for (i = 0; i < func->ntypes; i++) {
5129 for (j = 0; j < func->nargs; j++) {
5130 if (signature[j] != func->types[i*func->nargs+j]) {
5131 break;
5132 }
5133 }
5134 if (j < func->nargs) {
5135 continue;
5136 }
5137 if (oldfunc != NULL((void*)0)) {
5138 *oldfunc = func->functions[i];
5139 }
5140 func->functions[i] = newfunc;
5141 res = 0;
5142 break;
5143 }
5144 return res;
5145}
5146
5147/*UFUNC_API*/
5148NPY_NO_EXPORT__attribute__((visibility("hidden"))) PyObject *
5149PyUFunc_FromFuncAndData(PyUFuncGenericFunction *func, void **data,
5150 char *types, int ntypes,
5151 int nin, int nout, int identity,
5152 const char *name, const char *doc, int unused)
5153{
5154 return PyUFunc_FromFuncAndDataAndSignature(func, data, types, ntypes,
5155 nin, nout, identity, name, doc, unused, NULL((void*)0));
5156}
5157
5158/*UFUNC_API*/
5159NPY_NO_EXPORT__attribute__((visibility("hidden"))) PyObject *
5160PyUFunc_FromFuncAndDataAndSignature(PyUFuncGenericFunction *func, void **data,
5161 char *types, int ntypes,
5162 int nin, int nout, int identity,
5163 const char *name, const char *doc,
5164 int unused, const char *signature)
5165{
5166 return PyUFunc_FromFuncAndDataAndSignatureAndIdentity(
5167 func, data, types, ntypes, nin, nout, identity, name, doc,
5168 unused, signature, NULL((void*)0));
5169}
5170
5171/*UFUNC_API*/
5172NPY_NO_EXPORT__attribute__((visibility("hidden"))) PyObject *
5173PyUFunc_FromFuncAndDataAndSignatureAndIdentity(PyUFuncGenericFunction *func, void **data,
5174 char *types, int ntypes,
5175 int nin, int nout, int identity,
5176 const char *name, const char *doc,
5177 const int unused, const char *signature,
5178 PyObject *identity_value)
5179{
5180 PyUFuncObject *ufunc;
5181 if (nin + nout > NPY_MAXARGS32) {
5182 PyErr_Format(PyExc_ValueError,
5183 "Cannot construct a ufunc with more than %d operands "
5184 "(requested number were: inputs = %d and outputs = %d)",
5185 NPY_MAXARGS32, nin, nout);
5186 return NULL((void*)0);
5187 }
5188
5189 ufunc = PyObject_GC_New(PyUFuncObject, &PyUFunc_Type)( (PyUFuncObject *) _PyObject_GC_New(&PyUFunc_Type) );
5190 /*
5191 * We use GC_New here for ufunc->obj, but do not use GC_Track since
5192 * ufunc->obj is still NULL at the end of this function.
5193 * See ufunc_frompyfunc where ufunc->obj is set and GC_Track is called.
5194 */
5195 if (ufunc == NULL((void*)0)) {
5196 return NULL((void*)0);
5197 }
5198
5199 ufunc->nin = nin;
5200 ufunc->nout = nout;
5201 ufunc->nargs = nin+nout;
5202 ufunc->identity = identity;
5203 if (ufunc->identity == PyUFunc_IdentityValue-3) {
5204 Py_INCREF(identity_value)_Py_INCREF(((PyObject*)(identity_value)));
5205 ufunc->identity_value = identity_value;
5206 }
5207 else {
5208 ufunc->identity_value = NULL((void*)0);
5209 }
5210
5211 ufunc->functions = func;
5212 ufunc->data = data;
5213 ufunc->types = types;
5214 ufunc->ntypes = ntypes;
5215 ufunc->core_signature = NULL((void*)0);
5216 ufunc->core_enabled = 0;
5217 ufunc->obj = NULL((void*)0);
5218 ufunc->core_num_dims = NULL((void*)0);
5219 ufunc->core_num_dim_ix = 0;
5220 ufunc->core_offsets = NULL((void*)0);
5221 ufunc->core_dim_ixs = NULL((void*)0);
5222 ufunc->core_dim_sizes = NULL((void*)0);
5223 ufunc->core_dim_flags = NULL((void*)0);
5224 ufunc->userloops = NULL((void*)0);
5225 ufunc->ptr = NULL((void*)0);
5226#if PY_VERSION_HEX((3 << 24) | (8 << 16) | (5 << 8) | (0xF <<
4) | (0 << 0))
>= 0x03080000
5227 ufunc->vectorcall = &ufunc_generic_vectorcall;
5228#else
5229 ufunc->reserved2 = NULL((void*)0);
5230#endif
5231 ufunc->reserved1 = 0;
5232 ufunc->iter_flags = 0;
5233
5234 /* Type resolution and inner loop selection functions */
5235 ufunc->type_resolver = &PyUFunc_DefaultTypeResolver;
5236 ufunc->legacy_inner_loop_selector = &PyUFunc_DefaultLegacyInnerLoopSelector;
5237 ufunc->masked_inner_loop_selector = &PyUFunc_DefaultMaskedInnerLoopSelector;
5238
5239 if (name == NULL((void*)0)) {
5240 ufunc->name = "?";
5241 }
5242 else {
5243 ufunc->name = name;
5244 }
5245 ufunc->doc = doc;
5246
5247 ufunc->op_flags = PyArray_mallocPyMem_RawMalloc(sizeof(npy_uint32)*ufunc->nargs);
5248 if (ufunc->op_flags == NULL((void*)0)) {
5249 Py_DECREF(ufunc)_Py_DECREF(((PyObject*)(ufunc)));
5250 return PyErr_NoMemory();
5251 }
5252 memset(ufunc->op_flags, 0, sizeof(npy_uint32)*ufunc->nargs);
5253
5254 if (signature != NULL((void*)0)) {
5255 if (_parse_signature(ufunc, signature) != 0) {
5256 Py_DECREF(ufunc)_Py_DECREF(((PyObject*)(ufunc)));
5257 return NULL((void*)0);
5258 }
5259 }
5260 return (PyObject *)ufunc;
5261}
5262
5263
5264/*UFUNC_API*/
5265NPY_NO_EXPORT__attribute__((visibility("hidden"))) int
5266PyUFunc_SetUsesArraysAsData(void **NPY_UNUSED(data)(__NPY_UNUSED_TAGGEDdata) __attribute__ ((__unused__)), size_t NPY_UNUSED(i)(__NPY_UNUSED_TAGGEDi) __attribute__ ((__unused__)))
5267{
5268 /* NumPy 1.21, 201-03-29 */
5269 PyErr_SetString(PyExc_RuntimeError,
5270 "PyUFunc_SetUsesArraysAsData() C-API function has been "
5271 "disabled. It was initially deprecated in NumPy 1.19.");
5272 return -1;
5273}
5274
5275
5276/*
5277 * This is the first-part of the CObject structure.
5278 *
5279 * I don't think this will change, but if it should, then
5280 * this needs to be fixed. The exposed C-API was insufficient
5281 * because I needed to replace the pointer and it wouldn't
5282 * let me with a destructor set (even though it works fine
5283 * with the destructor).
5284 */
5285typedef struct {
5286 PyObject_HEADPyObject ob_base;
5287 void *c_obj;
5288} _simple_cobj;
5289
5290#define _SETCPTR(cobj, val) ((_simple_cobj *)(cobj))->c_obj = (val)
5291
5292/* return 1 if arg1 > arg2, 0 if arg1 == arg2, and -1 if arg1 < arg2 */
5293static int
5294cmp_arg_types(int *arg1, int *arg2, int n)
5295{
5296 for (; n > 0; n--, arg1++, arg2++) {
5297 if (PyArray_EquivTypenums(*arg1, *arg2)) {
5298 continue;
5299 }
5300 if (PyArray_CanCastSafely(*arg1, *arg2)) {
5301 return -1;
5302 }
5303 return 1;
5304 }
5305 return 0;
5306}
5307
5308/*
5309 * This frees the linked-list structure when the CObject
5310 * is destroyed (removed from the internal dictionary)
5311*/
5312static NPY_INLINEinline void
5313_free_loop1d_list(PyUFunc_Loop1d *data)
5314{
5315 int i;
5316
5317 while (data != NULL((void*)0)) {
5318 PyUFunc_Loop1d *next = data->next;
5319 PyArray_freePyMem_RawFree(data->arg_types);
5320
5321 if (data->arg_dtypes != NULL((void*)0)) {
5322 for (i = 0; i < data->nargs; i++) {
5323 Py_DECREF(data->arg_dtypes[i])_Py_DECREF(((PyObject*)(data->arg_dtypes[i])));
5324 }
5325 PyArray_freePyMem_RawFree(data->arg_dtypes);
5326 }
5327
5328 PyArray_freePyMem_RawFree(data);
5329 data = next;
5330 }
5331}
5332
5333static void
5334_loop1d_list_free(PyObject *ptr)
5335{
5336 PyUFunc_Loop1d *data = (PyUFunc_Loop1d *)PyCapsule_GetPointer(ptr, NULL((void*)0));
5337 _free_loop1d_list(data);
5338}
5339
5340
5341/*
5342 * This function allows the user to register a 1-d loop with an already
5343 * created ufunc. This function is similar to RegisterLoopForType except
5344 * that it allows a 1-d loop to be registered with PyArray_Descr objects
5345 * instead of dtype type num values. This allows a 1-d loop to be registered
5346 * for a structured array dtype or a custom dtype. The ufunc is called
5347 * whenever any of it's input arguments match the user_dtype argument.
5348 *
5349 * ufunc - ufunc object created from call to PyUFunc_FromFuncAndData
5350 * user_dtype - dtype that ufunc will be registered with
5351 * function - 1-d loop function pointer
5352 * arg_dtypes - array of dtype objects describing the ufunc operands
5353 * data - arbitrary data pointer passed in to loop function
5354 *
5355 * returns 0 on success, -1 for failure
5356 */
5357/*UFUNC_API*/
5358NPY_NO_EXPORT__attribute__((visibility("hidden"))) int
5359PyUFunc_RegisterLoopForDescr(PyUFuncObject *ufunc,
5360 PyArray_Descr *user_dtype,
5361 PyUFuncGenericFunction function,
5362 PyArray_Descr **arg_dtypes,
5363 void *data)
5364{
5365 int i;
5366 int result = 0;
5367 int *arg_typenums;
5368 PyObject *key, *cobj;
5369
5370 if (user_dtype == NULL((void*)0)) {
1
Assuming 'user_dtype' is not equal to NULL
2
Taking false branch
5371 PyErr_SetString(PyExc_TypeError,
5372 "unknown user defined struct dtype");
5373 return -1;
5374 }
5375
5376 key = PyLong_FromLong((long) user_dtype->type_num);
5377 if (key == NULL((void*)0)) {
3
Assuming 'key' is not equal to NULL
4
Taking false branch
5378 return -1;
5379 }
5380
5381 arg_typenums = PyArray_mallocPyMem_RawMalloc(ufunc->nargs * sizeof(int));
5382 if (arg_typenums == NULL((void*)0)) {
5
Assuming 'arg_typenums' is not equal to NULL
6
Taking false branch
5383 PyErr_NoMemory();
5384 return -1;
5385 }
5386 if (arg_dtypes != NULL((void*)0)) {
7
Assuming 'arg_dtypes' is equal to NULL
8
Taking false branch
5387 for (i = 0; i < ufunc->nargs; i++) {
5388 arg_typenums[i] = arg_dtypes[i]->type_num;
5389 }
5390 }
5391 else {
5392 for (i = 0; i < ufunc->nargs; i++) {
9
Assuming 'i' is >= field 'nargs'
10
Loop condition is false. Execution continues on line 5397
5393 arg_typenums[i] = user_dtype->type_num;
5394 }
5395 }
5396
5397 result = PyUFunc_RegisterLoopForType(ufunc, user_dtype->type_num,
11
Calling 'PyUFunc_RegisterLoopForType'
5398 function, arg_typenums, data);
5399
5400 if (result == 0) {
5401 cobj = PyDict_GetItemWithError(ufunc->userloops, key);
5402 if (cobj == NULL((void*)0) && PyErr_Occurred()) {
5403 result = -1;
5404 }
5405 else if (cobj == NULL((void*)0)) {
5406 PyErr_SetString(PyExc_KeyError,
5407 "userloop for user dtype not found");
5408 result = -1;
5409 }
5410 else {
5411 int cmp = 1;
5412 PyUFunc_Loop1d *current = PyCapsule_GetPointer(cobj, NULL((void*)0));
5413 if (current == NULL((void*)0)) {
5414 result = -1;
5415 goto done;
5416 }
5417 while (current != NULL((void*)0)) {
5418 cmp = cmp_arg_types(current->arg_types,
5419 arg_typenums, ufunc->nargs);
5420 if (cmp >= 0 && current->arg_dtypes == NULL((void*)0)) {
5421 break;
5422 }
5423 current = current->next;
5424 }
5425 if (cmp == 0 && current != NULL((void*)0) && current->arg_dtypes == NULL((void*)0)) {
5426 current->arg_dtypes = PyArray_mallocPyMem_RawMalloc(ufunc->nargs *
5427 sizeof(PyArray_Descr*));
5428 if (current->arg_dtypes == NULL((void*)0)) {
5429 PyErr_NoMemory();
5430 result = -1;
5431 goto done;
5432 }
5433 else if (arg_dtypes != NULL((void*)0)) {
5434 for (i = 0; i < ufunc->nargs; i++) {
5435 current->arg_dtypes[i] = arg_dtypes[i];
5436 Py_INCREF(current->arg_dtypes[i])_Py_INCREF(((PyObject*)(current->arg_dtypes[i])));
5437 }
5438 }
5439 else {
5440 for (i = 0; i < ufunc->nargs; i++) {
5441 current->arg_dtypes[i] = user_dtype;
5442 Py_INCREF(current->arg_dtypes[i])_Py_INCREF(((PyObject*)(current->arg_dtypes[i])));
5443 }
5444 }
5445 current->nargs = ufunc->nargs;
5446 }
5447 else {
5448 PyErr_SetString(PyExc_RuntimeError,
5449 "loop already registered");
5450 result = -1;
5451 }
5452 }
5453 }
5454
5455done:
5456 PyArray_freePyMem_RawFree(arg_typenums);
5457
5458 Py_DECREF(key)_Py_DECREF(((PyObject*)(key)));
5459
5460 return result;
5461}
5462
5463/*UFUNC_API*/
5464NPY_NO_EXPORT__attribute__((visibility("hidden"))) int
5465PyUFunc_RegisterLoopForType(PyUFuncObject *ufunc,
5466 int usertype,
5467 PyUFuncGenericFunction function,
5468 const int *arg_types,
5469 void *data)
5470{
5471 PyArray_Descr *descr;
5472 PyUFunc_Loop1d *funcdata;
5473 PyObject *key, *cobj;
5474 int i;
5475 int *newtypes=NULL((void*)0);
5476
5477 descr=PyArray_DescrFromType(usertype);
5478 if ((usertype < NPY_USERDEF && usertype != NPY_VOID) || (descr==NULL((void*)0))) {
12
Assuming 'usertype' is >= NPY_USERDEF
13
Assuming 'descr' is not equal to NULL
14
Taking false branch
5479 PyErr_SetString(PyExc_TypeError, "unknown user-defined type");
5480 return -1;
5481 }
5482 Py_DECREF(descr)_Py_DECREF(((PyObject*)(descr)));
5483
5484 if (ufunc->userloops == NULL((void*)0)) {
15
Assuming field 'userloops' is not equal to NULL
16
Taking false branch
5485 ufunc->userloops = PyDict_New();
5486 }
5487 key = PyLong_FromLong((long) usertype);
17
Calling 'PyLong_FromLong'
19
Returning from 'PyLong_FromLong'
31
PyObject ownership leak with reference count of 1
5488 if (key == NULL((void*)0)) {
20
Assuming 'key' is not equal to NULL
21
Taking false branch
5489 return -1;
5490 }
5491 funcdata = PyArray_mallocPyMem_RawMalloc(sizeof(PyUFunc_Loop1d));
5492 if (funcdata == NULL((void*)0)) {
22
Assuming 'funcdata' is not equal to NULL
23
Taking false branch
5493 goto fail;
5494 }
5495 newtypes = PyArray_mallocPyMem_RawMalloc(sizeof(int)*ufunc->nargs);
5496 if (newtypes == NULL((void*)0)) {
24
Assuming 'newtypes' is not equal to NULL
25
Taking false branch
5497 goto fail;
5498 }
5499 if (arg_types
25.1
'arg_types' is not equal to NULL
25.1
'arg_types' is not equal to NULL
!= NULL((void*)0)) {
26
Taking true branch
5500 for (i = 0; i
26.1
'i' is >= field 'nargs'
26.1
'i' is >= field 'nargs'
< ufunc->nargs; i++) {
27
Loop condition is false. Execution continues on line 5510
5501 newtypes[i] = arg_types[i];
5502 }
5503 }
5504 else {
5505 for (i = 0; i < ufunc->nargs; i++) {
5506 newtypes[i] = usertype;
5507 }
5508 }
5509
5510 funcdata->func = function;
5511 funcdata->arg_types = newtypes;
5512 funcdata->data = data;
5513 funcdata->next = NULL((void*)0);
5514 funcdata->arg_dtypes = NULL((void*)0);
5515 funcdata->nargs = 0;
5516
5517 /* Get entry for this user-defined type*/
5518 cobj = PyDict_GetItemWithError(ufunc->userloops, key);
5519 if (cobj == NULL((void*)0) && PyErr_Occurred()) {
28
Assuming 'cobj' is equal to NULL
29
Assuming the condition is true
30
Taking true branch
5520 return 0;
5521 }
5522 /* If it's not there, then make one and return. */
5523 else if (cobj == NULL((void*)0)) {
5524 cobj = PyCapsule_New((void *)funcdata, NULL((void*)0), _loop1d_list_free);
5525 if (cobj == NULL((void*)0)) {
5526 goto fail;
5527 }
5528 PyDict_SetItem(ufunc->userloops, key, cobj);
5529 Py_DECREF(cobj)_Py_DECREF(((PyObject*)(cobj)));
5530 Py_DECREF(key)_Py_DECREF(((PyObject*)(key)));
5531 return 0;
5532 }
5533 else {
5534 PyUFunc_Loop1d *current, *prev = NULL((void*)0);
5535 int cmp = 1;
5536 /*
5537 * There is already at least 1 loop. Place this one in
5538 * lexicographic order. If the next one signature
5539 * is exactly like this one, then just replace.
5540 * Otherwise insert.
5541 */
5542 current = PyCapsule_GetPointer(cobj, NULL((void*)0));
5543 if (current == NULL((void*)0)) {
5544 goto fail;
5545 }
5546 while (current != NULL((void*)0)) {
5547 cmp = cmp_arg_types(current->arg_types, newtypes, ufunc->nargs);
5548 if (cmp >= 0) {
5549 break;
5550 }
5551 prev = current;
5552 current = current->next;
5553 }
5554 if (cmp == 0) {
5555 /* just replace it with new function */
5556 current->func = function;
5557 current->data = data;
5558 PyArray_freePyMem_RawFree(newtypes);
5559 PyArray_freePyMem_RawFree(funcdata);
5560 }
5561 else {
5562 /*
5563 * insert it before the current one by hacking the internals
5564 * of cobject to replace the function pointer --- can't use
5565 * CObject API because destructor is set.
5566 */
5567 funcdata->next = current;
5568 if (prev == NULL((void*)0)) {
5569 /* place this at front */
5570 _SETCPTR(cobj, funcdata);
5571 }
5572 else {
5573 prev->next = funcdata;
5574 }
5575 }
5576 }
5577 Py_DECREF(key)_Py_DECREF(((PyObject*)(key)));
5578 return 0;
5579
5580 fail:
5581 Py_DECREF(key)_Py_DECREF(((PyObject*)(key)));
5582 PyArray_freePyMem_RawFree(funcdata);
5583 PyArray_freePyMem_RawFree(newtypes);
5584 if (!PyErr_Occurred()) PyErr_NoMemory();
5585 return -1;
5586}
5587
5588#undef _SETCPTR
5589
5590
5591static void
5592ufunc_dealloc(PyUFuncObject *ufunc)
5593{
5594 PyObject_GC_UnTrack((PyObject *)ufunc);
5595 PyArray_freePyMem_RawFree(ufunc->core_num_dims);
5596 PyArray_freePyMem_RawFree(ufunc->core_dim_ixs);
5597 PyArray_freePyMem_RawFree(ufunc->core_dim_sizes);
5598 PyArray_freePyMem_RawFree(ufunc->core_dim_flags);
5599 PyArray_freePyMem_RawFree(ufunc->core_offsets);
5600 PyArray_freePyMem_RawFree(ufunc->core_signature);
5601 PyArray_freePyMem_RawFree(ufunc->ptr);
5602 PyArray_freePyMem_RawFree(ufunc->op_flags);
5603 Py_XDECREF(ufunc->userloops)_Py_XDECREF(((PyObject*)(ufunc->userloops)));
5604 if (ufunc->identity == PyUFunc_IdentityValue-3) {
5605 Py_DECREF(ufunc->identity_value)_Py_DECREF(((PyObject*)(ufunc->identity_value)));
5606 }
5607 if (ufunc->obj != NULL((void*)0)) {
5608 Py_DECREF(ufunc->obj)_Py_DECREF(((PyObject*)(ufunc->obj)));
5609 }
5610 PyObject_GC_Del(ufunc);
5611}
5612
5613static PyObject *
5614ufunc_repr(PyUFuncObject *ufunc)
5615{
5616 return PyUnicode_FromFormat("<ufunc '%s'>", ufunc->name);
5617}
5618
5619static int
5620ufunc_traverse(PyUFuncObject *self, visitproc visit, void *arg)
5621{
5622 Py_VISIT(self->obj)do { if (self->obj) { int vret = visit(((PyObject*)(self->
obj)), arg); if (vret) return vret; } } while (0)
;
5623 if (self->identity == PyUFunc_IdentityValue-3) {
5624 Py_VISIT(self->identity_value)do { if (self->identity_value) { int vret = visit(((PyObject
*)(self->identity_value)), arg); if (vret) return vret; } }
while (0)
;
5625 }
5626 return 0;
5627}
5628
5629/******************************************************************************
5630 *** UFUNC METHODS ***
5631 *****************************************************************************/
5632
5633
5634/*
5635 * op.outer(a,b) is equivalent to op(a[:,NewAxis,NewAxis,etc.],b)
5636 * where a has b.ndim NewAxis terms appended.
5637 *
5638 * The result has dimensions a.ndim + b.ndim
5639 */
5640static PyObject *
5641ufunc_outer(PyUFuncObject *ufunc,
5642 PyObject *const *args, Py_ssize_t len_args, PyObject *kwnames)
5643{
5644 if (ufunc->core_enabled) {
5645 PyErr_Format(PyExc_TypeError,
5646 "method outer is not allowed in ufunc with non-trivial"\
5647 " signature");
5648 return NULL((void*)0);
5649 }
5650
5651 if (ufunc->nin != 2) {
5652 PyErr_SetString(PyExc_ValueError,
5653 "outer product only supported "\
5654 "for binary functions");
5655 return NULL((void*)0);
5656 }
5657
5658 if (len_args != 2) {
5659 PyErr_SetString(PyExc_TypeError, "exactly two arguments expected");
5660 return NULL((void*)0);
5661 }
5662
5663 return ufunc_generic_fastcall(ufunc, args, len_args, kwnames, NPY_TRUE1);
5664}
5665
5666
5667static PyObject *
5668prepare_input_arguments_for_outer(PyObject *args, PyUFuncObject *ufunc)
5669{
5670 PyArrayObject *ap1 = NULL((void*)0);
5671 PyObject *tmp;
5672 static PyObject *_numpy_matrix;
5673 npy_cache_import("numpy", "matrix", &_numpy_matrix);
5674
5675 const char *matrix_deprecation_msg = (
5676 "%s.outer() was passed a numpy matrix as %s argument. "
5677 "Special handling of matrix is deprecated and will result in an "
5678 "error in most cases. Please convert the matrix to a NumPy "
5679 "array to retain the old behaviour. You can use `matrix.A` "
5680 "to achieve this.");
5681
5682 tmp = PyTuple_GET_ITEM(args, 0)((((void) (0)), (PyTupleObject *)(args))->ob_item[0]);
5683
5684 if (PyObject_IsInstance(tmp, _numpy_matrix)) {
5685 /* DEPRECATED 2020-05-13, NumPy 1.20 */
5686 if (PyErr_WarnFormat(PyExc_DeprecationWarning, 1,
5687 matrix_deprecation_msg, ufunc->name, "first") < 0) {
5688 return NULL((void*)0);
5689 }
5690 ap1 = (PyArrayObject *) PyArray_FromObject(tmp, NPY_NOTYPE, 0, 0)PyArray_FromAny(tmp, PyArray_DescrFromType(NPY_NOTYPE), 0, 0,
(0x0100 | 0x0400) | 0x0040, ((void*)0))
;
5691 }
5692 else {
5693 ap1 = (PyArrayObject *) PyArray_FROM_O(tmp)PyArray_FromAny(tmp, ((void*)0), 0, 0, 0, ((void*)0));
5694 }
5695 if (ap1 == NULL((void*)0)) {
5696 return NULL((void*)0);
5697 }
5698
5699 PyArrayObject *ap2 = NULL((void*)0);
5700 tmp = PyTuple_GET_ITEM(args, 1)((((void) (0)), (PyTupleObject *)(args))->ob_item[1]);
5701 if (PyObject_IsInstance(tmp, _numpy_matrix)) {
5702 /* DEPRECATED 2020-05-13, NumPy 1.20 */
5703 if (PyErr_WarnFormat(PyExc_DeprecationWarning, 1,
5704 matrix_deprecation_msg, ufunc->name, "second") < 0) {
5705 Py_DECREF(ap1)_Py_DECREF(((PyObject*)(ap1)));
5706 return NULL((void*)0);
5707 }
5708 ap2 = (PyArrayObject *) PyArray_FromObject(tmp, NPY_NOTYPE, 0, 0)PyArray_FromAny(tmp, PyArray_DescrFromType(NPY_NOTYPE), 0, 0,
(0x0100 | 0x0400) | 0x0040, ((void*)0))
;
5709 }
5710 else {
5711 ap2 = (PyArrayObject *) PyArray_FROM_O(tmp)PyArray_FromAny(tmp, ((void*)0), 0, 0, 0, ((void*)0));
5712 }
5713 if (ap2 == NULL((void*)0)) {
5714 Py_DECREF(ap1)_Py_DECREF(((PyObject*)(ap1)));
5715 return NULL((void*)0);
5716 }
5717 /* Construct new shape from ap1 and ap2 and then reshape */
5718 PyArray_Dims newdims;
5719 npy_intp newshape[NPY_MAXDIMS32];
5720 newdims.len = PyArray_NDIM(ap1) + PyArray_NDIM(ap2);
5721 newdims.ptr = newshape;
5722
5723 if (newdims.len > NPY_MAXDIMS32) {
5724 PyErr_Format(PyExc_ValueError,
5725 "maximum supported dimension for an ndarray is %d, but "
5726 "`%s.outer()` result would have %d.",
5727 NPY_MAXDIMS32, ufunc->name, newdims.len);
5728 goto fail;
5729 }
5730 if (newdims.ptr == NULL((void*)0)) {
5731 goto fail;
5732 }
5733 memcpy(newshape, PyArray_DIMS(ap1), PyArray_NDIM(ap1) * sizeof(npy_intp));
5734 for (int i = PyArray_NDIM(ap1); i < newdims.len; i++) {
5735 newshape[i] = 1;
5736 }
5737
5738 PyArrayObject *ap_new;
5739 ap_new = (PyArrayObject *)PyArray_Newshape(ap1, &newdims, NPY_CORDER);
5740 if (ap_new == NULL((void*)0)) {
5741 goto fail;
5742 }
5743 if (PyArray_NDIM(ap_new) != newdims.len ||
5744 !PyArray_CompareLists(PyArray_DIMS(ap_new), newshape, newdims.len)) {
5745 PyErr_Format(PyExc_TypeError,
5746 "%s.outer() called with ndarray-subclass of type '%s' "
5747 "which modified its shape after a reshape. `outer()` relies "
5748 "on reshaping the inputs and is for example not supported for "
5749 "the 'np.matrix' class (the usage of matrix is generally "
5750 "discouraged). "
5751 "To work around this issue, please convert the inputs to "
5752 "numpy arrays.",
5753 ufunc->name, Py_TYPE(ap_new)(((PyObject*)(ap_new))->ob_type)->tp_name);
5754 Py_DECREF(ap_new)_Py_DECREF(((PyObject*)(ap_new)));
5755 goto fail;
5756 }
5757
5758 Py_DECREF(ap1)_Py_DECREF(((PyObject*)(ap1)));
5759 return Py_BuildValue("(NN)", ap_new, ap2);
5760
5761 fail:
5762 Py_XDECREF(ap1)_Py_XDECREF(((PyObject*)(ap1)));
5763 Py_XDECREF(ap2)_Py_XDECREF(((PyObject*)(ap2)));
5764 return NULL((void*)0);
5765}
5766
5767
5768static PyObject *
5769ufunc_reduce(PyUFuncObject *ufunc,
5770 PyObject *const *args, Py_ssize_t len_args, PyObject *kwnames)
5771{
5772 return PyUFunc_GenericReduction(
5773 ufunc, args, len_args, kwnames, UFUNC_REDUCE0);
5774}
5775
5776static PyObject *
5777ufunc_accumulate(PyUFuncObject *ufunc,
5778 PyObject *const *args, Py_ssize_t len_args, PyObject *kwnames)
5779{
5780 return PyUFunc_GenericReduction(
5781 ufunc, args, len_args, kwnames, UFUNC_ACCUMULATE1);
5782}
5783
5784static PyObject *
5785ufunc_reduceat(PyUFuncObject *ufunc,
5786 PyObject *const *args, Py_ssize_t len_args, PyObject *kwnames)
5787{
5788 return PyUFunc_GenericReduction(
5789 ufunc, args, len_args, kwnames, UFUNC_REDUCEAT2);
5790}
5791
5792/* Helper for ufunc_at, below */
5793static NPY_INLINEinline PyArrayObject *
5794new_array_op(PyArrayObject *op_array, char *data)
5795{
5796 npy_intp dims[1] = {1};
5797 PyObject *r = PyArray_NewFromDescr(&PyArray_Type, PyArray_DESCR(op_array),
5798 1, dims, NULL((void*)0), data,
5799 NPY_ARRAY_WRITEABLE0x0400, NULL((void*)0));
5800 return (PyArrayObject *)r;
5801}
5802
5803/*
5804 * Call ufunc only on selected array items and store result in first operand.
5805 * For add ufunc, method call is equivalent to op1[idx] += op2 with no
5806 * buffering of the first operand.
5807 * Arguments:
5808 * op1 - First operand to ufunc
5809 * idx - Indices that are applied to first operand. Equivalent to op1[idx].
5810 * op2 - Second operand to ufunc (if needed). Must be able to broadcast
5811 * over first operand.
5812 */
5813static PyObject *
5814ufunc_at(PyUFuncObject *ufunc, PyObject *args)
5815{
5816 PyObject *op1 = NULL((void*)0);
5817 PyObject *idx = NULL((void*)0);
5818 PyObject *op2 = NULL((void*)0);
5819 PyArrayObject *op1_array = NULL((void*)0);
5820 PyArrayObject *op2_array = NULL((void*)0);
5821 PyArrayMapIterObject *iter = NULL((void*)0);
5822 PyArrayIterObject *iter2 = NULL((void*)0);
5823 PyArray_Descr *dtypes[3] = {NULL((void*)0), NULL((void*)0), NULL((void*)0)};
5824 PyArrayObject *operands[3] = {NULL((void*)0), NULL((void*)0), NULL((void*)0)};
5825 PyArrayObject *array_operands[3] = {NULL((void*)0), NULL((void*)0), NULL((void*)0)};
5826
5827 int needs_api = 0;
5828
5829 PyUFuncGenericFunction innerloop;
5830 void *innerloopdata;
5831 npy_intp i;
5832 int nop;
5833
5834 /* override vars */
5835 int errval;
5836 PyObject *override = NULL((void*)0);
5837
5838 NpyIter *iter_buffer;
5839 NpyIter_IterNextFunc *iternext;
5840 npy_uint32 op_flags[NPY_MAXARGS32];
5841 int buffersize;
5842 int errormask = 0;
5843 char * err_msg = NULL((void*)0);
5844 NPY_BEGIN_THREADS_DEFPyThreadState *_save=((void*)0);;
5845
5846 if (ufunc->nin > 2) {
5847 PyErr_SetString(PyExc_ValueError,
5848 "Only unary and binary ufuncs supported at this time");
5849 return NULL((void*)0);
5850 }
5851
5852 if (ufunc->nout != 1) {
5853 PyErr_SetString(PyExc_ValueError,
5854 "Only single output ufuncs supported at this time");
5855 return NULL((void*)0);
5856 }
5857
5858 if (!PyArg_ParseTuple(args, "OO|O:at", &op1, &idx, &op2)) {
5859 return NULL((void*)0);
5860 }
5861
5862 if (ufunc->nin == 2 && op2 == NULL((void*)0)) {
5863 PyErr_SetString(PyExc_ValueError,
5864 "second operand needed for ufunc");
5865 return NULL((void*)0);
5866 }
5867 errval = PyUFunc_CheckOverride(ufunc, "at",
5868 args, NULL((void*)0), NULL((void*)0), 0, NULL((void*)0), &override);
5869
5870 if (errval) {
5871 return NULL((void*)0);
5872 }
5873 else if (override) {
5874 return override;
5875 }
5876
5877 if (!PyArray_Check(op1)((((PyObject*)(op1))->ob_type) == (&PyArray_Type) || PyType_IsSubtype
((((PyObject*)(op1))->ob_type), (&PyArray_Type)))
) {
5878 PyErr_SetString(PyExc_TypeError,
5879 "first operand must be array");
5880 return NULL((void*)0);
5881 }
5882
5883 op1_array = (PyArrayObject *)op1;
5884
5885 /* Create second operand from number array if needed. */
5886 if (op2 != NULL((void*)0)) {
5887 op2_array = (PyArrayObject *)PyArray_FromAny(op2, NULL((void*)0),
5888 0, 0, 0, NULL((void*)0));
5889 if (op2_array == NULL((void*)0)) {
5890 goto fail;
5891 }
5892 }
5893
5894 /* Create map iterator */
5895 iter = (PyArrayMapIterObject *)PyArray_MapIterArrayCopyIfOverlap(
5896 op1_array, idx, 1, op2_array);
5897 if (iter == NULL((void*)0)) {
5898 goto fail;
5899 }
5900 op1_array = iter->array; /* May be updateifcopied on overlap */
5901
5902 if (op2 != NULL((void*)0)) {
5903 /*
5904 * May need to swap axes so that second operand is
5905 * iterated over correctly
5906 */
5907 if ((iter->subspace != NULL((void*)0)) && (iter->consec)) {
5908 PyArray_MapIterSwapAxes(iter, &op2_array, 0);
5909 if (op2_array == NULL((void*)0)) {
5910 goto fail;
5911 }
5912 }
5913
5914 /*
5915 * Create array iter object for second operand that
5916 * "matches" the map iter object for the first operand.
5917 * Then we can just iterate over the first and second
5918 * operands at the same time and not have to worry about
5919 * picking the correct elements from each operand to apply
5920 * the ufunc to.
5921 */
5922 if ((iter2 = (PyArrayIterObject *)\
5923 PyArray_BroadcastToShape((PyObject *)op2_array,
5924 iter->dimensions, iter->nd))==NULL((void*)0)) {
5925 goto fail;
5926 }
5927 }
5928
5929 /*
5930 * Create dtypes array for either one or two input operands.
5931 * The output operand is set to the first input operand
5932 */
5933 operands[0] = op1_array;
5934 if (op2_array != NULL((void*)0)) {
5935 operands[1] = op2_array;
5936 operands[2] = op1_array;
5937 nop = 3;
5938 }
5939 else {
5940 operands[1] = op1_array;
5941 operands[2] = NULL((void*)0);
5942 nop = 2;
5943 }
5944
5945 if (ufunc->type_resolver(ufunc, NPY_UNSAFE_CASTING,
5946 operands, NULL((void*)0), dtypes) < 0) {
5947 goto fail;
5948 }
5949 if (ufunc->legacy_inner_loop_selector(ufunc, dtypes,
5950 &innerloop, &innerloopdata, &needs_api) < 0) {
5951 goto fail;
5952 }
5953
5954 Py_INCREF(PyArray_DESCR(op1_array))_Py_INCREF(((PyObject*)(PyArray_DESCR(op1_array))));
5955 array_operands[0] = new_array_op(op1_array, iter->dataptr);
5956 if (iter2 != NULL((void*)0)) {
5957 Py_INCREF(PyArray_DESCR(op2_array))_Py_INCREF(((PyObject*)(PyArray_DESCR(op2_array))));
5958 array_operands[1] = new_array_op(op2_array, PyArray_ITER_DATA(iter2)((void *)(((PyArrayIterObject *)(iter2))->dataptr)));
5959 Py_INCREF(PyArray_DESCR(op1_array))_Py_INCREF(((PyObject*)(PyArray_DESCR(op1_array))));
5960 array_operands[2] = new_array_op(op1_array, iter->dataptr);
5961 }
5962 else {
5963 Py_INCREF(PyArray_DESCR(op1_array))_Py_INCREF(((PyObject*)(PyArray_DESCR(op1_array))));
5964 array_operands[1] = new_array_op(op1_array, iter->dataptr);
5965 array_operands[2] = NULL((void*)0);
5966 }
5967
5968 /* Set up the flags */
5969 op_flags[0] = NPY_ITER_READONLY0x00020000|
5970 NPY_ITER_ALIGNED0x00100000;
5971
5972 if (iter2 != NULL((void*)0)) {
5973 op_flags[1] = NPY_ITER_READONLY0x00020000|
5974 NPY_ITER_ALIGNED0x00100000;
5975 op_flags[2] = NPY_ITER_WRITEONLY0x00040000|
5976 NPY_ITER_ALIGNED0x00100000|
5977 NPY_ITER_ALLOCATE0x01000000|
5978 NPY_ITER_NO_BROADCAST0x08000000|
5979 NPY_ITER_NO_SUBTYPE0x02000000;
5980 }
5981 else {
5982 op_flags[1] = NPY_ITER_WRITEONLY0x00040000|
5983 NPY_ITER_ALIGNED0x00100000|
5984 NPY_ITER_ALLOCATE0x01000000|
5985 NPY_ITER_NO_BROADCAST0x08000000|
5986 NPY_ITER_NO_SUBTYPE0x02000000;
5987 }
5988
5989 if (_get_bufsize_errmask(NULL((void*)0), ufunc->name, &buffersize, &errormask) < 0) {
5990 goto fail;
5991 }
5992
5993 /*
5994 * Create NpyIter object to "iterate" over single element of each input
5995 * operand. This is an easy way to reuse the NpyIter logic for dealing
5996 * with certain cases like casting operands to correct dtype. On each
5997 * iteration over the MapIterArray object created above, we'll take the
5998 * current data pointers from that and reset this NpyIter object using
5999 * those data pointers, and then trigger a buffer copy. The buffer data
6000 * pointers from the NpyIter object will then be passed to the inner loop
6001 * function.
6002 */
6003 iter_buffer = NpyIter_AdvancedNew(nop, array_operands,
6004 NPY_ITER_EXTERNAL_LOOP0x00000008|
6005 NPY_ITER_REFS_OK0x00000020|
6006 NPY_ITER_ZEROSIZE_OK0x00000040|
6007 NPY_ITER_BUFFERED0x00000200|
6008 NPY_ITER_GROWINNER0x00000400|
6009 NPY_ITER_DELAY_BUFALLOC0x00000800,
6010 NPY_KEEPORDER, NPY_UNSAFE_CASTING,
6011 op_flags, dtypes,
6012 -1, NULL((void*)0), NULL((void*)0), buffersize);
6013
6014 if (iter_buffer == NULL((void*)0)) {
6015 goto fail;
6016 }
6017
6018 needs_api = needs_api | NpyIter_IterationNeedsAPI(iter_buffer);
6019
6020 iternext = NpyIter_GetIterNext(iter_buffer, NULL((void*)0));
6021 if (iternext == NULL((void*)0)) {
6022 NpyIter_Deallocate(iter_buffer);
6023 goto fail;
6024 }
6025
6026 if (!needs_api) {
6027 NPY_BEGIN_THREADSdo {_save = PyEval_SaveThread();} while (0);;
6028 }
6029
6030 /*
6031 * Iterate over first and second operands and call ufunc
6032 * for each pair of inputs
6033 */
6034 i = iter->size;
6035 while (i > 0)
6036 {
6037 char *dataptr[3];
6038 char **buffer_dataptr;
6039 /* one element at a time, no stride required but read by innerloop */
6040 npy_intp count[3] = {1, 0xDEADBEEF, 0xDEADBEEF};
6041 npy_intp stride[3] = {0xDEADBEEF, 0xDEADBEEF, 0xDEADBEEF};
6042
6043 /*
6044 * Set up data pointers for either one or two input operands.
6045 * The output data pointer points to the first operand data.
6046 */
6047 dataptr[0] = iter->dataptr;
6048 if (iter2 != NULL((void*)0)) {
6049 dataptr[1] = PyArray_ITER_DATA(iter2)((void *)(((PyArrayIterObject *)(iter2))->dataptr));
6050 dataptr[2] = iter->dataptr;
6051 }
6052 else {
6053 dataptr[1] = iter->dataptr;
6054 dataptr[2] = NULL((void*)0);
6055 }
6056
6057 /* Reset NpyIter data pointers which will trigger a buffer copy */
6058 NpyIter_ResetBasePointers(iter_buffer, dataptr, &err_msg);
6059 if (err_msg) {
6060 break;
6061 }
6062
6063 buffer_dataptr = NpyIter_GetDataPtrArray(iter_buffer);
6064
6065 innerloop(buffer_dataptr, count, stride, innerloopdata);
6066
6067 if (needs_api && PyErr_Occurred()) {
6068 break;
6069 }
6070
6071 /*
6072 * Call to iternext triggers copy from buffer back to output array
6073 * after innerloop puts result in buffer.
6074 */
6075 iternext(iter_buffer);
6076
6077 PyArray_MapIterNext(iter);
6078 if (iter2 != NULL((void*)0)) {
6079 PyArray_ITER_NEXT(iter2)do { ((PyArrayIterObject *)(iter2))->index++; if (((PyArrayIterObject
*)(iter2))->nd_m1 == 0) { do { (((PyArrayIterObject *)(iter2
)))->dataptr += ((PyArrayIterObject *)(((PyArrayIterObject
*)(iter2))))->strides[0]; (((PyArrayIterObject *)(iter2))
)->coordinates[0]++; } while (0); } else if (((PyArrayIterObject
*)(iter2))->contiguous) ((PyArrayIterObject *)(iter2))->
dataptr += PyArray_DESCR(((PyArrayIterObject *)(iter2))->ao
)->elsize; else if (((PyArrayIterObject *)(iter2))->nd_m1
== 1) { do { if ((((PyArrayIterObject *)(iter2)))->coordinates
[1] < (((PyArrayIterObject *)(iter2)))->dims_m1[1]) { (
((PyArrayIterObject *)(iter2)))->coordinates[1]++; (((PyArrayIterObject
*)(iter2)))->dataptr += (((PyArrayIterObject *)(iter2)))->
strides[1]; } else { (((PyArrayIterObject *)(iter2)))->coordinates
[1] = 0; (((PyArrayIterObject *)(iter2)))->coordinates[0]++
; (((PyArrayIterObject *)(iter2)))->dataptr += (((PyArrayIterObject
*)(iter2)))->strides[0] - (((PyArrayIterObject *)(iter2))
)->backstrides[1]; } } while (0); } else { int __npy_i; for
(__npy_i=((PyArrayIterObject *)(iter2))->nd_m1; __npy_i >=
0; __npy_i--) { if (((PyArrayIterObject *)(iter2))->coordinates
[__npy_i] < ((PyArrayIterObject *)(iter2))->dims_m1[__npy_i
]) { ((PyArrayIterObject *)(iter2))->coordinates[__npy_i]++
; ((PyArrayIterObject *)(iter2))->dataptr += ((PyArrayIterObject
*)(iter2))->strides[__npy_i]; break; } else { ((PyArrayIterObject
*)(iter2))->coordinates[__npy_i] = 0; ((PyArrayIterObject
*)(iter2))->dataptr -= ((PyArrayIterObject *)(iter2))->
backstrides[__npy_i]; } } } } while (0)
;
6080 }
6081
6082 i--;
6083 }
6084
6085 NPY_END_THREADSdo { if (_save) { PyEval_RestoreThread(_save); _save = ((void
*)0);} } while (0);
;
6086
6087 if (err_msg) {
6088 PyErr_SetString(PyExc_ValueError, err_msg);
6089 }
6090
6091 NpyIter_Deallocate(iter_buffer);
6092
6093 Py_XDECREF(op2_array)_Py_XDECREF(((PyObject*)(op2_array)));
6094 Py_XDECREF(iter)_Py_XDECREF(((PyObject*)(iter)));
6095 Py_XDECREF(iter2)_Py_XDECREF(((PyObject*)(iter2)));
6096 for (i = 0; i < 3; i++) {
6097 Py_XDECREF(dtypes[i])_Py_XDECREF(((PyObject*)(dtypes[i])));
6098 Py_XDECREF(array_operands[i])_Py_XDECREF(((PyObject*)(array_operands[i])));
6099 }
6100
6101 if (needs_api && PyErr_Occurred()) {
6102 return NULL((void*)0);
6103 }
6104 else {
6105 Py_RETURN_NONEreturn _Py_INCREF(((PyObject*)((&_Py_NoneStruct)))), (&
_Py_NoneStruct)
;
6106 }
6107
6108fail:
6109 /* iter_buffer has already been deallocated, don't use NpyIter_Dealloc */
6110 if (op1_array != (PyArrayObject*)op1) {
6111 PyArray_DiscardWritebackIfCopy(op1_array);
6112 }
6113 Py_XDECREF(op2_array)_Py_XDECREF(((PyObject*)(op2_array)));
6114 Py_XDECREF(iter)_Py_XDECREF(((PyObject*)(iter)));
6115 Py_XDECREF(iter2)_Py_XDECREF(((PyObject*)(iter2)));
6116 for (i = 0; i < 3; i++) {
6117 Py_XDECREF(dtypes[i])_Py_XDECREF(((PyObject*)(dtypes[i])));
6118 Py_XDECREF(array_operands[i])_Py_XDECREF(((PyObject*)(array_operands[i])));
6119 }
6120
6121 return NULL((void*)0);
6122}
6123
6124
6125static struct PyMethodDef ufunc_methods[] = {
6126 {"reduce",
6127 (PyCFunction)ufunc_reduce,
6128 METH_FASTCALL0x0080 | METH_KEYWORDS0x0002, NULL((void*)0) },
6129 {"accumulate",
6130 (PyCFunction)ufunc_accumulate,
6131 METH_FASTCALL0x0080 | METH_KEYWORDS0x0002, NULL((void*)0) },
6132 {"reduceat",
6133 (PyCFunction)ufunc_reduceat,
6134 METH_FASTCALL0x0080 | METH_KEYWORDS0x0002, NULL((void*)0) },
6135 {"outer",
6136 (PyCFunction)ufunc_outer,
6137 METH_FASTCALL0x0080 | METH_KEYWORDS0x0002, NULL((void*)0)},
6138 {"at",
6139 (PyCFunction)ufunc_at,
6140 METH_VARARGS0x0001, NULL((void*)0)},
6141 {NULL((void*)0), NULL((void*)0), 0, NULL((void*)0)} /* sentinel */
6142};
6143
6144
6145/******************************************************************************
6146 *** UFUNC GETSET ***
6147 *****************************************************************************/
6148
6149
6150static char
6151_typecharfromnum(int num) {
6152 PyArray_Descr *descr;
6153 char ret;
6154
6155 descr = PyArray_DescrFromType(num);
6156 ret = descr->type;
6157 Py_DECREF(descr)_Py_DECREF(((PyObject*)(descr)));
6158 return ret;
6159}
6160
6161
6162static PyObject *
6163ufunc_get_doc(PyUFuncObject *ufunc)
6164{
6165 static PyObject *_sig_formatter;
6166 PyObject *doc;
6167
6168 npy_cache_import(
6169 "numpy.core._internal",
6170 "_ufunc_doc_signature_formatter",
6171 &_sig_formatter);
6172
6173 if (_sig_formatter == NULL((void*)0)) {
6174 return NULL((void*)0);
6175 }
6176
6177 /*
6178 * Put docstring first or FindMethod finds it... could so some
6179 * introspection on name and nin + nout to automate the first part
6180 * of it the doc string shouldn't need the calling convention
6181 */
6182 doc = PyObject_CallFunctionObjArgs(_sig_formatter,
6183 (PyObject *)ufunc, NULL((void*)0));
6184 if (doc == NULL((void*)0)) {
6185 return NULL((void*)0);
6186 }
6187 if (ufunc->doc != NULL((void*)0)) {
6188 Py_SETREF(doc, PyUnicode_FromFormat("%S\n\n%s", doc, ufunc->doc))do { PyObject *_py_tmp = ((PyObject*)(doc)); (doc) = (PyUnicode_FromFormat
("%S\n\n%s", doc, ufunc->doc)); _Py_DECREF(((PyObject*)(_py_tmp
))); } while (0)
;
6189 }
6190 return doc;
6191}
6192
6193
6194static PyObject *
6195ufunc_get_nin(PyUFuncObject *ufunc)
6196{
6197 return PyLong_FromLong(ufunc->nin);
6198}
6199
6200static PyObject *
6201ufunc_get_nout(PyUFuncObject *ufunc)
6202{
6203 return PyLong_FromLong(ufunc->nout);
6204}
6205
6206static PyObject *
6207ufunc_get_nargs(PyUFuncObject *ufunc)
6208{
6209 return PyLong_FromLong(ufunc->nargs);
6210}
6211
6212static PyObject *
6213ufunc_get_ntypes(PyUFuncObject *ufunc)
6214{
6215 return PyLong_FromLong(ufunc->ntypes);
6216}
6217
6218static PyObject *
6219ufunc_get_types(PyUFuncObject *ufunc)
6220{
6221 /* return a list with types grouped input->output */
6222 PyObject *list;
6223 PyObject *str;
6224 int k, j, n, nt = ufunc->ntypes;
6225 int ni = ufunc->nin;
6226 int no = ufunc->nout;
6227 char *t;
6228 list = PyList_New(nt);
6229 if (list == NULL((void*)0)) {
6230 return NULL((void*)0);
6231 }
6232 t = PyArray_mallocPyMem_RawMalloc(no+ni+2);
6233 n = 0;
6234 for (k = 0; k < nt; k++) {
6235 for (j = 0; j<ni; j++) {
6236 t[j] = _typecharfromnum(ufunc->types[n]);
6237 n++;
6238 }
6239 t[ni] = '-';
6240 t[ni+1] = '>';
6241 for (j = 0; j < no; j++) {
6242 t[ni + 2 + j] = _typecharfromnum(ufunc->types[n]);
6243 n++;
6244 }
6245 str = PyUnicode_FromStringAndSize(t, no + ni + 2);
6246 PyList_SET_ITEM(list, k, str)PyList_SetItem(list, k, str);
6247 }
6248 PyArray_freePyMem_RawFree(t);
6249 return list;
6250}
6251
6252static PyObject *
6253ufunc_get_name(PyUFuncObject *ufunc)
6254{
6255 return PyUnicode_FromString(ufunc->name);
6256}
6257
6258static PyObject *
6259ufunc_get_identity(PyUFuncObject *ufunc)
6260{
6261 npy_bool reorderable;
6262 return _get_identity(ufunc, &reorderable);
6263}
6264
6265static PyObject *
6266ufunc_get_signature(PyUFuncObject *ufunc)
6267{
6268 if (!ufunc->core_enabled) {
6269 Py_RETURN_NONEreturn _Py_INCREF(((PyObject*)((&_Py_NoneStruct)))), (&
_Py_NoneStruct)
;
6270 }
6271 return PyUnicode_FromString(ufunc->core_signature);
6272}
6273
6274#undef _typecharfromnum
6275
6276/*
6277 * Docstring is now set from python
6278 * static char *Ufunctype__doc__ = NULL;
6279 */
6280static PyGetSetDef ufunc_getset[] = {
6281 {"__doc__",
6282 (getter)ufunc_get_doc,
6283 NULL((void*)0), NULL((void*)0), NULL((void*)0)},
6284 {"nin",
6285 (getter)ufunc_get_nin,
6286 NULL((void*)0), NULL((void*)0), NULL((void*)0)},
6287 {"nout",
6288 (getter)ufunc_get_nout,
6289 NULL((void*)0), NULL((void*)0), NULL((void*)0)},
6290 {"nargs",
6291 (getter)ufunc_get_nargs,
6292 NULL((void*)0), NULL((void*)0), NULL((void*)0)},
6293 {"ntypes",
6294 (getter)ufunc_get_ntypes,
6295 NULL((void*)0), NULL((void*)0), NULL((void*)0)},
6296 {"types",
6297 (getter)ufunc_get_types,
6298 NULL((void*)0), NULL((void*)0), NULL((void*)0)},
6299 {"__name__",
6300 (getter)ufunc_get_name,
6301 NULL((void*)0), NULL((void*)0), NULL((void*)0)},
6302 {"identity",
6303 (getter)ufunc_get_identity,
6304 NULL((void*)0), NULL((void*)0), NULL((void*)0)},
6305 {"signature",
6306 (getter)ufunc_get_signature,
6307 NULL((void*)0), NULL((void*)0), NULL((void*)0)},
6308 {NULL((void*)0), NULL((void*)0), NULL((void*)0), NULL((void*)0), NULL((void*)0)}, /* Sentinel */
6309};
6310
6311
6312/******************************************************************************
6313 *** UFUNC TYPE OBJECT ***
6314 *****************************************************************************/
6315
6316NPY_NO_EXPORT__attribute__((visibility("hidden"))) PyTypeObject PyUFunc_Type = {
6317 PyVarObject_HEAD_INIT(NULL, 0){ { 1, ((void*)0) }, 0 },
6318 .tp_name = "numpy.ufunc",
6319 .tp_basicsize = sizeof(PyUFuncObject),
6320 .tp_dealloc = (destructor)ufunc_dealloc,
6321 .tp_repr = (reprfunc)ufunc_repr,
6322 .tp_call = (ternaryfunc)ufunc_generic_call,
6323 .tp_str = (reprfunc)ufunc_repr,
6324 .tp_flags = Py_TPFLAGS_DEFAULT( 0 | (1UL << 18) | 0) |
6325#if PY_VERSION_HEX((3 << 24) | (8 << 16) | (5 << 8) | (0xF <<
4) | (0 << 0))
>= 0x03080000
6326 _Py_TPFLAGS_HAVE_VECTORCALL(1UL << 11) |
6327#endif
6328 Py_TPFLAGS_HAVE_GC(1UL << 14),
6329 .tp_traverse = (traverseproc)ufunc_traverse,
6330 .tp_methods = ufunc_methods,
6331 .tp_getset = ufunc_getset,
6332#if PY_VERSION_HEX((3 << 24) | (8 << 16) | (5 << 8) | (0xF <<
4) | (0 << 0))
>= 0x03080000
6333 .tp_vectorcall_offset = offsetof(PyUFuncObject, vectorcall)__builtin_offsetof(PyUFuncObject, vectorcall),
6334#endif
6335};
6336
6337/* End of code for ufunc objects */

/opt/pyrefcon/lib/pyrefcon/models/models/PyLong_FromLong.model

1#ifndef PyLong_FromLong
2struct _object;
3typedef struct _object PyObject;
4PyObject* clang_analyzer_PyObject_New_Reference();
5PyObject* PyLong_FromLong(long v) {
6 return clang_analyzer_PyObject_New_Reference();
18
Setting reference count to 1
7}
8#else
9#warning "API PyLong_FromLong is defined as a macro."
10#endif