「しかのこのこのここしたんたん」を生成する有限状態マルコフ言語をpythonで再現してみる。
「しかのこのこのここしたんたん」というマルコフ連鎖
先日、youtubeのホーム画面で次の動画を見かけました。
その時はサムネを見ただけで内容を確認しなかったのですが、ふとこの動画のことを思い出して、自分で「しかのこのこのここしたんたん」を生成するマルコフ連鎖を考えてみようと思い立ちました。
有限状態マルコフ文法
最初、「状態遷移図1」のような文法を考えました。
しかし、これはあまりに冗長です。
s1.s2.s3とs4.s5.s6が互いに対称的であること。
「たん」を生成するs1とs6は、「たん」を生成する以外に分岐が存在しないこと。
上の二つを考慮して、次のような状態遷移図を考えました。
「状態遷移図2」をpythonで再現する。
import random
list = ['しか', 'の', 'こ', 'し' ,'たん']
def r1():
r1 = random.randint(1,2)
return r1
num_list = [1, 2, 3]
def r2():
r2 = random.choice(num_list)
return r2
def s2():
global ch
global trans
while r1() == 1:
ch += list[4]
else:
ch += list[0]
while r2() == 1 or r2() == 2:
if r1() == 1:
ch += list[2]
continue
else:
ch += list[1]
continue
else:
ch += list[3]
まず「しか」「の」「こ」「し」「たん」という四つの要素を持ったlistを用意しました。
list = ['しか', 'の', 'こ', 'し' ,'たん']
list2 = ['start->', 's1->', 's2->']
つぎに、「1or2をランダムに生成する関数」と「1or2or3をランダムに生成する関数」を定義しました。
num_list = [1, 2, 3]
def r2():
r2 = random.choice(num_list)
return r2
「1or2をランダムに生成する関数」を呼び出し、1が出続ける限り「たん」を生成し、2が出たときに「しか」を生成してs2へ遷移するようにしました。
while r1() == 1:
trans += list2[0]
ch += list[4]
else:
ch += list[0]
s2へ遷移したとき、「1or2or3をランダムに生成する関数」が「1or2」を生成したとき、再び「1or2をランダムに生成する関数」を呼び出し、それぞれ1と2が出たとき「の」と「こ」を生成するようにしました。
また、「1or2or3をランダムに生成する関数」が3を生成したとき「し」を生成し、初期状態に戻すようにしました。
while r2() == 1 or r2() == 2:
if r1() == 1:
trans += list2[2]
trans += list2[2]
ch += list[2]
continue
else:
trans += list2[2]
trans += list2[2]
ch += list[1]
continue
else:
ch += list[3]
いままでの一連の処理を三回繰り返せば、「しかのこのこのここしたんたん」が1,417,176分の1の確率で生成されることになります。
最後に
これを自動化し、いくつかのグラフを付したアプリを紹介します。
このアプリでは一番上の段に左から「生成された連鎖の大きさを10ごとに区切った棒グラフ」と「関数の実行回数1回目・二回目・三回目それぞれまでに発生した遷移の数の円グラフ」と「連鎖の長さの確率密度関数」が並び、二段目には生成された連鎖の遷移の順番を表示し、三段目には生成された連鎖そのものと状態遷移図が載っています。
この記事が気に入ったらサポートをしてみませんか?