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_SimpleBinaryComparisonTypeResolver (PyUFuncObject *ufunc, NPY_CASTING casting, PyArrayObject **operands, PyObject *type_tup, PyArray_Descr **out_dtypes)
NPY_NO_EXPORT int PyUFunc_SimpleUnaryOperationTypeResolver (PyUFuncObject *ufunc, NPY_CASTING casting, PyArrayObject **operands, PyObject *type_tup, PyArray_Descr **out_dtypes)
NPY_NO_EXPORT int PyUFunc_OnesLikeTypeResolver (PyUFuncObject *ufunc, NPY_CASTING casting, PyArrayObject **operands, PyObject *type_tup, PyArray_Descr **out_dtypes)
NPY_NO_EXPORT int PyUFunc_SimpleBinaryOperationTypeResolver (PyUFuncObject *ufunc, NPY_CASTING casting, PyArrayObject **operands, PyObject *type_tup, PyArray_Descr **out_dtypes)
NPY_NO_EXPORT int PyUFunc_AbsoluteTypeResolver (PyUFuncObject *ufunc, NPY_CASTING casting, PyArrayObject **operands, PyObject *type_tup, PyArray_Descr **out_dtypes)
NPY_NO_EXPORT int PyUFunc_AdditionTypeResolver (PyUFuncObject *ufunc, NPY_CASTING casting, PyArrayObject **operands, PyObject *type_tup, PyArray_Descr **out_dtypes)
NPY_NO_EXPORT int PyUFunc_SubtractionTypeResolver (PyUFuncObject *ufunc, NPY_CASTING casting, PyArrayObject **operands, PyObject *type_tup, PyArray_Descr **out_dtypes)
NPY_NO_EXPORT int PyUFunc_MultiplicationTypeResolver (PyUFuncObject *ufunc, NPY_CASTING casting, PyArrayObject **operands, PyObject *type_tup, PyArray_Descr **out_dtypes)
NPY_NO_EXPORT int PyUFunc_DivisionTypeResolver (PyUFuncObject *ufunc, NPY_CASTING casting, PyArrayObject **operands, PyObject *type_tup, PyArray_Descr **out_dtypes)
NPY_NO_EXPORT int linear_search_type_resolver (PyUFuncObject *self, PyArrayObject **op, NPY_CASTING input_casting, NPY_CASTING output_casting, int any_object, PyArray_Descr **out_dtype)
NPY_NO_EXPORT int type_tuple_type_resolver (PyUFuncObject *self, PyObject *type_tup, PyArrayObject **op, NPY_CASTING casting, int any_object, PyArray_Descr **out_dtype)
NPY_NO_EXPORT int PyUFunc_DefaultLegacyInnerLoopSelector (PyUFuncObject *ufunc, PyArray_Descr **dtypes, PyUFuncGenericFunction *out_innerloop, void **out_innerloopdata, int *out_needs_api)
NPY_NO_EXPORT int PyUFunc_DefaultMaskedInnerLoopSelector (PyUFuncObject *ufunc, PyArray_Descr **dtypes, PyArray_Descr *mask_dtypes, npy_intp *NPY_UNUSED(fixed_strides), npy_intp NPY_UNUSED(fixed_mask_stride), PyUFunc_MaskedStridedInnerLoopFunc **out_innerloop, NpyAuxData **out_innerloopdata, int *out_needs_api)

Function Documentation

NPY_NO_EXPORT int linear_search_type_resolver ( PyUFuncObject self,
PyArrayObject **  op,
NPY_CASTING  input_casting,
NPY_CASTING  output_casting,
int  any_object,
PyArray_Descr **  out_dtype 
)
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
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_DefaultTypeResolver().

NPY_NO_EXPORT int PyUFunc_AbsoluteTypeResolver ( PyUFuncObject ufunc,
NPY_CASTING  casting,
PyArrayObject **  operands,
PyObject *  type_tup,
PyArray_Descr **  out_dtypes 
)
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_AdditionTypeResolver ( PyUFuncObject ufunc,
NPY_CASTING  casting,
PyArrayObject **  operands,
PyObject *  type_tup,
PyArray_Descr **  out_dtypes 
)
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

