numpy  2.0.0
src/umath/reduction.c File Reference
#include <Python.h>
#include "npy_config.h"
#include <numpy/arrayobject.h>
#include "npy_pycompat.h"
#include "lowlevel_strided_loops.h"
#include "reduction.h"

Defines

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

Functions

static PyArrayObjectallocate_reduce_result (PyArrayObject *arr, npy_bool *axis_flags, PyArray_Descr *dtype, int subok)
static PyArrayObjectconform_reduce_result (int ndim, npy_bool *axis_flags, PyArrayObject *out, int keepdims, const char *funcname)
NPY_NO_EXPORT PyArrayObjectPyArray_CreateReduceResult (PyArrayObject *operand, PyArrayObject *out, PyArray_Descr *dtype, npy_bool *axis_flags, int keepdims, int subok, const char *funcname)
static int check_nonreorderable_axes (int ndim, npy_bool *axis_flags, const char *funcname)
NPY_NO_EXPORT PyArrayObjectPyArray_InitializeReduceResult (PyArrayObject *result, PyArrayObject *operand, npy_bool *axis_flags, int reorderable, npy_intp *out_skip_first_count, const char *funcname)
NPY_NO_EXPORT PyArrayObjectPyUFunc_ReduceWrapper (PyArrayObject *operand, PyArrayObject *out, PyArrayObject *wheremask, PyArray_Descr *operand_dtype, PyArray_Descr *result_dtype, NPY_CASTING casting, npy_bool *axis_flags, int reorderable, int keepdims, int subok, PyArray_AssignReduceIdentityFunc *assign_identity, PyArray_ReduceLoopFunc *loop, void *data, npy_intp buffersize, const char *funcname)

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 PyArrayObject* allocate_reduce_result ( PyArrayObject arr,
npy_bool axis_flags,
PyArray_Descr dtype,
int  subok 
) [static]
Allocates a result array for a reduction operation, with dimensions matching 'arr' except set to 1 with 0 stride wherever axis_flags is True. Dropping the reduction axes from the result must be done later by the caller once the computation is complete.
This function always allocates a base class ndarray.
If 'dtype' isn't NULL, this function steals its reference.
Build the new strides and shape
Finally, allocate the array

References _PyArray_Descr::elsize, NPY_MAXDIMS, npy_stride_sort_item::perm, PyArray_CreateSortedStridePerm(), PyArray_DIMS, PyArray_DTYPE(), PyArray_NDIM, PyArray_NewFromDescr(), PyArray_STRIDES, and PyArray_Type.

static int check_nonreorderable_axes ( int  ndim,
npy_bool axis_flags,
const char *  funcname 
) [static]
Checks that there are only zero or one dimensions selected in 'axis_flags', and raises an error about a non-reorderable reduction if not.
static PyArrayObject* conform_reduce_result ( int  ndim,
npy_bool axis_flags,
PyArrayObject out,
int  keepdims,
const char *  funcname 
) [static]
Conforms an output parameter 'out' to have 'ndim' dimensions with dimensions of size one added in the appropriate places indicated by 'axis_flags'.
The return value is a view into 'out'.
If the 'keepdims' parameter is true, do a simpler validation and return a new reference to 'out'.
Construct the strides and shape
Allocate the view
NPY_NO_EXPORT PyArrayObject* PyArray_CreateReduceResult ( PyArrayObject operand,
PyArrayObject out,
PyArray_Descr dtype,
npy_bool axis_flags,
int  keepdims,
int  subok,
const char *  funcname 
)
Creates a result for reducing 'operand' along the axes specified in 'axis_flags'. If 'dtype' isn't NULL, this function steals a reference to 'dtype'.
If 'out' isn't NULL, this function creates a view conforming to the number of dimensions of 'operand', adding a singleton dimension for each reduction axis specified. In this case, 'dtype' is ignored (but its reference is still stolen), and the caller must handle any type conversion/validity check for 'out'
If 'subok' is true, creates a result with the subtype of 'operand', otherwise creates on with the base ndarray class.
If 'out' is NULL, it allocates a new array whose shape matches that of 'operand', except for at the reduction axes. If 'dtype' is NULL, the dtype of 'operand' is used for the result.
This function steals the reference to 'dtype'
Steal the dtype reference
NPY_NO_EXPORT PyArrayObject* PyArray_InitializeReduceResult ( PyArrayObject result,
PyArrayObject operand,
npy_bool axis_flags,
int  reorderable,
npy_intp out_skip_first_count,
const char *  funcname 
)
This function initializes a result array for a reduction operation which has no identity. This means it needs to copy the first element it sees along the reduction axes to result, then return a view of the operand which excludes that element.
If a reduction has an identity, such as 0 or 1, the result should be initialized by calling PyArray_AssignZero(result, NULL, NULL) or PyArray_AssignOne(result, NULL, NULL), because this function raises an exception when there are no elements to reduce (which appropriate iff the reduction operation has no identity).
This means it copies the subarray indexed at zero along each reduction axis into 'result', then returns a view into 'operand' excluding those copied elements.

