pub struct Context { /* private fields */ }Expand description
A manager for the state of a discrete-event simulation
Provides core simulation services including
- Maintaining a notion of time
- Scheduling events to occur at some point in the future and executing them at that time
- Holding data that can be accessed by simulation modules
Simulations are constructed out of a series of interacting modules that
take turns manipulating the Context through a mutable reference. Modules
store data in the simulation using the DataPlugin trait that allows them
to retrieve data by type.
The future event list of the simulation is a queue of Callback objects -
called plans - that will assume control of the Context at a future point
in time and execute the logic in the associated FnOnce(&mut Context)
closure. Modules can add plans to this queue through the Context.
The simulation also has a separate callback mechanism. Callbacks fire before the next timed event (even if it is scheduled for the current time). This allows modules to schedule actions for immediate execution but outside of the current iteration of the event loop.
Modules can also emit ‘events’ that other modules can subscribe to handle by event type. This allows modules to broadcast that specific things have occurred and have other modules take turns reacting to these occurrences.
Implementations§
Source§impl Context
impl Context
Sourcepub fn subscribe_to_event<E: IxaEvent>(
&mut self,
handler: impl Fn(&mut Context, E) + 'static,
) -> EventListenerId<E>
pub fn subscribe_to_event<E: IxaEvent>( &mut self, handler: impl Fn(&mut Context, E) + 'static, ) -> EventListenerId<E>
Register to handle emission of events of type E
Handlers will be called upon event emission in order of subscription as
queued Callbacks with the appropriate event.
Sourcepub fn unsubscribe_from_event<E: IxaEvent>(
&mut self,
listener_id: &EventListenerId<E>,
) -> bool
pub fn unsubscribe_from_event<E: IxaEvent>( &mut self, listener_id: &EventListenerId<E>, ) -> bool
Unsubscribe a previously registered event listener.
Returns true if a listener was unsubscribed and false if the token is
unknown, already unsubscribed, or otherwise absent.
Sourcepub fn emit_event<E: IxaEvent>(&mut self, event: E)
pub fn emit_event<E: IxaEvent>(&mut self, event: E)
Emit an event of type E to be handled by registered receivers
Receivers will handle events in the order that they have subscribed and are queued as callbacks
Sourcepub fn add_plan(
&mut self,
time: impl Into<f64>,
callback: impl FnOnce(&mut Context) + 'static,
) -> PlanId
pub fn add_plan( &mut self, time: impl Into<f64>, callback: impl FnOnce(&mut Context) + 'static, ) -> PlanId
Add a plan to the future event list at the specified time in the normal phase
The supplied time is converted to f64 before validation.
use ixa::Context;
struct ModelTime(f64);
impl From<ModelTime> for f64 {
fn from(time: ModelTime) -> Self {
time.0
}
}
let mut context = Context::new();
context.add_plan(ModelTime(1.0), |_| {});Returns a PlanId for the newly-added plan that can be used to cancel it
if needed.
§Panics
Panics if time is in the past, infinite, or NaN.
Sourcepub fn add_plan_with_phase(
&mut self,
time: impl Into<f64>,
callback: impl FnOnce(&mut Context) + 'static,
phase: ExecutionPhase,
) -> PlanId
pub fn add_plan_with_phase( &mut self, time: impl Into<f64>, callback: impl FnOnce(&mut Context) + 'static, phase: ExecutionPhase, ) -> PlanId
Add a plan to the future event list at the specified time and with the specified phase (first, normal, or last among plans at the specified time)
The supplied time is converted to f64 before validation.
Returns a PlanId for the newly-added plan that can be used to cancel it
if needed.
§Panics
Panics if time is in the past, infinite, or NaN.
Sourcepub fn add_passive_plan(
&mut self,
time: impl Into<f64>,
callback: impl FnOnce(&mut Context) + 'static,
) -> PlanId
pub fn add_passive_plan( &mut self, time: impl Into<f64>, callback: impl FnOnce(&mut Context) + 'static, ) -> PlanId
Add a passive plan to the future event list at the specified time in the normal phase.
Passive plans execute like regular plans but do not keep the simulation timeline alive.
The supplied time is converted to f64 before validation.
Returns a PlanId for the newly-added plan that can be used to cancel it
if needed.
§Panics
Panics if time is in the past, infinite, or NaN.
Sourcepub fn schedule_shutdown(&mut self, time: f64) -> PlanId
pub fn schedule_shutdown(&mut self, time: f64) -> PlanId
Schedule Context::shutdown at the specified maximum simulation time.
The shutdown request is scheduled through Context::add_passive_plan,
so it does not keep the simulation timeline alive when non-passive work is
exhausted before time. If execution reaches time, normal shutdown
finishes queued callbacks and regular plans at that time before running
shutdown-time plans. If execution ends earlier, the future passive
shutdown plan remains queued like any other future passive plan.
This schedules the shutdown request itself. Use Context::add_shutdown_plan
to schedule work that should run during normal shutdown.
Returns a PlanId that can be passed to Context::cancel_plan.
§Examples
use ixa::Context;
let mut context = Context::new();
context.schedule_shutdown(10.0);
context.add_plan(20.0, |_| {});
context.execute();
assert_eq!(context.get_current_time(), 10.0);§Panics
Panics if time is in the past, infinite, or NaN.
Sourcepub fn add_passive_plan_with_phase(
&mut self,
time: impl Into<f64>,
callback: impl FnOnce(&mut Context) + 'static,
phase: ExecutionPhase,
) -> PlanId
pub fn add_passive_plan_with_phase( &mut self, time: impl Into<f64>, callback: impl FnOnce(&mut Context) + 'static, phase: ExecutionPhase, ) -> PlanId
Add a passive plan to the future event list at the specified time and with the specified phase.
Passive plans execute like regular plans but do not keep the simulation timeline alive.
The supplied time is converted to f64 before validation.
Returns a PlanId for the newly-added plan that can be used to cancel it
if needed.
§Panics
Panics if time is in the past, infinite, or NaN.
Sourcepub fn add_shutdown_plan(
&mut self,
callback: impl FnOnce(&mut Context) + 'static,
) -> PlanId
pub fn add_shutdown_plan( &mut self, callback: impl FnOnce(&mut Context) + 'static, ) -> PlanId
Add a plan to execute during shutdown-time in the normal phase.
Shutdown-time plans execute after regular plans at the current simulation time are exhausted during normal shutdown, and after natural exhaustion of the regular plan queue.
Returns a PlanId for the newly-added plan that can be used to cancel it
if needed.
Sourcepub fn add_shutdown_plan_with_phase(
&mut self,
callback: impl FnOnce(&mut Context) + 'static,
phase: ExecutionPhase,
) -> PlanId
pub fn add_shutdown_plan_with_phase( &mut self, callback: impl FnOnce(&mut Context) + 'static, phase: ExecutionPhase, ) -> PlanId
Add a plan to execute during shutdown-time with the specified phase.
Shutdown-time plans have no simulation time. They are ordered by phase and insertion order.
Returns a PlanId for the newly-added plan that can be used to cancel it
if needed.
Sourcepub fn add_periodic_plan_with_phase(
&mut self,
period: impl Into<f64>,
callback: impl Fn(&mut Context) + 'static,
phase: ExecutionPhase,
)
pub fn add_periodic_plan_with_phase( &mut self, period: impl Into<f64>, callback: impl Fn(&mut Context) + 'static, phase: ExecutionPhase, )
Add a passive periodic plan with specified priority to the future event list.
Periodic plans reschedule themselves after every run. They do not keep the simulation timeline alive: when no non-passive plans remain, normal shutdown begins, and only passive plans at the final current time can still run during that execution pass. Future passive periodic plans remain queued and may run if later non-passive work is scheduled.
The supplied period is converted to f64 before validation.
Notes:
- The first periodic plan is scheduled at time
0.0. Ifset_start_timewas set to a positive value, this will currently panic because the first plan occurs before the start time (see issue #634 for future behavior).
§Panics
Panics if plan period is negative, infinite, or NaN.
Sourcepub fn cancel_plan(&mut self, plan_id: &PlanId)
pub fn cancel_plan(&mut self, plan_id: &PlanId)
Cancel a plan that has been added to the queue
§Panics
This function panics if you cancel a plan which has already been cancelled or executed.
Sourcepub fn queue_callback(&mut self, callback: impl FnOnce(&mut Context) + 'static)
pub fn queue_callback(&mut self, callback: impl FnOnce(&mut Context) + 'static)
Add a Callback to the queue to be executed before the next plan
Sourcepub fn get_data_mut<T: DataPlugin>(
&mut self,
_data_plugin: T,
) -> &mut T::DataContainer
pub fn get_data_mut<T: DataPlugin>( &mut self, _data_plugin: T, ) -> &mut T::DataContainer
Retrieve a mutable reference to the data container associated with a
DataPlugin
If the data container has not been already added to the Context then
this function will use the DataPlugin::init method
to construct a new data container and store it in the Context.
Returns a mutable reference to the data container
Sourcepub fn get_data<T: DataPlugin>(&self, _data_plugin: T) -> &T::DataContainer
pub fn get_data<T: DataPlugin>(&self, _data_plugin: T) -> &T::DataContainer
Retrieve a reference to the data container associated with a
DataPlugin
Returns a reference to the data container if it exists or else None
Sourcepub fn shutdown(&mut self)
pub fn shutdown(&mut self)
Request normal shutdown.
Normal shutdown stops simulation time from advancing. Execution continues
through queued callbacks, regular plans at the current time, and then
shutdown-time plans. Calling shutdown during shutdown-time execution
does not return execution to regular current-time plans.
Sourcepub fn abort(&mut self)
pub fn abort(&mut self)
Stop the current event loop immediately.
Abort only stops the current execute loop. The stopped status is cleared
when execute is called again.
Sourcepub fn get_current_time(&self) -> f64
pub fn get_current_time(&self) -> f64
Get the current simulation time
Returns the current time in the simulation. The behavior depends on execution state:
- During execution: returns the time of the currently executing plan or callback
- Before execution: returns the start time (if set via
Context::set_start_time), or0.0
The time can be negative if a negative start time was set before execution.
Sourcepub fn set_start_time(&mut self, start_time: impl Into<f64>)
pub fn set_start_time(&mut self, start_time: impl Into<f64>)
Set the start time for the simulation. Must be finite.
The supplied start time is converted to f64 before validation.
- Call before
Context.execute(). start_timemust be finite (not NaN or infinite).- May be called only once.
- If plans are already scheduled,
start_timemust be earlier than or equal to the earliest scheduled plan time.
§Panics
Panics if:
start_timeis NaN or infinite.- the start time was already set.
Context::execute()has been called.start_timeis later than the earliest scheduled plan time.
Sourcepub fn get_start_time(&self) -> Option<f64>
pub fn get_start_time(&self) -> Option<f64>
Get the start time that was set via set_start_time, or None if not set.
Sourcepub fn execute(&mut self)
pub fn execute(&mut self)
Execute the simulation until callbacks and plans are exhausted and shutdown work is complete.
Sourcepub fn execute_single_step(&mut self)
pub fn execute_single_step(&mut self)
Executes a single callback, plan, or shutdown status transition.
pub fn get_execution_statistics(&mut self) -> ExecutionStatistics
Trait Implementations§
Source§impl ContextBase for Context
impl ContextBase for Context
fn subscribe_to_event<E: IxaEvent>( &mut self, handler: impl Fn(&mut Context, E) + 'static, ) -> EventListenerId<E>
fn unsubscribe_from_event<E: IxaEvent>( &mut self, listener_id: &EventListenerId<E>, ) -> bool
fn emit_event<E: IxaEvent>(&mut self, event: E)
fn add_plan( &mut self, time: impl Into<f64>, callback: impl FnOnce(&mut Context) + 'static, ) -> PlanId
fn add_plan_with_phase( &mut self, time: impl Into<f64>, callback: impl FnOnce(&mut Context) + 'static, phase: ExecutionPhase, ) -> PlanId
fn add_passive_plan( &mut self, time: impl Into<f64>, callback: impl FnOnce(&mut Context) + 'static, ) -> PlanId
fn add_passive_plan_with_phase( &mut self, time: impl Into<f64>, callback: impl FnOnce(&mut Context) + 'static, phase: ExecutionPhase, ) -> PlanId
fn add_shutdown_plan( &mut self, callback: impl FnOnce(&mut Context) + 'static, ) -> PlanId
fn add_shutdown_plan_with_phase( &mut self, callback: impl FnOnce(&mut Context) + 'static, phase: ExecutionPhase, ) -> PlanId
fn add_periodic_plan_with_phase( &mut self, period: impl Into<f64>, callback: impl Fn(&mut Context) + 'static, phase: ExecutionPhase, )
fn cancel_plan(&mut self, plan_id: &PlanId)
fn queue_callback(&mut self, callback: impl FnOnce(&mut Context) + 'static)
fn get_data_mut<T: DataPlugin>(&mut self, plugin: T) -> &mut T::DataContainer
fn get_data<T: DataPlugin>(&self, plugin: T) -> &T::DataContainer
fn get_current_time(&self) -> f64
fn get_execution_statistics(&mut self) -> ExecutionStatistics
fn abort(&mut self)
Source§impl ContextEntitiesExt for Context
impl ContextEntitiesExt for Context
fn add_entity<E: Entity, PL: PropertyInitializationList<E>>( &mut self, property_list: PL, ) -> Result<EntityId<E>, IxaError>
Source§fn get_property<E: Entity, P: Property<E>>(&self, entity_id: EntityId<E>) -> P
fn get_property<E: Entity, P: Property<E>>(&self, entity_id: EntityId<E>) -> P
entity_id. Read moreSource§fn set_property<E: Entity, P: Property<E>>(
&mut self,
entity_id: EntityId<E>,
property_value: P,
)
fn set_property<E: Entity, P: Property<E>>( &mut self, entity_id: EntityId<E>, property_value: P, )
PropertyChangeEvent.Source§fn index_property<E: Entity, P: IndexableProperty<E>>(&mut self)
fn index_property<E: Entity, P: IndexableProperty<E>>(&mut self)
P. Read moreSource§fn index_property_counts<E: Entity, P: IndexableProperty<E>>(&mut self)
fn index_property_counts<E: Entity, P: IndexableProperty<E>>(&mut self)
P. Read moreSource§fn track_periodic_value_change_counts<E, PL, P, F>(
&mut self,
period: impl Into<f64>,
handler: F,
)where
E: Entity,
PL: PropertyList<E> + Eq + Hash,
P: IndexableProperty<E>,
F: Fn(&mut Context, &mut StratifiedValueChangeCounter<E, PL, P>) + 'static,
fn track_periodic_value_change_counts<E, PL, P, F>(
&mut self,
period: impl Into<f64>,
handler: F,
)where
E: Entity,
PL: PropertyList<E> + Eq + Hash,
P: IndexableProperty<E>,
F: Fn(&mut Context, &mut StratifiedValueChangeCounter<E, PL, P>) + 'static,
Source§fn with_query_results<'a, E: Entity, Q: Query<E>>(
&'a self,
query: Q,
callback: &mut dyn FnMut(EntitySet<'a, E>),
)
fn with_query_results<'a, E: Entity, Q: Query<E>>( &'a self, query: Q, callback: &mut dyn FnMut(EntitySet<'a, E>), )
EntitySet.
This is especially efficient for indexed queries, as this method can reduce to wrapping
a single indexed source.Source§fn query_entity_count<E: Entity, Q: Query<E>>(&self, query: Q) -> usize
fn query_entity_count<E: Entity, Q: Query<E>>(&self, query: Q) -> usize
Source§fn sample_entity<E, Q, R>(&self, rng_id: R, query: Q) -> Option<EntityId<E>>
fn sample_entity<E, Q, R>(&self, rng_id: R, query: Q) -> Option<EntityId<E>>
None if the
query’s result set is empty. Read moreSource§fn count_and_sample_entity<E, Q, R>(
&self,
rng_id: R,
query: Q,
) -> (usize, Option<EntityId<E>>)
fn count_and_sample_entity<E, Q, R>( &self, rng_id: R, query: Q, ) -> (usize, Option<EntityId<E>>)
Source§fn sample_entities<E, Q, R>(
&self,
rng_id: R,
query: Q,
n: usize,
) -> Vec<EntityId<E>>
fn sample_entities<E, Q, R>( &self, rng_id: R, query: Q, n: usize, ) -> Vec<EntityId<E>>
requested entities uniformly from the query results. If the
query’s result set has fewer than requested entities, the entire result
set is returned. Read moreSource§fn get_entity_count<E: Entity>(&self) -> usize
fn get_entity_count<E: Entity>(&self) -> usize
E.Source§fn get_entity_iterator<E: Entity>(&self) -> PopulationIterator<E> ⓘ
fn get_entity_iterator<E: Entity>(&self) -> PopulationIterator<E> ⓘ
E.Source§fn query<E: Entity, Q: Query<E>>(&self, query: Q) -> EntitySet<'_, E>
fn query<E: Entity, Q: Query<E>>(&self, query: Q) -> EntitySet<'_, E>
EntitySet representing the query results.Source§fn query_result_iterator<E: Entity, Q: Query<E>>(
&self,
query: Q,
) -> EntitySetIterator<'_, E> ⓘ
fn query_result_iterator<E: Entity, Q: Query<E>>( &self, query: Q, ) -> EntitySetIterator<'_, E> ⓘ
Source§impl ContextGlobalPropertiesExt for Context
impl ContextGlobalPropertiesExt for Context
Source§fn set_global_property_value<T: GlobalProperty + 'static>(
&mut self,
_property: T,
value: T::Value,
) -> Result<(), IxaError>
fn set_global_property_value<T: GlobalProperty + 'static>( &mut self, _property: T, value: T::Value, ) -> Result<(), IxaError>
Source§fn get_global_property_value<T: GlobalProperty + 'static>(
&self,
_property: T,
) -> Option<&T::Value>
fn get_global_property_value<T: GlobalProperty + 'static>( &self, _property: T, ) -> Option<&T::Value>
Source§fn load_global_properties(&mut self, file_name: &Path) -> Result<(), IxaError>
fn load_global_properties(&mut self, file_name: &Path) -> Result<(), IxaError>
Source§fn load_parameters_from_json<T: 'static + Debug + DeserializeOwned>(
&mut self,
file_name: &Path,
) -> Result<T, IxaError>
fn load_parameters_from_json<T: 'static + Debug + DeserializeOwned>( &mut self, file_name: &Path, ) -> Result<T, IxaError>
Source§impl ContextNetworkExt for Context
impl ContextNetworkExt for Context
Source§fn add_edge<E: Entity, ET: EdgeType<E>>(
&mut self,
entity_id: EntityId<E>,
neighbor: EntityId<E>,
weight: f32,
inner: ET,
) -> Result<(), IxaError>
fn add_edge<E: Entity, ET: EdgeType<E>>( &mut self, entity_id: EntityId<E>, neighbor: EntityId<E>, weight: f32, inner: ET, ) -> Result<(), IxaError>
Source§fn add_edge_bidi<E: Entity, ET: EdgeType<E>>(
&mut self,
entity1: EntityId<E>,
entity2: EntityId<E>,
weight: f32,
inner: ET,
) -> Result<(), IxaError>
fn add_edge_bidi<E: Entity, ET: EdgeType<E>>( &mut self, entity1: EntityId<E>, entity2: EntityId<E>, weight: f32, inner: ET, ) -> Result<(), IxaError>
Source§fn remove_edge<E: Entity, ET: EdgeType<E>>(
&mut self,
entity_id: EntityId<E>,
neighbor: EntityId<E>,
) -> Option<Edge<E, ET>>
fn remove_edge<E: Entity, ET: EdgeType<E>>( &mut self, entity_id: EntityId<E>, neighbor: EntityId<E>, ) -> Option<Edge<E, ET>>
ET from entity_id to neighbor and return it, or None if
the edge does not exist.Source§fn get_edge<E: Entity, ET: EdgeType<E>>(
&self,
entity_id: EntityId<E>,
neighbor: EntityId<E>,
) -> Option<&Edge<E, ET>>
fn get_edge<E: Entity, ET: EdgeType<E>>( &self, entity_id: EntityId<E>, neighbor: EntityId<E>, ) -> Option<&Edge<E, ET>>
ET from entity_id to neighbor if one exists.Source§fn get_edges<E: Entity, ET: EdgeType<E>>(
&self,
entity_id: EntityId<E>,
) -> Vec<Edge<E, ET>>
fn get_edges<E: Entity, ET: EdgeType<E>>( &self, entity_id: EntityId<E>, ) -> Vec<Edge<E, ET>>
ET from entity_id.Source§fn get_matching_edges<E: Entity, ET: EdgeType<E>>(
&self,
entity_id: EntityId<E>,
filter: impl Fn(&Self, &Edge<E, ET>) -> bool,
) -> Vec<Edge<E, ET>>
fn get_matching_edges<E: Entity, ET: EdgeType<E>>( &self, entity_id: EntityId<E>, filter: impl Fn(&Self, &Edge<E, ET>) -> bool, ) -> Vec<Edge<E, ET>>
Source§impl ContextRandomExt for Context
impl ContextRandomExt for Context
Source§fn init_random(&mut self, base_seed: u64)
fn init_random(&mut self, base_seed: u64)
RngPlugin data container to store rngs as well as a base
seed. Note that rngs are created lazily when get_rng is called.Source§fn sample<R: RngId + 'static, T>(
&self,
_rng_type: R,
sampler: impl FnOnce(&mut R::RngType) -> T,
) -> T
fn sample<R: RngId + 'static, T>( &self, _rng_type: R, sampler: impl FnOnce(&mut R::RngType) -> T, ) -> T
RngId by applying the specified sampler function. If the Rng has not been used
before, one will be created with the base seed you defined in set_base_random_seed.
Note that this will panic if set_base_random_seed was not called yet.Source§fn debug_rng_state<R: RngId + 'static>(&self, _rng_id: R) -> u64
fn debug_rng_state<R: RngId + 'static>(&self, _rng_id: R) -> u64
Source§fn sample_distr<R: RngId + 'static, T>(
&self,
_rng_type: R,
distribution: impl Distribution<T>,
) -> Twhere
R::RngType: Rng,
fn sample_distr<R: RngId + 'static, T>(
&self,
_rng_type: R,
distribution: impl Distribution<T>,
) -> Twhere
R::RngType: Rng,
RngId. If the Rng has not been used before, one will be
created with the base seed you defined in set_base_random_seed.
Note that this will panic if set_base_random_seed was not called yet.Source§fn sample_range<R: RngId + 'static, S, T>(&self, rng_id: R, range: S) -> Twhere
R::RngType: Rng,
S: SampleRange<T>,
T: SampleUniform,
fn sample_range<R: RngId + 'static, S, T>(&self, rng_id: R, range: S) -> Twhere
R::RngType: Rng,
S: SampleRange<T>,
T: SampleUniform,
range
using the generator associated with the given RngId.
Note that this will panic if set_base_random_seed was not called yet.Source§fn sample_bool<R: RngId + 'static>(&self, rng_id: R, p: impl Into<f64>) -> boolwhere
R::RngType: Rng,
fn sample_bool<R: RngId + 'static>(&self, rng_id: R, p: impl Into<f64>) -> boolwhere
R::RngType: Rng,
Source§impl ContextReportExt for Context
impl ContextReportExt for Context
fn generate_filename(&mut self, short_name: &str) -> PathBuf
Source§fn add_report_by_type_id(
&mut self,
type_id: TypeId,
short_name: &str,
) -> Result<(), IxaError>
fn add_report_by_type_id( &mut self, type_id: TypeId, short_name: &str, ) -> Result<(), IxaError>
Source§fn add_report<T: Report + 'static>(
&mut self,
short_name: &str,
) -> Result<(), IxaError>
fn add_report<T: Report + 'static>( &mut self, short_name: &str, ) -> Result<(), IxaError>
add_report with each report type, passing the name of the report type.
The short_name is used for file naming to distinguish what data each
output file points to. Read morefn get_writer(&self, type_id: TypeId) -> RefMut<'_, Writer<File>>
Source§fn send_report<T: Report>(&self, report: T)
fn send_report<T: Report>(&self, report: T)
Source§fn report_options(&mut self) -> &mut ConfigReportOptions
fn report_options(&mut self) -> &mut ConfigReportOptions
ConfigReportOptions object which has setter methods for report configuration