diff options
author | Mark Wiebe <mwiebe@enthought.com> | 2011-06-27 17:59:34 -0500 |
---|---|---|
committer | Charles Harris <charlesr.harris@gmail.com> | 2011-07-06 16:24:12 -0600 |
commit | b2ac4ad231970a107eff18509dcd5daff9c509ae (patch) | |
tree | 4ced244c4cab5d01cc55e3238675f34cd270ecc5 /numpy | |
parent | e72099374c89e39b8177ff656ff7a793931b4b7a (diff) | |
download | numpy-b2ac4ad231970a107eff18509dcd5daff9c509ae.tar.gz |
ENH: umath: Move the type resolution functions into their own file
Diffstat (limited to 'numpy')
-rw-r--r-- | numpy/core/SConscript | 1 | ||||
-rw-r--r-- | numpy/core/code_generators/genapi.py | 1 | ||||
-rw-r--r-- | numpy/core/setup.py | 3 | ||||
-rw-r--r-- | numpy/core/src/umath/loops.c.src | 320 | ||||
-rw-r--r-- | numpy/core/src/umath/ufunc_object.c | 2015 | ||||
-rw-r--r-- | numpy/core/src/umath/ufunc_object.h | 80 | ||||
-rw-r--r-- | numpy/core/src/umath/ufunc_type_resolution.c | 2012 | ||||
-rw-r--r-- | numpy/core/src/umath/ufunc_type_resolution.h | 116 | ||||
-rw-r--r-- | numpy/core/src/umath/umathmodule.c.src | 1 | ||||
-rw-r--r-- | numpy/core/src/umath/umathmodule_onefile.c | 1 |
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" |