Discrete-Time Models and the Logistic Map

Many organisms breed in discrete seasons, and many diseases are tracked generation by generation, so their dynamics are naturally written as a rule mapping this year’s state to next year’s. These maps are simple to iterate yet capable of astonishingly rich behavior — including deterministic chaos from a one-line equation.

Bifurcation diagram of the logistic map: as  increases the attractor period-doubles into chaos.
Figure 1. Bifurcation diagram of the logistic map: as rr increases the attractor period-doubles into chaos.

Geometric growth#

The discrete analogue of exponential growth is geometric growth, Nt+1=λNt,N_{t+1}=\lambda N_t, which generates the sequence Nt=λtN0N_t=\lambda^t N_0. Here λ\lambda is the finite (per-generation) growth rate; it links to the continuous intrinsic rate by λ=er\lambda=e^{r}. The population grows when λ>1\lambda>1, shrinks when λ<1\lambda<1, and holds steady when λ=1\lambda=1.

The Ricker model#

Real populations are density-dependent, and the Ricker model builds crowding into a discrete map, Nt+1=Nt er(1−Nt/K).N_{t+1}=N_t\,e^{r(1-N_t/K)}. When NtN_t is small the exponent is near rr and growth is nearly geometric; as NtN_t approaches the carrying capacity KK the exponent goes to zero and Nt+1≈NtN_{t+1}\approx N_t. Unlike the smooth continuous logistic, overshoot in the Ricker map can produce oscillations and, for large rr, chaos.

The logistic map#

The most famous discrete model is the logistic map, xt+1=r xt(1−xt),x_{t+1}=r\,x_t(1-x_t), where xt∈[0,1]x_t\in[0,1] is a scaled population fraction and rr is a growth parameter (here 0≤r≤40\le r\le 4). Robert May’s 1976 analysis of this map showed that even a trivial nonlinear rule can produce cycles and chaos, reshaping how ecologists think about complexity and predictability.

Fixed points and stability#

A fixed point x∗x^* satisfies x∗=f(x∗)x^*=f(x^*) with f(x)=rx(1−x)f(x)=rx(1-x). Solving x∗=rx∗(1−x∗)x^*=rx^*(1-x^*) gives two fixed points: x∗=0x^*=0 and x∗=1−1/rx^*=1-1/r (the latter positive only when r>1r>1). Stability of a discrete map depends on the slope at the fixed point: x∗x^* is stable when ∣f′(x∗)∣<1.|f'(x^*)|<1. Here f′(x)=r(1−2x)f'(x)=r(1-2x). At x∗=0x^*=0, f′(0)=rf'(0)=r, so the origin is stable only for r<1r<1. At x∗=1−1/rx^*=1-1/r, f′(x∗)=r(1−2(1−1/r))=2−rf'(x^*)=r\bigl(1-2(1-1/r)\bigr)=2-r, so this nonzero fixed point is stable when ∣2−r∣<1|2-r|<1, i.e. for 1<r<31<r<3.

Period-doubling and chaos#

As rr increases past 33 the fixed point loses stability and a stable 2-cycle appears; past ≈3.449\approx 3.449 a 4-cycle; then 8, 16, and so on, with the thresholds bunching up in a period-doubling cascade. Beyond r≈3.569r\approx 3.569 the dynamics become chaotic — bounded, aperiodic, and sensitive to initial conditions. Each loss of stability is a bifurcation, and plotting the long-run attractor against rr produces the classic bifurcation diagram.

Cobweb plots#

A cobweb plot visualizes iteration: draw y=f(x)y=f(x) and the line y=xy=x, then bounce between them (up to the curve, across to the diagonal) to trace the orbit. Converging staircases spiral into a stable fixed point; diverging ones reveal cycles or chaos.

A worked example#

Take the logistic map with r=2.5r=2.5. The nonzero fixed point is x∗=1−1/r=1−1/2.5=1−0.4=0.6x^*=1-1/r=1-1/2.5=1-0.4=0.6. Its stability slope is f′(x∗)=2−r=2−2.5=−0.5f'(x^*)=2-r=2-2.5=-0.5, and since ∣−0.5∣<1|-0.5|<1 the fixed point is stable — orbits converge to 0.60.6. Now take r=3.2r=3.2: the fixed point x∗=1−1/3.2=0.6875x^*=1-1/3.2=0.6875 has slope 2−3.2=−1.22-3.2=-1.2, and ∣−1.2∣>1|-1.2|>1, so it is unstable; the map instead settles onto a stable 2-cycle.

In code#

We iterate the map and build the bifurcation diagram by plotting late iterates over a range of rr.

R#

R
logmap <- function(x, r) r * x * (1 - x)

# converge to the fixed point 0.6 when r = 2.5
x <- 0.1
for (i in 1:100) x <- logmap(x, 2.5)
round(x, 6)   # 0.6

# bifurcation diagram
rs <- seq(2.8, 4.0, length.out = 600)
plot(NULL, xlim = range(rs), ylim = c(0, 1), xlab = "r", ylab = "x")
for (r in rs) {
  x <- 0.2
  for (i in 1:300) x <- logmap(x, r)          # transient
  for (i in 1:200) { x <- logmap(x, r); points(r, x, pch = ".") }
}

Python#

Python
import numpy as np

def logmap(x, r):
    return r * x * (1 - x)

x = 0.1
for _ in range(100):
    x = logmap(x, 2.5)
print(round(x, 6))   # 0.6  -> stable fixed point

# bifurcation diagram data
rs = np.linspace(2.8, 4.0, 600)
R, X = [], []
for r in rs:
    x = 0.2
    for _ in range(300):        # discard transient
        x = logmap(x, r)
    for _ in range(200):
        x = logmap(x, r)
        R.append(r); X.append(x)
# plt.plot(R, X, ',k')  -> period-doubling route to chaos
0.6

Julia#

Julia
logmap(x, r) = r * x * (1 - x)

x = 0.1
for _ in 1:100
    x = logmap(x, 2.5)
end
round(x, digits = 6)   # 0.6

rs = range(2.8, 4.0; length = 600)
R = Float64[]; X = Float64[]
for r in rs
    x = 0.2
    for _ in 1:300; x = logmap(x, r); end       # transient
    for _ in 1:200
        x = logmap(x, r)
        push!(R, r); push!(X, x)
    end
end
# scatter(R, X; markersize = 0.5)  -> bifurcation diagram

Why it matters#

Discrete maps are the right tool for seasonally breeding populations and generation-based disease models, and they force us to check stability with the slope condition ∣f′(x∗)∣<1|f'(x^*)|<1 rather than the sign of a derivative. The logistic map is a canonical warning that simple, fully deterministic ecological rules can generate irregular, effectively unpredictable dynamics — a lesson that carries directly into forecasting outbreaks and managed populations.