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 /* The most generic inner loop for a standard element-wise ufunc */
00011 typedef void (*PyUFuncGenericFunction)
00012             (char **args,
00013              npy_intp *dimensions,
00014              npy_intp *steps,
00015              void *innerloopdata);
00016 
00017 /*
00018  * The most generic inner loop for a masked standard element-wise ufunc.
00019  * The mask data and step is at args[narg] and steps[narg], after all
00020  * the operands.
00021  */
00022 typedef void (*PyUFuncGenericMaskedFunction)
00023             (char **args,
00024              npy_intp *dimensions,
00025              npy_intp *steps,
00026              NpyAuxData *innerloopdata);
00027 
00028 /* Forward declaration for the type resolution function */
00029 struct _tagPyUFuncObject;
00030 
00031 /*
00032  * Given the operands for calling a ufunc, should determine the
00033  * calculation input and output data types and return an inner loop function.
00034  * This function should validate that the casting rule is being followed,
00035  * and fail if it is not.
00036  *
00037  * For backwards compatibility, the regular type resolution function does not
00038  * support auxiliary data with object semantics. The type resolution call
00039  * which returns a masked generic function returns a standard NpyAuxData
00040  * object, for which the NPY_AUXDATA_FREE and NPY_AUXDATA_CLONE macros
00041  * work.
00042  *
00043  * ufunc:             The ufunc object.
00044  * casting:           The 'casting' parameter provided to the ufunc.
00045  * operands:          An array of length (ufunc->nin + ufunc->nout),
00046  *                    with the output parameters possibly NULL.
00047  * type_tup:          Either NULL, or the type_tup passed to the ufunc.
00048  * out_dtypes:        An array which should be populated with new
00049  *                    references to (ufunc->nin + ufunc->nout) new
00050  *                    dtypes, one for each input and output. These
00051  *                    dtypes should all be in native-endian format.
00052  * out_innerloop:     Should be populated with the correct ufunc inner
00053  *                    loop for the given type.
00054  * out_innerloopdata: Should be populated with the void* data to
00055  *                    be passed into the out_innerloop function.
00056  *
00057  * Should return 0 on success, -1 on failure (with exception set),
00058  * or -2 if Py_NotImplemented should be returned.
00059  */
00060 typedef int (PyUFunc_TypeResolutionFunc)(
00061                                 struct _tagPyUFuncObject *ufunc,
00062                                 NPY_CASTING casting,
00063                                 PyArrayObject **operands,
00064                                 PyObject *type_tup,
00065                                 PyArray_Descr **out_dtypes,
00066                                 PyUFuncGenericFunction *out_innerloop,
00067                                 void **out_innerloopdata);
00068 typedef int (PyUFunc_TypeResolutionMaskedFunc)(
00069                                 struct _tagPyUFuncObject *ufunc,
00070                                 NPY_CASTING casting,
00071                                 PyArrayObject **operands,
00072                                 PyObject *type_tup,
00073                                 PyArray_Descr **out_dtypes,
00074                                 PyUFuncGenericMaskedFunction *out_innerloop,
00075                                 NpyAuxData **out_innerloopdata);
00076 
00077 typedef struct _tagPyUFuncObject {
00078         PyObject_HEAD
00079         /*
00080          * nin: Number of inputs
00081          * nout: Number of outputs
00082          * nargs: Always nin + nout (Why is it stored?)
00083          */
00084         int nin, nout, nargs;
00085 
00086         /* Identity for reduction, either PyUFunc_One or PyUFunc_Zero */
00087         int identity;
00088 
00089         /* Array of one-dimensional core loops */
00090         PyUFuncGenericFunction *functions;
00091         /* Array of funcdata that gets passed into the functions */
00092         void **data;
00093         /* The number of elements in 'functions' and 'data' */
00094         int ntypes;
00095 
00096         /* Does not appear to be used */
00097         int check_return;
00098 
00099         /* The name of the ufunc */
00100         char *name;
00101 
00102         /* Array of type numbers, of size ('nargs' * 'ntypes') */
00103         char *types;
00104 
00105         /* Documentation string */
00106         char *doc;
00107 
00108         void *ptr;
00109         PyObject *obj;
00110         PyObject *userloops;
00111     
00112         /* generalized ufunc parameters */
00113 
00114         /* 0 for scalar ufunc; 1 for generalized ufunc */
00115         int core_enabled;
00116         /* number of distinct dimension names in signature */
00117         int core_num_dim_ix;
00118  
00119         /*
00120          * dimension indices of input/output argument k are stored in
00121          * core_dim_ixs[core_offsets[k]..core_offsets[k]+core_num_dims[k]-1]
00122          */
00123 
00124         /* numbers of core dimensions of each argument */
00125         int *core_num_dims;
00126         /*
00127          * dimension indices in a flatted form; indices
00128          * are in the range of [0,core_num_dim_ix)
00129          */
00130         int *core_dim_ixs;
00131         /*
00132          * positions of 1st core dimensions of each
00133          * argument in core_dim_ixs
00134          */
00135         int *core_offsets;
00136         /* signature string for printing purpose */
00137         char *core_signature;
00138 
00139         /*
00140          * A function which resolves the types and returns an inner loop.
00141          * This is used by the regular ufunc, the reduction operations
00142          * have a different set of rules.
00143          */
00144         PyUFunc_TypeResolutionFunc *type_resolution_function;
00145         /*
00146          * A function which resolves the types and returns an inner loop.
00147          * This is used by the regular ufunc when it requires using
00148          * a mask to select which elements to compute.
00149          */
00150         PyUFunc_TypeResolutionMaskedFunc *type_resolution_masked_function;
00151 } PyUFuncObject;
00152 
00153 #include "arrayobject.h"
00154 
00155 #define UFUNC_ERR_IGNORE 0
00156 #define UFUNC_ERR_WARN   1
00157 #define UFUNC_ERR_RAISE  2
00158 #define UFUNC_ERR_CALL   3
00159 #define UFUNC_ERR_PRINT  4
00160 #define UFUNC_ERR_LOG    5
00161 
00162         /* Python side integer mask */
00163 
00164 #define UFUNC_MASK_DIVIDEBYZERO 0x07
00165 #define UFUNC_MASK_OVERFLOW 0x3f
00166 #define UFUNC_MASK_UNDERFLOW 0x1ff
00167 #define UFUNC_MASK_INVALID 0xfff
00168 
00169 #define UFUNC_SHIFT_DIVIDEBYZERO 0
00170 #define UFUNC_SHIFT_OVERFLOW     3
00171 #define UFUNC_SHIFT_UNDERFLOW    6
00172 #define UFUNC_SHIFT_INVALID      9
00173 
00174 
00175 /* platform-dependent code translates floating point
00176    status to an integer sum of these values
00177 */
00178 #define UFUNC_FPE_DIVIDEBYZERO  1
00179 #define UFUNC_FPE_OVERFLOW      2
00180 #define UFUNC_FPE_UNDERFLOW     4
00181 #define UFUNC_FPE_INVALID       8
00182 
00183 /* Error mode that avoids look-up (no checking) */
00184 #define UFUNC_ERR_DEFAULT       0
00185 
00186 #define UFUNC_OBJ_ISOBJECT      1
00187 #define UFUNC_OBJ_NEEDS_API     2
00188 
00189    /* Default user error mode */
00190 #define UFUNC_ERR_DEFAULT2                               \
00191         (UFUNC_ERR_WARN << UFUNC_SHIFT_DIVIDEBYZERO) +  \
00192         (UFUNC_ERR_WARN << UFUNC_SHIFT_OVERFLOW) +      \
00193         (UFUNC_ERR_WARN << UFUNC_SHIFT_INVALID)
00194 
00195 #if NPY_ALLOW_THREADS
00196 #define NPY_LOOP_BEGIN_THREADS do {if (!(loop->obj & UFUNC_OBJ_NEEDS_API)) _save = PyEval_SaveThread();} while (0)
00197 #define NPY_LOOP_END_THREADS   do {if (!(loop->obj & UFUNC_OBJ_NEEDS_API)) PyEval_RestoreThread(_save);} while (0)
00198 #else
00199 #define NPY_LOOP_BEGIN_THREADS
00200 #define NPY_LOOP_END_THREADS
00201 #endif
00202 
00203 #define PyUFunc_One 1
00204 #define PyUFunc_Zero 0
00205 #define PyUFunc_None -1
00206 
00207 #define UFUNC_REDUCE 0
00208 #define UFUNC_ACCUMULATE 1
00209 #define UFUNC_REDUCEAT 2
00210 #define UFUNC_OUTER 3
00211 
00212 
00213 typedef struct {
00214         int nin;
00215         int nout;
00216         PyObject *callable;
00217 } PyUFunc_PyFuncData;
00218 
00219 /* A linked-list of function information for
00220    user-defined 1-d loops.
00221  */
00222 typedef struct _loop1d_info {
00223         PyUFuncGenericFunction func;
00224         void *data;
00225         int *arg_types;
00226         struct _loop1d_info *next;
00227 } PyUFunc_Loop1d;
00228 
00229 
00230 #include "__ufunc_api.h"
00231 
00232 #define UFUNC_PYVALS_NAME "UFUNC_PYVALS"
00233 
00234 #define UFUNC_CHECK_ERROR(arg)                                          \
00235         do {if ((((arg)->obj & UFUNC_OBJ_NEEDS_API) && PyErr_Occurred()) ||                         \
00236             ((arg)->errormask &&                                        \
00237              PyUFunc_checkfperr((arg)->errormask,                       \
00238                                 (arg)->errobj,                          \
00239                                 &(arg)->first)))                        \
00240                 goto fail;} while (0)
00241 
00242 /* This code checks the IEEE status flags in a platform-dependent way */
00243 /* Adapted from Numarray  */
00244 
00245 #if (defined(__unix__) || defined(unix)) && !defined(USG)
00246 #include <sys/param.h>
00247 #endif
00248 
00249 /*  OSF/Alpha (Tru64)  ---------------------------------------------*/
00250 #if defined(__osf__) && defined(__alpha)
00251 
00252 #include <machine/fpu.h>
00253 
00254 #define UFUNC_CHECK_STATUS(ret) {               \
00255         unsigned long fpstatus;                 \
00256                                                 \
00257         fpstatus = ieee_get_fp_control();                               \
00258         /* clear status bits as well as disable exception mode if on */ \
00259         ieee_set_fp_control( 0 );                                       \
00260         ret = ((IEEE_STATUS_DZE & fpstatus) ? UFUNC_FPE_DIVIDEBYZERO : 0) \
00261                 | ((IEEE_STATUS_OVF & fpstatus) ? UFUNC_FPE_OVERFLOW : 0) \
00262                 | ((IEEE_STATUS_UNF & fpstatus) ? UFUNC_FPE_UNDERFLOW : 0) \
00263                 | ((IEEE_STATUS_INV & fpstatus) ? UFUNC_FPE_INVALID : 0); \
00264         }
00265 
00266 /* MS Windows -----------------------------------------------------*/
00267 #elif defined(_MSC_VER)
00268 
00269 #include <float.h>
00270 
00271   /* Clear the floating point exception default of Borland C++ */
00272 #if defined(__BORLANDC__)
00273 #define UFUNC_NOFPE _control87(MCW_EM, MCW_EM);
00274 #endif
00275 
00276 #define UFUNC_CHECK_STATUS(ret) {                \
00277         int fpstatus = (int) _clearfp();                        \
00278                                                                         \
00279         ret = ((SW_ZERODIVIDE & fpstatus) ? UFUNC_FPE_DIVIDEBYZERO : 0) \
00280                 | ((SW_OVERFLOW & fpstatus) ? UFUNC_FPE_OVERFLOW : 0)   \
00281                 | ((SW_UNDERFLOW & fpstatus) ? UFUNC_FPE_UNDERFLOW : 0) \
00282                 | ((SW_INVALID & fpstatus) ? UFUNC_FPE_INVALID : 0);    \
00283         }
00284 
00285 /* Solaris --------------------------------------------------------*/
00286 /* --------ignoring SunOS ieee_flags approach, someone else can
00287 **         deal with that! */
00288 #elif defined(sun) || defined(__BSD__) || defined(__OpenBSD__) || \
00289       (defined(__FreeBSD__) && (__FreeBSD_version < 502114)) || \
00290       defined(__NetBSD__)
00291 #include <ieeefp.h>
00292 
00293 #define UFUNC_CHECK_STATUS(ret) {                               \
00294         int fpstatus;                                           \
00295                                                                 \
00296         fpstatus = (int) fpgetsticky();                                 \
00297         ret = ((FP_X_DZ  & fpstatus) ? UFUNC_FPE_DIVIDEBYZERO : 0)      \
00298                 | ((FP_X_OFL & fpstatus) ? UFUNC_FPE_OVERFLOW : 0)      \
00299                 | ((FP_X_UFL & fpstatus) ? UFUNC_FPE_UNDERFLOW : 0)     \
00300                 | ((FP_X_INV & fpstatus) ? UFUNC_FPE_INVALID : 0);      \
00301         (void) fpsetsticky(0);                                          \
00302         }
00303 
00304 #elif defined(__GLIBC__) || defined(__APPLE__) || \
00305       defined(__CYGWIN__) || defined(__MINGW32__) || \
00306       (defined(__FreeBSD__) && (__FreeBSD_version >= 502114))
00307 
00308 #if defined(__GLIBC__) || defined(__APPLE__) || \
00309     defined(__MINGW32__) || defined(__FreeBSD__)
00310 #include <fenv.h>
00311 #elif defined(__CYGWIN__)
00312 #include "fenv/fenv.c"
00313 #endif
00314 
00315 #define UFUNC_CHECK_STATUS(ret) {                                       \
00316         int fpstatus = (int) fetestexcept(FE_DIVBYZERO | FE_OVERFLOW |  \
00317                                           FE_UNDERFLOW | FE_INVALID);   \
00318         ret = ((FE_DIVBYZERO  & fpstatus) ? UFUNC_FPE_DIVIDEBYZERO : 0) \
00319                 | ((FE_OVERFLOW   & fpstatus) ? UFUNC_FPE_OVERFLOW : 0) \
00320                 | ((FE_UNDERFLOW  & fpstatus) ? UFUNC_FPE_UNDERFLOW : 0) \
00321                 | ((FE_INVALID    & fpstatus) ? UFUNC_FPE_INVALID : 0); \
00322         (void) feclearexcept(FE_DIVBYZERO | FE_OVERFLOW |               \
00323                              FE_UNDERFLOW | FE_INVALID);                \
00324 }
00325 
00326 #elif defined(_AIX)
00327 
00328 #include <float.h>
00329 #include <fpxcp.h>
00330 
00331 #define UFUNC_CHECK_STATUS(ret) { \
00332         fpflag_t fpstatus; \
00333  \
00334         fpstatus = fp_read_flag(); \
00335         ret = ((FP_DIV_BY_ZERO & fpstatus) ? UFUNC_FPE_DIVIDEBYZERO : 0) \
00336                 | ((FP_OVERFLOW & fpstatus) ? UFUNC_FPE_OVERFLOW : 0)   \
00337                 | ((FP_UNDERFLOW & fpstatus) ? UFUNC_FPE_UNDERFLOW : 0) \
00338                 | ((FP_INVALID & fpstatus) ? UFUNC_FPE_INVALID : 0); \
00339         fp_swap_flag(0); \
00340 }
00341 
00342 #else
00343 
00344 #define NO_FLOATING_POINT_SUPPORT
00345 #define UFUNC_CHECK_STATUS(ret) { \
00346     ret = 0; \
00347   }
00348 
00349 #endif
00350 
00351 /*
00352  * THESE MACROS ARE DEPRECATED.
00353  * Use npy_set_floatstatus_* in the npymath library.
00354  */
00355 #define generate_divbyzero_error() npy_set_floatstatus_divbyzero()
00356 #define generate_overflow_error() npy_set_floatstatus_overflow()
00357 
00358   /* Make sure it gets defined if it isn't already */
00359 #ifndef UFUNC_NOFPE
00360 #define UFUNC_NOFPE
00361 #endif
00362 
00363 
00364 #ifdef __cplusplus
00365 }
00366 #endif
00367 #endif /* !Py_UFUNCOBJECT_H */