Skip to content

jmqd/simul

Repository files navigation

simul is a discrete-event simulation library for running high-level simulations of real-world problems and for running simulated experiments.

simul is a discrete-event simulator using incremental time progression, with M/M/c queues for interactions between agents. It also supports some forms of experimentation and simulated annealing to replicate a simulation many times, varying the simulation parameters.

Use-cases:

Usage

Warning

Experimental and unstable. Almost all APIs are expected to change.

  • For some examples, see the examples subdirectory.
  • For use cases where your agents need their own custom state, define a struct, implement Agent, and pass your agents into Simulation via constructing AgentInitializers.

Basic usage

[dependencies] simul = "0.4.1"
use simul::agent::*; use simul::Simulation; use simul::SimulationParameters; /// Example of a minimal, simple Simulation that can be executed. fn main() { // Runs a simulation with a producer that produces work at every tick of // discrete time (period=1), and a consumer that cannot keep up (can only // process that work every third tick). let mut simulation = Simulation::new(SimulationParameters { // We pass in two agents: // `producer`: produces a message to the consumer every tick // `consumer`: consumes w/ no side effects every second tick // Agents are powerful, and you can pass-in custom implementations here. agent_initializers: vec![ periodic_producing_agent("producer", 1, "consumer"), periodic_consuming_agent("consumer", 2), ], // We pass in a halt condition so the simulation knows when it is finished. // In this case, it is "when the simulation is 10 ticks old, we're done." halt_check: |s: &Simulation| s.time == 10, ..Default::default() }); // For massive simulations, you might block on this line for a long time. simulation.run(); // Post-simulation, you can do analytics on the stored metrics, data, etc. simulation .agents .iter() .for_each(|agent| println!("{:#?}", agent)); }

Simulation Concepts / Abstraction

  • A simulation is a collection of Agents that interact with each other via Messages.
  • The simulation keeps a discrete time (u64) which is incremented on each tick of the Simulation.
  • What an Agent does at each tick of the simulation is provided by you in its on_tick() and on_message() methods.
  • Agents must have a unique name.
  • If an Agent wants to interact with another Agent, it can send a Message via the &mut ctx: AgentContext passed into on_tick and on_message.

The simulation runs all the logic of calling process(), distributing messages, tracking metrics, incrementing time, and when to halt. A Simulation is finished when the provided halt_check function returns true, or if an Agent responds with a special Interrupt to halt the Simulation.

Poisson-distributed example w/ Plotting

Here's an example of an outputted graph from a simulation run. In this simulation, we show the average waiting time of customers in a line at a cafe. The customers arrive at a Poisson-distributed arrival rate (lambda<-60.0) and a Poisson-distributed coffee-serving rate with the same distribution.

This simulation maps to the real world by assuming one tick of discrete-simulation time is equal to one second.

Basically, the barista serves coffees at around 60 seconds per drink and the customers arrive at about the same rate, both modeled by a stochastic Poisson generator.

This simulation has a halt_check condition of the simulation's time being equal to 60*60*12, representing a full 12-hour day of the cafe being open.

Contributing

Issues, bugs, features are tracked in TODO.org

About

discrete event simulation library for high-level simulations of real-world problems and simulated experiments

Resources

License

Stars

Watchers

Forks

Contributors