numpy 2.0.0
src/multiarray/mapping.c File Reference
#include <Python.h>
#include "structmember.h"
#include "numpy/arrayobject.h"
#include "npy_config.h"
#include "numpy/npy_3kcompat.h"
#include "common.h"
#include "iterators.h"
#include "mapping.h"

Defines

#define PY_SSIZE_T_CLEAN
#define _MULTIARRAYMODULE
#define NPY_NO_PREFIX
#define SOBJ_NOTFANCY   0
#define SOBJ_ISFANCY   1
#define SOBJ_BADARRAY   2
#define SOBJ_TOOMANY   3
#define SOBJ_LISTTUP   4

Functions

static PyObject * array_subscript_simple (PyArrayObject *self, PyObject *op)
NPY_NO_EXPORT Py_ssize_t array_length (PyArrayObject *self)
NPY_NO_EXPORT PyObject * array_big_item (PyArrayObject *self, intp i)
NPY_NO_EXPORT int _array_ass_item (PyArrayObject *self, Py_ssize_t i, PyObject *v)
NPY_NO_EXPORT PyObject * array_item_nice (PyArrayObject *self, Py_ssize_t i)
NPY_NO_EXPORT int array_ass_big_item (PyArrayObject *self, intp i, PyObject *v)
static void _swap_axes (PyArrayMapIterObject *mit, PyArrayObject **ret, int getmap)
static PyObject * PyArray_GetMap (PyArrayMapIterObject *mit)
static int PyArray_SetMap (PyArrayMapIterObject *mit, PyObject *op)
NPY_NO_EXPORT int count_new_axes_0d (PyObject *tuple)
NPY_NO_EXPORT PyObject * add_new_axes_0d (PyArrayObject *arr, int newaxis_count)
static int fancy_indexing_check (PyObject *args)
NPY_NO_EXPORT PyObject * array_subscript (PyArrayObject *self, PyObject *op)
static int array_ass_sub_simple (PyArrayObject *self, PyObject *index, PyObject *op)
static int _tuple_of_integers (PyObject *seq, intp *vals, int maxvals)
static int array_ass_sub (PyArrayObject *self, PyObject *index, PyObject *op)
static PyObject * array_subscript_nice (PyArrayObject *self, PyObject *op)
static int _nonzero_indices (PyObject *myBool, PyArrayIterObject **iters)
static int _convert_obj (PyObject *obj, PyArrayIterObject **iter)
NPY_NO_EXPORT void PyArray_MapIterReset (PyArrayMapIterObject *mit)
NPY_NO_EXPORT void PyArray_MapIterNext (PyArrayMapIterObject *mit)
NPY_NO_EXPORT void PyArray_MapIterBind (PyArrayMapIterObject *mit, PyArrayObject *arr)
NPY_NO_EXPORT PyObject * PyArray_MapIterNew (PyObject *indexobj, int oned, int fancy)
static void arraymapiter_dealloc (PyArrayMapIterObject *mit)

Variables

NPY_NO_EXPORT PyMappingMethods array_as_mapping
NPY_NO_EXPORT PyTypeObject PyArrayMapIter_Type

Define Documentation

#define _MULTIARRAYMODULE
#include <stdio.h>
#define NPY_NO_PREFIX
#define PY_SSIZE_T_CLEAN
#define SOBJ_BADARRAY   2

Referenced by count_new_axes_0d().

#define SOBJ_ISFANCY   1

Referenced by count_new_axes_0d().

#define SOBJ_LISTTUP   4
#define SOBJ_NOTFANCY   0

Referenced by fancy_indexing_check().

#define SOBJ_TOOMANY   3

Referenced by count_new_axes_0d().


Function Documentation

NPY_NO_EXPORT int _array_ass_item ( PyArrayObject self,
Py_ssize_t  i,
PyObject *  v 
)
static int _convert_obj ( PyObject *  obj,
PyArrayIterObject **  iter 
) [static]
convert an indexing object to an INTP indexing array iterator
if possible -- otherwise, it is a Slice or Ellipsis object and has to be interpreted on bind to a particular array so leave it NULL for now.

References PyArrayMapIterObject::iteraxes.

static int _nonzero_indices ( PyObject *  myBool,
PyArrayIterObject **  iters 
) [static]
************ End of Mapping Protocol *************************
***************** Subscript Array Iterator *********************

<blockquote class="first">

</blockquote>

System Message: WARNING/2 (<string>, line 3) Block quote ends without a blank line; unexpected unindent.
This object handles subscript behavior for array objects. *

