krABMaga
A modern developing art for reliable and efficient ABM simulation with the Rust language.
Introduction
krABMaga is a discrete events simulation engine for developing ABM simulation written in the Rust language.
krABMaga is designed to be a ready-to-use tool for the ABM community and for this reason the architectural concepts of the well-adopted MASON library were re-engineered to exploit the Rust peculiarities and programming model, in particular by keeping the visualization and the simulation subsystems fully separated.
Developed by IsisLab
Table of contents§
- Table of contents
- Dependencies
- How to run your first example simulaton
- How to write your first model
- Available features
- Macros for playing with Simulation Terminal
- How to contribute
- Architecture
Dependencies§
The visualization framework requires certain dependencies to run the simulation properly.
- 💻 Windows: VS2019 build tools
- 🍎 MacOS: No dependencies needed.
- 🐧 Linux: A few dependencies are needed. Check here for a list based on your distribution.
How to run your first example simulaton§
First of all, install latest version of Rust. Follow steps to setup Rust toolchain (cargo, rustc and rustup).
Now, you can download/clone all available krABMaga examples from our github repository called examples.
To run a simulation, go to root directory of a model, for example /path/to/examples/flockers
. With command ls
, you should be able to see a typcal krABMaga simulation struct:
src
: main folder with code. It containsmain.rs
file and two directories for model and visulization components.Cargo.toml
: Configuration file for Rust project, with dependencies and features.assets
: an images folder. It contains all the icons that can be used for visualization.Makefile.toml
: another configuration file, necessary to a correct execution of visualization.
Inside the root directory of model that you choose, you can run a models with or without visualization.
To simply run your simulation, with no visualization:
cargo run --release
Running in this way, you can see our Simulation Terminal
(better known as Simulation Monitor
) based on tui-rs, a rust library that provides components to create terminal with an interface. As a modelist, you can use krABMaga macros to create several plots, print logs and add a model description (shown using a popup)
Based on Bevy game engine, it's possible to run simulation with visualization. It's also available a menu to start and stop simulations and a slider to set simulation speed. To run a model with visualization enabled, you have to start the simulation with the command:
cargo run --release --features visualization
# Alternative command. Requires 'cargo make' installed
cargo make run --release
In addition to the classical visualization, you can run your krABMaga simulation inside your browser using Web Assembly. This is possible with the command:
# Requires 'cargo make' installed
cargo make serve --release
How to write your first model§
If you don't start from our Template, add this to your Cargo.toml
:
[dependencies]
krABMaga = { git="https://github.com/krABMaga/krABMaga.git" }
[features]
visualization = ["krABMaga/visualization"]
visualization_wasm = ["krABMaga/visualization_wasm"]
We strongly recommend to use Template or any other example as base of a new project, especially if you want to provide any visualization.
Each krABMaga model needs structs that implements our Traits, one for State and the other for Agent. In the State struct you have to put Agent field(s), because it represents the ecosystem of a simulation. More details for each krABMaga componenet are in the Architecture section.
The simplest part is main.rs
, because is similar for each example.
You can define two main functions using cfg directive, that can remove code based on which features are (not) enabled.
Without visualization, you have only to use simulate! to run simulation, passing a state, step number and how may time repeat your simulation.
With visualization, you have to set graphical settings (like dimension or background) and call start method.
// Main used when only the simulation should run, without any visualization.
#[cfg(not(any(feature = "visualization", feature = "visualization_wasm")))]
fn main() {
let dim = (200., 200.);
let state = Flocker::new(dim, num_agents);
let step = 10;
let reps = 1;
let num_agents = 100;
let _ = simulate!(state, step, reps);
}
// Main used when a visualization feature is applied.
#[cfg(any(feature = "visualization", feature = "visualization_wasm"))]
fn main() {
let dim = (200., 200.);
let num_agents = 100;
let state = Flocker::new(dim, num_agents);
Visualization::default()
.with_window_dimensions(1000., 700.)
.with_simulation_dimensions(dim.0 as f32, dim.1 as f32)
.with_background_color(Color::rgb(0., 0., 0.))
.with_name("Flockers")
.start::<VisState, Flocker>(VisState, state);
}
Available features§
This library offers some features to make your simulation more interesting and to avoid to install many dependencies that are not needed for basic simulation.
cargo run --release --features <name_feature>
Compilation Feature | Description | Experimental | Release Candidate | Stable |
---|---|---|---|---|
No Features | Possibility to run model using Simulation Terminal and setup model-exploration experiments (Parameter Sweeping, Genetic and Random) in sequential/parallel mode. It's enough to create your base simulations. | 🦀 | ||
visualization | Based on Bevy engine , it makes possible to visualize your model elements, to understand better the behavior of your simulation. | 🦀 | ||
visualization-wasm | Based on Web Assembly , give you the possibility to execute your visualized simulation inside your own browser. | 🦀 | ||
distributed-mpi | Enable distributed model exploration using MPI. At each iteration, the amount of configurations are balanced among your nodes. | 🦀 | ||
bayesian | Use ML Rust libraries to use/create function to use Bayesian Optimization . | 🦀 | ||
parallel | Speed-up a single simulation parallelizing agent scheduling during a step. | 🦀 |
Macros for playing with Simulation Terminal§
Simulation Terminal
is enabled by default using macro simulate!
, so can be used passing a state, step number and how may time repeat your simulation..
That macro has a fourth optional parameter, a boolean. When false
is passed, Simulation Terminal
is disabled.
($s:expr, $step:expr, $reps:expr $(, $flag:expr)?) => {{
// Macro code
}}
You can create tabs and plot your data using two macro:
addplot!
let you create a new plot that will be displayed in its own tab.
addplot!(String::from("Chart Name"), String::from("xxxx"), String::from("yyyyy"));
plot!
to add a point to a plot. Points can be added during simulation execution, for example insideafter_step
method. You have to pass plot name, series name, x value and y value. Coordinate values need to bef64
.
plot!(String::from("Chart name"), String::from("s1"), x, y);
On Terminal home page there is also a log section, you can plot log messages when some event needs to be noticed.
You can navigate among all logs using ↑↓ arrows.
To add a log use the macro log!
, passing a LogType
(an enum) and the log message.
log!(LogType::Info, String::from("Log Message"));
Are available four type of Logs:
pub enum LogType {
Info,
Warning,
Error,
Critical,
}
How to contribute§
If you want to test, add or change something inside krABMaga engine, you can clone main repo locally, and change dependecy inside Cargo.toml
of your examples:
[dependencies]
# krABMaga = { git="https://github.com/krABMaga/krABMaga.git" }
krABMaga = { path="path/to/krABMaga"}
Architecture§
Agents§
The krABMaga framework defines a trait Agent
that can be implemented on a struct to define Agent
specific functionalities,
mainly the step
method which specifies how the agent behaves for each simulation step, and the get_id
method,
to uniquely identify an agent. There are also other methods, with default implementation, to improve agent control:
is_stopped
notify the scheduler if a specific agent should be removed or not, based on some condition.before_step
andafter_step
to implement some operations before/after a step.
The krABMaga framework allow multi-agent implementations: you can define multiple 'Agent' that implement the trait, and Wolf, Sheep & Grass is the main example of this feature.
Simulation state§
The simulation state can be considered as the single source of truth of the simulation, where data resides and is updated.
Like Agent
, krABMaga exposes a State
trait to let the user mark a particular structure as a simulation state, along with
exposing an update
method to define logic to execute once for each simulation step. The simulation state is the perfect
structure to put field definitions on (such as 2D continuous fields, grids and so on). An important effect of the state being
the single source of truth forces agents to update (and most importantly read) their own location by interacting with the
state, even though they can store their own location locally in the agent structure too. Although, to be sure one is interacting
with the latest computed data, it is considered a good practice to update both an agent own location field and its copy on the
state structure.
Schedule§
The simulation timeline is controlled by a Schedule structure that takes care of notifying all the scheduled agents, and the simulation state that a step has been taken. For this reason, agents should be scheduled so that they can be notified when a step has been taken. The scheduler works as a priority queue, where the agents are sorted according to their scheduled time and a priority value - an integer. The simulation time - a real value - starts from the scheduling time of the first agent. The schedule structure exposed by the krABMaga framework provides two methods to do so:
-
schedule_once
to insert an agent in the schedule for a specific simulation step. The scheduling time and the priority are given as parameters. The priority is used to sort all agents within the same simulation time. -
schedule_repeating
which acts like schedule once, with the difference that the agent will be scheduled for all subsequent simulation steps.
The schedule provides the step
method which allows executing one simulation step. In this way, the programmer can
easily design his/her simulation by looping for a certain number of step or for a given amount of CPU time.
Data structures§
The currently implemented structures are:
-
Field2D
, a sparse matrix structure modelling agent interactions on a 2D real space with coordinates represented by 2D f32 tuples (Real2D
). -
Grid2D
, a discrete field representing agents locations as 2D i32 tuples (Int2D
). This structure keeps two copies of a DBDashMap in sync, one the inverse of the other, to allow constant time access both by key (agent) and by value (position). There are two kind of Grid based on density,SparseGrid2D
andDenseGrid2D
. -
NumberGrid2D
, a simpler version of theGrid2D
to use with simpler values. This is useful to represent simulation spaces covered by a simple entity that can be represented with a non-agent structure. This data structure can be used with any structure that can be cloned, most notably simple primitive values such as f32s. As the previous grid, there are two implementations:SparseNumberGrid2D
andDenseNumberGrid2D
. -
Network
andHNetwork
to connect any kind of nodes usingEdge
/HEdge
. WithNetwork
you can define both directed and undirected graphs and connect a couple of nodes with an edge with label and/or weight.HNetwork
is a generalization of aNetwork
to represent hypergraph. In this case,HEdge
is anHashSet
of nodes. With this fields you can reproduce any kind of graph or network, such as for our exampleVirus on a Network
.
Support conference paper§
If you find this code useful in your research, please consider citing:
@ARTICLE{AntelmiASIASIM2019,
author={Antelmi, A. and Cordasco, G. and D’Auria, M. and De Vinco, D. and Negro, A. and Spagnuolo, C.},
title={On Evaluating Rust as a Programming Language for the Future of Massive Agent-Based Simulations},
journal={Communications in Computer and Information Science},
note={Conference of 19th Asia Simulation Conference, AsiaSim 2019 ; Conference Date: 30 October 2019 Through 1 November 2019; Conference Code:233729},
year={2019},
volume={1094},
pages={15-28},
doi={10.1007/978-981-15-1078-6_2},
issn={18650929},
isbn={9789811510779},
}