result : The array into which the result is computed. This must have
the same number of dimensions as 'operand', but for each axis i where 'axis_flags[i]' is True, it has a single element.
System Message: WARNING/2 (<string>, line 19) Definition list ends without a blank line; unexpected unindent.
operand : The array being reduced. axis_flags : An array of boolean flags, one for each axis of 'operand'.

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

<blockquote> When a flag is True, it indicates to reduce along that axis.</blockquote>

System Message: WARNING/2 (<string>, line 22) Block quote ends without a blank line; unexpected unindent.
reorderable : If True, the reduction being done is reorderable, which
means specifying multiple axes of reduction at once is ok, and the reduction code may calculate the reduction in an arbitrary order. The calculation may be reordered because of cache behavior or multithreading requirements.
out_skip_first_count : This gets populated with the number of first-visit
elements that should be skipped during the iteration loop.
funcname : The name of the reduction operation, for the purpose of
better quality error messages. For example, "numpy.max" would be a good name for NumPy's max function.
Returns a view which contains the remaining elements on which to do the reduction.
Default to no skipping first-visit elements in the iteration
If this reduction is non-reorderable, make sure there are only 0 or 1 axes in axis_flags.
Take a view into 'operand' which we can modify.
Now copy the subarray of the first element along each reduction axis, then return a view to the rest.
Adjust the shape to only look at the first element along any of the reduction axes. We count the number of reduction axes at the same time.
Copy the elements into the result to start.
If there is one reduction axis, adjust the view's shape to only look at the remaining elements
If there are zero reduction axes, make the view empty
Otherwise iterate over the whole operand, but tell the inner loop to skip the elements we already copied by setting the skip_first_count.
NPY_NO_EXPORT PyArrayObject* PyUFunc_ReduceWrapper ( PyArrayObject operand,
PyArrayObject out,
PyArrayObject wheremask,
PyArray_Descr operand_dtype,
PyArray_Descr result_dtype,
NPY_CASTING  casting,
npy_bool axis_flags,
int  reorderable,
int  keepdims,
int  subok,
PyArray_AssignReduceIdentityFunc assign_identity,
PyArray_ReduceLoopFunc loop,
void *  data,
npy_intp  buffersize,
const char *  funcname 
)
This function executes all the standard NumPy reduction function boilerplate code, just calling assign_identity and the appropriate inner loop function where necessary.
operand : The array to be reduced. out : NULL, or the array into which to place the result. wheremask : NOT YET SUPPORTED, but this parameter is placed here

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

<blockquote> so that support can be added in the future without breaking API compatibility. Pass in NULL.</blockquote>

System Message: WARNING/2 (<string>, line 10) Block quote ends without a blank line; unexpected unindent.
operand_dtype : The dtype the inner loop expects for the operand. result_dtype : The dtype the inner loop expects for the result. casting : The casting rule to apply to the operands. axis_flags : Flags indicating the reduction axes of 'operand'. reorderable : If True, the reduction being done is reorderable, which

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

<blockquote> means specifying multiple axes of reduction at once is ok, and the reduction code may calculate the reduction in an arbitrary order. The calculation may be reordered because of cache behavior or multithreading requirements.</blockquote>

System Message: WARNING/2 (<string>, line 19) Block quote ends without a blank line; unexpected unindent.
keepdims : If true, leaves the reduction dimensions in the result
with size one.
subok : If true, the result uses the subclass of operand, otherwise
it is always a base class ndarray.
assign_identity : If NULL, PyArray_InitializeReduceResult is used, otherwise
this function is called to initialize the result to the reduction's unit.
System Message: WARNING/2 (<string>, line 26) Definition list ends without a blank line; unexpected unindent.
loop : The loop which does the reduction. data : Data which is passed to assign_identity and the inner loop. buffersize : Buffer size for the iterator. For the default, pass in 0. funcname : The name of the reduction function, for error messages.
TODO FIXME: if you squint, this is essentially an second independent implementation of generalized ufuncs with signature (i)->(), plus a few extra bells and whistles. (Indeed, as far as I can tell, it was originally split out to support a fancy version of count_nonzero... which is not actually a reduction function at all, it's just a (i)->() function!) So probably these two implementation should be merged into one. (In fact it would be quite nice to support axis= and keepdims etc. for arbitrary generalized ufuncs!)
Iterator parameters
Validate that the parameters for future expansion are NULL
This either conforms 'out' to the ndim of 'operand', or allocates a new array appropriate for this reduction.
Initialize the result to the reduction unit if possible, otherwise copy the initial values and get a view to the rest.
If this reduction is non-reorderable, make sure there are only 0 or 1 axes in axis_flags.
empty op_view signals no reduction; but 0-d arrays cannot be empty
Set up the iterator
Straightforward reduction
Strip out the extra 'one' dimensions in the result