Lotka-Volterra’s Predator–Prey Model

Author

Daniel Vartanian

Published

2024-10-25

Project Status: Inactive – The project has reached a stable, usable state but is no longer being actively developed; support/maintenance will be provided as time allows. License: MIT

Overview

This document focuses on illustrating the Lotka-Volterra’s model, originally developed by Alfred J. Lotka (1925) and Vito Volterra (1926), to describe the dynamics of biological systems where two species interact: one as a predator and the other as prey.

The dynamics of the model are represented by the following set of first-order, nonlinear differential equations:

\[ \begin{aligned} \frac{dx}{dt} & = \alpha x - \beta xy \\ \frac{dy}{dt} & = - \gamma y + \delta xy \end{aligned} \]

where:

  • \(x\) and \(y\) are the populations of the prey and predator, respectively;
  • \(\alpha\) and \(\delta\) are the prey per capita growth rate and the effect of the presence of prey on the predator’s growth rate, respectively;
  • \(\beta\) and \(\gamma\) are the effect of the presence of predators on the prey death rate and predator’s per capita death rate, respectively.

Setting up the environment

Code
library(checkmate, quietly = TRUE)
library(deSolve, quietly = TRUE)
library(dplyr, quietly = TRUE)
library(ggplot2, quietly = TRUE)
library(latex2exp, quietly = TRUE)
library(magrittr, quietly = TRUE)

Numerical solution of the equations

Code
lotka_volterra <- function(
    x = 0.9, 
    y = 1.8, 
    alpha = 2 / 3, 
    beta = 4 / 3, 
    gamma = 1, 
    delta = 1, 
    from = 0, 
    to = 100,
    by = 0.01
  ) {
  checkmate::assert_number(x, lower = 0)
  checkmate::assert_number(y, lower = 0)
  checkmate::assert_number(alpha)
  checkmate::assert_number(beta)
  checkmate::assert_number(gamma)
  checkmate::assert_number(delta)
  checkmate::assert_number(from, lower = 0)
  checkmate::assert_number(to, lower = from)
  checkmate::assert_number(by, lower = 0)
  
  fun <- function (t, y, parms) {
    list2env(as.list(y), envir = environment())
    list2env(as.list(parms), envir = environment())
    
    list(
      c(
        dx = (alpha * x) - (beta * x * y), # Prey
        dp = (- gamma * y) + (delta * x * y) # Predator
      )
    )
  }
  
  initial_values <- c(x = x, y = y)
  parameters <- list(alpha = alpha, beta = beta, gamma = gamma, delta = delta)
  time <- seq(from = from, to = to, by = by)
  
  data <- 
    deSolve::ode(
      y = initial_values,
      times = time, 
      func = fun,
      parms = parameters
    ) |>
    dplyr::as_tibble() |>
    dplyr::mutate(dplyr::across(dplyr::everything(), ~ as.numeric(.x)))
  
  list(
    data = data,
    initial_values = as.list(initial_values),
    parameters = parameters
  ) |>
  invisible()
}
Code
lotka_volterra() |> magrittr::extract2("data")
#> # A tibble: 10,001 × 3
#>    time     x     y
#>   <dbl> <dbl> <dbl>
#> 1  0    0.9    1.8 
#> 2  0.01 0.885  1.80
#> 3  0.02 0.869  1.80
#> 4  0.03 0.855  1.79
#> 5  0.04 0.840  1.79
#> 6  0.05 0.826  1.79
#> # ℹ 9,995 more rows

Plotting population dynamics