It is an iterator object with a next method * It abstracts the n-dimensional mapping behavior to make the looping *

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

<blockquote class="last"> code more understandable (maybe) * and so that indexing can be set up ahead of time *</blockquote>

This function takes a Boolean array and constructs index objects and iterators as if nonzero(Bool) had been called

pre-determine how many nonzero entries there are
create count-sized index arrays for each dimension
Loop through the Boolean array and copy coordinates for non-zero entries
Borrowed from ITER_NEXT macro

static void _swap_axes ( PyArrayMapIterObject mit,
PyArrayObject **  ret,
int  getmap 
) [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.

arr might not have the right number of dimensions and need to be reshaped first by pre-pending ones
Setting and getting need to have different permutations. On the get we are permuting the returned object, but on setting we are permuting the object-to-be-set. The set permutation is the inverse of the get permutation.
For getting the array the tuple for transpose is (n1,...,n1+n2-1,0,...,n1-1,n1+n2,...,n3-1) n1 is the number of dimensions of the broadcast index array n2 is the number of dimensions skipped at the start n3 is the number of dimensions of the result
For setting the array the tuple for transpose is (n2,...,n1+n2-1,0,...,n2-1,n1+n2,...n3-1)
use n1 as the boundary if getting but n2 if setting

static int _tuple_of_integers ( PyObject *  seq,
intp vals,
int  maxvals 
) [static]
return -1 if tuple-object seq is not a tuple of integers.
otherwise fill vals with converted integers
NPY_NO_EXPORT PyObject* add_new_axes_0d ( PyArrayObject arr,
int  newaxis_count 
)

Referenced by array_subscript().

NPY_NO_EXPORT int array_ass_big_item ( PyArrayObject self,
intp  i,
PyObject *  v 
)
static int array_ass_sub ( PyArrayObject self,
PyObject *  index,
PyObject *  op 
) [static]

Doing "a[...] += 1" triggers assigning an array to itself, so this check is needed.
Several different exceptions to the 0-d no-indexing rule <blockquote>

  1. ellipses (handled above generally)
  2. empty tuple
  3. Using newaxis (None)
  4. Boolean mask indexing

</blockquote>

<

don't do anything
Integer-tuple

static int array_ass_sub_simple ( PyArrayObject self,
PyObject *  index,
PyObject *  op 
) [static]
Another assignment hacked by using CopyObject. This only works if subscript returns a standard view. Again there are two cases. In the first case, PyArray_CopyObject can be used. In the second case, a new indexing function has to be used.

Rest of standard (view-based) indexing
Note: this code path should never be reached with an index that
produces scalars -- those are handled earlier in array_ass_sub

NPY_NO_EXPORT PyObject* array_big_item ( PyArrayObject self,
intp  i 
)
NPY_NO_EXPORT PyObject* array_item_nice ( PyArrayObject self,
Py_ssize_t  i 
)
contains optimization for 1-d arrays

References PyArray_ISWRITEABLE.

NPY_NO_EXPORT Py_ssize_t array_length ( PyArrayObject self)
System Message: SEVERE/4 (<string>, line 1)
Title overline & underline mismatch.

                    IMPLEMENT MAPPING PROTOCOL                          ***
 

References index2ptr().

NPY_NO_EXPORT PyObject* array_subscript ( PyArrayObject self,
PyObject *  op 
)

Check for multiple field access
extract multiple fields if all elements in sequence are either string or unicode (i.e. no break occurred).
Allow Boolean mask selection also
wrap arguments into a mapiter object

References add_new_axes_0d(), count_new_axes_0d(), NPY_DEFAULT, Py_TYPE, PyArray_Check, PyArray_DIMS, PyArray_ISBOOL, and PyArray_NewFromDescr().

Referenced by _strings_richcompare().

static PyObject* array_subscript_nice ( PyArrayObject self,
PyObject *  op 
) [static]
There are places that require that array_subscript return a PyArrayObject and not possibly a scalar. Thus, this is the function exposed to Python so that 0-dim arrays are passed as scalars

optimization for a tuple of integers
mp could be a scalar if op is not an Int, Scalar, Long or other Index object and still convertable to an integer (so that the code goes to array_subscript_simple). So, this cast is a bit dangerous..
The following is just a copy of PyArray_Return with an additional logic in the nd == 0 case.

References Bool, CARRAY, PyArrayObject::data, PyArrayObject::dimensions, MAX_DIMS, PyArrayObject::nd, PyArray_BOOL, PyArray_DescrFromType(), PyArray_FromAny(), PyArray_INTP, PyArray_IterNew(), PyArray_New(), PyArray_SIZE, and PyArray_Type.

NPY_NO_EXPORT PyObject * array_subscript_simple ( PyArrayObject self,
PyObject *  op 
) [static]
Called when treating array object like a mapping -- called first from Python when using a[object] unless object is a standard slice object (not an extended one).
There are two situations: <blockquote>
1 - the subscript is a standard view and a reference to the array can be returned
2 - the subscript uses Boolean masks or integer indexing and therefore a new array is created and returned. </blockquote>

Standard (view-based) Indexing
This will only work if new array will be a view

static void arraymapiter_dealloc ( PyArrayMapIterObject mit) [static]

Referenced by PyArray_MapIterNew().

NPY_NO_EXPORT int count_new_axes_0d ( PyObject *  tuple)
static int fancy_indexing_check ( PyObject *  args) [static]
This checks the args for any fancy indexing objects

Sequences < MAX_DIMS with any slice objects or newaxis, or Ellipsis is considered standard as long as there are also no Arrays and or additional sequences embedded.

References SOBJ_NOTFANCY.

static PyObject* PyArray_GetMap ( PyArrayMapIterObject mit) [static]

Unbound map iterator --- Bind should have been called
This relies on the map iterator object telling us the shape
of the new array in nd and dimensions.
Now just iterate through the new array filling it in with the next object from the original array as defined by the mapping iterator
check for consecutive axes

<

then we need to swap

NPY_NO_EXPORT void PyArray_MapIterBind ( PyArrayMapIterObject mit,
PyArrayObject arr 
)
Bind a mapiteration to a particular array <blockquote>
Determine if subspace iteration is necessary. If so, 1) Fill in mit->iteraxes 2) Create subspace iterator 3) Update nd, dimensions, and size.
Subspace iteration is necessary if: arr->nd > mit->numiter </blockquote>
Need to check for index-errors somewhere.
Let's do it at bind time and also convert all <0 values to >0 here as well.

