Skip to content

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)