Goal. Reproduce a Moran process by hand so the birth-death dynamics and fixation are felt before they are formalised. This activity is deliberately longer than the usual 20 minutes.
The deck. There is a write-on deck at /decks/moran-process/main.pdf: the Hawk-Dove payoffs printed, the birth-death chain with its transition probabilities blank, and tables for the fitnesses and the selection probabilities.
Use moran process form and have students play in pairs.
Also requires use of dice, allowing for multiples of 4 and 6. For example:
Virtual modification: use breakout rooms of 4. For dice, show how to use the
Python random library.
Explain that we will aim to reproduce a Moran process with \(n=3\).

We will do this with the Hawk–Dove game:
Recall, this corresponds to sharing of 4 resources:
Give students 5 minutes to write out the fitnesses of each type in each possible situation.
Confirm:
| \(f(\text{hawk})\) | \(f(\text{dove})\) | |
|---|---|---|
| 1 hawk, 2 doves | \(0\times0 + 2\times3 = 6\) | \(1\times1 + 1\times2 = 3\) |
| 2 hawks, 1 dove | \(1\times0 + 1\times3 = 3\) | \(2\times1 + 0\times2 = 2\) |
Give students 5 minutes to write out the probabilities of selection of each type in each possible situation.
Confirm:
| Select | Selection: birth | Selection: death | |
|---|---|---|---|
| 1 hawk, 2 doves | hawk | \(\frac{6}{6 + 2\times3}\) | \(\frac{1}{3}\) |
| 1 hawk, 2 doves | dove | \(\frac{2\times3}{6 + 2\times3}\) | \(\frac{2}{3}\) |
| 2 hawks, 1 dove | hawk | \(\frac{2\times3}{2\times3 + 2}\) | \(\frac{2}{3}\) |
| 2 hawks, 1 dove | dove | \(\frac{2}{2\times3 + 2}\) | \(\frac{1}{3}\) |
Let students simulate.
Count from groups to obtain mean fixation rate of a hawk.
Show the following code that allows us to simulate the simulation undertaken by the students (this is not the same code as in the notes):
import collections
import matplotlib.pyplot as plt
import numpy as np
import tqdm
def roll_n_sided_dice(n=6):
"""Roll a dice with n sides."""
return np.random.randint(1, n + 1)
class MoranProcess:
"""
A class for a Moran process with a population of size n=3 using the
standard hawk-dove game:
A = [[0, 3],
[1, 2]]
Note that this is a simulation corresponding to an in-class activity
where students roll dice.
"""
def __init__(self, number_of_hawks=1, seed=None):
if seed is not None:
np.random.seed(seed)
self.number_of_hawks = number_of_hawks
self.number_of_doves = 3 - number_of_hawks
self.dice_and_values_for_hawk_birth = {1: (6, {1, 2, 3}), 2: (4, {1, 2, 3})}
self.dice_and_values_for_hawk_death = {1: (6, {1, 2}), 2: (6, {1, 2, 3, 4})}
self.history = [(self.number_of_hawks, self.number_of_doves)]
def step(self):
"""Select a hawk or a dove for birth and death, then update."""
birth_dice, birth_values = self.dice_and_values_for_hawk_birth[self.number_of_hawks]
death_dice, death_values = self.dice_and_values_for_hawk_death[self.number_of_hawks]
select_hawk_for_birth = self.roll_dice_for_selection(dice=birth_dice, values=birth_values)
select_hawk_for_death = self.roll_dice_for_selection(dice=death_dice, values=death_values)
if select_hawk_for_birth:
self.number_of_hawks += 1
else:
self.number_of_doves += 1
if select_hawk_for_death:
self.number_of_hawks -= 1
else:
self.number_of_doves -= 1
self.history.append((self.number_of_hawks, self.number_of_doves))
def roll_dice_for_selection(self, dice, values):
"""Return True if the roll is in the target set."""
return roll_n_sided_dice(n=dice) in values
def simulate(self):
"""Run the simulation until the number of hawks is 0 or 3."""
while self.number_of_hawks in [1, 2]:
self.step()
return self.number_of_hawks
def __len__(self):
return len(self.history)
This carries out the simulations:
repetitions = 10 ** 5
end_states = []
path_lengths = []
for seed in range(repetitions):
mp = MoranProcess(seed=seed)
end_states.append(mp.simulate())
path_lengths.append(len(mp))
counts = collections.Counter(end_states)
counts[3] / repetitions
# ≈ 0.54666
Discuss obtaining theoretic probabilities of changing state:
Now work through the notes, culminating in the proof of the theorem for the absorption probabilities of a birth–death process.
Discuss and use code from the chapter to show the fixation with the hawk–dove game:
a = np.array([[0, 3], [1, 2]])
Calculate theoretic value using the formula from the theorem:
This gives (for \(n=3\)):
| \(i=1\) | \(i=2\) | |
|---|---|---|
| \(f_{1i}\) | 3 | 3/2 |
| \(f_{2i}\) | 3/2 | 1 |
| \(\gamma_i\) | 1/2 | 2/3 |
Thus:
Work through the Moran Process chapter.
Discussion Point: After the definition of the moran process, ask how this differs from our example?
Discussion Point: After the definition of fixation probability, ask what the fixation probability of a hawk is based on our simulation?
Discussion Point: After the theoretic fixation in two types ask how this could be used for our example? Leave this as an exercise.
Everything below is already derived in the activity above; this is the same material in the order the deck asks for it.
Fitnesses. With one hawk and two doves, \(f(\text{hawk}) = 6\) and \(f(\text{dove}) = 3\). With two hawks and one dove, \(f(\text{hawk}) = 3\) and \(f(\text{dove}) = 2\). So the hawk is fitter when hawks are rare and when they are common, but by a much smaller margin once they are common.
Selection. Birth is proportional to the total fitness of each type; death is uniform, so it is proportional to how many of that type there are.
| State | Born a hawk | Dies a hawk |
|---|---|---|
| 1 hawk, 2 doves | \(6/12 = 1/2\) | \(1/3\) |
| 2 hawks, 1 dove | \(6/8 = 3/4\) | \(2/3\) |
Transitions. The count only changes when the type born differs from the type that dies:
The remaining probability in each state is the chance of drawing the same type for birth and death, which leaves the state unchanged.
Fixation. With \(\gamma_i = p_{i,i-1}/p_{i,i+1}\) we get \(\gamma_1 = 1/2\) and \(\gamma_2 = 2/3\), so
Simulating the students' dice gives about \(0.547\), so a class of twenty pairs should land somewhere near eleven hawk fixations out of twenty. That spread is worth naming: with twenty runs the standard error is about \(0.11\), so anything from roughly 8 to 14 is consistent with the theory.
The activity above is written up as a marked exam question: Question 1 (the in-class activity) on the Moran Process page, with a full worked solution. Closing the loop here is the step that helps students who find exams hard: work through that question together, or set it as the immediate follow-up, so they see the game they just played turned into a full-mark answer.
General email templates to send before and after this class. Fill in the bracketed placeholders before sending.
Hi all,
A reminder that our next Game Theory class covers Moran Processes.
All of the course materials, including the relevant chapter, are available
at https://vknight.org/gt/. It is worth skimming the chapter beforehand.
See you in class,
Vince
Dear all,
Thanks for your work in today's class on Moran Processes.
A recording is available here [RECORDING LINK] and on Learning Central.
All class resources are available at https://vknight.org/gt/.
Thanks,
Vince