no subspace iteration needed. Finish up and Return
all indexing arrays have been converted to 0 therefore we can extract the subspace with a simple getitem call which will use view semantics
But, be sure to do it with a true array.
Expand dimensions of result
Now, we still need to interpret the ellipsis and slice objects to determine which axes the indexing arrays are referring to
The number of dimensions an ellipsis takes up
Now fill in iteraxes -- remember indexing arrays have been converted to 0's in mit->indexobj
Only expand the first ellipsis
We need to fill in the starting coordinates for the subspace
Should be slice object or another Ellipsis
Here check the indexes (now that we have iteraxes)

NPY_NO_EXPORT PyObject* PyArray_MapIterNew ( PyObject *  indexobj,
int  oned,
int  fancy 
)

Must have some kind of fancy indexing if we are here indexobj is either a list, an arrayobject, or a tuple (with at least 1 list or arrayobject or Bool object)
convert all inputs to iterators
must be a tuple
Make a copy of the tuple -- we will be replacing index objects with 0's
we need to grow the new indexing object and fill it with 0s for each of the iterators produced
Store the number of iterators actually converted These will be mapped to actual axes at bind time

References arraymapiter_dealloc().

NPY_NO_EXPORT void PyArray_MapIterNext ( PyArrayMapIterObject mit)
This function needs to update the state of the map iterator and point mit->dataptr to the memory-location of the next object

Sub-space iteration
reset coord to coordinates of beginning of the subspace

References Py_TYPE.

NPY_NO_EXPORT void PyArray_MapIterReset ( PyArrayMapIterObject mit)
Reset the map iterator to the beginning
static int PyArray_SetMap ( PyArrayMapIterObject mit,
PyObject *  op 
) [static]

Unbound Map Iterator

<

then we need to swap
Be sure values array is "broadcastable"
to shape of mit->dimensions, mit->nd
Need to decref arrays with objects in them
ignored unless VOID array with object's


Variable Documentation

NPY_NO_EXPORT PyMappingMethods array_as_mapping
Initial value:
 {






    (inquiry)array_length,              

    (binaryfunc)array_subscript_nice,       
    (objobjargproc)array_ass_sub,       
}
NPY_NO_EXPORT PyTypeObject PyArrayMapIter_Type
The mapiter object must be created new each time. It does not work to bind to a new array, and continue.
This was the orginal intention, but currently that does not work. Do not expose the MapIter_Type to Python.
It's not very useful anyway, since mapiter(indexobj); mapiter.bind(a); mapiter is equivalent to a[indexobj].flat but the latter gets to use slice syntax.