UFUNC API

常量

UFUNC_ERR_{HANDLER}
UFUNC_ERR_IGNORE
UFUNC_ERR_WARN
UFUNC_ERR_RAISE
UFUNC_ERR_CALL
UFUNC_{THING}_{ERR}
UFUNC_MASK_DIVIDEBYZERO
UFUNC_MASK_OVERFLOW
UFUNC_MASK_UNDERFLOW
UFUNC_MASK_INVALID
UFUNC_SHIFT_DIVIDEBYZERO
UFUNC_SHIFT_OVERFLOW
UFUNC_SHIFT_UNDERFLOW
UFUNC_SHIFT_INVALID
UFUNC_FPE_DIVIDEBYZERO
UFUNC_FPE_OVERFLOW
UFUNC_FPE_UNDERFLOW
UFUNC_FPE_INVALID
PyUFunc_{VALUE}
PyUFunc_One
PyUFunc_Zero
PyUFunc_MinusOne
PyUFunc_ReorderableNone
PyUFunc_None
PyUFunc_IdentityValue

宏指令

NPY_LOOP_BEGIN_THREADS

在通用函数代码中使用,仅在loop->obj不为真时释放python gil( i.e. 这不是对象数组循环)。需要使用 NPY_BEGIN_THREADS_DEF 在变量声明区域中。

NPY_LOOP_END_THREADS

在通用函数代码中用于在释放python gil时重新获取它(因为loop->obj不是真的)。

类型

type PyUFuncGenericFunction

通过元素(指针)来实现函数 N 有以下签名的时间:

void loopfunc(char **args, npy_intp const *dimensions, npy_intp const *steps, void *data)

args

指向输入和输出数组的实际数据的指针数组。首先给出输入参数,然后给出输出参数。

尺寸

指向此函数循环所在维度的大小的指针。

步骤

对于每个输入和输出参数,指向要跳转到该维度下一个元素的字节数的指针。

data

任意数据(额外参数、函数名, etc. )它可以与ufunc一起存储,并在调用时传入。

这是一个func的例子,专门用于添加双打返回双打。

static void
double_add(char **args,
           npy_intp const *dimensions,
           npy_intp const *steps,
           void *extra)
{
    npy_intp i;
    npy_intp is1 = steps[0], is2 = steps[1];
    npy_intp os = steps[2], n = dimensions[0];
    char *i1 = args[0], *i2 = args[1], *op = args[2];
    for (i = 0; i < n; i++) {
        *((double *)op) = *((double *)i1) +
                          *((double *)i2);
        i1 += is1;
        i2 += is2;
        op += os;
     }
}

功能

PyObject *PyUFunc_FromFuncAndData(PyUFuncGenericFunction *func, void **data, char *types, int ntypes, int nin, int nout, int identity, char *name, char *doc, int unused)

从所需变量创建新的广播通用函数。每个ufunc都围绕一个元素一个元素操作的概念构建。每个UFUNC对象都包含指向1-D循环的指针,这些循环实现了每个支持类型的基本功能。

注解

这个 funcdata类型namedoc 参数未被复制 PyUFunc_FromFuncAndData . 调用方必须确保这些数组使用的内存不会被释放,只要ufunc对象是活动的。

参数
  • func -- 必须为长度数组 n型 包含 PyUFuncGenericFunction 项目。

  • data -- 应该是 NULL 或指向大小数组的指针 n型 . 此数组可能包含要传递给func数组中相应循环函数的任意额外数据。

  • types -- 长度 (nin + nout) * ntypes 数组 char 编码 numpy.dtype.num (仅内置)在 func 数组接受。例如,将ufunc与三个 ntypesnin 一个 nout ,其中第一个函数接受 numpy.int32 第二个呢 numpy.int64 ,两者都返回 numpy.bool_types 将是 (char[]) {{5, 5, 0, 7, 7, 0}} 自从 NPY_INT32 是5, NPY_INT64 是7, NPY_BOOL 是0。也可以使用位宽度名称(例如 NPY_INT32NPY_COMPLEX128 如果需要的话。 铸造规则 将在运行时用于查找第一个 func 可通过提供的输入/输出进行调用。

  • ntypes -- UFUNC实现了多少种不同的数据类型特定函数。

  • nin -- 此操作的输入数。

  • nout -- 输出的数量

  • identity -- 要么 PyUFunc_OnePyUFunc_ZeroPyUFunc_MinusOnePyUFunc_None . 这指定将空数组传递给ufunc的reduce方法时应返回的内容。特殊价值 PyUFunc_IdentityValue 只能用于 PyUFunc_FromFuncAndDataAndSignatureAndIdentity 方法,以允许将任意python对象用作标识。

  • name -- ufunc的名称作为 NULL 终止的字符串。如果指定“add”或“multiple”的名称,则在未指定任何数据类型时,可以为整数类型的缩减启用特殊的行为。如果输入类型是小于 numpy.int_ 数据类型,它将在内部向上转换为 numpy.int_ (或) numpy.uint )数据类型。

  • doc -- 允许传入要与ufunc一起存储的文档字符串。文档字符串不应包含函数名或调用签名,因为在访问 __doc__ ufunc的属性。

  • unused -- 为了C-API的向后兼容性而未使用和存在。

