logo

Gillespie Stochastic Simulation Algorithm 📂Probability Theory

Gillespie Stochastic Simulation Algorithm

Algorithm 1

For xt=i\mathbf{x}_{t} = i, P(Xt+τ=jxt=i)=aj(xt),j=1,,n P \left( \mathbf{X}_{t + \tau} = j | \mathbf{x}_{t} = i \right) = a_{j} \left( \mathbf{x}_{t} \right) \qquad , j = 1, \cdots , n the method for simulating the realization of a continuous Markov chain {Xt}\left\{ \mathbf{X}_{t} \right\} is called the Gillespie Stochastic Simulation Algorithm, or simply SSA.


Input

Receives initial values t=0t=0 and X0=x\mathbf{X}_{0} = \mathbf{x}.


Step 1.

Calculate jaj(xt)\sum_{j} a_{j} \left( \mathbf{x}_{t} \right).


Step 2.

Sample τ\tau from the exponential distribution exp(jaj(xt))\exp \left( \sum_{j} a_{j} \left( \mathbf{x}_{t} \right) \right). The larger jaj(xt)\sum_{j} a_{j} \left( \mathbf{x}_{t} \right) is, the smaller the expected value of τ\tau becomes, and events occur more frequently.


Step 3.

Select jj with the probability of ajjaj(xt)\displaystyle {{a_{j}} \over {\sum_{j} a_{j} \left( \mathbf{x}_{t} \right)}}. The larger aja_{j} is, the higher the probability that event jj will occur.


Step 4.

Record (t+τ,xt+τ)\left( t + \tau, \mathbf{x}_{t + \tau} \right) and update as tt+τxtxt+τ \begin{align*} t \gets & t + \tau \\ \mathbf{x}_{t} \gets & \mathbf{x}_{t + \tau} \end{align*} . Since {Xt}\left\{ \mathbf{X}_{t} \right\} is a continuous-time Markov chain, one can return to Step 1 and repeat. Stop the algorithm when enough data has been obtained.


Output

Obtains the realization of given {Xt}\left\{ \mathbf{X}_{t} \right\}.

Explanation

Example

The algorithm might look complicated with all the general expressions, but it’s actually pretty simple.

Consider a simple Birth-Death Process. This process starts with NN individuals and shows the increase or decrease in population according to the birth rate b>0b > 0 and the death rate d>0d > 0. Whether bb is greater or smaller than dd will determine the pattern, but the frequency of events itself depends on their absolute values. It is plausible that events, whether births or deaths, happen more frequently in proportion to the current number of individuals, and the interval at which events occur when the population is ii follows τexp((b+d)i) \tau \sim \exp \left( (b+d) i \right) . Once the timing of an event is decided, we choose which event, birth or death, will occur. At tt, if the population is ii, to breed at t+τt + \tau means j=i+1j = i+1, and to die means j=i1j = i-1. These are proportional to the rate b,db, d and the population at tt, ii, respectively, so ai+1(x)=biai1(x)=di a_{i+1} (x) = b i \\ a_{i-1} (x) = d i . According to Step 3, decide which event will occur with the probability calculated by normalizing these.

Code

The following is the Julia code that directly translates the above example. b=2d=1 b = 2 \\ d = 1 With the given parameters, repeat the simulation ten thousand times starting with the initial population N=2N=2 and compute the average at t=2t = 2 to compare with the theoretical prediction. It is written to be easy to read rather than efficient, so let’s check if the algorithm is implemented as described in the example.

using Distributions
using Plots

b = 2.0
d = 1.0
θ = b/(b+d)

result = plot(xlims = (0,2), ylims = (0, Inf))

Y = Int64[]
@time for _ in 1:10000
    y = [2]
    t = [0.0]
    while t[end] < 2 && y[end] > 0
        push!(t, t[end] + rand(Exponential(1/((b+d) * y[end]))))
        if rand() < θ
            push!(y, y[end] + 1)
        else
            push!(y, y[end] - 1)
        end
    end
    if t[end] > 2
        push!(Y, y[end-1])
    else
        push!(Y, 0)
    end
    plot!(result, t,y, label = :none, alpha = 0.01, color = :black)
end

plot!(result, 0:0.1:2,2exp.((b-d) .* 0:0.1:2), label = :none, color = :red, linewidth = 4, linestyle = :dot)
result

abs(mean(Y) - 2exp.(2(b-d)))

example.png

Visualizing the result looks like the above. The difference from the theoretical prediction 2exp(2(bd))=14.782\exp(2(b-d)) = 14.78 is about 0.1, confirming that it has been calculated quite accurately.