Reaction Scheduling and Ownership
Scheduling is part of the reaction model.
Each Reaction turns model state into an absolute, observable occurrence time.
The simulation engine subscribes to that occurrence and keeps its scheduler aligned with it.
Ownership
Scheduling responsibilities have explicit owners:
- A
TimeDistributiongenerates non-negative delay samples for aTimeDistributedReaction. - A reaction owns its absolute, observable
nextOccurrenceand decides when to draw, preserve, transform, or replace a putative occurrence. - An
AbsoluteEventowns one fixed absolute occurrence. - A
ConditionalEventdraws a new putative occurrence when its conditions become valid and unregisters itself after its first successful execution. - A
ReactionHostowns reaction membership and publishes it as an observable list of reactions. BothNodeandEnvironmentare reaction hosts. Ownership is explicit in both directions: every reaction exposes its fixedhost, and a host only registers reactions whose host is the host itself. - Every
ConditionandActionexposes thereactionowning it, and a reaction only accepts conditions and actions it owns. Their host, and possibly their node, are reached through the owning reaction. Conditions and actions that work on a node take it as an explicit target, while local ones work on the node hosting theirNodeReaction. Conditionexposes reactive validity through the general model contract. A recurring reaction owns a subscription to their combined validity. Specialized reaction families validate the concrete condition types they accept and own exact subscriptions to any additional semantic inputs used by their scheduling law.- Disposing a reaction releases its derived observables and exact subscription handles. Model observables remain owned by the model entities that expose them.
- During a reaction execution or scheduled command, the engine collects directly invalidated reactions and refreshes each affected reaction once when that model mutation completes.
- The engine owns one exact subscription to every scheduled reaction’s
nextOccurrence. - The scheduler indexes reactions by their current occurrence time.
The model and execution paths are therefore distinct:
scheduling: model observable -> dirty reaction -> mutation completion -> reaction policy -> nextOccurrence emission -> engine -> scheduler reindexing
firing: scheduler selection -> engine time advance -> reaction procedure -> model mutation and/or removalReaction scheduling transitions
Initialization
Once the environment is ready, the engine asks each reaction to complete initialization.
The reaction activates its reactive inputs, computes any specialized state, and establishes its first
nextOccurrence before the engine inserts it into the scheduler.
A reaction is scheduled at an infinite future time while its conditions are invalid;
sampling begins on the transition to valid.
An AbsoluteEvent starts at its fixed occurrence and uses its conditions
as occurrence-time guards.
A reaction cloned onto another node is a newly instantiated program.
Its conditions and actions are cloned onto the new reaction:
a node target that was the host of the original reaction becomes the host of the new one, other targets are kept.
Firing
The scheduler selects the reaction with the earliest occurrence and the engine advances simulation time to it.
The engine calls the selected reaction’s execute;
the reaction owns condition, actions, recurrence, and single-use removal.
A scheduling-gated reaction exposes a finite occurrence while its conditions are valid.
At its fixed occurrence, an AbsoluteEvent evaluates its conditions,
applies its actions when all conditions are valid, and unregisters itself.
Successful recurring execution advances the reaction’s stateful distribution.
A ConditionalEvent unregisters itself after its actions complete.
Reactive invalidation
An observable model change can invalidate a reaction between occurrences.
Observable model state includes node contents, positions, neighborhoods, nodes within a range,
and layer values observed at node positions.
The reaction is marked dirty synchronously.
When the enclosing reaction execution or scheduled command completes,
each dirty reaction refreshes its specialized state once and applies an invalidation policy distinct from post-firing
advancement, in first-invalidation order.
An additional semantic input can trigger this refresh while combined condition validity remains true.
If that policy changes nextOccurrence, the observable emits and the engine immediately asks the scheduler to
reindex the reaction.
An invalid reaction publishes the infinite occurrence.
Sampling occurs when its scheduling policy enables it again.
Revalidation refreshes specialized state and applies the invalidation policy from the current simulation time.
The correct invalidation policy belongs to the reaction family:
- The
GenericReactionpolicy draws a fresh delay. - A
ConditionalEventdraws on each invalid-to-valid transition from the current simulation time. A later invalidation discards that occurrence and publishes infinity. Repeated valid updates preserve the pending occurrence. - An
AbstractMarkovianNodeReactionpreserves or rescales a surviving exponential residual after a positive rate change and requires anExponentialTime. Its rate must be non-negative and different from NaN. Zero suspends scheduling; positive infinity produces an immediate occurrence subject to the distribution’s start time.
Membership and removal
Callers add and remove reactions through a ReactionHost.
The host changes membership first and, if a simulation is attached,
emits exactly one ordinary reactionAdded or reactionRemoved notification.
Adding a node emits reactionAdded once for each reaction already hosted by that node; removing a node emits the
corresponding reactionRemoved notifications before disposing the node.
The engine processes that notification on the simulation thread.
Removal disposes the exact scheduling subscription before removing the scheduler entry;
disposal is idempotent and prevents later scheduling emissions.
Both event policies invoke the same host removal operation when their one-shot procedure completes.
Node cloning reconstructs each NodeReaction through cloneOnNewNode, including
a fresh conditional event and time distribution.
Engine boundary
The engine integrates a reaction into execution in a fixed order:
- Complete reaction initialization and establish the current occurrence.
- Insert the reaction into the scheduler.
- Subscribe to
nextOccurrence. - Collect direct reaction invalidations during each reaction execution or scheduled command.
- Refresh each dirty reaction once when that model mutation completes.
- Reindex the reaction on every subsequent occurrence emission.
- Select and execute the earliest finite reaction.
- Process membership notifications from
ReactionHostimplementations.
Registration, occurrence emissions, scheduler updates, and scheduler removal are confined to the simulation thread. Host mutations notify the engine through its command queue; other mutations originating from another thread must be submitted through the same simulation scheduling API.
For the event loop, commands, monitors, and scheduler implementation, see the simulation engine explanation.