PyObject *PyUFunc_FromFuncAndDataAndSignature(PyUFuncGenericFunction *func, void **data, char *types, int ntypes, int nin, int nout, int identity, char *name, char *doc, int unused, char *signature)

此函数与上面的pyufunc_fromfuncddata非常相似,但有一个额外的 签名 参数,定义 generalized universal functions . 类似于UFunc是如何围绕一个元素一个元素的操作构建的,gufuncs是围绕一个元素一个元素一个元素的操作构建的。 signature 定义要操作的子数组。

参数
  • signature -- 新Gufunc的签名。将其设置为空相当于调用pyufunc_fromfuncddata。复制字符串,以便释放传入的缓冲区。

PyObject *PyUFunc_FromFuncAndDataAndSignatureAndIdentity(PyUFuncGenericFunction *func, void **data, char *types, int ntypes, int nin, int nout, int identity, char *name, char *doc, int unused, char *signature, PyObject *identity_value)

此函数与 PyUFunc_FromFuncAndDataAndSignature 上面,但有一个额外的 identity_value 参数,当 identity 传递为 PyUFunc_IdentityValue .

参数
  • identity_value -- 新Gufunc的身份。必须作为 NULL 除非 identity 论证是 PyUFunc_IdentityValue . 将其设置为空相当于调用pyufunc_FromFuncndDataAndSignature。

int PyUFunc_RegisterLoopForType(PyUFuncObject *ufunc, int usertype, PyUFuncGenericFunction function, int *arg_types, void *data)

此函数允许用户使用已创建的ufunc注册一维循环,以便在使用任何输入参数作为用户定义的数据类型调用ufunc时使用。这是为了让UFUNC与内置数据类型一起工作。数据类型必须已在numpy系统中注册。循环作为 功能 . 此循环可以接受任意数据,这些数据应作为 data . 循环所需的数据类型作为 arg_types 它必须是指向内存的指针,大小至少与ufunc->nargs相同。

int PyUFunc_RegisterLoopForDescr(PyUFuncObject *ufunc, PyArray_Descr *userdtype, PyUFuncGenericFunction function, PyArray_Descr **arg_dtypes, void *data)

此函数的行为类似于上面的pyufunc_registerloopfortype,但它允许用户使用pyarray_descr对象而不是d type type num值注册一维循环。这允许为结构化数组数据类型和自定义数据类型(而不是标量数据类型)注册一维循环。

int PyUFunc_ReplaceLoopBySignature(PyUFuncObject *ufunc, PyUFuncGenericFunction newfunc, int *signature, PyUFuncGenericFunction *oldfunc)

替换与给定值匹配的一维循环 签名 在已经创建的 ufunc 使用新的一维循环newfunc。返回旧的一维循环函数 奥尔德芬克 . 成功时返回0,失败时返回-1。此函数仅适用于内置类型(使用 PyUFunc_RegisterLoopForType 对于用户定义的类型)。签名是一个数据类型数字数组,指示输入,后跟一维循环假定的输出。

int PyUFunc_GenericFunction(PyUFuncObject *self, PyObject *args, PyObject *kwds, PyArrayObject **mps)

NumPy 版后已移除: 1.19

除非NumPy意识到此功能存在问题,否则此功能将按计划快速删除而不进行更换。

