2017年12月29日金曜日

FitzHugh-Nagumo modelがわからない…(原点回帰)

 前回はtauをいじって遊んでいたんですが、ちゃんとtauの働きを見てみようということで0.5から1.5を0.1刻みで動かしてみた。その一部。




0.8と0.9の間に、何かの分岐点がありそう。そんなわけで0.8から0.9を0.01刻みで変えた結果、tau=0.85と0.86の間に分岐点がありそうだなーと思ったんだけど、考えてみれば1点に収束することなんてありえなくね?という気がしてきた。逆ならまだしもさ。

で、tau=0.85の図をちょっとだけ拡大してみた。

あ、でも意外と真ん中に円が見えてきたりはしない。
でも最後どうなってるか気になる。

そんなわけでめちゃめちゃ拡大してみることにする。上のtau=0.85から1本だけ取り出して拡大。


これを拡大して…。


拡大して…。


拡大して…。


拡大して…。


拡大して…。


拡大して…。


拡大して…。


拡大して…。


拡大して…。


拡大して…。


拡大して…。(やっと見えてきた)


まあそうだよね。

逆にタウ=0.9だった場合をもう一度見てみる。

これも延々と時間をかければどんどん中心によっていくのだろうか。
やりたくね~といいつつ回します。
乱数を消してしまったので、もう一度設定してまずT=100, 200でu-v平面にプロットしたものを出力。


まあそうでしょうな。
この記事の最初でtauをちょっとずつ大きくしていったときに、この楕円形のような軌道が平行四辺形な軌道になっていった。その時はあまりそのことを気にせず、中心の円にだけ目がいってしまっていたが、むしろ気にするべきはその平行四辺形と楕円形の境界のほうなのではないかという気がしてきた。中央に落ち込んでいかなければ同じ平行四辺形上を、落ち込んでいく場合には楕円形のようになっていくというイメージ。

tau=1、T=100のとき。

これは中心に円がある、と最初は見ていたが、これもずっと放っておけば中心に落ち込んでいくような気が今になるとしてくるぞ!よっしゃtau=1のまま、T=1000にしてやれ!

結果。


落ち込まんのかい!

tau=2, T=200を見てみる。

tauはuとvの振れ幅を大きくする的なイメージは間違っていないと思うわけで、だからある値を分け目にして落ち込んでいくかが決まってそうな気がするんだよなぁ~~~~するんだけどなぁ~~~~~~~~~~~

2017年12月27日水曜日

FitzHugh-Nagumo modelで遊ぶぞ!(強い意志)

・その後もういっかいそのまま走らせたら結構綺麗な線ができた件
 →毎回乱数を作らせているので、結果は毎回違っても問題はない。ただし期待していたものとはやはり異なる。

・cの値変更しても全然変化がない件
 →外部入力の値(i_input)をc倍するの忘れていた。追加。

・昨日bを0.8→0.2に変更してからずっとそのままな件
 →再度b=0.8にすると全ノード振動しなくなる。aも大きくすると振動しなくなる。そんなわけでa, bは振動を抑え込む方向に影響を持っていそうな感じ。

・uとvの初期値について考えたことなかった件
 →色々いじってみたけど最終的な振動の様子にはあまり影響がなさそう。ただ1-Nみたいに差が大きいと図によってスケールが異なって腹立つので、np.random.randn(N)にした。

・現状確認



螺旋の始まりを確かめに行こう
生まれた理由を確かめに行こう
さあ
響く音も放つ光も
何も無かった頃へ
繰り返すだけのこの現実ごと
偽れるように
抜け出せるように

今時間は止まって ほら
始まりのメロディーが聞こえる
(ジミーサムP The 9th より)

と、大好きな曲が脳裏をよぎる。螺旋、シュキ…。
螺旋の先を想像するとそこには無限があって、宇宙規模のはかなさを感じる。そういう意味でDNAが螺旋なのもこれはもう神の悪戯。そしてそれを歌詞に反映するジミーサムPは神。The 9thは神。

