logo

Agent-based Model Simulation of Reproduction 📂Dynamics

Agent-based Model Simulation of Reproduction

Simulation

malthusian_growth_simulation.gif

In this post, we attempt to emulate the macroscopic growth of a population by giving generated agents the action to replicate themselves. Everything related to space or movement in this simulation is merely for visualization purposes and has no actual relevance to the objective.

Variables

  • $t$: Represents the current turn.
  • $N(t)$: Indicates the number of agents at turn $t$.

Parameters

  • $N_{0} \in \mathbb{N}$: Represents the number of agents at the start of the simulation.
  • $b \in [0,1]$: Birth Rate, which indicates the probability of an agent replicating.
  • $t_{\text{end}} \in \mathbb{N}$: Determines the turn at which the simulation ends.

Actions

(For all agents, every turn)

  • Reproduction: Creates a new agent at their location with probability b.
  • Movement: Moves according to a vector drawn from a bivariate normal distribution $N \left( \mathbb{0} , \Sigma \right)$.

Code Review

Step 1. Initialization and Agent Creation

julia> N0 = 5 # 초기 인구수
5

julia> b = 0.05 # 번식률
0.05

julia> max\_iteration = 180 # 시뮬레이션 기간
180

julia> gaussian2 = MvNormal([0.0; 0.0], 0.02I) # 2차원 정규분포
IsoNormal(
dim: 2
μ: [0.0, 0.0]
Σ: [0.02 0.0; 0.0 0.02]
)

julia> Random.seed!(2);

julia> Time\_evolution = [] # 인구수를 기록하기 위한 스택
Any[]

Similar to the Agent-Based Simulation Tutorial, agents are created. Here, the variables reflect the above parameter settings.

  • N0 $\leftarrow N_{0} = 5$
  • b $\leftarrow b = 0.05$
  • max_iteration $\leftarrow t_{\text{end}} = 180$

Random.seed!(2) is the seed number setting for reproducibility, and time_evolution is a stack for recording population numbers. While it doesn’t affect the simulation itself, it is an important technique for repeating and analyzing the simulation.

julia> coordinate = rand(gaussian2, N0)'
5×2 Adjoint{Float64,Array{Float64,2}}:
  0.104598   -0.105289
 -0.086056   -0.243734
 -0.0955465   0.0787217
 -0.121846    0.0732683
  0.176526    0.165338

julia> N = N0
5

$N$ indicates the number of individuals, so initially, one must receive the initial number of individuals as $N \gets N_{0}$.

20201112_193047.png

Scatter plots of the agents’ locations like the above show them densely clustered together.


Step 2. Agent Reproduction

julia> replicated = (rand(N) .< b)
5-element BitArray{1}:
 0
 0
 1
 0
 0

julia> new\_coordinate = coordinate[replicated,:]
1×2 Array{Float64,2}:
 -0.0955465  0.0787217

julia> coordinate = cat(coordinate, new\_coordinate, dims = 1)
6×2 Array{Float64,2}:
  0.104598   -0.105289
 -0.086056   -0.243734
 -0.0955465   0.0787217
 -0.121846    0.0732683
  0.176526    0.165338
 -0.0955465   0.0787217

Random numbers between 0 and 1 are drawn for the current number of agents. If this is less than b, it means that reproduction has occurred with the probability of b. In the screenshot above, it can be seen that the third agent has reproduced with a probability of $5\%$, where the third row from Step 1. was directly added as a new row.


Step 3. Recording and Agent Movement

julia> N = size(coordinate, 1)
6

julia> push!(time\_evolution, N)
1-element Array{Any,1}:
 6

julia> coordinate = coordinate + rand(gaussian2, N)'
6×2 Array{Float64,2}:
  0.0678177  -0.0642068
 -0.137464   -0.0672691
 -0.0571189   0.06278
 -0.0635334   0.226498
  0.18355     0.180084
  0.0920502   0.0682156

Since one more agent was added in Step 2., $N$ was also updated, and the number at this instance was recorded. Each agent’s coordinates are expressed in a matrix, so adding a $N \times 2$ matrix, which is a bivariate normal distribution drawn $N$ times, implements the agents’ movement. By actually plotting a scatter plot, we can see they have moved slightly compared to Step 1..

20201112_192927.png

After this, we go back to Step 2. and keep repeating until $t = t_{\text{end}}$ is reached.

Just by repeating this process, one can observe the phenomenon similar to the gif at the top of the post.

Complete Code

Below is the Julia code used in this post.

cd(@__DIR__) # 파일 저장 경로

@time using Plots
@time using Random
@time using Distributions
@time using LinearAlgebra

N0 = 5 # 초기 인구수
b = 0.05 # 번식률
max_iteration = 180 # 시뮬레이션 기간
gaussian2 = MvNormal([0.0; 0.0], 0.02I) # 2차원 정규분포

Random.seed!(2);
time_evolution = [] # 인구수를 기록하기 위한 스택
let
  coordinate = rand(gaussian2, N0)'
  N = N0

  anim = @animate for t = (0:max_iteration)/100
    plot(coordinate[:,1], coordinate[:,2], Seriestype = :scatter,
      markercolor = RGB(1.,94/255,0.), markeralpha = 0.4, markerstrokewidth	= 0.1,
      title = "t = $t", aspect_ratio = 1, size = [400,400],
      xaxis=true,yaxis=true,axis=nothing, legend = false)
      xlims!(-10.,10.)
      ylims!(-10.,10.)

    replicated = (rand(N) .< b)
    new_coordinate = coordinate[replicated,:]
    coordinate = cat(coordinate, new_coordinate, dims = 1)

    N = size(coordinate, 1)
    push!(time_evolution, N)
    coordinate = coordinate + rand(gaussian2, N)'
  end
  gif(anim, "malthusian_growth_simulation.gif", fps = 18)
end