Table of Contents

Class np.NDIterator

Namespace
NumSharp
Assembly
NumSharp.dll

NumPy's numpy.nditer — the public, managed face of NumSharp's NDIterRef.

// numpy: for x in np.nditer(a): total += x
foreach (var vals in np.nditer(a))
    total += (int)vals[0];

// numpy: it = np.nditer(a, flags=['multi_index'])
//        while not it.finished: print(it.multi_index, it[0]); it.iternext()
var it = np.nditer(a, flags: new[] {"multi_index"});
while (!it.finished) { Use(it.multi_index, it[0]); it.iternext(); }
public class np.NDIterator : IEnumerable<NDArray[]>, IEnumerable, IDisposable
Inheritance
np.NDIterator
Implements
Inherited Members

Remarks

Port of NumPy 2.4.2's numpy/_core/src/multiarray/nditer_pywrap.c — the Python WRAPPER around the C iterator, which is what this class is: argument conversion, flag-string parsing, the property surface and the iteration protocol. The iterator itself is NDIterRef (NumPy's NpyIter), which already implements the buffering, casting, coalescing, broadcasting and index tracking.

Lifetime. NDIterRef is a ref struct and cannot live in a class field, so this class owns the heap NDIterState directly (handed over by NDIterRef.Detach) and re-borrows a non-owning NDIterRef for the duration of each call. It therefore MUST be disposed — close(), Dispose() or a using — which frees the unmanaged state and resolves any copy_if_overlap / updateifcopy write-backs, exactly like NumPy's with np.nditer(...) as it:. A finalizer is the safety net.

The yielded arrays alias the iterator. this[int] and value return views onto the iterator's LIVE data pointer (0-d normally, 1-d under external_loop), so they change under you on the next step and are invalid after disposal — the same contract as NumPy, where the loop variable must be copied to be kept. Writing through them writes to the operand (or its buffer), which is how readwrite iteration mutates an array.

Iteration yields NDArray[], always. NumPy yields a bare 0-d array for one operand and a tuple for several; C# has no such union, so enumeration always produces the operand array — vals[0] for the single-operand case. This is the same choice np.Broadcast made (object[] always).

Properties

Current