而不是这个函数 PyObject_Call(ufunc, args, kwds) 应该使用。上面的函数与此不同,因为它忽略了对非数组或数组子类作为输入的支持。为了确保相同的行为,可能需要使用 PyArray_FromAny(obj, NULL, 0, 0, NPY_ARRAY_ENSUREARRAY, NULL) .

int PyUFunc_checkfperr(int errmask, PyObject *errobj)

一个简单的接口到IEEE错误标志检查支持。这个 错误掩码 参数是的掩码 UFUNC_MASK_{{ERR}} 位掩码指示要检查的错误(以及如何检查错误)。这个 埃罗布吉 必须是一个包含两个元素的python元组:一个包含将在任何错误通信中使用的名称的字符串,以及一个可调用的python对象(回调函数)或 Py_None . 只有在以下情况下才使用可调用对象: UFUNC_ERR_CALL 设置为所需的错误检查方法。这个程序管理gil,即使在释放gil之后也可以安全地调用。如果确定IEEE兼容硬件中存在错误,则返回-1,否则返回0。

void PyUFunc_clearfperr()

清除IEEE错误标志。

void PyUFunc_GetPyValues(char *name, int *bufsize, int *errmask, PyObject **errobj)

从线程本地存储区域获取用于ufunc处理的python值,除非设置了默认值,在这种情况下,将忽略名称查找。名称作为字符串放在 *errobj . 第二个元素是在错误回调时调用的查找函数。将要使用的查找缓冲区大小的值传递给 蟾蜍尺码 ,并将错误掩码的值放入 错误掩码 .

通用函数

每个ufunc的核心是一组特定于类型的函数,这些函数定义了每个支持类型的基本功能。这些函数必须计算基础函数 N\geq1 时代。在计算过程中可能会用到额外的数据。此功能允许将一些常规函数用作这些基本循环函数。通用函数具有将变量指向正确位置并设置函数调用所需的所有代码。常规函数假定要调用的实际函数作为额外数据传入,并使用正确的值调用它。所有这些函数都适用于直接放置在pyufunobject结构的函数成员中存储的函数数组中。

void PyUFunc_f_f_As_d_d(char **args, npy_intp const *dimensions, npy_intp const *steps, void *func)
void PyUFunc_d_d(char **args, npy_intp const *dimensions, npy_intp const *steps, void *func)
void PyUFunc_f_f(char **args, npy_intp const *dimensions, npy_intp const *steps, void *func)
void PyUFunc_g_g(char **args, npy_intp const *dimensions, npy_intp const *steps, void *func)
void PyUFunc_F_F_As_D_D(char **args, npy_intp const *dimensions, npy_intp const *steps, void *func)
void PyUFunc_F_F(char **args, npy_intp const *dimensions, npy_intp const *steps, void *func)
void PyUFunc_D_D(char **args, npy_intp const *dimensions, npy_intp const *steps, void *func)
void PyUFunc_G_G(char **args, npy_intp const *dimensions, npy_intp const *steps, void *func)
void PyUFunc_e_e(char **args, npy_intp const *dimensions, npy_intp const *steps, void *func)
void PyUFunc_e_e_As_f_f(char **args, npy_intp const *dimensions, npy_intp const *steps, void *func)
void PyUFunc_e_e_As_d_d(char **args, npy_intp const *dimensions, npy_intp const *steps, void *func)

UFUNC的类型特定的核心一维函数,通过调用一个接受一个输入参数并返回一个输出的函数来获得每个计算。此函数已传入 func . 字母对应于支持的数据类型的dtypechar( e 一半, f -浮动, d -双, g -长双倍, F -cFLASH, D -Couple, G -克隆双)。参数 func 必须支持相同的签名。_as_x_x变量假定Ndarray是一种数据类型,但将值强制转换为使用具有不同数据类型的基础函数。因此, PyUFunc_f_f_As_d_d 使用数据类型的ndarrays NPY_FLOAT 但调用一个接受double并返回double的C函数。

