Frequency-Dependent Selection: Coevolution
Frequency-dependent selection occurs when the fitness of a genotype depends on
its frequency in the population. Host-parasite or predator-prey interactions are
classical examples of negative frequency-dependent selection, leading to cyclical,
coevolutionary dynamics. These dynamics are often called "Red Queen" dynamics.
Below is a simulation of a simple host-parasite interaction, following a haploid
matching-allele model. Its dynamic is strongly dependent on initial genotype
frequencies (the four lines show the two host and two parasite genotype frequencies):
Stable coevolutionary dynamics are an artefact of purely deterministic models, however. Even when slightly perturbed, the coevolutionary dynamics will change dramatically:
Code
First plot
var data = [];
var generations = 400;
var host_frequencies = [0,0];
var parasite_frequencies = [0,0];
var sh = 0.2;
var sp = 0.5;
function initialize_frequencies() {
host_frequencies[0] = Math.random();
data.push([host_frequencies[0]]);
host_frequencies[1] = 1 - host_frequencies[0];
data.push([host_frequencies[1]]);
parasite_frequencies[0] = Math.random();
data.push([parasite_frequencies[0]]);
parasite_frequencies[1] = 1 - parasite_frequencies[0];
data.push([parasite_frequencies[1]]);
}
initialize_frequencies();
for (var i = 0; i < generations; i = i + 1) {
host_selection();
parasite_selection();
data[0].push(host_frequencies[0]);
data[1].push(host_frequencies[1]);
data[2].push(parasite_frequencies[0]);
data[3].push(parasite_frequencies[1]);
}
draw_line_chart(data,"Generation","p",[]);
function host_selection() {
var sum_host_frequencies = 0;
for (var i = 0; i < host_frequencies.length; i = i + 1) {
var current_host_fitness = 0;
for (var ii = 0; ii < parasite_frequencies.length; ii = ii + 1) {
current_host_fitness = current_host_fitness + get_host_fitness(i, ii);
}
host_frequencies[i] = host_frequencies[i] * current_host_fitness;
sum_host_frequencies = sum_host_frequencies + host_frequencies[i];
}
for (i = 0; i < host_frequencies.length; i = i + 1) {
host_frequencies[i] = host_frequencies[i] / sum_host_frequencies;
}
}
function get_host_fitness(i,ii){
return (i == ii ? 1-sh : 1) * parasite_frequencies[ii]
}
function parasite_selection() {
var sum_parasite_frequencies = 0;
for (var i = 0; i < parasite_frequencies.length; i = i + 1) {
var current_parasite_fitness = 0;
for (var ii = 0; ii < host_frequencies.length; ii = ii + 1) {
current_parasite_fitness = current_parasite_fitness + get_parasite_fitness(i, ii);
}
parasite_frequencies[i] = parasite_frequencies[i] * current_parasite_fitness;
sum_parasite_frequencies = sum_parasite_frequencies + parasite_frequencies[i];
}
for (i = 0; i < parasite_frequencies.length; i = i + 1) {
parasite_frequencies[i] = parasite_frequencies[i] / sum_parasite_frequencies;
}
}
function get_parasite_fitness(i,ii) {
return (i == ii ? 1 : 1-sp) * host_frequencies[ii]
}
Second plot
var data = [];
var generations = 2000;
var host_frequencies = [0,0];
var parasite_frequencies = [0,0];
var sh = 0.2;
var sp = 0.5;
function initialize_frequencies() {
host_frequencies[0] = Math.random();
data.push([host_frequencies[0]]);
host_frequencies[1] = 1 - host_frequencies[0];
data.push([host_frequencies[1]]);
parasite_frequencies[0] = Math.random();
data.push([parasite_frequencies[0]]);
parasite_frequencies[1] = 1 - parasite_frequencies[0];
data.push([parasite_frequencies[1]]);
}
initialize_frequencies();
for (var i = 0; i < generations; i = i + 1) {
host_selection();
parasite_selection();
data[0].push(host_frequencies[0]);
data[1].push(host_frequencies[1]);
data[2].push(parasite_frequencies[0]);
data[3].push(parasite_frequencies[1]);
}
draw_line_chart(data,"Generation","p",[]);
function host_selection() {
var sum_host_frequencies = 0;
for (var i = 0; i < host_frequencies.length; i = i + 1) {
var current_host_fitness = 0;
for (var ii = 0; ii < parasite_frequencies.length; ii = ii + 1) {
current_host_fitness = current_host_fitness + get_host_fitness(i, ii);
}
host_frequencies[i] = host_frequencies[i] * current_host_fitness;
host_frequencies[i] = host_frequencies[i] + Math.random() * 0.01;
sum_host_frequencies = sum_host_frequencies + host_frequencies[i];
}
for (i = 0; i < host_frequencies.length; i = i + 1) {
host_frequencies[i] = host_frequencies[i] / sum_host_frequencies;
}
}
function get_host_fitness(i,ii){
return (i == ii ? 1-sh : 1) * parasite_frequencies[ii]
}
function parasite_selection() {
var sum_parasite_frequencies = 0;
for (var i = 0; i < parasite_frequencies.length; i = i + 1) {
var current_parasite_fitness = 0;
for (var ii = 0; ii < host_frequencies.length; ii = ii + 1) {
current_parasite_fitness = current_parasite_fitness + get_parasite_fitness(i, ii);
}
parasite_frequencies[i] = parasite_frequencies[i] * current_parasite_fitness;
sum_parasite_frequencies = sum_parasite_frequencies + parasite_frequencies[i];
}
for (i = 0; i < parasite_frequencies.length; i = i + 1) {
parasite_frequencies[i] = parasite_frequencies[i] / sum_parasite_frequencies;
}
}
function get_parasite_fitness(i,ii) {
return (i == ii ? 1 : 1-sp) * host_frequencies[ii]
}
Note: the draw_line_chart function is built with D3.js
and can be found here.