ArrayForEach¶
Apply the loop body to each slice of an array or packet along some axis and stack the results along some axis.
This is similar to a foreach node for a list, but acts along an axis of an array or packet and produces an array or packet as a result. Importantly, the node supports auto-vectorization, where the loop body is transformed into array operations that act on all elements of the looped axes simultaneously. The result can also be compiled (if a carefully chosen subset of supported nodes is used in the loop body) to be run very efficiently on the GPU or multicore CPU. Whether the loop body will see the looped-over axis (as a singleton, i.e., one-element, axis) or not can be controlled via the pass_singleton_axis property. The loop body can also loop over multiple input arrays simultaneously, but note that the loop only makes a single pass along the respective arrays in lock-step, which therefore need to have the same length along their respective looped-over axis. If a packet has multiple chunks each with different axes, one may also specify a comma-separated list of axes to loop over to indicate the axis to loop over for each such chunk. Otherwise, any chunks that do not have the sole specified axis for the respective packet are implicitly dropped. By default, the result is stacked along the same axis as the input; if a singleton axis is passed through to the loop body, the body can control the output axis values, and otherwise the input axis values are passed through unchanged. Alternatively one may also stack along a different axis of a given type; as a convenience, one may pass in a dictionary (structure) of axis fields (each typically an array) used to initialize or override the fields of the concatenated axis (this also works when stacking along the same axis and/or when passing through a singleton axis). Additionally one may also pass in input arguments without looping over an axis by setting the respective axis to "none". The node can also be used with plain arrays, blocks, chunks, or packets in any combination. The loop body (the stretch of nodes that are repeatedly run) begins with a Placeholder node that receives the current slice of the input argument, or multiple such placeholders if one wishes to loop over multiple arguments simultaneously, and the final node of the loop body is then wired into the "body" input of the Array For Each node. The node will invoke the loop body for each slice being iterated over and stack the resulting processed slices. More Info... Version 1.0.0
Ports/Properties¶
body¶
Graph to apply (loop body).
- verbose name: Body
- default value: None
- port type: GraphPort
- value type: Graph
body__signature¶
Arguments passed to the loop body. The loop body will generally receive a slice of the array being iterated over (along the axis specified by the axis1..N parameters). The loop can iterate over multiple arrays (or packets) simultaneously, in which case the loop body will receive one slice from each wired-in array as separate arguments, which may be named slice1, slice2, and so forth (or any other names can be used here). Your loop body therefore needs to contain this many Placeholder nodes, with their respective slotnames matching the names listed here (e.g., slice1, slice2, etc.). Then, anything downstream of (i.e., depending on the value of) those Placeholders nodes will collectively constitute your loop body. The final output node of your loop body is then wired into the "body" input port of the loop node. In graphical UIs, the edge will be drawn in dotted style to indicate that the preceding graph itself is given to the loop node as the loop body (which will then execute it zero or more times), which is in contrast to a regular (solid) edge that indices normal data flow wherein first the preceding node runs, and then its output is passed to the subsequent node. The ArrayForEach node will then stack the results of the loop body into a single array or packet along the chosen stacking axis.
- verbose name: Body [Data Slice]
- default value: (slice1)
- port type: Port
- value type: object (can be None)
data1¶
Array 1 to iterate over.
- verbose name: Data1
- default value: None
- port type: DataPort
- value type: AnyNumeric (can be None)
- data direction: IN
data2¶
Array 2 to iterate over.
- verbose name: Data2
- default value: None
- port type: DataPort
- value type: AnyNumeric (can be None)
- data direction: IN
data3¶
Array 3 to iterate over.
- verbose name: Data3
- default value: None
- port type: DataPort
- value type: AnyNumeric (can be None)
- data direction: IN
data4¶
Array 4 to iterate over.
- verbose name: Data4
- default value: None
- port type: DataPort
- value type: AnyNumeric (can be None)
- data direction: IN
data5¶
Array 5 to iterate over.
- verbose name: Data5
- default value: None
- port type: DataPort
- value type: AnyNumeric (can be None)
- data direction: IN
result¶
Result array.
- verbose name: Result
- default value: None
- port type: DataPort
- value type: AnyNumeric (can be None)
- data direction: OUT
axis1¶
Axis over which to iterate for data1. None means do not iterate, i.e., pass the data as-is. You can also enter the axis label here if you have multiple axes of same type but with different labels, as in feature.mylabel. If you intend to loop over one axis for the first chunk but another axis in the next chunk, you can also specify a comma-separated list of axes here.
- verbose name: Loop Axis (Data1)
- default value: axis
- port type: ComboPort
- value type: str (can be None)
axis2¶
Axis over which to iterate for data2. See axis1 documentation for additional information.
- verbose name: Loop Axis (Data2)
- default value: none
- port type: ComboPort
- value type: str (can be None)
axis3¶
Axis over which to iterate for data3. See axis1 documentation for additional information.
- verbose name: Loop Axis (Data3)
- default value: none
- port type: ComboPort
- value type: str (can be None)
axis4¶
Axis over which to iterate for data4. See axis1 documentation for additional information.
- verbose name: Loop Axis (Data4)
- default value: none
- port type: ComboPort
- value type: str (can be None)
axis5¶
Axis over which to iterate for data5. See axis1 documentation for additional information.
- verbose name: Loop Axis (Data5)
- default value: none
- port type: ComboPort
- value type: str (can be None)
stack_axis¶
Axis along which the outputs will be stacked. For non-packet outputs, this can also be the numeric position where the axis shall appear in the output array. If this is set to (same), and only one kind of typed axis was used in axis1..N, then this will stack the outputs data along the same kind of axis, which will be prepended unless pass_singleton_axis was True, in which case the position of that axis will be preserved. This can also be a comma-separated list of axes, in which case the first chunk is stacked along the first axis, the second chunk along the second axis, and so forth.
- verbose name: Stack Along Axis
- default value: (same)
- port type: ComboPort
- value type: str (can be None)
pass_singleton_axis¶
Whether the loop body shall receive the looped-over axis as a one-element axis. Note that this is only supported for axes with all-numeric fields (e.g., time, lag, or frequency). The alternative is to drop the axis from the data seen by the loop body.
- verbose name: Pass Singleton Axis To Body
- default value: False
- port type: BoolPort
- value type: bool (can be None)
field_overrides¶
Optionally a dictionary of axis field overrides to use in the concatenated data. This is mainly useful when not passing a singleton axis, and stacking along an axis other than '(same)', in which case the resulting axis would be initialized to default/dummy values unless those fields were overridden via this argument.
- verbose name: Override Stack Axis Fields
- default value: {}
- port type: DictPort
- value type: dict (can be None)
split_random_seed¶
Whether the DrawRandomSeed node should yield different seeds in each loop iteration. WARNING: even if this is set to True, it is currently only respected when using the from_haiku_context option in DrawRandomSeed, and not otherwise. To still use split seeds in conjunction with an enclosing WithRandomSeed, you can use DrawRandomSeed before the loop and draw a full array of seeds, which you can then pass to the loop as an additional data argument.
- verbose name: Split Random Seed
- default value: False
- port type: BoolPort
- value type: bool (can be None)
backend¶
Optional compute backend to use. If the chosen backend is not installed, the system will fall back to the backend configured in the backend_fallback setting (numpy by default). Keep means to retain the current backend of the given input data. Numpy is the basic CPU backend, and forcing it will cause the loop body to be applied to each slice of the given array(s) in sequence along a desired axis, and the results will be stacked along the chosen output axis. Jax instead will invoke the loop body only once on the 0th array slice, and work out the result of applying the body across all slices in a batched fashion using vectorized math operations (the principle is to send a special sentinel array called a Tracer through the loop body, which behaves like a single array slice as far as the loop body is concerned, but which actually applies all operations that it "experiences" to the original full array in a batched or "broadcasted" fashion). This is much faster than the numpy backend since the overhead associated with the body is only incurred once. Other backends currently are analogous to the numpy strategy, but this may change in future NeuroPype versions.
- verbose name: Backend / Compilation
- default value: jax
- port type: EnumPort
- value type: str (can be None)
set_breakpoint¶
Set a breakpoint on this node. If this is enabled, your debugger (if one is attached) will trigger a breakpoint.
- verbose name: Set Breakpoint (Debug Only)
- default value: False
- port type: BoolPort
- value type: bool (can be None)
metadata¶
User-definable meta-data associated with the node. Usually reserved for technical purposes.
- verbose name: Metadata
- default value: {}
- port type: DictPort
- value type: dict (can be None)