numpy  2.0.0
include/numpy/ufuncobject.h
Go to the documentation of this file.
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 */