Pythonでライフゲーム! 人工生命入門

皆さんライフゲームって聞いたことありますか?

ん?ゲーム?と思われた方もいるかもしれませんが、ライフゲームって一般的なゲームとは違います!私たちは全く操作しません。ただただ画面を眺めて、それぞれの人工生命の遷移を楽しむだけなんです。でも、仕組みを知ったうえで見てみると、とても神秘的で魅せられるものがあります!

主なルールは4つほどしかないのですが、全体の振る舞いは何とも不思議で意志を持っているような、まさに生命のように感じます。たった4つほどのルールしかないのにです!これは、創発といわれ、複雑系において大変重要な要素を成しています。

ということで、今回は、Pythonを使用してライフゲームを実装し、創発により引き起こされるその神秘的なものに魅せられに行きましょう!

ライフゲームとは

ライフゲームとは生命の
1.誕生しない
2.誕生(生)
3.生存
4.淘汰(死)
の4状態をドットで表し、特定のルールの下でシミュレーションしたものです。それぞれのルールについて詳しく見てみましょう。

上の図にはマスが9つあります。これは、ドットの誕生や淘汰を決定する単位になります。この基本単位の中心のマスが、周囲のパターンによって誕生(マスが黒いドットになる)したり淘汰(マスが白抜きになる)されたりします。

ライフゲームのたった4つのルール1:誕生しない

注目しているセルに生命が存在しないとき、周囲に存在する生命の個体数が、1,2,4,5,6,7,8のとき、生命は誕生しません。

誕生できないパターン例

※ルールの説明の図では遷移後にも周りの生命の状態が同じになっていますが、実際は周囲の生命が次状態で生きているとは限りませんし、また、誕生していないとも言えません。説明の便宜上、そのように示させていただきました。

ライフゲームのたった4つのルール2:誕生

注目しているマスに生命が存在していないとき、次状態で生命が誕生するのは、注目しているマスの周囲に生命が3つ存在しているときのみです。

次状態で誕生する例

ライフゲームのたった4つのルール3:生存

注目しているマスに生命がいる状態(黒塗のドットあり)のとき、周囲の8つのマスのうち、2または3つのマスに生命が存在している場合、その注目しているマスの生命は状態が1ステップ遷移しても生存することができます。

次状態でも生存するパターン例

上のようなパターンの時、人工生命は生存していることができます。3つか4つ個体が存在している状態がちょうど居心地が良いという感じですね。

ライフゲームのたった4つのルール4:淘汰

注目しているマスの周囲のマスで生命が存在している数が、1, 4, 5, 6, 7, 8のとき、その注目したマスの生命は淘汰(死)されます。

次状態で淘汰されるパターンの例

周囲に生命がいない場合や自分以外に1つしかいない場合は、生きていけず、淘汰されます。つまり、過疎すぎてやっていけないのです。

また反対に、4つ以上存在している場合には、弱肉強食の世界で負けるので淘汰されます(という解釈ができます)。

Pythonでライフゲームを実装!

Pythonで実装するにあたり、ポイントを以下に示します。

  1. 周囲は一回り分だけゼロパディングする。またそこで生命が誕生することはない。
  2. 二つの行列を定義し、一方の行列にはゼロパディング部分を除いた領域にランダムに生命を誕生させる。
  3. 一方の行列に3×3のフィルターを適用するイメージで、順に計算し他方の行列に結果を格納。
    ※面全体の計算が終わるまで同じ行列に上書きできません!
  4. 注目しているマスの0, 1を判定&条件分岐し、1ならば、周囲の個体数に応じて生存と淘汰の状態のプログラムを、0ならば誕生しない状態と、誕生する状態のプログラムを書く。

1は一番端の個体の計算をするために必要となります。以下にプログラムを示します。

# ライブラリのインポート
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation    # アニメーションを作成します
#from matplotlib.animation import PillowWriter   # gifファイル書き出しに必要となる場合があります

# 上で説明したことを実行する関数を定義します。
# Nは生命が生存可能なマスの辺の長さです。ゼロパディングを考慮するために必要です。
# そのため、NumPy配列で定義されたcellは(N+2, N+2)の大きさになります。
def f(N, cell):
  cell_new = cell.copy()   # 1ステップ状態遷移後の結果を格納する配列を用意します。
  for i in range(1, cell.shape[0]-1):  # 周囲のゼロパディングを考慮して注目セルのx座標を遷移させます。
    for j in range(1, cell.shape[1]-1):  # 周囲のゼロパディングを考慮して注目セルのy座標を遷移させます。
      if cell[i, j] == 1: 
        N_shu = cell[i-1:i+2, j-1:j+2].sum() - 1 # 周囲の1の個数(自身が足されるため1引きます)
        if N_shu==2 or N_shu==3:
          cell_new[i, j] = 1
        else:
          cell_new[i, j] = 0
      else:
        N_shu = cell[i-1:i+2, j-1:j+2].sum()
        if N_shu==3:
          cell_new[i, j] = 1
        else:
          cell_new[i, j] = 0
          
  return cell_new

