This blog post draws heavily on the excellent SysMIC course I completed during my PhD.
Agent based models (ABM) are one of a class of computational models for simulating the actions and interactions of autonomous agents (both individual or collective entities such as organizations or groups). The goal of ABM is to search for explanatory insight into the collective behavior of agents obeying simple rules, typically in natural systems. There are many ways to get hooked on ABM, for me I found the Game of Life intriguing (there are many examples from biological, ecological and socioeconomical systems).
This blog post is interested in how from simple rules complexity can emerge.
Conway’s Game of Life
Life (or the Game of Life) was introduced by the mathematician John Horton Conway in 1970. Though originally introduced to demonstrate interesting mathematical behaviour, we can consider it as a simple model for how cells interact. In this model time is discrete and represents generations. The cells lie on a rectangular grid. At each time step there are a set of rules that determine whether a cell lives or dies depending on the number of surrounding cells present. There is also the possibility that cells are `born’.
We provide a set of rules and conditions that leads to changes in the state of a variable. The changes are done in discrete steps and the variables only assume a finite number of discrete states. The simplest case is that a variable can be either “off” or “on” (0 or 1), i.e. a two-state model.
Before we proceed to give the rules of Life and a R implementation you should investigate it for yourself. The rules all depend on the eight nearest-neighbours of a cell.
- Go to the interactive Life game at http://www.julianpulgarin.com/canvaslife/
- Create some initial live cells by clicking on cells in the grid (black cells indicate cells that are alive).
- Click on Next Generation to see what happens at the next timestep.
- Turn the speed down to around 30. Then click on Start Life and Stop Life to start and stop the simulation.
- Experiment with different initial configurations and examine how the system evolves.
A R implementation of Life
The three rules of life are:
- a cell dies if it has less than two or more than three nearest neighbours. This reflects under population (Allee type effect) and over population respectively;
- a cell remains alive if it has two or three nearest neighbours;
- a cell is born in an empty grid space if it has three nearest neighbours.
Don’t reinvent the wheel
A quick Google search using the search term “cran package game of life” identified the
simecol package as being potentially useful for exploring this problem (it is also useful practice to think about how you might code this problem yourself - look on Github for other examples).
A nice feature of
simecol that helps with its reproducibility and inspired some of my own package design is the construction of “all-in-one” model objects. That is, everything that defines one particular model, equations and data are stored together in one
simObj (spoken: sim-Object). This package also holds simplicity over efficiency in its design principles as its target users (ecologists) often have limited programming experience.
This is facilitated by each simulation model being implemented as a S4 object (superclass simObj) with a number of customisable slots (see
This simplicity is evident when looking at the default code for Conway’s Game of Life shown above. The internal function
eightneighbours returns the sum of the eight neighbours of a cell within a matrix. Look at the matrix
m1 and the output of
eightneighbours when we pass it
m1 (as the argument
init which normally defaults as random). If our 3 by 3 grid were subject to rules of life (refer to them again above) what would
m2 look like in the next generation?
We can use
heatmap visualise the matrix (this had issues compiling so we opted for loading the
Matrix package and using the
(The complexity in
conway is further hidden from the user by calling the
solver = "iteration", pointing towards another function in the
desolve package (this package also contains General Solvers for Initial Value Problems of Ordinary Differential Equations)).
Let’s check what happens to our Block described above in
m1 (note how the cells appear to be wider (x) than they are tall (y)).
A strong and stable cellular formation that will persist. Re-read the rules to check you can see why and also extend the run of the simulation by changing how long the simulation runs for using
times(conway) <- 1:10. These are known as still-lifes. Can you think of another four cell organism that will create a still-life?
We can access the underlying data and check by summing each matrix what happens to the population; is the block stable?
We can visualise how simple rules can give rise to complexity (The Blind Watchmaker); like stumbling upon a pocket-watch found on a beach.
Let’s explore a few more interesting examples by specifying the starting cells that are alive. We create initial life by assigning those cells in a finite grid with values of one to be alive and zero if not. It is very difficult to predict what will happen and how long life will persist for in the grid making this a popular mathematical curio.
Spontaneous appeared Spaceships out of Random Dust
Run this code after uncommenting
glider (fly my pretty).
Try out other gliders and spaceships.
Back to reality
In this part we will adapt the original life program to include some more realistic cellular behaviours and thus build more interesting agent based models from a biological point of view. A simple way to do this is to alter the values for the number of nearest neighbours affecting cell births and deaths.
We can assume that our bacteria are growing in a Petri dish and multiply asexually (no partners required). Each bacterium can grow as long as it is not completely surrounded. The bacteria form a biofilm that helps with their survival, a lonely bacterium will perish.
I wonder what caused the plateau between thirteen and fifteen? Appears to be localised to the bottom of the Petri dish where the bacteria are wiped out from overcrowding. This is probably due to edge effects of the Petri dish container and the off-centre start position of the first bacterium shown below.
Our new rules allow the cells to reproduce and fill their container (given enough time) but they are constrained from creating a green square by the rule that says being totally surrounded casuses death.
We leave our Petri dish out next to a radiation source. The Petri dish is randomly struck by ionising radiation hitting some of our bacteria. We can use the matrix format of our simulated colony to easily simulate the effect of this event through matrix multiplication.
Ever since its publication, Conway’s Game of Life has attracted much interest, because of the surprising ways in which the patterns can evolve. Life provides an example of emergence and self-organization. It is interesting for computer scientists, physicists, biologists, biochemists, economists, mathematicians, philosophers, generative scientists and others to observe the way that complex patterns can emerge from the implementation of very simple rules. The game can also serve as a didactic analogy, used to convey the somewhat counter-intuitive notion that “design” and “organization” can spontaneously emerge in the absence of a designer. - Wikipedia