arr[key]
arr[key][flopscope source]
Index the array. Basic indexing is free; advanced indexing bills.
Adapted from NumPy docs np.getitem
Array indexing. Basic slicing: free (view). Fancy indexing: 4*numel(output); boolean masks add numel(mask).
Basic indexing -- every part of key is an int (Python or numpy
scalar), slice, flops.newaxis (None), Ellipsis, or a tuple
of those -- returns a view, matching NumPy's zero-copy semantics: 0 FLOPs.
Advanced indexing materializes a gathered copy and is billed under
"getitem": 4 FLOPs per gathered output element (matching take),
plus one scan FLOP per boolean-mask element (matching compress). A
part triggers advanced indexing when it is any of:
a
bool/ flops.bool_ scalar -- numpy routes a bare boolean scalar through the advanced-index copy path (prepending a length-1 / length-0 axis), a genuine copy though it is not anndarray;any other part that coerces to an integer- or boolean-dtype array -- an
ndarray(orFlopscopeArray) of any ndim including 0-d, alist,tuple,range,array.array,memoryview, or any future array-like sequence/buffer. This matches numpy's own rule (any array-like integer/bool index gathers a copy) rather than an enumerated type list, so it cannot silently miss a sequence kind: the part is classified byflops.asarray(part).dtype, and only itsdtype/size are read -- the originalkeyis what actually indexes, so a single-use generator part is never consumed.
This is about a part -- an already-decomposed element of parts --
not the top-level key: m[1:3, ::2] has key as a tuple, but
that tuple is the multi-axis split itself (parts = key), and its
parts are slices, so it stays basic. Likewise v[(0, 2, 4)] on a 1-D
v has key as the 3-tuple; splitting it into parts 0, 2, 4
yields three int parts -- basic, and numpy raises its own "too many
indices" error since none of them consumes as an array. A tuple only
gathers when it survives the top-level split as one part, e.g.
v[(0, 2, 4),] (a 1-tuple containing the 3-tuple) or
m[tuple_a, tuple_b] (each axis's index happens to be a tuple).
A numpy/Python integer scalar stays basic (a view) -- only integer
arrays (or a sequence/buffer coerced to one) gather. A part numpy
cannot turn into an integer/bool array -- an object array (kind O,
e.g. a generator), a string/bytes field selector (U/S), a
float/complex array, or a ragged sequence flops.asarray rejects --
falls through to super().__getitem__ unbilled, so numpy handles or
raises on it exactly as usual. mask_elems counts boolean elements
only: a bool scalar contributes 1, a bool array contributes its size;
integer operands add nothing beyond the gather.