diff options
-rw-r--r-- | numpy/core/code_generators/generate_umath.py | 85 | ||||
-rw-r--r-- | numpy/core/src/umath/ufunc_object.c | 21 |
2 files changed, 100 insertions, 6 deletions
diff --git a/numpy/core/code_generators/generate_umath.py b/numpy/core/code_generators/generate_umath.py index f81291395..d151b6619 100644 --- a/numpy/core/code_generators/generate_umath.py +++ b/numpy/core/code_generators/generate_umath.py @@ -100,7 +100,7 @@ class Ufunc(object): docstring: docstring for the ufunc type_descriptions: list of TypeDescription objects """ - def __init__(self, nin, nout, identity, docstring, + def __init__(self, nin, nout, identity, docstring, typereso, *type_descriptions): self.nin = nin self.nout = nout @@ -108,6 +108,7 @@ class Ufunc(object): identity = None_ self.identity = identity self.docstring = docstring + self.typereso = typereso self.type_descriptions = [] for td in type_descriptions: self.type_descriptions.extend(td) @@ -236,6 +237,7 @@ defdict = { 'add' : Ufunc(2, 1, Zero, docstrings.get('numpy.core.umath.add'), + None, TD(notimes_or_obj), [TypeDescription('M', UsesArraysAsData, 'Mm', 'M'), TypeDescription('m', UsesArraysAsData, 'mm', 'm'), @@ -246,6 +248,7 @@ defdict = { 'subtract' : Ufunc(2, 1, Zero, docstrings.get('numpy.core.umath.subtract'), + None, TD(notimes_or_obj), [TypeDescription('M', UsesArraysAsData, 'Mm', 'M'), TypeDescription('m', UsesArraysAsData, 'mm', 'm'), @@ -256,24 +259,28 @@ defdict = { 'multiply' : Ufunc(2, 1, One, docstrings.get('numpy.core.umath.multiply'), + None, TD(notimes_or_obj), TD(O, f='PyNumber_Multiply'), ), 'divide' : Ufunc(2, 1, One, docstrings.get('numpy.core.umath.divide'), + None, TD(intfltcmplx), TD(O, f='PyNumber_Divide'), ), 'floor_divide' : Ufunc(2, 1, One, docstrings.get('numpy.core.umath.floor_divide'), + None, TD(intfltcmplx), TD(O, f='PyNumber_FloorDivide'), ), 'true_divide' : Ufunc(2, 1, One, docstrings.get('numpy.core.umath.true_divide'), + None, TD('bBhH', out='d'), TD('iIlLqQ', out='d'), TD(flts+cmplx), @@ -282,12 +289,14 @@ defdict = { 'conjugate' : Ufunc(1, 1, None, docstrings.get('numpy.core.umath.conjugate'), + None, TD(ints+flts+cmplx), TD(P, f='conjugate'), ), 'fmod' : Ufunc(2, 1, Zero, docstrings.get('numpy.core.umath.fmod'), + None, TD(ints), TD(flts, f='fmod', astype={'e':'f'}), TD(P, f='fmod'), @@ -295,24 +304,28 @@ defdict = { 'square' : Ufunc(1, 1, None, docstrings.get('numpy.core.umath.square'), + None, TD(ints+inexact), TD(O, f='Py_square'), ), 'reciprocal' : Ufunc(1, 1, None, docstrings.get('numpy.core.umath.reciprocal'), + None, TD(ints+inexact), TD(O, f='Py_reciprocal'), ), 'ones_like' : Ufunc(1, 1, None, docstrings.get('numpy.core.umath.ones_like'), + None, TD(noobj), TD(O, f='Py_get_one'), ), 'power' : Ufunc(2, 1, One, docstrings.get('numpy.core.umath.power'), + None, TD(ints), TD(inexact, f='pow', astype={'e':'f'}), TD(O, f='npy_ObjectPower'), @@ -320,6 +333,7 @@ defdict = { 'absolute' : Ufunc(1, 1, None, docstrings.get('numpy.core.umath.absolute'), + None, TD(bints+flts+timedeltaonly), TD(cmplx, out=('f', 'd', 'g')), TD(O, f='PyNumber_Absolute'), @@ -327,11 +341,13 @@ defdict = { '_arg' : Ufunc(1, 1, None, docstrings.get('numpy.core.umath._arg'), + None, TD(cmplx, out=('f', 'd', 'g')), ), 'negative' : Ufunc(1, 1, None, docstrings.get('numpy.core.umath.negative'), + None, TD(bints+flts+timedeltaonly), TD(cmplx, f='neg'), TD(O, f='PyNumber_Negative'), @@ -339,359 +355,422 @@ defdict = { 'sign' : Ufunc(1, 1, None, docstrings.get('numpy.core.umath.sign'), + None, TD(nobool_or_datetime), ), 'greater' : Ufunc(2, 1, None, docstrings.get('numpy.core.umath.greater'), + 'PyUFunc_BinaryComparisonTypeResolution', TD(all, out='?'), ), 'greater_equal' : Ufunc(2, 1, None, docstrings.get('numpy.core.umath.greater_equal'), + None, TD(all, out='?'), ), 'less' : Ufunc(2, 1, None, docstrings.get('numpy.core.umath.less'), + 'PyUFunc_BinaryComparisonTypeResolution', TD(all, out='?'), ), 'less_equal' : Ufunc(2, 1, None, docstrings.get('numpy.core.umath.less_equal'), + 'PyUFunc_BinaryComparisonTypeResolution', TD(all, out='?'), ), 'equal' : Ufunc(2, 1, None, docstrings.get('numpy.core.umath.equal'), + 'PyUFunc_BinaryComparisonTypeResolution', TD(all, out='?'), ), 'not_equal' : Ufunc(2, 1, None, docstrings.get('numpy.core.umath.not_equal'), + 'PyUFunc_BinaryComparisonTypeResolution', TD(all, out='?'), ), 'logical_and' : Ufunc(2, 1, One, docstrings.get('numpy.core.umath.logical_and'), + 'PyUFunc_BinaryComparisonTypeResolution', TD(nodatetime_or_obj, out='?'), TD(P, f='logical_and'), ), 'logical_not' : Ufunc(1, 1, None, docstrings.get('numpy.core.umath.logical_not'), + None, TD(nodatetime_or_obj, out='?'), TD(P, f='logical_not'), ), 'logical_or' : Ufunc(2, 1, Zero, docstrings.get('numpy.core.umath.logical_or'), + 'PyUFunc_BinaryComparisonTypeResolution', TD(nodatetime_or_obj, out='?'), TD(P, f='logical_or'), ), 'logical_xor' : Ufunc(2, 1, None, docstrings.get('numpy.core.umath.logical_xor'), + 'PyUFunc_BinaryComparisonTypeResolution', TD(nodatetime_or_obj, out='?'), TD(P, f='logical_xor'), ), 'maximum' : Ufunc(2, 1, None, docstrings.get('numpy.core.umath.maximum'), + None, TD(noobj), TD(O, f='npy_ObjectMax') ), 'minimum' : Ufunc(2, 1, None, docstrings.get('numpy.core.umath.minimum'), + None, TD(noobj), TD(O, f='npy_ObjectMin') ), 'fmax' : Ufunc(2, 1, None, docstrings.get('numpy.core.umath.fmax'), + None, TD(noobj), TD(O, f='npy_ObjectMax') ), 'fmin' : Ufunc(2, 1, None, docstrings.get('numpy.core.umath.fmin'), + None, TD(noobj), TD(O, f='npy_ObjectMin') ), 'logaddexp' : Ufunc(2, 1, None, docstrings.get('numpy.core.umath.logaddexp'), + None, TD(flts, f="logaddexp", astype={'e':'f'}) ), 'logaddexp2' : Ufunc(2, 1, None, docstrings.get('numpy.core.umath.logaddexp2'), + None, TD(flts, f="logaddexp2", astype={'e':'f'}) ), # FIXME: decide if the times should have the bitwise operations. 'bitwise_and' : Ufunc(2, 1, One, docstrings.get('numpy.core.umath.bitwise_and'), + None, TD(bints), TD(O, f='PyNumber_And'), ), 'bitwise_or' : Ufunc(2, 1, Zero, docstrings.get('numpy.core.umath.bitwise_or'), + None, TD(bints), TD(O, f='PyNumber_Or'), ), 'bitwise_xor' : Ufunc(2, 1, None, docstrings.get('numpy.core.umath.bitwise_xor'), + None, TD(bints), TD(O, f='PyNumber_Xor'), ), 'invert' : Ufunc(1, 1, None, docstrings.get('numpy.core.umath.invert'), + None, TD(bints), TD(O, f='PyNumber_Invert'), ), 'left_shift' : Ufunc(2, 1, None, docstrings.get('numpy.core.umath.left_shift'), + None, TD(ints), TD(O, f='PyNumber_Lshift'), ), 'right_shift' : Ufunc(2, 1, None, docstrings.get('numpy.core.umath.right_shift'), + None, TD(ints), TD(O, f='PyNumber_Rshift'), ), 'degrees' : Ufunc(1, 1, None, docstrings.get('numpy.core.umath.degrees'), + None, TD(fltsP, f='degrees', astype={'e':'f'}), ), 'rad2deg' : Ufunc(1, 1, None, docstrings.get('numpy.core.umath.rad2deg'), + None, TD(fltsP, f='rad2deg', astype={'e':'f'}), ), 'radians' : Ufunc(1, 1, None, docstrings.get('numpy.core.umath.radians'), + None, TD(fltsP, f='radians', astype={'e':'f'}), ), 'deg2rad' : Ufunc(1, 1, None, docstrings.get('numpy.core.umath.deg2rad'), + None, TD(fltsP, f='deg2rad', astype={'e':'f'}), ), 'arccos' : Ufunc(1, 1, None, docstrings.get('numpy.core.umath.arccos'), + None, TD(inexact, f='acos', astype={'e':'f'}), TD(P, f='arccos'), ), 'arccosh' : Ufunc(1, 1, None, docstrings.get('numpy.core.umath.arccosh'), + None, TD(inexact, f='acosh', astype={'e':'f'}), TD(P, f='arccosh'), ), 'arcsin' : Ufunc(1, 1, None, docstrings.get('numpy.core.umath.arcsin'), + None, TD(inexact, f='asin', astype={'e':'f'}), TD(P, f='arcsin'), ), 'arcsinh' : Ufunc(1, 1, None, docstrings.get('numpy.core.umath.arcsinh'), + None, TD(inexact, f='asinh', astype={'e':'f'}), TD(P, f='arcsinh'), ), 'arctan' : Ufunc(1, 1, None, docstrings.get('numpy.core.umath.arctan'), + None, TD(inexact, f='atan', astype={'e':'f'}), TD(P, f='arctan'), ), 'arctanh' : Ufunc(1, 1, None, docstrings.get('numpy.core.umath.arctanh'), + None, TD(inexact, f='atanh', astype={'e':'f'}), TD(P, f='arctanh'), ), 'cos' : Ufunc(1, 1, None, docstrings.get('numpy.core.umath.cos'), + None, TD(inexact, f='cos', astype={'e':'f'}), TD(P, f='cos'), ), 'sin' : Ufunc(1, 1, None, docstrings.get('numpy.core.umath.sin'), + None, TD(inexact, f='sin', astype={'e':'f'}), TD(P, f='sin'), ), 'tan' : Ufunc(1, 1, None, docstrings.get('numpy.core.umath.tan'), + None, TD(inexact, f='tan', astype={'e':'f'}), TD(P, f='tan'), ), 'cosh' : Ufunc(1, 1, None, docstrings.get('numpy.core.umath.cosh'), + None, TD(inexact, f='cosh', astype={'e':'f'}), TD(P, f='cosh'), ), 'sinh' : Ufunc(1, 1, None, docstrings.get('numpy.core.umath.sinh'), + None, TD(inexact, f='sinh', astype={'e':'f'}), TD(P, f='sinh'), ), 'tanh' : Ufunc(1, 1, None, docstrings.get('numpy.core.umath.tanh'), + None, TD(inexact, f='tanh', astype={'e':'f'}), TD(P, f='tanh'), ), 'exp' : Ufunc(1, 1, None, docstrings.get('numpy.core.umath.exp'), + None, TD(inexact, f='exp', astype={'e':'f'}), TD(P, f='exp'), ), 'exp2' : Ufunc(1, 1, None, docstrings.get('numpy.core.umath.exp2'), + None, TD(inexact, f='exp2', astype={'e':'f'}), TD(P, f='exp2'), ), 'expm1' : Ufunc(1, 1, None, docstrings.get('numpy.core.umath.expm1'), + None, TD(inexact, f='expm1', astype={'e':'f'}), TD(P, f='expm1'), ), 'log' : Ufunc(1, 1, None, docstrings.get('numpy.core.umath.log'), + None, TD(inexact, f='log', astype={'e':'f'}), TD(P, f='log'), ), 'log2' : Ufunc(1, 1, None, docstrings.get('numpy.core.umath.log2'), + None, TD(inexact, f='log2', astype={'e':'f'}), TD(P, f='log2'), ), 'log10' : Ufunc(1, 1, None, docstrings.get('numpy.core.umath.log10'), + None, TD(inexact, f='log10', astype={'e':'f'}), TD(P, f='log10'), ), 'log1p' : Ufunc(1, 1, None, docstrings.get('numpy.core.umath.log1p'), + None, TD(inexact, f='log1p', astype={'e':'f'}), TD(P, f='log1p'), ), 'sqrt' : Ufunc(1, 1, None, docstrings.get('numpy.core.umath.sqrt'), + None, TD(inexact, f='sqrt', astype={'e':'f'}), TD(P, f='sqrt'), ), 'ceil' : Ufunc(1, 1, None, docstrings.get('numpy.core.umath.ceil'), + None, TD(flts, f='ceil', astype={'e':'f'}), TD(P, f='ceil'), ), 'trunc' : Ufunc(1, 1, None, docstrings.get('numpy.core.umath.trunc'), + None, TD(flts, f='trunc', astype={'e':'f'}), TD(P, f='trunc'), ), 'fabs' : Ufunc(1, 1, None, docstrings.get('numpy.core.umath.fabs'), + None, TD(flts, f='fabs', astype={'e':'f'}), TD(P, f='fabs'), ), 'floor' : Ufunc(1, 1, None, docstrings.get('numpy.core.umath.floor'), + None, TD(flts, f='floor', astype={'e':'f'}), TD(P, f='floor'), ), 'rint' : Ufunc(1, 1, None, docstrings.get('numpy.core.umath.rint'), + None, TD(inexact, f='rint', astype={'e':'f'}), TD(P, f='rint'), ), 'arctan2' : Ufunc(2, 1, None, docstrings.get('numpy.core.umath.arctan2'), + None, TD(flts, f='atan2', astype={'e':'f'}), TD(P, f='arctan2'), ), 'remainder' : Ufunc(2, 1, None, docstrings.get('numpy.core.umath.remainder'), + None, TD(intflt), TD(O, f='PyNumber_Remainder'), ), 'hypot' : Ufunc(2, 1, None, docstrings.get('numpy.core.umath.hypot'), + None, TD(flts, f='hypot', astype={'e':'f'}), TD(P, f='hypot'), ), 'isnan' : Ufunc(1, 1, None, docstrings.get('numpy.core.umath.isnan'), + None, TD(inexact, out='?'), ), 'isinf' : Ufunc(1, 1, None, docstrings.get('numpy.core.umath.isinf'), + None, TD(inexact, out='?'), ), 'isfinite' : Ufunc(1, 1, None, docstrings.get('numpy.core.umath.isfinite'), + None, TD(inexact, out='?'), ), 'signbit' : Ufunc(1, 1, None, docstrings.get('numpy.core.umath.signbit'), + None, TD(flts, out='?'), ), 'copysign' : Ufunc(2, 1, None, docstrings.get('numpy.core.umath.copysign'), + None, TD(flts), ), 'nextafter' : Ufunc(2, 1, None, docstrings.get('numpy.core.umath.nextafter'), + None, TD(flts), ), 'spacing' : Ufunc(1, 1, None, docstrings.get('numpy.core.umath.spacing'), + None, TD(flts), ), 'modf' : Ufunc(1, 2, None, docstrings.get('numpy.core.umath.modf'), + None, TD(flts), ), } @@ -831,6 +910,10 @@ r"""f = PyUFunc_FromFuncAndData(%s_functions, %s_data, %s_signatures, %d, uf.nin, uf.nout, uf.identity, name, docstring)) + if uf.typereso != None: + mlist.append( + r"((PyUFuncObject *)f)->type_resolution_function = &%s;" % + uf.typereso) mlist.append(r"""PyDict_SetItemString(dictionary, "%s", f);""" % name) mlist.append(r"""Py_DECREF(f);""") code3list.append('\n'.join(mlist)) diff --git a/numpy/core/src/umath/ufunc_object.c b/numpy/core/src/umath/ufunc_object.c index 693732562..463fb341c 100644 --- a/numpy/core/src/umath/ufunc_object.c +++ b/numpy/core/src/umath/ufunc_object.c @@ -1778,14 +1778,26 @@ PyUFunc_BinaryComparisonTypeResolution(PyUFuncObject *ufunc, PyUFuncGenericFunction *out_innerloop, void **out_innerloopdata) { - int i, type_num; + int i, type_num, type_num1, type_num2; char *ufunc_name; ufunc_name = ufunc->name ? ufunc->name : "<unnamed ufunc>"; - /* Use the default type resolution if there's a custom data type */ - if (PyArray_DESCR(operands[0])->type_num >= NPY_NTYPES || - PyArray_DESCR(operands[1])->type_num >= NPY_NTYPES) { + 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"); + 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); } @@ -1798,7 +1810,6 @@ PyUFunc_BinaryComparisonTypeResolution(PyUFuncObject *ufunc, } out_dtypes[1] = out_dtypes[0]; Py_INCREF(out_dtypes[1]); - } else { /* |