Systems and complexitySystems thinking and modelling

Modeling With Agents: Agent Geography [Systems thinking & modelling series]

This is part 68 of a series of articles featuring the book Beyond Connecting the Dots, Modeling for Meaningful Results.

One of the key strengths of Agent Based Modeling is that it allows us to study the geographic relationship among our agents. So if we are developing a disease model we do not have to assume that all the agents are perfectly mixed together like atoms in a gas (such as we generally would in System Dynamics). Instead, using Agent Based Modeling we can explicitly define the proximity of the different agents and study how this geography affects the spread of the disease.

In general when we talk about geography we mean spatial geography: the locations of people within a region in terms of their latitude and longitude (and sometimes their elevation). Insight Maker supports this kind of geography, but it also supports a second kind of geography: network geography. Insight Maker allows the specification of “connections” between agents. This leads to a new type of geography where you have centrally located agents (ones connected to many other agents) and agents far from the network’s center (those that are unconnected or just connected to a very few other agents).

Spatial geography and network geography
Figure 1. Spatial geography and network geography.

Both of these types of geographies can be useful in exploring important features of real-world systems. In the following sections, we will introduce their properties and show you how to use them in your own models.

Spatial Geography

In Insight Maker, each Agent Population can be given dimensions in terms of a width and a height. By default, agents are placed at a random location within this region. You can, however, choose a different placement method for the starting position of the agents. The following placement methods are available:

Random: The default. Agents are placed at random positions within the geometry specified for the agent population.

Grid: Agents are aligned in a grid within the population. When using this placement method, ensure that you have enough agents to complete the grid. You might need to experiment with increasing or decreasing the number of agents to make the grid fit perfectly for a given set of region dimensions.

Ellipse: Agents are arranged in a single ellipse within the region. If the region geometry is a square, then the agents will be arranged in a circle.

Network: Assuming network connections between agents have been specified, the agents will be arranged in an attempt to create a pleasing layout of the network structure.

Custom Function: Here you can specify a custom function to control the layout of the agents. This function will be called once for each agent in the population and should return a two-element vector where the first element is the x-coordinate of the agent, and the second element is the y-coordinate. The primitive Self in this function will refer to the agent that is being positioned.

Illustration of the four agent placement algorithms. From the top: random, grid, ellipse, and a custom function using: {2*Self.Index(), 50+50*sin(Self.Index())/10)}.
Figure 2. Illustration of the four agent placement algorithms. From the top: random, grid, ellipse, and a custom function using: {2*Self.Index(), 50+50*sin(Self.Index())/10)}.

Spatial Find Functions

When working with a spatially explicit model, a number of additional find functions are available. These allow you to obtain references to agents that match a given spatial criteria.

FindNearby() is a function that returns a vector of agents that are within a given proximity to a target agent. It takes three arguments: the agent population primitive, the agent target for which you want nearby neighbors, and a distance. All agents within the specified distance to the target agent will be returned as a vector.

It is useful now to introduce a concept that will be very helpful to you. When used in an Agent, Self always refers to the agent itself. If you have a primitive within an agent, Self can be used from that primitive to get a reference to the agent containing the primitive. So the following equation in an agent will return a vector of agents that are within 15 miles of the agent itself:

[Population].FindNearby(Self, {15 Miles})

Two other useful functions for finding agents in spatial relation to each other are FindNearest() and FindFurthest(). FindNearest returns the agent nearest to the target, while FindFurthest returns the agent that is furthest away from it. Each of these also supports an optional third argument determining how many nearby (or far away) agents to return (this optional argument defaults to one when omitted).

For example, the following equation finds the agent nearest to the current agent:

[Population].FindNearest(Self)

While this finds the three agents that are furthest from the current agent:

[Population].FindFurthest(Self, 3)

Movement Functions

You can also move agents to new locations during simulation. To do this, it is helpful to introduce a new primitive we have not yet discussed. This primitive is the Action primitive. Action primitives are designed to execute some action that changes the state of your model. For instance, they can be used to move agents or change the values of the primitives within an agent. An action is triggered in the same way a transition is triggered. Like a transition, there are three possible methods of triggering the action: timeout, probability, and condition.

For instance, we can use an action primitive in an agent and the Move() function to make agents move during the simulation. The Move function takes one argument: a vector containing the x- and y-distances to move the agent. Thus, we could place an action primitive in our agent and give it the following action property to make the agent move randomly over time1. The equation will move the agent a random distance between -0.5 and 0.5 units in the x-direction and a random distance between -0.5 and 0.5 units in the y-direction.

Self.Move({rand(), rand()-0.5)}

Another useful movement function is the MoveTowards() function. MoveTowards moves an agent toward (or away from) the location of another agent. MoveTowards takes two arguments: the target agent to move toward and how far to move toward that agent (with negative values indicating movement away). The following command would move an agent one meter closer to its nearest neighbor in the population.

Self.MoveTowards([Population].FindNearest(Self), {1 Meter})

Exercise 10-11
Write an equation to move an agent 2 meters toward the furthest healthy agent.

Answer available >

Interactive model: Agent Movement

A model illustrating the use of movement within agent based models can be found in Chapter 10 of Beyond Connecting the Dots. We adapt the previous disease model so that healthy agents flee from the nearest infected agent.

Network Geography

To create and remove connections between agents you can use the Connect() and Unconnect() functions. Both of these take two arguments: the agents that should be connected or disconnected. For example, to connect an agent to its nearest neighbor, you could use the following:

Self.Connect([Population].FindNearest(Self))

To disconnect an agent from its nearest neighbor (assuming they are connected), you would use:

Self.Unconnect([Population].FindNearest(Self))

To obtain a vector of connections to an agent, use the Connected() function:

Self.Connected()

Connections are not directed, so creating a connection from agent A to agent B is the same as creating a connection from agent B to agent A. Also, only one connection between a given pair of agents will exist at a time. So creating two connections between a given pair of agents will have the same effect as creating a single connection.

By default, no connections are created when a simulation is initially started. If you change the Network Structure configuration property of the agent population primitive, you can specify a function to create connections when the simulation is started. This function is called once for each pair of agents in the model. The agents are available in the function as the variables a and b. If the function evaluates to true, then the agents will start connected. If the function evaluates to false, the agents will not be initially connected.

You could use this function to, for instance, specify that 40% of agents will be directly connected to each other at the start of the simulation. The following equation would do that by generating a random true/false value with 40% probability of returning true each time it is called:

RandBoolean(0.4)

Next edition: Modeling With Agents: Multiline Equations.

Article sources: Beyond Connecting the Dots, Insight Maker. Reproduced by permission.

Notes:

  1. What we are implementing here is known as a “random walk” or Brownian motion. It is a commonly studied pattern of movement with wide applications in science.

Scott Fortmann-Roe and Gene Bellinger

Scott Fortmann-Roe, creator of Insight Maker, and Gene Bellinger, creator of SystemsWiki, have written the innovative interactive book "Beyond Connecting the Dots" to demystify systems thinking and modelling.

Related Articles

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Back to top button