自己組織化臨界のモデル
砂山崩しというモデルを見つけた.(開発者の名前を取って,BTW モデルとも言われるそうだ.)
この実装をしてみた.条件は下記である.
ブロック追加
• 毎回、ランダムに1つのマス目が選ばれ、そこに1つのブロックが追加される。
• 既にブロックが積まれているマス目にブロックが落ちると、上に積み重なる。
飛散
• 1つのマス目に4つのブロックが積まれると、その4つのブロックが上下左右の4つの隣接マス目に分散される。
• 分散先のマス目に既に3つのブロックがある場合、さらに分散が発生する可能性がある。
コードは下記.
import numpy as np
import matplotlib.pyplot as plt
import imageio
import os
import random
# シミュレーションパラメータ
GRID_SIZE = 20 # グリッドのサイズ
NUM_STEPS = 1000 # シミュレーションのステップ数
GIF_INTERVAL = 5 # GIFにフレームを追加する間隔
# 出力ディレクトリ
OUTPUT_DIR = "sandpile_frames"
if not os.path.exists(OUTPUT_DIR):
os.makedirs(OUTPUT_DIR)
# 初期化
grid = np.zeros((GRID_SIZE, GRID_SIZE), dtype=int)
frames = []
def topple(grid):
"""グリッド上のトップリング処理を実行する。"""
unstable = grid >= 4
while np.any(unstable):
# トップリングするセルの座標を取得
topple_cells = np.argwhere(unstable)
for cell in topple_cells:
i, j = cell
grid[i, j] -= 4
# 上下左右にブロックを追加
if i > 0:
grid[i-1, j] += 1
if i < GRID_SIZE - 1:
grid[i+1, j] += 1
if j > 0:
grid[i, j-1] += 1
if j < GRID_SIZE - 1:
grid[i, j+1] += 1
unstable = grid >= 4
# カラーマップの設定
cmap = plt.cm.viridis
norm = plt.Normalize(vmin=0, vmax=4)
for step in range(NUM_STEPS):
# ランダムにセルを選んでブロックを追加
i = random.randint(0, GRID_SIZE - 1)
j = random.randint(0, GRID_SIZE - 1)
grid[i, j] += 1
# トップリング処理
topple(grid)
# GIFに追加するフレームを取得
if step % GIF_INTERVAL == 0:
plt.figure(figsize=(6,6))
plt.imshow(grid, cmap=cmap, norm=norm)
plt.title(f"Step: {step}")
plt.axis('off')
frame_path = os.path.join(OUTPUT_DIR, f"frame_{step}.png")
plt.savefig(frame_path)
plt.close()
frames.append(frame_path)
# GIFの作成
gif_path = "sandpile_simulation.gif"
with imageio.get_writer(gif_path, mode='I', duration=0.1) as writer:
for frame_path in frames:
image = imageio.imread(frame_path)
writer.append_data(image)
# フレーム画像の削除(オプション)
for frame_path in frames:
os.remove(frame_path)
print(f"シミュレーションが完了しました。GIFファイル: {gif_path}")
参考文献
- MAS コミュニティ 砂山くずしモデル https://mas.kke.co.jp/model/sand_model/