Overview

This section aims to provide a rough overview over the main classes and functions of agentpy and how they are meant to be used. For a more detailed description of each element, please refer to the API Reference. Throughout this documentation, agentpy is imported as follows:

import agentpy as ap

Creating models

The basic framework for agent-based models consists of three levels:

  1. Model, which contains agents, environments, parameters, & procedures

  2. Environment, Grid, and Network, which contain agents

  3. Agent, the basic building blocks of the model

All of these classes are designed to be customized through the creation of sub-classes with their own variables and methods. A custom agent type could be defined as follows:

class MyAgentType(ap.Agent):

    def setup(self):
        # Initialize an attribute with a parameter
        self.my_attribute = self.p.my_parameter

    def agent_method(self):
        # Define custom actions here
        pass

The method Agent.setup() is meant to be overwritten and will be called after an agents’ creation. All variables of an agents should be initialized in this method. Other methods can represent actions that the agent will be able to take during a simulation.

We can further see that the agent comes with a built-in attribute p that allows it to access the models’ parameters. All model objects (i.e. agents, environments, and the model itself) are equipped with such properties to access different parts of the model:

  • model returns the model instance

  • model.t returns the model’s time-step

  • id returns a unique identifier number for each object

  • p returns an AttrDict of the models’ parameters

  • envs returns an EnvList of the objects’ environments

  • agents (not for agents) returns an AgentList of the objects’ agents

  • log returns a dict of the objects’ recorded variables

Using the new agent type defined above, here is how a basic model could look like:

class MyModel(ap.Model):

    def setup(self):
        """ Called at the start of the simulation """
        self.add_agents(self.p.agents, MyAgentType)  # Add new agents

    def step(self):
        """ Called at every simulation step """
        self.agents.agent_method()  # Call a method for every agent

    def update(self):
        """ Called after setup as well as after each step """
        self.agents.record('my_attribute')  # Record a dynamic variable

    def end(self):
        """ Called at the end of the simulation """
        self.measure('my_measure', 1)  # Record an evaluation measure

This custom model is defined by four special methods that will be used automatically during different parts of a simulation. If you want to see a basic model like this in action, take a look at the Wealth transfer demonstration in the Model Library.

Using agents

Agentpy comes with various tools to create, manipulate, and delete agents. The method Model.add_agents() can be used to initialize new agents. A list of all agents in a model can be accessed through Model.agents. Lists of agents are returned as an AgentList, which provides special features to access and manipulate the whole group of agents.

For example, when the model defined above calls self.agents.agent_method(), it will call the method MyAgentType.agent_method() for every agent in the model. Similar commands can be used to set and access variables, or select subsets of agents with boolean operators. The following command, for example, would select all agents with an id above one:

self.agents.select(self.agents.id > 1)

Further examples can be found in the AgentList reference or the Virus spread model.

Using environments

Environments can contain agents just like the main model, and are useful if one wants to regard particular topologies for interaction or multiple environments that can hold seperate populations of agents. Agents can be moved between environments with the methods Agent.enter() and Agent.exit().

New environments can be created with Model.add_env(). Similar to agents, the attribute envs returns an EnvList with special features to deal with groups of environments. There are three different types of environments:

  • Environment, which simply contain agents without any topology.

  • Network, in which agents can be connected via a networkx graph.

  • Grid, in which agents occupy a position on a x-dimensional space.

Applied examples of networks can be found in the demonstration models Virus spread and Button network, while a spatial grid is used in Forest fire.

Recording data

As can be seen in the model defined above, there are two main types of data in agentpy. The first are dynamic variables, which can be stored for each object (agent, environment, or model) and time-step. They are useful to look at the dynamics of individual or aggregate objects over time and can be recorded by calling the method record() for the respective object.

The other type of recordable data are evaluation measures. These, in contrast, can be stored only for the model as a whole and only once per run. They are useful as summary statistics that can be compared over multiple runs, and can be recorded with the method Model.measure().

Running a simulation

To perform a simulation, we have to initialize a new instance of our model type with a dictionary of parameters, after which we use the function Model.run(). This will return a DataDict with recorded data from the simulation. A simple run could be prepared and executed as follows:

parameters = {'my_parameter':42,
              'agents':10,
              'steps':10, }

model = MyModel(parameters)
results = model.run()

The procedure of a simulation is as follows:

  1. The model initializes with the time-step Model.t = 0.

  2. Model.setup() and Model.update() are called.

  3. The model’s time-step is increased by 1.

  4. Model.step() and Model.update() are called.

  5. Step 2 and 3 are repeated until the simulation is stopped.

  6. Model.end() is called.

The simulation of a model can be stopped by one of the following three ways:

  1. Calling the Model.stop() during the simulation.

  2. Reaching the time-limit, which be defined as follows:

    • Defining steps in the paramater dictionary.

    • Passing steps as an argument to Model.run().

Multi-run experiments

The class Experiment can be used to run a model multiple times with repeated iterations, varied parameters, and distinct scenarios. To prepare a sample of parameters for an experiment, one can use one of the sampling functions sample(), sample_saltelli(), or sample_discrete(). Here is an example of an experiment with the model defined above:

parameter_ranges = {'my_parameter': 42,
                    'agents': (10, 20, int),
                    'steps': (10, 20, int)}

sample = ap.sample(parameter_ranges, n=5)

exp = ap.Experiment(MyModel, sample, iterations=2,
                    scenarios=('sc1','sc2'))

results = exp.run()

In this experiment, we use a sample where one parameter is kept fixed while the other two are varied 5 times from 10 to 20 and set to integer. Every possible combination is repeated 2 times, which results in 50 runs. Each run further has one result for each of the two scenarios sc1 and sc2. For more applied examples of experiments, check out the demonstration models Virus spread, Button network, and Forest fire.

Output and analysis

Both Model and Experiment can be used to run a simulation, which will return a DataDict with output data. The output from the experiment defined above looks as follows:

>>> results
DataDict {
'log': Dictionary with 5 keys
'parameters':
    'fixed': Dictionary with 1 key
    'varied': DataFrame with 2 variables and 25 rows
'measures': DataFrame with 1 variable and 50 rows
'variables':
    'MyAgentType': DataFrame with 1 variable and 10500 rows
}

The output can contain the following categories of data:

  • log holds meta-data about the model and simulation performance.

  • parameters holds the parameter values that have been used for the experiment.

  • variables holds dynamic variables, which can be recorded at multiple time-steps.

  • measures holds evaluation measures that are recoreded only once per simulation.

This data can be stored with DataDict.save() and load(). DataDict.arrange() can further be used to generate a specific dataframe for analysis or visualization. All data is given in a pandas.DataFrame and formatted as long-form data, which makes it compatible to use with statistical packages like seaborn. Agentpy further provides the following functions for analysis:

To see applied examples of these functions, please check out the Model Library.