canvas_engineering.scheduling¶
Region scheduling: clock-driven firing decisions.
canvas_engineering.scheduling.RegionScheduler
¶
Evaluates clock rules to decide which regions fire each step.
Each region's ClockSpec determines when it fires: - periodic: fires when external_t % period == 0 - on_event: fires when a residual summary exceeds a threshold - boundary: fires on a named lifecycle event
Regions without a ClockSpec always fire (backward compatible).
Cooldown suppresses re-firing for N steps after a fire. max_silence forces firing after N steps of silence regardless.
Internal microsteps
Regions with clock.domain == "internal" and clock.max_inner_steps
produce additional inner steps beyond the main external step.
Use step_plan() to get a list of active-region sets:
the first set is the normal external step, subsequent sets are
internal microsteps for regions with internal clocks.
reset()
¶
Reset scheduler state (e.g., between episodes).
step(external_t, summaries=None, boundary=None)
¶
Determine which regions should fire this step.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
external_t
|
int
|
Current external timestep. |
required |
summaries
|
Optional[Dict[str, Dict[str, float]]]
|
Residual summaries from ResidualAccumulator.summaries(). Format: {region_name: {kind_name: float_value}}. |
None
|
boundary
|
Optional[str]
|
Optional named boundary event (e.g., "episode_end"). |
None
|
Returns:
| Type | Description |
|---|---|
Set[str]
|
Set of region names that should update this step. |
step_plan(external_t, summaries=None, boundary=None)
¶
Returns a list of active-region sets, one per inner step.
The first set is the external step (always present, same as step()).
Subsequent sets are internal microsteps for regions with
clock.domain == "internal" and clock.max_inner_steps.
Usage
plan = scheduler.step_plan(t, summaries) for active in plan: canvas = dispatcher(canvas, active_regions=active)