numpy 2.0.0
src/umath/ufunc_object.c File Reference
#include "Python.h"
#include "npy_config.h"
#include "numpy/npy_3kcompat.h"
#include "numpy/noprefix.h"
#include "numpy/ufuncobject.h"
#include "lowlevel_strided_loops.h"
#include "ufunc_object.h"

Data Structures

struct  _simple_cobj

Defines

#define _UMATHMODULE
#define NPY_NO_DEPRECATED_API
#define NPY_UF_DBG_TRACING   0
#define NPY_UF_DBG_PRINT(s)
#define NPY_UF_DBG_PRINT1(s, p1)
#define NPY_UF_DBG_PRINT2(s, p1, p2)
#define NPY_UF_DBG_PRINT3(s, p1, p2, p3)
#define USE_USE_DEFAULTS   1
#define USE_NEW_ITERATOR_GENFUNC   1
#define HANDLEIT(NAME, str)
#define NO_UFUNCLOOP   0
#define ZERO_EL_REDUCELOOP   0
#define ONE_UFUNCLOOP   1
#define ONE_EL_REDUCELOOP   1
#define NOBUFFER_UFUNCLOOP   2
#define NOBUFFER_REDUCELOOP   2
#define BUFFER_UFUNCLOOP   3
#define BUFFER_REDUCELOOP   3
#define SIGNATURE_NOBUFFER_UFUNCLOOP   4
#define _GETATTR_(str, rstr)
#define _SETCPTR(cobj, val)   ((_simple_cobj *)(cobj))->c_obj = (val)

Functions

