numpy
2.0.0
|
00001 #ifndef _NPY_PRIVATE__REDUCTION_H_ 00002 #define _NPY_PRIVATE__REDUCTION_H_ 00003 00004 /************************************************************ 00005 * Typedefs used by PyArray_ReduceWrapper, new in 1.7. 00006 ************************************************************/ 00007 00008 /* 00009 * This is a function for assigning a reduction identity to the result, 00010 * before doing the reduction computation. The 00011 * value in 'data' is passed through from PyArray_ReduceWrapper. 00012 * 00013 * This function could, for example, simply be a call like 00014 * return PyArray_AssignZero(result, NULL, NULL); 00015 * 00016 * It should return -1 on failure, or 0 on success. 00017 */ 00018 typedef int (PyArray_AssignReduceIdentityFunc)(PyArrayObject *result, 00019 void *data); 00020 00021 /* 00022 * This is a function for the reduce loop. 00023 * 00024 * The needs_api parameter indicates whether it's ok to release the GIL during 00025 * the loop, such as when the iternext() function never calls 00026 * a function which could raise a Python exception. 00027 * 00028 * Ths skip_first_count parameter indicates how many elements need to be 00029 * skipped based on NpyIter_IsFirstVisit checks. This can only be positive 00030 * when the 'assign_identity' parameter was NULL when calling 00031 * PyArray_ReduceWrapper. 00032 * 00033 * The loop gets two data pointers and two strides, and should 00034 * look roughly like this: 00035 * { 00036 * NPY_BEGIN_THREADS_DEF; 00037 * if (!needs_api) { 00038 * NPY_BEGIN_THREADS; 00039 * } 00040 * // This first-visit loop can be skipped if 'assign_identity' was non-NULL 00041 * if (skip_first_count > 0) { 00042 * do { 00043 * char *data0 = dataptr[0], *data1 = dataptr[1]; 00044 * npy_intp stride0 = strideptr[0], stride1 = strideptr[1]; 00045 * npy_intp count = *countptr; 00046 * 00047 * // Skip any first-visit elements 00048 * if (NpyIter_IsFirstVisit(iter, 0)) { 00049 * if (stride0 == 0) { 00050 * --count; 00051 * --skip_first_count; 00052 * data1 += stride1; 00053 * } 00054 * else { 00055 * skip_first_count -= count; 00056 * count = 0; 00057 * } 00058 * } 00059 * 00060 * while (count--) { 00061 * *(result_t *)data0 = my_reduce_op(*(result_t *)data0, 00062 * *(operand_t *)data1); 00063 * data0 += stride0; 00064 * data1 += stride1; 00065 * } 00066 * 00067 * // Jump to the faster loop when skipping is done 00068 * if (skip_first_count == 0) { 00069 * if (iternext(iter)) { 00070 * break; 00071 * } 00072 * else { 00073 * goto finish_loop; 00074 * } 00075 * } 00076 * } while (iternext(iter)); 00077 * } 00078 * do { 00079 * char *data0 = dataptr[0], *data1 = dataptr[1]; 00080 * npy_intp stride0 = strideptr[0], stride1 = strideptr[1]; 00081 * npy_intp count = *countptr; 00082 * 00083 * while (count--) { 00084 * *(result_t *)data0 = my_reduce_op(*(result_t *)data0, 00085 * *(operand_t *)data1); 00086 * data0 += stride0; 00087 * data1 += stride1; 00088 * } 00089 * } while (iternext(iter)); 00090 * finish_loop: 00091 * if (!needs_api) { 00092 * NPY_END_THREADS; 00093 * } 00094 * return (needs_api && PyErr_Occurred()) ? -1 : 0; 00095 * } 00096 * 00097 * If needs_api is True, this function should call PyErr_Occurred() 00098 * to check if an error occurred during processing, and return -1 for 00099 * error, 0 for success. 00100 */ 00101 typedef int (PyArray_ReduceLoopFunc)(NpyIter *iter, 00102 char **dataptr, 00103 npy_intp *strideptr, 00104 npy_intp *countptr, 00105 NpyIter_IterNextFunc *iternext, 00106 int needs_api, 00107 npy_intp skip_first_count, 00108 void *data); 00109 00110 /* 00111 * This function executes all the standard NumPy reduction function 00112 * boilerplate code, just calling assign_identity and the appropriate 00113 * inner loop function where necessary. 00114 * 00115 * operand : The array to be reduced. 00116 * out : NULL, or the array into which to place the result. 00117 * wheremask : NOT YET SUPPORTED, but this parameter is placed here 00118 * so that support can be added in the future without breaking 00119 * API compatibility. Pass in NULL. 00120 * operand_dtype : The dtype the inner loop expects for the operand. 00121 * result_dtype : The dtype the inner loop expects for the result. 00122 * casting : The casting rule to apply to the operands. 00123 * axis_flags : Flags indicating the reduction axes of 'operand'. 00124 * reorderable : If True, the reduction being done is reorderable, which 00125 * means specifying multiple axes of reduction at once is ok, 00126 * and the reduction code may calculate the reduction in an 00127 * arbitrary order. The calculation may be reordered because 00128 * of cache behavior or multithreading requirements. 00129 * keepdims : If true, leaves the reduction dimensions in the result 00130 * with size one. 00131 * subok : If true, the result uses the subclass of operand, otherwise 00132 * it is always a base class ndarray. 00133 * assign_identity : If NULL, PyArray_InitializeReduceResult is used, otherwise 00134 * this function is called to initialize the result to 00135 * the reduction's unit. 00136 * loop : The loop which does the reduction. 00137 * data : Data which is passed to assign_identity and the inner loop. 00138 * buffersize : Buffer size for the iterator. For the default, pass in 0. 00139 * funcname : The name of the reduction function, for error messages. 00140 */ 00141 NPY_NO_EXPORT PyArrayObject * 00142 PyUFunc_ReduceWrapper(PyArrayObject *operand, PyArrayObject *out, 00143 PyArrayObject *wheremask, 00144 PyArray_Descr *operand_dtype, 00145 PyArray_Descr *result_dtype, 00146 NPY_CASTING casting, 00147 npy_bool *axis_flags, int reorderable, 00148 int keepdims, 00149 int subok, 00150 PyArray_AssignReduceIdentityFunc *assign_identity, 00151 PyArray_ReduceLoopFunc *loop, 00152 void *data, npy_intp buffersize, const char *funcname); 00153 00154 #endif