Parallel#

class braintools.cogtask.Parallel(*phases, name='Parallel')[source]#

Parallel composition - phases execute simultaneously.

Useful for multi-modality tasks where different input channels have different encoding patterns during the same time period.

Created via: phase1 | phase2

Semantics#

  • The parent’s duration is the maximum of its children’s durations.

  • Each child runs through its own on_enter / on_exit lifecycle bound to its own duration (not the parent’s max), so noise and time-varying labels respect the child’s declared length.

  • Inputs from all children are written into the parent slice.

  • Outputs come from the first child by convention. To combine outputs from multiple children, declare disjoint output features per child and compose explicitly.

Examples

>>> # Two stimuli presented simultaneously
>>> parallel = StimulusA(500*u.ms) | StimulusB(500*u.ms)
children()[source]#

Return the immediate child phases of a compound phase.

Leaf phases return []. Subclasses like Sequence, Repeat, Parallel, If, Switch, While override this so that the Task can traverse the whole tree to bind features.

Return type:

List[Phase]

encode_inputs(ctx)[source]#

Fill ctx.inputs[phase_start:phase_end] with input encoding.

Called once per phase after duration is determined. Must modify ctx.inputs in-place.

Parameters:

ctx (Context) – Context with input buffer and trial state.

Return type:

None

encode_outputs(ctx)[source]#

Fill ctx.outputs[phase_start:phase_end] with target encoding.

Called once per phase after duration is determined. Must modify ctx.outputs in-place.

Parameters:

ctx (Context) – Context with output buffer and trial state.

Return type:

None

execute(ctx)[source]#

Encode each child within its own [phase_start, phase_start+dur).

Return type:

None

execute_packed(ctx)[source]#

Packed-mode parallel execution.

Every child starts at the same parent_cursor slot; the parent cursor advances by the maximum of the children’s actual step counts. Child input/output writes compose via the leaf merge logic in _execute_leaf_packed (later children inherit earlier slot contents outside their active range). Only the first child’s output writes are propagated (matching the static semantic).

Return type:

None

get_duration(ctx)[source]#

Duration is max of children.

Return type:

int

max_steps(ctx)[source]#

Static upper bound on this phase’s length in timesteps.

Must return a Python int with no dependence on traced values. Used by Task in variable-length mode to size shape-stable buffers. The default delegates to get_duration which is correct for fixed-duration phases. Variable-duration phases (e.g. those wrapping TruncExp/UniformDuration) override this to return the truncation upper bound divided by ctx.dt.

Parameters:

ctx (Context) – A stub or trial context providing ctx.dt. The default implementation does not read ctx.rng or trial state.

Returns:

Upper bound on number of timesteps for this phase.

Return type:

int

step_count(ctx)[source]#

Traced actual length of this phase in timesteps.

Returns a jax.Array int32 scalar. May depend on ctx[...] values populated by trial_init. Must satisfy 0 <= step_count(ctx) <= max_steps(ctx) for every trial.

The default returns a static value equal to get_duration; that is correct for any phase whose actual length matches its upper bound. Variable-duration phases override this to compute the traced length from ctx state without any int(...) cast.

Return type:

Array