Creating a model with Assasim
This article can be seen as a tutorial to develop an agent-based simulation using assasim.
Prerequisite: Having installed assasim
Start by editing the
simulation-dev.sh script to provide the editor you want to use in the rest of the tutorial in the
Overview of the developement steps:
- Definition of the agents and interactions (in terms of attributes)
- First step of precompilation which generates the tools to implement behaviors
- Implementation of behaviors by the user
- Second step of precompilation which generates the compilable code
- Compilation of the model
To begin the development, execute the following command:
./simulation-dev.sh my_model.hpp where
my_model.hpp is the name of the model you want to create.
In the following, an authorized type is defined by:
- int, float, char, bool and variants (e.g. uint64_t)
- A c struct (i.e. a struct with no methods, no inheritance and no access specifier) with attributes of authorized type.
Warning: you should never use anonymous struct for an authorized type attribute. Always declare your structs using the C++ syntax:
Definition of the agents and interactions
A model is composed of two main objects: agents and interactions.
Interactions are messages that agents can use to exchange information, give orders etc. You can define an interaction by defining a class which inherites from class Interaction. There are a few restrictions for an interaction to be valid:
- all the attributes should be public, and of authorized type
- it should contain no method (except custom constructors).
Agents are the players in the simulation. An agent type is defined by a set of attributes which can be public, private or critical (explained below) and a Behavior method which is called for each instance of an agent type at each step of the simulation. For this step, you should only define the attributes of the agents.
An agent type is just a class which inherits from class Agent. There are a few restriction for an agent type to be valid:
- all the public attributes should be of authorized type
- private attributes can be of non-authorized type, but in that case you have to bear in mind that the initial value of the attribute is determined by the default constructor of the non-authorized type.
- you can also add a tag to a public variable (see example below) to make it critical. A critical value is replicated on all the machines and is updated only when it it changes. It can be useful if the attribute will be accessed a lot in one step, and if it does not change very often.
First step of precompilation
When you are done with defining the attributes of the interactions and agents, you can close your editor or press enter depending on the mode option you put in the script. It will trigger the first step of precompilation, generating the environment to implement behaviors of agents.
Implementation of behaviors
After the first step of precompilation, the script should have opened two files: your file defining the model that you created and a file “behaviors.cpp”. It is in the latter that you should implement the behavior function. Several syntax shortcuts are provided to handle messages and public attribute access.
You can use the syntaxe
id_ to get the id of the agent and there is a constant
T_type which gives the unique id of agent type T.
Public attribute request
You can get the value of public attribute A of agent of type T with id I with the following syntax:
Example: to get attribute money of agent of type Citizen with id 42
You can use this syntax anywhere in the methods of the agent type you consider, in conditions, expressions etc. Note that the id given in the  can be any valid expression, including variables.
Iterate over ids of existing agents
You can browse all ids of valid agents of type T with the following syntax:
Example: Make Citizen 0 display all the values of pos.x of the existing Citizens
If you want to send interactions to an other agent, you first should look at the generated complete constructor in the interaction. Then if you wish to send the interaction defined with the constructor M(a1,…,ak) to agent of type T with id I, you can use the following syntax:
Example: to send message Request(42,’a’,true) to agent of type Citizen with id 42
Now if you want to process the received messages of type M, you can use the following C++-11 syntax:
Example: iterate over the received Request and print the orders received
When you have finished implementing behaviors, you can close your editor or press enter depending on the mode option you put in the script. Then the compilable code is generated and the final code is compiled. If no error occurs, the executable can be found in directory
Running the program using the CLI
First you need to define an instanciation, i.e the initial state of the model. You need to specify the number of agent for each agent types and then you can give the default values of the attributes for each agent type, and even specify for each agent the value of its attributes. A prototype of instanciation file have been generated and is located in the directory
path/to/filename.hpp_step2/empty_instance.json. It contains some fields which need to be filled (marked by a “#”). You can copy it and fill it with the values you want. Once it is done, the simulation is ready be launched.
Using the CLI
You can find the sources for the CLI in the folder cli/ in the root directory of Assasim. See the installation guide to compile the program. Then you can launch the program with the following syntax:
./assasim-cli path/to/filename.hpp_build/assasim-simulation <number_of_masters>
Once you are in the CLI, you can set some general variables like the number of threads used or the number of steps executed at each generation run by the user. You can see the list of available commands using autocompletion and the command “help”.
Then you have to specify the instanciation file using the command
You can launch the simulation for a certain number of steps with
run <number> or you can launch it in background and then pause it at any time. When the simulation is paused, you can export the snapshot of the simulation into json or binary json. You can also convert a snapshot into an instanciation in order to restart your simulation later where you left it.
Finally, when you are done just use the command
exit and the simulation is properly killed.