生態系のモデリング
生態系は食べて食べられての食物連鎖により回っている.
そんな過程をモデリングするプランクトン生態系モデルというモデルを見つけたので実装してみる.
コードは下記.
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
from matplotlib.colors import ListedColormap
# シミュレーションパラメータ
WIDTH = 100 # 水槽の幅
HEIGHT = 100 # 水槽の高さ
NUM_STEPS = 200 # シミュレーションのステップ数
# プランクトンの種類を定義
EMPTY = 0 # 空のセル
PLANT = 1 # 植物プランクトン
ANIMAL = 2 # 動物プランクトン
# エネルギーパラメータ
INITIAL_ANIMAL_ENERGY = 5 # 動物プランクトンの初期エネルギー
ENERGY_GAIN_FROM_EATING = 4 # 植物プランクトンを食べたときのエネルギー増加
ENERGY_COST_OF_MOVEMENT = 1 # 移動時のエネルギー消費
ENERGY_THRESHOLD_FOR_REPRODUCTION = 8 # 繁殖に必要なエネルギー閾値
# 密度制限(植物プランクトンが死ぬ閾値)
PLANT_OVERPOPULATION_THRESHOLD = 4
# グリッドの初期化
grid = np.zeros((HEIGHT, WIDTH), dtype=int)
# 植物プランクトンを少なめに初期配置
plant_grid = np.random.choice([EMPTY, PLANT], size=(HEIGHT, WIDTH), p=[0.95, 0.05])
# 動物プランクトンを少なめに初期配置
animal_grid = np.zeros((HEIGHT, WIDTH), dtype=int)
animal_positions = np.random.choice([EMPTY, ANIMAL], size=(HEIGHT, WIDTH), p=[0.95, 0.05])
animal_grid += animal_positions
animal_energy = np.where(animal_grid == ANIMAL, INITIAL_ANIMAL_ENERGY, 0)
grid += plant_grid
grid += animal_grid
# カラーマップの定義(0:空、1:植物プランクトン、2:動物プランクトン)
cmap = ListedColormap(['black', 'green', 'red'])
# 可視化のためのセットアップ
fig = plt.figure(figsize=(6,6))
ims = []
# シミュレーション開始
for step in range(NUM_STEPS):
new_grid = grid.copy()
new_animal_energy = animal_energy.copy()
# 植物プランクトンの更新
for y in range(HEIGHT):
for x in range(WIDTH):
if grid[y, x] == PLANT:
# 周囲の植物プランクトンの数をカウント
neighbors = grid[max(y-1,0):min(y+2,HEIGHT), max(x-1,0):min(x+2,WIDTH)]
num_plants = np.count_nonzero(neighbors == PLANT) - 1 # 自分自身を除く
if num_plants >= PLANT_OVERPOPULATION_THRESHOLD:
new_grid[y, x] = EMPTY # 過密のため死亡
elif grid[y, x] == EMPTY:
# 一定の確率で新たに植物プランクトンが発生
if np.random.rand() < 0.01: # 発生確率を下げる
new_grid[y, x] = PLANT
# 動物プランクトンの更新
for y in range(HEIGHT):
for x in range(WIDTH):
if grid[y, x] == ANIMAL:
# エネルギーが0以下なら死亡
if animal_energy[y, x] <= 0:
new_grid[y, x] = EMPTY
new_animal_energy[y, x] = 0
continue
# 移動先をランダムに選択
dirs = [(-1,0), (1,0), (0,-1), (0,1)]
np.random.shuffle(dirs)
moved = False
for dy, dx in dirs:
ny, nx = (y + dy) % HEIGHT, (x + dx) % WIDTH
if grid[ny, nx] == PLANT:
# 植物プランクトンを食べる
new_grid[ny, nx] = ANIMAL
new_animal_energy[ny, nx] = animal_energy[y, x] + ENERGY_GAIN_FROM_EATING - ENERGY_COST_OF_MOVEMENT
new_grid[y, x] = EMPTY
new_animal_energy[y, x] = 0
moved = True
break
elif grid[ny, nx] == EMPTY:
# 空きマスに移動
new_grid[ny, nx] = ANIMAL
new_animal_energy[ny, nx] = animal_energy[y, x] - ENERGY_COST_OF_MOVEMENT
new_grid[y, x] = EMPTY
new_animal_energy[y, x] = 0
moved = True
break
if not moved:
# 移動できない場合、エネルギーだけ消費
new_animal_energy[y, x] -= ENERGY_COST_OF_MOVEMENT
# 繁殖
if new_animal_energy[y, x] >= ENERGY_THRESHOLD_FOR_REPRODUCTION:
# 周囲の空きマスを探す
for dy, dx in dirs:
ny, nx = (y + dy) % HEIGHT, (x + dx) % WIDTH
if new_grid[ny, nx] == EMPTY:
new_grid[ny, nx] = ANIMAL
new_animal_energy[ny, nx] = new_animal_energy[y, x] // 2
new_animal_energy[y, x] = new_animal_energy[y, x] // 2
break
# グリッドとエネルギーの更新
grid = new_grid
animal_energy = new_animal_energy
# 可視化
im = plt.imshow(grid, animated=True, cmap=cmap, vmin=0, vmax=2)
ims.append([im])
# GIFの生成(フレームレートを調整)
ani = animation.ArtistAnimation(fig, ims, interval=200, blit=True)
ani.save('plankton_simulation.gif', writer='pillow')
plt.show()
参考文献
- MAS コミュニティ プランクトン生態系モデルhttps://mas.kke.co.jp/model/plankton/