CppyABM is a free open-source header-only library that enables agent-based modeling both C++ and Python. The model development follows similar semantics and style in both languages. Therefore, a model developed in one languages can be conveniently transferred to another. In addition, CppyABM provides essential binding tools to specifically expose certain parts of a model written in C++ for further development in Python. This enables users to take the advantage of both languages simultaneously.
CppyABM provides three base classes of Env, Agent, and Patch for agent-based modeling. These classes can be inherited and extended based on specific simulation requirements. Agent is designed to simulate moving objects; Patch is for non-moving objects; and Env stores and coordinates Agent and Patch objects. Patch object can accomodate agents and heteregenious quantities within the simulation domain. There is a three-way connections between Env, Agent, and Patch. Env has stored pointers to Agent and Patch; Patch has pointers to the residing Agent as well as Env object; and agent has pointers to host Patch and Env object. This three-way connection enables full information retreival among the entire simulation entities. Both Agent and Patch require an input argument of Env for initialization. Also, Agent requires an identity variable termed Agent::class_name to enable multi-agent modeling; and Patch requires a MESH_ITEM object to gather three pieces of information, MESH_ITEM::index, MESH_ITEM::coords, and MESH_ITEM::neighbors_indices. There are few conventions that need further explanation to define an environment. Since Python requires object ownership, any object shared between C++ and Python ends, i.e. Patch and Agent objects, needs to be stored in Python end and referenced as pointers in C++ end. To satisfy this requirement, two template functions of Env::generate_agent and Env::generate_patch are provided to manage the generation and storage of agents and patches. These functions need to be customized for each model (see example). A repository variable needs to be defined within Python to store created objects. Simultaneously, the objects need to be added to Env::agents and Env::patches which are the standard containers defined within C++. Using these functions, the defined agents and patches can be accessed in both C++ and Python without further measure (see example).
Using pip manager:
pip install --upgrade cppyabm
Or, download the package and in the root folder, command:
python3 setup.py install
The library can be also installed solely for C++ development using,
Once installed, the library can be linked using Cmake as,
The library can be also locally linked without installation by providing the include
directory located in the root folder to the project,
To automatically clone CppyABM and link against the project,
For a showcase, see example.
In order to create a mixed model using both languages of C++ and Python, in addition to CppyABM, pybind11 needs to be installed. It can be either seperately installed according to the instruction given on pybind11-installation, or can be included in a project using Cmake.
The latter can be also achieved by using,
For a showcase, see example.
The model development in C++ is based on template programing to keep the internal connections between different class objects valid for the derived models. The primary layout of an agent-based model in C++ is,
For the above layout, two generator functions are,
For a complete example in C++, check out Cpp example.
The basic layout of an agent-based model in Python is,
Within Python, the generator functions require an additional step of storing the created objects in the local repositories. Also, the repositories needs to be updated to remove inactive agents. For a complete example in Python, check out Py example.
A model writen in C++ can be further extended within Python by the creation of bindings. Generally, there are two types of binding approach; exposure: to expose certain functionality already written in C++ code to Python; extention: to bind a functionality that needs to be (further) implemented in Python. We currently use pybind11 to generate Python bindings. By having the derived classes of myEnv
, myAgent
, and myPatch
, the binding template looks like,
where module_name
is the Python module created for binding. The template class bind_tools::Bind
is the main binding tool. It receives the derived classes as template arguments together with the extension schemes (prefixed tram
). It also receives m
together with the binding names used for the derived classes ("myEnv","myAgent","myPatch"
). m
is a py::module
object created automatically by pybind11. The exposure schemes are trampoline classes introduced in pybind11. CppyABM provides three trampoline classes of tramEnv
,tramAgent
,tramPatch
that can be inherited in order to declare any extention to the compiler (see Extention). For the exposure purposes, these classes can be directly passed to the bind_tools::Bind
without modification,
The bind_tools::Bind
automatically binds the class members and functions of the base classes, i.e. Env
,Agent
, and Patch
, as the members of the derived classes. However, the specific attributes of the derived class needs to be bind in a seperate step. For that, bind_tools::Bind
provides three functions of get_env
, get_agent
and get_patch
to have access to the exposed classes in order to attach further class members. Two pybind11 functions of def
and def_readwrite
can be used to bind class functions and members, respectively. For example, assuming that myEnv
has a function named myEnvFunc
, and myAgent
has a member myAgentMem
, the following code will expose these class attibutes,
For the extention purposes, the base classes of bind_tools::tramEnv, bind_tools::tramAgent, bind_tools::tramPatch can be inherited and extended prior to a call to bind_tools::Bind
. We use pybind11 semantics for the creation of trampoline. Assuming that the class function of myEnvFunc
belonging to myEnv
needs to be overwritten within Python, the following trampoline can be defined,
Once the specialized trampoline is defined,
By default, pybind11 converts the content of the variables based on STL containers. This prevents pass-by-reference and therefore any change made to the variable within Python is not reflected within C++. To prevent this, the STL-based variables needs to be exposed opaque. Within CppyABM, two variables of agents
and patches
as the default containers are based on STL. Therefore, prior to binding process, the following functions need to be executed,
To see an example combining all steps, see binding example
We use Cmake for the model compilation and generation of Python binding. pybind11_add_module
provided by pybind11 takes care of a Python module creation for the given set of C++ files. See binding example for an example.
We use RTvisualize for real-time visualization of the agent-based modeling. The realization of agents in 2D and 3D simulations can be done by using Scatter plot 2D and Scatter plot 3D (see here). The heteregenous distribution of Patch quantities within the simulation domain can be monitored used Map plot. And the evolution of a variable in the course of simulation can be monitored using Line plots. An example can be found on here.
In order to demonstrate the use case of CppyABM, we design a computer model of the biological tissue growth in response to injury. For description of the problem, see the article. Implementtion files of the examples together with Cmake files can be found on here.
This project is licensed under the MIT License - see the LICENSE.md file for details
Familiarity with pybind11 is helpful during the Python binding process.
In case of encountering a problem, pls report it as an issue or contant the author (jalil) .nou risa@ gmai l.com