static int _does_loop_use_arrays (void *data)
static int _error_handler (int method, PyObject *errobj, char *errtype, int retstatus, int *first)
NPY_NO_EXPORT int PyUFunc_getfperr (void)
NPY_NO_EXPORT int PyUFunc_handlefperr (int errmask, PyObject *errobj, int retstatus, int *first)
NPY_NO_EXPORT int PyUFunc_checkfperr (int errmask, PyObject *errobj, int *first)
NPY_NO_EXPORT void PyUFunc_clearfperr ()
static void _find_array_prepare (PyObject *args, PyObject *kwds, PyObject **output_prep, int nin, int nout)
static int _extract_pyvals (PyObject *ref, char *name, int *bufsize, int *errmask, PyObject **errobj)
NPY_NO_EXPORT int PyUFunc_GetPyValues (char *name, int *bufsize, int *errmask, PyObject **errobj)
static int _has_reflected_op (PyObject *op, char *name)
static int _next_non_white_space (const char *str, int offset)
static int _is_alpha_underscore (char ch)
static int _is_alnum_underscore (char ch)
static int _get_end_of_name (const char *str, int offset)
static int _is_same_name (const char *s1, const char *s2)
static int _parse_signature (PyUFuncObject *self, const char *signature)
static int get_ufunc_arguments (PyUFuncObject *self, PyObject *args, PyObject *kwds, PyArrayObject **out_op, NPY_ORDER *out_order, NPY_CASTING *out_casting, PyObject **out_extobj, PyObject **out_typetup, int *out_subok, PyArrayObject **out_wheremask)
static int check_for_trivial_loop (PyUFuncObject *self, PyArrayObject **op, PyArray_Descr **dtype, npy_intp buffersize)
static void trivial_two_operand_loop (PyArrayObject **op, PyUFuncGenericFunction innerloop, void *innerloopdata)
static void trivial_three_operand_loop (PyArrayObject **op, PyUFuncGenericFunction innerloop, void *innerloopdata)
static int prepare_ufunc_output (PyUFuncObject *self, PyArrayObject **op, PyObject *arr_prep, PyObject *arr_prep_args, int i)
static int iterator_loop (PyUFuncObject *self, PyArrayObject **op, PyArray_Descr **dtype, NPY_ORDER order, npy_intp buffersize, PyObject **arr_prep, PyObject *arr_prep_args, PyUFuncGenericFunction innerloop, void *innerloopdata)
static int execute_ufunc_loop (PyUFuncObject *self, int trivial_loop_ok, PyArrayObject **op, PyArray_Descr **dtype, NPY_ORDER order, npy_intp buffersize, PyObject **arr_prep, PyObject *arr_prep_args, PyUFuncGenericFunction innerloop, void *innerloopdata)
static int execute_ufunc_masked_loop (PyUFuncObject *self, PyArrayObject *wheremask, PyArrayObject **op, PyArray_Descr **dtype, NPY_ORDER order, npy_intp buffersize, PyObject **arr_prep, PyObject *arr_prep_args, PyUFuncGenericMaskedFunction innerloop, NpyAuxData *innerloopdata)
static PyObject * make_arr_prep_args (npy_intp nin, PyObject *args, PyObject *kwds)
static int PyUFunc_GeneralizedFunction (PyUFuncObject *self, PyObject *args, PyObject *kwds, PyArrayObject **op)
NPY_NO_EXPORT int PyUFunc_GenericFunction (PyUFuncObject *self, PyObject *args, PyObject *kwds, PyArrayObject **op)
static int get_binary_op_function (PyUFuncObject *self, int *otype, PyUFuncGenericFunction *out_innerloop, void **out_innerloopdata)
static PyObject * PyUFunc_ReductionOp (PyUFuncObject *self, PyArrayObject *arr, PyArrayObject *out, int axis, int otype, int operation, char *opname)
static PyObject * PyUFunc_Reduce (PyUFuncObject *self, PyArrayObject *arr, PyArrayObject *out, int axis, int otype)
static PyObject * PyUFunc_Accumulate (PyUFuncObject *self, PyArrayObject *arr, PyArrayObject *out, int axis, int otype)
static PyObject * PyUFunc_Reduceat (PyUFuncObject *self, PyArrayObject *arr, PyArrayObject *ind, PyArrayObject *out, int axis, int otype)
static PyObject * PyUFunc_GenericReduction (PyUFuncObject *self, PyObject *args, PyObject *kwds, int operation)
static void _find_array_wrap (PyObject *args, PyObject *kwds, PyObject **output_wrap, int nin, int nout)
static PyObject * ufunc_generic_call (PyUFuncObject *self, PyObject *args, PyObject *kwds)
NPY_NO_EXPORT PyObject * ufunc_geterr (PyObject *NPY_UNUSED(dummy), PyObject *args)
static int ufunc_update_use_defaults (void)
NPY_NO_EXPORT PyObject * ufunc_seterr (PyObject *NPY_UNUSED(dummy), PyObject *args)
NPY_NO_EXPORT int PyUFunc_ReplaceLoopBySignature (PyUFuncObject *func, PyUFuncGenericFunction newfunc, int *signature, PyUFuncGenericFunction *oldfunc)
NPY_NO_EXPORT PyObject * PyUFunc_FromFuncAndData (PyUFuncGenericFunction *func, void **data, char *types, int ntypes, int nin, int nout, int identity, char *name, char *doc, int check_return)
NPY_NO_EXPORT PyObject * PyUFunc_FromFuncAndDataAndSignature (PyUFuncGenericFunction *func, void **data, char *types, int ntypes, int nin, int nout, int identity, char *name, char *doc, int check_return, const char *signature)
NPY_NO_EXPORT int PyUFunc_SetUsesArraysAsData (void **data, size_t i)
static int cmp_arg_types (int *arg1, int *arg2, int n)
static NPY_INLINE void _free_loop1d_list (PyUFunc_Loop1d *data)
static void _loop1d_list_free (void *ptr)
NPY_NO_EXPORT int PyUFunc_RegisterLoopForType (PyUFuncObject *ufunc, int usertype, PyUFuncGenericFunction function, int *arg_types, void *data)
static void ufunc_dealloc (PyUFuncObject *self)
static PyObject * ufunc_repr (PyUFuncObject *self)
static PyObject * ufunc_outer (PyUFuncObject *self, PyObject *args, PyObject *kwds)
static PyObject * ufunc_reduce (PyUFuncObject *self, PyObject *args, PyObject *kwds)
static PyObject * ufunc_accumulate (PyUFuncObject *self, PyObject *args, PyObject *kwds)
static PyObject * ufunc_reduceat (PyUFuncObject *self, PyObject *args, PyObject *kwds)
static PyObject * _makeargs (int num, char *ltr, int null_if_none)
static char _typecharfromnum (int num)
static PyObject * ufunc_get_doc (PyUFuncObject *self)
static PyObject * ufunc_get_nin (PyUFuncObject *self)
static PyObject * ufunc_get_nout (PyUFuncObject *self)
static PyObject * ufunc_get_nargs (PyUFuncObject *self)
static PyObject * ufunc_get_ntypes (PyUFuncObject *self)
static PyObject * ufunc_get_types (PyUFuncObject *self)
static PyObject * ufunc_get_name (PyUFuncObject *self)
static PyObject * ufunc_get_identity (PyUFuncObject *self)
static PyObject * ufunc_get_signature (PyUFuncObject *self)

Variables

static int PyUFunc_NUM_NODEFAULTS = 0
static PyObject * PyUFunc_PYVALS_NAME = NULL
static struct PyMethodDef ufunc_methods []
static PyGetSetDef ufunc_getset []
NPY_NO_EXPORT PyTypeObject PyUFunc_Type

Define Documentation

