Agent-based Model Simulation of Reproduction
Simulation
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}$.
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..
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