void PyUFunc_ff_f_As_dd_d(char **args, npy_intp const *dimensions, npy_intp const *steps, void *func)
void PyUFunc_ff_f(char **args, npy_intp const *dimensions, npy_intp const *steps, void *func)
void PyUFunc_dd_d(char **args, npy_intp const *dimensions, npy_intp const *steps, void *func)
void PyUFunc_gg_g(char **args, npy_intp const *dimensions, npy_intp const *steps, void *func)
void PyUFunc_FF_F_As_DD_D(char **args, npy_intp const *dimensions, npy_intp const *steps, void *func)
void PyUFunc_DD_D(char **args, npy_intp const *dimensions, npy_intp const *steps, void *func)
void PyUFunc_FF_F(char **args, npy_intp const *dimensions, npy_intp const *steps, void *func)
void PyUFunc_GG_G(char **args, npy_intp const *dimensions, npy_intp const *steps, void *func)
void PyUFunc_ee_e(char **args, npy_intp const *dimensions, npy_intp const *steps, void *func)
void PyUFunc_ee_e_As_ff_f(char **args, npy_intp const *dimensions, npy_intp const *steps, void *func)
void PyUFunc_ee_e_As_dd_d(char **args, npy_intp const *dimensions, npy_intp const *steps, void *func)

UFUNC的类型特定的核心一维函数,其中每个计算通过调用一个接受两个输入参数并返回一个输出的函数来获得。要调用的基础函数作为 func . 字母对应于通用函数支持的特定数据类型的DTypechar。参数 func 必须支持相应的签名。这个 _As_XX_X 变量假定一个数据类型的ndarrays,但在循环的每个迭代中强制转换值,以使用采用不同数据类型的基础函数。

void PyUFunc_O_O(char **args, npy_intp const *dimensions, npy_intp const *steps, void *func)
void PyUFunc_OO_O(char **args, npy_intp const *dimensions, npy_intp const *steps, void *func)

一个输入、一个输出和两个输入、一个输出核心的一维函数 NPY_OBJECT 数据类型。这些函数处理引用计数问题,并在出错时提前返回。要调用的实际函数是 func 它必须接受有签名的电话 (PyObject*) (PyObject*) 对于 PyUFunc_O_O(PyObject*)(PyObject *, PyObject *) 对于 PyUFunc_OO_O .

void PyUFunc_O_O_method(char **args, npy_intp const *dimensions, npy_intp const *steps, void *func)

这个通用的一维核心函数假定 func 是表示输入对象的方法的字符串。对于循环的每次迭代,都会从数组及其 func 调用方法,将结果返回到输出数组。

void PyUFunc_OO_O_method(char **args, npy_intp const *dimensions, npy_intp const *steps, void *func)

这个通用的一维核心函数假定 func 表示接受一个参数的输入对象的方法的字符串。中的第一个论点 args 是其函数被调用的方法,是中的第二个参数 args 是传递给函数的参数。函数的输出存储在 args .

void PyUFunc_On_Om(char **args, npy_intp const *dimensions, npy_intp const *steps, void *func)

这是umath.frompyfunc(函数,nin,nout)创建的动态ufunc使用的一维核心函数。在这种情况下 func 是指向 PyUFunc_PyFuncData 具有定义的结构

type PyUFunc_PyFuncData
typedef struct {
    int nin;
    int nout;
    PyObject *callable;
} PyUFunc_PyFuncData;

在循环的每个迭代中, nin 输入对象从它们的对象数组中提取出来并放入参数元组python中。 可赎回的 使用输入参数调用,并将nout输出放入其对象数组中。

导入API

PY_UFUNC_UNIQUE_SYMBOL
NO_IMPORT_UFUNC
void import_ufunc(void)

这些是用于从扩展模块访问ufunc c-api的常量和函数,与访问数组c-api的方式完全相同。这个 import_ufunc 必须始终调用()函数(在扩展模块的初始化子例程中)。如果扩展模块在一个文件中,那么这就是所需的全部内容。如果扩展模块使用多个文件,则其他两个常量非常有用。在这种情况下,定义 PY_UFUNC_UNIQUE_SYMBOL 对于代码和源文件中不包含模块初始化功能但仍需要访问ufunc api的唯一内容,请定义 PY_UFUNC_UNIQUE_SYMBOL 与以前使用的名称相同,并且还定义 NO_IMPORT_UFUNC .

C-API实际上是一个函数指针数组。此数组由import-ufunc创建(并由全局变量指向)。全局变量要么静态定义,要么允许其他文件查看,具体取决于 PY_UFUNC_UNIQUE_SYMBOLNO_IMPORT_UFUNC .