numpy
2.0.0
|
00001 #ifndef Py_UFUNCOBJECT_H 00002 #define Py_UFUNCOBJECT_H 00003 00004 #include <numpy/npy_math.h> 00005 00006 #ifdef __cplusplus 00007 extern "C" { 00008 #endif 00009 00010 /* 00011 * The legacy generic inner loop for a standard element-wise or 00012 * generalized ufunc. 00013 */ 00014 typedef void (*PyUFuncGenericFunction) 00015 (char **args, 00016 npy_intp *dimensions, 00017 npy_intp *strides, 00018 void *innerloopdata); 00019 00020 /* 00021 * The most generic one-dimensional inner loop for 00022 * a standard element-wise ufunc. This typedef is also 00023 * more consistent with the other NumPy function pointer typedefs 00024 * than PyUFuncGenericFunction. 00025 */ 00026 typedef void (PyUFunc_StridedInnerLoopFunc)( 00027 char **dataptrs, npy_intp *strides, 00028 npy_intp count, 00029 NpyAuxData *innerloopdata); 00030 00031 /* 00032 * The most generic one-dimensional inner loop for 00033 * a masked standard element-wise ufunc. "Masked" here means that it skips 00034 * doing calculations on any items for which the maskptr array has a true 00035 * value. 00036 */ 00037 typedef void (PyUFunc_MaskedStridedInnerLoopFunc)( 00038 char **dataptrs, npy_intp *strides, 00039 char *maskptr, npy_intp mask_stride, 00040 npy_intp count, 00041 NpyAuxData *innerloopdata); 00042 00043 /* Forward declaration for the type resolver and loop selector typedefs */ 00044 struct _tagPyUFuncObject; 00045 00046 /* 00047 * Given the operands for calling a ufunc, should determine the 00048 * calculation input and output data types and return an inner loop function. 00049 * This function should validate that the casting rule is being followed, 00050 * and fail if it is not. 00051 * 00052 * For backwards compatibility, the regular type resolution function does not 00053 * support auxiliary data with object semantics. The type resolution call 00054 * which returns a masked generic function returns a standard NpyAuxData 00055 * object, for which the NPY_AUXDATA_FREE and NPY_AUXDATA_CLONE macros 00056 * work. 00057 * 00058 * ufunc: The ufunc object. 00059 * casting: The 'casting' parameter provided to the ufunc. 00060 * operands: An array of length (ufunc->nin + ufunc->nout), 00061 * with the output parameters possibly NULL. 00062 * type_tup: Either NULL, or the type_tup passed to the ufunc. 00063 * out_dtypes: An array which should be populated with new 00064 * references to (ufunc->nin + ufunc->nout) new 00065 * dtypes, one for each input and output. These 00066 * dtypes should all be in native-endian format. 00067 * 00068 * Should return 0 on success, -1 on failure (with exception set), 00069 * or -2 if Py_NotImplemented should be returned. 00070 */ 00071 typedef int (PyUFunc_TypeResolutionFunc)( 00072 struct _tagPyUFuncObject *ufunc, 00073 NPY_CASTING casting, 00074 PyArrayObject **operands, 00075 PyObject *type_tup, 00076 PyArray_Descr **out_dtypes); 00077 00078 /* 00079 * Given an array of DTypes as returned by the PyUFunc_TypeResolutionFunc, 00080 * and an array of fixed strides (the array will contain NPY_MAX_INTP for 00081 * strides which are not necessarily fixed), returns an inner loop 00082 * with associated auxiliary data. 00083 * 00084 * For backwards compatibility, there is a variant of the inner loop 00085 * selection which returns an inner loop irrespective of the strides, 00086 * and with a void* static auxiliary data instead of an NpyAuxData * 00087 * dynamically allocatable auxiliary data. 00088 * 00089 * ufunc: The ufunc object. 00090 * dtypes: An array which has been populated with dtypes, 00091 * in most cases by the type resolution funciton 00092 * for the same ufunc. 00093 * fixed_strides: For each input/output, either the stride that 00094 * will be used every time the function is called 00095 * or NPY_MAX_INTP if the stride might change or 00096 * is not known ahead of time. The loop selection 00097 * function may use this stride to pick inner loops 00098 * which are optimized for contiguous or 0-stride 00099 * cases. 00100 * out_innerloop: Should be populated with the correct ufunc inner 00101 * loop for the given type. 00102 * out_innerloopdata: Should be populated with the void* data to 00103 * be passed into the out_innerloop function. 00104 * out_needs_api: If the inner loop needs to use the Python API, 00105 * should set the to 1, otherwise should leave 00106 * this untouched. 00107 */ 00108 typedef int (PyUFunc_LegacyInnerLoopSelectionFunc)( 00109 struct _tagPyUFuncObject *ufunc, 00110 PyArray_Descr **dtypes, 00111 PyUFuncGenericFunction *out_innerloop, 00112 void **out_innerloopdata, 00113 int *out_needs_api); 00114 typedef int (PyUFunc_InnerLoopSelectionFunc)( 00115 struct _tagPyUFuncObject *ufunc, 00116 PyArray_Descr **dtypes, 00117 npy_intp *fixed_strides, 00118 PyUFunc_StridedInnerLoopFunc **out_innerloop, 00119 NpyAuxData **out_innerloopdata, 00120 int *out_needs_api); 00121 typedef int (PyUFunc_MaskedInnerLoopSelectionFunc)( 00122 struct _tagPyUFuncObject *ufunc, 00123 PyArray_Descr **dtypes, 00124 PyArray_Descr *mask_dtype, 00125 npy_intp *fixed_strides, 00126 npy_intp fixed_mask_stride, 00127 PyUFunc_MaskedStridedInnerLoopFunc **out_innerloop, 00128 NpyAuxData **out_innerloopdata, 00129 int *out_needs_api); 00130 00131 typedef struct _tagPyUFuncObject { 00132 PyObject_HEAD 00133 /* 00134 * nin: Number of inputs 00135 * nout: Number of outputs 00136 * nargs: Always nin + nout (Why is it stored?) 00137 */ 00138 int nin, nout, nargs; 00139 00140 /* Identity for reduction, either PyUFunc_One or PyUFunc_Zero */ 00141 int identity; 00142 00143 /* Array of one-dimensional core loops */ 00144 PyUFuncGenericFunction *functions; 00145 /* Array of funcdata that gets passed into the functions */ 00146 void **data; 00147 /* The number of elements in 'functions' and 'data' */ 00148 int ntypes; 00149 00150 /* Does not appear to be used */ 00151 int check_return; 00152 00153 /* The name of the ufunc */ 00154 char *name; 00155 00156 /* Array of type numbers, of size ('nargs' * 'ntypes') */ 00157 char *types; 00158 00159 /* Documentation string */ 00160 char *doc; 00161 00162 void *ptr; 00163 PyObject *obj; 00164 PyObject *userloops; 00165 00166 /* generalized ufunc parameters */ 00167 00168 /* 0 for scalar ufunc; 1 for generalized ufunc */ 00169 int core_enabled; 00170 /* number of distinct dimension names in signature */ 00171 int core_num_dim_ix; 00172 00173 /* 00174 * dimension indices of input/output argument k are stored in 00175 * core_dim_ixs[core_offsets[k]..core_offsets[k]+core_num_dims[k]-1] 00176 */ 00177 00178 /* numbers of core dimensions of each argument */ 00179 int *core_num_dims; 00180 /* 00181 * dimension indices in a flatted form; indices 00182 * are in the range of [0,core_num_dim_ix) 00183 */ 00184 int *core_dim_ixs; 00185 /* 00186 * positions of 1st core dimensions of each 00187 * argument in core_dim_ixs 00188 */ 00189 int *core_offsets; 00190 /* signature string for printing purpose */ 00191 char *core_signature; 00192 00193 /* 00194 * A function which resolves the types and fills an array 00195 * with the dtypes for the inputs and outputs. 00196 */ 00197 PyUFunc_TypeResolutionFunc *type_resolver; 00198 /* 00199 * A function which returns an inner loop written for 00200 * NumPy 1.6 and earlier ufuncs. This is for backwards 00201 * compatibility, and may be NULL if inner_loop_selector 00202 * is specified. 00203 */ 00204 PyUFunc_LegacyInnerLoopSelectionFunc *legacy_inner_loop_selector; 00205 /* 00206 * A function which returns an inner loop for the new mechanism 00207 * in NumPy 1.7 and later. If provided, this is used, otherwise 00208 * if NULL the legacy_inner_loop_selector is used instead. 00209 */ 00210 PyUFunc_InnerLoopSelectionFunc *inner_loop_selector; 00211 /* 00212 * A function which returns a masked inner loop for the ufunc. 00213 */ 00214 PyUFunc_MaskedInnerLoopSelectionFunc *masked_inner_loop_selector; 00215 } PyUFuncObject; 00216 00217 #include "arrayobject.h" 00218 00219 #define UFUNC_ERR_IGNORE 0 00220 #define UFUNC_ERR_WARN 1 00221 #define UFUNC_ERR_RAISE 2 00222 #define UFUNC_ERR_CALL 3 00223 #define UFUNC_ERR_PRINT 4 00224 #define UFUNC_ERR_LOG 5 00225 00226 /* Python side integer mask */ 00227 00228 #define UFUNC_MASK_DIVIDEBYZERO 0x07 00229 #define UFUNC_MASK_OVERFLOW 0x3f 00230 #define UFUNC_MASK_UNDERFLOW 0x1ff 00231 #define UFUNC_MASK_INVALID 0xfff 00232 00233 #define UFUNC_SHIFT_DIVIDEBYZERO 0 00234 #define UFUNC_SHIFT_OVERFLOW 3 00235 #define UFUNC_SHIFT_UNDERFLOW 6 00236 #define UFUNC_SHIFT_INVALID 9 00237 00238 00239 /* platform-dependent code translates floating point 00240 status to an integer sum of these values 00241 */ 00242 #define UFUNC_FPE_DIVIDEBYZERO 1 00243 #define UFUNC_FPE_OVERFLOW 2 00244 #define UFUNC_FPE_UNDERFLOW 4 00245 #define UFUNC_FPE_INVALID 8 00246 00247 /* Error mode that avoids look-up (no checking) */ 00248 #define UFUNC_ERR_DEFAULT 0 00249 00250 #define UFUNC_OBJ_ISOBJECT 1 00251 #define UFUNC_OBJ_NEEDS_API 2 00252 00253 /* Default user error mode */ 00254 #define UFUNC_ERR_DEFAULT2 \ 00255 (UFUNC_ERR_WARN << UFUNC_SHIFT_DIVIDEBYZERO) + \ 00256 (UFUNC_ERR_WARN << UFUNC_SHIFT_OVERFLOW) + \ 00257 (UFUNC_ERR_WARN << UFUNC_SHIFT_INVALID) 00258 00259 #if NPY_ALLOW_THREADS 00260 #define NPY_LOOP_BEGIN_THREADS do {if (!(loop->obj & UFUNC_OBJ_NEEDS_API)) _save = PyEval_SaveThread();} while (0); 00261 #define NPY_LOOP_END_THREADS do {if (!(loop->obj & UFUNC_OBJ_NEEDS_API)) PyEval_RestoreThread(_save);} while (0); 00262 #else 00263 #define NPY_LOOP_BEGIN_THREADS 00264 #define NPY_LOOP_END_THREADS 00265 #endif 00266 00267 /* 00268 * UFunc has unit of 1, and the order of operations can be reordered 00269 * This case allows reduction with multiple axes at once. 00270 */ 00271 #define PyUFunc_One 1 00272 /* 00273 * UFunc has unit of 0, and the order of operations can be reordered 00274 * This case allows reduction with multiple axes at once. 00275 */ 00276 #define PyUFunc_Zero 0 00277 /* 00278 * UFunc has no unit, and the order of operations cannot be reordered. 00279 * This case does not allow reduction with multiple axes at once. 00280 */ 00281 #define PyUFunc_None -1 00282 /* 00283 * UFunc has no unit, and the order of operations can be reordered 00284 * This case allows reduction with multiple axes at once. 00285 */ 00286 #define PyUFunc_ReorderableNone -2 00287 00288 #define UFUNC_REDUCE 0 00289 #define UFUNC_ACCUMULATE 1 00290 #define UFUNC_REDUCEAT 2 00291 #define UFUNC_OUTER 3 00292 00293 00294 typedef struct { 00295 int nin; 00296 int nout; 00297 PyObject *callable; 00298 } PyUFunc_PyFuncData; 00299 00300 /* A linked-list of function information for 00301 user-defined 1-d loops. 00302 */ 00303 typedef struct _loop1d_info { 00304 PyUFuncGenericFunction func; 00305 void *data; 00306 int *arg_types; 00307 struct _loop1d_info *next; 00308 } PyUFunc_Loop1d; 00309 00310 00311 #include "__ufunc_api.h" 00312 00313 #define UFUNC_PYVALS_NAME "UFUNC_PYVALS" 00314 00315 #define UFUNC_CHECK_ERROR(arg) \ 00316 do {if ((((arg)->obj & UFUNC_OBJ_NEEDS_API) && PyErr_Occurred()) || \ 00317 ((arg)->errormask && \ 00318 PyUFunc_checkfperr((arg)->errormask, \ 00319 (arg)->errobj, \ 00320 &(arg)->first))) \ 00321 goto fail;} while (0) 00322 00323 /* This code checks the IEEE status flags in a platform-dependent way */ 00324 /* Adapted from Numarray */ 00325 00326 #if (defined(__unix__) || defined(unix)) && !defined(USG) 00327 #include <sys/param.h> 00328 #endif 00329 00330 /* OSF/Alpha (Tru64) ---------------------------------------------*/ 00331 #if defined(__osf__) && defined(__alpha) 00332 00333 #include <machine/fpu.h> 00334 00335 #define UFUNC_CHECK_STATUS(ret) { \ 00336 unsigned long fpstatus; \ 00337 \ 00338 fpstatus = ieee_get_fp_control(); \ 00339 /* clear status bits as well as disable exception mode if on */ \ 00340 ieee_set_fp_control( 0 ); \ 00341 ret = ((IEEE_STATUS_DZE & fpstatus) ? UFUNC_FPE_DIVIDEBYZERO : 0) \ 00342 | ((IEEE_STATUS_OVF & fpstatus) ? UFUNC_FPE_OVERFLOW : 0) \ 00343 | ((IEEE_STATUS_UNF & fpstatus) ? UFUNC_FPE_UNDERFLOW : 0) \ 00344 | ((IEEE_STATUS_INV & fpstatus) ? UFUNC_FPE_INVALID : 0); \ 00345 } 00346 00347 /* MS Windows -----------------------------------------------------*/ 00348 #elif defined(_MSC_VER) 00349 00350 #include <float.h> 00351 00352 /* Clear the floating point exception default of Borland C++ */ 00353 #if defined(__BORLANDC__) 00354 #define UFUNC_NOFPE _control87(MCW_EM, MCW_EM); 00355 #endif 00356 00357 #define UFUNC_CHECK_STATUS(ret) { \ 00358 int fpstatus = (int) _clearfp(); \ 00359 \ 00360 ret = ((SW_ZERODIVIDE & fpstatus) ? UFUNC_FPE_DIVIDEBYZERO : 0) \ 00361 | ((SW_OVERFLOW & fpstatus) ? UFUNC_FPE_OVERFLOW : 0) \ 00362 | ((SW_UNDERFLOW & fpstatus) ? UFUNC_FPE_UNDERFLOW : 0) \ 00363 | ((SW_INVALID & fpstatus) ? UFUNC_FPE_INVALID : 0); \ 00364 } 00365 00366 /* Solaris --------------------------------------------------------*/ 00367 /* --------ignoring SunOS ieee_flags approach, someone else can 00368 ** deal with that! */ 00369 #elif defined(sun) || defined(__BSD__) || defined(__OpenBSD__) || \ 00370 (defined(__FreeBSD__) && (__FreeBSD_version < 502114)) || \ 00371 defined(__NetBSD__) 00372 #include <ieeefp.h> 00373 00374 #define UFUNC_CHECK_STATUS(ret) { \ 00375 int fpstatus; \ 00376 \ 00377 fpstatus = (int) fpgetsticky(); \ 00378 ret = ((FP_X_DZ & fpstatus) ? UFUNC_FPE_DIVIDEBYZERO : 0) \ 00379 | ((FP_X_OFL & fpstatus) ? UFUNC_FPE_OVERFLOW : 0) \ 00380 | ((FP_X_UFL & fpstatus) ? UFUNC_FPE_UNDERFLOW : 0) \ 00381 | ((FP_X_INV & fpstatus) ? UFUNC_FPE_INVALID : 0); \ 00382 (void) fpsetsticky(0); \ 00383 } 00384 00385 #elif defined(__GLIBC__) || defined(__APPLE__) || \ 00386 defined(__CYGWIN__) || defined(__MINGW32__) || \ 00387 (defined(__FreeBSD__) && (__FreeBSD_version >= 502114)) 00388 00389 #if defined(__GLIBC__) || defined(__APPLE__) || \ 00390 defined(__MINGW32__) || defined(__FreeBSD__) 00391 #include <fenv.h> 00392 #elif defined(__CYGWIN__) 00393 #include "fenv/fenv.c" 00394 #endif 00395 00396 #define UFUNC_CHECK_STATUS(ret) { \ 00397 int fpstatus = (int) fetestexcept(FE_DIVBYZERO | FE_OVERFLOW | \ 00398 FE_UNDERFLOW | FE_INVALID); \ 00399 ret = ((FE_DIVBYZERO & fpstatus) ? UFUNC_FPE_DIVIDEBYZERO : 0) \ 00400 | ((FE_OVERFLOW & fpstatus) ? UFUNC_FPE_OVERFLOW : 0) \ 00401 | ((FE_UNDERFLOW & fpstatus) ? UFUNC_FPE_UNDERFLOW : 0) \ 00402 | ((FE_INVALID & fpstatus) ? UFUNC_FPE_INVALID : 0); \ 00403 (void) feclearexcept(FE_DIVBYZERO | FE_OVERFLOW | \ 00404 FE_UNDERFLOW | FE_INVALID); \ 00405 } 00406 00407 #elif defined(_AIX) 00408 00409 #include <float.h> 00410 #include <fpxcp.h> 00411 00412 #define UFUNC_CHECK_STATUS(ret) { \ 00413 fpflag_t fpstatus; \ 00414 \ 00415 fpstatus = fp_read_flag(); \ 00416 ret = ((FP_DIV_BY_ZERO & fpstatus) ? UFUNC_FPE_DIVIDEBYZERO : 0) \ 00417 | ((FP_OVERFLOW & fpstatus) ? UFUNC_FPE_OVERFLOW : 0) \ 00418 | ((FP_UNDERFLOW & fpstatus) ? UFUNC_FPE_UNDERFLOW : 0) \ 00419 | ((FP_INVALID & fpstatus) ? UFUNC_FPE_INVALID : 0); \ 00420 fp_swap_flag(0); \ 00421 } 00422 00423 #else 00424 00425 #define NO_FLOATING_POINT_SUPPORT 00426 #define UFUNC_CHECK_STATUS(ret) { \ 00427 ret = 0; \ 00428 } 00429 00430 #endif 00431 00432 /* 00433 * THESE MACROS ARE DEPRECATED. 00434 * Use npy_set_floatstatus_* in the npymath library. 00435 */ 00436 #define generate_divbyzero_error() npy_set_floatstatus_divbyzero() 00437 #define generate_overflow_error() npy_set_floatstatus_overflow() 00438 00439 /* Make sure it gets defined if it isn't already */ 00440 #ifndef UFUNC_NOFPE 00441 #define UFUNC_NOFPE 00442 #endif 00443 00444 00445 #ifdef __cplusplus 00446 } 00447 #endif 00448 #endif /* !Py_UFUNCOBJECT_H */