これは、被食者数を $u(t)$ で、捕食者数を $v(t)$ で表すとして、 以下のような非線形の常微分微分方程式で表される.
$\left\{\begin{array}{rcl} \displaystyle \frac{du}{dt} & = & - C_1 uv + D_1 u \\ \displaystyle \frac{dv}{dt} & = & C_2 uv - D_2 v \end{array}\right.$
ただし、係数 $C_1$, $C_2$, $D_1$, $D_2$ は全て定数で正としておこう.
相図等についてはまた話すとして、まずはこいつに従って計算してみよう.
離散時間の近似解を $u_n \cong u(n\Delta t)$, $v_n \cong v(n\Delta t)$, と書くとして、Euler スキームは次のようになるだろう.
$\left\{\begin{array}{rcl} \displaystyle \frac{u_{n+1} - u_n}{\Delta t} & = & - C_1 u_n v_n + D_1 u_n \\ \displaystyle \frac{v_{n+1} - v_n}{\Delta t} & = & C_2 u_n v_n - D_2 v_n \end{array}\right.$
これを分かりやすく書き直すと次のようになる.
$\left\{\begin{array}{rcl} u_{n+1} & = & u_n - \Delta t C_1 u_n v_n + \Delta t D_1 u_n = (1 + \Delta t D_1 - \Delta t C_1 v_n ) u_n \\ % v_{n+1} & = & v_n + \Delta t C_2 u_n v_n - \Delta t D_2 v_n = (1 - \Delta t D_2 + \Delta t C_2 u_n ) v_n \end{array}\right.$
定数などを、 $C_1 = $ $C_2 = $ $D_1 = $ $D_2 = 1.0$, $u(0) = v(0) = 0.7$, $\Delta t = 0.05$ としてやってみよう.
まず定数を設定して、
C1 = C2 = D1 = D2 = 1.0
u0 = v0 = 0.7
Δt = 0.05
Euler スキームを関数として定義する.
function euler(u,v)
u_new = (1 + Δt*D1 - Δt*C1*v) * u
v_new = (1 - Δt*D2 + Δt*C2*u) * v
u,v = u_new, v_new
return u, v
end
初期値を試しに入れて、動作するかどうか確かめてみよう
euler(u0,v0)
とりあえず動きそうなので,思い切って 500ステップほど動かしてみようか.
u,v = u0, v0
uv_sq = [ u0, v0 ]
for i in 1:500
u,v = euler(u,v)
uv_sq = hcat(uv_sq, [u,v])
end
結果をまずちょっと眺めてみて、
uv_sq
グラフにしてみよう
using Plots
gr()
plot(uv_sq')
# 行列を与えると、縦ベクトルを別々のグラフとして描いてくれる.ちなみに,' は行列の転置記号.
青線が $u_n$ で、赤線が $v_n$ だね.
横軸を、配列の要素番号ではなくてもとの問題の時間 $t$ にあわせたければ、次のようにすれば良い.
t_sq = [0:Δt:500*Δt]
plot(t_sq, uv_sq')
ふ〜む、だんだん振幅が大きくなっているけど本当かな? ちょっと $\Delta t$ を小さくしてみて、変化したりしないかチェックしてみよう.
上のグラフと比べたいので、同じ時間($t=25.0$)まで計算することにしよう.すると次のような感じかな.
Δt = 0.01
lastT = 25
N = Int(lastT/Δt)
u,v = u0, v0
uv_sq = [ u0, v0 ]
for i in 1:N
u,v = euler(u,v)
uv_sq = hcat(uv_sq, [u,v])
end
t_sq = 0:Δt:lastT
plot(t_sq, uv_sq')
んん? 随分変わったぞ? 振幅が余り変わらなくなった.どうやら Euler スキームはこの問題だと少し信用ならないようだな.あとでもう少し信用できそうな方法で計算し直そう.
あまり信用ならないけれども、まあまったく外れというわけでもないだろうから、まずは Euler 法の結果を相図にして、様子を見てみよう.なにか見えてくるものがあるかもしれない.
u_sq = uv_sq[1,:]
v_sq = uv_sq[2,:]
plot(u_sq, v_sq, aspect_ratio = 1)
# aspect_ratio は、縦横の軸目盛りの比率を指定する.1 にすると、縦横の縮尺が一致する.
plot!((u0,v0), marker = :circle, lab = "initial value")
# lab に指定した文字列は、legend に現れる
どうやら、相図の上では、ぐるぐると周っている状態のようだ.円とはすこし違った歪んだ形のようではあるが.
自力で作ってみよう! そして、プログラムして、動かしてみよう!
注意として、この問題は非線形なので、時間対称なスキームを作ると当然ながらそれは陰的なスキームになる.つまり、非線形方程式を説かないと、時間ステップを進めることが出来ないのだ.
というわけで、スキームを作ったら、Newton 法を自力で用いるか、NLsolve パッケージを使うかしないといけないな.そういう風にプログラムをして、自分で動かしてみよう.
漁業の影響がどう出るか、Volterra モデルで見てみよう. これがこのモデルの「キモ」であるので、注意深く考えながらやろう.
まず、モデルの数式は、漁業の影響係数 $E > 0$ を用いて、次のようになる.
$\left\{\begin{array}{rcl} \displaystyle \frac{du}{dt} & = & - C_1 uv + D_1 u - E u\\ \displaystyle \frac{dv}{dt} & = & C_2 uv - D_2 v - E v \end{array}\right.$
そこで、この係数 $E$ を $E = 0.5$ として以下、計算してみよう.
スキームを一部変えるだけでいいはずだ.次のようになるだろう.
$\left\{\begin{array}{rcl} \displaystyle \frac{u_{n+1} - u_n}{\Delta t} & = & - C_1 u_n v_n + D_1 u_n - E u_n\\ \displaystyle \frac{v_{n+1} - v_n}{\Delta t} & = & C_2 u_n v_n - D_2 v_n - E v_n \end{array}\right.$
これを分かりやすく書き直すと次のようになる.
$\left\{\begin{array}{rcl} u_{n+1} & = & u_n - \Delta t C_1 u_n v_n + \Delta t D_1 u_n - \Delta E u_n = (1 + \Delta t D_1 - \Delta t E - \Delta t C_1 v_n ) u_n \\ % v_{n+1} & = & v_n + \Delta t C_2 u_n v_n - \Delta t D_2 v_n - \Delta t E v_n = (1 - \Delta t D_2 - \Delta t E + \Delta t C_2 u_n ) v_n \end{array}\right.$
E = 0.5
function euler_fishing(u,v)
u_new = (1 + Δt*D1 - Δt*E - Δt*C1*v) * u
v_new = (1 - Δt*D2 - Δt*E + Δt*C2*u) * v
u,v = u_new, v_new
return u, v
end
Δt = 0.01
lastT = 25
N = Int(lastT/Δt)
u,v = u0, v0
uv_f_sq = [ u0, v0 ]
for i in 1:N
u,v = euler_fishing(u,v)
uv_f_sq = hcat(uv_f_sq, [u,v])
end
t_sq = 0:Δt:lastT
plot(t_sq, uv_f_sq')
んんん? これは随分変わったな.早速相図を描いてみよう.
u_f_sq = uv_f_sq[1,:]
v_f_sq = uv_f_sq[2,:]
plot(u_f_sq, v_f_sq, aspect_ratio = 1)
plot!((u0,v0), marker = :circle, lab = "initial value")
変化を見たいので、漁業効果の入っていないデータと一緒に描いてみよう.
plot(u_sq, v_sq, aspect_ratio = 1)
plot!(u_f_sq, v_f_sq)
plot!((u0,v0), marker = :circle, lab = "initial value")
どうやら、漁業が行われると、相図の上での軌跡の中心が右下にずれるようだ.
じつはこの「軌跡の中心」は幸いにも手計算で求めることが出来て、
漁業なし… 中心 $\displaystyle = \left(\frac{D_2}{C_2}, \frac{D_1}{C_1}\right)$,
漁業あり… 中心 $\displaystyle = \left(\frac{D_2 + E}{C_2}, \frac{D_1 - E}{C_1}\right)$
ということがわかっている.そこでこれも相図に描き込んでみよう.
plot(u_sq, v_sq, aspect_ratio = 1)
plot!(u_f_sq, v_f_sq)
plot!((u0,v0), marker = :circle, lab = "initial value")
plot!((D2/C2,D1/C1), marker = :circle, lab = "center without fishing")
plot!(((D2 + E)/C2,(D1 - E)/C1), marker = :circle, lab = "center with fishing")
なんとなく、いろいろと分かってきたようなきがするのではないだろうか.
Interact パッケージを使えば良いわけだ.
using Interact
係数 E の影響を計算がきちんと受けるように、関数の引数に明示しておこう.
function euler_fishing_mod(u,v,E)
u_new = (1 + Δt*D1 - Δt*E - Δt*C1*v) * u
v_new = (1 - Δt*D2 - Δt*E + Δt*C2*u) * v
u,v = u_new, v_new
return u, v
end
あとはこいつを使って、これまでと同等のことをやれば良い.
@manipulate for E in 0.0:0.01:0.99
u,v = u0, v0
uv_f_sq = [ u0, v0 ]
for i in 1:N
u,v = euler_fishing_mod(u,v,E)
uv_f_sq = hcat(uv_f_sq, [u,v])
end
u_f_sq = uv_f_sq[1,:]
v_f_sq = uv_f_sq[2,:]
plot(u_sq, v_sq, aspect_ratio = 1)
plot!(u_f_sq, v_f_sq)
plot!((u0,v0), marker = :circle, lab = "initial value")
plot!((D2/C2,D1/C1), marker = :circle, lab = "center without fishing")
plot!(((D2 + E)/C2,(D1 - E)/C1), marker = :circle, lab = "center with fishing")
end
漁業の影響が多少ならば、魚も増えて良いことばかりのように見えるが、漁業の影響が強くなりすぎるといろいろな点で危ないことが見えてくるだろう.
もう難しくないだろう.チャレンジしてみよう.