2
3

敵と味方が戦うドローンの群れのシミュレーション。JITデコレーターの高速化で大規模化を実現。

Last updated at Posted at 2024-07-26

8bcffd41-8a10-4d2f-b426-0bf1c101b479.png

「メモリ空間のボイドたち」

序章
未来には、無限の情報とデータが流れる「メモリ空間」と呼ばれる広大な領域が存在していた。この空間は、数え切れないほどのデジタル生物たち、すなわち「ボイドたち」で満ちていた。ボイドたちは、メモリ空間の中で情報を運び、処理し、調和を保つために複雑なルールに従っていた。

メモリ空間のルール
メモリ空間でのボイドたちは、三つの基本的なルールに従って行動していた。これらのルールは、彼らがメモリ空間をスムーズに機能させるための鍵となっていた。

分離(Separation):
ボイドたちは、互いに衝突しないように、一定の距離を保っていた。もし他のボイドが近くに来ると、ボイドたちはその位置から遠ざかるように動き、データの衝突やエラーを防いでいた。これは、メモリ空間が整然と保たれるために不可欠なルールだった。

整列(Alignment):
ボイドたちは、近くのボイドたちの動きに合わせて自分の速度を調整していた。これにより、ボイドたちは協調して働くことができ、データの流れがスムーズに保たれていた。整列の力によって、メモリ空間全体が効率的に動作していた。

結束(Cohesion):
ボイドたちは、お互いの位置を見て、集団全体が一つの塊として動くようにしていた。これにより、データの同期が取れ、メモリ空間内の情報が正確に処理されていた。結束の力は、ボイドたちの連携を強化し、全体の協力を促進していた。

敵の出現
しかし、メモリ空間には「敵ボイド」と呼ばれる存在が現れることがあった。これらの敵ボイドは、メモリ空間の秩序を乱し、情報の流れを妨げる存在だった。敵ボイドが近づくと、メモリ空間のボイドたちは、分離のルールを強化し、敵との距離を広げるために動き出した。

敵ボイドは、データの誤りや衝突を引き起こし、メモリ空間全体の動作を混乱させることを目的としていた。ボイドたちは、整列と結束の力を駆使して、敵ボイドの影響を最小限に抑え、メモリ空間の秩序を維持しようとした。

メモリ空間の戦い
ある日、メモリ空間は大規模な敵ボイドの攻撃に直面した。敵ボイドたちは、メモリ空間の中心部に向かって一斉に進攻し、情報の流れを混乱させようとした。ボイドたちは、これまでの経験とルールを駆使して、敵ボイドに立ち向かうことに決めた。

ボイドたちは、分離の力で敵ボイドと距離を取り、整列の力で全体の動きを一致させ、結束の力で集団全体を一つに保ち続けた。敵ボイドが引き起こす誤りや衝突に対抗するために、ボイドたちは最大限の努力を注いだ。

結末
戦いが続く中、ボイドたちはお互いの位置と速度を見ながら、迅速に対応し、敵の攻撃を巧妙にかわしていった。整列の力で敵の動きに合わせ、結束の力で集団を一つに保ち続けた。その結果、ボイドたちは敵ボイドの攻撃を打ち払い、メモリ空間の秩序を取り戻すことができた。

メモリ空間は再び平穏を取り戻し、ボイドたちはその秩序と調和を維持し続けた。彼らの行動は、情報処理の精度と効率を保つための模範となり、メモリ空間の中での平和を守り続けるのだった。

敵と味方が戦う群れのシミュレーションを作成するには、ボイドモデルに敵と味方の2種類のボイドを導入し、それぞれに異なる行動規則を適用する必要があります。以下のコードでは、敵と味方のボイドをシミュレートし、戦う様子を可視化します。敵はプレイヤーのボイドを追いかけ、味方は敵から逃げるという基本的な動作を実装しています。

JIT(Just-In-Time)コンパイラを使ってPythonコードの速度を向上させる方法としては、Numbaライブラリが有名です。Numbaは、Pythonコードの特定の部分をコンパイルして高速化するためのツールです。

update_boids関数にJITデコレーターを追加して、高速化を図ります。

処理時間: 205.5367522239685秒 (高速化しないと30分たっても計算が終わりません。)

boids_simulation_large.gif

説明

クラスの定義:

Boidクラスには、is_enemy属性を追加し、ボイドが敵か味方かを識別します。

ボイドの更新:

update_boids関数では、敵ボイドが他のボイド(特に味方)を追いかけるようにするため、距離がCHASE_DIST以下の敵ボイドには追跡の影響を与えます。

アニメーションの作成:

FuncAnimationを使ってアニメーションを生成し、敵と味方のボイドを異なる色で表示します。

このコードをGoogle Colabノートブックに貼り付けて実行すると、敵と味方のボイドの動きを可視化したアニメーションが表示されます。ボイドの動きやパラメータは、シミュレーションのニーズに応じて調整できます。

