numpy  2.0.0
src/umath/ufunc_type_resolution.c File Reference
#include "Python.h"
#include "npy_config.h"
#include "npy_pycompat.h"
#include "numpy/ufuncobject.h"
#include "ufunc_type_resolution.h"
#include "common.h"

Data Structures

struct  _ufunc_masker_data

Defines

#define _UMATHMODULE
#define NPY_NO_DEPRECATED_API   NPY_API_VERSION
#define PY_ARRAY_UNIQUE_SYMBOL   _npy_umathmodule_ARRAY_API
#define NO_IMPORT_ARRAY

Functions

static const char * npy_casting_to_string (NPY_CASTING casting)
NPY_NO_EXPORT int PyUFunc_ValidateCasting (PyUFuncObject *ufunc, NPY_CASTING casting, PyArrayObject **operands, PyArray_Descr **dtypes)
static PyArray_Descrensure_dtype_nbo (PyArray_Descr *type)
NPY_NO_EXPORT int PyUFunc_DefaultTypeResolver (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)
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_NegativeTypeResolver (PyUFuncObject *ufunc, NPY_CASTING casting, PyArrayObject **operands, PyObject *type_tup, PyArray_Descr **out_dtypes)
NPY_NO_EXPORT int PyUFunc_OnesLikeTypeResolver (PyUFuncObject *ufunc, NPY_CASTING NPY_UNUSED(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)
static PyArray_Descrtimedelta_dtype_with_copied_meta (PyArray_Descr *dtype)
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 PyUFunc_MixedDivisionTypeResolver (PyUFuncObject *ufunc, NPY_CASTING casting, PyArrayObject **operands, PyObject *type_tup, PyArray_Descr **out_dtypes)
static int find_userloop (PyUFuncObject *ufunc, PyArray_Descr **dtypes, PyUFuncGenericFunction *out_innerloop, void **out_innerloopdata)
NPY_NO_EXPORT int PyUFunc_DefaultLegacyInnerLoopSelector (PyUFuncObject *ufunc, PyArray_Descr **dtypes, PyUFuncGenericFunction *out_innerloop, void **out_innerloopdata, int *out_needs_api)
static NpyAuxDataufunc_masker_data_clone (NpyAuxData *data)
static void unmasked_ufunc_loop_as_masked (char **dataptrs, npy_intp *strides, char *mask, npy_intp mask_stride, npy_intp loopsize, NpyAuxData *innerloopdata)
NPY_NO_EXPORT int PyUFunc_DefaultMaskedInnerLoopSelector (PyUFuncObject *ufunc, PyArray_Descr **dtypes, PyArray_Descr *mask_dtype, npy_intp *NPY_UNUSED(fixed_strides), npy_intp NPY_UNUSED(fixed_mask_stride), PyUFunc_MaskedStridedInnerLoopFunc **out_innerloop, NpyAuxData **out_innerloopdata, int *out_needs_api)
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, PyArray_Descr **dtypes, int *out_no_castable_output, char *out_err_src_typecode, char *out_err_dst_typecode)
static int set_ufunc_loop_data_types (PyUFuncObject *self, PyArrayObject **op, PyArray_Descr **out_dtypes, int *type_nums, PyArray_Descr **dtypes)
static int linear_search_userloop_type_resolver (PyUFuncObject *self, PyArrayObject **op, NPY_CASTING input_casting, NPY_CASTING output_casting, int any_object, int use_min_scalar, PyArray_Descr **out_dtype, int *out_no_castable_output, char *out_err_src_typecode, char *out_err_dst_typecode)
static int type_tuple_userloop_type_resolver (PyUFuncObject *self, int n_specified, int *specified_types, PyArrayObject **op, NPY_CASTING casting, int any_object, int use_min_scalar, PyArray_Descr **out_dtype)
static int dtype_kind_to_simplified_ordering (char kind)
static int should_use_min_scalar (PyArrayObject **op, int nop)
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)

