#discrete-event #agent #process #simulator #monte-carlo #no-alloc

no-std odem-rs

Object-based Discrete-Event Modelling in Rust using async/await

2 releases

new 0.1.1 Feb 21, 2025
0.1.0 Feb 21, 2025

#36 in Simulation

MIT license

640KB
9K SLoC

ODEM-rs: Object-based Discrete-Event Modeling for Rust

ODEM-rs is a high-performance, object-based discrete-event modeling library for Rust, designed to facilitate Monte Carlo-style simulation models using Rust’s async/await system. It provides an extensible, deterministic, and event-driven framework where concurrent agents interact through scheduled jobs.

πŸš€ Key Features

  • Process-Based Simulation: Allows modeling simulation entities as asynchronous agents with isolated state and internally concurrent jobs.
  • Event-Driven Execution: Skips directly between significant events rather than executing at fixed time intervals.
  • Deterministic & Portable: Uses deterministic PRNGs and cooperative concurrency for reproducible results.
  • Flexible & Extensible: Provides library traits to tailor simulators and data structures for custom needs.
  • Safe & Sound: Validated with Miri to detect undefined behavior and enforce stacked borrow rules.
  • Integrated: Integrates seamlessly with tracing, uom, and rand.
  • Embedded-friendly: Can be used in bare-metal environments with a reduced feature-set.

⏳ Execution Principle

ODEM-rs follows a discrete-event execution model, where simulation advances incrementally based on scheduled events. At any given model time, all continuations (representing agents and jobs) that are scheduled for execution are processed instantaneously in terms of model time before the clock is advanced. Thus, the passing of model time is explicit, allowing for deterministic execution. The execution order is determined by:

  • Model time - Monotonically increasing time preserves cause-and-effect relationships between processes.
  • Rank (between agents) – Defines execution priority among different agents.
  • Precedence (between jobs) – Ensures the correct sequencing of dependent jobs within one agent.
  • Insertion Order – Resolves ties between jobs with equal precedence by executing them in the order they were scheduled.

Once all scheduled tasks for a specific model time have executed, the simulation time jumps to the next scheduled event, skipping idle periods. This execution model is managed by an event calendar, which is a part of the async/await runtime executor. The executor schedules and processes continuations in deterministic order as described above. This allows ODEM-rs to seamlessly integrate with Rust’s async runtime model, leveraging native concurrency while maintaining strict event sequencing.

πŸ“– Getting Started

Installation

Add ODEM-rs to your Cargo.toml:

[dependencies]
odem-rs = "0.1"

Example: Barbershop Simulation

In order to get you started quickly, here is an example scenario featuring a simple barbershop model. Customers arrive at random intervals and request service from a single barber. Once a customer arrives, they occupy the barber for a random duration simulating the haircut, then release the barber for the next customer. The simulation runs for 12 hours.

use odem_rs::{prelude::*, sync::facility::Facility};

#[derive(Config, Default)]
struct Barbershop {
	barber: Facility,
	rng_stream: RngStream,
}

struct Customer;

impl Behavior<Barbershop> for Customer {
	type Output = ();
	
	async fn actions(&self, sim: &Sim<Barbershop>) {
		let mut duration = sim.global().rng_stream.rng();
		let chair = sim.global().barber.seize().await;
		sim.advance(duration.random_range(12.0..18.0)).await;
		chair.release();
	}
}

async fn sim_main(sim: &Sim<Barbershop>) {
	sim.fork(async {
		let mut delay = sim.global().rng_stream.rng();
		let pool = Pool::dynamic();
		loop {
			sim.advance(delay.random_range(12.0..24.0)).await;
			sim.activate(pool.alloc(Agent::new(Customer)));
		}
	}).or(sim.advance(12.0 * 60.0)).await;
}

fn main() {
	simulation(sim_main).ok();
}

More examples can be found in the examples directory.

🎯 Why Use ODEM-rs?

  • βœ… Native Rust Design: Leverages Rust’s async runtime for efficient, structured concurrency.
  • βœ… Safe & Deterministic: Memory safe and fully deterministic event scheduling with PRNG-based randomness.
  • βœ… High Performance: Optimized for large-scale simulations with minimal runtime overhead.
  • βœ… Extensible: Provides customizable traits for tailoring the simulation to specific modeling needs.

πŸ‘₯ Contributors & Acknowledgments

ODEM-rs is part of ongoing doctoral research and has benefited from contributions by:

  • Lukas Markeffsky with whom I enjoyed in-depth discussions on Rust’s type system and whose incredible insight and sharp mind helped a lot to find and resolve soundness issues in addition to improving the ergonomics of the library.
  • Paula Wiesner with whom I performed early prototyping of agent-based approaches and who is still interested in the progress of this project, despite having successfully moved past academia. I appreciate the enthusiasm!

I welcome contributions, feedback, and feature requests! Open an issue or submit a PR.

πŸ“œ License

ODEM-rs is licensed under MIT. See LICENSE for details.

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in ODEM-rs by you, shall be licensed as MIT, without any additional terms or conditions.

Dependencies

~5–7.5MB
~142K SLoC