logo

ジレスピ確率シミュレーションアルゴリズム 📂確率論

ジレスピ確率シミュレーションアルゴリズム

アルゴリズム 1

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 連続マルコフ連鎖 {Xt}\left\{ \mathbf{X}_{t} \right\}実現をシミュレーションする方法は ジレスピー確率シミュレーションアルゴリズムgillespie Stochastic Simulation Algorithm、短く SSAstochastic Simulation Algorithmと呼ばれている。


入力

初期値t=0t=0X0=x\mathbf{X}_{0} = \mathbf{x}を受け取る。


ステップ1.

jaj(xt)\sum_{j} a_{j} \left( \mathbf{x}_{t} \right)を計算する。


ステップ2.

指数分布exp(jaj(xt))\exp \left( \sum_{j} a_{j} \left( \mathbf{x}_{t} \right) \right)からτ\tauをサンプリングする。jaj(xt)\sum_{j} a_{j} \left( \mathbf{x}_{t} \right)が大きいほど、τ\tauの期待値は小さくなり、事象は頻繁に発生する。


ステップ3.

ajjaj(xt)\displaystyle {{a_{j}} \over {\sum_{j} a_{j} \left( \mathbf{x}_{t} \right)}}の確率でjjを選ぶ。aja_{j}が大きいほど、事象jjが発生する確率が高くなる。


ステップ4.

(t+τ,xt+τ)\left( t + \tau, \mathbf{x}_{t + \tau} \right)を記録し、 tt+τxtxt+τ \begin{align*} t \gets & t + \tau \\ \mathbf{x}_{t} \gets & \mathbf{x}_{t + \tau} \end{align*} のように更新する。{Xt}\left\{ \mathbf{X}_{t} \right\}は連続時間マルコフ連鎖なので、ステップ1に戻って繰り返し実行することができる。十分なデータを得たら、アルゴリズムを停止する。


出力

与えられた{Xt}\left\{ \mathbf{X}_{t} \right\}の実現を得る。

説明

アルゴリズムは式が一般的に書かれていて少し難しそうに見えるけど、実際はとても簡単だ。

簡単な誕生-死滅プロセスbirth-Death processを考えてみよう。このプロセスはNN人の人口から始まり、繁殖係数b>0b > 0と死亡係数d>0d > 0に従って人口の増減が表される。bbddより大きいか小さいかで異なる様相が現れるけれども、まず事象が発生する頻度そのものはこれらの絶対値に依存する。生存であれ死であれ、その時点での個体数に比例して頻繁に発生するのが妥当だし、人口数iiの時の事象が発生する間隔は τexp((b+d)i) \tau \sim \exp \left( (b+d) i \right) に従う。一度事象が発生する時点を定めたら、次に発生する事象が誕生か死かを選ぶ。tt時点の人口数がiiの時、t+τt + \tau時点で繁殖するということはj=i+1j = i+1、死ぬということはj=i1j = i-1を意味する。これらはそれぞれ係数b,db, dtt時点の人口数iiに比例するので、 ai+1(x)=biai1(x)=di a_{i+1} (x) = b i \\ a_{i-1} (x) = d i ステップ3でこれらを正規化normalizeして得られる確率でどの事象が発生するかを決定すればいい。

コード

以下は上記の例をそのままコードに転写したJuliaのコードだ。 b=2d=1 b = 2 \\ d = 1 与えられたパラメータで、初期人口N=2N=2から始めてシミュレーションを1万回繰り返し、t=2t = 2で平均を計算して理論的な予測と比較する。読みやすさを重視して書いたので、アルゴリズムが例の説明通りに実装されているかを確認しよう。

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

実行結果を可視化すると上のようになる。理論的な予測値2exp(2(bd))=14.782\exp(2(b-d)) = 14.78との差は0.1程度で、かなり正確に計算されたことが確認できる。