Expand description
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 simulation
- 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 simulation
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 typical krABMaga simulation struct:
src
: main folder with code. It containsmain.rs
file and two directories for model and visualization 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 = 0.1.*
[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 component 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 by 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 dependency 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 f64 tuples (Real2D
). -
Grid2D
, a discrete field representing agents locations as 2D i64 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 f64s. 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},
}
Modules
- Main module, with structs for Agents, Fields and Schedule
Macros
- Create new plot for your simulation. Call this macro one time for each plot you want to create. We suggest to call this macro in the
init
function of your simulation. - Macro to perform bayesian optimization. You should use this macro to optimize your simulation, but can be used to optimize any function.
- Run a simulation two times with same parameter. Compares initial agents, their behavior for each step and the final state to determine whether a model is reproducible or not.
- Add a description to your simulation. You can show a popup (pressing
s
) with this message. - Macro to optimizes the simulation parameters by adopting an evolutionary searching strategy. Specifically, krABMaga provides a genetic algorithm-based approach. The macro will generate a dataframe with the results of the exploration. The dataframe can be saved in a csv file.
- Macro to perform a model exploration. The macro will generate a dataframe with the results of the exploration. The dataframe can be saved in a csv file.
- Macro to perform distributed model exploration using basic parameter sweeping based on MPI
- Macro to perform sequential model exploration using a genetic algorithm on AWS
- Macro to perform distributed model exploration using a genetic algorithm based on MPI
- Macro to perform sequential model exploration using a genetic algorithm.
- Macro to perform sequential model exploration using a genetic algorithm.
- Macro to to perform parallel model exploration using basic parameters sweeping
- Macro to to perform sequential model exploration using basic parameters sweeping
- Generate parameter values using a Uniform Distribution. Use it to generate a list of values for parameter sweeping.
- Load parameters from a csv.
- Add a log to the simulation logger.
- Add a point to a series of an existing plot. Crete the series at the first call. Can’t add a point to a plot that doesn’t exist, use
addplot!()
instead. - Macro to perform model exploration using the random search algorithm. Try to find the best model by randomly sampling the parameter space. The goal is to minimize the cost function.
- Run simulation directly using this macro. By default,
Simulation Terminal
is used - Run simulations using this macro. Not based on
Simulation Terminal
. Return execution times of each repetition.
Enums
- Enum to represent the different types of computing backends that can be used to explore the model. By default, the model exploration is sequential.
- Model Exploration modes
- Options of
simulate_old!
macro to specify how to display results. - Available log types to use for
Simulation Terminal
log mechanism. Change color of logs in the terminal. #[derive(Copy, Clone, Debug)]
Functions
- Create a csv file with the experiment results.