incerto
Rust crate for heavyweight multi-threaded Monte Carlo simulations.
Usage
This crate is powered by Bevy, which is a high-performance ECS framework.
This means that simulations are set up and executed using Entities and Systems.
In-depth knowledge of Bevy's internals is not required however, since we have abstracted away most interactions with Bevy. Instead, we expect the user to only:
- Define components.
- Spawn entities, each a collection of one or more components.
- Implement systems that update the entities on each simulation step.
use *;
let monte_carlo: MonteCarlo = new
// add one or more entity spawners
.add_entity_spawner
.add_entity_spawner
// add one or more systems
.add_systems
.add_systems
// finish
.build;
It is recommended to start with the examples.
Define components
Components will be the primary data type in the simulation.
They can be anything, so long as they can derive the Component trait.
Empty components, typically called Markers, are also sometimes useful to pick out specific entities.
;
;
Spawn entities
Entities are spawned at the beginning of each simulation using user-provided functions like this one.
Note that entities are in fact collections of one or more components, as such the spawn() function accepts a Bundle. A bundle can be a single component like above, or a tuple with multiple components.
Implement systems
Systems are the processing logic of the simulation. During each step, every user-defined system is executed once. Systems use queries to interact with and update entities in the simulation.
/// Increment all counters by one in each simulation step.
Queries may use the With and Without keywords to filter their scope.
They may also select multiple components, mutably or immutably. (note the use of mut, & and &mut)
Systems may also work with multiple queries. This allows for entities in the simulation to interact with each other.
Running the simulation
The simulation may be executed using the run(), reset() and run_new() methods.
// Run the simulation for 100 steps.
monte_carlo.run;
// Continue the same simulation for another 200 steps.
monte_carlo.run;
// Run the simulation for 500 steps from the beginning.
monte_carlo.reset;
monte_carlo.run;
// Can also be done like this.
monte_carlo.run_new;
Collecting results
Currently the following ways of fetching simulation results are supported.
- Count the number of remaining entities with a component
Cby callingmonte_carlo.count::<C>(). - Read out a value of the sole existing entity with component
Cby implementingObserveSingleforCand then callingmonte_carlo.observe_single::<C>(). - Read out a value aggregated from multiple existing entities with component
Cby implementingObserveManyforCand then callingmonte_carlo.observe_many::<C>().
Planned work
- Allow for filters like
WithandWithoutwhen observing values. - Add support for recoding time series during the simulation.
- Add some utilities to the crate for easy access to random values, noise etc
Credits
The name as well as the initial motivation behind this project came from the brilliant Incerto book series by Nassim Nicholas Taleb.