Define Documentation

#define _UMATHMODULE
#define NO_IMPORT_ARRAY
#define NPY_NO_DEPRECATED_API   NPY_API_VERSION
#define PY_ARRAY_UNIQUE_SYMBOL   _npy_umathmodule_ARRAY_API

Function Documentation

static int dtype_kind_to_simplified_ordering ( char  kind) [static]
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.
Boolean kind
Unsigned int kind
Signed int kind
Float kind
Complex kind
Anything else

Referenced by set_ufunc_loop_data_types().

static PyArray_Descr* ensure_dtype_nbo ( PyArray_Descr type) [static]
Returns a new reference to type if it is already NBO, otherwise returns a copy converted to NBO.

Referenced by PyUFunc_MultiplicationTypeResolver().

static int find_userloop ( PyUFuncObject ufunc,
PyArray_Descr **  dtypes,
PyUFuncGenericFunction out_innerloop,
void **  out_innerloopdata 
) [static]
Use this to try to avoid repeating the same userdef loop search
no more ufunc arguments to check
It matched
Didn't find a match
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().

static int linear_search_userloop_type_resolver ( PyUFuncObject self,
PyArrayObject **  op,
NPY_CASTING  input_casting,
NPY_CASTING  output_casting,
int  any_object,
int  use_min_scalar,
PyArray_Descr **  out_dtype,
int *  out_no_castable_output,
char *  out_err_src_typecode,
char *  out_err_dst_typecode 
) [static]
Does a search through the arguments and the loops
Use this to try to avoid repeating the same userdef loop search
no more ufunc arguments to check
Error
Found a match
Didn't find a match
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
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 NPY_OBJECT, NPY_VOID, PyArray_CanCastArrayTo(), PyArray_CanCastTypeTo(), PyArray_DESCR, and PyArray_DescrFromType().

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
NPY_NO_EXPORT int PyUFunc_DefaultTypeResolver ( PyUFuncObject ufunc,
NPY_CASTING  casting,
PyArrayObject **  operands,
PyObject *  type_tup,
PyArray_Descr **  out_dtypes 
)
This function applies the default type resolution rules

for the provided ufunc.

Returns 0 on success, -1 on error.

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, or a float32 loop for float64 inputs.
Find the best ufunc inner loop, and fill in the dtypes
Find the specified ufunc inner loop, and fill in the dtypes

References linear_search_type_resolver(), _tagPyUFuncObject::nin, _tagPyUFuncObject::nout, NPY_SAFE_CASTING, PyArray_DESCR, PyTypeNum_ISOBJECT, and type_tuple_type_resolver().

Referenced by PyUFunc_MultiplicationTypeResolver(), and PyUFunc_SimpleUnaryOperationTypeResolver().

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_MixedDivisionTypeResolver ( PyUFuncObject ufunc,
NPY_CASTING  casting,
PyArrayObject **  operands,
PyObject *  type_tup,
PyArray_Descr **  out_dtypes 
)
Function to check and report floor division warning when python2.x is invoked with -3 switch See PEP238 and #7949 for numpy This function will not be hit for py3 or when __future__ imports division. See generate_umath.py for reason
Depreciation checks needed only on python 2
If both types are integer, warn the user, same as python does

References data, _ufunc_masker_data::nargs, npy_memchr(), _ufunc_masker_data::unmasked_innerloop, and _ufunc_masker_data::unmasked_innerloopdata.

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_NegativeTypeResolver ( PyUFuncObject ufunc,
NPY_CASTING  casting,
PyArrayObject **  operands,
PyObject *  type_tup,
PyArray_Descr **  out_dtypes 
)
The type resolver would have upcast already
2013-12-05, 1.9

References NPY_UNSAFE_CASTING, and PyUFunc_SimpleUnaryOperationTypeResolver().

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

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

Referenced by PyUFunc_NegativeTypeResolver().

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
The type resolver would have upcast already
2013-12-05, 1.9
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