#define _GETATTR_ (   str,
  rstr 
)
Value:
do {if (strcmp(name, #str) == 0)     \
        return PyObject_HasAttrString(op, "__" #rstr "__");} while (0);
#define _SETCPTR (   cobj,
  val 
)    ((_simple_cobj *)(cobj))->c_obj = (val)
#define _UMATHMODULE
#define BUFFER_REDUCELOOP   3
#define BUFFER_UFUNCLOOP   3
#define HANDLEIT (   NAME,
  str 
)
Value:
{if (retstatus & UFUNC_FPE_##NAME) {        \
            handle = errmask & UFUNC_MASK_##NAME;                       \
            if (handle &&                                               \
                _error_handler(handle >> UFUNC_SHIFT_##NAME,            \
                               errobj, str, retstatus, first) < 0)      \
                return -1;                                              \
        }}
#define NO_UFUNCLOOP   0
#define NOBUFFER_REDUCELOOP   2
#define NOBUFFER_UFUNCLOOP   2
#define NPY_NO_DEPRECATED_API
#define NPY_UF_DBG_PRINT (   s)
#define NPY_UF_DBG_PRINT1 (   s,
  p1 
)
#define NPY_UF_DBG_PRINT2 (   s,
  p1,
  p2 
)
#define NPY_UF_DBG_PRINT3 (   s,
  p1,
  p2,
  p3 
)
#define NPY_UF_DBG_TRACING   0
**** PRINTF DEBUG TRACING *********
#define ONE_EL_REDUCELOOP   1
#define ONE_UFUNCLOOP   1
#define SIGNATURE_NOBUFFER_UFUNCLOOP   4
#define USE_NEW_ITERATOR_GENFUNC   1
#define USE_USE_DEFAULTS   1
System Message: ERROR/3 (<string>, line 1) Document or section may not begin with a transition.

System Message: ERROR/3 (<string>, line 1) Document may not end with a transition.
System Message: ERROR/3 (<string>, line 1) Document or section may not begin with a transition.

System Message: ERROR/3 (<string>, line 1) Document may not end with a transition.
#define ZERO_EL_REDUCELOOP   0

Function Documentation

static int _does_loop_use_arrays ( void *  data) [static]
System Message: ERROR/3 (<string>, line 1) Document or section may not begin with a transition.

System Message: ERROR/3 (<string>, line 1) Document may not end with a transition.
System Message: ERROR/3 (<string>, line 1) Document or section may not begin with a transition.

System Message: ERROR/3 (<string>, line 1) Document may not end with a transition.
Return 1 if the given data pointer for the loop specifies that it needs the arrays as the data pointer.

NOTE: This is easier to specify with the type_resolution_function
in the ufunc object.
static int _error_handler ( int  method,
PyObject *  errobj,
char *  errtype,
int  retstatus,
int *  first 
) [static]
fpstatus is the ufunc_formatted hardware status errmask is the handling mask specified by the user. errobj is a Python object with (string, callable object or None) or NULL
2. for each of the flags determine whether to ignore, warn, raise error, or call Python function. If ignore, do nothing If warn, print a warning and continue If raise return an error If call, call a user-defined function with string
static int _extract_pyvals ( PyObject *  ref,
char *  name,
int *  bufsize,
int *  errmask,
PyObject **  errobj 
) [static]
Extracts some values from the global pyvals tuple. ref - should hold the global tuple name - is the name of the ufunc (ufuncobj->name) bufsize - receives the buffer size to use errmask - receives the bitmask for error handling errobj - receives the python object to call with the error,

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

<blockquote> if an error handling method is 'call'</blockquote>

References PyUString_InternFromString, and UFUNC_PYVALS_NAME.

static void _find_array_prepare ( PyObject *  args,
PyObject *  kwds,
PyObject **  output_prep,
int  nin,
int  nout 
) [static]
This function analyzes the input arguments and determines an appropriate __array_prepare__ function to call for the outputs.
If an output argument is provided, then it is prepped with its own __array_prepare__ not with the one determined by the input arguments.
if the provided output argument is already an ndarray, the prepping function is None (which means no prepping will be done --- not even PyArray_Return).
A NULL is placed in output_prep for outputs that should just have PyArray_Return called.

If a 'subok' parameter is passed and isn't True, don't wrap
If we have some preps defined, find the one of highest priority
Here prep is the prepping function determined from the input arrays (could be NULL).
For all the output arrays decide what to do.
1) Use the prep function determined from the input arrays This is the default if the output array is not passed in.
2) Use the __array_prepare__ method of the output object. This is special cased for exact ndarray so that no PyArray_Return is done in that case.
Output argument one may also be in a keyword argument
Output argument one may also be in a keyword argument
None signals to not call any wrapping

static void _find_array_wrap ( PyObject *  args,
PyObject *  kwds,
PyObject **  output_wrap,
int  nin,
int  nout 
) [static]
This function analyzes the input arguments and determines an appropriate __array_wrap__ function to call for the outputs.
If an output argument is provided, then it is wrapped with its own __array_wrap__ not with the one determined by the input arguments.
if the provided output argument is already an array, the wrapping function is None (which means no wrapping will be done --- not even PyArray_Return).
A NULL is placed in output_wrap for outputs that should just have PyArray_Return called.

If a 'subok' parameter is passed and isn't True, don't wrap
If we have some wraps defined, find the one of highest priority
Here wrap is the wrapping function determined from the input arrays (could be NULL).
For all the output arrays decide what to do.
1) Use the wrap function determined from the input arrays This is the default if the output array is not passed in.
2) Use the __array_wrap__ method of the output object passed in. -- this is special cased for exact ndarray so that no PyArray_Return is done in that case.
Output argument one may also be in a keyword argument
Output argument one may also be in a keyword argument
None signals to not call any wrapping

