Several subsequent models have explored ‘solutions’ to Rogers’ paradox. These involve relaxing the obviously unrealistic assumptions. One of these is that individuals in the model come in one of two fixed types: social learners (who always learn socially), and individual learners (who always learn individually). This is obviously unrealistic. Most organisms that can learn individually can also learn socially, and the two capacities likely rely on the same underlying mechanisms (e.g. associative learning, see e.g. Heyes (2012)).
Modelling critical social learners
To explore how a mixed learning strategy would compete with pure strategies (only social or only individual learning), Enquist, Eriksson, and Ghirlanda (2007) added another type of individual to Rogers’ model: a critical social learner. These individuals first try social learning, and if the result is unsatisfactory, they then try individual learning.
The following function modifies the rogers_model()
function from the last chapter to include critical learners. We need to change the code in a few places, but the modifications should be all easy to understand at this point. To start with, in the output tibble, we need to track the proportion of individual learners (before they were simply the individuals that were not social learners) and of the proportion of the individuals adopting the new strategy, critical social learning. We have now two more variables for this: p_IL
and p_CL
. Next, we need to add a learning routine for critical learners. This involves repeating the social learning code originally written for the social learners. We then apply the individual learning code to those critical learners who copied the incorrect behaviour, i.e. if their behaviour is different from E
(this makes them ‘unsatisfied’). To make it easier to follow, we now insert the fitness updates into the learning section. This is because only those critical learners who are unsatisfied will suffer the costs of individual learning. If we left it to afterwards, it’s easy to lose track of who is paying what fitness cost.
Reproduction and mutation are changed to account for the three learning strategies. We now need to get the relative fitness of social and individual learners, and then reproduce based on those fitnesses. Individuals left over become critical learners. We could calculate the relative fitness of critical learners, but it’s not really necessary given that the proportion of critical learners will always be 1 minus the proportion of social and individual learners. Similarly, mutation now needs to specify that individuals can mutate into either of the two other learning strategies. We assume this mutation is unbiased, and mutation is equally likely to result in the two other strategies. Notice the use of the function sample()
when we set the learning strategies of the new population. So far we used it for binary choices, now we are using it with three elements (c("individual", "social", "critical"
) and three probabilities (prob = c(fitness_IL, fitness_SL, 1 - (fitness_SL + fitness_IL))
).
library(tidyverse)
rogers_model2 <- function(N, t_max, r_max, w = 1, b = 0.5, c, s = 0, mu, p, u) {
# Check parameters to avoid negative fitnesses
if (b * (1 + c) > 1 || b * (1 + s) > 1) {
stop("Invalid parameter values: ensure b*(1+c) < 1 and b*(1+s) < 1")
}
# Create output tibble
output <- tibble(generation = rep(1:t_max, r_max),
run = as.factor(rep(1:r_max, each = t_max)),
p_SL = as.numeric(rep(NA, t_max * r_max)),
p_IL = as.numeric(rep(NA, t_max * r_max)),
p_CL = as.numeric(rep(NA, t_max * r_max)),
W = as.numeric(rep(NA, t_max * r_max)))
for (r in 1:r_max) {
# Create a population of individuals
population <- tibble(learning = rep("individual", N),
behaviour = rep(NA, N), fitness = rep(NA, N))
# Initialise the environment
E <- 0
for (t in 1:t_max) {
# Now we integrate fitnesses into the learning stage
population$fitness <- w
# 1. Social learning
if (sum(population$learning == "social") > 0) {
# Subtract cost b*s from fitness of social learners
population$fitness[population$learning == "social"] <-
population$fitness[population$learning == "social"] - b*s
# Update behaviour
population$behaviour[population$learning == "social"] <-
sample(previous_population$behaviour, sum(population$learning == "social"), replace = TRUE)
}
# 2. Individual learning
# Subtract cost b*c from fitness of individual learners
population$fitness[population$learning == "individual"] <-
population$fitness[population$learning == "individual"] - b*c
# Update behaviour
learn_correct <- sample(c(TRUE, FALSE), N, prob = c(p, 1 - p), replace = TRUE)
population$behaviour[learn_correct & population$learning == "individual"] <- E
population$behaviour[!learn_correct & population$learning == "individual"] <- E - 1
# 3. Critical social learning
if (sum(population$learning == "critical") > 0) {
# Subtract b*s from fitness of socially learning critical learners
population$fitness[population$learning == "critical"] <-
population$fitness[population$learning == "critical"] - b*s
# First critical learners socially learn
population$behaviour[population$learning == "critical"] <-
sample(previous_population$behaviour,
sum(population$learning == "critical"), replace = TRUE)
# Subtract b*c from fitness of individually learning critical learners
population$fitness[population$learning == "critical" & population$behaviour != E] <-
population$fitness[population$learning == "critical" & population$behaviour != E] - b*c
# Individual learning for those critical learners who did not copy correct behaviour
population$behaviour[learn_correct & population$learning == "critical" & population$behaviour != E] <- E
population$behaviour[!learn_correct & population$learning == "critical" & population$behaviour != E] <- E - 1
}
# 4. Calculate fitnesses (now only need to do the b bonus or penalty)
population$fitness[population$behaviour == E] <-
population$fitness[population$behaviour == E] + b
population$fitness[population$behaviour != E] <-
population$fitness[population$behaviour != E] - b
# 5. store population characteristics in output
output[output$generation == t & output$run == r, ]$p_SL <-
mean(population$learning == "social")
output[output$generation == t & output$run == r, ]$p_IL <-
mean(population$learning == "individual")
output[output$generation == t & output$run == r, ]$p_CL <-
mean(population$learning == "critical")
output[output$generation == t & output$run == r, ]$W <-
mean(population$fitness)
# 6. Reproduction
previous_population <- population
population$behaviour <- NA
population$fitness <- NA
# Individual learners
if (sum(previous_population$learning == "individual") > 0) {
fitness_IL <- sum(previous_population$fitness[previous_population$learning == "individual"]) /
sum(previous_population$fitness)
} else {
fitness_IL <- 0
}
# Social learners
if (sum(previous_population$learning == "social") > 0) {
fitness_SL <- sum(previous_population$fitness[previous_population$learning == "social"]) /
sum(previous_population$fitness)
} else {
fitness_SL <- 0
}
population$learning <- sample(c("individual", "social", "critical"), size = N,
prob = c(fitness_IL, fitness_SL, 1 - (fitness_SL + fitness_IL)), replace = TRUE)
mutation <- sample(c(TRUE, FALSE), N, prob = c(mu, 1 - mu), replace = TRUE)
previous_population2 <- population
population$learning[mutation & previous_population2$learning == "individual"] <-
sample(c("critical", "social"),
sum(mutation & previous_population2$learning == "individual"),
prob = c(0.5, 0.5), replace = TRUE)
population$learning[mutation & previous_population2$learning == "social"] <-
sample(c("critical", "individual"),
sum(mutation & previous_population2$learning == "social"),
prob = c(0.5, 0.5), replace = TRUE)
population$learning[mutation & previous_population2$learning == "critical"] <-
sample(c("individual", "social"),
sum(mutation & previous_population2$learning == "critical"),
prob = c(0.5, 0.5), replace = TRUE)
# 7. Potential environmental change
if (runif(1) < u) E <- E + 1
}
}
# Export data from function
output
}
Now we can run rogers_model2()
, with the same parameter values as we initially ran rogers_model()
in the last chapter.
data_model <- rogers_model2(N = 1000, t_max = 200, r_max = 10, c = 0.9, mu = 0.01, p = 1, u = 0.2)
As before, it’s difficult to see what’s happening unless we plot the data. The following function plot_prop()
now plots the proportion of all three learning strategies. To do this we need to convert our wide data_model
tibble (where each strategy is in a different column) to long format (where all proportions are in a single column, and a new column indexes the strategy). To do this we use pivot_longer()
, similarly to what we did in Chapter 7. For visualisation purposes, we also rename the variables that keep track of the frequencies of the strategies (p_IL
, p_SL
, p_CL
) with full words. For this plot, we only visualise the averages of all runs with the stat_summary()
function.
plot_prop <- function(data_model) {
names(data_model)[3:5] <- c("social", "individual", "critical")
data_model_long <- pivot_longer(data_model, -c(W, generation, run),
names_to = "learning",
values_to = "proportion")
ggplot(data = data_model_long, aes(y = proportion, x = generation, colour = learning)) +
stat_summary(fun = mean, geom = "line", size = 1) +
ylim(c(0, 1)) +
theme_bw() +
labs(y = "proportion of learners")
}
plot_prop(data_model)
Here we can see that critical learners have a clear advantage over the other two learning strategies. Critical learners go virtually to fixation, barring mutation which prevents it from going to 100%. It pays off being a flexible, discerning learner who only learns individually when social learning does not work.
What about Rogers’ paradox? Do critical learners exceed the mean fitness of a population entirely composed of individual learners? We can use the plot_W()
function from the last chapter to find out:
plot_W(data_model, c = 0.9, p = 1)
Yes: Even if there is still some noise, critical learners clearly outperform the dotted line indicating a hypothetical 100% individual learning population. Rogers’ paradox is solved.