サメ–小魚モデルの作成
今回はサメ–小魚モデルを実装してみた.
これはmiura & sakurama (2017)を参考に知ったモデルをPythonで組んでみたモデルである.
サメと小魚の動きがシミュレーションできて面白い.サメの挙動がおかしくなる部分があるが,それは今後の課題にしたい.
コードは下記.
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
# エージェントクラスの定義
class Agent:
def __init__(self, x, y, vx, vy, speed, fov, agent_type):
self.x = x # x座標
self.y = y # y座標
self.vx = vx # x方向の速度成分
self.vy = vy # y方向の速度成分
self.speed = speed # 移動速度
self.fov = fov # 視野(半径)
self.agent_type = agent_type # エージェントの種類('Shark'または'Fish')
def update_direction(self, agents):
# 自分以外のエージェントを取得
other_agents = [agent for agent in agents if agent != self]
if not other_agents:
return
# 他のエージェントとの距離を計算
distances = []
for agent in other_agents:
dx = agent.x - self.x
dy = agent.y - self.y
# 周期境界条件の適用
dx = dx - 100 if dx > 50 else dx + 100 if dx < -50 else dx
dy = dy - 100 if dy > 50 else dy + 100 if dy < -50 else dy
distance = np.hypot(dx, dy)
if distance <= self.fov:
distances.append((distance, agent, dx, dy))
if not distances:
# 視野内にエージェントがいない場合
return
# 最も近いエージェントを取得
distances.sort(key=lambda x: x[0])
nearest = distances[0]
nearest_agent = nearest[1]
dx = nearest[2]
dy = nearest[3]
# 行動ルールの実装
if self.agent_type == 'Shark':
if nearest_agent.agent_type == 'Fish':
# 小魚を追いかける
angle = np.arctan2(dy, dx)
self.vx = np.cos(angle)
self.vy = np.sin(angle)
elif nearest_agent.agent_type == 'Shark':
# 他のサメから逃げる
angle = np.arctan2(-dy, -dx)
self.vx = np.cos(angle)
self.vy = np.sin(angle)
elif self.agent_type == 'Fish':
if nearest_agent.agent_type == 'Shark':
# サメから逃げる
angle = np.arctan2(-dy, -dx)
self.vx = np.cos(angle)
self.vy = np.sin(angle)
# 小魚は他の小魚から逃げない
def move(self):
# エージェントの位置を更新
self.x += self.vx * self.speed
self.y += self.vy * self.speed
# 周期境界条件の適用
self.x = self.x % 100
self.y = self.y % 100
# シミュレーションのパラメータ設定
num_sharks = 5 # サメの数
num_fish = 100 # 小魚の数
speed_shark = 1.5 # サメの速度
speed_fish = 1.0 # 小魚の速度
fov_shark = 15 # サメの視野
fov_fish = 10 # 小魚の視野
num_steps = 200 # シミュレーションのステップ数
agents = []
# サメエージェントの初期化
for _ in range(num_sharks):
x = np.random.uniform(0, 100)
y = np.random.uniform(0, 100)
angle = np.random.uniform(0, 2*np.pi)
vx = np.cos(angle)
vy = np.sin(angle)
agent = Agent(x, y, vx, vy, speed_shark, fov_shark, 'Shark')
agents.append(agent)
# 小魚エージェントの初期化
for _ in range(num_fish):
x = np.random.uniform(0, 100)
y = np.random.uniform(0, 100)
angle = np.random.uniform(0, 2*np.pi)
vx = np.cos(angle)
vy = np.sin(angle)
agent = Agent(x, y, vx, vy, speed_fish, fov_fish, 'Fish')
agents.append(agent)
# グラフの設定
fig, ax = plt.subplots(figsize=(6,6))
ax.set_xlim(0, 100)
ax.set_ylim(0, 100)
ax.set_xlabel('X Coordinate') # X座標
ax.set_ylabel('Y Coordinate') # Y座標
ax.set_title('Shark–Fish Model Simulation') # サメ–小魚モデルのシミュレーション
# サメと小魚のプロットを初期化
shark_plot, = ax.plot([], [], 'bo', markersize=8, label='Shark') # サメ
fish_plot, = ax.plot([], [], 'go', markersize=4, label='Fish') # 小魚
ax.legend()
# 初期化関数
def init():
shark_plot.set_data([], [])
fish_plot.set_data([], [])
return shark_plot, fish_plot
# アニメーション関数
def animate(i):
# エージェントの方向を更新
for agent in agents:
agent.update_direction(agents)
# エージェントの位置を更新
for agent in agents:
agent.move()
# プロットデータの更新
shark_x = [agent.x for agent in agents if agent.agent_type == 'Shark']
shark_y = [agent.y for agent in agents if agent.agent_type == 'Shark']
fish_x = [agent.x for agent in agents if agent.agent_type == 'Fish']
fish_y = [agent.y for agent in agents if agent.agent_type == 'Fish']
shark_plot.set_data(shark_x, shark_y)
fish_plot.set_data(fish_x, fish_y)
return shark_plot, fish_plot
# アニメーションの作成
ani = animation.FuncAnimation(fig, animate, frames=num_steps, init_func=init, interval=100, blit=True)
# アニメーションをGIFとして保存
ani.save('shark_fish_simulation.gif', writer='pillow')
参考文献
- 三浦, 政司., & 桜間, 一徳. (2017). マルチエージェントシミュレーションをはじめてみよう. システム/制御/情報, 61(5), 169–174. https://doi.org/10.11509/isciesci.61.5_169