simul 0.5.1

A discrete-event simulation library aimed at high-level use-cases to quickly simulate real-world problems and run simulated experiments. Some example use cases might include simulating logistics or operations research problems, running experiments to determine optimal parameters, simulating queueing systems, distributed systems, performance engineering, and so on.
Documentation
`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](https://en.wikipedia.org/wiki/M/M/c_queue) 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:
- [Discrete-event simulation]https://en.wikipedia.org/wiki/Discrete-event_simulation
- [Complex adaptive systems]https://authors.library.caltech.edu/60491/1/MGM%20113.pdf
- [Simulated annealing]https://en.wikipedia.org/wiki/Simulated_annealing
- [Job-shop scheduling]https://en.wikipedia.org/wiki/Job-shop_scheduling
- [Birth-death processes]https://en.wikipedia.org/wiki/Birth%E2%80%93death_process
- [Computer experiments]https://en.wikipedia.org/wiki/Computer_experiment
- Other: simulating logistics, operations research problems, running experiments
  to approximate a global optimum, simulating queueing systems, distributed
  systems, performance engineering/analysis, and so on.

# 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

``` toml
[dependencies]
simul = "0.4.1"
```

``` rust
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.

![](./readme-assets/cafe-example-queued-durations.png)

# Contributing

Issues, bugs, features are tracked in TODO.org