・閑話休題
 →ぼんやりと自分が期待していることはつまりu-v平面に複数種類のリミットサイクルを描いてほしいのだということがわかってきた。小さいサイクルは各振動子の自発振動で、外部入力がある閾値を超えた時に大きなリミットサイクルを描いてほしい。これは単振動子の時に外部入力Iがある値を越えると大きなサイクルを描いていて、それを下回ると小さなサイクルに帰着していたことと整合性がとれる。
  そういう目で結果をもう一度見てみると、現在は同じ周期で振動し続けている様子がみられることから、自発振動と外部入力のパワーバランスがおかしくてどっちかでしか振動していないんじゃないかと想像した。

  まず外部入力を消してみる。つまりc=0にした。結果。

さほど変化がない。つまり外部入力なんてあってなかったようなもんなんや!
  逆にcを大きくしていったんだが、c=100000とかになってもあまり変化がないので、どうやらほぼ自発振動しかしていなさそう。
  a, bについては結構いじったので、残るはtauとgamma。試しにgammaいじったら全部一点に帰着とかだったのですぐ戻した。
  ところで一般性を持たせたいので、パラメタいじるにしても何かの変数で表現出来た方がいいかと思うので、tau=Nにしてみた。


ああ!この形は!
この形は!一昨日見たぞ!振動子1つの時と同じ波形だ!

近いところまで来た気がする。むしろ今まで全然実装出来ていなかった感がすごい。
ここでやっとスタートなのでは?

といったところでお勤めの時間になりました。

2017年12月26日火曜日

FitzHugh-Nagumo modelでやっと遊んだ

とりあえずノードを5個に増やした。
C, Dはこんな感じ
C=np.array([[0,1,0,1,1],
            [1,0,1,1,1],
            [0,1,0,1,1],
            [1,1,1,0,0],
            [1,1,1,0,0]])
D=np.array([[0,4,0,5,5],
            [4,0,4,3,3],
            [0,4,0,5,5],
            [5,3,5,0,0],
            [5,3,5,0,0]])
そのうちの3種類をプロット。



""生き物の鼓動""感が出てた昨日からはだいぶ無機物的な波になってきたなという印象で面白みがない。ただキレイはキレイよね。
ノイズを加える。



ただ汚いだけや!

connection matrixが全部1だから均一になっているのではという仮説を立て、Cを乱数にしてみる。ついでにノードも10個へ。
Dは自分でいい感じで書いたマップにいい感じの長さを設定したもの。
(なおノイズは入れない)

きたねぇな…
上の図を眺めていると、node7の青線が同じ波形を繰り返すというよりはブレブレなことに気づいた。
node7のみ取り出してみる。


うーん。なんかコレジャナイ。
同じ波形がバラバラの周期で出てきたりすると嬉しいんだけどな~。
0~13秒の波形と、21秒~34秒の波形が似ているっちゃ似ているんだけど、なんか魅力を感じない。
u-v平面に至ってはもう平面を飛ぶハエって感じ。

遊びごたえが得られず消化不良のまま終わる。

FitzHugh-Nagumo modelで遊ぶという強い意志

昨日のおさらい。
頭から書いていったコードを整理する。
------------------------------------------------------
import numpy as np
import matplotlib.pyplot as plt

def floor(vector):
    shape=vector.shape
    vector=vector.reshape(-1)
    for i in range(vector.size):
        vector[i]=np.int(vector[i])
 
    vector.reshape(shape)
    return vector

def i_input(u, i):
    con=C[:, i]
    delay=D[:, i]
    temp=np.zeros(N)+u.shape[1]-1
    temp=floor(temp-delay)
    con[temp<0]=0
    temp[temp<0]=0
    pulse=np.zeros(N)
    for j in range(N):
        pulse[j]=u[j, temp[j]]
 
    iinput=np.dot(con, pulse)
    return iinput

def d_u(u, v):
    base=g(u[:, -1], v[:, -1])
    for i in range(u.shape[0]):
        base[i]+=i_input(u, i)
 
    return base

def g(u, v):
    return tau*(v+gamma*u-u**3/3)

def d_v(u, v):
    return h(u[:, -1], v[:, -1])

def h(u, v):
    return -(u-a-b*v)/tau

a=0.7
b=0.8
c=10
tau=1
gamma=1
N=2
C=np.ones((N, N))
D=np.ones((N, N))
for i in range(N):
    C[i, i]=0
    D[i, i]=0