static NPY_INLINE void _free_loop1d_list ( PyUFunc_Loop1d data) [static]
This frees the linked-list structure when the CObject is destroyed (removed from the internal dictionary)
static int _get_end_of_name ( const char *  str,
int  offset 
) [static]
Return the ending position of a variable name
static int _has_reflected_op ( PyObject *  op,
char *  name 
) [static]

References PyArray_malloc.

static int _is_alnum_underscore ( char  ch) [static]

Referenced by PyUFunc_GetPyValues().

static int _is_alpha_underscore ( char  ch) [static]
static int _is_same_name ( const char *  s1,
const char *  s2 
) [static]
Returns 1 if the dimension names pointed by s1 and s2 are the same, otherwise returns 0.
static void _loop1d_list_free ( void *  ptr) [static]
static PyObject* _makeargs ( int  num,
char *  ltr,
int  null_if_none 
) [static]
System Message: SEVERE/4 (<string>, line 1)
Title overline & underline mismatch.

                           UFUNC GETSET                                 ***
 
construct the string y1,y2,...,yn
static int _next_non_white_space ( const char *  str,
int  offset 
) [static]
Return the position of next non-white-space char in the string
static int _parse_signature ( PyUFuncObject self,
const char *  signature 
) [static]
Sets core_num_dim_ix, core_num_dims, core_dim_ixs, core_offsets, and core_signature in PyUFuncObject "self". Returns 0 unless an error occured.

<

number of dimension of the current argument

<

index into core_num_dims&core_offsets

<

index into core_dim_ixs
Allocate sufficient memory to store pointers to all dimension names

<

shrink this later
loop over input/output arguments
expect "->"
parse core dimensions of one argument, e.g. "()", "(i)", or "(i,j)"
loop over core dimensions
The list of input arguments (or output arguments) was only read partially
check for trivial core-signature, e.g. "(),()->()"

static char _typecharfromnum ( int  num) [static]
static int check_for_trivial_loop ( PyUFuncObject self,
PyArrayObject **  op,
PyArray_Descr **  dtype,
npy_intp  buffersize 
) [static]
This checks whether a trivial loop is ok, making copies of scalar and one dimensional operands if that will help.
Returns 1 if a trivial loop is ok, 0 if it is not, and -1 if there is an error.

If the dtype doesn't match, or the array isn't aligned, indicate that the trivial loop can't be done.
If op[j] is a scalar or small one dimensional array input, make a copy to keep the opportunity for a trivial loop.

static int cmp_arg_types ( int *  arg1,
int *  arg2,
int  n 
) [static]
return 1 if arg1 > arg2, 0 if arg1 == arg2, and -1 if arg1 < arg2
static int execute_ufunc_loop ( PyUFuncObject self,
int  trivial_loop_ok,
PyArrayObject **  op,
PyArray_Descr **  dtype,
NPY_ORDER  order,
npy_intp  buffersize,
PyObject **  arr_prep,
PyObject *  arr_prep_args,
PyUFuncGenericFunction  innerloop,
void *  innerloopdata 
) [static]
trivial_loop_ok - 1 if no alignment, data conversion, etc required nin - number of inputs nout - number of outputs op - the operands (nin + nout of them) order - the loop execution order/output memory order buffersize - how big of a buffer to use arr_prep - the __array_prepare__ functions for the outputs innerloop - the inner loop function innerloopdata - data to pass to the inner loop

First check for the trivial cases that don't need an iterator
Call the __prepare_array__ if necessary
Call the __prepare_array__ if necessary
Have to choose the input with more dimensions to clone, as one of them could be a scalar.
Call the __prepare_array__ if necessary
Call the __prepare_array__ if necessary
If no trivial loop matched, an iterator is required to resolve broadcasting, etc

static int execute_ufunc_masked_loop ( PyUFuncObject self,
PyArrayObject wheremask,
PyArrayObject **  op,
PyArray_Descr **  dtype,
NPY_ORDER  order,
npy_intp  buffersize,
PyObject **  arr_prep,
PyObject *  arr_prep_args,
PyUFuncGenericMaskedFunction  innerloop,
NpyAuxData innerloopdata 
) [static]
nin - number of inputs nout - number of outputs wheremask - if not NULL, the 'where=' parameter to the ufunc. op - the operands (nin + nout of them) order - the loop execution order/output memory order buffersize - how big of a buffer to use arr_prep - the __array_prepare__ functions for the outputs innerloop - the inner loop function innerloopdata - data to pass to the inner loop

Set up the flags
Allocate the iterator. Because the types of the inputs were already checked, we use the casting rule 'unsafe' which is faster to calculate.
Copy any allocated outputs
Call the __array_prepare__ functions where necessary
Only do the loop if the iteration size is non-zero
Reset the iterator with the base pointers from the wrapped outputs
Get the variables needed for the loop
Execute the loop

static int get_binary_op_function ( PyUFuncObject self,
int *  otype,
PyUFuncGenericFunction out_innerloop,
void **  out_innerloopdata 
) [static]
Given the output type, finds the specified binary op. The ufunc must have nin==2 and nout==1. The function may modify otype if the given type isn't found.
Returns 0 on success, -1 on failure.

