mirror of https://github.com/explosion/spaCy.git
447 lines
15 KiB
C
447 lines
15 KiB
C
#ifndef Py_UFUNCOBJECT_H
|
|
#define Py_UFUNCOBJECT_H
|
|
|
|
#include <numpy/npy_math.h>
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
/*
|
|
* The legacy generic inner loop for a standard element-wise or
|
|
* generalized ufunc.
|
|
*/
|
|
typedef void (*PyUFuncGenericFunction)
|
|
(char **args,
|
|
npy_intp *dimensions,
|
|
npy_intp *strides,
|
|
void *innerloopdata);
|
|
|
|
/*
|
|
* The most generic one-dimensional inner loop for
|
|
* a standard element-wise ufunc. This typedef is also
|
|
* more consistent with the other NumPy function pointer typedefs
|
|
* than PyUFuncGenericFunction.
|
|
*/
|
|
typedef void (PyUFunc_StridedInnerLoopFunc)(
|
|
char **dataptrs, npy_intp *strides,
|
|
npy_intp count,
|
|
NpyAuxData *innerloopdata);
|
|
|
|
/*
|
|
* The most generic one-dimensional inner loop for
|
|
* a masked standard element-wise ufunc. "Masked" here means that it skips
|
|
* doing calculations on any items for which the maskptr array has a true
|
|
* value.
|
|
*/
|
|
typedef void (PyUFunc_MaskedStridedInnerLoopFunc)(
|
|
char **dataptrs, npy_intp *strides,
|
|
char *maskptr, npy_intp mask_stride,
|
|
npy_intp count,
|
|
NpyAuxData *innerloopdata);
|
|
|
|
/* Forward declaration for the type resolver and loop selector typedefs */
|
|
struct _tagPyUFuncObject;
|
|
|
|
/*
|
|
* Given the operands for calling a ufunc, should determine the
|
|
* calculation input and output data types and return an inner loop function.
|
|
* This function should validate that the casting rule is being followed,
|
|
* and fail if it is not.
|
|
*
|
|
* For backwards compatibility, the regular type resolution function does not
|
|
* support auxiliary data with object semantics. The type resolution call
|
|
* which returns a masked generic function returns a standard NpyAuxData
|
|
* object, for which the NPY_AUXDATA_FREE and NPY_AUXDATA_CLONE macros
|
|
* work.
|
|
*
|
|
* ufunc: The ufunc object.
|
|
* casting: The 'casting' parameter provided to the ufunc.
|
|
* operands: An array of length (ufunc->nin + ufunc->nout),
|
|
* with the output parameters possibly NULL.
|
|
* type_tup: Either NULL, or the type_tup passed to the ufunc.
|
|
* out_dtypes: An array which should be populated with new
|
|
* references to (ufunc->nin + ufunc->nout) new
|
|
* dtypes, one for each input and output. These
|
|
* dtypes should all be in native-endian format.
|
|
*
|
|
* Should return 0 on success, -1 on failure (with exception set),
|
|
* or -2 if Py_NotImplemented should be returned.
|
|
*/
|
|
typedef int (PyUFunc_TypeResolutionFunc)(
|
|
struct _tagPyUFuncObject *ufunc,
|
|
NPY_CASTING casting,
|
|
PyArrayObject **operands,
|
|
PyObject *type_tup,
|
|
PyArray_Descr **out_dtypes);
|
|
|
|
/*
|
|
* Given an array of DTypes as returned by the PyUFunc_TypeResolutionFunc,
|
|
* and an array of fixed strides (the array will contain NPY_MAX_INTP for
|
|
* strides which are not necessarily fixed), returns an inner loop
|
|
* with associated auxiliary data.
|
|
*
|
|
* For backwards compatibility, there is a variant of the inner loop
|
|
* selection which returns an inner loop irrespective of the strides,
|
|
* and with a void* static auxiliary data instead of an NpyAuxData *
|
|
* dynamically allocatable auxiliary data.
|
|
*
|
|
* ufunc: The ufunc object.
|
|
* dtypes: An array which has been populated with dtypes,
|
|
* in most cases by the type resolution funciton
|
|
* for the same ufunc.
|
|
* fixed_strides: For each input/output, either the stride that
|
|
* will be used every time the function is called
|
|
* or NPY_MAX_INTP if the stride might change or
|
|
* is not known ahead of time. The loop selection
|
|
* function may use this stride to pick inner loops
|
|
* which are optimized for contiguous or 0-stride
|
|
* cases.
|
|
* out_innerloop: Should be populated with the correct ufunc inner
|
|
* loop for the given type.
|
|
* out_innerloopdata: Should be populated with the void* data to
|
|
* be passed into the out_innerloop function.
|
|
* out_needs_api: If the inner loop needs to use the Python API,
|
|
* should set the to 1, otherwise should leave
|
|
* this untouched.
|
|
*/
|
|
typedef int (PyUFunc_LegacyInnerLoopSelectionFunc)(
|
|
struct _tagPyUFuncObject *ufunc,
|
|
PyArray_Descr **dtypes,
|
|
PyUFuncGenericFunction *out_innerloop,
|
|
void **out_innerloopdata,
|
|
int *out_needs_api);
|
|
typedef int (PyUFunc_InnerLoopSelectionFunc)(
|
|
struct _tagPyUFuncObject *ufunc,
|
|
PyArray_Descr **dtypes,
|
|
npy_intp *fixed_strides,
|
|
PyUFunc_StridedInnerLoopFunc **out_innerloop,
|
|
NpyAuxData **out_innerloopdata,
|
|
int *out_needs_api);
|
|
typedef int (PyUFunc_MaskedInnerLoopSelectionFunc)(
|
|
struct _tagPyUFuncObject *ufunc,
|
|
PyArray_Descr **dtypes,
|
|
PyArray_Descr *mask_dtype,
|
|
npy_intp *fixed_strides,
|
|
npy_intp fixed_mask_stride,
|
|
PyUFunc_MaskedStridedInnerLoopFunc **out_innerloop,
|
|
NpyAuxData **out_innerloopdata,
|
|
int *out_needs_api);
|
|
|
|
typedef struct _tagPyUFuncObject {
|
|
PyObject_HEAD
|
|
/*
|
|
* nin: Number of inputs
|
|
* nout: Number of outputs
|
|
* nargs: Always nin + nout (Why is it stored?)
|
|
*/
|
|
int nin, nout, nargs;
|
|
|
|
/* Identity for reduction, either PyUFunc_One or PyUFunc_Zero */
|
|
int identity;
|
|
|
|
/* Array of one-dimensional core loops */
|
|
PyUFuncGenericFunction *functions;
|
|
/* Array of funcdata that gets passed into the functions */
|
|
void **data;
|
|
/* The number of elements in 'functions' and 'data' */
|
|
int ntypes;
|
|
|
|
/* Does not appear to be used */
|
|
int check_return;
|
|
|
|
/* The name of the ufunc */
|
|
char *name;
|
|
|
|
/* Array of type numbers, of size ('nargs' * 'ntypes') */
|
|
char *types;
|
|
|
|
/* Documentation string */
|
|
char *doc;
|
|
|
|
void *ptr;
|
|
PyObject *obj;
|
|
PyObject *userloops;
|
|
|
|
/* generalized ufunc parameters */
|
|
|
|
/* 0 for scalar ufunc; 1 for generalized ufunc */
|
|
int core_enabled;
|
|
/* number of distinct dimension names in signature */
|
|
int core_num_dim_ix;
|
|
|
|
/*
|
|
* dimension indices of input/output argument k are stored in
|
|
* core_dim_ixs[core_offsets[k]..core_offsets[k]+core_num_dims[k]-1]
|
|
*/
|
|
|
|
/* numbers of core dimensions of each argument */
|
|
int *core_num_dims;
|
|
/*
|
|
* dimension indices in a flatted form; indices
|
|
* are in the range of [0,core_num_dim_ix)
|
|
*/
|
|
int *core_dim_ixs;
|
|
/*
|
|
* positions of 1st core dimensions of each
|
|
* argument in core_dim_ixs
|
|
*/
|
|
int *core_offsets;
|
|
/* signature string for printing purpose */
|
|
char *core_signature;
|
|
|
|
/*
|
|
* A function which resolves the types and fills an array
|
|
* with the dtypes for the inputs and outputs.
|
|
*/
|
|
PyUFunc_TypeResolutionFunc *type_resolver;
|
|
/*
|
|
* A function which returns an inner loop written for
|
|
* NumPy 1.6 and earlier ufuncs. This is for backwards
|
|
* compatibility, and may be NULL if inner_loop_selector
|
|
* is specified.
|
|
*/
|
|
PyUFunc_LegacyInnerLoopSelectionFunc *legacy_inner_loop_selector;
|
|
/*
|
|
* A function which returns an inner loop for the new mechanism
|
|
* in NumPy 1.7 and later. If provided, this is used, otherwise
|
|
* if NULL the legacy_inner_loop_selector is used instead.
|
|
*/
|
|
PyUFunc_InnerLoopSelectionFunc *inner_loop_selector;
|
|
/*
|
|
* A function which returns a masked inner loop for the ufunc.
|
|
*/
|
|
PyUFunc_MaskedInnerLoopSelectionFunc *masked_inner_loop_selector;
|
|
} PyUFuncObject;
|
|
|
|
#include "arrayobject.h"
|
|
|
|
#define UFUNC_ERR_IGNORE 0
|
|
#define UFUNC_ERR_WARN 1
|
|
#define UFUNC_ERR_RAISE 2
|
|
#define UFUNC_ERR_CALL 3
|
|
#define UFUNC_ERR_PRINT 4
|
|
#define UFUNC_ERR_LOG 5
|
|
|
|
/* Python side integer mask */
|
|
|
|
#define UFUNC_MASK_DIVIDEBYZERO 0x07
|
|
#define UFUNC_MASK_OVERFLOW 0x3f
|
|
#define UFUNC_MASK_UNDERFLOW 0x1ff
|
|
#define UFUNC_MASK_INVALID 0xfff
|
|
|
|
#define UFUNC_SHIFT_DIVIDEBYZERO 0
|
|
#define UFUNC_SHIFT_OVERFLOW 3
|
|
#define UFUNC_SHIFT_UNDERFLOW 6
|
|
#define UFUNC_SHIFT_INVALID 9
|
|
|
|
|
|
/* platform-dependent code translates floating point
|
|
status to an integer sum of these values
|
|
*/
|
|
#define UFUNC_FPE_DIVIDEBYZERO 1
|
|
#define UFUNC_FPE_OVERFLOW 2
|
|
#define UFUNC_FPE_UNDERFLOW 4
|
|
#define UFUNC_FPE_INVALID 8
|
|
|
|
/* Error mode that avoids look-up (no checking) */
|
|
#define UFUNC_ERR_DEFAULT 0
|
|
|
|
#define UFUNC_OBJ_ISOBJECT 1
|
|
#define UFUNC_OBJ_NEEDS_API 2
|
|
|
|
/* Default user error mode */
|
|
#define UFUNC_ERR_DEFAULT2 \
|
|
(UFUNC_ERR_WARN << UFUNC_SHIFT_DIVIDEBYZERO) + \
|
|
(UFUNC_ERR_WARN << UFUNC_SHIFT_OVERFLOW) + \
|
|
(UFUNC_ERR_WARN << UFUNC_SHIFT_INVALID)
|
|
|
|
#if NPY_ALLOW_THREADS
|
|
#define NPY_LOOP_BEGIN_THREADS do {if (!(loop->obj & UFUNC_OBJ_NEEDS_API)) _save = PyEval_SaveThread();} while (0);
|
|
#define NPY_LOOP_END_THREADS do {if (!(loop->obj & UFUNC_OBJ_NEEDS_API)) PyEval_RestoreThread(_save);} while (0);
|
|
#else
|
|
#define NPY_LOOP_BEGIN_THREADS
|
|
#define NPY_LOOP_END_THREADS
|
|
#endif
|
|
|
|
/*
|
|
* UFunc has unit of 1, and the order of operations can be reordered
|
|
* This case allows reduction with multiple axes at once.
|
|
*/
|
|
#define PyUFunc_One 1
|
|
/*
|
|
* UFunc has unit of 0, and the order of operations can be reordered
|
|
* This case allows reduction with multiple axes at once.
|
|
*/
|
|
#define PyUFunc_Zero 0
|
|
/*
|
|
* UFunc has no unit, and the order of operations cannot be reordered.
|
|
* This case does not allow reduction with multiple axes at once.
|
|
*/
|
|
#define PyUFunc_None -1
|
|
/*
|
|
* UFunc has no unit, and the order of operations can be reordered
|
|
* This case allows reduction with multiple axes at once.
|
|
*/
|
|
#define PyUFunc_ReorderableNone -2
|
|
|
|
#define UFUNC_REDUCE 0
|
|
#define UFUNC_ACCUMULATE 1
|
|
#define UFUNC_REDUCEAT 2
|
|
#define UFUNC_OUTER 3
|
|
|
|
|
|
typedef struct {
|
|
int nin;
|
|
int nout;
|
|
PyObject *callable;
|
|
} PyUFunc_PyFuncData;
|
|
|
|
/* A linked-list of function information for
|
|
user-defined 1-d loops.
|
|
*/
|
|
typedef struct _loop1d_info {
|
|
PyUFuncGenericFunction func;
|
|
void *data;
|
|
int *arg_types;
|
|
struct _loop1d_info *next;
|
|
} PyUFunc_Loop1d;
|
|
|
|
|
|
#include "__ufunc_api.h"
|
|
|
|
#define UFUNC_PYVALS_NAME "UFUNC_PYVALS"
|
|
|
|
#define UFUNC_CHECK_ERROR(arg) \
|
|
do {if ((((arg)->obj & UFUNC_OBJ_NEEDS_API) && PyErr_Occurred()) || \
|
|
((arg)->errormask && \
|
|
PyUFunc_checkfperr((arg)->errormask, \
|
|
(arg)->errobj, \
|
|
&(arg)->first))) \
|
|
goto fail;} while (0)
|
|
|
|
/* This code checks the IEEE status flags in a platform-dependent way */
|
|
/* Adapted from Numarray */
|
|
|
|
#if (defined(__unix__) || defined(unix)) && !defined(USG)
|
|
#include <sys/param.h>
|
|
#endif
|
|
|
|
/* OSF/Alpha (Tru64) ---------------------------------------------*/
|
|
#if defined(__osf__) && defined(__alpha)
|
|
|
|
#include <machine/fpu.h>
|
|
|
|
#define UFUNC_CHECK_STATUS(ret) { \
|
|
unsigned long fpstatus; \
|
|
\
|
|
fpstatus = ieee_get_fp_control(); \
|
|
/* clear status bits as well as disable exception mode if on */ \
|
|
ieee_set_fp_control( 0 ); \
|
|
ret = ((IEEE_STATUS_DZE & fpstatus) ? UFUNC_FPE_DIVIDEBYZERO : 0) \
|
|
| ((IEEE_STATUS_OVF & fpstatus) ? UFUNC_FPE_OVERFLOW : 0) \
|
|
| ((IEEE_STATUS_UNF & fpstatus) ? UFUNC_FPE_UNDERFLOW : 0) \
|
|
| ((IEEE_STATUS_INV & fpstatus) ? UFUNC_FPE_INVALID : 0); \
|
|
}
|
|
|
|
/* MS Windows -----------------------------------------------------*/
|
|
#elif defined(_MSC_VER)
|
|
|
|
#include <float.h>
|
|
|
|
/* Clear the floating point exception default of Borland C++ */
|
|
#if defined(__BORLANDC__)
|
|
#define UFUNC_NOFPE _control87(MCW_EM, MCW_EM);
|
|
#endif
|
|
|
|
#define UFUNC_CHECK_STATUS(ret) { \
|
|
int fpstatus = (int) _clearfp(); \
|
|
\
|
|
ret = ((SW_ZERODIVIDE & fpstatus) ? UFUNC_FPE_DIVIDEBYZERO : 0) \
|
|
| ((SW_OVERFLOW & fpstatus) ? UFUNC_FPE_OVERFLOW : 0) \
|
|
| ((SW_UNDERFLOW & fpstatus) ? UFUNC_FPE_UNDERFLOW : 0) \
|
|
| ((SW_INVALID & fpstatus) ? UFUNC_FPE_INVALID : 0); \
|
|
}
|
|
|
|
/* Solaris --------------------------------------------------------*/
|
|
/* --------ignoring SunOS ieee_flags approach, someone else can
|
|
** deal with that! */
|
|
#elif defined(sun) || defined(__BSD__) || defined(__OpenBSD__) || \
|
|
(defined(__FreeBSD__) && (__FreeBSD_version < 502114)) || \
|
|
defined(__NetBSD__)
|
|
#include <ieeefp.h>
|
|
|
|
#define UFUNC_CHECK_STATUS(ret) { \
|
|
int fpstatus; \
|
|
\
|
|
fpstatus = (int) fpgetsticky(); \
|
|
ret = ((FP_X_DZ & fpstatus) ? UFUNC_FPE_DIVIDEBYZERO : 0) \
|
|
| ((FP_X_OFL & fpstatus) ? UFUNC_FPE_OVERFLOW : 0) \
|
|
| ((FP_X_UFL & fpstatus) ? UFUNC_FPE_UNDERFLOW : 0) \
|
|
| ((FP_X_INV & fpstatus) ? UFUNC_FPE_INVALID : 0); \
|
|
(void) fpsetsticky(0); \
|
|
}
|
|
|
|
#elif defined(__GLIBC__) || defined(__APPLE__) || \
|
|
defined(__CYGWIN__) || defined(__MINGW32__) || \
|
|
(defined(__FreeBSD__) && (__FreeBSD_version >= 502114))
|
|
|
|
#if defined(__GLIBC__) || defined(__APPLE__) || \
|
|
defined(__MINGW32__) || defined(__FreeBSD__)
|
|
#include <fenv.h>
|
|
#endif
|
|
|
|
#define UFUNC_CHECK_STATUS(ret) { \
|
|
int fpstatus = (int) fetestexcept(FE_DIVBYZERO | FE_OVERFLOW | \
|
|
FE_UNDERFLOW | FE_INVALID); \
|
|
ret = ((FE_DIVBYZERO & fpstatus) ? UFUNC_FPE_DIVIDEBYZERO : 0) \
|
|
| ((FE_OVERFLOW & fpstatus) ? UFUNC_FPE_OVERFLOW : 0) \
|
|
| ((FE_UNDERFLOW & fpstatus) ? UFUNC_FPE_UNDERFLOW : 0) \
|
|
| ((FE_INVALID & fpstatus) ? UFUNC_FPE_INVALID : 0); \
|
|
(void) feclearexcept(FE_DIVBYZERO | FE_OVERFLOW | \
|
|
FE_UNDERFLOW | FE_INVALID); \
|
|
}
|
|
|
|
#elif defined(_AIX)
|
|
|
|
#include <float.h>
|
|
#include <fpxcp.h>
|
|
|
|
#define UFUNC_CHECK_STATUS(ret) { \
|
|
fpflag_t fpstatus; \
|
|
\
|
|
fpstatus = fp_read_flag(); \
|
|
ret = ((FP_DIV_BY_ZERO & fpstatus) ? UFUNC_FPE_DIVIDEBYZERO : 0) \
|
|
| ((FP_OVERFLOW & fpstatus) ? UFUNC_FPE_OVERFLOW : 0) \
|
|
| ((FP_UNDERFLOW & fpstatus) ? UFUNC_FPE_UNDERFLOW : 0) \
|
|
| ((FP_INVALID & fpstatus) ? UFUNC_FPE_INVALID : 0); \
|
|
fp_swap_flag(0); \
|
|
}
|
|
|
|
#else
|
|
|
|
#define NO_FLOATING_POINT_SUPPORT
|
|
#define UFUNC_CHECK_STATUS(ret) { \
|
|
ret = 0; \
|
|
}
|
|
|
|
#endif
|
|
|
|
/*
|
|
* THESE MACROS ARE DEPRECATED.
|
|
* Use npy_set_floatstatus_* in the npymath library.
|
|
*/
|
|
#define generate_divbyzero_error() npy_set_floatstatus_divbyzero()
|
|
#define generate_overflow_error() npy_set_floatstatus_overflow()
|
|
|
|
/* Make sure it gets defined if it isn't already */
|
|
#ifndef UFUNC_NOFPE
|
|
#define UFUNC_NOFPE
|
|
#endif
|
|
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
#endif /* !Py_UFUNCOBJECT_H */
|