!pip install numba

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
from IPython.display import Image, display
import time
from numba import jit

# 定数
NUM_ALLIES = 500  # 数を増やす
NUM_ENEMIES = 500  # 数を増やす
WIDTH, HEIGHT = 100, 100
SPEED = 1
SEPARATION_DIST = 5
ALIGNMENT_DIST = 10
COHESION_DIST = 10
CHASE_DIST = 15
FRAMES = 400  # アニメーションの長さを延ばす
FPS = 20

class Boid:
    def __init__(self, x, y, is_enemy=False):
        self.position = np.array([x, y])
        self.velocity = np.random.rand(2) * 2 - 1
        self.velocity = self.velocity / np.linalg.norm(self.velocity) * SPEED
        self.is_enemy = is_enemy

@jit(nopython=True)
def update_boids(boids_positions, boids_velocities, boids_is_enemy):
    num_boids = len(boids_positions)
    for i in range(num_boids):
        boid_pos = boids_positions[i]
        boid_vel = boids_velocities[i]
        is_enemy = boids_is_enemy[i]

        separation = np.zeros(2)
        alignment = np.zeros(2)
        cohesion = np.zeros(2)
        count_separation = count_alignment = count_cohesion = 0

        for j in range(num_boids):
            if i == j:
                continue

            other_boid_pos = boids_positions[j]
            other_boid_vel = boids_velocities[j]
            other_is_enemy = boids_is_enemy[j]

            distance = np.linalg.norm(boid_pos - other_boid_pos)

            if distance < SEPARATION_DIST:
                separation += (boid_pos - other_boid_pos) / distance
                count_separation += 1

            if distance < ALIGNMENT_DIST:
                alignment += other_boid_vel
                count_alignment += 1

            if distance < COHESION_DIST:
                cohesion += other_boid_pos
                count_cohesion += 1

            if is_enemy and distance < CHASE_DIST:
                separation += (boid_pos - other_boid_pos) / distance

        if count_separation > 0:
            separation /= count_separation
        if count_alignment > 0:
            alignment /= count_alignment
        if count_cohesion > 0:
            cohesion = (cohesion / count_cohesion) - boid_pos

        boid_vel += separation + alignment + cohesion
        if np.linalg.norm(boid_vel) > SPEED:
            boid_vel = boid_vel / np.linalg.norm(boid_vel) * SPEED

        boid_pos += boid_vel
        boid_pos[0] %= WIDTH
        boid_pos[1] %= HEIGHT

def animate(frame):
    plt.clf()
    boids_positions = np.array([boid.position for boid in boids])
    boids_velocities = np.array([boid.velocity for boid in boids])
    boids_is_enemy = np.array([boid.is_enemy for boid in boids])
    update_boids(boids_positions, boids_velocities, boids_is_enemy)
    for i, boid in enumerate(boids):
        boid.position = boids_positions[i]
        boid.velocity = boids_velocities[i]
    positions_allies = np.array([boid.position for boid in boids if not boid.is_enemy])
    positions_enemies = np.array([boid.position for boid in boids if boid.is_enemy])
    plt.scatter(positions_allies[:, 0], positions_allies[:, 1], c='b', s=10, label='Allies')
    plt.scatter(positions_enemies[:, 0], positions_enemies[:, 1], c='r', s=10, label='Enemies')
    plt.xlim(0, WIDTH)
    plt.ylim(0, HEIGHT)
    plt.gca().set_aspect('equal')
    plt.legend()

boids = [Boid(np.random.rand() * WIDTH, np.random.rand() * HEIGHT) for _ in range(NUM_ALLIES)] + \
        [Boid(np.random.rand() * WIDTH, np.random.rand() * HEIGHT, is_enemy=True) for _ in range(NUM_ENEMIES)]

fig = plt.figure()

# 処理時間の計測開始
start_time = time.time()

ani = FuncAnimation(fig, animate, frames=FRAMES, interval=1000/FPS)

# GIFファイルとして保存
gif_path = 'boids_simulation_large.gif'
ani.save(gif_path, writer='imagemagick', fps=FPS)

# 処理時間の計測終了と表示
end_time = time.time()
print(f"処理時間: {end_time - start_time}")

# GIFを表示
display(Image(filename=gif_path))

説明
Numbaのインポート: numbaライブラリをインポートします。

JITデコレーターの追加: update_boids関数に@jit(nopython=True)デコレーターを追加します。このデコレーターは、関数がNumPy配列やPythonの標準型のみを使う場合に高速化します。

データの取り扱い: boids_positions, boids_velocities, boids_is_enemyとしてボイドの位置、速度、敵かどうかの情報をNumPy配列として処理します。

これにより、ボイドのシミュレーションの速度が向上し、アニメーションの生成がより効率的になります。

2
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
3