summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--numpy/core/code_generators/generate_umath.py85
-rw-r--r--numpy/core/src/umath/ufunc_object.c21
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 {
/*