References ensure_dtype_nbo(), NPY_TIMEDELTA, and PyArray_DESCR.

NPY_NO_EXPORT int PyUFunc_DefaultLegacyInnerLoopSelector ( PyUFuncObject ufunc,
PyArray_Descr **  dtypes,
PyUFuncGenericFunction out_innerloop,
void **  out_innerloopdata,
int *  out_needs_api 
)
If there are user-loops search them first. TODO: There needs to be a loop selection acceleration structure,

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

<blockquote> like a hash table.</blockquote>

Error
Found a loop
Copy the types into an int array for matching

References PyArray_free.

NPY_NO_EXPORT int PyUFunc_DefaultMaskedInnerLoopSelector ( PyUFuncObject ufunc,
PyArray_Descr **  dtypes,
PyArray_Descr mask_dtype,
npy_intp NPY_UNUSEDfixed_strides,
npy_intp   NPY_UNUSEDfixed_mask_stride,
PyUFunc_MaskedStridedInnerLoopFunc **  out_innerloop,
NpyAuxData **  out_innerloopdata,
int *  out_needs_api 
)
This function wraps a legacy inner loop so it becomes masked.
Returns 0 on success, -1 on error.
Create a new NpyAuxData object for the masker data
Get the unmasked ufunc inner loop
Return the loop function + aux data

References _loop1d_info::arg_types, _loop1d_info::next, NpyCapsule_AsVoidPtr(), PyArray_DESCR, PyTypeNum_ISUSERDEF, set_ufunc_loop_data_types(), and ufunc_loop_matches().

NPY_NO_EXPORT int PyUFunc_DivisionTypeResolver ( PyUFuncObject ufunc,
NPY_CASTING  casting,
PyArrayObject **  operands,
PyObject *  type_tup,
PyArray_Descr **  out_dtypes 
)
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
NPY_NO_EXPORT int PyUFunc_MultiplicationTypeResolver ( PyUFuncObject ufunc,
NPY_CASTING  casting,
PyArrayObject **  operands,
PyObject *  type_tup,
PyArray_Descr **  out_dtypes 
)
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

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

NPY_NO_EXPORT int PyUFunc_OnesLikeTypeResolver ( PyUFuncObject ufunc,
NPY_CASTING  casting,
PyArrayObject **  operands,
PyObject *  type_tup,
PyArray_Descr **  out_dtypes 
)
NPY_NO_EXPORT int PyUFunc_SimpleBinaryComparisonTypeResolver ( PyUFuncObject ufunc,
NPY_CASTING  casting,
PyArrayObject **  operands,
PyObject *  type_tup,
PyArray_Descr **  out_dtypes 
)
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.
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
NPY_NO_EXPORT int PyUFunc_SimpleBinaryOperationTypeResolver ( PyUFuncObject ufunc,
NPY_CASTING  casting,
PyArrayObject **  operands,
PyObject *  type_tup,
PyArray_Descr **  out_dtypes 
)
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

References PyArray_ResultType().

Referenced by timedelta_dtype_with_copied_meta().

NPY_NO_EXPORT int PyUFunc_SimpleUnaryOperationTypeResolver ( PyUFuncObject ufunc,
NPY_CASTING  casting,
PyArrayObject **  operands,
PyObject *  type_tup,
PyArray_Descr **  out_dtypes 
)
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

References PyUFunc_DefaultTypeResolver().

NPY_NO_EXPORT int PyUFunc_SubtractionTypeResolver ( PyUFuncObject ufunc,
NPY_CASTING  casting,
PyArrayObject **  operands,
PyObject *  type_tup,
PyArray_Descr **  out_dtypes 
)
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
NPY_NO_EXPORT int type_tuple_type_resolver ( PyUFuncObject self,
PyObject *  type_tup,
PyArrayObject **  op,
NPY_CASTING  casting,
int  any_object,
PyArray_Descr **  out_dtype 
)
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
Didn't work
If no function was found, throw an error

Referenced by PyUFunc_DefaultTypeResolver().