The values published by the most recent MoveNext(). Borrowed: the per-step views are handed to the consumer, who owns them (NumPy's [x.copy() for x in it] idiom is the one that keeps them).

public NDArray[] Current { get; }

Property Value

NDArray[]

this[int]

A LIVE view of operand i at the current position (NumPy's it[i]) — 0-d normally, 1-d spanning the inner loop under external_loop. Writing through it writes to the operand or its buffer; the view is invalidated by the next step and by disposal.

public NDArray this[int i] { get; }

Parameters

i int

Property Value

NDArray

dtypes

The per-operand iteration dtypes (NumPy's dtypes).

public NPTypeCode[] dtypes { get; }

Property Value

NPTypeCode[]

finished

True once iteration has run past the end (NumPy's finished).

public bool finished { get; }

Property Value

bool

has_delayed_bufalloc

Whether buffer allocation is still delayed pending a reset() (NumPy's has_delayed_bufalloc).

public bool has_delayed_bufalloc { get; }

Property Value

bool

has_index

Whether a C- or F-order flat index is being tracked (NumPy's has_index).

public bool has_index { get; }

Property Value

bool

has_multi_index

Whether a multi-index is being tracked (NumPy's has_multi_index).

public bool has_multi_index { get; }

Property Value

bool

index

The tracked flat index (NumPy's index). Requires the c_index or f_index flag.

public long index { get; }

Property Value

long

iterationneedsapi

Whether iteration needs the Python C-API (NumPy's iterationneedsapi). Always FALSE in NumSharp — there is no Python runtime, and the transfer flags never carry REQUIRES_PYAPI.

public bool iterationneedsapi { get; }

Property Value

bool

iterindex

The current flat iteration position (NumPy's iterindex).

public long iterindex { get; set; }

Property Value

long

iterrange

The [start, end) sub-range being iterated (NumPy's iterrange). Setting it requires the ranged flag.

public (long Start, long End) iterrange { get; set; }

Property Value

(long Start, long End)

itersize

Total number of elements the iterator will visit (NumPy's itersize).

public long itersize { get; }

Property Value

long

itviews

Per-operand views with the iterator's internal axis ordering (NumPy's itviews). Not available while buffering.

public NDArray[] itviews { get; }

Property Value

NDArray[]

multi_index

The tracked multi-index (NumPy's multi_index). Requires the multi_index flag.

public long[] multi_index { get; }

Property Value

long[]

ndim

The number of dimensions iterated (NumPy's ndim).

public int ndim { get; }

Property Value

int

nop

The number of operands (NumPy's nop).

public int nop { get; }

Property Value

int

operands

The operands, including any the iterator ALLOCATED (NumPy's operands).

public NDArray[] operands { get; }

Property Value

NDArray[]

shape

The shape being iterated (NumPy's shape). Without multi_index the iterator is free to coalesce and reorder axes, so this is the COALESCED shape (probed: a C-contiguous (2,3) reports (6,)); with multi_index the original axis order is preserved and it reports (2, 3).

public long[] shape { get; }

Property Value

long[]

value

The current values — one live view per operand (NumPy's value). NumPy returns a bare array for a single operand and a tuple otherwise; this always returns the array, so use value[0] for the single-operand case.

public NDArray[] value { get; }

Property Value

NDArray[]

Methods

Dispose()

Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.

public void Dispose()

~NDIterator()

protected ~NDIterator()

GetEnumerator()

Enumerates the iterator's single live cursor, so — as in NumPy, where iter(it) is it — a second enumeration RESUMES where the first stopped rather than restarting (call reset() to go again).

public IEnumerator<NDArray[]> GetEnumerator()

Returns

IEnumerator<NDArray[]>

Remarks

Deliberately a thin wrapper rather than this, even though returning this would model iter(it) is it more literally: foreach disposes the enumerator it obtains, and this class's Dispose() frees the unmanaged iterator state. Handing out this would therefore CLOSE the iterator at the end of any foreach/LINQ pass, making every property read afterwards throw. The wrapper's Dispose is a no-op and the cursor is still shared, so the observable semantics are unchanged. (np.Broadcast can safely return this only because it owns no unmanaged resources.)

MoveNext()

Publishes the values at the current position and THEN advances — the exact shape of NumPy's next (return self.value followed by iternext()), which is why after consuming one element the cursor already reads 1 and a copy() taken there continues from the SECOND element.

public bool MoveNext()

Returns

bool

Remarks

Publishing before advancing is safe because value captures the operand's ABSOLUTE data pointer, so the handed-out view keeps pointing at the element it was made for. The exception is buffered external_loop iteration, where the view aliases a buffer the next step refills — NumPy has the identical hazard, hence its documented [x.copy() for x in it] idiom.

close()

Resolve write-backs and release the iterator (NumPy's close(), i.e. the end of a with np.nditer(...) as it: block). Idempotent; the iterator is unusable afterwards.

public void close()

copy()

Duplicate the iterator at its current position (NumPy's copy()). The copy owns its own state and must be disposed independently.

public np.NDIterator copy()

Returns

np.NDIterator

debug_print()

Dump the iterator's internal state (NumPy's debug_print()).

public void debug_print()

enable_external_loop()

Switch to external-loop iteration after construction (NumPy's enable_external_loop()).

public void enable_external_loop()

iternext()

Advance to the next element/chunk (NumPy's iternext()). Returns false at the end.

public bool iternext()

Returns

bool

remove_axis(int)

Remove an axis from iteration (NumPy's remove_axis(i)). Requires the multi_index flag.

public void remove_axis(int axis)

Parameters

axis int

remove_multi_index()

Stop tracking the multi-index, letting the iterator coalesce and reorder axes (NumPy's remove_multi_index()). Resets the position to the start.

public void remove_multi_index()

reset()

Rewind to the start (NumPy's reset()); also allocates delayed buffers.

public void reset()