File: | numpy/core/src/umath/ufunc_object.c |
Warning: | line 4637, column 19 Calling function '_get_normalized_typetup' with a PyObject argument whose ownership has been released |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
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 | |||||||||||||
69 | typedef 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__ */ | ||||||||||||
76 | typedef 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 | */ | ||||||||||||
87 | static 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 | |||||||||||||
100 | static PyObject * | ||||||||||||
101 | prepare_input_arguments_for_outer(PyObject *args, PyUFuncObject *ufunc); | ||||||||||||
102 | |||||||||||||
103 | |||||||||||||
104 | /*UFUNC_API*/ | ||||||||||||
105 | NPY_NO_EXPORT__attribute__((visibility("hidden"))) int | ||||||||||||
106 | PyUFunc_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(¶m); | ||||||||||||
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*/ | ||||||||||||
125 | NPY_NO_EXPORT__attribute__((visibility("hidden"))) int | ||||||||||||
126 | PyUFunc_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*/ | ||||||||||||
142 | NPY_NO_EXPORT__attribute__((visibility("hidden"))) int | ||||||||||||
143 | PyUFunc_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*/ | ||||||||||||
155 | NPY_NO_EXPORT__attribute__((visibility("hidden"))) void | ||||||||||||
156 | PyUFunc_clearfperr() | ||||||||||||
157 | { | ||||||||||||
158 | char param = 0; | ||||||||||||
159 | npy_clear_floatstatus_barrier(¶m); | ||||||||||||
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 | */ | ||||||||||||
168 | static 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 | */ | ||||||||||||
226 | static 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 | */ | ||||||||||||
274 | static 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 */ | ||||||||||||
327 | NPY_NO_EXPORT__attribute__((visibility("hidden"))) int | ||||||||||||
328 | set_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 | */ | ||||||||||||
364 | NPY_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 | */ | ||||||||||||
403 | static 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 | */ | ||||||||||||
436 | handle_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 | */ | ||||||||||||
462 | static 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 | */ | ||||||||||||
521 | NPY_NO_EXPORT__attribute__((visibility("hidden"))) int | ||||||||||||
522 | PyUFunc_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 */ | ||||||||||||
530 | static 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 | |||||||||||||
540 | static int | ||||||||||||
541 | _is_alpha_underscore(char ch) | ||||||||||||
542 | { | ||||||||||||
543 | return (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z') || ch == '_'; | ||||||||||||
544 | } | ||||||||||||
545 | |||||||||||||
546 | static 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 | */ | ||||||||||||
555 | static 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 | */ | ||||||||||||
575 | static 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 | */ | ||||||||||||
592 | static 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 | */ | ||||||||||||
610 | static 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 | |||||||||||||
796 | fail: | ||||||||||||
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 | */ | ||||||||||||
812 | static 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 | */ | ||||||||||||
841 | NPY_NO_EXPORT__attribute__((visibility("hidden"))) const char* | ||||||||||||
842 | ufunc_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 | */ | ||||||||||||
850 | static 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 | |||||||||||||
864 | static 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 | |||||||||||||
878 | static 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 | */ | ||||||||||||
911 | static int | ||||||||||||
912 | convert_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 | |||||||||||||
974 | fail: | ||||||||||||
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 | */ | ||||||||||||
992 | static int | ||||||||||||
993 | check_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 | */ | ||||||||||||
1045 | static int | ||||||||||||
1046 | prepare_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 | */ | ||||||||||||
1123 | static NPY_INLINEinline int | ||||||||||||
1124 | try_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 | |||||||||||||
1254 | static int | ||||||||||||
1255 | iterator_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 | */ | ||||||||||||
1403 | static int | ||||||||||||
1404 | execute_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 | */ | ||||||||||||
1458 | static int | ||||||||||||
1459 | execute_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 | */ | ||||||||||||
1624 | static 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 | */ | ||||||||||||
1689 | static 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 | */ | ||||||||||||
1706 | static 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 | */ | ||||||||||||
1727 | static 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 | */ | ||||||||||||
1758 | static 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 | */ | ||||||||||||
1888 | static 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 | */ | ||||||||||||
1958 | static 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 | */ | ||||||||||||
2051 | static 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 | */ | ||||||||||||
2090 | static 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 | |||||||||||||
2107 | static int | ||||||||||||
2108 | PyUFunc_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 | |||||||||||||
2604 | fail: | ||||||||||||
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 | |||||||||||||
2618 | static int | ||||||||||||
2619 | PyUFunc_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 | |||||||||||||
2773 | fail: | ||||||||||||
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*/ | ||||||||||||
2785 | NPY_NO_EXPORT__attribute__((visibility("hidden"))) int | ||||||||||||
2786 | PyUFunc_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 | */ | ||||||||||||
2807 | static int | ||||||||||||
2808 | get_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 | |||||||||||||
2896 | static int | ||||||||||||
2897 | reduce_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 | |||||||||||||
2957 | static int | ||||||||||||
2958 | reduce_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 | |||||||||||||
3075 | finish_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 | */ | ||||||||||||
3098 | static PyArrayObject * | ||||||||||||
3099 | PyUFunc_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 | |||||||||||||
3177 | static PyObject * | ||||||||||||
3178 | PyUFunc_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 | |||||||||||||
3509 | finish: | ||||||||||||
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 | |||||||||||||
3525 | fail: | ||||||||||||
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 | */ | ||||||||||||
3554 | static PyObject * | ||||||||||||
3555 | PyUFunc_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 | |||||||||||||
3901 | finish: | ||||||||||||
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 | |||||||||||||
3910 | fail: | ||||||||||||
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 | |||||||||||||
3919 | static npy_bool | ||||||||||||
3920 | tuple_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 | |||||||||||||
3931 | static 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 | */ | ||||||||||||
3974 | static 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 */ | ||||||||||||
3993 | static 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 | */ | ||||||||||||
4000 | static PyObject * | ||||||||||||
4001 | PyUFunc_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 | |||||||||||||
4353 | fail: | ||||||||||||
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 | */ | ||||||||||||
4375 | static 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 | */ | ||||||||||||
4414 | static 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 | |||||||||||||
4460 | static 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 | */ | ||||||||||||
4515 | static int | ||||||||||||
4516 | _get_normalized_typetup(PyUFuncObject *ufunc, | ||||||||||||
4517 | PyObject *dtype_obj, PyObject *signature_obj, PyObject **out_typetup) | ||||||||||||
4518 | { | ||||||||||||
4519 | if (dtype_obj
| ||||||||||||
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
| ||||||||||||
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
| ||||||||||||
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 | */ | ||||||||||||
4679 | static PyObject * | ||||||||||||
4680 | ufunc_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
| ||||||||||||
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 | |||||||||||||
4962 | fail: | ||||||||||||
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 | */ | ||||||||||||
4977 | static PyObject * | ||||||||||||
4978 | ufunc_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 | */ | ||||||||||||
5038 | static PyObject * | ||||||||||||
5039 | ufunc_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 | |||||||||||||
5052 | NPY_NO_EXPORT__attribute__((visibility("hidden"))) PyObject * | ||||||||||||
5053 | ufunc_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 | |||||||||||||
5085 | NPY_NO_EXPORT__attribute__((visibility("hidden"))) PyObject * | ||||||||||||
5086 | ufunc_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*/ | ||||||||||||
5119 | NPY_NO_EXPORT__attribute__((visibility("hidden"))) int | ||||||||||||
5120 | PyUFunc_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*/ | ||||||||||||
5148 | NPY_NO_EXPORT__attribute__((visibility("hidden"))) PyObject * | ||||||||||||
5149 | PyUFunc_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*/ | ||||||||||||
5159 | NPY_NO_EXPORT__attribute__((visibility("hidden"))) PyObject * | ||||||||||||
5160 | PyUFunc_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*/ | ||||||||||||
5172 | NPY_NO_EXPORT__attribute__((visibility("hidden"))) PyObject * | ||||||||||||
5173 | PyUFunc_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*/ | ||||||||||||
5265 | NPY_NO_EXPORT__attribute__((visibility("hidden"))) int | ||||||||||||
5266 | PyUFunc_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 | */ | ||||||||||||
5285 | typedef 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 */ | ||||||||||||
5293 | static int | ||||||||||||
5294 | cmp_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 | */ | ||||||||||||
5312 | static 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 | |||||||||||||
5333 | static 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*/ | ||||||||||||
5358 | NPY_NO_EXPORT__attribute__((visibility("hidden"))) int | ||||||||||||
5359 | PyUFunc_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)) { | ||||||||||||
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)) { | ||||||||||||
5378 | return -1; | ||||||||||||
5379 | } | ||||||||||||
5380 | |||||||||||||
5381 | arg_typenums = PyArray_mallocPyMem_RawMalloc(ufunc->nargs * sizeof(int)); | ||||||||||||
5382 | if (arg_typenums == NULL((void*)0)) { | ||||||||||||
5383 | PyErr_NoMemory(); | ||||||||||||
5384 | return -1; | ||||||||||||
5385 | } | ||||||||||||
5386 | if (arg_dtypes != NULL((void*)0)) { | ||||||||||||
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++) { | ||||||||||||
5393 | arg_typenums[i] = user_dtype->type_num; | ||||||||||||
5394 | } | ||||||||||||
5395 | } | ||||||||||||
5396 | |||||||||||||
5397 | result = PyUFunc_RegisterLoopForType(ufunc, user_dtype->type_num, | ||||||||||||
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 | |||||||||||||
5455 | done: | ||||||||||||
5456 | PyArray_freePyMem_RawFree(arg_typenums); | ||||||||||||
5457 | |||||||||||||
5458 | Py_DECREF(key)_Py_DECREF(((PyObject*)(key))); | ||||||||||||
5459 | |||||||||||||
5460 | return result; | ||||||||||||
5461 | } | ||||||||||||
5462 | |||||||||||||
5463 | /*UFUNC_API*/ | ||||||||||||
5464 | NPY_NO_EXPORT__attribute__((visibility("hidden"))) int | ||||||||||||
5465 | PyUFunc_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))) { | ||||||||||||
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)) { | ||||||||||||
5485 | ufunc->userloops = PyDict_New(); | ||||||||||||
5486 | } | ||||||||||||
5487 | key = PyLong_FromLong((long) usertype); | ||||||||||||
5488 | if (key == NULL((void*)0)) { | ||||||||||||
5489 | return -1; | ||||||||||||
5490 | } | ||||||||||||
5491 | funcdata = PyArray_mallocPyMem_RawMalloc(sizeof(PyUFunc_Loop1d)); | ||||||||||||
5492 | if (funcdata == NULL((void*)0)) { | ||||||||||||
5493 | goto fail; | ||||||||||||
5494 | } | ||||||||||||
5495 | newtypes = PyArray_mallocPyMem_RawMalloc(sizeof(int)*ufunc->nargs); | ||||||||||||
5496 | if (newtypes == NULL((void*)0)) { | ||||||||||||
5497 | goto fail; | ||||||||||||
5498 | } | ||||||||||||
5499 | if (arg_types != NULL((void*)0)) { | ||||||||||||
5500 | for (i = 0; i < ufunc->nargs; i++) { | ||||||||||||
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()) { | ||||||||||||
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 | |||||||||||||
5591 | static void | ||||||||||||
5592 | ufunc_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 | |||||||||||||
5613 | static PyObject * | ||||||||||||
5614 | ufunc_repr(PyUFuncObject *ufunc) | ||||||||||||
5615 | { | ||||||||||||
5616 | return PyUnicode_FromFormat("<ufunc '%s'>", ufunc->name); | ||||||||||||
5617 | } | ||||||||||||
5618 | |||||||||||||
5619 | static int | ||||||||||||
5620 | ufunc_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 | */ | ||||||||||||
5640 | static PyObject * | ||||||||||||
5641 | ufunc_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 | |||||||||||||
5667 | static PyObject * | ||||||||||||
5668 | prepare_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 | |||||||||||||
5768 | static PyObject * | ||||||||||||
5769 | ufunc_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 | |||||||||||||
5776 | static PyObject * | ||||||||||||
5777 | ufunc_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 | |||||||||||||
5784 | static PyObject * | ||||||||||||
5785 | ufunc_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 */ | ||||||||||||
5793 | static NPY_INLINEinline PyArrayObject * | ||||||||||||
5794 | new_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 | */ | ||||||||||||
5813 | static PyObject * | ||||||||||||
5814 | ufunc_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 | |||||||||||||
6108 | fail: | ||||||||||||
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 | |||||||||||||
6125 | static 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 | |||||||||||||
6150 | static 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 | |||||||||||||
6162 | static PyObject * | ||||||||||||
6163 | ufunc_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 | |||||||||||||
6194 | static PyObject * | ||||||||||||
6195 | ufunc_get_nin(PyUFuncObject *ufunc) | ||||||||||||
6196 | { | ||||||||||||
6197 | return PyLong_FromLong(ufunc->nin); | ||||||||||||
6198 | } | ||||||||||||
6199 | |||||||||||||
6200 | static PyObject * | ||||||||||||
6201 | ufunc_get_nout(PyUFuncObject *ufunc) | ||||||||||||
6202 | { | ||||||||||||
6203 | return PyLong_FromLong(ufunc->nout); | ||||||||||||
6204 | } | ||||||||||||
6205 | |||||||||||||
6206 | static PyObject * | ||||||||||||
6207 | ufunc_get_nargs(PyUFuncObject *ufunc) | ||||||||||||
6208 | { | ||||||||||||
6209 | return PyLong_FromLong(ufunc->nargs); | ||||||||||||
6210 | } | ||||||||||||
6211 | |||||||||||||
6212 | static PyObject * | ||||||||||||
6213 | ufunc_get_ntypes(PyUFuncObject *ufunc) | ||||||||||||
6214 | { | ||||||||||||
6215 | return PyLong_FromLong(ufunc->ntypes); | ||||||||||||
6216 | } | ||||||||||||
6217 | |||||||||||||
6218 | static PyObject * | ||||||||||||
6219 | ufunc_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 | |||||||||||||
6252 | static PyObject * | ||||||||||||
6253 | ufunc_get_name(PyUFuncObject *ufunc) | ||||||||||||
6254 | { | ||||||||||||
6255 | return PyUnicode_FromString(ufunc->name); | ||||||||||||
6256 | } | ||||||||||||
6257 | |||||||||||||
6258 | static PyObject * | ||||||||||||
6259 | ufunc_get_identity(PyUFuncObject *ufunc) | ||||||||||||
6260 | { | ||||||||||||
6261 | npy_bool reorderable; | ||||||||||||
6262 | return _get_identity(ufunc, &reorderable); | ||||||||||||
6263 | } | ||||||||||||
6264 | |||||||||||||
6265 | static PyObject * | ||||||||||||
6266 | ufunc_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 | */ | ||||||||||||
6280 | static 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 | |||||||||||||
6316 | NPY_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 */ |
1 | #ifndef PyUnicode_FromEncodedObject |
2 | struct _object; |
3 | typedef struct _object PyObject; |
4 | PyObject* clang_analyzer_PyObject_New_Reference(); |
5 | PyObject* PyUnicode_FromEncodedObject(PyObject *obj, const char *encoding, const char *errors) { |
6 | return clang_analyzer_PyObject_New_Reference(); |
7 | } |
8 | #else |
9 | #warning "API PyUnicode_FromEncodedObject is defined as a macro." |
10 | #endif |
1 | void _Py_DECREF(PyObject *op) { --op->ob_refcnt; } |