simu-des 0.1.0

Discrete-event simulation for Rust, inspired by SimPy — single-threaded async executor, resources, and Monte Carlo parallelism.
Documentation

simu

CI crates.io docs.rs License: MIT OR Apache-2.0 REUSE status

A Rust library for Discrete Event Simulation (DES), inspired by Python's SimPy but designed to be idiomatic Rust, high-performance, and scalable.

Goals:

  • Model complex, process-oriented simulations (e.g. hospital operations, logistics, queuing systems)
  • Support thousands of concurrent simulation processes with low overhead
  • Reproducible results via seeded RNG, or a pluggable external feed (SimEnv::with_source) — e.g. the portable SplitMix64 generator that can be re-implemented in another language for exact cross-engine comparison
  • Monte Carlo parallelism across independent simulation runs using OS threads

New to simu? Start with the tutorial module — five short chapters modeled on SimPy's "SimPy in 10 minutes", every snippet a running doc-test — and its four sub-60-line companion examples (cargo run --example intro_car, intro_charging, intro_cancellation, intro_charging_station). A signature cheat-sheet lives in API.md.

Installation

[dependencies]
simu-des = "0.1"

The crate is published as simu-des (the crates.io name simu was taken) but the library target is named simu, so it is imported as use simu::… — exactly as in the examples below.

Quick start

use simu::{SimEnv, Resource};

let mut env = SimEnv::with_seed(42);
let machine = Resource::new(1);

for i in 1..=3_u32 {
    let h = env.handle();
    let m = machine.clone();
    env.spawn(async move {
        let _guard = m.request().await;   // queue for machine
        h.timeout(2.0).await;             // hold for 2 time units
        println!("job {} done at {}", i, h.now());
    });
}

env.run();  // prints: job 1 done at 2, job 2 done at 4, job 3 done at 6

monte_carlo::run works out of the box (one std::thread per seed). For large seed counts, enable the optional feature to run on rayon's bounded thread pool instead:

[dependencies]
simu-des = { version = "0.1", features = ["monte-carlo"] }

Using simu with AI assistants

The repository ships two LLM-oriented files, kept in sync with the crate's compile-checked doc-tests:

  • llms.txt — a complete single-file reference: signatures, canonical patterns, a SimPy → simu translation table, and anti-patterns with their symptoms.
  • docs/simu-for-agents.md — a compact version designed to be dropped into your own project's agent context (CLAUDE.md, cursor rules, …) when you build simulations with simu.

Core primitives

Type Description
SimEnv Central coordinator: owns event queue, current time, processes, and seeded RNG
EnvHandle Cloneable handle passed into processes; provides timeout, event, rng, now
Timeout Future that resolves after a simulated delay (h.timeout(5.0).await)
EventTrigger / EventAwaitable Paired handles for manual inter-process signalling
Resource / ResourceGuard FIFO capacity-limited pool; RAII release on guard drop
PriorityResource Priority-scheduled pool (lower number = higher priority; FIFO within a level)
PreemptiveResource / PreemptiveGuard Priority pool whose in-use units can be preempted by a higher-priority request (cooperative-at-yield)
Container Reservoir of continuous quantity (put / get, strict head-of-line FIFO waiters)
ProcessHandle<T> Observable spawn; .await for the return value, drop to detach
AnyOf / AllOf Future combinators via the any_of! / all_of! macros

Building

cargo build

Testing

cargo test                  # run all tests
cargo test <test_name>      # run a single test

See TESTING.md for the full test strategy, coverage report, and benchmark guide.

Benchmarks

cargo bench                              # all benchmark groups
cargo bench -- timeout_throughput        # one group only
cargo bench -- --save-baseline main      # save baseline
cargo bench -- --baseline main           # compare against baseline

HTML reports are written to target/criterion/. Five benchmark groups cover executor throughput, resource contention, event broadcast, mixed workload, and Monte Carlo scaling.

Linting

cargo clippy -- -D warnings

Examples

Start with the four intro examples (one per tutorial chapter, each under 60 lines): intro_car, intro_charging, intro_cancellation, intro_charging_station.

Beyond those, three end-to-end examples demonstrate every public primitive in different domains. All run 10 parallel Monte Carlo simulations, write per-run logs, and print a summary table to stdout. See examples/hospital.md, examples/brewery.md, and examples/warehouse.md for full walkthroughs (sequence diagrams, configuration, sample output).

cargo run --example hospital --release

A hospital emergency department: priority-scheduled triage nurse, three beds with eviction of the longest-admitted patient when a critical case arrives, and a blood bank modelled as a Container. Logs to target/sim-logs/run_<N>.log.

cargo run --example brewery --release

A craft brewery / bio-reactor production line from the food & beverage domain: mash → boil → ferment → condition → bottle → CIP. The QA inspector contaminates the longest-running fermentation with a per-batch EventTrigger; contaminated batches preempt routine cleanups via a PriorityResource. Logs to target/sim-logs/brewery_run_<N>.log.

cargo run --example warehouse --release

A distribution center from the logistics / material-handling domain: inbound trucks (unload → QC → putaway) and outbound orders (pick → pack → load) share one small forklift fleet. The fleet is a PreemptiveResource — urgent truck-side work evicts a routine putaway, whose driver parks the pallet and finishes it later. The first example to exercise PreemptiveResource. Logs to target/sim-logs/warehouse_run_<N>.log. A browser-based visualizer for its runs lives in examples/warehouse-viz/.

SimPy parity

compare/ cross-checks simu against Python's SimPy as a reference oracle: identical JSON-contract models run on both engines and are compared per seed. Both sides draw from the same portable feed (SplitMix64 + shared transforms, re-implemented in compare/models/_feed.py), so the queue models are checked in exact mode — per-seed metrics agree to ~1e-15 — while hospital stays on a distributional test for its eviction-handoff ordering exception. Performance is compared on two axes: single-thread engine efficiency (wall-clock / events-per-sec / peak-RSS), and a Monte Carlo benchmark where simu fans independent replications across cores via monte_carlo::run while SimPy is GIL-serialised — showing the full parallel advantage. Canonical queue models are additionally checked against closed-form queueing theory, so neither engine is trusted blindly.

compare/run_comparison.sh             # build Rust, set up venv, write compare/REPORT.md
compare/run_comparison.sh --no-perf   # correctness only

See compare/README.md for methodology and compare/REPORT.md for the latest results. On the queue models simu runs ~10× faster at ~13× lower memory; the Container strict-FIFO divergence the harness originally surfaced is now fixed.

For contributors

See CONTRIBUTING.md for the contribution checklist (style, SPDX headers, DCO sign-off, review process).

Internal design docs, aimed at people changing the library itself:

  • SPEC.md — architecture, API contracts, invariants, and roadmap (the design source of truth).
  • PLAN.md — implementation plan and history.
  • TESTING.md — test strategy, coverage, and benchmark groups.

License

Licensed under either of

at your option — the Rust ecosystem's standard dual license. The repository is REUSE-compliant: every file carries SPDX licensing information, verified by reuse lint in CI.

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.