t=0
T=20
dt=0.005

u=np.array([5,3]).reshape(-1, 1)
v=np.array([5,3]).reshape(-1, 1)

t+=dt
while t<T:
    du=d_u(u, v)
    dv=d_v(u, v)
    temp_u=u[:, -1]+du*dt
    temp_v=v[:, -1]+dv*dt
    u=np.c_[u, temp_u]
    v=np.c_[v, temp_v]
    t+=dt

fig=plt.figure()
ax=fig.gca()
ax.plot(np.arange(0, u.shape[1], 1)*dt, u[0, :], c='g', label='u1')
ax.plot(np.arange(0, v.shape[1], 1)*dt, v[0, :], c='b', label='v1')
ax.plot(np.arange(0, u.shape[1], 1)*dt, u[1, :], c='m', label='u2')
ax.plot(np.arange(0, v.shape[1], 1)*dt, v[1, :], c='r', label='v2')
ax.legend()
plt.show()
fig2=plt.figure()
ax2=fig2.gca()
ax2.plot(u[0, :], v[0, :], c='g', label='node1')
ax2.plot(u[1, :], v[1, :], c='m', label='node2')
ax2.legend()
plt.show()
------------------------------------------------------
(なおmatplotlibの使い方がいまだによくわかっていないので、やみくもにやっていい感じで表示してくれたものをとりあえずそのまま利用しているため、ラストがきたない)

bを半分にしたら振動はするけどu-v平面での回転が逆では、という話をしていた。
なおuとvがマイナスに突入することにも疑問を抱いていたが、それは問題ない気がしてきた。というのも振動子1つの場合の図でも突入している故。考えてみれば偶数乗の項が無いので、むしろゼロを挟む感じで振動するのが自然なのかもしれない。

で、間違えてuとv逆にしてたりしない?と思い式を確認したところ、参照してたレビューの式が間違ってました。これは悲しい。

修正したものが以下。
------------------------------------------------------
def d_u(u, v):
    base=g(u[:, -1], v[:, -1])
    for i in range(u.shape[0]):
        base[i]+=i_input(u, i) #これが加算か減算かは要確認
 
    return base

def g(u, v):
    return tau*(-v+gamma*u-u**3/3) #vの前にマイナス

def d_v(u, v):
    return h(u[:, -1], v[:, -1])

def h(u, v):
    return -(-u-a+b*v)/tau #uの前にマイナス、b*vをプラスへ
------------------------------------------------------
なおd_uで外部からの入力に関しては加減のどちらが正しいのかわからん。感覚的には加算なのでプラスに変更しましたがこれも確認が必要。

パラメタを
a=0.7, b=0.2, c=10, tau=1, gamma=1, N=2
C=[[0, 1], [1, 0]]
D=[[0, 1], [1, 0]]

T=20
dt=0.005
u=[5;3]
v=[5;3]

とした実行結果。



素敵や。

さて今後は
・ノードを増やす
・ノイズを加える
・C, Dに乱数を入れてみる
といったことに着手しようと思うが、この後ろに続けるとぐちゃぐちゃするのでいったんここまで。

2017年12月25日月曜日

FitzHugh-Nagumo modelで遊びたかった

 これを読んでいたら後半でモデリングの話が出現。その中でもFitzHugh-Nagumo modelは扱う式が少ないので実装できる気がしたのでやってみた。
 ググって出てきたこちらを参考に、まずは振動子が1つの場合をば。

---------------------------------------------------------
import numpy as np
import matplotlib.pyplot as plt

a=0.7
b=0.8
c=10
I=0.33
T=10
dt=0.01

def d_u(u, v):
    return c*(-v+u-u**3/3+I)

def d_v(u, v):
    return u-b*v+a

u=[1,]
v=[1,]

t=0
t+=dt
while t<T:
    du=d_u(u[-1], v[-1])
    dv=d_v(u[-1], v[-1])
    u.append(u[-1]+dt*du)
    v.append(v[-1]+dt*dv)
    t+=dt

plt.plot(np.arange(0, len(u), 1)*dt, u, c='b')
plt.plot(np.arange(0, len(v), 1)*dt, v, c='r')
plt.show()