#アニメーション生成の前準備
fig = plt.figure(figsize=(15, 15))
#表示される図の目盛りを非表示にします。
plt.tick_params(labelbottom=False,
                labelleft=False,
                labelright=False,
                labeltop=False)
ims = []  # アニメーション作成に使用します。
N=100   # この場合、人工生命が存在しうる領域は100x100です。
cell = np.zeros((N+2, N+2), dtype=np.int)  # cellを定義します。
mat = np.random.randint(0, 2, size=(N, N), dtype=np.int)  # 0と1の一様分布から初期値をランダムに生成します。
cell[1:-1, 1:-1] = mat   # ランダムに生成した値をcellの生命が存在可能な領域に代入します。

# ここからがメインのライフゲームです!
for _ in range(100):   # 100ステップの状態遷移を実行します。
  cell= f(N, cell)
  # 以下の2行はアニメーション作成の準備です。
  im = plt.imshow(cell, cmap=plt.cm.gray_r, animated=True)
  ims.append([im]) # imを[]で囲って追加しないとアニメーション作成時にエラーが起こります。

#アニメーションの生成をします。
ani = animation.ArtistAnimation(fig, ims,interval=100)
#GIFファイルとして保存します。
ani.save('output.gif', writer='imagemagick')

どうでしょうか?できましたか?環境によってはアニメーション作成でエラーが起こるようです。調べるとバグらしいですね。これは、ググって対処していただければと思います。

以下に、いくつか結果のGif画像を示しますね。

まずは、10×10で100ステップの状態遷移を行ったときの例です。ライフゲームには、特定のパターンになると次状態で変化しない現象が起こります。

つぎに、50×50で100ステップ行ったときの例です。

これは、100×100で300ステップ行ったときの例です。

このライフゲームでは、状態が変化しないパターンや、発信器のように周期的なパターンを同じところで繰り返すなどの面白い現象がありますが、ここでは割愛します。

この3つの例は、初期値がランダムでした。では、規則的な初期値を与えるとどうなるでしょうか?例を一つ示したいと思います。上のプログラムの

mat = np.random.randint(0, 2, size=(N, N), dtype=np.int)  # 0と1の一様分布から初期値をランダムに生成します。
cell[1:-1, 1:-1] = mat   # ランダムに生成した値をcellの生命が存在可能な領域に代入します。

を以下のように変更してみてください。

cell[:, [15, 17,19, -16, -18, -20]] = 1
cell[[15, 17,19, -16, -18, -20], :] = 1

これは、初期状態を以下の図に示すように規則的にする操作です。

規則的な初期状態の例

このような初期状態にすると、以下のGifで示すような状態遷移をします。とても美しいですよね。

ライフゲームについて調べると、たったこれだけのミクロの個体に対するルールのみで、マクロの振る舞いが驚くほど多彩で美しいです。気になる方は調べてみてください!

汎用人工知能と創発

当サイトは汎用人工知能をテーマとすることが目標なので、ここではライフゲームを代表とする創発と、汎用人工知能について考察してみたいと思います。

創発とは

創発とはwikipediaによると、

創発(そうはつ、英語:emergence)とは、部分の性質の単純な総和にとどまらない性質が、全体として現れることである。局所的な複数の相互作用が複雑に組織化することで、個別の要素の振る舞いからは予測できないようなシステムが構成される。

https://ja.wikipedia.org/wiki/%E5%89%B5%E7%99%BA

とされており、情報工学における創発に関しては、以下のように記載されています。

コンピュータサイエンスの分野では、シミュレーションによって創発現象を人工的に作り出すことが研究されている。代表的な例は、ニューラルネットワーク遺伝的アルゴリズム群知能などである。また近年、ウェブを活発な相互作用が行われる創発システムとして捉えなおす動きがある。

https://ja.wikipedia.org/wiki/%E5%89%B5%E7%99%BA

汎用人工知能とは

汎用人工知能とは未だ実現できていない、いわゆる強いAIのことです。多くの人工知能研究者が知の探究として最初に興味を持つきっかけになることが多いのではないでしょうか?

人間の脳には、感情生成に関与している扁桃体や、記憶に関与している海場などの大脳辺縁系や、高度知能にかかわる大脳新皮質、運動制御などにかかわっている小脳など、様々な器官が存在しています。いまだ明らかになっていない部分も多いですが、脳の情報処理は神経細胞というミクロな単純な活動がマクロになることで、人間のような高度知能を持つ脳を実現していると考えることができます。つまり、創発が大いに関与していると考えられるのではないでしょうか?

実際には、汎用人工知能とは言わなくても、人工知能分野では創発からアイディアを受けいるものもありますし、今後の人工知能発展にどのように関与していくのか注目したいです。

Follow me!