The mesa library is very nice, and it should be faster and easier to implement models that a plain numpy implementation.
However, mesa is undergoing changes so many of the online examples are based on earlier versions of the library. This page is a collection of code segments that I used to build all examples covered in class and what I suggest you use for assignments. These are based on the latest version of the library (3.0.0b0).
Using a consistent style between models/applications means that it is easier to focus on the similarities between the applications and should result in faster development.
As we implement more complicated models and need more functionality I will add to this page.
However, this page is not intended to be a replacement for the mesa documentation so spend some time browsing that.
First load in the standard modules — I have broken this into three cells based on their general purpose
1 2 3 4 5 6 | |
Next load functions to build animations
1 2 | |
Finally install mesa using
1 | |
and load in mesa and verify the correct version is used
1 2 | |
You should get output '3.0.2' or '3.1.0.dev'.
Agent classWe need to create a class to represent the Agent. Depending on the application, I might called this class
Cell (for Game of Life model),
Tree (for fire model),
Person (for SIR models), etc., or I might be lazy and just call them Agent. In this page of code snippets I will always use name Agent.
The minimal code for Agent is
1 2 3 4 5 6 | |
Agent class with statesOften an agent can be in one of a number of predefined states, so take the Game of Life where the agent, Cell, is either DEAD or ALIVE. In this case our class definition starts with:
1 2 3 4 5 6 7 8 9 10 | |
Agent class with simultaneous updateIn some applications, such as the Game of Life, we want to update ALL agents at exactly the same time — in contrast to updating agents either in order (for the Traffic model) or at random.
To get the simultaneous update in mesa we have class
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | |
In this code, our agent has:
_next_step which stores the state that the agent will change to in the next step.compute_step which computes the value of _next_state, typically based on the agent's state and the state of its neighbours.step just update state using the value in _next_state.Then in the step function in the Model class we have
1 2 3 4 5 6 7 | |
where the first line updates the _next_state for all agents without changing state and once that is completed the second line updates the state for all agents.
Model classThe Model class stores the agents, controls how that are updated, and what data is recorded. Similar to the Agent class you can call this anything, so you could use
FireModel (for fire model),
SchellingModel (for the Schelling model), etc., but I tend to just use Model. In this page of code snippets I will always use name Model.
At a minimum the Model class has
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | |
Mesa comes with a nice visualisation and UI (for model parameter selection) but I had issues in getting it to work with Colab so we are going build our own using matplotllib.animation. We need to implement the following:
draw_model creates a graphical representation of the current state of the model and its agents.1 2 3 4 5 6 7 8 9 | |
mode.step) and displays the model (by calling draw_model)1 2 3 | |
Then to create an animation we:
Model with desired parameter values.matplotlib window using (or similar if multiple plots).1 2 | |
1 2 3 | |
DataCollector classSee mesa documentation for details.
If Model has a grid, we often need to loop over all locations in the grid, for example to place an agent at each location (think Cell in Game of Life or a Tree in Fire Model). This can be done from within a method of Model using
1 2 | |
or if not interested in the contents (say when in Model.__init__ and placing agents) we use
1 2 3 | |
To loop over all agents in the model use
1 2 | |
Within the Agent class, we often need to get a list of its neighbours — and then filter/count those alive, etc. The cleanest approach is to have a method which performs the task of getting the list of neighbours. For example, in the Game of Life we might have
1 2 3 4 5 6 | |