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
iint
Property Value
dtypes
The per-operand iteration dtypes (NumPy's dtypes).
public NPTypeCode[] dtypes { get; }
Property Value
finished
True once iteration has run past the end (NumPy's finished).
public bool finished { get; }
Property Value
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
has_index
Whether a C- or F-order flat index is being tracked (NumPy's has_index).
public bool has_index { get; }
Property Value
has_multi_index
Whether a multi-index is being tracked (NumPy's has_multi_index).
public bool has_multi_index { get; }
Property Value
index
The tracked flat index (NumPy's index). Requires the c_index or
f_index flag.
public long index { get; }
Property Value
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
iterindex
The current flat iteration position (NumPy's iterindex).
public long iterindex { get; set; }
Property Value
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
itersize
Total number of elements the iterator will visit (NumPy's itersize).
public long itersize { get; }
Property Value
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
nop
The number of operands (NumPy's nop).
public int nop { get; }
Property Value
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
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
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
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
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
axisint
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()