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 #include <numpy/npy_common.h>
00006 
00007 #ifdef __cplusplus
00008 extern "C" {
00009 #endif
00010 
00011 /*
00012  * The legacy generic inner loop for a standard element-wise or
00013  * generalized ufunc.
00014  */
00015 typedef void (*PyUFuncGenericFunction)
00016             (char **args,
00017              npy_intp *dimensions,
00018              npy_intp *strides,
00019              void *innerloopdata);
00020 
00021 /*
00022  * The most generic one-dimensional inner loop for
00023  * a masked standard element-wise ufunc. "Masked" here means that it skips
00024  * doing calculations on any items for which the maskptr array has a true
00025  * value.
00026  */
00027 typedef void (PyUFunc_MaskedStridedInnerLoopFunc)(
00028                 char **dataptrs, npy_intp *strides,
00029                 char *maskptr, npy_intp mask_stride,
00030                 npy_intp count,
00031                 NpyAuxData *innerloopdata);
00032 
00033 /* Forward declaration for the type resolver and loop selector typedefs */
00034 struct _tagPyUFuncObject;
00035 
00036 /*
00037  * Given the operands for calling a ufunc, should determine the
00038  * calculation input and output data types and return an inner loop function.
00039  * This function should validate that the casting rule is being followed,
00040  * and fail if it is not.
00041  *
00042  * For backwards compatibility, the regular type resolution function does not
00043  * support auxiliary data with object semantics. The type resolution call
00044  * which returns a masked generic function returns a standard NpyAuxData
00045  * object, for which the NPY_AUXDATA_FREE and NPY_AUXDATA_CLONE macros
00046  * work.
00047  *
00048  * ufunc:             The ufunc object.
00049  * casting:           The 'casting' parameter provided to the ufunc.
00050  * operands:          An array of length (ufunc->nin + ufunc->nout),
00051  *                    with the output parameters possibly NULL.
00052  * type_tup:          Either NULL, or the type_tup passed to the ufunc.
00053  * out_dtypes:        An array which should be populated with new
00054  *                    references to (ufunc->nin + ufunc->nout) new
00055  *                    dtypes, one for each input and output. These
00056  *                    dtypes should all be in native-endian format.
00057  *
00058  * Should return 0 on success, -1 on failure (with exception set),
00059  * or -2 if Py_NotImplemented should be returned.
00060  */
00061 typedef int (PyUFunc_TypeResolutionFunc)(
00062                                 struct _tagPyUFuncObject *ufunc,
00063                                 NPY_CASTING casting,
00064                                 PyArrayObject **operands,
00065                                 PyObject *type_tup,
00066                                 PyArray_Descr **out_dtypes);
00067 
00068 /*
00069  * Given an array of DTypes as returned by the PyUFunc_TypeResolutionFunc,
00070  * and an array of fixed strides (the array will contain NPY_MAX_INTP for
00071  * strides which are not necessarily fixed), returns an inner loop
00072  * with associated auxiliary data.
00073  *
00074  * For backwards compatibility, there is a variant of the inner loop
00075  * selection which returns an inner loop irrespective of the strides,
00076  * and with a void* static auxiliary data instead of an NpyAuxData *
00077  * dynamically allocatable auxiliary data.
00078  *
00079  * ufunc:             The ufunc object.
00080  * dtypes:            An array which has been populated with dtypes,
00081  *                    in most cases by the type resolution funciton
00082  *                    for the same ufunc.
00083  * fixed_strides:     For each input/output, either the stride that
00084  *                    will be used every time the function is called
00085  *                    or NPY_MAX_INTP if the stride might change or
00086  *                    is not known ahead of time. The loop selection
00087  *                    function may use this stride to pick inner loops
00088  *                    which are optimized for contiguous or 0-stride
00089  *                    cases.
00090  * out_innerloop:     Should be populated with the correct ufunc inner
00091  *                    loop for the given type.
00092  * out_innerloopdata: Should be populated with the void* data to
00093  *                    be passed into the out_innerloop function.
00094  * out_needs_api:     If the inner loop needs to use the Python API,
00095  *                    should set the to 1, otherwise should leave
00096  *                    this untouched.
00097  */
00098 typedef int (PyUFunc_LegacyInnerLoopSelectionFunc)(
00099                             struct _tagPyUFuncObject *ufunc,
00100                             PyArray_Descr **dtypes,
00101                             PyUFuncGenericFunction *out_innerloop,
00102                             void **out_innerloopdata,
00103                             int *out_needs_api);
00104 typedef int (PyUFunc_MaskedInnerLoopSelectionFunc)(
00105                             struct _tagPyUFuncObject *ufunc,
00106                             PyArray_Descr **dtypes,
00107                             PyArray_Descr *mask_dtype,
00108                             npy_intp *fixed_strides,
00109                             npy_intp fixed_mask_stride,
00110                             PyUFunc_MaskedStridedInnerLoopFunc **out_innerloop,
00111                             NpyAuxData **out_innerloopdata,
00112                             int *out_needs_api);
00113 
00114 typedef struct _tagPyUFuncObject {
00115         PyObject_HEAD
00116         /*
00117          * nin: Number of inputs
00118          * nout: Number of outputs
00119          * nargs: Always nin + nout (Why is it stored?)
00120          */
00121         int nin, nout, nargs;
00122 
00123         /* Identity for reduction, either PyUFunc_One or PyUFunc_Zero */
00124         int identity;
00125 
00126         /* Array of one-dimensional core loops */
00127         PyUFuncGenericFunction *functions;
00128         /* Array of funcdata that gets passed into the functions */
00129         void **data;
00130         /* The number of elements in 'functions' and 'data' */
00131         int ntypes;
00132 
00133         /* Used to be unused field 'check_return' */
00134         int reserved1;
00135 
00136         /* The name of the ufunc */
00137         const char *name;
00138 
00139         /* Array of type numbers, of size ('nargs' * 'ntypes') */
00140         char *types;
00141 
00142         /* Documentation string */
00143         const char *doc;
00144 
00145         void *ptr;
00146         PyObject *obj;
00147         PyObject *userloops;
00148 
00149         /* generalized ufunc parameters */
00150 
00151         /* 0 for scalar ufunc; 1 for generalized ufunc */
00152         int core_enabled;
00153         /* number of distinct dimension names in signature */
00154         int core_num_dim_ix;
00155 
00156         /*
00157          * dimension indices of input/output argument k are stored in
00158          * core_dim_ixs[core_offsets[k]..core_offsets[k]+core_num_dims[k]-1]
00159          */
00160 
00161         /* numbers of core dimensions of each argument */
00162         int *core_num_dims;
00163         /*
00164          * dimension indices in a flatted form; indices
00165          * are in the range of [0,core_num_dim_ix)
00166          */
00167         int *core_dim_ixs;
00168         /*
00169          * positions of 1st core dimensions of each
00170          * argument in core_dim_ixs
00171          */
00172         int *core_offsets;
00173         /* signature string for printing purpose */
00174         char *core_signature;
00175 
00176         /*
00177          * A function which resolves the types and fills an array
00178          * with the dtypes for the inputs and outputs.
00179          */
00180         PyUFunc_TypeResolutionFunc *type_resolver;
00181         /*
00182          * A function which returns an inner loop written for
00183          * NumPy 1.6 and earlier ufuncs. This is for backwards
00184          * compatibility, and may be NULL if inner_loop_selector
00185          * is specified.
00186          */
00187         PyUFunc_LegacyInnerLoopSelectionFunc *legacy_inner_loop_selector;
00188         /*
00189          * This was blocked off to be the "new" inner loop selector in 1.7,
00190          * but this was never implemented. (This is also why the above
00191          * selector is called the "legacy" selector.)
00192          */
00193         void *reserved2;
00194         /*
00195          * A function which returns a masked inner loop for the ufunc.
00196          */
00197         PyUFunc_MaskedInnerLoopSelectionFunc *masked_inner_loop_selector;
00198 
00199         /*
00200          * List of flags for each operand when ufunc is called by nditer object.
00201          * These flags will be used in addition to the default flags for each
00202          * operand set by nditer object.
00203          */
00204         npy_uint32 *op_flags;
00205 
00206         /*
00207          * List of global flags used when ufunc is called by nditer object.
00208          * These flags will be used in addition to the default global flags
00209          * set by nditer object.
00210          */
00211         npy_uint32 iter_flags;
00212 } PyUFuncObject;
00213 
00214 #include "arrayobject.h"
00215 
00216 #define UFUNC_ERR_IGNORE 0
00217 #define UFUNC_ERR_WARN   1
00218 #define UFUNC_ERR_RAISE  2
00219 #define UFUNC_ERR_CALL   3
00220 #define UFUNC_ERR_PRINT  4
00221 #define UFUNC_ERR_LOG    5
00222 
00223         /* Python side integer mask */
00224 
00225 #define UFUNC_MASK_DIVIDEBYZERO 0x07
00226 #define UFUNC_MASK_OVERFLOW 0x3f
00227 #define UFUNC_MASK_UNDERFLOW 0x1ff
00228 #define UFUNC_MASK_INVALID 0xfff
00229 
00230 #define UFUNC_SHIFT_DIVIDEBYZERO 0
00231 #define UFUNC_SHIFT_OVERFLOW     3
00232 #define UFUNC_SHIFT_UNDERFLOW    6
00233 #define UFUNC_SHIFT_INVALID      9
00234 
00235 
00236 #define UFUNC_OBJ_ISOBJECT      1
00237 #define UFUNC_OBJ_NEEDS_API     2
00238 
00239    /* Default user error mode */
00240 #define UFUNC_ERR_DEFAULT                               \
00241         (UFUNC_ERR_WARN << UFUNC_SHIFT_DIVIDEBYZERO) +  \
00242         (UFUNC_ERR_WARN << UFUNC_SHIFT_OVERFLOW) +      \
00243         (UFUNC_ERR_WARN << UFUNC_SHIFT_INVALID)
00244 
00245 #if NPY_ALLOW_THREADS
00246 #define NPY_LOOP_BEGIN_THREADS do {if (!(loop->obj & UFUNC_OBJ_NEEDS_API)) _save = PyEval_SaveThread();} while (0);
00247 #define NPY_LOOP_END_THREADS   do {if (!(loop->obj & UFUNC_OBJ_NEEDS_API)) PyEval_RestoreThread(_save);} while (0);
00248 #else
00249 #define NPY_LOOP_BEGIN_THREADS
00250 #define NPY_LOOP_END_THREADS
00251 #endif
00252 
00253 /*
00254  * UFunc has unit of 0, and the order of operations can be reordered
00255  * This case allows reduction with multiple axes at once.
00256  */
00257 #define PyUFunc_Zero 0
00258 /*
00259  * UFunc has unit of 1, and the order of operations can be reordered
00260  * This case allows reduction with multiple axes at once.
00261  */
00262 #define PyUFunc_One 1
00263 /*
00264  * UFunc has unit of -1, and the order of operations can be reordered
00265  * This case allows reduction with multiple axes at once. Intended for
00266  * bitwise_and reduction.
00267  */
00268 #define PyUFunc_MinusOne 2
00269 /*
00270  * UFunc has no unit, and the order of operations cannot be reordered.
00271  * This case does not allow reduction with multiple axes at once.
00272  */
00273 #define PyUFunc_None -1
00274 /*
00275  * UFunc has no unit, and the order of operations can be reordered
00276  * This case allows reduction with multiple axes at once.
00277  */
00278 #define PyUFunc_ReorderableNone -2
00279 
00280 #define UFUNC_REDUCE 0
00281 #define UFUNC_ACCUMULATE 1
00282 #define UFUNC_REDUCEAT 2
00283 #define UFUNC_OUTER 3
00284 
00285 
00286 typedef struct {
00287         int nin;
00288         int nout;
00289         PyObject *callable;
00290 } PyUFunc_PyFuncData;
00291 
00292 /* A linked-list of function information for
00293    user-defined 1-d loops.
00294  */
00295 typedef struct _loop1d_info {
00296         PyUFuncGenericFunction func;
00297         void *data;
00298         int *arg_types;
00299         struct _loop1d_info *next;
00300         int nargs;
00301         PyArray_Descr **arg_dtypes;
00302 } PyUFunc_Loop1d;
00303 
00304 
00305 #include "__ufunc_api.h"
00306 
00307 #define UFUNC_PYVALS_NAME "UFUNC_PYVALS"
00308 
00309 #define UFUNC_CHECK_ERROR(arg) \
00310         do {if ((((arg)->obj & UFUNC_OBJ_NEEDS_API) && PyErr_Occurred()) || \
00311             ((arg)->errormask && \
00312              PyUFunc_checkfperr((arg)->errormask, \
00313                                 (arg)->errobj, \
00314                                 &(arg)->first))) \
00315                 goto fail;} while (0)
00316 
00317 
00318 /* keep in sync with ieee754.c.src */
00319 #if defined(sun) || defined(__BSD__) || defined(__OpenBSD__) || \
00320       (defined(__FreeBSD__) && (__FreeBSD_version < 502114)) || \
00321       defined(__NetBSD__) || \
00322       defined(__GLIBC__) || defined(__APPLE__) || \
00323       defined(__CYGWIN__) || defined(__MINGW32__) || \
00324       (defined(__FreeBSD__) && (__FreeBSD_version >= 502114)) || \
00325       defined(_AIX) || \
00326       defined(_MSC_VER) || \
00327       defined(__osf__) && defined(__alpha)
00328 #else
00329 #define NO_FLOATING_POINT_SUPPORT
00330 #endif
00331 
00332 
00333 /*
00334  * THESE MACROS ARE DEPRECATED.
00335  * Use npy_set_floatstatus_* in the npymath library.
00336  */
00337 #define UFUNC_FPE_DIVIDEBYZERO  NPY_FPE_DIVIDEBYZERO
00338 #define UFUNC_FPE_OVERFLOW      NPY_FPE_OVERFLOW
00339 #define UFUNC_FPE_UNDERFLOW     NPY_FPE_UNDERFLOW
00340 #define UFUNC_FPE_INVALID       NPY_FPE_INVALID
00341 
00342 #define UFUNC_CHECK_STATUS(ret) \
00343     { \
00344        ret = npy_clear_floatstatus(); \
00345     }
00346 #define generate_divbyzero_error() npy_set_floatstatus_divbyzero()
00347 #define generate_overflow_error() npy_set_floatstatus_overflow()
00348 
00349   /* Make sure it gets defined if it isn't already */
00350 #ifndef UFUNC_NOFPE
00351 /* Clear the floating point exception default of Borland C++ */
00352 #if defined(__BORLANDC__)
00353 #define UFUNC_NOFPE _control87(MCW_EM, MCW_EM);
00354 #else
00355 #define UFUNC_NOFPE
00356 #endif
00357 #endif
00358 
00359 
00360 #ifdef __cplusplus
00361 }
00362 #endif
00363 #endif /* !Py_UFUNCOBJECT_H */