📚 The CoCalc Library - books, templates and other resources
License: OTHER
The Fitness landscape
A genotype is represented by a length-N array of 0s and 1.
The fitness landscape maps from each location in N-D space to a random fitness.
As an example, here's a 3-D landscape.
one_values
and zero_values
contain the fitness contributions of having a 1 or 0 at each element of the location array.
The fitness of a location is the mean of its fitness contributions.
fitness
evaluates the fitness of a location.
distance
computes the number of bit flips to get from one location to another.
It uses np.logical_xor
The agents
Here's the class that represents agents.
Each agent has a location, a reference to a FitnessLandscape, and a fitness.
The Simulator
The Simulator
class provides methods to run the simulations.
We'll use a few functions to create agents. If we want to start with identical agents:
Or agents at random locations:
Or one agent at each possible location:
make_all_agents
uses itertools.product
, which returns a generator that enumerates the Cartesian product of the set {0, 1}
with itself N
times, which is a fancy way to say that it enumerates all sequences of N
bits. Here's an example:
The distribution of fitness
Let's create a fitness landscape with an agent at each location and see what the distribution of fitness looks like.
plot_fitnesses
plots the CDF of fitness across the population.
Initially the distribution is approximately Gaussian, because it's the sum of 8 independent uniformly distributed variates. See the Central Limit Theorem.
After one time step, there's not much change.
After 100 time steps, we can see that the number of unique values has decreased.
Instruments
To measure these changes over the course of the simulations, we'll use Instrument objects.
The MeanFitness
instrument computes the mean fitness after each time step.
Here's mean fitness as a function of (simulated) time for a single run.
We can get a better sense of average behavior, and variation around the average, but plotting multiple runs.
agent_maker1
puts one agent at each location.
With no differential survival or reproduction, we get a random walk.
Differential survival
We can add differential survival by overriding choose_dead
With differential survival, mean fitness increases and then levels off.
We can add differential reproduction by overriding choose_replacements
With differential reproduction (but not survival), mean fitness increases and then levels off.
Exercise: What if you have both? Write a class called SimWithBoth
that uses the new versions of choose_dead
and choose_replacements
. Does mean fitness increase more quickly?
Number of different agents
Without mutation, we have no way to add diversity. The number of occupied locations goes down over time.
OccupiedLocations
is an instrument that counts the number of occupied locations.
Here's what that looks like with no differential survival or reproduction.
Exercise: What effect do differential survival and reproduction have on the number of occupied locations?
The model we have so far might explain changes in existing populations, but it doesn't explain increasing diversity or complexity.
Mutation
Mutation is one way of increasing, or at least maintaining, diversity.
Mutant
is a kind of agent that overrides copy
:
To test it out, I'll create an agent at a random location.
If we make 20 copies, we expect about one mutant.
agent_maker2
makes identical agents.
If we start with identical mutants, we still see increasing fitness.
And now the number of occupied locations increases, reaching a steady state at about 10.
In steady state, many agents are at the optimal location, and others are usually just a few mutations away. To quantify that, we can compute the mean distance between all pairs of agents.
The distance between two agents is the number of bit flips to get from one location to another.
Mean distance is initially 0, when all agents are identical. It increases as the population migrates toward the optimal location, then settles into a steady state around 1.5.
Changing landscape
One cause of speciation is a change in the landscape. Suppose a population in steady state in one landscape is transported to another landscape. After a period of migration, it would settle around the new equilibrium point, with a small mean distance between agents. The mean distance between the original agents and the migrants is generally much larger.
The following simulation runs 500 steps on one landscape, then switches to a different landscape and resumes the simulation.
After the switch to a new landscape, mean fitness drops briefly, then the population migrates to the new optimal location, which happens to be higher, in this example.
The number of occupied locations (sometimes) increases while the population is migrating.
And the mean distance (sometimes) increases until the population reaches the new steady state.
The mean distance between clusters is much bigger than the dispersion within clusters, so we can interpret the clusters as distinct species.
Exercise: When we change the landscape, the number of occupied locations and the mean distance usually increase, but the effect is not always big enough to be obvious. You might want to try out some different random seeds to see how general the effect is.