numpy 2.0.0
src/umath/ufunc_type_resolution.h File Reference

Go to the source code of this file.

Functions

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)
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_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)

Function Documentation

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 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.

For making a better error message on coercion error
If the ufunc has userloops, search for them.
Error
A loop was found
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.

System Message: ERROR/3 (<string>, line 9) Unexpected indentation.

<blockquote>

  • Use PyArray_ResultType to get the output type
  • Look up the inner loop in a table based on the output type_num

</blockquote>

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).
Copy the types into an int array for matching
Error
Found a match
Save the inner loop and its data
If no function was found, throw an error
TODO: We should try again if the casting rule is same_kind
or unsafe, and look for a function more liberally.

Referenced by PyUFunc_DefaultTypeResolution().

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 
)
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.

For making a better error message on coercion error
Fill in specified_types from the tuple or string
If the ufunc has userloops, search for them.
Error
Found matching loop
Copy the types into an int array for matching
Error
It worked
Save the inner loop and its data
Didn't work
If no function was found, throw an error

Referenced by PyUFunc_DefaultTypeResolution().

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 
)
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.

Use the default for complex types, to find the loop producing float

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 
)
This function applies the type resolution rules for addition. In particular, there are a number of special cases with datetime:

System Message: ERROR/3 (<string>, line 3) Unexpected indentation.

<blockquote> 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>)]</blockquote>

System Message: WARNING/2 (<string>, line 10) Block quote ends without a blank line; unexpected unindent.
TODO: Non-linear time unit cases require highly special-cased loops
M8[<A>] + m8[Y|M|B] m8[Y|M|B] + M8[<A>]

Use the default when datetime and timedelta are not involved
m8[<A>] + m8[<B>] => m8[gcd(<A>,<B>)] + m8[gcd(<A>,<B>)]
m8[<A>] + M8[<B>] => m8[gcd(<A>,<B>)] + M8[gcd(<A>,<B>)]
Make a new NPY_TIMEDELTA, and copy the datetime's metadata
m8[<A>] + int => m8[<A>] + m8[<A>]
M8[<A>] + m8[<B>] => M8[gcd(<A>,<B>)] + m8[gcd(<A>,<B>)]
Make a new NPY_TIMEDELTA, and copy the datetime's metadata
M8[<A>] + int => M8[<A>] + m8[<A>]
Make a new NPY_TIMEDELTA, and copy type1's metadata
int + m8[<A>] => m8[<A>] + m8[<A>]
Make a new NPY_TIMEDELTA, and copy type2's metadata
Check against the casting rules
Search in the functions list

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 
)
This function applies the type resolution rules for division. In particular, there are a number of special cases with datetime:

System Message: ERROR/3 (<string>, line 3) Unexpected indentation.

<blockquote> 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>]</blockquote>

Use the default when datetime and timedelta are not involved
m8[<A>] / m8[<B>] to m8[gcd(<A>,<B>)] / m8[gcd(<A>,<B>)] -> float64
m8[<A>] / int## => m8[<A>] / int64
m8[<A>] / float## => m8[<A>] / float64
Check against the casting rules
Search in the functions list

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 
)
This function applies the type resolution rules for multiplication. In particular, there are a number of special cases with datetime:

System Message: ERROR/3 (<string>, line 3) Unexpected indentation.

<blockquote> int## * m8[<A>] => int64 * m8[<A>] m8[<A>] * int## => m8[<A>] * int64 float## * m8[<A>] => float64 * m8[<A>] m8[<A>] * float## => m8[<A>] * float64</blockquote>

Use the default when datetime and timedelta are not involved
m8[<A>] * int## => m8[<A>] * int64
m8[<A>] * float## => m8[<A>] * float64
int## * m8[<A>] => int64 * m8[<A>]
float## * m8[<A>] => float64 * m8[<A>]
Check against the casting rules
Search in the functions list

References _tagPyUFuncObject::data, ensure_dtype_nbo(), _tagPyUFuncObject::functions, _tagPyUFuncObject::name, NPY_DOUBLE, NPY_LONGLONG, NPY_TIMEDELTA, _tagPyUFuncObject::ntypes, PyArray_DESCR, PyArray_DescrFromType(), PyArray_DescrNewFromType(), PyArray_PromoteTypes(), PyTypeNum_ISDATETIME, PyTypeNum_ISFLOAT, PyTypeNum_ISINTEGER, PyUFunc_DefaultTypeResolution(), PyUFunc_ValidateCasting(), PyUString_ConcatAndDel, PyUString_FromFormat, PyUString_FromString, and _tagPyUFuncObject::types.

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_SimpleBinaryComparisonTypeResolution ( PyUFuncObject ufunc,
NPY_CASTING  casting,
PyArrayObject **  operands,
PyObject *  type_tup,
PyArray_Descr **  out_dtypes,
PyUFuncGenericFunction out_innerloop,
void **  out_innerloopdata 
)
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.

Use the default type resolution if there's a custom data type or object arrays.
Input types are the result type
If the type tuple isn't a single-element tuple, let the default type resolution handle this one.
Output type is always boolean
Check against the casting rules
If we have a built-in type, search in the functions list

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 
)
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.

Use the default type resolution if there's a custom data type or object arrays.
Input types are the result type
If the type tuple isn't a single-element tuple, let the default type resolution handle this one.
Check against the casting rules
If we have a built-in type, search in the functions list

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 
)
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.

Use the default type resolution if there's a custom data type or object arrays.
Input types are the result type
If the type tuple isn't a single-element tuple, let the default type resolution handle this one.
Check against the casting rules
If we have a built-in type, search in the functions list

References PyUFunc_DefaultTypeResolution().

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 
)
This function applies the type resolution rules for subtraction. In particular, there are a number of special cases with datetime:

System Message: ERROR/3 (<string>, line 3) Unexpected indentation.

<blockquote> 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>)]</blockquote>

System Message: WARNING/2 (<string>, line 8) Block quote ends without a blank line; unexpected unindent.
TODO: Non-linear time unit cases require highly special-cased loops
M8[<A>] - m8[Y|M|B]

Use the default when datetime and timedelta are not involved
m8[<A>] - m8[<B>] => m8[gcd(<A>,<B>)] - m8[gcd(<A>,<B>)]
m8[<A>] - int => m8[<A>] - m8[<A>]
M8[<A>] - m8[<B>] => M8[gcd(<A>,<B>)] - m8[gcd(<A>,<B>)]
Make a new NPY_TIMEDELTA, and copy the datetime's metadata
M8[<A>] - int => M8[<A>] - m8[<A>]
Make a new NPY_TIMEDELTA, and copy type1's metadata
M8[<A>] - M8[<B>] => M8[gcd(<A>,<B>)] - M8[gcd(<A>,<B>)]
Make a new NPY_TIMEDELTA, and copy type1's metadata
int - m8[<A>] => m8[<A>] - m8[<A>]
Check against the casting rules
Search in the functions list