References PyArray_DESCR, PyArray_PromoteTypes(), and timedelta_dtype_with_copied_meta().

NPY_NO_EXPORT int PyUFunc_ValidateCasting ( PyUFuncObject ufunc,
NPY_CASTING  casting,
PyArrayObject **  operands,
PyArray_Descr **  dtypes 
)
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.

References _tagPyUFuncObject::name, _tagPyUFuncObject::nin, _tagPyUFuncObject::nout, npy_casting_to_string(), PyArray_CanCastArrayTo(), PyArray_CanCastTypeTo(), PyArray_DESCR, PyUString_ConcatAndDel, PyUString_FromFormat, and PyUString_FromString.

Referenced by PyUFunc_MultiplicationTypeResolver().

static int set_ufunc_loop_data_types ( PyUFuncObject self,
PyArrayObject **  op,
PyArray_Descr **  out_dtypes,
int *  type_nums,
PyArray_Descr **  dtypes 
) [static]
Fill the dtypes array. For outputs, also search the inputs for a matching type_num to copy instead of creating a new one, similarly to preserve metadata.
Copy the dtype from 'op' if the type_num matches, to preserve metadata.
For outputs, copy the dtype from op[0] if the type_num matches, similarly to preserve metdata.
Otherwise create a plain descr from the type number

References dtype_kind_to_simplified_ordering(), kind(), PyArray_DESCR, and PyArray_NDIM.

Referenced by ufunc_loop_matches().

static int should_use_min_scalar ( PyArrayObject **  op,
int  nop 
) [static]
Determine if there are any scalars, and if so, whether the maximum "kind" of the scalars surpasses the maximum "kind" of the arrays
Indicate whether to use the min_scalar_type function

Referenced by type_tuple_userloop_type_resolver().

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.

References PyUFunc_SimpleBinaryOperationTypeResolver().

Referenced by PyUFunc_SubtractionTypeResolver().

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
no match
no match
Error
Cannot cast inputs
Success
If no function was found, throw an error

Referenced by PyUFunc_DefaultTypeResolver().

static int type_tuple_userloop_type_resolver ( PyUFuncObject self,
int  n_specified,
int *  specified_types,
PyArrayObject **  op,
NPY_CASTING  casting,
int  any_object,
int  use_min_scalar,
PyArray_Descr **  out_dtype 
) [static]
Does a search through the arguments and the loops
Use this to try to avoid repeating the same userdef loop search
It works
Didn't match
Error
Didn't find a match

References NPY_MAXARGS, NPY_NOTYPE, PyArray_DescrConverter(), PyArray_DescrFromType(), PyBytes_AsStringAndSize, PyBytes_Check, should_use_min_scalar(), and _PyArray_Descr::type_num.

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,
PyArray_Descr **  dtypes,
int *  out_no_castable_output,
char *  out_err_src_typecode,
char *  out_err_dst_typecode 
) [static]
First check if all the inputs can be safely cast to the types for this function
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 type num is NPY_VOID and struct dtypes have been passed in, use struct dtype object. Otherwise create new dtype object from type num.
If all the inputs are scalars, use the regular promotion rules, not the special value-checking ones.
If all the inputs were ok, then check casting back to the outputs.

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

static NpyAuxData* ufunc_masker_data_clone ( NpyAuxData data) [static]
Allocate a new one
Copy the data (unmasked data doesn't have object semantics)
static void unmasked_ufunc_loop_as_masked ( char **  dataptrs,
npy_intp strides,
char *  mask,
npy_intp  mask_stride,
npy_intp  loopsize,
NpyAuxData innerloopdata 
) [static]
This function wraps a regular unmasked ufunc inner loop as a masked ufunc inner loop, only calling the function for elements where the mask is True.
Put the aux data into local variables
Process the data as runs of unmasked values
Skip masked values
Process unmasked values (assumes unmasked loop doesn't mess with the 'args' pointer values)