Code
plot_pop_dynamics <- function(
    x = 0.9, 
    y = 1.8, 
    alpha = 2 / 3, 
    beta = 4 / 3, 
    gamma = 1, 
    delta = 1, 
    from = 0, 
    to = 100,
    by = 0.01
  ) {
  checkmate::assert_number(x, lower = 0)
  checkmate::assert_number(y, lower = 0)
  checkmate::assert_number(alpha)
  checkmate::assert_number(beta)
  checkmate::assert_number(gamma)
  checkmate::assert_number(delta)
  checkmate::assert_number(from, lower = 0)
  checkmate::assert_number(to, lower = from)
  checkmate::assert_number(by, lower = 0)
  
  lotka_volterra(x, y, alpha, beta, gamma, delta, from, to, by) |>
    list2env(envir = environment())
  
  plot <- 
    data |>
    ggplot2::ggplot(ggplot2::aes(x = time)) +
    ggplot2::geom_line(
      ggplot2::aes(y = x, color = "Prey"),
      linewidth = 0.75
    ) +
    ggplot2::geom_line(
      ggplot2::aes(y = y, color = "Predator"),
      linetype = "dashed",
      linewidth = 0.75
    ) +
    ggplot2::labs(
      title = "Lotka-Volterra's Model Population Dynamics",
      subtitle = latex2exp::TeX(
        paste0(
          "$X_0$ = ", initial_values$x, " | ",
          "$Y_0$ = ", initial_values$y, " | ",
          "$\\alpha$ = ", round(parameters$alpha, 2), " | ",
          "$\\beta$ = ", round(parameters$beta, 2), " | ",
          "$\\gamma$ = ", round(parameters$gamma, 2), " | ",
          "$\\delta$ = ", round(parameters$delta, 2)
        ),
      ),
      x = "Time", 
      y = "Population",
      color = ggplot2::element_blank()
    ) +
    ggplot2::scale_color_manual(
      breaks = c("Prey", "Predator"),
      values = c("blue", "red")
    )
  
  print(plot)
  
  invisible()
}
Code
plot_pop_dynamics()

Phase space visualization

Code
gg_color_hue <- function(n) {
  hues = seq(15, 375, length = n + 1)
  hcl(h = hues, l = 65, c = 100)[1:n]
}
Code
plot_phase_space <- function(
    x = 0.9, 
    y = 1:5,
    alpha = 2 / 3, 
    beta = 4 / 3, 
    gamma = 1, 
    delta = 1, 
    from = 0, 
    to = 100,
    by = 0.01
) {
  checkmate::assert_number(x, lower = 0)
  checkmate::assert_numeric(y, lower = 0)
  checkmate::assert_number(alpha)
  checkmate::assert_number(beta)
  checkmate::assert_number(gamma)
  checkmate::assert_number(delta)
  checkmate::assert_number(from, lower = 0)
  checkmate::assert_number(to, lower = from)
  checkmate::assert_number(by, lower = 0)

  plot <-ggplot2::ggplot()
  
  for (i in y) {
    data_i <- 
      lotka_volterra(x, i, alpha, beta, gamma, delta, from, to, by) |>
      magrittr::extract2("data") |>
      dplyr::mutate(color = as.character(i))
    
    plot <-
      plot +
      ggplot2::geom_path(
        data = data_i,
        ggplot2::aes(x = x, y = y, color = color),
        linewidth = 0.75
      )
  }
  
  colors <- gg_color_hue(length(y))
  names(colors) <- as.character(y)
  
  plot <-
    plot +
    ggplot2::labs(
      title = "Lotka-Volterra's Model Phase-Space",
      subtitle = latex2exp::TeX(
        paste0(
          "$X_0$ = ", x, " | ",
          "$\\alpha$ = ", round(alpha, 2), " | ",
          "$\\beta$ = ", round(beta, 2), " | ",
          "$\\gamma$ = ", round(gamma, 2), " | ",
          "$\\delta$ = ", round(delta, 2)
        ),
      ),
      x = "Prey",
      y = "Predator"
    ) +
    scale_color_manual(name = latex2exp::TeX("$Y_0$"), values = colors)
  
  print(plot)
  
  invisible()
}
Code
plot_phase_space()

References

Lotka, A. J. (1925). Elements of physical biology. Williams & Wilkins Company. http://archive.org/details/elementsofphysic017171mbp
Volterra, V. (1926). Fluctuations in the abundance of a species considered mathematically. Nature, 118(2972), 558–560. https://doi.org/10.1038/118558a0