plt.plot(u, v, c='g')
plt.show()
---------------------------------------------------------


リミットサイクル的な図に。

。。。えっ?
 前述の参考にしたサイトには「I を約 0.342 より 大きくすると (subcritical な) Hopf 分岐が起こり、周期的に変動する解が得られます。」と記載されている。上ではI=0.33としているにも関わらず周期的に変動している。合わない。

 数値シミュレーションの関係と推測し、dt=0.01からdt=0.005に小さくして再度実行。




数値シミュレーションの都合だった模様です。

同様にして次はI=0.35、dt=0.005として再度実行。




こちらはまぁさっき見たのと同じですな。

 で、今度はこの振動子を増やす。まずは振動子の数は2つ。コネクションは1、delayも1とテキトーである。その他a, b, cとかタウとかガンマとか、パラメータのバランスをいい感じでとらないと発散しそうだなと思いつつ、まずは実装する。
---------------------------------------------------------
import numpy as np
import matplotlib.pyplot as plt

a=0.7
b=0.8
c=10

N=2
C=np.ones((N, N))
D=np.ones((N, N))
for i in range(N):
    C[i, i]=0
    D[i, i]=0

def floor(vector):
    shape=vector.shape
    vector=vector.reshape(-1)
    for i in range(vector.size):
        vector[i]=np.int(vector[i])
 
    vector.reshape(shape)
    return vector

def i_input(u, i):
    con=C[:, i]
    delay=D[:, i]
    temp=np.zeros(N)+u.shape[1]-1
    temp=floor(temp-delay)
    con[temp<0]=0
    temp[temp<0]=0
    pulse=np.zeros(N)
    for j in range(N):
        pulse[j]=u[j, temp[j]]
 
    iinput=np.dot(con, pulse)
    return iinput

def d_u(u, v):
    base=g(u[:, -1], v[:, -1])
    for i in range(u.shape[0]):
        base[i]+=i_input(u, i)
 
    return base

tau=1
gamma=1
def g(u, v):
    return tau*(v+gamma*u-u**3/3)

def d_v(u, v):
    return h(u[:, -1], v[:, -1])

def h(u, v):
    return -(u-a-b*v)/tau

t=0
T=10
dt=0.005

u=np.array([1,1]).reshape(-1, 1)
v=np.array([1,1]).reshape(-1, 1)

t+=dt
while t<T:
    du=d_u(u, v)
    dv=d_v(u, v)
    temp_u=u[:, -1]+du*dt
    temp_v=v[:, -1]+dv*dt
    u=np.c_[u, temp_u]
    v=np.c_[v, temp_v]
    t+=dt

plt.plot(np.arange(0, T, dt), u[0, :], c='g')
plt.plot(np.arange(0, T, dt), v[0, :], c='r')
plt.show()
---------------------------------------------------------

後半のvの伸びがすごい。
嫌な予感を抱きながらT=15にしてみる。
ダメそう。
実際T=20にしたら悲しみのoverflow。
現時点ではさっぱりパラメータの意義を理解していないので、その辺りを式眺めながら考えていい感じのパラメータ組み合わせを探すのが今後か。お手上げなら絨毯爆撃で。

それにしても前半の1振動子の時の図を見ると、波形から""生き物の鼓動""が感じられて素敵(※一大学生の感想)。蔵本モデルは単純な分波形が無機物的なので、その差を感じられたのが今年のクリスマスプレゼントでしたとさ。


ところで元のレビューのFitzHugh-Nagumoモデルの式ちょいちょい間違ってるよね?


(12/25 17:35追記)
vを小さくするということで、まずはbを半分にしてみたら早速振動してくれた。

ただしその意味するところは不明である。
それとリミットサイクルの回転方向が前半のものと逆というのも不自然。membrane potentialがギュインと上がった直後にrecovery potentialがギュインと上がってもとに戻る、つまりu-v平面でいえば反時計回りの方が自然である。
さらにいえばuもvも負の値に突入してるのもおかしい気がする。ここで負になってることが反時計回りとかとも関係してそうな気がする。u**3とかあるし。

つまりやっぱりわからん。。。
今後2よりも多くの振動子に増やしたいので、あんまりテキトーにその場しのぎしても後で結局戻ってくることになりそうですな。