If the type is custom and there are userloops, search for it here
Search for a function with compatible inputs
If the signature is "xx->x", we found the loop
Otherwise, we found the natural type of the reduction, replace otype and search again
Search for the exact function
Since the signature is "xx->x", we found the loop

static int get_ufunc_arguments ( PyUFuncObject self,
PyObject *  args,
PyObject *  kwds,
PyArrayObject **  out_op,
NPY_ORDER out_order,
NPY_CASTING out_casting,
PyObject **  out_extobj,
PyObject **  out_typetup,
int *  out_subok,
PyArrayObject **  out_wheremask 
) [static]
*** GENERIC UFUNC USING ITERATOR ****
Parses the positional and keyword arguments for a generic ufunc call.
Note that if an error is returned, the caller must free the non-zero references in out_op. This function does not do its own clean-up.

Check number of arguments
Get input arguments
TODO: There should be a comment here explaining what
context does.
Indicate not implemented if there are flexible objects (structured type or string) but no object types.
Not sure - adding this increased to 246 errors, 150 failures.
Get positional output arguments
Translate None to NULL
If it's an array, can use it
Get keyword output and other arguments. Raise an error if anything else is present in the keyword dictionary.
Provides a policy for allowed casting
Another way to specify 'sig'
Allow this parameter to be None
Overrides the global parameters buffer size, error mask, and error object
First output may be specified as a keyword parameter
Allows the default output layout to be overridden
Allows a specific function inner loop to be selected
Provides a boolean array 'where=' mask if out_wheremask is supplied.

static int iterator_loop ( PyUFuncObject self,
PyArrayObject **  op,
PyArray_Descr **  dtype,
NPY_ORDER  order,
npy_intp  buffersize,
PyObject **  arr_prep,
PyObject *  arr_prep_args,
PyUFuncGenericFunction  innerloop,
void *  innerloopdata 
) [static]

Set up the flags
Allocate the iterator. Because the types of the inputs were already checked, we use the casting rule 'unsafe' which is faster to calculate.
Copy any allocated outputs
Call the __array_prepare__ functions where necessary
Only do the loop if the iteration size is non-zero
Reset the iterator with the base pointers from the wrapped outputs
Get the variables needed for the loop
Execute the loop

static PyObject* make_arr_prep_args ( npy_intp  nin,
PyObject *  args,
PyObject *  kwds 
) [static]

Copy the tuple, but set the nin-th item to the keyword arg

static int prepare_ufunc_output ( PyUFuncObject self,
PyArrayObject **  op,
PyObject *  arr_prep,
PyObject *  arr_prep_args,
int  i 
) [static]
Calls the given __array_prepare__ function on the operand *op, substituting it in place if a new array is returned and matches the old one.

System Message: WARNING/2 (<string>, line 1); backlink Inline emphasis start-string without end-string.
This requires that the dimensions, strides and data type remain exactly the same, which may be more strict than before.

If the same object was returned, nothing to do
If the result doesn't match, throw an error
Replace the op value

static PyObject* PyUFunc_Accumulate ( PyUFuncObject self,
PyArrayObject arr,
PyArrayObject out,
int  axis,
int  otype 
) [static]

References PyArrayObject::descr.

NPY_NO_EXPORT int PyUFunc_checkfperr ( int  errmask,
PyObject *  errobj,
int *  first 
)

  1. check hardware flag --- this is platform dependent code

References NPY_MAXARGS, PyArray_CheckExact, and PyArray_IsAnyScalar.

NPY_NO_EXPORT void PyUFunc_clearfperr ( )
Checking the status flag clears it
NPY_NO_EXPORT PyObject* PyUFunc_FromFuncAndData ( PyUFuncGenericFunction func,
void **  data,
char *  types,
int  ntypes,
int  nin,
int  nout,
int  identity,
char *  name,
char *  doc,
int  check_return 
)
NPY_NO_EXPORT PyObject* PyUFunc_FromFuncAndDataAndSignature ( PyUFuncGenericFunction func,
void **  data,
char *  types,
int  ntypes,
int  nin,
int  nout,
int  identity,
char *  name,
char *  doc,
int  check_return,
const char *  signature 
)
static int PyUFunc_GeneralizedFunction ( PyUFuncObject self,
PyObject *  args,
PyObject *  kwds,
PyArrayObject **  op 
) [static]

