summaryrefslogtreecommitdiff
path: root/numpy
diff options
context:
space:
mode:
Diffstat (limited to 'numpy')
-rw-r--r--numpy/core/SConscript1
-rw-r--r--numpy/core/code_generators/genapi.py1
-rw-r--r--numpy/core/setup.py3
-rw-r--r--numpy/core/src/umath/loops.c.src320
-rw-r--r--numpy/core/src/umath/ufunc_object.c2015
-rw-r--r--numpy/core/src/umath/ufunc_object.h80
-rw-r--r--numpy/core/src/umath/ufunc_type_resolution.c2012
-rw-r--r--numpy/core/src/umath/ufunc_type_resolution.h116
-rw-r--r--numpy/core/src/umath/umathmodule.c.src1
-rw-r--r--numpy/core/src/umath/umathmodule_onefile.c1
10 files changed, 2294 insertions, 2256 deletions
diff --git a/numpy/core/SConscript b/numpy/core/SConscript
index 55330a609..ca630254e 100644
--- a/numpy/core/SConscript
+++ b/numpy/core/SConscript
@@ -488,6 +488,7 @@ env.DistutilsPythonExtension('multiarray_tests', source=multiarray_tests_src)
#-------------------
if ENABLE_SEPARATE_COMPILATION:
umathmodule_src.extend([pjoin('src', 'umath', 'ufunc_object.c')])
+ umathmodule_src.extend([pjoin('src', 'umath', 'ufunc_type_resolution.c')])
umathmodule_src.extend(umath_loops_src)
else:
umathmodule_src = [pjoin('src', 'umath', 'umathmodule_onefile.c')]
diff --git a/numpy/core/code_generators/genapi.py b/numpy/core/code_generators/genapi.py
index f69424d31..b4d651b1d 100644
--- a/numpy/core/code_generators/genapi.py
+++ b/numpy/core/code_generators/genapi.py
@@ -51,6 +51,7 @@ API_FILES = [join('multiarray', 'methods.c'),
join('multiarray', 'nditer_pywrap.c'),
join('multiarray', 'einsum.c.src'),
join('umath', 'ufunc_object.c'),
+ join('umath', 'ufunc_type_resolution.c'),
join('umath', 'loops.c.src'),
]
THIS_DIR = os.path.dirname(__file__)
diff --git a/numpy/core/setup.py b/numpy/core/setup.py
index b0984dc5c..80f84d29f 100644
--- a/numpy/core/setup.py
+++ b/numpy/core/setup.py
@@ -822,7 +822,8 @@ def configuration(parent_package='',top_path=None):
join('src', 'umath', 'umathmodule.c.src'),
join('src', 'umath', 'funcs.inc.src'),
join('src', 'umath', 'loops.c.src'),
- join('src', 'umath', 'ufunc_object.c')]
+ join('src', 'umath', 'ufunc_object.c'),
+ join('src', 'umath', 'ufunc_type_resolution.c')]
umath_deps = [
generate_umath_py,
diff --git a/numpy/core/src/umath/loops.c.src b/numpy/core/src/umath/loops.c.src
index 8f86391ff..e85b24c42 100644
--- a/numpy/core/src/umath/loops.c.src
+++ b/numpy/core/src/umath/loops.c.src
@@ -33,37 +33,37 @@
#define OUTPUT_LOOP\
char *op1 = args[1];\
- intp os1 = steps[1];\
- intp n = dimensions[0];\
- intp i;\
+ npy_intp os1 = steps[1];\
+ npy_intp n = dimensions[0];\
+ npy_intp i;\
for(i = 0; i < n; i++, op1 += os1)
#define UNARY_LOOP\
char *ip1 = args[0], *op1 = args[1];\
- intp is1 = steps[0], os1 = steps[1];\
- intp n = dimensions[0];\
- intp i;\
+ npy_intp is1 = steps[0], os1 = steps[1];\
+ npy_intp n = dimensions[0];\
+ npy_intp i;\
for(i = 0; i < n; i++, ip1 += is1, op1 += os1)
#define UNARY_LOOP_TWO_OUT\
char *ip1 = args[0], *op1 = args[1], *op2 = args[2];\
- intp is1 = steps[0], os1 = steps[1], os2 = steps[2];\
- intp n = dimensions[0];\
- intp i;\
+ npy_intp is1 = steps[0], os1 = steps[1], os2 = steps[2];\
+ npy_intp n = dimensions[0];\
+ npy_intp i;\
for(i = 0; i < n; i++, ip1 += is1, op1 += os1, op2 += os2)
#define BINARY_LOOP\
char *ip1 = args[0], *ip2 = args[1], *op1 = args[2];\
- intp is1 = steps[0], is2 = steps[1], os1 = steps[2];\
- intp n = dimensions[0];\
- intp i;\
+ npy_intp is1 = steps[0], is2 = steps[1], os1 = steps[2];\
+ npy_intp n = dimensions[0];\
+ npy_intp i;\
for(i = 0; i < n; i++, ip1 += is1, ip2 += is2, op1 += os1)
#define BINARY_REDUCE_LOOP_INNER\
char *ip2 = args[1]; \
- intp is2 = steps[1]; \
- intp n = dimensions[0]; \
- intp i; \
+ npy_intp is2 = steps[1]; \
+ npy_intp n = dimensions[0]; \
+ npy_intp i; \
for(i = 0; i < n; i++, ip2 += is2)
#define BINARY_REDUCE_LOOP(TYPE)\
@@ -73,9 +73,9 @@
#define BINARY_LOOP_TWO_OUT\
char *ip1 = args[0], *ip2 = args[1], *op1 = args[2], *op2 = args[3];\
- intp is1 = steps[0], is2 = steps[1], os1 = steps[2], os2 = steps[3];\
- intp n = dimensions[0];\
- intp i;\
+ npy_intp is1 = steps[0], is2 = steps[1], os1 = steps[2], os2 = steps[3];\
+ npy_intp n = dimensions[0];\
+ npy_intp i;\
for(i = 0; i < n; i++, ip1 += is1, ip2 += is2, op1 += os1, op2 += os2)
/******************************************************************************
@@ -95,7 +95,7 @@ typedef longdouble longdoubleBinaryFunc(longdouble x, longdouble y);
/*UFUNC_API*/
NPY_NO_EXPORT void
-PyUFunc_e_e(char **args, intp *dimensions, intp *steps, void *func)
+PyUFunc_e_e(char **args, npy_intp *dimensions, npy_intp *steps, void *func)
{
halfUnaryFunc *f = (halfUnaryFunc *)func;
UNARY_LOOP {
@@ -106,7 +106,7 @@ PyUFunc_e_e(char **args, intp *dimensions, intp *steps, void *func)
/*UFUNC_API*/
NPY_NO_EXPORT void
-PyUFunc_e_e_As_f_f(char **args, intp *dimensions, intp *steps, void *func)
+PyUFunc_e_e_As_f_f(char **args, npy_intp *dimensions, npy_intp *steps, void *func)
{
floatUnaryFunc *f = (floatUnaryFunc *)func;
UNARY_LOOP {
@@ -117,7 +117,7 @@ PyUFunc_e_e_As_f_f(char **args, intp *dimensions, intp *steps, void *func)
/*UFUNC_API*/
NPY_NO_EXPORT void
-PyUFunc_e_e_As_d_d(char **args, intp *dimensions, intp *steps, void *func)
+PyUFunc_e_e_As_d_d(char **args, npy_intp *dimensions, npy_intp *steps, void *func)
{
doubleUnaryFunc *f = (doubleUnaryFunc *)func;
UNARY_LOOP {
@@ -128,7 +128,7 @@ PyUFunc_e_e_As_d_d(char **args, intp *dimensions, intp *steps, void *func)
/*UFUNC_API*/
NPY_NO_EXPORT void
-PyUFunc_f_f(char **args, intp *dimensions, intp *steps, void *func)
+PyUFunc_f_f(char **args, npy_intp *dimensions, npy_intp *steps, void *func)
{
floatUnaryFunc *f = (floatUnaryFunc *)func;
UNARY_LOOP {
@@ -139,7 +139,7 @@ PyUFunc_f_f(char **args, intp *dimensions, intp *steps, void *func)
/*UFUNC_API*/
NPY_NO_EXPORT void
-PyUFunc_f_f_As_d_d(char **args, intp *dimensions, intp *steps, void *func)
+PyUFunc_f_f_As_d_d(char **args, npy_intp *dimensions, npy_intp *steps, void *func)
{
doubleUnaryFunc *f = (doubleUnaryFunc *)func;
UNARY_LOOP {
@@ -150,7 +150,7 @@ PyUFunc_f_f_As_d_d(char **args, intp *dimensions, intp *steps, void *func)
/*UFUNC_API*/
NPY_NO_EXPORT void
-PyUFunc_ee_e(char **args, intp *dimensions, intp *steps, void *func)
+PyUFunc_ee_e(char **args, npy_intp *dimensions, npy_intp *steps, void *func)
{
halfBinaryFunc *f = (halfBinaryFunc *)func;
BINARY_LOOP {
@@ -162,7 +162,7 @@ PyUFunc_ee_e(char **args, intp *dimensions, intp *steps, void *func)
/*UFUNC_API*/
NPY_NO_EXPORT void
-PyUFunc_ee_e_As_ff_f(char **args, intp *dimensions, intp *steps, void *func)
+PyUFunc_ee_e_As_ff_f(char **args, npy_intp *dimensions, npy_intp *steps, void *func)
{
floatBinaryFunc *f = (floatBinaryFunc *)func;
BINARY_LOOP {
@@ -174,7 +174,7 @@ PyUFunc_ee_e_As_ff_f(char **args, intp *dimensions, intp *steps, void *func)
/*UFUNC_API*/
NPY_NO_EXPORT void
-PyUFunc_ee_e_As_dd_d(char **args, intp *dimensions, intp *steps, void *func)
+PyUFunc_ee_e_As_dd_d(char **args, npy_intp *dimensions, npy_intp *steps, void *func)
{
doubleBinaryFunc *f = (doubleBinaryFunc *)func;
BINARY_LOOP {
@@ -186,7 +186,7 @@ PyUFunc_ee_e_As_dd_d(char **args, intp *dimensions, intp *steps, void *func)
/*UFUNC_API*/
NPY_NO_EXPORT void
-PyUFunc_ff_f(char **args, intp *dimensions, intp *steps, void *func)
+PyUFunc_ff_f(char **args, npy_intp *dimensions, npy_intp *steps, void *func)
{
floatBinaryFunc *f = (floatBinaryFunc *)func;
BINARY_LOOP {
@@ -198,7 +198,7 @@ PyUFunc_ff_f(char **args, intp *dimensions, intp *steps, void *func)
/*UFUNC_API*/
NPY_NO_EXPORT void
-PyUFunc_ff_f_As_dd_d(char **args, intp *dimensions, intp *steps, void *func)
+PyUFunc_ff_f_As_dd_d(char **args, npy_intp *dimensions, npy_intp *steps, void *func)
{
doubleBinaryFunc *f = (doubleBinaryFunc *)func;
BINARY_LOOP {
@@ -210,7 +210,7 @@ PyUFunc_ff_f_As_dd_d(char **args, intp *dimensions, intp *steps, void *func)
/*UFUNC_API*/
NPY_NO_EXPORT void
-PyUFunc_d_d(char **args, intp *dimensions, intp *steps, void *func)
+PyUFunc_d_d(char **args, npy_intp *dimensions, npy_intp *steps, void *func)
{
doubleUnaryFunc *f = (doubleUnaryFunc *)func;
UNARY_LOOP {
@@ -221,7 +221,7 @@ PyUFunc_d_d(char **args, intp *dimensions, intp *steps, void *func)
/*UFUNC_API*/
NPY_NO_EXPORT void
-PyUFunc_dd_d(char **args, intp *dimensions, intp *steps, void *func)
+PyUFunc_dd_d(char **args, npy_intp *dimensions, npy_intp *steps, void *func)
{
doubleBinaryFunc *f = (doubleBinaryFunc *)func;
BINARY_LOOP {
@@ -233,7 +233,7 @@ PyUFunc_dd_d(char **args, intp *dimensions, intp *steps, void *func)
/*UFUNC_API*/
NPY_NO_EXPORT void
-PyUFunc_g_g(char **args, intp *dimensions, intp *steps, void *func)
+PyUFunc_g_g(char **args, npy_intp *dimensions, npy_intp *steps, void *func)
{
longdoubleUnaryFunc *f = (longdoubleUnaryFunc *)func;
UNARY_LOOP {
@@ -244,7 +244,7 @@ PyUFunc_g_g(char **args, intp *dimensions, intp *steps, void *func)
/*UFUNC_API*/
NPY_NO_EXPORT void
-PyUFunc_gg_g(char **args, intp *dimensions, intp *steps, void *func)
+PyUFunc_gg_g(char **args, npy_intp *dimensions, npy_intp *steps, void *func)
{
longdoubleBinaryFunc *f = (longdoubleBinaryFunc *)func;
BINARY_LOOP {
@@ -271,7 +271,7 @@ typedef void clongdoubleBinaryFunc(clongdouble *x, clongdouble *y,
/*UFUNC_API*/
NPY_NO_EXPORT void
-PyUFunc_F_F(char **args, intp *dimensions, intp *steps, void *func)
+PyUFunc_F_F(char **args, npy_intp *dimensions, npy_intp *steps, void *func)
{
cfloatUnaryFunc *f = (cfloatUnaryFunc *)func;
UNARY_LOOP {
@@ -283,7 +283,7 @@ PyUFunc_F_F(char **args, intp *dimensions, intp *steps, void *func)
/*UFUNC_API*/
NPY_NO_EXPORT void
-PyUFunc_F_F_As_D_D(char **args, intp *dimensions, intp *steps, void *func)
+PyUFunc_F_F_As_D_D(char **args, npy_intp *dimensions, npy_intp *steps, void *func)
{
cdoubleUnaryFunc *f = (cdoubleUnaryFunc *)func;
UNARY_LOOP {
@@ -298,7 +298,7 @@ PyUFunc_F_F_As_D_D(char **args, intp *dimensions, intp *steps, void *func)
/*UFUNC_API*/
NPY_NO_EXPORT void
-PyUFunc_FF_F(char **args, intp *dimensions, intp *steps, void *func)
+PyUFunc_FF_F(char **args, npy_intp *dimensions, npy_intp *steps, void *func)
{
cfloatBinaryFunc *f = (cfloatBinaryFunc *)func;
BINARY_LOOP {
@@ -311,7 +311,7 @@ PyUFunc_FF_F(char **args, intp *dimensions, intp *steps, void *func)
/*UFUNC_API*/
NPY_NO_EXPORT void
-PyUFunc_FF_F_As_DD_D(char **args, intp *dimensions, intp *steps, void *func)
+PyUFunc_FF_F_As_DD_D(char **args, npy_intp *dimensions, npy_intp *steps, void *func)
{
cdoubleBinaryFunc *f = (cdoubleBinaryFunc *)func;
BINARY_LOOP {
@@ -328,7 +328,7 @@ PyUFunc_FF_F_As_DD_D(char **args, intp *dimensions, intp *steps, void *func)
/*UFUNC_API*/
NPY_NO_EXPORT void
-PyUFunc_D_D(char **args, intp *dimensions, intp *steps, void *func)
+PyUFunc_D_D(char **args, npy_intp *dimensions, npy_intp *steps, void *func)
{
cdoubleUnaryFunc *f = (cdoubleUnaryFunc *)func;
UNARY_LOOP {
@@ -340,7 +340,7 @@ PyUFunc_D_D(char **args, intp *dimensions, intp *steps, void *func)
/*UFUNC_API*/
NPY_NO_EXPORT void
-PyUFunc_DD_D(char **args, intp *dimensions, intp *steps, void *func)
+PyUFunc_DD_D(char **args, npy_intp *dimensions, npy_intp *steps, void *func)
{
cdoubleBinaryFunc *f = (cdoubleBinaryFunc *)func;
BINARY_LOOP {
@@ -353,7 +353,7 @@ PyUFunc_DD_D(char **args, intp *dimensions, intp *steps, void *func)
/*UFUNC_API*/
NPY_NO_EXPORT void
-PyUFunc_G_G(char **args, intp *dimensions, intp *steps, void *func)
+PyUFunc_G_G(char **args, npy_intp *dimensions, npy_intp *steps, void *func)
{
clongdoubleUnaryFunc *f = (clongdoubleUnaryFunc *)func;
UNARY_LOOP {
@@ -365,7 +365,7 @@ PyUFunc_G_G(char **args, intp *dimensions, intp *steps, void *func)
/*UFUNC_API*/
NPY_NO_EXPORT void
-PyUFunc_GG_G(char **args, intp *dimensions, intp *steps, void *func)
+PyUFunc_GG_G(char **args, npy_intp *dimensions, npy_intp *steps, void *func)
{
clongdoubleBinaryFunc *f = (clongdoubleBinaryFunc *)func;
BINARY_LOOP {
@@ -383,7 +383,7 @@ PyUFunc_GG_G(char **args, intp *dimensions, intp *steps, void *func)
/*UFUNC_API*/
NPY_NO_EXPORT void
-PyUFunc_O_O(char **args, intp *dimensions, intp *steps, void *func)
+PyUFunc_O_O(char **args, npy_intp *dimensions, npy_intp *steps, void *func)
{
unaryfunc f = (unaryfunc)func;
UNARY_LOOP {
@@ -400,7 +400,7 @@ PyUFunc_O_O(char **args, intp *dimensions, intp *steps, void *func)
/*UFUNC_API*/
NPY_NO_EXPORT void
-PyUFunc_O_O_method(char **args, intp *dimensions, intp *steps, void *func)
+PyUFunc_O_O_method(char **args, npy_intp *dimensions, npy_intp *steps, void *func)
{
char *meth = (char *)func;
UNARY_LOOP {
@@ -417,7 +417,7 @@ PyUFunc_O_O_method(char **args, intp *dimensions, intp *steps, void *func)
/*UFUNC_API*/
NPY_NO_EXPORT void
-PyUFunc_OO_O(char **args, intp *dimensions, intp *steps, void *func)
+PyUFunc_OO_O(char **args, npy_intp *dimensions, npy_intp *steps, void *func)
{
binaryfunc f = (binaryfunc)func;
BINARY_LOOP {
@@ -435,7 +435,7 @@ PyUFunc_OO_O(char **args, intp *dimensions, intp *steps, void *func)
/*UFUNC_API*/
NPY_NO_EXPORT void
-PyUFunc_OO_O_method(char **args, intp *dimensions, intp *steps, void *func)
+PyUFunc_OO_O_method(char **args, npy_intp *dimensions, npy_intp *steps, void *func)
{
char *meth = (char *)func;
BINARY_LOOP {
@@ -459,9 +459,9 @@ PyUFunc_OO_O_method(char **args, intp *dimensions, intp *steps, void *func)
/*UFUNC_API*/
NPY_NO_EXPORT void
-PyUFunc_On_Om(char **args, intp *dimensions, intp *steps, void *func)
+PyUFunc_On_Om(char **args, npy_intp *dimensions, npy_intp *steps, void *func)
{
- intp n = dimensions[0];
+ npy_intp n = dimensions[0];
PyUFunc_PyFuncData *data = (PyUFunc_PyFuncData *)func;
int nin = data->nin;
int nout = data->nout;
@@ -469,7 +469,7 @@ PyUFunc_On_Om(char **args, intp *dimensions, intp *steps, void *func)
char *ptrs[NPY_MAXARGS];
PyObject *arglist, *result;
PyObject *in, **op;
- intp i, j, ntot;
+ npy_intp i, j, ntot;
ntot = nin+nout;
@@ -530,7 +530,7 @@ PyUFunc_On_Om(char **args, intp *dimensions, intp *steps, void *func)
**/
NPY_NO_EXPORT void
-BOOL_@kind@(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func))
+BOOL_@kind@(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func))
{
BINARY_LOOP {
Bool in1 = *((Bool *)ip1) != 0;
@@ -548,7 +548,7 @@ BOOL_@kind@(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func))
**/
NPY_NO_EXPORT void
-BOOL_@kind@(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func))
+BOOL_@kind@(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func))
{
if(IS_BINARY_REDUCE) {
BINARY_REDUCE_LOOP(Bool) {
@@ -572,7 +572,7 @@ BOOL_@kind@(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func))
NPY_NO_EXPORT void
-BOOL_logical_xor(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func))
+BOOL_logical_xor(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func))
{
BINARY_LOOP {
Bool in1 = *((Bool *)ip1) != 0;
@@ -586,7 +586,7 @@ BOOL_logical_xor(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(fu
* #OP = >, <#
**/
NPY_NO_EXPORT void
-BOOL_@kind@(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func))
+BOOL_@kind@(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func))
{
BINARY_LOOP {
Bool in1 = *((Bool *)ip1) != 0;
@@ -601,7 +601,7 @@ BOOL_@kind@(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func))
* #OP = !=, ==#
**/
NPY_NO_EXPORT void
-BOOL_@kind@(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func))
+BOOL_@kind@(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func))
{
UNARY_LOOP {
Bool in1 = *(Bool *)ip1;
@@ -611,7 +611,7 @@ BOOL_@kind@(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func))
/**end repeat**/
NPY_NO_EXPORT void
-BOOL_ones_like(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(data))
+BOOL_ones_like(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(data))
{
OUTPUT_LOOP {
*((Bool *)op1) = 1;
@@ -642,7 +642,7 @@ BOOL_ones_like(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(data
#define @S@@TYPE@_fmin @S@@TYPE@_minimum
NPY_NO_EXPORT void
-@S@@TYPE@_ones_like(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(data))
+@S@@TYPE@_ones_like(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(data))
{
OUTPUT_LOOP {
*((@s@@type@ *)op1) = 1;
@@ -650,7 +650,7 @@ NPY_NO_EXPORT void
}
NPY_NO_EXPORT void
-@S@@TYPE@_square(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(data))
+@S@@TYPE@_square(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(data))
{
UNARY_LOOP {
const @s@@type@ in1 = *(@s@@type@ *)ip1;
@@ -659,7 +659,7 @@ NPY_NO_EXPORT void
}
NPY_NO_EXPORT void
-@S@@TYPE@_reciprocal(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(data))
+@S@@TYPE@_reciprocal(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(data))
{
UNARY_LOOP {
const @s@@type@ in1 = *(@s@@type@ *)ip1;
@@ -668,7 +668,7 @@ NPY_NO_EXPORT void
}
NPY_NO_EXPORT void
-@S@@TYPE@_conjugate(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func))
+@S@@TYPE@_conjugate(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func))
{
UNARY_LOOP {
const @s@@type@ in1 = *(@s@@type@ *)ip1;
@@ -677,7 +677,7 @@ NPY_NO_EXPORT void
}
NPY_NO_EXPORT void
-@S@@TYPE@_negative(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func))
+@S@@TYPE@_negative(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func))
{
UNARY_LOOP {
const @s@@type@ in1 = *(@s@@type@ *)ip1;
@@ -686,7 +686,7 @@ NPY_NO_EXPORT void
}
NPY_NO_EXPORT void
-@S@@TYPE@_logical_not(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func))
+@S@@TYPE@_logical_not(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func))
{
UNARY_LOOP {
const @s@@type@ in1 = *(@s@@type@ *)ip1;
@@ -695,7 +695,7 @@ NPY_NO_EXPORT void
}
NPY_NO_EXPORT void
-@S@@TYPE@_invert(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func))
+@S@@TYPE@_invert(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func))
{
UNARY_LOOP {
const @s@@type@ in1 = *(@s@@type@ *)ip1;
@@ -710,7 +710,7 @@ NPY_NO_EXPORT void
* #OP = +, -,*, &, |, ^, <<, >>#
*/
NPY_NO_EXPORT void
-@S@@TYPE@_@kind@(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func))
+@S@@TYPE@_@kind@(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func))
{
if(IS_BINARY_REDUCE) {
BINARY_REDUCE_LOOP(@s@@type@) {
@@ -734,7 +734,7 @@ NPY_NO_EXPORT void
* #OP = ==, !=, >, >=, <, <=, &&, ||#
*/
NPY_NO_EXPORT void
-@S@@TYPE@_@kind@(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func))
+@S@@TYPE@_@kind@(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func))
{
BINARY_LOOP {
const @s@@type@ in1 = *(@s@@type@ *)ip1;
@@ -745,7 +745,7 @@ NPY_NO_EXPORT void
/**end repeat2**/
NPY_NO_EXPORT void
-@S@@TYPE@_logical_xor(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func))
+@S@@TYPE@_logical_xor(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func))
{
BINARY_LOOP {
const @s@@type@ in1 = *(@s@@type@ *)ip1;
@@ -759,7 +759,7 @@ NPY_NO_EXPORT void
* #OP = >, <#
**/
NPY_NO_EXPORT void
-@S@@TYPE@_@kind@(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func))
+@S@@TYPE@_@kind@(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func))
{
if (IS_BINARY_REDUCE) {
BINARY_REDUCE_LOOP(@s@@type@) {
@@ -779,7 +779,7 @@ NPY_NO_EXPORT void
/**end repeat2**/
NPY_NO_EXPORT void
-@S@@TYPE@_true_divide(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func))
+@S@@TYPE@_true_divide(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func))
{
BINARY_LOOP {
const double in1 = (double)(*(@s@@type@ *)ip1);
@@ -789,7 +789,7 @@ NPY_NO_EXPORT void
}
NPY_NO_EXPORT void
-@S@@TYPE@_power(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func))
+@S@@TYPE@_power(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func))
{
BINARY_LOOP {
const @ftype@ in1 = (@ftype@)*(@s@@type@ *)ip1;
@@ -799,7 +799,7 @@ NPY_NO_EXPORT void
}
NPY_NO_EXPORT void
-@S@@TYPE@_fmod(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func))
+@S@@TYPE@_fmod(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func))
{
BINARY_LOOP {
const @s@@type@ in1 = *(@s@@type@ *)ip1;
@@ -818,7 +818,7 @@ NPY_NO_EXPORT void
/**end repeat1**/
NPY_NO_EXPORT void
-U@TYPE@_absolute(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func))
+U@TYPE@_absolute(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func))
{
UNARY_LOOP {
const u@type@ in1 = *(u@type@ *)ip1;
@@ -827,7 +827,7 @@ U@TYPE@_absolute(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(fu
}
NPY_NO_EXPORT void
-@TYPE@_absolute(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func))
+@TYPE@_absolute(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func))
{
UNARY_LOOP {
const @type@ in1 = *(@type@ *)ip1;
@@ -836,7 +836,7 @@ NPY_NO_EXPORT void
}
NPY_NO_EXPORT void
-U@TYPE@_sign(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func))
+U@TYPE@_sign(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func))
{
UNARY_LOOP {
const u@type@ in1 = *(u@type@ *)ip1;
@@ -845,7 +845,7 @@ U@TYPE@_sign(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func))
}
NPY_NO_EXPORT void
-@TYPE@_sign(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func))
+@TYPE@_sign(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func))
{
UNARY_LOOP {
const @type@ in1 = *(@type@ *)ip1;
@@ -854,7 +854,7 @@ NPY_NO_EXPORT void
}
NPY_NO_EXPORT void
-@TYPE@_divide(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func))
+@TYPE@_divide(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func))
{
BINARY_LOOP {
const @type@ in1 = *(@type@ *)ip1;
@@ -880,7 +880,7 @@ NPY_NO_EXPORT void
}
NPY_NO_EXPORT void
-U@TYPE@_divide(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func))
+U@TYPE@_divide(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func))
{
BINARY_LOOP {
const u@type@ in1 = *(u@type@ *)ip1;
@@ -896,7 +896,7 @@ U@TYPE@_divide(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func
}
NPY_NO_EXPORT void
-@TYPE@_remainder(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func))
+@TYPE@_remainder(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func))
{
BINARY_LOOP {
const @type@ in1 = *(@type@ *)ip1;
@@ -919,7 +919,7 @@ NPY_NO_EXPORT void
}
NPY_NO_EXPORT void
-U@TYPE@_remainder(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func))
+U@TYPE@_remainder(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func))
{
BINARY_LOOP {
const u@type@ in1 = *(u@type@ *)ip1;
@@ -943,7 +943,7 @@ U@TYPE@_remainder(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(f
*/
NPY_NO_EXPORT void
-TIMEDELTA_negative(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func))
+TIMEDELTA_negative(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func))
{
UNARY_LOOP {
const npy_timedelta in1 = *(npy_timedelta *)ip1;
@@ -957,7 +957,7 @@ TIMEDELTA_negative(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(
}
NPY_NO_EXPORT void
-TIMEDELTA_absolute(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func))
+TIMEDELTA_absolute(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func))
{
UNARY_LOOP {
const npy_timedelta in1 = *(npy_timedelta *)ip1;
@@ -971,7 +971,7 @@ TIMEDELTA_absolute(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(
}
NPY_NO_EXPORT void
-TIMEDELTA_sign(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func))
+TIMEDELTA_sign(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func))
{
UNARY_LOOP {
const npy_timedelta in1 = *(npy_timedelta *)ip1;
@@ -985,7 +985,7 @@ TIMEDELTA_sign(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func
*/
NPY_NO_EXPORT void
-@TYPE@_ones_like(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(data))
+@TYPE@_ones_like(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(data))
{
OUTPUT_LOOP {
*((@type@ *)op1) = 1;
@@ -997,7 +997,7 @@ NPY_NO_EXPORT void
* #OP = ==, !=, >, >=, <, <=#
*/
NPY_NO_EXPORT void
-@TYPE@_@kind@(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func))
+@TYPE@_@kind@(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func))
{
BINARY_LOOP {
const @type@ in1 = *(@type@ *)ip1;
@@ -1012,7 +1012,7 @@ NPY_NO_EXPORT void
* #OP = >, <#
**/
NPY_NO_EXPORT void
-@TYPE@_@kind@(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func))
+@TYPE@_@kind@(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func))
{
if (IS_BINARY_REDUCE) {
BINARY_REDUCE_LOOP(@type@) {
@@ -1042,7 +1042,7 @@ NPY_NO_EXPORT void
/**end repeat**/
NPY_NO_EXPORT void
-DATETIME_Mm_M_add(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(data))
+DATETIME_Mm_M_add(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(data))
{
BINARY_LOOP {
const datetime in1 = *(datetime *)ip1;
@@ -1057,7 +1057,7 @@ DATETIME_Mm_M_add(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(d
}
NPY_NO_EXPORT void
-DATETIME_mM_M_add(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func))
+DATETIME_mM_M_add(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func))
{
BINARY_LOOP {
const timedelta in1 = *(timedelta *)ip1;
@@ -1072,7 +1072,7 @@ DATETIME_mM_M_add(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(f
}
NPY_NO_EXPORT void
-TIMEDELTA_mm_m_add(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func))
+TIMEDELTA_mm_m_add(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func))
{
BINARY_LOOP {
const timedelta in1 = *(timedelta *)ip1;
@@ -1087,7 +1087,7 @@ TIMEDELTA_mm_m_add(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(
}
NPY_NO_EXPORT void
-DATETIME_Mm_M_subtract(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func))
+DATETIME_Mm_M_subtract(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func))
{
BINARY_LOOP {
const datetime in1 = *(datetime *)ip1;
@@ -1102,7 +1102,7 @@ DATETIME_Mm_M_subtract(char **args, intp *dimensions, intp *steps, void *NPY_UNU
}
NPY_NO_EXPORT void
-DATETIME_MM_m_subtract(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func))
+DATETIME_MM_m_subtract(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func))
{
BINARY_LOOP {
const datetime in1 = *(datetime *)ip1;
@@ -1117,7 +1117,7 @@ DATETIME_MM_m_subtract(char **args, intp *dimensions, intp *steps, void *NPY_UNU
}
NPY_NO_EXPORT void
-TIMEDELTA_mm_m_subtract(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func))
+TIMEDELTA_mm_m_subtract(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func))
{
BINARY_LOOP {
const timedelta in1 = *(timedelta *)ip1;
@@ -1133,7 +1133,7 @@ TIMEDELTA_mm_m_subtract(char **args, intp *dimensions, intp *steps, void *NPY_UN
/* Note: Assuming 'q' == NPY_LONGLONG */
NPY_NO_EXPORT void
-TIMEDELTA_mq_m_multiply(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func))
+TIMEDELTA_mq_m_multiply(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func))
{
BINARY_LOOP {
const npy_timedelta in1 = *(npy_timedelta *)ip1;
@@ -1149,7 +1149,7 @@ TIMEDELTA_mq_m_multiply(char **args, intp *dimensions, intp *steps, void *NPY_UN
/* Note: Assuming 'q' == NPY_LONGLONG */
NPY_NO_EXPORT void
-TIMEDELTA_qm_m_multiply(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func))
+TIMEDELTA_qm_m_multiply(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func))
{
BINARY_LOOP {
const npy_int64 in1 = *(npy_int64 *)ip1;
@@ -1164,7 +1164,7 @@ TIMEDELTA_qm_m_multiply(char **args, intp *dimensions, intp *steps, void *NPY_UN
}
NPY_NO_EXPORT void
-TIMEDELTA_md_m_multiply(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func))
+TIMEDELTA_md_m_multiply(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func))
{
BINARY_LOOP {
const npy_timedelta in1 = *(npy_timedelta *)ip1;
@@ -1179,7 +1179,7 @@ TIMEDELTA_md_m_multiply(char **args, intp *dimensions, intp *steps, void *NPY_UN
}
NPY_NO_EXPORT void
-TIMEDELTA_dm_m_multiply(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func))
+TIMEDELTA_dm_m_multiply(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func))
{
BINARY_LOOP {
const double in1 = *(double *)ip1;
@@ -1195,7 +1195,7 @@ TIMEDELTA_dm_m_multiply(char **args, intp *dimensions, intp *steps, void *NPY_UN
/* Note: Assuming 'q' == NPY_LONGLONG */
NPY_NO_EXPORT void
-TIMEDELTA_mq_m_divide(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func))
+TIMEDELTA_mq_m_divide(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func))
{
BINARY_LOOP {
const npy_timedelta in1 = *(npy_timedelta *)ip1;
@@ -1210,7 +1210,7 @@ TIMEDELTA_mq_m_divide(char **args, intp *dimensions, intp *steps, void *NPY_UNUS
}
NPY_NO_EXPORT void
-TIMEDELTA_md_m_divide(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func))
+TIMEDELTA_md_m_divide(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func))
{
BINARY_LOOP {
const npy_timedelta in1 = *(npy_timedelta *)ip1;
@@ -1231,7 +1231,7 @@ TIMEDELTA_md_m_divide(char **args, intp *dimensions, intp *steps, void *NPY_UNUS
}
NPY_NO_EXPORT void
-TIMEDELTA_mm_d_divide(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func))
+TIMEDELTA_mm_d_divide(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func))
{
BINARY_LOOP {
const npy_timedelta in1 = *(npy_timedelta *)ip1;
@@ -1267,7 +1267,7 @@ TIMEDELTA_mm_d_divide(char **args, intp *dimensions, intp *steps, void *NPY_UNUS
* # OP = +, -, *, /#
*/
NPY_NO_EXPORT void
-@TYPE@_@kind@(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func))
+@TYPE@_@kind@(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func))
{
if(IS_BINARY_REDUCE) {
BINARY_REDUCE_LOOP(@type@) {
@@ -1291,7 +1291,7 @@ NPY_NO_EXPORT void
* #OP = ==, !=, <, <=, >, >=, &&, ||#
*/
NPY_NO_EXPORT void
-@TYPE@_@kind@(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func))
+@TYPE@_@kind@(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func))
{
BINARY_LOOP {
const @type@ in1 = *(@type@ *)ip1;
@@ -1302,7 +1302,7 @@ NPY_NO_EXPORT void
/**end repeat1**/
NPY_NO_EXPORT void
-@TYPE@_logical_xor(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func))
+@TYPE@_logical_xor(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func))
{
BINARY_LOOP {
const @type@ in1 = *(@type@ *)ip1;
@@ -1312,7 +1312,7 @@ NPY_NO_EXPORT void
}
NPY_NO_EXPORT void
-@TYPE@_logical_not(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func))
+@TYPE@_logical_not(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func))
{
UNARY_LOOP {
const @type@ in1 = *(@type@ *)ip1;
@@ -1325,7 +1325,7 @@ NPY_NO_EXPORT void
* #func = npy_isnan, npy_isinf, npy_isfinite, npy_signbit#
**/
NPY_NO_EXPORT void
-@TYPE@_@kind@(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func))
+@TYPE@_@kind@(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func))
{
UNARY_LOOP {
const @type@ in1 = *(@type@ *)ip1;
@@ -1335,7 +1335,7 @@ NPY_NO_EXPORT void
/**end repeat1**/
NPY_NO_EXPORT void
-@TYPE@_spacing(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func))
+@TYPE@_spacing(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func))
{
UNARY_LOOP {
const @type@ in1 = *(@type@ *)ip1;
@@ -1344,7 +1344,7 @@ NPY_NO_EXPORT void
}
NPY_NO_EXPORT void
-@TYPE@_copysign(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func))
+@TYPE@_copysign(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func))
{
BINARY_LOOP {
const @type@ in1 = *(@type@ *)ip1;
@@ -1354,7 +1354,7 @@ NPY_NO_EXPORT void
}
NPY_NO_EXPORT void
-@TYPE@_nextafter(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func))
+@TYPE@_nextafter(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func))
{
BINARY_LOOP {
const @type@ in1 = *(@type@ *)ip1;
@@ -1368,7 +1368,7 @@ NPY_NO_EXPORT void
* #OP = >=, <=#
**/
NPY_NO_EXPORT void
-@TYPE@_@kind@(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func))
+@TYPE@_@kind@(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func))
{
/* */
if (IS_BINARY_REDUCE) {
@@ -1393,7 +1393,7 @@ NPY_NO_EXPORT void
* #OP = >=, <=#
**/
NPY_NO_EXPORT void
-@TYPE@_@kind@(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func))
+@TYPE@_@kind@(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func))
{
/* */
if (IS_BINARY_REDUCE) {
@@ -1414,7 +1414,7 @@ NPY_NO_EXPORT void
/**end repeat1**/
NPY_NO_EXPORT void
-@TYPE@_floor_divide(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func))
+@TYPE@_floor_divide(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func))
{
BINARY_LOOP {
const @type@ in1 = *(@type@ *)ip1;
@@ -1424,7 +1424,7 @@ NPY_NO_EXPORT void
}
NPY_NO_EXPORT void
-@TYPE@_remainder(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func))
+@TYPE@_remainder(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func))
{
BINARY_LOOP {
const @type@ in1 = *(@type@ *)ip1;
@@ -1440,7 +1440,7 @@ NPY_NO_EXPORT void
}
NPY_NO_EXPORT void
-@TYPE@_square(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(data))
+@TYPE@_square(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(data))
{
UNARY_LOOP {
const @type@ in1 = *(@type@ *)ip1;
@@ -1449,7 +1449,7 @@ NPY_NO_EXPORT void
}
NPY_NO_EXPORT void
-@TYPE@_reciprocal(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(data))
+@TYPE@_reciprocal(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(data))
{
UNARY_LOOP {
const @type@ in1 = *(@type@ *)ip1;
@@ -1458,7 +1458,7 @@ NPY_NO_EXPORT void
}
NPY_NO_EXPORT void
-@TYPE@_ones_like(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(data))
+@TYPE@_ones_like(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(data))
{
OUTPUT_LOOP {
*((@type@ *)op1) = 1;
@@ -1466,7 +1466,7 @@ NPY_NO_EXPORT void
}
NPY_NO_EXPORT void
-@TYPE@_conjugate(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func))
+@TYPE@_conjugate(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func))
{
UNARY_LOOP {
const @type@ in1 = *(@type@ *)ip1;
@@ -1475,7 +1475,7 @@ NPY_NO_EXPORT void
}
NPY_NO_EXPORT void
-@TYPE@_absolute(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func))
+@TYPE@_absolute(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func))
{
UNARY_LOOP {
const @type@ in1 = *(@type@ *)ip1;
@@ -1486,7 +1486,7 @@ NPY_NO_EXPORT void
}
NPY_NO_EXPORT void
-@TYPE@_negative(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func))
+@TYPE@_negative(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func))
{
UNARY_LOOP {
const @type@ in1 = *(@type@ *)ip1;
@@ -1495,7 +1495,7 @@ NPY_NO_EXPORT void
}
NPY_NO_EXPORT void
-@TYPE@_sign(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func))
+@TYPE@_sign(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func))
{
/* Sign of nan is nan */
UNARY_LOOP {
@@ -1505,7 +1505,7 @@ NPY_NO_EXPORT void
}
NPY_NO_EXPORT void
-@TYPE@_modf(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func))
+@TYPE@_modf(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func))
{
UNARY_LOOP_TWO_OUT {
const @type@ in1 = *(@type@ *)ip1;
@@ -1515,7 +1515,7 @@ NPY_NO_EXPORT void
#ifdef HAVE_FREXP@C@
NPY_NO_EXPORT void
-@TYPE@_frexp(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func))
+@TYPE@_frexp(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func))
{
UNARY_LOOP_TWO_OUT {
const @type@ in1 = *(@type@ *)ip1;
@@ -1526,7 +1526,7 @@ NPY_NO_EXPORT void
#ifdef HAVE_LDEXP@C@
NPY_NO_EXPORT void
-@TYPE@_ldexp(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func))
+@TYPE@_ldexp(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func))
{
BINARY_LOOP {
const @type@ in1 = *(@type@ *)ip1;
@@ -1536,7 +1536,7 @@ NPY_NO_EXPORT void
}
NPY_NO_EXPORT void
-@TYPE@_ldexp_long(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func))
+@TYPE@_ldexp_long(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func))
{
/*
* Additional loop to handle long integer inputs (cf. #866, #1633).
@@ -1583,7 +1583,7 @@ NPY_NO_EXPORT void
* # OP = +, -, *, /#
*/
NPY_NO_EXPORT void
-HALF_@kind@(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func))
+HALF_@kind@(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func))
{
if(IS_BINARY_REDUCE) {
char *iop1 = args[0];
@@ -1611,7 +1611,7 @@ HALF_@kind@(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func))
* #OP = npy_half_eq, npy_half_ne, npy_half_lt, npy_half_le, npy_half_gt, npy_half_ge, _HALF_LOGICAL_AND, _HALF_LOGICAL_OR#
*/
NPY_NO_EXPORT void
-HALF_@kind@(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func))
+HALF_@kind@(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func))
{
BINARY_LOOP {
const npy_half in1 = *(npy_half *)ip1;
@@ -1624,7 +1624,7 @@ HALF_@kind@(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func))
#undef _HALF_LOGICAL_OR
NPY_NO_EXPORT void
-HALF_logical_xor(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func))
+HALF_logical_xor(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func))
{
BINARY_LOOP {
const int in1 = !npy_half_iszero(*(npy_half *)ip1);
@@ -1634,7 +1634,7 @@ HALF_logical_xor(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(fu
}
NPY_NO_EXPORT void
-HALF_logical_not(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func))
+HALF_logical_not(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func))
{
UNARY_LOOP {
const npy_half in1 = *(npy_half *)ip1;
@@ -1647,7 +1647,7 @@ HALF_logical_not(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(fu
* #func = npy_half_isnan, npy_half_isinf, npy_half_isfinite, npy_half_signbit#
**/
NPY_NO_EXPORT void
-HALF_@kind@(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func))
+HALF_@kind@(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func))
{
UNARY_LOOP {
const npy_half in1 = *(npy_half *)ip1;
@@ -1657,7 +1657,7 @@ HALF_@kind@(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func))
/**end repeat**/
NPY_NO_EXPORT void
-HALF_spacing(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func))
+HALF_spacing(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func))
{
UNARY_LOOP {
const npy_half in1 = *(npy_half *)ip1;
@@ -1666,7 +1666,7 @@ HALF_spacing(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func))
}
NPY_NO_EXPORT void
-HALF_copysign(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func))
+HALF_copysign(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func))
{
BINARY_LOOP {
const npy_half in1 = *(npy_half *)ip1;
@@ -1676,7 +1676,7 @@ HALF_copysign(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)
}
NPY_NO_EXPORT void
-HALF_nextafter(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func))
+HALF_nextafter(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func))
{
BINARY_LOOP {
const npy_half in1 = *(npy_half *)ip1;
@@ -1690,7 +1690,7 @@ HALF_nextafter(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func
* #OP = npy_half_ge, npy_half_le#
**/
NPY_NO_EXPORT void
-HALF_@kind@(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func))
+HALF_@kind@(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func))
{
/* */
BINARY_LOOP {
@@ -1706,7 +1706,7 @@ HALF_@kind@(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func))
* #OP = npy_half_ge, npy_half_le#
**/
NPY_NO_EXPORT void
-HALF_@kind@(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func))
+HALF_@kind@(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func))
{
/* */
BINARY_LOOP {
@@ -1718,7 +1718,7 @@ HALF_@kind@(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func))
/**end repeat**/
NPY_NO_EXPORT void
-HALF_floor_divide(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func))
+HALF_floor_divide(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func))
{
BINARY_LOOP {
const float in1 = npy_half_to_float(*(npy_half *)ip1);
@@ -1728,7 +1728,7 @@ HALF_floor_divide(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(f
}
NPY_NO_EXPORT void
-HALF_remainder(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func))
+HALF_remainder(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func))
{
BINARY_LOOP {
const float in1 = npy_half_to_float(*(npy_half *)ip1);
@@ -1744,7 +1744,7 @@ HALF_remainder(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func
}
NPY_NO_EXPORT void
-HALF_square(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(data))
+HALF_square(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(data))
{
UNARY_LOOP {
const float in1 = npy_half_to_float(*(npy_half *)ip1);
@@ -1753,7 +1753,7 @@ HALF_square(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(data))
}
NPY_NO_EXPORT void
-HALF_reciprocal(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(data))
+HALF_reciprocal(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(data))
{
UNARY_LOOP {
const float in1 = npy_half_to_float(*(npy_half *)ip1);
@@ -1762,7 +1762,7 @@ HALF_reciprocal(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(dat
}
NPY_NO_EXPORT void
-HALF_ones_like(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(data))
+HALF_ones_like(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(data))
{
OUTPUT_LOOP {
*((npy_half *)op1) = NPY_HALF_ONE;
@@ -1770,7 +1770,7 @@ HALF_ones_like(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(data
}
NPY_NO_EXPORT void
-HALF_conjugate(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func))
+HALF_conjugate(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func))
{
UNARY_LOOP {
const npy_half in1 = *(npy_half *)ip1;
@@ -1779,7 +1779,7 @@ HALF_conjugate(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func
}
NPY_NO_EXPORT void
-HALF_absolute(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func))
+HALF_absolute(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func))
{
UNARY_LOOP {
const npy_half in1 = *(npy_half *)ip1;
@@ -1788,7 +1788,7 @@ HALF_absolute(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)
}
NPY_NO_EXPORT void
-HALF_negative(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func))
+HALF_negative(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func))
{
UNARY_LOOP {
const npy_half in1 = *(npy_half *)ip1;
@@ -1797,7 +1797,7 @@ HALF_negative(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)
}
NPY_NO_EXPORT void
-HALF_sign(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func))
+HALF_sign(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func))
{
/* Sign of nan is nan */
UNARY_LOOP {
@@ -1809,7 +1809,7 @@ HALF_sign(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func))
}
NPY_NO_EXPORT void
-HALF_modf(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func))
+HALF_modf(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func))
{
float temp;
@@ -1822,7 +1822,7 @@ HALF_modf(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func))
#ifdef HAVE_FREXPF
NPY_NO_EXPORT void
-HALF_frexp(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func))
+HALF_frexp(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func))
{
UNARY_LOOP_TWO_OUT {
const float in1 = npy_half_to_float(*(npy_half *)ip1);
@@ -1833,7 +1833,7 @@ HALF_frexp(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func))
#ifdef HAVE_LDEXPF
NPY_NO_EXPORT void
-HALF_ldexp(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func))
+HALF_ldexp(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func))
{
BINARY_LOOP {
const float in1 = npy_half_to_float(*(npy_half *)ip1);
@@ -1843,7 +1843,7 @@ HALF_ldexp(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func))
}
NPY_NO_EXPORT void
-HALF_ldexp_long(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func))
+HALF_ldexp_long(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func))
{
/*
* Additional loop to handle long integer inputs (cf. #866, #1633).
@@ -1907,7 +1907,7 @@ HALF_ldexp_long(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(fun
* #OP = +, -#
*/
NPY_NO_EXPORT void
-C@TYPE@_@kind@(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func))
+C@TYPE@_@kind@(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func))
{
BINARY_LOOP {
const @type@ in1r = ((@type@ *)ip1)[0];
@@ -1921,7 +1921,7 @@ C@TYPE@_@kind@(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func
/**end repeat1**/
NPY_NO_EXPORT void
-C@TYPE@_multiply(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func))
+C@TYPE@_multiply(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func))
{
BINARY_LOOP {
const @type@ in1r = ((@type@ *)ip1)[0];
@@ -1934,7 +1934,7 @@ C@TYPE@_multiply(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(fu
}
NPY_NO_EXPORT void
-C@TYPE@_divide(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func))
+C@TYPE@_divide(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func))
{
BINARY_LOOP {
const @type@ in1r = ((@type@ *)ip1)[0];
@@ -1966,7 +1966,7 @@ C@TYPE@_divide(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func
}
NPY_NO_EXPORT void
-C@TYPE@_floor_divide(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func))
+C@TYPE@_floor_divide(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func))
{
BINARY_LOOP {
const @type@ in1r = ((@type@ *)ip1)[0];
@@ -1991,7 +1991,7 @@ C@TYPE@_floor_divide(char **args, intp *dimensions, intp *steps, void *NPY_UNUSE
* #OP = CGT, CGE, CLT, CLE, CEQ, CNE#
*/
NPY_NO_EXPORT void
-C@TYPE@_@kind@(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func))
+C@TYPE@_@kind@(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func))
{
BINARY_LOOP {
const @type@ in1r = ((@type@ *)ip1)[0];
@@ -2009,7 +2009,7 @@ C@TYPE@_@kind@(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func
#OP2 = &&, ||#
*/
NPY_NO_EXPORT void
-C@TYPE@_@kind@(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func))
+C@TYPE@_@kind@(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func))
{
BINARY_LOOP {
const @type@ in1r = ((@type@ *)ip1)[0];
@@ -2022,7 +2022,7 @@ C@TYPE@_@kind@(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func
/**end repeat1**/
NPY_NO_EXPORT void
-C@TYPE@_logical_xor(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func))
+C@TYPE@_logical_xor(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func))
{
BINARY_LOOP {
const @type@ in1r = ((@type@ *)ip1)[0];
@@ -2036,7 +2036,7 @@ C@TYPE@_logical_xor(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED
}
NPY_NO_EXPORT void
-C@TYPE@_logical_not(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func))
+C@TYPE@_logical_not(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func))
{
UNARY_LOOP {
const @type@ in1r = ((@type@ *)ip1)[0];
@@ -2051,7 +2051,7 @@ C@TYPE@_logical_not(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED
* #OP = ||, ||, &&#
**/
NPY_NO_EXPORT void
-C@TYPE@_@kind@(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func))
+C@TYPE@_@kind@(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func))
{
UNARY_LOOP {
const @type@ in1r = ((@type@ *)ip1)[0];
@@ -2062,7 +2062,7 @@ C@TYPE@_@kind@(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func
/**end repeat1**/
NPY_NO_EXPORT void
-C@TYPE@_square(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(data))
+C@TYPE@_square(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(data))
{
UNARY_LOOP {
const @type@ in1r = ((@type@ *)ip1)[0];
@@ -2073,7 +2073,7 @@ C@TYPE@_square(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(data
}
NPY_NO_EXPORT void
-C@TYPE@_reciprocal(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(data))
+C@TYPE@_reciprocal(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(data))
{
UNARY_LOOP {
const @type@ in1r = ((@type@ *)ip1)[0];
@@ -2093,7 +2093,7 @@ C@TYPE@_reciprocal(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(
}
NPY_NO_EXPORT void
-C@TYPE@_ones_like(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(data))
+C@TYPE@_ones_like(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(data))
{
OUTPUT_LOOP {
((@type@ *)op1)[0] = 1;
@@ -2102,7 +2102,7 @@ C@TYPE@_ones_like(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(d
}
NPY_NO_EXPORT void
-C@TYPE@_conjugate(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)) {
+C@TYPE@_conjugate(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)) {
UNARY_LOOP {
const @type@ in1r = ((@type@ *)ip1)[0];
const @type@ in1i = ((@type@ *)ip1)[1];
@@ -2112,7 +2112,7 @@ C@TYPE@_conjugate(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(f
}
NPY_NO_EXPORT void
-C@TYPE@_absolute(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func))
+C@TYPE@_absolute(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func))
{
UNARY_LOOP {
const @type@ in1r = ((@type@ *)ip1)[0];
@@ -2122,7 +2122,7 @@ C@TYPE@_absolute(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(fu
}
NPY_NO_EXPORT void
-C@TYPE@__arg(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func))
+C@TYPE@__arg(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func))
{
UNARY_LOOP {
const @type@ in1r = ((@type@ *)ip1)[0];
@@ -2132,7 +2132,7 @@ C@TYPE@__arg(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func))
}
NPY_NO_EXPORT void
-C@TYPE@_sign(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func))
+C@TYPE@_sign(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func))
{
/* fixme: sign of nan is currently 0 */
UNARY_LOOP {
@@ -2150,7 +2150,7 @@ C@TYPE@_sign(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func))
* #OP = CGE, CLE#
*/
NPY_NO_EXPORT void
-C@TYPE@_@kind@(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func))
+C@TYPE@_@kind@(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func))
{
BINARY_LOOP {
const @type@ in1r = ((@type@ *)ip1)[0];
@@ -2174,7 +2174,7 @@ C@TYPE@_@kind@(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func
* #OP = CGE, CLE#
*/
NPY_NO_EXPORT void
-C@TYPE@_@kind@(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func))
+C@TYPE@_@kind@(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func))
{
BINARY_LOOP {
const @type@ in1r = ((@type@ *)ip1)[0];
@@ -2215,7 +2215,7 @@ C@TYPE@_@kind@(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func
* #OP = EQ, NE, GT, GE, LT, LE#
*/
NPY_NO_EXPORT void
-OBJECT_@kind@(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)) {
+OBJECT_@kind@(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func)) {
BINARY_LOOP {
PyObject *in1 = *(PyObject **)ip1;
PyObject *in2 = *(PyObject **)ip2;
@@ -2231,7 +2231,7 @@ OBJECT_@kind@(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func)
/**end repeat**/
NPY_NO_EXPORT void
-OBJECT_sign(char **args, intp *dimensions, intp *steps, void *NPY_UNUSED(func))
+OBJECT_sign(char **args, npy_intp *dimensions, npy_intp *steps, void *NPY_UNUSED(func))
{
#if defined(NPY_PY3K)
PyObject *zero = PyLong_FromLong(0);
diff --git a/numpy/core/src/umath/ufunc_object.c b/numpy/core/src/umath/ufunc_object.c
index de541af42..b7fecefc8 100644
--- a/numpy/core/src/umath/ufunc_object.c
+++ b/numpy/core/src/umath/ufunc_object.c
@@ -946,143 +946,6 @@ fail:
return -1;
}
-static const char *
-_casting_to_string(NPY_CASTING casting)
-{
- switch (casting) {
- case NPY_NO_CASTING:
- return "no";
- case NPY_EQUIV_CASTING:
- return "equiv";
- case NPY_SAFE_CASTING:
- return "safe";
- case NPY_SAME_KIND_CASTING:
- return "same_kind";
- case NPY_UNSAFE_CASTING:
- return "unsafe";
- default:
- return "<unknown>";
- }
-}
-
-
-static int
-ufunc_loop_matches(PyUFuncObject *self,
- PyArrayObject **op,
- NPY_CASTING input_casting,
- NPY_CASTING output_casting,
- int any_object,
- int use_min_scalar,
- int *types,
- int *out_no_castable_output,
- char *out_err_src_typecode,
- char *out_err_dst_typecode)
-{
- npy_intp i, nin = self->nin, nop = nin + self->nout;
-
- /*
- * First check if all the inputs can be safely cast
- * to the types for this function
- */
- for (i = 0; i < nin; ++i) {
- PyArray_Descr *tmp;
-
- /*
- * If no inputs are objects and there are more than one
- * loop, don't allow conversion to object. The rationale
- * behind this is mostly performance. Except for custom
- * ufuncs built with just one object-parametered inner loop,
- * only the types that are supported are implemented. Trying
- * the object version of logical_or on float arguments doesn't
- * seem right.
- */
- if (types[i] == NPY_OBJECT && !any_object && self->ntypes > 1) {
- return 0;
- }
-
- tmp = PyArray_DescrFromType(types[i]);
- if (tmp == NULL) {
- return -1;
- }
-
-#if NPY_UF_DBG_TRACING
- printf("Checking type for op %d, type %d: ", (int)i, (int)types[i]);
- PyObject_Print((PyObject *)tmp, stdout, 0);
- printf(", operand type: ");
- PyObject_Print((PyObject *)PyArray_DESCR(op[i]), stdout, 0);
- printf("\n");
-#endif
- /*
- * If all the inputs are scalars, use the regular
- * promotion rules, not the special value-checking ones.
- */
- if (!use_min_scalar) {
- if (!PyArray_CanCastTypeTo(PyArray_DESCR(op[i]), tmp,
- input_casting)) {
- Py_DECREF(tmp);
- return 0;
- }
- }
- else {
- if (!PyArray_CanCastArrayTo(op[i], tmp, input_casting)) {
- Py_DECREF(tmp);
- return 0;
- }
- }
- Py_DECREF(tmp);
- }
- NPY_UF_DBG_PRINT("The inputs all worked\n");
-
- /*
- * If all the inputs were ok, then check casting back to the
- * outputs.
- */
- for (i = nin; i < nop; ++i) {
- if (op[i] != NULL) {
- PyArray_Descr *tmp = PyArray_DescrFromType(types[i]);
- if (tmp == NULL) {
- return -1;
- }
- if (!PyArray_CanCastTypeTo(tmp, PyArray_DESCR(op[i]),
- output_casting)) {
- if (!(*out_no_castable_output)) {
- *out_no_castable_output = 1;
- *out_err_src_typecode = tmp->type;
- *out_err_dst_typecode = PyArray_DESCR(op[i])->type;
- }
- Py_DECREF(tmp);
- return 0;
- }
- Py_DECREF(tmp);
- }
- }
- NPY_UF_DBG_PRINT("The outputs all worked\n");
-
- return 1;
-}
-
-static int
-set_ufunc_loop_data_types(PyUFuncObject *self, PyArrayObject **op,
- PyArray_Descr **out_dtype,
- int *types)
-{
- int i, nin = self->nin, nop = nin + self->nout;
-
- /* Fill the dtypes array */
- for (i = 0; i < nop; ++i) {
- out_dtype[i] = PyArray_DescrFromType(types[i]);
- if (out_dtype[i] == NULL) {
- while (--i >= 0) {
- Py_DECREF(out_dtype[i]);
- out_dtype[i] = NULL;
- }
- return -1;
- }
- }
-
- return 0;
-}
-
/*
* This checks whether a trivial loop is ok,
* making copies of scalar and one dimensional operands if that will
@@ -1135,1884 +998,6 @@ check_for_trivial_loop(PyUFuncObject *self,
return 1;
}
-/*
- * Does a search through the arguments and the loops
- */
-static int
-find_ufunc_matching_userloop(PyUFuncObject *self,
- PyArrayObject **op,
- NPY_CASTING input_casting,
- NPY_CASTING output_casting,
- int any_object,
- int use_min_scalar,
- PyArray_Descr **out_dtype,
- PyUFuncGenericFunction *out_innerloop,
- void **out_innerloopdata,
- int *out_no_castable_output,
- char *out_err_src_typecode,
- char *out_err_dst_typecode)
-{
- npy_intp i, nin = self->nin;
- PyUFunc_Loop1d *funcdata;
-
- /* Use this to try to avoid repeating the same userdef loop search */
- int last_userdef = -1;
-
- for (i = 0; i < nin; ++i) {
- int type_num = PyArray_DESCR(op[i])->type_num;
- if (type_num != last_userdef && PyTypeNum_ISUSERDEF(type_num)) {
- PyObject *key, *obj;
-
- last_userdef = type_num;
-
- key = PyInt_FromLong(type_num);
- if (key == NULL) {
- return -1;
- }
- obj = PyDict_GetItem(self->userloops, key);
- Py_DECREF(key);
- if (obj == NULL) {
- continue;
- }
- funcdata = (PyUFunc_Loop1d *)NpyCapsule_AsVoidPtr(obj);
- while (funcdata != NULL) {
- int *types = funcdata->arg_types;
- switch (ufunc_loop_matches(self, op,
- input_casting, output_casting,
- any_object, use_min_scalar,
- types,
- out_no_castable_output, out_err_src_typecode,
- out_err_dst_typecode)) {
- /* Error */
- case -1:
- return -1;
- /* Found a match */
- case 1:
- set_ufunc_loop_data_types(self, op, out_dtype, types);
-
- /* Save the inner loop and its data */
- *out_innerloop = funcdata->func;
- *out_innerloopdata = funcdata->data;
-
- NPY_UF_DBG_PRINT("Returning userdef inner "
- "loop successfully\n");
-
- return 0;
- }
-
- funcdata = funcdata->next;
- }
- }
- }
-
- /* Didn't find a match */
- return 0;
-}
-
-/*
- * Does a search through the arguments and the loops
- */
-static int
-find_ufunc_specified_userloop(PyUFuncObject *self,
- int n_specified,
- int *specified_types,
- PyArrayObject **op,
- NPY_CASTING casting,
- int any_object,
- int use_min_scalar,
- PyArray_Descr **out_dtype,
- PyUFuncGenericFunction *out_innerloop,
- void **out_innerloopdata)
-{
- int i, j, nin = self->nin, nop = nin + self->nout;
- PyUFunc_Loop1d *funcdata;
-
- /* Use this to try to avoid repeating the same userdef loop search */
- int last_userdef = -1;
-
- int no_castable_output = 0;
- char err_src_typecode = '-', err_dst_typecode = '-';
-
- for (i = 0; i < nin; ++i) {
- int type_num = PyArray_DESCR(op[i])->type_num;
- if (type_num != last_userdef && PyTypeNum_ISUSERDEF(type_num)) {
- PyObject *key, *obj;
-
- last_userdef = type_num;
-
- key = PyInt_FromLong(type_num);
- if (key == NULL) {
- return -1;
- }
- obj = PyDict_GetItem(self->userloops, key);
- Py_DECREF(key);
- if (obj == NULL) {
- continue;
- }
- funcdata = (PyUFunc_Loop1d *)NpyCapsule_AsVoidPtr(obj);
- while (funcdata != NULL) {
- int *types = funcdata->arg_types;
- int matched = 1;
-
- if (n_specified == nop) {
- for (j = 0; j < nop; ++j) {
- if (types[j] != specified_types[j]) {
- matched = 0;
- break;
- }
- }
- } else {
- if (types[nin] != specified_types[0]) {
- matched = 0;
- }
- }
- if (!matched) {
- continue;
- }
-
- switch (ufunc_loop_matches(self, op,
- casting, casting,
- any_object, use_min_scalar,
- types,
- &no_castable_output, &err_src_typecode,
- &err_dst_typecode)) {
- /* It works */
- case 1:
- set_ufunc_loop_data_types(self, op, out_dtype, types);
-
- /* Save the inner loop and its data */
- *out_innerloop = funcdata->func;
- *out_innerloopdata = funcdata->data;
-
- NPY_UF_DBG_PRINT("Returning userdef inner "
- "loop successfully\n");
-
- return 0;
- /* Didn't match */
- case 0:
- PyErr_Format(PyExc_TypeError,
- "found a user loop for ufunc '%s' "
- "matching the type-tuple, "
- "but the inputs and/or outputs could not be "
- "cast according to the casting rule",
- self->name ? self->name : "(unknown)");
- return -1;
- /* Error */
- case -1:
- return -1;
- }
-
- funcdata = funcdata->next;
- }
- }
- }
-
- /* Didn't find a match */
- return 0;
-}
-
-/*
- * Provides an ordering for the dtype 'kind' character codes, to help
- * determine when to use the min_scalar_type function. This groups
- * 'kind' into boolean, integer, floating point, and everything else.
- */
-
-static int
-dtype_kind_to_simplified_ordering(char kind)
-{
- switch (kind) {
- /* Boolean kind */
- case 'b':
- return 0;
- /* Unsigned int kind */
- case 'u':
- /* Signed int kind */
- case 'i':
- return 1;
- /* Float kind */
- case 'f':
- /* Complex kind */
- case 'c':
- return 2;
- /* Anything else */
- default:
- return 3;
- }
-}
-
-static int
-should_use_min_scalar(PyArrayObject **op, int nop)
-{
- int i, use_min_scalar, kind;
- int all_scalars = 1, max_scalar_kind = -1, max_array_kind = -1;
-
- /*
- * Determine if there are any scalars, and if so, whether
- * the maximum "kind" of the scalars surpasses the maximum
- * "kind" of the arrays
- */
- use_min_scalar = 0;
- if (nop > 1) {
- for(i = 0; i < nop; ++i) {
- kind = dtype_kind_to_simplified_ordering(
- PyArray_DESCR(op[i])->kind);
- if (PyArray_NDIM(op[i]) == 0) {
- if (kind > max_scalar_kind) {
- max_scalar_kind = kind;
- }
- }
- else {
- all_scalars = 0;
- if (kind > max_array_kind) {
- max_array_kind = kind;
- }
-
- }
- }
-
- /* Indicate whether to use the min_scalar_type function */
- if (!all_scalars && max_array_kind >= max_scalar_kind) {
- use_min_scalar = 1;
- }
- }
-
- return use_min_scalar;
-}
-
-/*
- * Does a linear search for the best inner loop of the ufunc.
- *
- * Note that if an error is returned, the caller must free the non-zero
- * references in out_dtype. This function does not do its own clean-up.
- */
-static int
-find_best_ufunc_inner_loop(PyUFuncObject *self,
- PyArrayObject **op,
- NPY_CASTING input_casting,
- NPY_CASTING output_casting,
- int any_object,
- PyArray_Descr **out_dtype,
- PyUFuncGenericFunction *out_innerloop,
- void **out_innerloopdata)
-{
- npy_intp i, j, nin = self->nin, nop = nin + self->nout;
- int types[NPY_MAXARGS];
- char *ufunc_name;
- int no_castable_output, use_min_scalar;
-
- /* For making a better error message on coercion error */
- char err_dst_typecode = '-', err_src_typecode = '-';
-
- ufunc_name = self->name ? self->name : "(unknown)";
-
- use_min_scalar = should_use_min_scalar(op, nin);
-
- /* If the ufunc has userloops, search for them. */
- if (self->userloops) {
- switch (find_ufunc_matching_userloop(self, op,
- input_casting, output_casting,
- any_object, use_min_scalar,
- out_dtype, out_innerloop, out_innerloopdata,
- &no_castable_output, &err_src_typecode,
- &err_dst_typecode)) {
- /* Error */
- case -1:
- return -1;
- /* A loop was found */
- case 1:
- return 0;
- }
- }
-
- /*
- * Determine the UFunc loop. This could in general be *much* faster,
- * and a better way to implement it might be for the ufunc to
- * provide a function which gives back the result type and inner
- * loop function.
- *
- * A default fast mechanism could be provided for functions which
- * follow the most typical pattern, when all functions have signatures
- * "xx...x -> x" for some built-in data type x, as follows.
- * - Use PyArray_ResultType to get the output type
- * - Look up the inner loop in a table based on the output type_num
- *
- * The method for finding the loop in the previous code did not
- * appear consistent (as noted by some asymmetry in the generated
- * coercion tables for np.add).
- */
- no_castable_output = 0;
- for (i = 0; i < self->ntypes; ++i) {
- char *orig_types = self->types + i*self->nargs;
-
- /* Copy the types into an int array for matching */
- for (j = 0; j < nop; ++j) {
- types[j] = orig_types[j];
- }
-
- NPY_UF_DBG_PRINT1("Trying function loop %d\n", (int)i);
- switch (ufunc_loop_matches(self, op,
- input_casting, output_casting,
- any_object, use_min_scalar,
- types,
- &no_castable_output, &err_src_typecode,
- &err_dst_typecode)) {
- /* Error */
- case -1:
- return -1;
- /* Found a match */
- case 1:
- set_ufunc_loop_data_types(self, op, out_dtype, types);
-
- /* Save the inner loop and its data */
- *out_innerloop = self->functions[i];
- *out_innerloopdata = self->data[i];
-
- NPY_UF_DBG_PRINT("Returning inner loop successfully\n");
-
- return 0;
- }
-
- }
-
- /* If no function was found, throw an error */
- NPY_UF_DBG_PRINT("No loop was found\n");
- if (no_castable_output) {
- PyErr_Format(PyExc_TypeError,
- "ufunc '%s' output (typecode '%c') could not be coerced to "
- "provided output parameter (typecode '%c') according "
- "to the casting rule '%s'",
- ufunc_name, err_src_typecode, err_dst_typecode,
- _casting_to_string(output_casting));
- }
- else {
- /*
- * TODO: We should try again if the casting rule is same_kind
- * or unsafe, and look for a function more liberally.
- */
- PyErr_Format(PyExc_TypeError,
- "ufunc '%s' not supported for the input types, and the "
- "inputs could not be safely coerced to any supported "
- "types according to the casting rule '%s'",
- ufunc_name,
- _casting_to_string(input_casting));
- }
-
- return -1;
-}
-
-/*
- * Does a linear search for the inner loop of the ufunc specified by type_tup.
- *
- * Note that if an error is returned, the caller must free the non-zero
- * references in out_dtype. This function does not do its own clean-up.
- */
-static int
-find_specified_ufunc_inner_loop(PyUFuncObject *self,
- PyObject *type_tup,
- PyArrayObject **op,
- NPY_CASTING casting,
- int any_object,
- PyArray_Descr **out_dtype,
- PyUFuncGenericFunction *out_innerloop,
- void **out_innerloopdata)
-{
- npy_intp i, j, n, nin = self->nin, nop = nin + self->nout;
- int n_specified = 0;
- int specified_types[NPY_MAXARGS], types[NPY_MAXARGS];
- char *ufunc_name;
- int no_castable_output, use_min_scalar;
-
- /* For making a better error message on coercion error */
- char err_dst_typecode = '-', err_src_typecode = '-';
-
- ufunc_name = self->name ? self->name : "(unknown)";
-
- use_min_scalar = should_use_min_scalar(op, nin);
-
- /* Fill in specified_types from the tuple or string */
- if (PyTuple_Check(type_tup)) {
- n = PyTuple_GET_SIZE(type_tup);
- if (n != 1 && n != nop) {
- PyErr_Format(PyExc_ValueError,
- "a type-tuple must be specified " \
- "of length 1 or %d for ufunc '%s'", (int)nop,
- self->name ? self->name : "(unknown)");
- return -1;
- }
-
- for (i = 0; i < n; ++i) {
- PyArray_Descr *dtype = NULL;
- if (!PyArray_DescrConverter(PyTuple_GET_ITEM(type_tup, i),
- &dtype)) {
- return -1;
- }
- specified_types[i] = dtype->type_num;
- Py_DECREF(dtype);
- }
-
- n_specified = n;
- }
- else if (PyBytes_Check(type_tup) || PyUnicode_Check(type_tup)) {
- Py_ssize_t length;
- char *str;
- PyObject *str_obj = NULL;
-
- if (PyUnicode_Check(type_tup)) {
- str_obj = PyUnicode_AsASCIIString(type_tup);
- if (str_obj == NULL) {
- return -1;
- }
- type_tup = str_obj;
- }
-
- if (!PyBytes_AsStringAndSize(type_tup, &str, &length) < 0) {
- Py_XDECREF(str_obj);
- return -1;
- }
- if (length != 1 && (length != nop + 2 ||
- str[nin] != '-' || str[nin+1] != '>')) {
- PyErr_Format(PyExc_ValueError,
- "a type-string for %s, " \
- "requires 1 typecode, or "
- "%d typecode(s) before " \
- "and %d after the -> sign",
- self->name ? self->name : "(unknown)",
- self->nin, self->nout);
- Py_XDECREF(str_obj);
- return -1;
- }
- if (length == 1) {
- PyArray_Descr *dtype;
- n_specified = 1;
- dtype = PyArray_DescrFromType(str[0]);
- if (dtype == NULL) {
- Py_XDECREF(str_obj);
- return -1;
- }
- NPY_UF_DBG_PRINT2("signature character '%c', type num %d\n",
- str[0], dtype->type_num);
- specified_types[0] = dtype->type_num;
- Py_DECREF(dtype);
- }
- else {
- PyArray_Descr *dtype;
- n_specified = (int)nop;
-
- for (i = 0; i < nop; ++i) {
- npy_intp istr = i < nin ? i : i+2;
-
- dtype = PyArray_DescrFromType(str[istr]);
- if (dtype == NULL) {
- Py_XDECREF(str_obj);
- return -1;
- }
- NPY_UF_DBG_PRINT2("signature character '%c', type num %d\n",
- str[istr], dtype->type_num);
- specified_types[i] = dtype->type_num;
- Py_DECREF(dtype);
- }
- }
- Py_XDECREF(str_obj);
- }
-
- /* If the ufunc has userloops, search for them. */
- if (self->userloops) {
- NPY_UF_DBG_PRINT("Searching user loops for specified sig\n");
- switch (find_ufunc_specified_userloop(self,
- n_specified, specified_types,
- op, casting,
- any_object, use_min_scalar,
- out_dtype, out_innerloop, out_innerloopdata)) {
- /* Error */
- case -1:
- return -1;
- /* Found matching loop */
- case 1:
- return 0;
- }
- }
-
- NPY_UF_DBG_PRINT("Searching loops for specified sig\n");
- for (i = 0; i < self->ntypes; ++i) {
- char *orig_types = self->types + i*self->nargs;
- int matched = 1;
-
- NPY_UF_DBG_PRINT1("Trying function loop %d\n", (int)i);
-
- /* Copy the types into an int array for matching */
- for (j = 0; j < nop; ++j) {
- types[j] = orig_types[j];
- }
-
- if (n_specified == nop) {
- for (j = 0; j < nop; ++j) {
- if (types[j] != specified_types[j]) {
- matched = 0;
- break;
- }
- }
- } else {
- NPY_UF_DBG_PRINT2("Specified type: %d, first output type: %d\n",
- specified_types[0], types[nin]);
- if (types[nin] != specified_types[0]) {
- matched = 0;
- }
- }
- if (!matched) {
- continue;
- }
-
- NPY_UF_DBG_PRINT("It matches, confirming type casting\n");
- switch (ufunc_loop_matches(self, op,
- casting, casting,
- any_object, use_min_scalar,
- types,
- &no_castable_output, &err_src_typecode,
- &err_dst_typecode)) {
- /* Error */
- case -1:
- return -1;
- /* It worked */
- case 1:
- set_ufunc_loop_data_types(self, op, out_dtype, types);
-
- /* Save the inner loop and its data */
- *out_innerloop = self->functions[i];
- *out_innerloopdata = self->data[i];
-
- NPY_UF_DBG_PRINT("Returning specified inner loop successfully\n");
-
- return 0;
- /* Didn't work */
- case 0:
- PyErr_Format(PyExc_TypeError,
- "found a loop for ufunc '%s' "
- "matching the type-tuple, "
- "but the inputs and/or outputs could not be "
- "cast according to the casting rule",
- ufunc_name);
- return -1;
- }
-
- }
-
- /* If no function was found, throw an error */
- NPY_UF_DBG_PRINT("No specified loop was found\n");
-
- PyErr_Format(PyExc_TypeError,
- "No loop matching the specified signature was found "
- "for ufunc %s", ufunc_name);
-
- return -1;
-}
-
-/*
- * Returns a new reference to type if it is already NBO, otherwise
- * returns a copy converted to NBO.
- */
-static PyArray_Descr *
-ensure_dtype_nbo(PyArray_Descr *type)
-{
- if (PyArray_ISNBO(type->byteorder)) {
- Py_INCREF(type);
- return type;
- }
- else {
- return PyArray_DescrNewByteorder(type, NPY_NATIVE);
- }
-}
-
-/*UFUNC_API
- *
- * This function applies the default type resolution rules
- * for the provided ufunc, filling out_dtypes, out_innerloop,
- * and out_innerloopdata.
- *
- * Returns 0 on success, -1 on error.
- */
-NPY_NO_EXPORT int
-PyUFunc_DefaultTypeResolution(PyUFuncObject *ufunc,
- NPY_CASTING casting,
- PyArrayObject **operands,
- PyObject *type_tup,
- PyArray_Descr **out_dtypes,
- PyUFuncGenericFunction *out_innerloop,
- void **out_innerloopdata)
-{
- int i, nop = ufunc->nin + ufunc->nout;
- int retval = 0, any_object = 0;
- NPY_CASTING input_casting;
-
- for (i = 0; i < nop; ++i) {
- if (operands[i] != NULL &&
- PyTypeNum_ISOBJECT(PyArray_DESCR(operands[i])->type_num)) {
- any_object = 1;
- break;
- }
- }
-
- /*
- * Decide the casting rules for inputs and outputs. We want
- * NPY_SAFE_CASTING or stricter, so that the loop selection code
- * doesn't choose an integer loop for float inputs, for example.
- */
- input_casting = (casting > NPY_SAFE_CASTING) ? NPY_SAFE_CASTING : casting;
-
- if (type_tup == NULL) {
- /* Find the best ufunc inner loop, and fill in the dtypes */
- retval = find_best_ufunc_inner_loop(ufunc, operands,
- input_casting, casting, any_object,
- out_dtypes, out_innerloop, out_innerloopdata);
- } else {
- /* Find the specified ufunc inner loop, and fill in the dtypes */
- retval = find_specified_ufunc_inner_loop(ufunc, type_tup,
- operands, casting, any_object, out_dtypes,
- out_innerloop, out_innerloopdata);
- }
-
- return retval;
-}
-
-/*
- * This function applies special type resolution rules for the case
- * where all the functions have the pattern XX->bool, using
- * PyArray_ResultType instead of a linear search to get the best
- * loop.
- *
- * Note that a simpler linear search through the functions loop
- * is still done, but switching to a simple array lookup for
- * built-in types would be better at some point.
- *
- * Returns 0 on success, -1 on error.
- */
-NPY_NO_EXPORT int
-PyUFunc_SimpleBinaryComparisonTypeResolution(PyUFuncObject *ufunc,
- NPY_CASTING casting,
- PyArrayObject **operands,
- PyObject *type_tup,
- PyArray_Descr **out_dtypes,
- PyUFuncGenericFunction *out_innerloop,
- void **out_innerloopdata)
-{
- int i, type_num, type_num1, type_num2;
- char *ufunc_name;
-
- ufunc_name = ufunc->name ? ufunc->name : "<unnamed ufunc>";
-
- if (ufunc->nin != 2 || ufunc->nout != 1) {
- PyErr_Format(PyExc_RuntimeError, "ufunc %s is configured "
- "to use binary comparison type resolution but has "
- "the wrong number of inputs or outputs",
- ufunc_name);
- return -1;
- }
-
- /*
- * Use the default type resolution if there's a custom data type
- * or object arrays.
- */
- type_num1 = PyArray_DESCR(operands[0])->type_num;
- type_num2 = PyArray_DESCR(operands[1])->type_num;
- if (type_num1 >= NPY_NTYPES || type_num2 >= NPY_NTYPES ||
- type_num1 == NPY_OBJECT || type_num2 == NPY_OBJECT) {
- return PyUFunc_DefaultTypeResolution(ufunc, casting, operands,
- type_tup, out_dtypes, out_innerloop, out_innerloopdata);
- }
-
- if (type_tup == NULL) {
- /* Input types are the result type */
- out_dtypes[0] = PyArray_ResultType(2, operands, 0, NULL);
- if (out_dtypes[0] == NULL) {
- return -1;
- }
- out_dtypes[1] = out_dtypes[0];
- Py_INCREF(out_dtypes[1]);
- }
- else {
- /*
- * If the type tuple isn't a single-element tuple, let the
- * default type resolution handle this one.
- */
- if (!PyTuple_Check(type_tup) || PyTuple_GET_SIZE(type_tup) != 1) {
- return PyUFunc_DefaultTypeResolution(ufunc, casting,
- operands, type_tup, out_dtypes,
- out_innerloop, out_innerloopdata);
- }
-
- if (!PyArray_DescrCheck(PyTuple_GET_ITEM(type_tup, 0))) {
- PyErr_SetString(PyExc_ValueError,
- "require data type in the type tuple");
- return -1;
- }
-
- out_dtypes[0] = ensure_dtype_nbo(
- (PyArray_Descr *)PyTuple_GET_ITEM(type_tup, 0));
- if (out_dtypes[0] == NULL) {
- return -1;
- }
- out_dtypes[1] = out_dtypes[0];
- Py_INCREF(out_dtypes[1]);
- }
-
- /* Output type is always boolean */
- out_dtypes[2] = PyArray_DescrFromType(NPY_BOOL);
- if (out_dtypes[2] == NULL) {
- for (i = 0; i < 2; ++i) {
- Py_DECREF(out_dtypes[i]);
- out_dtypes[i] = NULL;
- }
- return -1;
- }
-
- /* Check against the casting rules */
- if (PyUFunc_ValidateCasting(ufunc, casting, operands, out_dtypes) < 0) {
- for (i = 0; i < 3; ++i) {
- Py_DECREF(out_dtypes[i]);
- out_dtypes[i] = NULL;
- }
- return -1;
- }
-
- type_num = out_dtypes[0]->type_num;
-
- /* If we have a built-in type, search in the functions list */
- if (type_num < NPY_NTYPES) {
- char *types = ufunc->types;
- int n = ufunc->ntypes;
-
- for (i = 0; i < n; ++i) {
- if (types[3*i] == type_num) {
- *out_innerloop = ufunc->functions[i];
- *out_innerloopdata = ufunc->data[i];
- return 0;
- }
- }
-
- PyErr_Format(PyExc_TypeError,
- "ufunc '%s' not supported for the input types",
- ufunc_name);
- return -1;
- }
- else {
- PyErr_SetString(PyExc_RuntimeError,
- "user type shouldn't have resulted from type promotion");
- return -1;
- }
-}
-
-/*
- * This function applies special type resolution rules for the case
- * where all the functions have the pattern X->X, copying
- * the input descr directly so that metadata is maintained.
- *
- * Note that a simpler linear search through the functions loop
- * is still done, but switching to a simple array lookup for
- * built-in types would be better at some point.
- *
- * Returns 0 on success, -1 on error.
- */
-NPY_NO_EXPORT int
-PyUFunc_SimpleUnaryOperationTypeResolution(PyUFuncObject *ufunc,
- NPY_CASTING casting,
- PyArrayObject **operands,
- PyObject *type_tup,
- PyArray_Descr **out_dtypes,
- PyUFuncGenericFunction *out_innerloop,
- void **out_innerloopdata)
-{
- int i, type_num, type_num1;
- char *ufunc_name;
-
- ufunc_name = ufunc->name ? ufunc->name : "<unnamed ufunc>";
-
- if (ufunc->nin != 1 || ufunc->nout != 1) {
- PyErr_Format(PyExc_RuntimeError, "ufunc %s is configured "
- "to use unary operation type resolution but has "
- "the wrong number of inputs or outputs",
- ufunc_name);
- return -1;
- }
-
- /*
- * Use the default type resolution if there's a custom data type
- * or object arrays.
- */
- type_num1 = PyArray_DESCR(operands[0])->type_num;
- if (type_num1 >= NPY_NTYPES || type_num1 == NPY_OBJECT) {
- return PyUFunc_DefaultTypeResolution(ufunc, casting, operands,
- type_tup, out_dtypes, out_innerloop, out_innerloopdata);
- }
-
- if (type_tup == NULL) {
- /* Input types are the result type */
- out_dtypes[0] = ensure_dtype_nbo(PyArray_DESCR(operands[0]));
- if (out_dtypes[0] == NULL) {
- return -1;
- }
- out_dtypes[1] = out_dtypes[0];
- Py_INCREF(out_dtypes[1]);
- }
- else {
- /*
- * If the type tuple isn't a single-element tuple, let the
- * default type resolution handle this one.
- */
- if (!PyTuple_Check(type_tup) || PyTuple_GET_SIZE(type_tup) != 1) {
- return PyUFunc_DefaultTypeResolution(ufunc, casting,
- operands, type_tup, out_dtypes,
- out_innerloop, out_innerloopdata);
- }
-
- if (!PyArray_DescrCheck(PyTuple_GET_ITEM(type_tup, 0))) {
- PyErr_SetString(PyExc_ValueError,
- "require data type in the type tuple");
- return -1;
- }
-
- out_dtypes[0] = ensure_dtype_nbo(
- (PyArray_Descr *)PyTuple_GET_ITEM(type_tup, 0));
- if (out_dtypes[0] == NULL) {
- return -1;
- }
- out_dtypes[1] = out_dtypes[0];
- Py_INCREF(out_dtypes[1]);
- }
-
- /* Check against the casting rules */
- if (PyUFunc_ValidateCasting(ufunc, casting, operands, out_dtypes) < 0) {
- for (i = 0; i < 2; ++i) {
- Py_DECREF(out_dtypes[i]);
- out_dtypes[i] = NULL;
- }
- return -1;
- }
-
- type_num = out_dtypes[0]->type_num;
-
- /* If we have a built-in type, search in the functions list */
- if (type_num < NPY_NTYPES) {
- char *types = ufunc->types;
- int n = ufunc->ntypes;
-
- for (i = 0; i < n; ++i) {
- if (types[2*i] == type_num) {
- *out_innerloop = ufunc->functions[i];
- *out_innerloopdata = ufunc->data[i];
- return 0;
- }
- }
-
- PyErr_Format(PyExc_TypeError,
- "ufunc '%s' not supported for the input types",
- ufunc_name);
- return -1;
- }
- else {
- PyErr_SetString(PyExc_RuntimeError,
- "user type shouldn't have resulted from type promotion");
- return -1;
- }
-}
-
-/*
- * The ones_like function shouldn't really be a ufunc, but while it
- * still is, this provides type resolution that always forces UNSAFE
- * casting.
- */
-NPY_NO_EXPORT int
-PyUFunc_OnesLikeTypeResolution(PyUFuncObject *ufunc,
- NPY_CASTING NPY_UNUSED(casting),
- PyArrayObject **operands,
- PyObject *type_tup,
- PyArray_Descr **out_dtypes,
- PyUFuncGenericFunction *out_innerloop,
- void **out_innerloopdata)
-{
- return PyUFunc_SimpleUnaryOperationTypeResolution(ufunc,
- NPY_UNSAFE_CASTING,
- operands, type_tup, out_dtypes,
- out_innerloop, out_innerloopdata);
-}
-
-
-/*
- * This function applies special type resolution rules for the case
- * where all the functions have the pattern XX->X, using
- * PyArray_ResultType instead of a linear search to get the best
- * loop.
- *
- * Note that a simpler linear search through the functions loop
- * is still done, but switching to a simple array lookup for
- * built-in types would be better at some point.
- *
- * Returns 0 on success, -1 on error.
- */
-NPY_NO_EXPORT int
-PyUFunc_SimpleBinaryOperationTypeResolution(PyUFuncObject *ufunc,
- NPY_CASTING casting,
- PyArrayObject **operands,
- PyObject *type_tup,
- PyArray_Descr **out_dtypes,
- PyUFuncGenericFunction *out_innerloop,
- void **out_innerloopdata)
-{
- int i, type_num, type_num1, type_num2;
- char *ufunc_name;
-
- ufunc_name = ufunc->name ? ufunc->name : "<unnamed ufunc>";
-
- if (ufunc->nin != 2 || ufunc->nout != 1) {
- PyErr_Format(PyExc_RuntimeError, "ufunc %s is configured "
- "to use binary operation type resolution but has "
- "the wrong number of inputs or outputs",
- ufunc_name);
- return -1;
- }
-
- /*
- * Use the default type resolution if there's a custom data type
- * or object arrays.
- */
- type_num1 = PyArray_DESCR(operands[0])->type_num;
- type_num2 = PyArray_DESCR(operands[1])->type_num;
- if (type_num1 >= NPY_NTYPES || type_num2 >= NPY_NTYPES ||
- type_num1 == NPY_OBJECT || type_num2 == NPY_OBJECT) {
- return PyUFunc_DefaultTypeResolution(ufunc, casting, operands,
- type_tup, out_dtypes, out_innerloop, out_innerloopdata);
- }
-
- if (type_tup == NULL) {
- /* Input types are the result type */
- out_dtypes[0] = PyArray_ResultType(2, operands, 0, NULL);
- if (out_dtypes[0] == NULL) {
- return -1;
- }
- out_dtypes[1] = out_dtypes[0];
- Py_INCREF(out_dtypes[1]);
- out_dtypes[2] = out_dtypes[0];
- Py_INCREF(out_dtypes[2]);
- }
- else {
- /*
- * If the type tuple isn't a single-element tuple, let the
- * default type resolution handle this one.
- */
- if (!PyTuple_Check(type_tup) || PyTuple_GET_SIZE(type_tup) != 1) {
- return PyUFunc_DefaultTypeResolution(ufunc, casting,
- operands, type_tup, out_dtypes,
- out_innerloop, out_innerloopdata);
- }
-
- if (!PyArray_DescrCheck(PyTuple_GET_ITEM(type_tup, 0))) {
- PyErr_SetString(PyExc_ValueError,
- "require data type in the type tuple");
- return -1;
- }
-
- out_dtypes[0] = ensure_dtype_nbo(
- (PyArray_Descr *)PyTuple_GET_ITEM(type_tup, 0));
- if (out_dtypes[0] == NULL) {
- return -1;
- }
- out_dtypes[1] = out_dtypes[0];
- Py_INCREF(out_dtypes[1]);
- out_dtypes[2] = out_dtypes[0];
- Py_INCREF(out_dtypes[2]);
- }
-
- /* Check against the casting rules */
- if (PyUFunc_ValidateCasting(ufunc, casting, operands, out_dtypes) < 0) {
- for (i = 0; i < 3; ++i) {
- Py_DECREF(out_dtypes[i]);
- out_dtypes[i] = NULL;
- }
- return -1;
- }
-
- type_num = out_dtypes[0]->type_num;
-
- /* If we have a built-in type, search in the functions list */
- if (type_num < NPY_NTYPES) {
- char *types = ufunc->types;
- int n = ufunc->ntypes;
-
- for (i = 0; i < n; ++i) {
- if (types[3*i] == type_num) {
- *out_innerloop = ufunc->functions[i];
- *out_innerloopdata = ufunc->data[i];
- return 0;
- }
- }
-
- PyErr_Format(PyExc_TypeError,
- "ufunc '%s' not supported for the input types",
- ufunc_name);
- return -1;
- }
- else {
- PyErr_SetString(PyExc_RuntimeError,
- "user type shouldn't have resulted from type promotion");
- return -1;
- }
-}
-
-/*
- * This function applies special type resolution rules for the absolute
- * ufunc. This ufunc converts complex -> float, so isn't covered
- * by the simple unary type resolution.
- *
- * Returns 0 on success, -1 on error.
- */
-NPY_NO_EXPORT int
-PyUFunc_AbsoluteTypeResolution(PyUFuncObject *ufunc,
- NPY_CASTING casting,
- PyArrayObject **operands,
- PyObject *type_tup,
- PyArray_Descr **out_dtypes,
- PyUFuncGenericFunction *out_innerloop,
- void **out_innerloopdata)
-{
- /* Use the default for complex types, to find the loop producing float */
- if (PyTypeNum_ISCOMPLEX(PyArray_DESCR(operands[0])->type_num)) {
- return PyUFunc_DefaultTypeResolution(ufunc, casting, operands,
- type_tup, out_dtypes, out_innerloop, out_innerloopdata);
- }
- else {
- return PyUFunc_SimpleUnaryOperationTypeResolution(ufunc, casting,
- operands, type_tup, out_dtypes,
- out_innerloop, out_innerloopdata);
- }
-}
-
-
-/*
- * This function returns the a new reference to the
- * capsule with the datetime metadata.
- *
- * NOTE: This function is copied from datetime.c in multiarray,
- * because umath and multiarray are not linked together.
- */
-static PyObject *
-get_datetime_metacobj_from_dtype(PyArray_Descr *dtype)
-{
- PyObject *metacobj;
-
- /* Check that the dtype has metadata */
- if (dtype->metadata == NULL) {
- PyErr_SetString(PyExc_TypeError,
- "Datetime type object is invalid, lacks metadata");
- return NULL;
- }
-
- /* Check that the dtype has unit metadata */
- metacobj = PyDict_GetItemString(dtype->metadata, NPY_METADATA_DTSTR);
- if (metacobj == NULL) {
- PyErr_SetString(PyExc_TypeError,
- "Datetime type object is invalid, lacks unit metadata");
- return NULL;
- }
-
- Py_INCREF(metacobj);
- return metacobj;
-}
-
-/*
- * Creates a new NPY_TIMEDELTA dtype, copying the datetime metadata
- * from the given dtype.
- *
- * NOTE: This function is copied from datetime.c in multiarray,
- * because umath and multiarray are not linked together.
- */
-static PyArray_Descr *
-timedelta_dtype_with_copied_meta(PyArray_Descr *dtype)
-{
- PyArray_Descr *ret;
- PyObject *metacobj;
-
- ret = PyArray_DescrNewFromType(NPY_TIMEDELTA);
- if (ret == NULL) {
- return NULL;
- }
- Py_XDECREF(ret->metadata);
- ret->metadata = PyDict_New();
- if (ret->metadata == NULL) {
- Py_DECREF(ret);
- return NULL;
- }
-
- metacobj = get_datetime_metacobj_from_dtype(dtype);
- if (metacobj == NULL) {
- Py_DECREF(ret);
- return NULL;
- }
-
- if (PyDict_SetItemString(ret->metadata, NPY_METADATA_DTSTR,
- metacobj) < 0) {
- Py_DECREF(metacobj);
- Py_DECREF(ret);
- return NULL;
- }
-
- return ret;
-}
-
-/*
- * This function applies the type resolution rules for addition.
- * In particular, there are a number of special cases with datetime:
- * m8[<A>] + m8[<B>] => m8[gcd(<A>,<B>)] + m8[gcd(<A>,<B>)]
- * m8[<A>] + int => m8[<A>] + m8[<A>]
- * int + m8[<A>] => m8[<A>] + m8[<A>]
- * M8[<A>] + int => M8[<A>] + m8[<A>]
- * int + M8[<A>] => m8[<A>] + M8[<A>]
- * M8[<A>] + m8[<B>] => M8[gcd(<A>,<B>)] + m8[gcd(<A>,<B>)]
- * m8[<A>] + M8[<B>] => m8[gcd(<A>,<B>)] + M8[gcd(<A>,<B>)]
- * TODO: Non-linear time unit cases require highly special-cased loops
- * M8[<A>] + m8[Y|M|B]
- * m8[Y|M|B] + M8[<A>]
- */
-NPY_NO_EXPORT int
-PyUFunc_AdditionTypeResolution(PyUFuncObject *ufunc,
- NPY_CASTING casting,
- PyArrayObject **operands,
- PyObject *type_tup,
- PyArray_Descr **out_dtypes,
- PyUFuncGenericFunction *out_innerloop,
- void **out_innerloopdata)
-{
- int type_num1, type_num2;
- char *types;
- int i, n;
- char *ufunc_name;
-
- ufunc_name = ufunc->name ? ufunc->name : "<unnamed ufunc>";
-
- type_num1 = PyArray_DESCR(operands[0])->type_num;
- type_num2 = PyArray_DESCR(operands[1])->type_num;
-
- /* Use the default when datetime and timedelta are not involved */
- if (!PyTypeNum_ISDATETIME(type_num1) && !PyTypeNum_ISDATETIME(type_num2)) {
- return PyUFunc_DefaultTypeResolution(ufunc, casting, operands,
- type_tup, out_dtypes, out_innerloop, out_innerloopdata);
- }
-
- if (type_num1 == NPY_TIMEDELTA) {
- /* m8[<A>] + m8[<B>] => m8[gcd(<A>,<B>)] + m8[gcd(<A>,<B>)] */
- if (type_num2 == NPY_TIMEDELTA) {
- out_dtypes[0] = PyArray_PromoteTypes(PyArray_DESCR(operands[0]),
- PyArray_DESCR(operands[1]));
- if (out_dtypes[0] == NULL) {
- return -1;
- }
- out_dtypes[1] = out_dtypes[0];
- Py_INCREF(out_dtypes[1]);
- out_dtypes[2] = out_dtypes[0];
- Py_INCREF(out_dtypes[2]);
- }
- /* m8[<A>] + M8[<B>] => m8[gcd(<A>,<B>)] + M8[gcd(<A>,<B>)] */
- else if (type_num2 == NPY_DATETIME) {
- out_dtypes[1] = PyArray_PromoteTypes(PyArray_DESCR(operands[0]),
- PyArray_DESCR(operands[1]));
- if (out_dtypes[1] == NULL) {
- return -1;
- }
- /* Make a new NPY_TIMEDELTA, and copy the datetime's metadata */
- out_dtypes[0] = timedelta_dtype_with_copied_meta(out_dtypes[1]);
- if (out_dtypes[0] == NULL) {
- Py_DECREF(out_dtypes[1]);
- out_dtypes[1] = NULL;
- return -1;
- }
- out_dtypes[2] = out_dtypes[1];
- Py_INCREF(out_dtypes[2]);
- }
- /* m8[<A>] + int => m8[<A>] + m8[<A>] */
- else if (PyTypeNum_ISINTEGER(type_num2) ||
- PyTypeNum_ISBOOL(type_num2)) {
- out_dtypes[0] = ensure_dtype_nbo(PyArray_DESCR(operands[0]));
- if (out_dtypes[0] == NULL) {
- return -1;
- }
- out_dtypes[1] = out_dtypes[0];
- Py_INCREF(out_dtypes[1]);
- out_dtypes[2] = out_dtypes[0];
- Py_INCREF(out_dtypes[2]);
-
- type_num2 = NPY_TIMEDELTA;
- }
- else {
- goto type_reso_error;
- }
- }
- else if (type_num1 == NPY_DATETIME) {
- /* M8[<A>] + m8[<B>] => M8[gcd(<A>,<B>)] + m8[gcd(<A>,<B>)] */
- if (type_num2 == NPY_TIMEDELTA) {
- out_dtypes[0] = PyArray_PromoteTypes(PyArray_DESCR(operands[0]),
- PyArray_DESCR(operands[1]));
- if (out_dtypes[0] == NULL) {
- return -1;
- }
- /* Make a new NPY_TIMEDELTA, and copy the datetime's metadata */
- out_dtypes[1] = timedelta_dtype_with_copied_meta(out_dtypes[0]);
- if (out_dtypes[1] == NULL) {
- Py_DECREF(out_dtypes[0]);
- out_dtypes[0] = NULL;
- return -1;
- }
- out_dtypes[2] = out_dtypes[0];
- Py_INCREF(out_dtypes[2]);
- }
- /* M8[<A>] + int => M8[<A>] + m8[<A>] */
- else if (PyTypeNum_ISINTEGER(type_num2) ||
- PyTypeNum_ISBOOL(type_num2)) {
- out_dtypes[0] = ensure_dtype_nbo(PyArray_DESCR(operands[0]));
- if (out_dtypes[0] == NULL) {
- return -1;
- }
- /* Make a new NPY_TIMEDELTA, and copy type1's metadata */
- out_dtypes[1] = timedelta_dtype_with_copied_meta(
- PyArray_DESCR(operands[0]));
- if (out_dtypes[1] == NULL) {
- Py_DECREF(out_dtypes[0]);
- out_dtypes[0] = NULL;
- return -1;
- }
- out_dtypes[2] = out_dtypes[0];
- Py_INCREF(out_dtypes[2]);
-
- type_num2 = NPY_TIMEDELTA;
- }
- else {
- goto type_reso_error;
- }
- }
- else if (PyTypeNum_ISINTEGER(type_num1) || PyTypeNum_ISBOOL(type_num1)) {
- /* int + m8[<A>] => m8[<A>] + m8[<A>] */
- if (type_num2 == NPY_TIMEDELTA) {
- out_dtypes[0] = ensure_dtype_nbo(PyArray_DESCR(operands[1]));
- if (out_dtypes[0] == NULL) {
- return -1;
- }
- out_dtypes[1] = out_dtypes[0];
- Py_INCREF(out_dtypes[1]);
- out_dtypes[2] = out_dtypes[0];
- Py_INCREF(out_dtypes[2]);
-
- type_num1 = NPY_TIMEDELTA;
- }
- else if (type_num2 == NPY_DATETIME) {
- /* Make a new NPY_TIMEDELTA, and copy type2's metadata */
- out_dtypes[0] = timedelta_dtype_with_copied_meta(
- PyArray_DESCR(operands[1]));
- if (out_dtypes[0] == NULL) {
- return -1;
- }
- out_dtypes[1] = ensure_dtype_nbo(PyArray_DESCR(operands[1]));
- if (out_dtypes[1] == NULL) {
- Py_DECREF(out_dtypes[0]);
- out_dtypes[0] = NULL;
- return -1;
- }
- out_dtypes[2] = out_dtypes[1];
- Py_INCREF(out_dtypes[2]);
-
- type_num1 = NPY_TIMEDELTA;
- }
- else {
- goto type_reso_error;
- }
- }
- else {
- goto type_reso_error;
- }
-
- /* Check against the casting rules */
- if (PyUFunc_ValidateCasting(ufunc, casting, operands, out_dtypes) < 0) {
- for (i = 0; i < 3; ++i) {
- Py_DECREF(out_dtypes[i]);
- out_dtypes[i] = NULL;
- }
- return -1;
- }
-
- /* Search in the functions list */
- types = ufunc->types;
- n = ufunc->ntypes;
-
- for (i = 0; i < n; ++i) {
- if (types[3*i] == type_num1 && types[3*i+1] == type_num2) {
- *out_innerloop = ufunc->functions[i];
- *out_innerloopdata = ufunc->data[i];
- return 0;
- }
- }
-
- PyErr_Format(PyExc_TypeError,
- "internal error: could not find appropriate datetime "
- "inner loop in %s ufunc", ufunc_name);
- return -1;
-
-type_reso_error: {
- PyObject *errmsg;
- errmsg = PyUString_FromFormat("ufunc %s cannot use operands "
- "with types ", ufunc_name);
- PyUString_ConcatAndDel(&errmsg,
- PyObject_Repr((PyObject *)PyArray_DESCR(operands[0])));
- PyUString_ConcatAndDel(&errmsg,
- PyUString_FromString(" and "));
- PyUString_ConcatAndDel(&errmsg,
- PyObject_Repr((PyObject *)PyArray_DESCR(operands[1])));
- PyErr_SetObject(PyExc_TypeError, errmsg);
- return -1;
- }
-}
-
-/*
- * This function applies the type resolution rules for subtraction.
- * In particular, there are a number of special cases with datetime:
- * m8[<A>] - m8[<B>] => m8[gcd(<A>,<B>)] - m8[gcd(<A>,<B>)]
- * m8[<A>] - int => m8[<A>] - m8[<A>]
- * int - m8[<A>] => m8[<A>] - m8[<A>]
- * M8[<A>] - int => M8[<A>] - m8[<A>]
- * M8[<A>] - m8[<B>] => M8[gcd(<A>,<B>)] - m8[gcd(<A>,<B>)]
- * TODO: Non-linear time unit cases require highly special-cased loops
- * M8[<A>] - m8[Y|M|B]
- */
-NPY_NO_EXPORT int
-PyUFunc_SubtractionTypeResolution(PyUFuncObject *ufunc,
- NPY_CASTING casting,
- PyArrayObject **operands,
- PyObject *type_tup,
- PyArray_Descr **out_dtypes,
- PyUFuncGenericFunction *out_innerloop,
- void **out_innerloopdata)
-{
- int type_num1, type_num2;
- char *types;
- int i, n;
- char *ufunc_name;
-
- ufunc_name = ufunc->name ? ufunc->name : "<unnamed ufunc>";
-
- type_num1 = PyArray_DESCR(operands[0])->type_num;
- type_num2 = PyArray_DESCR(operands[1])->type_num;
-
- /* Use the default when datetime and timedelta are not involved */
- if (!PyTypeNum_ISDATETIME(type_num1) && !PyTypeNum_ISDATETIME(type_num2)) {
- return PyUFunc_DefaultTypeResolution(ufunc, casting, operands,
- type_tup, out_dtypes, out_innerloop, out_innerloopdata);
- }
-
- if (type_num1 == NPY_TIMEDELTA) {
- /* m8[<A>] - m8[<B>] => m8[gcd(<A>,<B>)] - m8[gcd(<A>,<B>)] */
- if (type_num2 == NPY_TIMEDELTA) {
- out_dtypes[0] = PyArray_PromoteTypes(PyArray_DESCR(operands[0]),
- PyArray_DESCR(operands[1]));
- if (out_dtypes[0] == NULL) {
- return -1;
- }
- out_dtypes[1] = out_dtypes[0];
- Py_INCREF(out_dtypes[1]);
- out_dtypes[2] = out_dtypes[0];
- Py_INCREF(out_dtypes[2]);
- }
- /* m8[<A>] - int => m8[<A>] - m8[<A>] */
- else if (PyTypeNum_ISINTEGER(type_num2) ||
- PyTypeNum_ISBOOL(type_num2)) {
- out_dtypes[0] = ensure_dtype_nbo(PyArray_DESCR(operands[0]));
- if (out_dtypes[0] == NULL) {
- return -1;
- }
- out_dtypes[1] = out_dtypes[0];
- Py_INCREF(out_dtypes[1]);
- out_dtypes[2] = out_dtypes[0];
- Py_INCREF(out_dtypes[2]);
-
- type_num2 = NPY_TIMEDELTA;
- }
- else {
- goto type_reso_error;
- }
- }
- else if (type_num1 == NPY_DATETIME) {
- /* M8[<A>] - m8[<B>] => M8[gcd(<A>,<B>)] - m8[gcd(<A>,<B>)] */
- if (type_num2 == NPY_TIMEDELTA) {
- out_dtypes[0] = PyArray_PromoteTypes(PyArray_DESCR(operands[0]),
- PyArray_DESCR(operands[1]));
- if (out_dtypes[0] == NULL) {
- return -1;
- }
- /* Make a new NPY_TIMEDELTA, and copy the datetime's metadata */
- out_dtypes[1] = timedelta_dtype_with_copied_meta(out_dtypes[0]);
- if (out_dtypes[1] == NULL) {
- Py_DECREF(out_dtypes[0]);
- out_dtypes[0] = NULL;
- return -1;
- }
- out_dtypes[2] = out_dtypes[0];
- Py_INCREF(out_dtypes[2]);
- }
- /* M8[<A>] - int => M8[<A>] - m8[<A>] */
- else if (PyTypeNum_ISINTEGER(type_num2) ||
- PyTypeNum_ISBOOL(type_num2)) {
- out_dtypes[0] = ensure_dtype_nbo(PyArray_DESCR(operands[0]));
- if (out_dtypes[0] == NULL) {
- return -1;
- }
- /* Make a new NPY_TIMEDELTA, and copy type1's metadata */
- out_dtypes[1] = timedelta_dtype_with_copied_meta(
- PyArray_DESCR(operands[0]));
- if (out_dtypes[1] == NULL) {
- Py_DECREF(out_dtypes[0]);
- out_dtypes[0] = NULL;
- return -1;
- }
- out_dtypes[2] = out_dtypes[0];
- Py_INCREF(out_dtypes[2]);
-
- type_num2 = NPY_TIMEDELTA;
- }
- /* M8[<A>] - M8[<B>] => M8[gcd(<A>,<B>)] - M8[gcd(<A>,<B>)] */
- else if (type_num2 == NPY_DATETIME) {
- out_dtypes[0] = PyArray_PromoteTypes(PyArray_DESCR(operands[0]),
- PyArray_DESCR(operands[1]));
- if (out_dtypes[0] == NULL) {
- return -1;
- }
- /* Make a new NPY_TIMEDELTA, and copy type1's metadata */
- out_dtypes[2] = timedelta_dtype_with_copied_meta(out_dtypes[0]);
- if (out_dtypes[2] == NULL) {
- Py_DECREF(out_dtypes[0]);
- return -1;
- }
- out_dtypes[1] = out_dtypes[0];
- Py_INCREF(out_dtypes[1]);
- }
- else {
- goto type_reso_error;
- }
- }
- else if (PyTypeNum_ISINTEGER(type_num1) || PyTypeNum_ISBOOL(type_num1)) {
- /* int - m8[<A>] => m8[<A>] - m8[<A>] */
- if (type_num2 == NPY_TIMEDELTA) {
- out_dtypes[0] = ensure_dtype_nbo(PyArray_DESCR(operands[1]));
- if (out_dtypes[0] == NULL) {
- return -1;
- }
- out_dtypes[1] = out_dtypes[0];
- Py_INCREF(out_dtypes[1]);
- out_dtypes[2] = out_dtypes[0];
- Py_INCREF(out_dtypes[2]);
-
- type_num1 = NPY_TIMEDELTA;
- }
- else {
- goto type_reso_error;
- }
- }
- else {
- goto type_reso_error;
- }
-
- /* Check against the casting rules */
- if (PyUFunc_ValidateCasting(ufunc, casting, operands, out_dtypes) < 0) {
- for (i = 0; i < 3; ++i) {
- Py_DECREF(out_dtypes[i]);
- out_dtypes[i] = NULL;
- }
- return -1;
- }
-
- /* Search in the functions list */
- types = ufunc->types;
- n = ufunc->ntypes;
-
- for (i = 0; i < n; ++i) {
- if (types[3*i] == type_num1 && types[3*i+1] == type_num2) {
- *out_innerloop = ufunc->functions[i];
- *out_innerloopdata = ufunc->data[i];
- return 0;
- }
- }
-
- PyErr_Format(PyExc_TypeError,
- "internal error: could not find appropriate datetime "
- "inner loop in %s ufunc", ufunc_name);
- return -1;
-
-type_reso_error: {
- PyObject *errmsg;
- errmsg = PyUString_FromFormat("ufunc %s cannot use operands "
- "with types ", ufunc_name);
- PyUString_ConcatAndDel(&errmsg,
- PyObject_Repr((PyObject *)PyArray_DESCR(operands[0])));
- PyUString_ConcatAndDel(&errmsg,
- PyUString_FromString(" and "));
- PyUString_ConcatAndDel(&errmsg,
- PyObject_Repr((PyObject *)PyArray_DESCR(operands[1])));
- PyErr_SetObject(PyExc_TypeError, errmsg);
- return -1;
- }
-}
-
-/*
- * This function applies the type resolution rules for multiplication.
- * In particular, there are a number of special cases with datetime:
- * int## * m8[<A>] => int64 * m8[<A>]
- * m8[<A>] * int## => m8[<A>] * int64
- * float## * m8[<A>] => float64 * m8[<A>]
- * m8[<A>] * float## => m8[<A>] * float64
- */
-NPY_NO_EXPORT int
-PyUFunc_MultiplicationTypeResolution(PyUFuncObject *ufunc,
- NPY_CASTING casting,
- PyArrayObject **operands,
- PyObject *type_tup,
- PyArray_Descr **out_dtypes,
- PyUFuncGenericFunction *out_innerloop,
- void **out_innerloopdata)
-{
- int type_num1, type_num2;
- char *types;
- int i, n;
- char *ufunc_name;
-
- ufunc_name = ufunc->name ? ufunc->name : "<unnamed ufunc>";
-
- type_num1 = PyArray_DESCR(operands[0])->type_num;
- type_num2 = PyArray_DESCR(operands[1])->type_num;
-
- /* Use the default when datetime and timedelta are not involved */
- if (!PyTypeNum_ISDATETIME(type_num1) && !PyTypeNum_ISDATETIME(type_num2)) {
- return PyUFunc_DefaultTypeResolution(ufunc, casting, operands,
- type_tup, out_dtypes, out_innerloop, out_innerloopdata);
- }
-
- if (type_num1 == NPY_TIMEDELTA) {
- /* m8[<A>] * int## => m8[<A>] * int64 */
- if (PyTypeNum_ISINTEGER(type_num2) || PyTypeNum_ISBOOL(type_num2)) {
- out_dtypes[0] = ensure_dtype_nbo(PyArray_DESCR(operands[0]));
- if (out_dtypes[0] == NULL) {
- return -1;
- }
- out_dtypes[1] = PyArray_DescrNewFromType(NPY_LONGLONG);
- if (out_dtypes[1] == NULL) {
- Py_DECREF(out_dtypes[0]);
- out_dtypes[0] = NULL;
- return -1;
- }
- out_dtypes[2] = out_dtypes[0];
- Py_INCREF(out_dtypes[2]);
-
- type_num2 = NPY_LONGLONG;
- }
- /* m8[<A>] * float## => m8[<A>] * float64 */
- else if (PyTypeNum_ISFLOAT(type_num2)) {
- out_dtypes[0] = ensure_dtype_nbo(PyArray_DESCR(operands[0]));
- if (out_dtypes[0] == NULL) {
- return -1;
- }
- out_dtypes[1] = PyArray_DescrNewFromType(NPY_DOUBLE);
- if (out_dtypes[1] == NULL) {
- Py_DECREF(out_dtypes[0]);
- out_dtypes[0] = NULL;
- return -1;
- }
- out_dtypes[2] = out_dtypes[0];
- Py_INCREF(out_dtypes[2]);
-
- type_num2 = NPY_DOUBLE;
- }
- else {
- goto type_reso_error;
- }
- }
- else if (PyTypeNum_ISINTEGER(type_num1) || PyTypeNum_ISBOOL(type_num1)) {
- /* int## * m8[<A>] => int64 * m8[<A>] */
- if (type_num2 == NPY_TIMEDELTA) {
- out_dtypes[0] = PyArray_DescrNewFromType(NPY_LONGLONG);
- if (out_dtypes[0] == NULL) {
- return -1;
- }
- out_dtypes[1] = ensure_dtype_nbo(PyArray_DESCR(operands[1]));
- if (out_dtypes[1] == NULL) {
- Py_DECREF(out_dtypes[0]);
- out_dtypes[0] = NULL;
- return -1;
- }
- out_dtypes[2] = out_dtypes[1];
- Py_INCREF(out_dtypes[2]);
-
- type_num1 = NPY_LONGLONG;
- }
- else {
- goto type_reso_error;
- }
- }
- else if (PyTypeNum_ISFLOAT(type_num1)) {
- /* float## * m8[<A>] => float64 * m8[<A>] */
- if (type_num2 == NPY_TIMEDELTA) {
- out_dtypes[0] = PyArray_DescrNewFromType(NPY_DOUBLE);
- if (out_dtypes[0] == NULL) {
- return -1;
- }
- out_dtypes[1] = ensure_dtype_nbo(PyArray_DESCR(operands[1]));
- if (out_dtypes[1] == NULL) {
- Py_DECREF(out_dtypes[0]);
- out_dtypes[0] = NULL;
- return -1;
- }
- out_dtypes[2] = out_dtypes[1];
- Py_INCREF(out_dtypes[2]);
-
- type_num1 = NPY_DOUBLE;
- }
- else {
- goto type_reso_error;
- }
- }
- else {
- goto type_reso_error;
- }
-
- /* Check against the casting rules */
- if (PyUFunc_ValidateCasting(ufunc, casting, operands, out_dtypes) < 0) {
- for (i = 0; i < 3; ++i) {
- Py_DECREF(out_dtypes[i]);
- out_dtypes[i] = NULL;
- }
- return -1;
- }
-
- /* Search in the functions list */
- types = ufunc->types;
- n = ufunc->ntypes;
-
- for (i = 0; i < n; ++i) {
- if (types[3*i] == type_num1 && types[3*i+1] == type_num2) {
- *out_innerloop = ufunc->functions[i];
- *out_innerloopdata = ufunc->data[i];
- return 0;
- }
- }
-
- PyErr_Format(PyExc_TypeError,
- "internal error: could not find appropriate datetime "
- "inner loop in %s ufunc", ufunc_name);
- return -1;
-
-type_reso_error: {
- PyObject *errmsg;
- errmsg = PyUString_FromFormat("ufunc %s cannot use operands "
- "with types ", ufunc_name);
- PyUString_ConcatAndDel(&errmsg,
- PyObject_Repr((PyObject *)PyArray_DESCR(operands[0])));
- PyUString_ConcatAndDel(&errmsg,
- PyUString_FromString(" and "));
- PyUString_ConcatAndDel(&errmsg,
- PyObject_Repr((PyObject *)PyArray_DESCR(operands[1])));
- PyErr_SetObject(PyExc_TypeError, errmsg);
- return -1;
- }
-}
-
-/*
- * This function applies the type resolution rules for division.
- * In particular, there are a number of special cases with datetime:
- * m8[<A>] / m8[<B>] to m8[gcd(<A>,<B>)] / m8[gcd(<A>,<B>)] -> float64
- * m8[<A>] / int## to m8[<A>] / int64 -> m8[<A>]
- * m8[<A>] / float## to m8[<A>] / float64 -> m8[<A>]
- */
-NPY_NO_EXPORT int
-PyUFunc_DivisionTypeResolution(PyUFuncObject *ufunc,
- NPY_CASTING casting,
- PyArrayObject **operands,
- PyObject *type_tup,
- PyArray_Descr **out_dtypes,
- PyUFuncGenericFunction *out_innerloop,
- void **out_innerloopdata)
-{
- int type_num1, type_num2;
- char *types;
- int i, n;
- char *ufunc_name;
-
- ufunc_name = ufunc->name ? ufunc->name : "<unnamed ufunc>";
-
- type_num1 = PyArray_DESCR(operands[0])->type_num;
- type_num2 = PyArray_DESCR(operands[1])->type_num;
-
- /* Use the default when datetime and timedelta are not involved */
- if (!PyTypeNum_ISDATETIME(type_num1) && !PyTypeNum_ISDATETIME(type_num2)) {
- return PyUFunc_DefaultTypeResolution(ufunc, casting, operands,
- type_tup, out_dtypes, out_innerloop, out_innerloopdata);
- }
-
- if (type_num1 == NPY_TIMEDELTA) {
- /*
- * m8[<A>] / m8[<B>] to
- * m8[gcd(<A>,<B>)] / m8[gcd(<A>,<B>)] -> float64
- */
- if (type_num2 == NPY_TIMEDELTA) {
- out_dtypes[0] = PyArray_PromoteTypes(PyArray_DESCR(operands[0]),
- PyArray_DESCR(operands[1]));
- if (out_dtypes[0] == NULL) {
- return -1;
- }
- out_dtypes[1] = out_dtypes[0];
- Py_INCREF(out_dtypes[1]);
- out_dtypes[2] = PyArray_DescrFromType(NPY_DOUBLE);
- if (out_dtypes[2] == NULL) {
- Py_DECREF(out_dtypes[0]);
- out_dtypes[0] = NULL;
- Py_DECREF(out_dtypes[1]);
- out_dtypes[1] = NULL;
- return -1;
- }
- }
- /* m8[<A>] / int## => m8[<A>] / int64 */
- else if (PyTypeNum_ISINTEGER(type_num2)) {
- out_dtypes[0] = ensure_dtype_nbo(PyArray_DESCR(operands[0]));
- if (out_dtypes[0] == NULL) {
- return -1;
- }
- out_dtypes[1] = PyArray_DescrFromType(NPY_LONGLONG);
- if (out_dtypes[1] == NULL) {
- Py_DECREF(out_dtypes[0]);
- out_dtypes[0] = NULL;
- return -1;
- }
- out_dtypes[2] = out_dtypes[0];
- Py_INCREF(out_dtypes[2]);
-
- type_num2 = NPY_LONGLONG;
- }
- /* m8[<A>] / float## => m8[<A>] / float64 */
- else if (PyTypeNum_ISFLOAT(type_num2)) {
- out_dtypes[0] = ensure_dtype_nbo(PyArray_DESCR(operands[0]));
- if (out_dtypes[0] == NULL) {
- return -1;
- }
- out_dtypes[1] = PyArray_DescrNewFromType(NPY_DOUBLE);
- if (out_dtypes[1] == NULL) {
- Py_DECREF(out_dtypes[0]);
- out_dtypes[0] = NULL;
- return -1;
- }
- out_dtypes[2] = out_dtypes[0];
- Py_INCREF(out_dtypes[2]);
-
- type_num2 = NPY_DOUBLE;
- }
- else {
- goto type_reso_error;
- }
- }
- else {
- goto type_reso_error;
- }
-
- /* Check against the casting rules */
- if (PyUFunc_ValidateCasting(ufunc, casting, operands, out_dtypes) < 0) {
- for (i = 0; i < 3; ++i) {
- Py_DECREF(out_dtypes[i]);
- out_dtypes[i] = NULL;
- }
- return -1;
- }
-
- /* Search in the functions list */
- types = ufunc->types;
- n = ufunc->ntypes;
-
- for (i = 0; i < n; ++i) {
- if (types[3*i] == type_num1 && types[3*i+1] == type_num2) {
- *out_innerloop = ufunc->functions[i];
- *out_innerloopdata = ufunc->data[i];
- return 0;
- }
- }
-
- PyErr_Format(PyExc_TypeError,
- "internal error: could not find appropriate datetime "
- "inner loop in %s ufunc", ufunc_name);
- return -1;
-
-type_reso_error: {
- PyObject *errmsg;
- errmsg = PyUString_FromFormat("ufunc %s cannot use operands "
- "with types ", ufunc_name);
- PyUString_ConcatAndDel(&errmsg,
- PyObject_Repr((PyObject *)PyArray_DESCR(operands[0])));
- PyUString_ConcatAndDel(&errmsg,
- PyUString_FromString(" and "));
- PyUString_ConcatAndDel(&errmsg,
- PyObject_Repr((PyObject *)PyArray_DESCR(operands[1])));
- PyErr_SetObject(PyExc_TypeError, errmsg);
- return -1;
- }
-}
-
-/*UFUNC_API
- *
- * Validates that the input operands can be cast to
- * the input types, and the output types can be cast to
- * the output operands where provided.
- *
- * Returns 0 on success, -1 (with exception raised) on validation failure.
- */
-NPY_NO_EXPORT int
-PyUFunc_ValidateCasting(PyUFuncObject *ufunc,
- NPY_CASTING casting,
- PyArrayObject **operands,
- PyArray_Descr **dtypes)
-{
- int i, nin = ufunc->nin, nop = nin + ufunc->nout;
- char *ufunc_name;
-
- ufunc_name = ufunc->name ? ufunc->name : "<unnamed ufunc>";
-
- for (i = 0; i < nop; ++i) {
- if (i < nin) {
- if (!PyArray_CanCastArrayTo(operands[i], dtypes[i], casting)) {
- PyObject *errmsg;
- errmsg = PyUString_FromFormat("Cannot cast ufunc %s "
- "input from ", ufunc_name);
- PyUString_ConcatAndDel(&errmsg,
- PyObject_Repr((PyObject *)PyArray_DESCR(operands[i])));
- PyUString_ConcatAndDel(&errmsg,
- PyUString_FromString(" to "));
- PyUString_ConcatAndDel(&errmsg,
- PyObject_Repr((PyObject *)dtypes[i]));
- PyUString_ConcatAndDel(&errmsg,
- PyUString_FromFormat(" with casting rule %s",
- _casting_to_string(casting)));
- PyErr_SetObject(PyExc_TypeError, errmsg);
- return -1;
- }
- } else if (operands[i] != NULL) {
- if (!PyArray_CanCastTypeTo(dtypes[i],
- PyArray_DESCR(operands[i]), casting)) {
- PyObject *errmsg;
- errmsg = PyUString_FromFormat("Cannot cast ufunc %s "
- "output from ", ufunc_name);
- PyUString_ConcatAndDel(&errmsg,
- PyObject_Repr((PyObject *)dtypes[i]));
- PyUString_ConcatAndDel(&errmsg,
- PyUString_FromString(" to "));
- PyUString_ConcatAndDel(&errmsg,
- PyObject_Repr((PyObject *)PyArray_DESCR(operands[i])));
- PyUString_ConcatAndDel(&errmsg,
- PyUString_FromFormat(" with casting rule %s",
- _casting_to_string(casting)));
- PyErr_SetObject(PyExc_TypeError, errmsg);
- return -1;
- }
- }
- }
-
- return 0;
-}
-
static void
trivial_two_operand_loop(PyArrayObject **op,
PyUFuncGenericFunction innerloop,
diff --git a/numpy/core/src/umath/ufunc_object.h b/numpy/core/src/umath/ufunc_object.h
index 59754380c..a8886be05 100644
--- a/numpy/core/src/umath/ufunc_object.h
+++ b/numpy/core/src/umath/ufunc_object.h
@@ -7,84 +7,4 @@ ufunc_geterr(PyObject *NPY_UNUSED(dummy), PyObject *args);
NPY_NO_EXPORT PyObject *
ufunc_seterr(PyObject *NPY_UNUSED(dummy), PyObject *args);
-NPY_NO_EXPORT int
-PyUFunc_SimpleBinaryComparisonTypeResolution(PyUFuncObject *ufunc,
- NPY_CASTING casting,
- PyArrayObject **operands,
- PyObject *type_tup,
- PyArray_Descr **out_dtypes,
- PyUFuncGenericFunction *out_innerloop,
- void **out_innerloopdata);
-
-NPY_NO_EXPORT int
-PyUFunc_SimpleUnaryOperationTypeResolution(PyUFuncObject *ufunc,
- NPY_CASTING casting,
- PyArrayObject **operands,
- PyObject *type_tup,
- PyArray_Descr **out_dtypes,
- PyUFuncGenericFunction *out_innerloop,
- void **out_innerloopdata);
-
-NPY_NO_EXPORT int
-PyUFunc_OnesLikeTypeResolution(PyUFuncObject *ufunc,
- NPY_CASTING casting,
- PyArrayObject **operands,
- PyObject *type_tup,
- PyArray_Descr **out_dtypes,
- PyUFuncGenericFunction *out_innerloop,
- void **out_innerloopdata);
-
-NPY_NO_EXPORT int
-PyUFunc_SimpleBinaryOperationTypeResolution(PyUFuncObject *ufunc,
- NPY_CASTING casting,
- PyArrayObject **operands,
- PyObject *type_tup,
- PyArray_Descr **out_dtypes,
- PyUFuncGenericFunction *out_innerloop,
- void **out_innerloopdata);
-
-NPY_NO_EXPORT int
-PyUFunc_AbsoluteTypeResolution(PyUFuncObject *ufunc,
- NPY_CASTING casting,
- PyArrayObject **operands,
- PyObject *type_tup,
- PyArray_Descr **out_dtypes,
- PyUFuncGenericFunction *out_innerloop,
- void **out_innerloopdata);
-
-NPY_NO_EXPORT int
-PyUFunc_AdditionTypeResolution(PyUFuncObject *ufunc,
- NPY_CASTING casting,
- PyArrayObject **operands,
- PyObject *type_tup,
- PyArray_Descr **out_dtypes,
- PyUFuncGenericFunction *out_innerloop,
- void **out_innerloopdata);
-
-NPY_NO_EXPORT int
-PyUFunc_SubtractionTypeResolution(PyUFuncObject *ufunc,
- NPY_CASTING casting,
- PyArrayObject **operands,
- PyObject *type_tup,
- PyArray_Descr **out_dtypes,
- PyUFuncGenericFunction *out_innerloop,
- void **out_innerloopdata);
-
-NPY_NO_EXPORT int
-PyUFunc_MultiplicationTypeResolution(PyUFuncObject *ufunc,
- NPY_CASTING casting,
- PyArrayObject **operands,
- PyObject *type_tup,
- PyArray_Descr **out_dtypes,
- PyUFuncGenericFunction *out_innerloop,
- void **out_innerloopdata);
-NPY_NO_EXPORT int
-PyUFunc_DivisionTypeResolution(PyUFuncObject *ufunc,
- NPY_CASTING casting,
- PyArrayObject **operands,
- PyObject *type_tup,
- PyArray_Descr **out_dtypes,
- PyUFuncGenericFunction *out_innerloop,
- void **out_innerloopdata);
-
#endif
diff --git a/numpy/core/src/umath/ufunc_type_resolution.c b/numpy/core/src/umath/ufunc_type_resolution.c
new file mode 100644
index 000000000..7f12fcc87
--- /dev/null
+++ b/numpy/core/src/umath/ufunc_type_resolution.c
@@ -0,0 +1,2012 @@
+/*
+ * This file implements type resolution for NumPy element-wise ufuncs.
+ * This mechanism is still backwards-compatible with the pre-existing
+ * legacy mechanism, so performs much slower than is necessary.
+ *
+ * Written by Mark Wiebe (mwwiebe@gmail.com)
+ * Copyright (c) 2011 by Enthought, Inc.
+ *
+ * See LICENSE.txt for the license.
+ */
+#define _UMATHMODULE
+
+#include "Python.h"
+
+#include "npy_config.h"
+#ifdef ENABLE_SEPARATE_COMPILATION
+#define PY_ARRAY_UNIQUE_SYMBOL _npy_umathmodule_ARRAY_API
+#define NO_IMPORT_ARRAY
+#endif
+
+#include "numpy/npy_3kcompat.h"
+
+#include "numpy/ufuncobject.h"
+#include "ufunc_type_resolution.h"
+
+static const char *
+npy_casting_to_string(NPY_CASTING casting)
+{
+ switch (casting) {
+ case NPY_NO_CASTING:
+ return "'no'";
+ case NPY_EQUIV_CASTING:
+ return "'equiv'";
+ case NPY_SAFE_CASTING:
+ return "'safe'";
+ case NPY_SAME_KIND_CASTING:
+ return "'same_kind'";
+ case NPY_UNSAFE_CASTING:
+ return "'unsafe'";
+ default:
+ return "<unknown>";
+ }
+}
+/*UFUNC_API
+ *
+ * Validates that the input operands can be cast to
+ * the input types, and the output types can be cast to
+ * the output operands where provided.
+ *
+ * Returns 0 on success, -1 (with exception raised) on validation failure.
+ */
+NPY_NO_EXPORT int
+PyUFunc_ValidateCasting(PyUFuncObject *ufunc,
+ NPY_CASTING casting,
+ PyArrayObject **operands,
+ PyArray_Descr **dtypes)
+{
+ int i, nin = ufunc->nin, nop = nin + ufunc->nout;
+ char *ufunc_name;
+
+ ufunc_name = ufunc->name ? ufunc->name : "<unnamed ufunc>";
+
+ for (i = 0; i < nop; ++i) {
+ if (i < nin) {
+ if (!PyArray_CanCastArrayTo(operands[i], dtypes[i], casting)) {
+ PyObject *errmsg;
+ errmsg = PyUString_FromFormat("Cannot cast ufunc %s "
+ "input from ", ufunc_name);
+ PyUString_ConcatAndDel(&errmsg,
+ PyObject_Repr((PyObject *)PyArray_DESCR(operands[i])));
+ PyUString_ConcatAndDel(&errmsg,
+ PyUString_FromString(" to "));
+ PyUString_ConcatAndDel(&errmsg,
+ PyObject_Repr((PyObject *)dtypes[i]));
+ PyUString_ConcatAndDel(&errmsg,
+ PyUString_FromFormat(" with casting rule %s",
+ npy_casting_to_string(casting)));
+ PyErr_SetObject(PyExc_TypeError, errmsg);
+ return -1;
+ }
+ } else if (operands[i] != NULL) {
+ if (!PyArray_CanCastTypeTo(dtypes[i],
+ PyArray_DESCR(operands[i]), casting)) {
+ PyObject *errmsg;
+ errmsg = PyUString_FromFormat("Cannot cast ufunc %s "
+ "output from ", ufunc_name);
+ PyUString_ConcatAndDel(&errmsg,
+ PyObject_Repr((PyObject *)dtypes[i]));
+ PyUString_ConcatAndDel(&errmsg,
+ PyUString_FromString(" to "));
+ PyUString_ConcatAndDel(&errmsg,
+ PyObject_Repr((PyObject *)PyArray_DESCR(operands[i])));
+ PyUString_ConcatAndDel(&errmsg,
+ PyUString_FromFormat(" with casting rule %s",
+ npy_casting_to_string(casting)));
+ PyErr_SetObject(PyExc_TypeError, errmsg);
+ return -1;
+ }
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * Returns a new reference to type if it is already NBO, otherwise
+ * returns a copy converted to NBO.
+ */
+static PyArray_Descr *
+ensure_dtype_nbo(PyArray_Descr *type)
+{
+ if (PyArray_ISNBO(type->byteorder)) {
+ Py_INCREF(type);
+ return type;
+ }
+ else {
+ return PyArray_DescrNewByteorder(type, NPY_NATIVE);
+ }
+}
+
+/*UFUNC_API
+ *
+ * This function applies the default type resolution rules
+ * for the provided ufunc, filling out_dtypes, out_innerloop,
+ * and out_innerloopdata.
+ *
+ * Returns 0 on success, -1 on error.
+ */
+NPY_NO_EXPORT int
+PyUFunc_DefaultTypeResolution(PyUFuncObject *ufunc,
+ NPY_CASTING casting,
+ PyArrayObject **operands,
+ PyObject *type_tup,
+ PyArray_Descr **out_dtypes,
+ PyUFuncGenericFunction *out_innerloop,
+ void **out_innerloopdata)
+{
+ int i, nop = ufunc->nin + ufunc->nout;
+ int retval = 0, any_object = 0;
+ NPY_CASTING input_casting;
+
+ for (i = 0; i < nop; ++i) {
+ if (operands[i] != NULL &&
+ PyTypeNum_ISOBJECT(PyArray_DESCR(operands[i])->type_num)) {
+ any_object = 1;
+ break;
+ }
+ }
+
+ /*
+ * Decide the casting rules for inputs and outputs. We want
+ * NPY_SAFE_CASTING or stricter, so that the loop selection code
+ * doesn't choose an integer loop for float inputs, for example.
+ */
+ input_casting = (casting > NPY_SAFE_CASTING) ? NPY_SAFE_CASTING : casting;
+
+ if (type_tup == NULL) {
+ /* Find the best ufunc inner loop, and fill in the dtypes */
+ retval = find_best_ufunc_inner_loop(ufunc, operands,
+ input_casting, casting, any_object,
+ out_dtypes, out_innerloop, out_innerloopdata);
+ } else {
+ /* Find the specified ufunc inner loop, and fill in the dtypes */
+ retval = find_specified_ufunc_inner_loop(ufunc, type_tup,
+ operands, casting, any_object, out_dtypes,
+ out_innerloop, out_innerloopdata);
+ }
+
+ return retval;
+}
+
+/*
+ * This function applies special type resolution rules for the case
+ * where all the functions have the pattern XX->bool, using
+ * PyArray_ResultType instead of a linear search to get the best
+ * loop.
+ *
+ * Note that a simpler linear search through the functions loop
+ * is still done, but switching to a simple array lookup for
+ * built-in types would be better at some point.
+ *
+ * Returns 0 on success, -1 on error.
+ */
+NPY_NO_EXPORT int
+PyUFunc_SimpleBinaryComparisonTypeResolution(PyUFuncObject *ufunc,
+ NPY_CASTING casting,
+ PyArrayObject **operands,
+ PyObject *type_tup,
+ PyArray_Descr **out_dtypes,
+ PyUFuncGenericFunction *out_innerloop,
+ void **out_innerloopdata)
+{
+ int i, type_num, type_num1, type_num2;
+ char *ufunc_name;
+
+ ufunc_name = ufunc->name ? ufunc->name : "<unnamed ufunc>";
+
+ if (ufunc->nin != 2 || ufunc->nout != 1) {
+ PyErr_Format(PyExc_RuntimeError, "ufunc %s is configured "
+ "to use binary comparison type resolution but has "
+ "the wrong number of inputs or outputs",
+ ufunc_name);
+ return -1;
+ }
+
+ /*
+ * Use the default type resolution if there's a custom data type
+ * or object arrays.
+ */
+ type_num1 = PyArray_DESCR(operands[0])->type_num;
+ type_num2 = PyArray_DESCR(operands[1])->type_num;
+ if (type_num1 >= NPY_NTYPES || type_num2 >= NPY_NTYPES ||
+ type_num1 == NPY_OBJECT || type_num2 == NPY_OBJECT) {
+ return PyUFunc_DefaultTypeResolution(ufunc, casting, operands,
+ type_tup, out_dtypes, out_innerloop, out_innerloopdata);
+ }
+
+ if (type_tup == NULL) {
+ /* Input types are the result type */
+ out_dtypes[0] = PyArray_ResultType(2, operands, 0, NULL);
+ if (out_dtypes[0] == NULL) {
+ return -1;
+ }
+ out_dtypes[1] = out_dtypes[0];
+ Py_INCREF(out_dtypes[1]);
+ }
+ else {
+ /*
+ * If the type tuple isn't a single-element tuple, let the
+ * default type resolution handle this one.
+ */
+ if (!PyTuple_Check(type_tup) || PyTuple_GET_SIZE(type_tup) != 1) {
+ return PyUFunc_DefaultTypeResolution(ufunc, casting,
+ operands, type_tup, out_dtypes,
+ out_innerloop, out_innerloopdata);
+ }
+
+ if (!PyArray_DescrCheck(PyTuple_GET_ITEM(type_tup, 0))) {
+ PyErr_SetString(PyExc_ValueError,
+ "require data type in the type tuple");
+ return -1;
+ }
+
+ out_dtypes[0] = ensure_dtype_nbo(
+ (PyArray_Descr *)PyTuple_GET_ITEM(type_tup, 0));
+ if (out_dtypes[0] == NULL) {
+ return -1;
+ }
+ out_dtypes[1] = out_dtypes[0];
+ Py_INCREF(out_dtypes[1]);
+ }
+
+ /* Output type is always boolean */
+ out_dtypes[2] = PyArray_DescrFromType(NPY_BOOL);
+ if (out_dtypes[2] == NULL) {
+ for (i = 0; i < 2; ++i) {
+ Py_DECREF(out_dtypes[i]);
+ out_dtypes[i] = NULL;
+ }
+ return -1;
+ }
+
+ /* Check against the casting rules */
+ if (PyUFunc_ValidateCasting(ufunc, casting, operands, out_dtypes) < 0) {
+ for (i = 0; i < 3; ++i) {
+ Py_DECREF(out_dtypes[i]);
+ out_dtypes[i] = NULL;
+ }
+ return -1;
+ }
+
+ type_num = out_dtypes[0]->type_num;
+
+ /* If we have a built-in type, search in the functions list */
+ if (type_num < NPY_NTYPES) {
+ char *types = ufunc->types;
+ int n = ufunc->ntypes;
+
+ for (i = 0; i < n; ++i) {
+ if (types[3*i] == type_num) {
+ *out_innerloop = ufunc->functions[i];
+ *out_innerloopdata = ufunc->data[i];
+ return 0;
+ }
+ }
+
+ PyErr_Format(PyExc_TypeError,
+ "ufunc '%s' not supported for the input types",
+ ufunc_name);
+ return -1;
+ }
+ else {
+ PyErr_SetString(PyExc_RuntimeError,
+ "user type shouldn't have resulted from type promotion");
+ return -1;
+ }
+}
+
+/*
+ * This function applies special type resolution rules for the case
+ * where all the functions have the pattern X->X, copying
+ * the input descr directly so that metadata is maintained.
+ *
+ * Note that a simpler linear search through the functions loop
+ * is still done, but switching to a simple array lookup for
+ * built-in types would be better at some point.
+ *
+ * Returns 0 on success, -1 on error.
+ */
+NPY_NO_EXPORT int
+PyUFunc_SimpleUnaryOperationTypeResolution(PyUFuncObject *ufunc,
+ NPY_CASTING casting,
+ PyArrayObject **operands,
+ PyObject *type_tup,
+ PyArray_Descr **out_dtypes,
+ PyUFuncGenericFunction *out_innerloop,
+ void **out_innerloopdata)
+{
+ int i, type_num, type_num1;
+ char *ufunc_name;
+
+ ufunc_name = ufunc->name ? ufunc->name : "<unnamed ufunc>";
+
+ if (ufunc->nin != 1 || ufunc->nout != 1) {
+ PyErr_Format(PyExc_RuntimeError, "ufunc %s is configured "
+ "to use unary operation type resolution but has "
+ "the wrong number of inputs or outputs",
+ ufunc_name);
+ return -1;
+ }
+
+ /*
+ * Use the default type resolution if there's a custom data type
+ * or object arrays.
+ */
+ type_num1 = PyArray_DESCR(operands[0])->type_num;
+ if (type_num1 >= NPY_NTYPES || type_num1 == NPY_OBJECT) {
+ return PyUFunc_DefaultTypeResolution(ufunc, casting, operands,
+ type_tup, out_dtypes, out_innerloop, out_innerloopdata);
+ }
+
+ if (type_tup == NULL) {
+ /* Input types are the result type */
+ out_dtypes[0] = ensure_dtype_nbo(PyArray_DESCR(operands[0]));
+ if (out_dtypes[0] == NULL) {
+ return -1;
+ }
+ out_dtypes[1] = out_dtypes[0];
+ Py_INCREF(out_dtypes[1]);
+ }
+ else {
+ /*
+ * If the type tuple isn't a single-element tuple, let the
+ * default type resolution handle this one.
+ */
+ if (!PyTuple_Check(type_tup) || PyTuple_GET_SIZE(type_tup) != 1) {
+ return PyUFunc_DefaultTypeResolution(ufunc, casting,
+ operands, type_tup, out_dtypes,
+ out_innerloop, out_innerloopdata);
+ }
+
+ if (!PyArray_DescrCheck(PyTuple_GET_ITEM(type_tup, 0))) {
+ PyErr_SetString(PyExc_ValueError,
+ "require data type in the type tuple");
+ return -1;
+ }
+
+ out_dtypes[0] = ensure_dtype_nbo(
+ (PyArray_Descr *)PyTuple_GET_ITEM(type_tup, 0));
+ if (out_dtypes[0] == NULL) {
+ return -1;
+ }
+ out_dtypes[1] = out_dtypes[0];
+ Py_INCREF(out_dtypes[1]);
+ }
+
+ /* Check against the casting rules */
+ if (PyUFunc_ValidateCasting(ufunc, casting, operands, out_dtypes) < 0) {
+ for (i = 0; i < 2; ++i) {
+ Py_DECREF(out_dtypes[i]);
+ out_dtypes[i] = NULL;
+ }
+ return -1;
+ }
+
+ type_num = out_dtypes[0]->type_num;
+
+ /* If we have a built-in type, search in the functions list */
+ if (type_num < NPY_NTYPES) {
+ char *types = ufunc->types;
+ int n = ufunc->ntypes;
+
+ for (i = 0; i < n; ++i) {
+ if (types[2*i] == type_num) {
+ *out_innerloop = ufunc->functions[i];
+ *out_innerloopdata = ufunc->data[i];
+ return 0;
+ }
+ }
+
+ PyErr_Format(PyExc_TypeError,
+ "ufunc '%s' not supported for the input types",
+ ufunc_name);
+ return -1;
+ }
+ else {
+ PyErr_SetString(PyExc_RuntimeError,
+ "user type shouldn't have resulted from type promotion");
+ return -1;
+ }
+}
+
+/*
+ * The ones_like function shouldn't really be a ufunc, but while it
+ * still is, this provides type resolution that always forces UNSAFE
+ * casting.
+ */
+NPY_NO_EXPORT int
+PyUFunc_OnesLikeTypeResolution(PyUFuncObject *ufunc,
+ NPY_CASTING NPY_UNUSED(casting),
+ PyArrayObject **operands,
+ PyObject *type_tup,
+ PyArray_Descr **out_dtypes,
+ PyUFuncGenericFunction *out_innerloop,
+ void **out_innerloopdata)
+{
+ return PyUFunc_SimpleUnaryOperationTypeResolution(ufunc,
+ NPY_UNSAFE_CASTING,
+ operands, type_tup, out_dtypes,
+ out_innerloop, out_innerloopdata);
+}
+
+
+/*
+ * This function applies special type resolution rules for the case
+ * where all the functions have the pattern XX->X, using
+ * PyArray_ResultType instead of a linear search to get the best
+ * loop.
+ *
+ * Note that a simpler linear search through the functions loop
+ * is still done, but switching to a simple array lookup for
+ * built-in types would be better at some point.
+ *
+ * Returns 0 on success, -1 on error.
+ */
+NPY_NO_EXPORT int
+PyUFunc_SimpleBinaryOperationTypeResolution(PyUFuncObject *ufunc,
+ NPY_CASTING casting,
+ PyArrayObject **operands,
+ PyObject *type_tup,
+ PyArray_Descr **out_dtypes,
+ PyUFuncGenericFunction *out_innerloop,
+ void **out_innerloopdata)
+{
+ int i, type_num, type_num1, type_num2;
+ char *ufunc_name;
+
+ ufunc_name = ufunc->name ? ufunc->name : "<unnamed ufunc>";
+
+ if (ufunc->nin != 2 || ufunc->nout != 1) {
+ PyErr_Format(PyExc_RuntimeError, "ufunc %s is configured "
+ "to use binary operation type resolution but has "
+ "the wrong number of inputs or outputs",
+ ufunc_name);
+ return -1;
+ }
+
+ /*
+ * Use the default type resolution if there's a custom data type
+ * or object arrays.
+ */
+ type_num1 = PyArray_DESCR(operands[0])->type_num;
+ type_num2 = PyArray_DESCR(operands[1])->type_num;
+ if (type_num1 >= NPY_NTYPES || type_num2 >= NPY_NTYPES ||
+ type_num1 == NPY_OBJECT || type_num2 == NPY_OBJECT) {
+ return PyUFunc_DefaultTypeResolution(ufunc, casting, operands,
+ type_tup, out_dtypes, out_innerloop, out_innerloopdata);
+ }
+
+ if (type_tup == NULL) {
+ /* Input types are the result type */
+ out_dtypes[0] = PyArray_ResultType(2, operands, 0, NULL);
+ if (out_dtypes[0] == NULL) {
+ return -1;
+ }
+ out_dtypes[1] = out_dtypes[0];
+ Py_INCREF(out_dtypes[1]);
+ out_dtypes[2] = out_dtypes[0];
+ Py_INCREF(out_dtypes[2]);
+ }
+ else {
+ /*
+ * If the type tuple isn't a single-element tuple, let the
+ * default type resolution handle this one.
+ */
+ if (!PyTuple_Check(type_tup) || PyTuple_GET_SIZE(type_tup) != 1) {
+ return PyUFunc_DefaultTypeResolution(ufunc, casting,
+ operands, type_tup, out_dtypes,
+ out_innerloop, out_innerloopdata);
+ }
+
+ if (!PyArray_DescrCheck(PyTuple_GET_ITEM(type_tup, 0))) {
+ PyErr_SetString(PyExc_ValueError,
+ "require data type in the type tuple");
+ return -1;
+ }
+
+ out_dtypes[0] = ensure_dtype_nbo(
+ (PyArray_Descr *)PyTuple_GET_ITEM(type_tup, 0));
+ if (out_dtypes[0] == NULL) {
+ return -1;
+ }
+ out_dtypes[1] = out_dtypes[0];
+ Py_INCREF(out_dtypes[1]);
+ out_dtypes[2] = out_dtypes[0];
+ Py_INCREF(out_dtypes[2]);
+ }
+
+ /* Check against the casting rules */
+ if (PyUFunc_ValidateCasting(ufunc, casting, operands, out_dtypes) < 0) {
+ for (i = 0; i < 3; ++i) {
+ Py_DECREF(out_dtypes[i]);
+ out_dtypes[i] = NULL;
+ }
+ return -1;
+ }
+
+ type_num = out_dtypes[0]->type_num;
+
+ /* If we have a built-in type, search in the functions list */
+ if (type_num < NPY_NTYPES) {
+ char *types = ufunc->types;
+ int n = ufunc->ntypes;
+
+ for (i = 0; i < n; ++i) {
+ if (types[3*i] == type_num) {
+ *out_innerloop = ufunc->functions[i];
+ *out_innerloopdata = ufunc->data[i];
+ return 0;
+ }
+ }
+
+ PyErr_Format(PyExc_TypeError,
+ "ufunc '%s' not supported for the input types",
+ ufunc_name);
+ return -1;
+ }
+ else {
+ PyErr_SetString(PyExc_RuntimeError,
+ "user type shouldn't have resulted from type promotion");
+ return -1;
+ }
+}
+
+/*
+ * This function applies special type resolution rules for the absolute
+ * ufunc. This ufunc converts complex -> float, so isn't covered
+ * by the simple unary type resolution.
+ *
+ * Returns 0 on success, -1 on error.
+ */
+NPY_NO_EXPORT int
+PyUFunc_AbsoluteTypeResolution(PyUFuncObject *ufunc,
+ NPY_CASTING casting,
+ PyArrayObject **operands,
+ PyObject *type_tup,
+ PyArray_Descr **out_dtypes,
+ PyUFuncGenericFunction *out_innerloop,
+ void **out_innerloopdata)
+{
+ /* Use the default for complex types, to find the loop producing float */
+ if (PyTypeNum_ISCOMPLEX(PyArray_DESCR(operands[0])->type_num)) {
+ return PyUFunc_DefaultTypeResolution(ufunc, casting, operands,
+ type_tup, out_dtypes, out_innerloop, out_innerloopdata);
+ }
+ else {
+ return PyUFunc_SimpleUnaryOperationTypeResolution(ufunc, casting,
+ operands, type_tup, out_dtypes,
+ out_innerloop, out_innerloopdata);
+ }
+}
+
+
+/*
+ * This function returns the a new reference to the
+ * capsule with the datetime metadata.
+ *
+ * NOTE: This function is copied from datetime.c in multiarray,
+ * because umath and multiarray are not linked together.
+ */
+static PyObject *
+get_datetime_metacobj_from_dtype(PyArray_Descr *dtype)
+{
+ PyObject *metacobj;
+
+ /* Check that the dtype has metadata */
+ if (dtype->metadata == NULL) {
+ PyErr_SetString(PyExc_TypeError,
+ "Datetime type object is invalid, lacks metadata");
+ return NULL;
+ }
+
+ /* Check that the dtype has unit metadata */
+ metacobj = PyDict_GetItemString(dtype->metadata, NPY_METADATA_DTSTR);
+ if (metacobj == NULL) {
+ PyErr_SetString(PyExc_TypeError,
+ "Datetime type object is invalid, lacks unit metadata");
+ return NULL;
+ }
+
+ Py_INCREF(metacobj);
+ return metacobj;
+}
+
+/*
+ * Creates a new NPY_TIMEDELTA dtype, copying the datetime metadata
+ * from the given dtype.
+ *
+ * NOTE: This function is copied from datetime.c in multiarray,
+ * because umath and multiarray are not linked together.
+ */
+static PyArray_Descr *
+timedelta_dtype_with_copied_meta(PyArray_Descr *dtype)
+{
+ PyArray_Descr *ret;
+ PyObject *metacobj;
+
+ ret = PyArray_DescrNewFromType(NPY_TIMEDELTA);
+ if (ret == NULL) {
+ return NULL;
+ }
+ Py_XDECREF(ret->metadata);
+ ret->metadata = PyDict_New();
+ if (ret->metadata == NULL) {
+ Py_DECREF(ret);
+ return NULL;
+ }
+
+ metacobj = get_datetime_metacobj_from_dtype(dtype);
+ if (metacobj == NULL) {
+ Py_DECREF(ret);
+ return NULL;
+ }
+
+ if (PyDict_SetItemString(ret->metadata, NPY_METADATA_DTSTR,
+ metacobj) < 0) {
+ Py_DECREF(metacobj);
+ Py_DECREF(ret);
+ return NULL;
+ }
+
+ return ret;
+}
+
+/*
+ * This function applies the type resolution rules for addition.
+ * In particular, there are a number of special cases with datetime:
+ * m8[<A>] + m8[<B>] => m8[gcd(<A>,<B>)] + m8[gcd(<A>,<B>)]
+ * m8[<A>] + int => m8[<A>] + m8[<A>]
+ * int + m8[<A>] => m8[<A>] + m8[<A>]
+ * M8[<A>] + int => M8[<A>] + m8[<A>]
+ * int + M8[<A>] => m8[<A>] + M8[<A>]
+ * M8[<A>] + m8[<B>] => M8[gcd(<A>,<B>)] + m8[gcd(<A>,<B>)]
+ * m8[<A>] + M8[<B>] => m8[gcd(<A>,<B>)] + M8[gcd(<A>,<B>)]
+ * TODO: Non-linear time unit cases require highly special-cased loops
+ * M8[<A>] + m8[Y|M|B]
+ * m8[Y|M|B] + M8[<A>]
+ */
+NPY_NO_EXPORT int
+PyUFunc_AdditionTypeResolution(PyUFuncObject *ufunc,
+ NPY_CASTING casting,
+ PyArrayObject **operands,
+ PyObject *type_tup,
+ PyArray_Descr **out_dtypes,
+ PyUFuncGenericFunction *out_innerloop,
+ void **out_innerloopdata)
+{
+ int type_num1, type_num2;
+ char *types;
+ int i, n;
+ char *ufunc_name;
+
+ ufunc_name = ufunc->name ? ufunc->name : "<unnamed ufunc>";
+
+ type_num1 = PyArray_DESCR(operands[0])->type_num;
+ type_num2 = PyArray_DESCR(operands[1])->type_num;
+
+ /* Use the default when datetime and timedelta are not involved */
+ if (!PyTypeNum_ISDATETIME(type_num1) && !PyTypeNum_ISDATETIME(type_num2)) {
+ return PyUFunc_DefaultTypeResolution(ufunc, casting, operands,
+ type_tup, out_dtypes, out_innerloop, out_innerloopdata);
+ }
+
+ if (type_num1 == NPY_TIMEDELTA) {
+ /* m8[<A>] + m8[<B>] => m8[gcd(<A>,<B>)] + m8[gcd(<A>,<B>)] */
+ if (type_num2 == NPY_TIMEDELTA) {
+ out_dtypes[0] = PyArray_PromoteTypes(PyArray_DESCR(operands[0]),
+ PyArray_DESCR(operands[1]));
+ if (out_dtypes[0] == NULL) {
+ return -1;
+ }
+ out_dtypes[1] = out_dtypes[0];
+ Py_INCREF(out_dtypes[1]);
+ out_dtypes[2] = out_dtypes[0];
+ Py_INCREF(out_dtypes[2]);
+ }
+ /* m8[<A>] + M8[<B>] => m8[gcd(<A>,<B>)] + M8[gcd(<A>,<B>)] */
+ else if (type_num2 == NPY_DATETIME) {
+ out_dtypes[1] = PyArray_PromoteTypes(PyArray_DESCR(operands[0]),
+ PyArray_DESCR(operands[1]));
+ if (out_dtypes[1] == NULL) {
+ return -1;
+ }
+ /* Make a new NPY_TIMEDELTA, and copy the datetime's metadata */
+ out_dtypes[0] = timedelta_dtype_with_copied_meta(out_dtypes[1]);
+ if (out_dtypes[0] == NULL) {
+ Py_DECREF(out_dtypes[1]);
+ out_dtypes[1] = NULL;
+ return -1;
+ }
+ out_dtypes[2] = out_dtypes[1];
+ Py_INCREF(out_dtypes[2]);
+ }
+ /* m8[<A>] + int => m8[<A>] + m8[<A>] */
+ else if (PyTypeNum_ISINTEGER(type_num2) ||
+ PyTypeNum_ISBOOL(type_num2)) {
+ out_dtypes[0] = ensure_dtype_nbo(PyArray_DESCR(operands[0]));
+ if (out_dtypes[0] == NULL) {
+ return -1;
+ }
+ out_dtypes[1] = out_dtypes[0];
+ Py_INCREF(out_dtypes[1]);
+ out_dtypes[2] = out_dtypes[0];
+ Py_INCREF(out_dtypes[2]);
+
+ type_num2 = NPY_TIMEDELTA;
+ }
+ else {
+ goto type_reso_error;
+ }
+ }
+ else if (type_num1 == NPY_DATETIME) {
+ /* M8[<A>] + m8[<B>] => M8[gcd(<A>,<B>)] + m8[gcd(<A>,<B>)] */
+ if (type_num2 == NPY_TIMEDELTA) {
+ out_dtypes[0] = PyArray_PromoteTypes(PyArray_DESCR(operands[0]),
+ PyArray_DESCR(operands[1]));
+ if (out_dtypes[0] == NULL) {
+ return -1;
+ }
+ /* Make a new NPY_TIMEDELTA, and copy the datetime's metadata */
+ out_dtypes[1] = timedelta_dtype_with_copied_meta(out_dtypes[0]);
+ if (out_dtypes[1] == NULL) {
+ Py_DECREF(out_dtypes[0]);
+ out_dtypes[0] = NULL;
+ return -1;
+ }
+ out_dtypes[2] = out_dtypes[0];
+ Py_INCREF(out_dtypes[2]);
+ }
+ /* M8[<A>] + int => M8[<A>] + m8[<A>] */
+ else if (PyTypeNum_ISINTEGER(type_num2) ||
+ PyTypeNum_ISBOOL(type_num2)) {
+ out_dtypes[0] = ensure_dtype_nbo(PyArray_DESCR(operands[0]));
+ if (out_dtypes[0] == NULL) {
+ return -1;
+ }
+ /* Make a new NPY_TIMEDELTA, and copy type1's metadata */
+ out_dtypes[1] = timedelta_dtype_with_copied_meta(
+ PyArray_DESCR(operands[0]));
+ if (out_dtypes[1] == NULL) {
+ Py_DECREF(out_dtypes[0]);
+ out_dtypes[0] = NULL;
+ return -1;
+ }
+ out_dtypes[2] = out_dtypes[0];
+ Py_INCREF(out_dtypes[2]);
+
+ type_num2 = NPY_TIMEDELTA;
+ }
+ else {
+ goto type_reso_error;
+ }
+ }
+ else if (PyTypeNum_ISINTEGER(type_num1) || PyTypeNum_ISBOOL(type_num1)) {
+ /* int + m8[<A>] => m8[<A>] + m8[<A>] */
+ if (type_num2 == NPY_TIMEDELTA) {
+ out_dtypes[0] = ensure_dtype_nbo(PyArray_DESCR(operands[1]));
+ if (out_dtypes[0] == NULL) {
+ return -1;
+ }
+ out_dtypes[1] = out_dtypes[0];
+ Py_INCREF(out_dtypes[1]);
+ out_dtypes[2] = out_dtypes[0];
+ Py_INCREF(out_dtypes[2]);
+
+ type_num1 = NPY_TIMEDELTA;
+ }
+ else if (type_num2 == NPY_DATETIME) {
+ /* Make a new NPY_TIMEDELTA, and copy type2's metadata */
+ out_dtypes[0] = timedelta_dtype_with_copied_meta(
+ PyArray_DESCR(operands[1]));
+ if (out_dtypes[0] == NULL) {
+ return -1;
+ }
+ out_dtypes[1] = ensure_dtype_nbo(PyArray_DESCR(operands[1]));
+ if (out_dtypes[1] == NULL) {
+ Py_DECREF(out_dtypes[0]);
+ out_dtypes[0] = NULL;
+ return -1;
+ }
+ out_dtypes[2] = out_dtypes[1];
+ Py_INCREF(out_dtypes[2]);
+
+ type_num1 = NPY_TIMEDELTA;
+ }
+ else {
+ goto type_reso_error;
+ }
+ }
+ else {
+ goto type_reso_error;
+ }
+
+ /* Check against the casting rules */
+ if (PyUFunc_ValidateCasting(ufunc, casting, operands, out_dtypes) < 0) {
+ for (i = 0; i < 3; ++i) {
+ Py_DECREF(out_dtypes[i]);
+ out_dtypes[i] = NULL;
+ }
+ return -1;
+ }
+
+ /* Search in the functions list */
+ types = ufunc->types;
+ n = ufunc->ntypes;
+
+ for (i = 0; i < n; ++i) {
+ if (types[3*i] == type_num1 && types[3*i+1] == type_num2) {
+ *out_innerloop = ufunc->functions[i];
+ *out_innerloopdata = ufunc->data[i];
+ return 0;
+ }
+ }
+
+ PyErr_Format(PyExc_TypeError,
+ "internal error: could not find appropriate datetime "
+ "inner loop in %s ufunc", ufunc_name);
+ return -1;
+
+type_reso_error: {
+ PyObject *errmsg;
+ errmsg = PyUString_FromFormat("ufunc %s cannot use operands "
+ "with types ", ufunc_name);
+ PyUString_ConcatAndDel(&errmsg,
+ PyObject_Repr((PyObject *)PyArray_DESCR(operands[0])));
+ PyUString_ConcatAndDel(&errmsg,
+ PyUString_FromString(" and "));
+ PyUString_ConcatAndDel(&errmsg,
+ PyObject_Repr((PyObject *)PyArray_DESCR(operands[1])));
+ PyErr_SetObject(PyExc_TypeError, errmsg);
+ return -1;
+ }
+}
+
+/*
+ * This function applies the type resolution rules for subtraction.
+ * In particular, there are a number of special cases with datetime:
+ * m8[<A>] - m8[<B>] => m8[gcd(<A>,<B>)] - m8[gcd(<A>,<B>)]
+ * m8[<A>] - int => m8[<A>] - m8[<A>]
+ * int - m8[<A>] => m8[<A>] - m8[<A>]
+ * M8[<A>] - int => M8[<A>] - m8[<A>]
+ * M8[<A>] - m8[<B>] => M8[gcd(<A>,<B>)] - m8[gcd(<A>,<B>)]
+ * TODO: Non-linear time unit cases require highly special-cased loops
+ * M8[<A>] - m8[Y|M|B]
+ */
+NPY_NO_EXPORT int
+PyUFunc_SubtractionTypeResolution(PyUFuncObject *ufunc,
+ NPY_CASTING casting,
+ PyArrayObject **operands,
+ PyObject *type_tup,
+ PyArray_Descr **out_dtypes,
+ PyUFuncGenericFunction *out_innerloop,
+ void **out_innerloopdata)
+{
+ int type_num1, type_num2;
+ char *types;
+ int i, n;
+ char *ufunc_name;
+
+ ufunc_name = ufunc->name ? ufunc->name : "<unnamed ufunc>";
+
+ type_num1 = PyArray_DESCR(operands[0])->type_num;
+ type_num2 = PyArray_DESCR(operands[1])->type_num;
+
+ /* Use the default when datetime and timedelta are not involved */
+ if (!PyTypeNum_ISDATETIME(type_num1) && !PyTypeNum_ISDATETIME(type_num2)) {
+ return PyUFunc_DefaultTypeResolution(ufunc, casting, operands,
+ type_tup, out_dtypes, out_innerloop, out_innerloopdata);
+ }
+
+ if (type_num1 == NPY_TIMEDELTA) {
+ /* m8[<A>] - m8[<B>] => m8[gcd(<A>,<B>)] - m8[gcd(<A>,<B>)] */
+ if (type_num2 == NPY_TIMEDELTA) {
+ out_dtypes[0] = PyArray_PromoteTypes(PyArray_DESCR(operands[0]),
+ PyArray_DESCR(operands[1]));
+ if (out_dtypes[0] == NULL) {
+ return -1;
+ }
+ out_dtypes[1] = out_dtypes[0];
+ Py_INCREF(out_dtypes[1]);
+ out_dtypes[2] = out_dtypes[0];
+ Py_INCREF(out_dtypes[2]);
+ }
+ /* m8[<A>] - int => m8[<A>] - m8[<A>] */
+ else if (PyTypeNum_ISINTEGER(type_num2) ||
+ PyTypeNum_ISBOOL(type_num2)) {
+ out_dtypes[0] = ensure_dtype_nbo(PyArray_DESCR(operands[0]));
+ if (out_dtypes[0] == NULL) {
+ return -1;
+ }
+ out_dtypes[1] = out_dtypes[0];
+ Py_INCREF(out_dtypes[1]);
+ out_dtypes[2] = out_dtypes[0];
+ Py_INCREF(out_dtypes[2]);
+
+ type_num2 = NPY_TIMEDELTA;
+ }
+ else {
+ goto type_reso_error;
+ }
+ }
+ else if (type_num1 == NPY_DATETIME) {
+ /* M8[<A>] - m8[<B>] => M8[gcd(<A>,<B>)] - m8[gcd(<A>,<B>)] */
+ if (type_num2 == NPY_TIMEDELTA) {
+ out_dtypes[0] = PyArray_PromoteTypes(PyArray_DESCR(operands[0]),
+ PyArray_DESCR(operands[1]));
+ if (out_dtypes[0] == NULL) {
+ return -1;
+ }
+ /* Make a new NPY_TIMEDELTA, and copy the datetime's metadata */
+ out_dtypes[1] = timedelta_dtype_with_copied_meta(out_dtypes[0]);
+ if (out_dtypes[1] == NULL) {
+ Py_DECREF(out_dtypes[0]);
+ out_dtypes[0] = NULL;
+ return -1;
+ }
+ out_dtypes[2] = out_dtypes[0];
+ Py_INCREF(out_dtypes[2]);
+ }
+ /* M8[<A>] - int => M8[<A>] - m8[<A>] */
+ else if (PyTypeNum_ISINTEGER(type_num2) ||
+ PyTypeNum_ISBOOL(type_num2)) {
+ out_dtypes[0] = ensure_dtype_nbo(PyArray_DESCR(operands[0]));
+ if (out_dtypes[0] == NULL) {
+ return -1;
+ }
+ /* Make a new NPY_TIMEDELTA, and copy type1's metadata */
+ out_dtypes[1] = timedelta_dtype_with_copied_meta(
+ PyArray_DESCR(operands[0]));
+ if (out_dtypes[1] == NULL) {
+ Py_DECREF(out_dtypes[0]);
+ out_dtypes[0] = NULL;
+ return -1;
+ }
+ out_dtypes[2] = out_dtypes[0];
+ Py_INCREF(out_dtypes[2]);
+
+ type_num2 = NPY_TIMEDELTA;
+ }
+ /* M8[<A>] - M8[<B>] => M8[gcd(<A>,<B>)] - M8[gcd(<A>,<B>)] */
+ else if (type_num2 == NPY_DATETIME) {
+ out_dtypes[0] = PyArray_PromoteTypes(PyArray_DESCR(operands[0]),
+ PyArray_DESCR(operands[1]));
+ if (out_dtypes[0] == NULL) {
+ return -1;
+ }
+ /* Make a new NPY_TIMEDELTA, and copy type1's metadata */
+ out_dtypes[2] = timedelta_dtype_with_copied_meta(out_dtypes[0]);
+ if (out_dtypes[2] == NULL) {
+ Py_DECREF(out_dtypes[0]);
+ return -1;
+ }
+ out_dtypes[1] = out_dtypes[0];
+ Py_INCREF(out_dtypes[1]);
+ }
+ else {
+ goto type_reso_error;
+ }
+ }
+ else if (PyTypeNum_ISINTEGER(type_num1) || PyTypeNum_ISBOOL(type_num1)) {
+ /* int - m8[<A>] => m8[<A>] - m8[<A>] */
+ if (type_num2 == NPY_TIMEDELTA) {
+ out_dtypes[0] = ensure_dtype_nbo(PyArray_DESCR(operands[1]));
+ if (out_dtypes[0] == NULL) {
+ return -1;
+ }
+ out_dtypes[1] = out_dtypes[0];
+ Py_INCREF(out_dtypes[1]);
+ out_dtypes[2] = out_dtypes[0];
+ Py_INCREF(out_dtypes[2]);
+
+ type_num1 = NPY_TIMEDELTA;
+ }
+ else {
+ goto type_reso_error;
+ }
+ }
+ else {
+ goto type_reso_error;
+ }
+
+ /* Check against the casting rules */
+ if (PyUFunc_ValidateCasting(ufunc, casting, operands, out_dtypes) < 0) {
+ for (i = 0; i < 3; ++i) {
+ Py_DECREF(out_dtypes[i]);
+ out_dtypes[i] = NULL;
+ }
+ return -1;
+ }
+
+ /* Search in the functions list */
+ types = ufunc->types;
+ n = ufunc->ntypes;
+
+ for (i = 0; i < n; ++i) {
+ if (types[3*i] == type_num1 && types[3*i+1] == type_num2) {
+ *out_innerloop = ufunc->functions[i];
+ *out_innerloopdata = ufunc->data[i];
+ return 0;
+ }
+ }
+
+ PyErr_Format(PyExc_TypeError,
+ "internal error: could not find appropriate datetime "
+ "inner loop in %s ufunc", ufunc_name);
+ return -1;
+
+type_reso_error: {
+ PyObject *errmsg;
+ errmsg = PyUString_FromFormat("ufunc %s cannot use operands "
+ "with types ", ufunc_name);
+ PyUString_ConcatAndDel(&errmsg,
+ PyObject_Repr((PyObject *)PyArray_DESCR(operands[0])));
+ PyUString_ConcatAndDel(&errmsg,
+ PyUString_FromString(" and "));
+ PyUString_ConcatAndDel(&errmsg,
+ PyObject_Repr((PyObject *)PyArray_DESCR(operands[1])));
+ PyErr_SetObject(PyExc_TypeError, errmsg);
+ return -1;
+ }
+}
+
+/*
+ * This function applies the type resolution rules for multiplication.
+ * In particular, there are a number of special cases with datetime:
+ * int## * m8[<A>] => int64 * m8[<A>]
+ * m8[<A>] * int## => m8[<A>] * int64
+ * float## * m8[<A>] => float64 * m8[<A>]
+ * m8[<A>] * float## => m8[<A>] * float64
+ */
+NPY_NO_EXPORT int
+PyUFunc_MultiplicationTypeResolution(PyUFuncObject *ufunc,
+ NPY_CASTING casting,
+ PyArrayObject **operands,
+ PyObject *type_tup,
+ PyArray_Descr **out_dtypes,
+ PyUFuncGenericFunction *out_innerloop,
+ void **out_innerloopdata)
+{
+ int type_num1, type_num2;
+ char *types;
+ int i, n;
+ char *ufunc_name;
+
+ ufunc_name = ufunc->name ? ufunc->name : "<unnamed ufunc>";
+
+ type_num1 = PyArray_DESCR(operands[0])->type_num;
+ type_num2 = PyArray_DESCR(operands[1])->type_num;
+
+ /* Use the default when datetime and timedelta are not involved */
+ if (!PyTypeNum_ISDATETIME(type_num1) && !PyTypeNum_ISDATETIME(type_num2)) {
+ return PyUFunc_DefaultTypeResolution(ufunc, casting, operands,
+ type_tup, out_dtypes, out_innerloop, out_innerloopdata);
+ }
+
+ if (type_num1 == NPY_TIMEDELTA) {
+ /* m8[<A>] * int## => m8[<A>] * int64 */
+ if (PyTypeNum_ISINTEGER(type_num2) || PyTypeNum_ISBOOL(type_num2)) {
+ out_dtypes[0] = ensure_dtype_nbo(PyArray_DESCR(operands[0]));
+ if (out_dtypes[0] == NULL) {
+ return -1;
+ }
+ out_dtypes[1] = PyArray_DescrNewFromType(NPY_LONGLONG);
+ if (out_dtypes[1] == NULL) {
+ Py_DECREF(out_dtypes[0]);
+ out_dtypes[0] = NULL;
+ return -1;
+ }
+ out_dtypes[2] = out_dtypes[0];
+ Py_INCREF(out_dtypes[2]);
+
+ type_num2 = NPY_LONGLONG;
+ }
+ /* m8[<A>] * float## => m8[<A>] * float64 */
+ else if (PyTypeNum_ISFLOAT(type_num2)) {
+ out_dtypes[0] = ensure_dtype_nbo(PyArray_DESCR(operands[0]));
+ if (out_dtypes[0] == NULL) {
+ return -1;
+ }
+ out_dtypes[1] = PyArray_DescrNewFromType(NPY_DOUBLE);
+ if (out_dtypes[1] == NULL) {
+ Py_DECREF(out_dtypes[0]);
+ out_dtypes[0] = NULL;
+ return -1;
+ }
+ out_dtypes[2] = out_dtypes[0];
+ Py_INCREF(out_dtypes[2]);
+
+ type_num2 = NPY_DOUBLE;
+ }
+ else {
+ goto type_reso_error;
+ }
+ }
+ else if (PyTypeNum_ISINTEGER(type_num1) || PyTypeNum_ISBOOL(type_num1)) {
+ /* int## * m8[<A>] => int64 * m8[<A>] */
+ if (type_num2 == NPY_TIMEDELTA) {
+ out_dtypes[0] = PyArray_DescrNewFromType(NPY_LONGLONG);
+ if (out_dtypes[0] == NULL) {
+ return -1;
+ }
+ out_dtypes[1] = ensure_dtype_nbo(PyArray_DESCR(operands[1]));
+ if (out_dtypes[1] == NULL) {
+ Py_DECREF(out_dtypes[0]);
+ out_dtypes[0] = NULL;
+ return -1;
+ }
+ out_dtypes[2] = out_dtypes[1];
+ Py_INCREF(out_dtypes[2]);
+
+ type_num1 = NPY_LONGLONG;
+ }
+ else {
+ goto type_reso_error;
+ }
+ }
+ else if (PyTypeNum_ISFLOAT(type_num1)) {
+ /* float## * m8[<A>] => float64 * m8[<A>] */
+ if (type_num2 == NPY_TIMEDELTA) {
+ out_dtypes[0] = PyArray_DescrNewFromType(NPY_DOUBLE);
+ if (out_dtypes[0] == NULL) {
+ return -1;
+ }
+ out_dtypes[1] = ensure_dtype_nbo(PyArray_DESCR(operands[1]));
+ if (out_dtypes[1] == NULL) {
+ Py_DECREF(out_dtypes[0]);
+ out_dtypes[0] = NULL;
+ return -1;
+ }
+ out_dtypes[2] = out_dtypes[1];
+ Py_INCREF(out_dtypes[2]);
+
+ type_num1 = NPY_DOUBLE;
+ }
+ else {
+ goto type_reso_error;
+ }
+ }
+ else {
+ goto type_reso_error;
+ }
+
+ /* Check against the casting rules */
+ if (PyUFunc_ValidateCasting(ufunc, casting, operands, out_dtypes) < 0) {
+ for (i = 0; i < 3; ++i) {
+ Py_DECREF(out_dtypes[i]);
+ out_dtypes[i] = NULL;
+ }
+ return -1;
+ }
+
+ /* Search in the functions list */
+ types = ufunc->types;
+ n = ufunc->ntypes;
+
+ for (i = 0; i < n; ++i) {
+ if (types[3*i] == type_num1 && types[3*i+1] == type_num2) {
+ *out_innerloop = ufunc->functions[i];
+ *out_innerloopdata = ufunc->data[i];
+ return 0;
+ }
+ }
+
+ PyErr_Format(PyExc_TypeError,
+ "internal error: could not find appropriate datetime "
+ "inner loop in %s ufunc", ufunc_name);
+ return -1;
+
+type_reso_error: {
+ PyObject *errmsg;
+ errmsg = PyUString_FromFormat("ufunc %s cannot use operands "
+ "with types ", ufunc_name);
+ PyUString_ConcatAndDel(&errmsg,
+ PyObject_Repr((PyObject *)PyArray_DESCR(operands[0])));
+ PyUString_ConcatAndDel(&errmsg,
+ PyUString_FromString(" and "));
+ PyUString_ConcatAndDel(&errmsg,
+ PyObject_Repr((PyObject *)PyArray_DESCR(operands[1])));
+ PyErr_SetObject(PyExc_TypeError, errmsg);
+ return -1;
+ }
+}
+
+/*
+ * This function applies the type resolution rules for division.
+ * In particular, there are a number of special cases with datetime:
+ * m8[<A>] / m8[<B>] to m8[gcd(<A>,<B>)] / m8[gcd(<A>,<B>)] -> float64
+ * m8[<A>] / int## to m8[<A>] / int64 -> m8[<A>]
+ * m8[<A>] / float## to m8[<A>] / float64 -> m8[<A>]
+ */
+NPY_NO_EXPORT int
+PyUFunc_DivisionTypeResolution(PyUFuncObject *ufunc,
+ NPY_CASTING casting,
+ PyArrayObject **operands,
+ PyObject *type_tup,
+ PyArray_Descr **out_dtypes,
+ PyUFuncGenericFunction *out_innerloop,
+ void **out_innerloopdata)
+{
+ int type_num1, type_num2;
+ char *types;
+ int i, n;
+ char *ufunc_name;
+
+ ufunc_name = ufunc->name ? ufunc->name : "<unnamed ufunc>";
+
+ type_num1 = PyArray_DESCR(operands[0])->type_num;
+ type_num2 = PyArray_DESCR(operands[1])->type_num;
+
+ /* Use the default when datetime and timedelta are not involved */
+ if (!PyTypeNum_ISDATETIME(type_num1) && !PyTypeNum_ISDATETIME(type_num2)) {
+ return PyUFunc_DefaultTypeResolution(ufunc, casting, operands,
+ type_tup, out_dtypes, out_innerloop, out_innerloopdata);
+ }
+
+ if (type_num1 == NPY_TIMEDELTA) {
+ /*
+ * m8[<A>] / m8[<B>] to
+ * m8[gcd(<A>,<B>)] / m8[gcd(<A>,<B>)] -> float64
+ */
+ if (type_num2 == NPY_TIMEDELTA) {
+ out_dtypes[0] = PyArray_PromoteTypes(PyArray_DESCR(operands[0]),
+ PyArray_DESCR(operands[1]));
+ if (out_dtypes[0] == NULL) {
+ return -1;
+ }
+ out_dtypes[1] = out_dtypes[0];
+ Py_INCREF(out_dtypes[1]);
+ out_dtypes[2] = PyArray_DescrFromType(NPY_DOUBLE);
+ if (out_dtypes[2] == NULL) {
+ Py_DECREF(out_dtypes[0]);
+ out_dtypes[0] = NULL;
+ Py_DECREF(out_dtypes[1]);
+ out_dtypes[1] = NULL;
+ return -1;
+ }
+ }
+ /* m8[<A>] / int## => m8[<A>] / int64 */
+ else if (PyTypeNum_ISINTEGER(type_num2)) {
+ out_dtypes[0] = ensure_dtype_nbo(PyArray_DESCR(operands[0]));
+ if (out_dtypes[0] == NULL) {
+ return -1;
+ }
+ out_dtypes[1] = PyArray_DescrFromType(NPY_LONGLONG);
+ if (out_dtypes[1] == NULL) {
+ Py_DECREF(out_dtypes[0]);
+ out_dtypes[0] = NULL;
+ return -1;
+ }
+ out_dtypes[2] = out_dtypes[0];
+ Py_INCREF(out_dtypes[2]);
+
+ type_num2 = NPY_LONGLONG;
+ }
+ /* m8[<A>] / float## => m8[<A>] / float64 */
+ else if (PyTypeNum_ISFLOAT(type_num2)) {
+ out_dtypes[0] = ensure_dtype_nbo(PyArray_DESCR(operands[0]));
+ if (out_dtypes[0] == NULL) {
+ return -1;
+ }
+ out_dtypes[1] = PyArray_DescrNewFromType(NPY_DOUBLE);
+ if (out_dtypes[1] == NULL) {
+ Py_DECREF(out_dtypes[0]);
+ out_dtypes[0] = NULL;
+ return -1;
+ }
+ out_dtypes[2] = out_dtypes[0];
+ Py_INCREF(out_dtypes[2]);
+
+ type_num2 = NPY_DOUBLE;
+ }
+ else {
+ goto type_reso_error;
+ }
+ }
+ else {
+ goto type_reso_error;
+ }
+
+ /* Check against the casting rules */
+ if (PyUFunc_ValidateCasting(ufunc, casting, operands, out_dtypes) < 0) {
+ for (i = 0; i < 3; ++i) {
+ Py_DECREF(out_dtypes[i]);
+ out_dtypes[i] = NULL;
+ }
+ return -1;
+ }
+
+ /* Search in the functions list */
+ types = ufunc->types;
+ n = ufunc->ntypes;
+
+ for (i = 0; i < n; ++i) {
+ if (types[3*i] == type_num1 && types[3*i+1] == type_num2) {
+ *out_innerloop = ufunc->functions[i];
+ *out_innerloopdata = ufunc->data[i];
+ return 0;
+ }
+ }
+
+ PyErr_Format(PyExc_TypeError,
+ "internal error: could not find appropriate datetime "
+ "inner loop in %s ufunc", ufunc_name);
+ return -1;
+
+type_reso_error: {
+ PyObject *errmsg;
+ errmsg = PyUString_FromFormat("ufunc %s cannot use operands "
+ "with types ", ufunc_name);
+ PyUString_ConcatAndDel(&errmsg,
+ PyObject_Repr((PyObject *)PyArray_DESCR(operands[0])));
+ PyUString_ConcatAndDel(&errmsg,
+ PyUString_FromString(" and "));
+ PyUString_ConcatAndDel(&errmsg,
+ PyObject_Repr((PyObject *)PyArray_DESCR(operands[1])));
+ PyErr_SetObject(PyExc_TypeError, errmsg);
+ return -1;
+ }
+}
+
+static int
+ufunc_loop_matches(PyUFuncObject *self,
+ PyArrayObject **op,
+ NPY_CASTING input_casting,
+ NPY_CASTING output_casting,
+ int any_object,
+ int use_min_scalar,
+ int *types,
+ int *out_no_castable_output,
+ char *out_err_src_typecode,
+ char *out_err_dst_typecode)
+{
+ npy_intp i, nin = self->nin, nop = nin + self->nout;
+
+ /*
+ * First check if all the inputs can be safely cast
+ * to the types for this function
+ */
+ for (i = 0; i < nin; ++i) {
+ PyArray_Descr *tmp;
+
+ /*
+ * If no inputs are objects and there are more than one
+ * loop, don't allow conversion to object. The rationale
+ * behind this is mostly performance. Except for custom
+ * ufuncs built with just one object-parametered inner loop,
+ * only the types that are supported are implemented. Trying
+ * the object version of logical_or on float arguments doesn't
+ * seem right.
+ */
+ if (types[i] == NPY_OBJECT && !any_object && self->ntypes > 1) {
+ return 0;
+ }
+
+ tmp = PyArray_DescrFromType(types[i]);
+ if (tmp == NULL) {
+ return -1;
+ }
+
+#if NPY_UF_DBG_TRACING
+ printf("Checking type for op %d, type %d: ", (int)i, (int)types[i]);
+ PyObject_Print((PyObject *)tmp, stdout, 0);
+ printf(", operand type: ");
+ PyObject_Print((PyObject *)PyArray_DESCR(op[i]), stdout, 0);
+ printf("\n");
+#endif
+ /*
+ * If all the inputs are scalars, use the regular
+ * promotion rules, not the special value-checking ones.
+ */
+ if (!use_min_scalar) {
+ if (!PyArray_CanCastTypeTo(PyArray_DESCR(op[i]), tmp,
+ input_casting)) {
+ Py_DECREF(tmp);
+ return 0;
+ }
+ }
+ else {
+ if (!PyArray_CanCastArrayTo(op[i], tmp, input_casting)) {
+ Py_DECREF(tmp);
+ return 0;
+ }
+ }
+ Py_DECREF(tmp);
+ }
+
+ /*
+ * If all the inputs were ok, then check casting back to the
+ * outputs.
+ */
+ for (i = nin; i < nop; ++i) {
+ if (op[i] != NULL) {
+ PyArray_Descr *tmp = PyArray_DescrFromType(types[i]);
+ if (tmp == NULL) {
+ return -1;
+ }
+ if (!PyArray_CanCastTypeTo(tmp, PyArray_DESCR(op[i]),
+ output_casting)) {
+ if (!(*out_no_castable_output)) {
+ *out_no_castable_output = 1;
+ *out_err_src_typecode = tmp->type;
+ *out_err_dst_typecode = PyArray_DESCR(op[i])->type;
+ }
+ Py_DECREF(tmp);
+ return 0;
+ }
+ Py_DECREF(tmp);
+ }
+ }
+
+ return 1;
+}
+
+static int
+set_ufunc_loop_data_types(PyUFuncObject *self, PyArrayObject **op,
+ PyArray_Descr **out_dtype,
+ int *types)
+{
+ int i, nin = self->nin, nop = nin + self->nout;
+
+ /* Fill the dtypes array */
+ for (i = 0; i < nop; ++i) {
+ out_dtype[i] = PyArray_DescrFromType(types[i]);
+ if (out_dtype[i] == NULL) {
+ while (--i >= 0) {
+ Py_DECREF(out_dtype[i]);
+ out_dtype[i] = NULL;
+ }
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * Does a search through the arguments and the loops
+ */
+static int
+find_ufunc_matching_userloop(PyUFuncObject *self,
+ PyArrayObject **op,
+ NPY_CASTING input_casting,
+ NPY_CASTING output_casting,
+ int any_object,
+ int use_min_scalar,
+ PyArray_Descr **out_dtype,
+ PyUFuncGenericFunction *out_innerloop,
+ void **out_innerloopdata,
+ int *out_no_castable_output,
+ char *out_err_src_typecode,
+ char *out_err_dst_typecode)
+{
+ npy_intp i, nin = self->nin;
+ PyUFunc_Loop1d *funcdata;
+
+ /* Use this to try to avoid repeating the same userdef loop search */
+ int last_userdef = -1;
+
+ for (i = 0; i < nin; ++i) {
+ int type_num = PyArray_DESCR(op[i])->type_num;
+ if (type_num != last_userdef && PyTypeNum_ISUSERDEF(type_num)) {
+ PyObject *key, *obj;
+
+ last_userdef = type_num;
+
+ key = PyInt_FromLong(type_num);
+ if (key == NULL) {
+ return -1;
+ }
+ obj = PyDict_GetItem(self->userloops, key);
+ Py_DECREF(key);
+ if (obj == NULL) {
+ continue;
+ }
+ funcdata = (PyUFunc_Loop1d *)NpyCapsule_AsVoidPtr(obj);
+ while (funcdata != NULL) {
+ int *types = funcdata->arg_types;
+ switch (ufunc_loop_matches(self, op,
+ input_casting, output_casting,
+ any_object, use_min_scalar,
+ types,
+ out_no_castable_output, out_err_src_typecode,
+ out_err_dst_typecode)) {
+ /* Error */
+ case -1:
+ return -1;
+ /* Found a match */
+ case 1:
+ set_ufunc_loop_data_types(self, op, out_dtype, types);
+
+ /* Save the inner loop and its data */
+ *out_innerloop = funcdata->func;
+ *out_innerloopdata = funcdata->data;
+
+ return 0;
+ }
+
+ funcdata = funcdata->next;
+ }
+ }
+ }
+
+ /* Didn't find a match */
+ return 0;
+}
+
+/*
+ * Does a search through the arguments and the loops
+ */
+static int
+find_ufunc_specified_userloop(PyUFuncObject *self,
+ int n_specified,
+ int *specified_types,
+ PyArrayObject **op,
+ NPY_CASTING casting,
+ int any_object,
+ int use_min_scalar,
+ PyArray_Descr **out_dtype,
+ PyUFuncGenericFunction *out_innerloop,
+ void **out_innerloopdata)
+{
+ int i, j, nin = self->nin, nop = nin + self->nout;
+ PyUFunc_Loop1d *funcdata;
+
+ /* Use this to try to avoid repeating the same userdef loop search */
+ int last_userdef = -1;
+
+ int no_castable_output = 0;
+ char err_src_typecode = '-', err_dst_typecode = '-';
+
+ for (i = 0; i < nin; ++i) {
+ int type_num = PyArray_DESCR(op[i])->type_num;
+ if (type_num != last_userdef && PyTypeNum_ISUSERDEF(type_num)) {
+ PyObject *key, *obj;
+
+ last_userdef = type_num;
+
+ key = PyInt_FromLong(type_num);
+ if (key == NULL) {
+ return -1;
+ }
+ obj = PyDict_GetItem(self->userloops, key);
+ Py_DECREF(key);
+ if (obj == NULL) {
+ continue;
+ }
+ funcdata = (PyUFunc_Loop1d *)NpyCapsule_AsVoidPtr(obj);
+ while (funcdata != NULL) {
+ int *types = funcdata->arg_types;
+ int matched = 1;
+
+ if (n_specified == nop) {
+ for (j = 0; j < nop; ++j) {
+ if (types[j] != specified_types[j]) {
+ matched = 0;
+ break;
+ }
+ }
+ } else {
+ if (types[nin] != specified_types[0]) {
+ matched = 0;
+ }
+ }
+ if (!matched) {
+ continue;
+ }
+
+ switch (ufunc_loop_matches(self, op,
+ casting, casting,
+ any_object, use_min_scalar,
+ types,
+ &no_castable_output, &err_src_typecode,
+ &err_dst_typecode)) {
+ /* It works */
+ case 1:
+ set_ufunc_loop_data_types(self, op, out_dtype, types);
+
+ /* Save the inner loop and its data */
+ *out_innerloop = funcdata->func;
+ *out_innerloopdata = funcdata->data;
+
+ return 0;
+ /* Didn't match */
+ case 0:
+ PyErr_Format(PyExc_TypeError,
+ "found a user loop for ufunc '%s' "
+ "matching the type-tuple, "
+ "but the inputs and/or outputs could not be "
+ "cast according to the casting rule",
+ self->name ? self->name : "(unknown)");
+ return -1;
+ /* Error */
+ case -1:
+ return -1;
+ }
+
+ funcdata = funcdata->next;
+ }
+ }
+ }
+
+ /* Didn't find a match */
+ return 0;
+}
+
+/*
+ * Provides an ordering for the dtype 'kind' character codes, to help
+ * determine when to use the min_scalar_type function. This groups
+ * 'kind' into boolean, integer, floating point, and everything else.
+ */
+
+static int
+dtype_kind_to_simplified_ordering(char kind)
+{
+ switch (kind) {
+ /* Boolean kind */
+ case 'b':
+ return 0;
+ /* Unsigned int kind */
+ case 'u':
+ /* Signed int kind */
+ case 'i':
+ return 1;
+ /* Float kind */
+ case 'f':
+ /* Complex kind */
+ case 'c':
+ return 2;
+ /* Anything else */
+ default:
+ return 3;
+ }
+}
+
+static int
+should_use_min_scalar(PyArrayObject **op, int nop)
+{
+ int i, use_min_scalar, kind;
+ int all_scalars = 1, max_scalar_kind = -1, max_array_kind = -1;
+
+ /*
+ * Determine if there are any scalars, and if so, whether
+ * the maximum "kind" of the scalars surpasses the maximum
+ * "kind" of the arrays
+ */
+ use_min_scalar = 0;
+ if (nop > 1) {
+ for(i = 0; i < nop; ++i) {
+ kind = dtype_kind_to_simplified_ordering(
+ PyArray_DESCR(op[i])->kind);
+ if (PyArray_NDIM(op[i]) == 0) {
+ if (kind > max_scalar_kind) {
+ max_scalar_kind = kind;
+ }
+ }
+ else {
+ all_scalars = 0;
+ if (kind > max_array_kind) {
+ max_array_kind = kind;
+ }
+
+ }
+ }
+
+ /* Indicate whether to use the min_scalar_type function */
+ if (!all_scalars && max_array_kind >= max_scalar_kind) {
+ use_min_scalar = 1;
+ }
+ }
+
+ return use_min_scalar;
+}
+
+/*
+ * Does a linear search for the best inner loop of the ufunc.
+ *
+ * Note that if an error is returned, the caller must free the non-zero
+ * references in out_dtype. This function does not do its own clean-up.
+ */
+NPY_NO_EXPORT int
+find_best_ufunc_inner_loop(PyUFuncObject *self,
+ PyArrayObject **op,
+ NPY_CASTING input_casting,
+ NPY_CASTING output_casting,
+ int any_object,
+ PyArray_Descr **out_dtype,
+ PyUFuncGenericFunction *out_innerloop,
+ void **out_innerloopdata)
+{
+ npy_intp i, j, nin = self->nin, nop = nin + self->nout;
+ int types[NPY_MAXARGS];
+ char *ufunc_name;
+ int no_castable_output, use_min_scalar;
+
+ /* For making a better error message on coercion error */
+ char err_dst_typecode = '-', err_src_typecode = '-';
+
+ ufunc_name = self->name ? self->name : "(unknown)";
+
+ use_min_scalar = should_use_min_scalar(op, nin);
+
+ /* If the ufunc has userloops, search for them. */
+ if (self->userloops) {
+ switch (find_ufunc_matching_userloop(self, op,
+ input_casting, output_casting,
+ any_object, use_min_scalar,
+ out_dtype, out_innerloop, out_innerloopdata,
+ &no_castable_output, &err_src_typecode,
+ &err_dst_typecode)) {
+ /* Error */
+ case -1:
+ return -1;
+ /* A loop was found */
+ case 1:
+ return 0;
+ }
+ }
+
+ /*
+ * Determine the UFunc loop. This could in general be *much* faster,
+ * and a better way to implement it might be for the ufunc to
+ * provide a function which gives back the result type and inner
+ * loop function.
+ *
+ * A default fast mechanism could be provided for functions which
+ * follow the most typical pattern, when all functions have signatures
+ * "xx...x -> x" for some built-in data type x, as follows.
+ * - Use PyArray_ResultType to get the output type
+ * - Look up the inner loop in a table based on the output type_num
+ *
+ * The method for finding the loop in the previous code did not
+ * appear consistent (as noted by some asymmetry in the generated
+ * coercion tables for np.add).
+ */
+ no_castable_output = 0;
+ for (i = 0; i < self->ntypes; ++i) {
+ char *orig_types = self->types + i*self->nargs;
+
+ /* Copy the types into an int array for matching */
+ for (j = 0; j < nop; ++j) {
+ types[j] = orig_types[j];
+ }
+
+ switch (ufunc_loop_matches(self, op,
+ input_casting, output_casting,
+ any_object, use_min_scalar,
+ types,
+ &no_castable_output, &err_src_typecode,
+ &err_dst_typecode)) {
+ /* Error */
+ case -1:
+ return -1;
+ /* Found a match */
+ case 1:
+ set_ufunc_loop_data_types(self, op, out_dtype, types);
+
+ /* Save the inner loop and its data */
+ *out_innerloop = self->functions[i];
+ *out_innerloopdata = self->data[i];
+
+ return 0;
+ }
+
+ }
+
+ /* If no function was found, throw an error */
+ if (no_castable_output) {
+ PyErr_Format(PyExc_TypeError,
+ "ufunc '%s' output (typecode '%c') could not be coerced to "
+ "provided output parameter (typecode '%c') according "
+ "to the casting rule '%s'",
+ ufunc_name, err_src_typecode, err_dst_typecode,
+ npy_casting_to_string(output_casting));
+ }
+ else {
+ /*
+ * TODO: We should try again if the casting rule is same_kind
+ * or unsafe, and look for a function more liberally.
+ */
+ PyErr_Format(PyExc_TypeError,
+ "ufunc '%s' not supported for the input types, and the "
+ "inputs could not be safely coerced to any supported "
+ "types according to the casting rule '%s'",
+ ufunc_name,
+ npy_casting_to_string(input_casting));
+ }
+
+ return -1;
+}
+
+/*
+ * Does a linear search for the inner loop of the ufunc specified by type_tup.
+ *
+ * Note that if an error is returned, the caller must free the non-zero
+ * references in out_dtype. This function does not do its own clean-up.
+ */
+NPY_NO_EXPORT int
+find_specified_ufunc_inner_loop(PyUFuncObject *self,
+ PyObject *type_tup,
+ PyArrayObject **op,
+ NPY_CASTING casting,
+ int any_object,
+ PyArray_Descr **out_dtype,
+ PyUFuncGenericFunction *out_innerloop,
+ void **out_innerloopdata)
+{
+ npy_intp i, j, n, nin = self->nin, nop = nin + self->nout;
+ int n_specified = 0;
+ int specified_types[NPY_MAXARGS], types[NPY_MAXARGS];
+ char *ufunc_name;
+ int no_castable_output, use_min_scalar;
+
+ /* For making a better error message on coercion error */
+ char err_dst_typecode = '-', err_src_typecode = '-';
+
+ ufunc_name = self->name ? self->name : "(unknown)";
+
+ use_min_scalar = should_use_min_scalar(op, nin);
+
+ /* Fill in specified_types from the tuple or string */
+ if (PyTuple_Check(type_tup)) {
+ n = PyTuple_GET_SIZE(type_tup);
+ if (n != 1 && n != nop) {
+ PyErr_Format(PyExc_ValueError,
+ "a type-tuple must be specified " \
+ "of length 1 or %d for ufunc '%s'", (int)nop,
+ self->name ? self->name : "(unknown)");
+ return -1;
+ }
+
+ for (i = 0; i < n; ++i) {
+ PyArray_Descr *dtype = NULL;
+ if (!PyArray_DescrConverter(PyTuple_GET_ITEM(type_tup, i),
+ &dtype)) {
+ return -1;
+ }
+ specified_types[i] = dtype->type_num;
+ Py_DECREF(dtype);
+ }
+
+ n_specified = n;
+ }
+ else if (PyBytes_Check(type_tup) || PyUnicode_Check(type_tup)) {
+ Py_ssize_t length;
+ char *str;
+ PyObject *str_obj = NULL;
+
+ if (PyUnicode_Check(type_tup)) {
+ str_obj = PyUnicode_AsASCIIString(type_tup);
+ if (str_obj == NULL) {
+ return -1;
+ }
+ type_tup = str_obj;
+ }
+
+ if (!PyBytes_AsStringAndSize(type_tup, &str, &length) < 0) {
+ Py_XDECREF(str_obj);
+ return -1;
+ }
+ if (length != 1 && (length != nop + 2 ||
+ str[nin] != '-' || str[nin+1] != '>')) {
+ PyErr_Format(PyExc_ValueError,
+ "a type-string for %s, " \
+ "requires 1 typecode, or "
+ "%d typecode(s) before " \
+ "and %d after the -> sign",
+ self->name ? self->name : "(unknown)",
+ self->nin, self->nout);
+ Py_XDECREF(str_obj);
+ return -1;
+ }
+ if (length == 1) {
+ PyArray_Descr *dtype;
+ n_specified = 1;
+ dtype = PyArray_DescrFromType(str[0]);
+ if (dtype == NULL) {
+ Py_XDECREF(str_obj);
+ return -1;
+ }
+ specified_types[0] = dtype->type_num;
+ Py_DECREF(dtype);
+ }
+ else {
+ PyArray_Descr *dtype;
+ n_specified = (int)nop;
+
+ for (i = 0; i < nop; ++i) {
+ npy_intp istr = i < nin ? i : i+2;
+
+ dtype = PyArray_DescrFromType(str[istr]);
+ if (dtype == NULL) {
+ Py_XDECREF(str_obj);
+ return -1;
+ }
+ specified_types[i] = dtype->type_num;
+ Py_DECREF(dtype);
+ }
+ }
+ Py_XDECREF(str_obj);
+ }
+
+ /* If the ufunc has userloops, search for them. */
+ if (self->userloops) {
+ switch (find_ufunc_specified_userloop(self,
+ n_specified, specified_types,
+ op, casting,
+ any_object, use_min_scalar,
+ out_dtype, out_innerloop, out_innerloopdata)) {
+ /* Error */
+ case -1:
+ return -1;
+ /* Found matching loop */
+ case 1:
+ return 0;
+ }
+ }
+
+ for (i = 0; i < self->ntypes; ++i) {
+ char *orig_types = self->types + i*self->nargs;
+ int matched = 1;
+
+ /* Copy the types into an int array for matching */
+ for (j = 0; j < nop; ++j) {
+ types[j] = orig_types[j];
+ }
+
+ if (n_specified == nop) {
+ for (j = 0; j < nop; ++j) {
+ if (types[j] != specified_types[j]) {
+ matched = 0;
+ break;
+ }
+ }
+ } else {
+ if (types[nin] != specified_types[0]) {
+ matched = 0;
+ }
+ }
+ if (!matched) {
+ continue;
+ }
+
+ switch (ufunc_loop_matches(self, op,
+ casting, casting,
+ any_object, use_min_scalar,
+ types,
+ &no_castable_output, &err_src_typecode,
+ &err_dst_typecode)) {
+ /* Error */
+ case -1:
+ return -1;
+ /* It worked */
+ case 1:
+ set_ufunc_loop_data_types(self, op, out_dtype, types);
+
+ /* Save the inner loop and its data */
+ *out_innerloop = self->functions[i];
+ *out_innerloopdata = self->data[i];
+
+ return 0;
+ /* Didn't work */
+ case 0:
+ PyErr_Format(PyExc_TypeError,
+ "found a loop for ufunc '%s' "
+ "matching the type-tuple, "
+ "but the inputs and/or outputs could not be "
+ "cast according to the casting rule",
+ ufunc_name);
+ return -1;
+ }
+
+ }
+
+ /* If no function was found, throw an error */
+ PyErr_Format(PyExc_TypeError,
+ "No loop matching the specified signature was found "
+ "for ufunc %s", ufunc_name);
+
+ return -1;
+}
+
+
diff --git a/numpy/core/src/umath/ufunc_type_resolution.h b/numpy/core/src/umath/ufunc_type_resolution.h
new file mode 100644
index 000000000..f1ded2e9b
--- /dev/null
+++ b/numpy/core/src/umath/ufunc_type_resolution.h
@@ -0,0 +1,116 @@
+#ifndef _NPY_PRIVATE__UFUNC_TYPE_RESOLUTION_H_
+#define _NPY_PRIVATE__UFUNC_TYPE_RESOLUTION_H_
+
+NPY_NO_EXPORT int
+PyUFunc_SimpleBinaryComparisonTypeResolution(PyUFuncObject *ufunc,
+ NPY_CASTING casting,
+ PyArrayObject **operands,
+ PyObject *type_tup,
+ PyArray_Descr **out_dtypes,
+ PyUFuncGenericFunction *out_innerloop,
+ void **out_innerloopdata);
+
+NPY_NO_EXPORT int
+PyUFunc_SimpleUnaryOperationTypeResolution(PyUFuncObject *ufunc,
+ NPY_CASTING casting,
+ PyArrayObject **operands,
+ PyObject *type_tup,
+ PyArray_Descr **out_dtypes,
+ PyUFuncGenericFunction *out_innerloop,
+ void **out_innerloopdata);
+
+NPY_NO_EXPORT int
+PyUFunc_OnesLikeTypeResolution(PyUFuncObject *ufunc,
+ NPY_CASTING casting,
+ PyArrayObject **operands,
+ PyObject *type_tup,
+ PyArray_Descr **out_dtypes,
+ PyUFuncGenericFunction *out_innerloop,
+ void **out_innerloopdata);
+
+NPY_NO_EXPORT int
+PyUFunc_SimpleBinaryOperationTypeResolution(PyUFuncObject *ufunc,
+ NPY_CASTING casting,
+ PyArrayObject **operands,
+ PyObject *type_tup,
+ PyArray_Descr **out_dtypes,
+ PyUFuncGenericFunction *out_innerloop,
+ void **out_innerloopdata);
+
+NPY_NO_EXPORT int
+PyUFunc_AbsoluteTypeResolution(PyUFuncObject *ufunc,
+ NPY_CASTING casting,
+ PyArrayObject **operands,
+ PyObject *type_tup,
+ PyArray_Descr **out_dtypes,
+ PyUFuncGenericFunction *out_innerloop,
+ void **out_innerloopdata);
+
+NPY_NO_EXPORT int
+PyUFunc_AdditionTypeResolution(PyUFuncObject *ufunc,
+ NPY_CASTING casting,
+ PyArrayObject **operands,
+ PyObject *type_tup,
+ PyArray_Descr **out_dtypes,
+ PyUFuncGenericFunction *out_innerloop,
+ void **out_innerloopdata);
+
+NPY_NO_EXPORT int
+PyUFunc_SubtractionTypeResolution(PyUFuncObject *ufunc,
+ NPY_CASTING casting,
+ PyArrayObject **operands,
+ PyObject *type_tup,
+ PyArray_Descr **out_dtypes,
+ PyUFuncGenericFunction *out_innerloop,
+ void **out_innerloopdata);
+
+NPY_NO_EXPORT int
+PyUFunc_MultiplicationTypeResolution(PyUFuncObject *ufunc,
+ NPY_CASTING casting,
+ PyArrayObject **operands,
+ PyObject *type_tup,
+ PyArray_Descr **out_dtypes,
+ PyUFuncGenericFunction *out_innerloop,
+ void **out_innerloopdata);
+NPY_NO_EXPORT int
+PyUFunc_DivisionTypeResolution(PyUFuncObject *ufunc,
+ NPY_CASTING casting,
+ PyArrayObject **operands,
+ PyObject *type_tup,
+ PyArray_Descr **out_dtypes,
+ PyUFuncGenericFunction *out_innerloop,
+ void **out_innerloopdata);
+
+/*
+ * Does a linear search for the best inner loop of the ufunc.
+ *
+ * Note that if an error is returned, the caller must free the non-zero
+ * references in out_dtype. This function does not do its own clean-up.
+ */
+NPY_NO_EXPORT int
+find_best_ufunc_inner_loop(PyUFuncObject *self,
+ PyArrayObject **op,
+ NPY_CASTING input_casting,
+ NPY_CASTING output_casting,
+ int any_object,
+ PyArray_Descr **out_dtype,
+ PyUFuncGenericFunction *out_innerloop,
+ void **out_innerloopdata);
+
+/*
+ * Does a linear search for the inner loop of the ufunc specified by type_tup.
+ *
+ * Note that if an error is returned, the caller must free the non-zero
+ * references in out_dtype. This function does not do its own clean-up.
+ */
+NPY_NO_EXPORT int
+find_specified_ufunc_inner_loop(PyUFuncObject *self,
+ PyObject *type_tup,
+ PyArrayObject **op,
+ NPY_CASTING casting,
+ int any_object,
+ PyArray_Descr **out_dtype,
+ PyUFuncGenericFunction *out_innerloop,
+ void **out_innerloopdata);
+
+#endif
diff --git a/numpy/core/src/umath/umathmodule.c.src b/numpy/core/src/umath/umathmodule.c.src
index 82afd7fd8..52dcd4c1b 100644
--- a/numpy/core/src/umath/umathmodule.c.src
+++ b/numpy/core/src/umath/umathmodule.c.src
@@ -39,6 +39,7 @@
#include "funcs.inc"
#include "loops.h"
#include "ufunc_object.h"
+#include "ufunc_type_resolution.h"
#include "__umath_generated.c"
#include "__ufunc_api.c"
diff --git a/numpy/core/src/umath/umathmodule_onefile.c b/numpy/core/src/umath/umathmodule_onefile.c
index 722f74eec..2255daf76 100644
--- a/numpy/core/src/umath/umathmodule_onefile.c
+++ b/numpy/core/src/umath/umathmodule_onefile.c
@@ -1,4 +1,5 @@
#include "loops.c"
#include "ufunc_object.c"
+#include "ufunc_type_resolution.c"
#include "umathmodule.c"