Use remapped axes for generalized ufunc
These parameters come from extobj= or from a TLS global
The selected inner loop
The dimensions which get passed to the inner loop
The strides which get passed to the inner loop
The __array_prepare__ function to call for each output
This is either args, or args with the out= parameter from kwds added appropriately.
Currently trying out SAME_KIND casting rule by default.
When provided, extobj and typetup contain borrowed references
Initialize all the operands and dtypes to NULL
Get all the arguments
Figure out the number of dimensions needed by the iterator
Fill in op_axes for all the operands
Note that n may be negative if broadcasting extends into the core dimensions.
Broadcast all the unspecified dimensions normally
Use the signature information for the rest
Get the buffersize, errormask, and error object globals
FAIL with NotImplemented if the other object has the __r<op>__ method and has __array_priority__ as an attribute (signalling it can handle ndarray's) and is not already an ndarray or a subtype of the same type.
If both are same subtype of object arrays, then proceed
Get the appropriate __array_prepare__ function to call for each output
Set up arr_prep_args if a prep function was needed
If the loop wants the arrays, provide them
Set up the iterator per-op flags. For generalized ufuncs, we can't do buffering, so must COPY or UPDATEIFCOPY.
Create the iterator
Fill in any allocated outputs
Set up the inner strides array. Because we're not doing buffering, the strides are fixed throughout the looping.
The strides after the first nop match core_dim_ixs
Set up the inner dimensions array
Move the core dimensions to start at the second element
Remove all the core dimensions from the iterator
The first nop strides are for the inner loop (but only can copy them after removing the core axes
Start with the floating-point exception flags cleared
Do the ufunc loop
Get the variables needed for the loop
Check whether any errors occurred during the loop
The caller takes ownership of all the references in op

NPY_NO_EXPORT int PyUFunc_GenericFunction ( PyUFuncObject self,
PyObject *  args,
PyObject *  kwds,
PyArrayObject **  op 
)
This generic function is called with the ufunc object, the arguments to it,

and an array of (pointers to) PyArrayObjects which are NULL.

'op' is an array of at least NPY_MAXARGS PyArrayObject *.

System Message: WARNING/2 (<string>, line 4); backlink Inline emphasis start-string without end-string.

These parameters come from extobj= or from a TLS global
The selected inner loop
The selected masked inner loop, when the 'where=' parameter or arrays with missing values are in op.
The mask provided in the 'where=' parameter
The __array_prepare__ function to call for each output
This is either args, or args with the out= parameter from kwds added appropriately.
Currently trying out SAME_KIND casting rule by default.
When provided, extobj and typetup contain borrowed references
Initialize all the operands and dtypes to NULL
Get all the arguments
For now just the where mask triggers this, but later arrays with missing data will trigger it as well.
Get the buffersize, errormask, and error object globals
This checks whether a trivial loop is ok, making copies of scalar and one dimensional operands if that will help.
Only do the trivial loop check for the unmasked version.
FAIL with NotImplemented if the other object has the __r<op>__ method and has __array_priority__ as an attribute (signalling it can handle ndarray's) and is not already an ndarray or a subtype of the same type.
If both are same subtype of object arrays, then proceed
Get the appropriate __array_prepare__ function to call for each output
Set up arr_prep_args if a prep function was needed
If the loop wants the arrays, provide them.

TODO: Remove this, since this is already basically broken
with the addition of the masked inner loops and not worth fixing.
Start with the floating-point exception flags cleared
Do the ufunc loop
Check whether any errors occurred during the loop
The caller takes ownership of all the references in op

static PyObject* PyUFunc_GenericReduction ( PyUFuncObject self,
PyObject *  args,
PyObject *  kwds,
int  operation 
) [static]
This code handles reduce, reduceat, and accumulate (accumulate and reduce are special cases of the more general reduceat but they are handled separately for speed)

Ensure input is an array
Check to see if input is zero-dimensional
Check to see that type (and otype) is not FLEXIBLE
If out is specified it determines otype unless otype already specified.
For integer types --- make sure at least a long is used for add and multiply reduction to avoid overflow

NPY_NO_EXPORT int PyUFunc_getfperr ( void  )
NPY_NO_EXPORT int PyUFunc_GetPyValues ( char *  name,
int *  bufsize,
int *  errmask,
PyObject **  errobj 
)
On return, if errobj is populated with a non-NULL value, the caller
owns a new reference to errobj.

References _is_alnum_underscore().

NPY_NO_EXPORT int PyUFunc_handlefperr ( int  errmask,
PyObject *  errobj,
int  retstatus,
int *  first 
)
static PyObject* PyUFunc_Reduce ( PyUFuncObject self,
PyArrayObject arr,
PyArrayObject out,
int  axis,
int  otype 
) [static]
We have two basic kinds of loops. One is used when arr is not-swapped and aligned and output type is the same as input type. The other uses buffers when one of these is not satisfied. <blockquote> Zero-length and one-length axes-to-be-reduced are handled separately.</blockquote>

References PyArrayObject::nd.

static PyObject* PyUFunc_Reduceat ( PyUFuncObject self,
PyArrayObject arr,
PyArrayObject ind,
PyArrayObject out,
int  axis,
int  otype 
) [static]
Reduceat performs a reduce over an axis using the indices as a guide
op.reduceat(array,indices) computes op.reduce(array[indices[i]:indices[i+1]] for i=0..end with an implicit indices[i+1]=len(array) assumed when i=end-1
if indices[i+1] <= indices[i]+1 then the result is array[indices[i]] for that value
op.accumulate(array) is the same as op.reduceat(array,indices)[::2] where indices is range(len(array)-1) with a zero placed in every other sample indices = zeros(len(array)*2-1) indices[1::2] = range(1,len(array))
output shape is based on the size of indices

The reduceat indices - ind must be validated outside this call
The selected inner loop
These parameters come from extobj= or from a TLS global
Check for out-of-bounds values in indices array
Take a reference to out for later returning
Set up the output data type, using the input's exact data type if the type number didn't change to preserve metadata
Set up the op_axes for the outer loop
Use the i-th iteration dimension to match up ind
Likewise with accumulate, must do UPDATEIFCOPY
The way reduceat is set up, we can't do buffering, so make a copy instead when necessary.
The per-operand flags for the outer loop
Remove the inner loop axis from the outer iterator
In case COPY or UPDATEIFCOPY occurred
Allocate the output for when there's no outer iterator
If the output has zero elements, return now.
Get the variables needed for the loop
Execute the loop with just the outer iterator
Copy the first element to start the reduction
Inner loop like REDUCE
Execute the loop with no iterators
Copy the first element to start the reduction
Inner loop like REDUCE

References PyArray_LONG.

static PyObject* PyUFunc_ReductionOp ( PyUFuncObject self,
PyArrayObject arr,
PyArrayObject out,
int  axis,
int  otype,
int  operation,
char *  opname 
) [static]
The implementation of the reduction operators with the new iterator turned into a bit of a long function here, but I think the design of this part needs to be changed to be more like einsum, so it may not be worth refactoring it too much. Consider this timing:

>>> a = arange(10000)
>>> timeit sum(a)
10000 loops, best of 3: 17 us per loop
>>> timeit einsum("i->",a)
100000 loops, best of 3: 13.5 us per loop

The selected inner loop
These parameters come from extobj= or from a TLS global
Take a reference to out for later returning
Set up the output data type, using the input's exact data type if the type number didn't change to preserve metadata
Set up the op_axes for the outer loop
The per-operand flags for the outer loop
This is because we can't buffer, so must do UPDATEIFCOPY
The way accumulate is set up, we can't do buffering, so make a copy instead when necessary.
Add some more flags
In case COPY or UPDATEIFCOPY occurred
Get the output
If the reduction unit has size zero, either return the reduction unit for UFUNC_REDUCE, or return the zero-sized output array for UFUNC_ACCUMULATE.
Only allocate an inner iterator if it's necessary
Also set the dtype for buffering arr
The per-operand flags for the inner loop
Should never get an inner iterator for ACCUMULATE
Get the variables needed for the loop
Execute the loop with two nested iterators
Only UFUNC_REDUCE uses iter_inner
Reset the inner iterator to the outer's data
Copy the first element to start the reduction
Turn the two items into three for the inner loop
Execute the loop with just the outer iterator
Copy the first element to start the reduction
Turn the two items into three for the inner loop
Execute the loop with just the inner iterator
Only UFUNC_REDUCE uses iter_inner
Reset the inner iterator to prepare the buffers
Copy the first element to start the reduction
Turn the two items into three for the inner loop
Execute the loop with no iterators
Turn the two items into three for the inner loop
Copy the first element to start the reduction

NPY_NO_EXPORT int PyUFunc_RegisterLoopForType ( PyUFuncObject ufunc,
int  usertype,
PyUFuncGenericFunction  function,
int *  arg_types,
void *  data 
)

Get entry for this user-defined type
If it's not there, then make one and return.
There is already at least 1 loop. Place this one in lexicographic order. If the next one signature is exactly like this one, then just replace. Otherwise insert.
just replace it with new function
insert it before the current one by hacking the internals of cobject to replace the function pointer --- can't use CObject API because destructor is set.
place this at front

NPY_NO_EXPORT int PyUFunc_ReplaceLoopBySignature ( PyUFuncObject func,
PyUFuncGenericFunction  newfunc,
int *  signature,
PyUFuncGenericFunction oldfunc 
)

Find the location of the matching signature

References _typecharfromnum(), and PyUString_FromStringAndSize.

NPY_NO_EXPORT int PyUFunc_SetUsesArraysAsData ( void **  data,
size_t  i 
)
Specify that the loop specified by the given index should use the array of input and arrays as the data pointer to the loop.
static void trivial_three_operand_loop ( PyArrayObject **  op,
PyUFuncGenericFunction  innerloop,
void *  innerloopdata 
) [static]
static void trivial_two_operand_loop ( PyArrayObject **  op,
PyUFuncGenericFunction  innerloop,
void *  innerloopdata 
) [static]
static PyObject* ufunc_accumulate ( PyUFuncObject self,
PyObject *  args,
PyObject *  kwds 
) [static]
static void ufunc_dealloc ( PyUFuncObject self) [static]
static PyObject* ufunc_generic_call ( PyUFuncObject self,
PyObject *  args,
PyObject *  kwds 
) [static]

Initialize all array objects to NULL to make cleanup easier if something goes wrong.
To allow the other argument to be given a chance
Free the input references
Use __array_wrap__ on all outputs if present on one of the input arguments. If present for multiple inputs: use __array_wrap__ of input object with largest __array_priority__ (default = 0.0)
Exception: we should not wrap outputs for items already passed in as output-arguments. These items should either be left unwrapped or wrapped by calling their own __array_wrap__ routine.
For each output argument, wrap will be either NULL --- call PyArray_Return() -- default if no output arguments given None --- array-object passed in don't call PyArray_Return method --- the __array_wrap__ method to call.
wrap outputs
default behavior

References PyArrayObject::dimensions, longlong, PyArrayObject::nd, PyArray_FromObject, PyArray_NOTYPE, and PyArray_Reshape().

Referenced by PyUFunc_FromFuncAndDataAndSignature().

static PyObject* ufunc_get_doc ( PyUFuncObject self) [static]

Put docstring first or FindMethod finds it... could so some introspection on name and nin + nout to automate the first part of it the doc string shouldn't need the calling convention construct name(x1, x2, ...,[ out1, out2, ...]) __doc__

Referenced by PyUFunc_FromFuncAndDataAndSignature().

static PyObject* ufunc_get_identity ( PyUFuncObject self) [static]
static PyObject* ufunc_get_name ( PyUFuncObject self) [static]
static PyObject* ufunc_get_nargs ( PyUFuncObject self) [static]
static PyObject* ufunc_get_nin ( PyUFuncObject self) [static]
static PyObject* ufunc_get_nout ( PyUFuncObject self) [static]
static PyObject* ufunc_get_ntypes ( PyUFuncObject self) [static]
static PyObject* ufunc_get_signature ( PyUFuncObject self) [static]
static PyObject* ufunc_get_types ( PyUFuncObject self) [static]

return a list with types grouped input->output

Referenced by PyUFunc_FromFuncAndDataAndSignature().

NPY_NO_EXPORT PyObject* ufunc_geterr ( PyObject *  NPY_UNUSEDdummy,
PyObject *  args 
)

Construct list of defaults

static PyObject* ufunc_outer ( PyUFuncObject self,
PyObject *  args,
PyObject *  kwds 
) [static]
System Message: SEVERE/4 (<string>, line 1)
Title overline & underline mismatch.

                          UFUNC METHODS                                 ***
 
op.outer(a,b) is equivalent to op(a[:,NewAxis,NewAxis,etc.],b) where a has b.ndim NewAxis terms appended.
The result has dimensions a.ndim + b.ndim

Construct new shape tuple

static PyObject* ufunc_reduce ( PyUFuncObject self,
PyObject *  args,
PyObject *  kwds 
) [static]
static PyObject* ufunc_reduceat ( PyUFuncObject self,
PyObject *  args,
PyObject *  kwds 
) [static]
static PyObject* ufunc_repr ( PyUFuncObject self) [static]
NPY_NO_EXPORT PyObject* ufunc_seterr ( PyObject *  NPY_UNUSEDdummy,
PyObject *  args 
)
static int ufunc_update_use_defaults ( void  ) [static]
This is a strategy to buy a little speed up and avoid the dictionary look-up in the default case. It should work in the presence of threads. If it is deemed too complicated or it doesn't actually work it could be taken out.

Variable Documentation

int PyUFunc_NUM_NODEFAULTS = 0 [static]
PyObject* PyUFunc_PYVALS_NAME = NULL [static]
NPY_NO_EXPORT PyTypeObject PyUFunc_Type
System Message: SEVERE/4 (<string>, line 1)
Title overline & underline mismatch.

                        UFUNC TYPE OBJECT                               ***
 

Referenced by PyUFunc_FromFuncAndDataAndSignature(), and ufunc_frompyfunc().

PyGetSetDef ufunc_getset[] [static]
Initial value:
 {
    {"__doc__",
        (getter)ufunc_get_doc,
        NULL, NULL, NULL},
    {"nin",
        (getter)ufunc_get_nin,
        NULL, NULL, NULL},
    {"nout",
        (getter)ufunc_get_nout,
        NULL, NULL, NULL},
    {"nargs",
        (getter)ufunc_get_nargs,
        NULL, NULL, NULL},
    {"ntypes",
        (getter)ufunc_get_ntypes,
        NULL, NULL, NULL},
    {"types",
        (getter)ufunc_get_types,
        NULL, NULL, NULL},
    {"__name__",
        (getter)ufunc_get_name,
        NULL, NULL, NULL},
    {"identity",
        (getter)ufunc_get_identity,
        NULL, NULL, NULL},
    {"signature",
        (getter)ufunc_get_signature,
        NULL, NULL, NULL},
    {NULL, NULL, NULL, NULL, NULL},  
}
Docstring is now set from python static char *Ufunctype__doc__ = NULL;

System Message: WARNING/2 (<string>, line 1); backlink Inline emphasis start-string without end-string.
struct PyMethodDef ufunc_methods[] [static]
Initial value:
 {
    {"reduce",
        (PyCFunction)ufunc_reduce,
        METH_VARARGS | METH_KEYWORDS, NULL },
    {"accumulate",
        (PyCFunction)ufunc_accumulate,
        METH_VARARGS | METH_KEYWORDS, NULL },
    {"reduceat",
        (PyCFunction)ufunc_reduceat,
        METH_VARARGS | METH_KEYWORDS, NULL },
    {"outer",
        (PyCFunction)ufunc_outer,
        METH_VARARGS | METH_KEYWORDS, NULL},
    {NULL, NULL, 0, NULL}           
}