naohiro701 commited on
Commit
321fdb6
·
verified ·
1 Parent(s): 5d1845f

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +119 -5
app.py CHANGED
@@ -1,5 +1,3 @@
1
- # boids_streamlit.py
2
-
3
  import streamlit as st
4
  import numpy as np
5
  import plotly.graph_objects as go
@@ -10,6 +8,7 @@ class Boid:
10
  def __init__(self, position, velocity):
11
  self.position = np.array(position, dtype='float64')
12
  self.velocity = np.array(velocity, dtype='float64')
 
13
  self.history = []
14
 
15
  def update(self, boids, width, height, params):
@@ -37,6 +36,7 @@ class Boid:
37
  self.avoid_others(boids, params)
38
  self.match_velocity(boids, params)
39
  self.limit_speed(params)
 
40
 
41
  def fly_towards_center(self, boids, params):
42
  centering_factor = params['centering_factor']
@@ -88,6 +88,20 @@ class Boid:
88
  if speed > params['max_speed']:
89
  self.velocity = (self.velocity / speed) * params['max_speed']
90
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
91
  def distance(self, other):
92
  return np.linalg.norm(self.position - other.position)
93
 
@@ -101,7 +115,11 @@ params = {
101
  'matching_factor': 0.05,
102
  'max_speed': 15.0,
103
  'draw_trail': False,
104
- 'max_history': 50
 
 
 
 
105
  }
106
 
107
  # Streamlitのサイドバーでパラメータを調整
@@ -116,9 +134,13 @@ params['max_speed'] = st.sidebar.slider("Maximum Speed", 5.0, 30.0, 15.0)
116
  params['draw_trail'] = st.sidebar.checkbox("Draw Trails")
117
  if params['draw_trail']:
118
  params['max_history'] = st.sidebar.slider("Trail Length", 10, 100, 50)
 
 
119
 
120
  # シミュレーション画面サイズ
121
  width, height = 800, 600
 
 
122
 
123
  # Boidsの初期化
124
  boids = []
@@ -161,7 +183,98 @@ if params['draw_trail']:
161
  fig.add_trace(trail_scatter)
162
 
163
  # Streamlitのタイトル
164
- st.title("Boids Simulation")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
165
 
166
  # アニメーションの表示領域
167
  animation_placeholder = st.empty()
@@ -179,6 +292,7 @@ if st.sidebar.button("Reset Simulation"):
179
  velocity = [np.cos(angle), np.sin(angle)]
180
  boids.append(Boid(position, velocity))
181
 
 
182
  while True:
183
  # Boidsの更新
184
  for boid in boids:
@@ -209,4 +323,4 @@ while True:
209
  animation_placeholder.plotly_chart(fig, use_container_width=True)
210
 
211
  # フレームレート調整
212
- time.sleep(sleep_time)
 
 
 
1
  import streamlit as st
2
  import numpy as np
3
  import plotly.graph_objects as go
 
8
  def __init__(self, position, velocity):
9
  self.position = np.array(position, dtype='float64')
10
  self.velocity = np.array(velocity, dtype='float64')
11
+ self.acceleration = np.zeros(2, dtype='float64')
12
  self.history = []
13
 
14
  def update(self, boids, width, height, params):
 
36
  self.avoid_others(boids, params)
37
  self.match_velocity(boids, params)
38
  self.limit_speed(params)
39
+ self.avoid_boundaries(width=params['width'], height=params['height'], params=params)
40
 
41
  def fly_towards_center(self, boids, params):
42
  centering_factor = params['centering_factor']
 
88
  if speed > params['max_speed']:
89
  self.velocity = (self.velocity / speed) * params['max_speed']
90
 
91
+ def avoid_boundaries(self, width, height, params):
92
+ margin = params['boundary_margin']
93
+ turn_factor = params['boundary_turn_factor']
94
+
95
+ if self.position[0] < margin:
96
+ self.acceleration[0] += turn_factor
97
+ elif self.position[0] > width - margin:
98
+ self.acceleration[0] -= turn_factor
99
+
100
+ if self.position[1] < margin:
101
+ self.acceleration[1] += turn_factor
102
+ elif self.position[1] > height - margin:
103
+ self.acceleration[1] -= turn_factor
104
+
105
  def distance(self, other):
106
  return np.linalg.norm(self.position - other.position)
107
 
 
115
  'matching_factor': 0.05,
116
  'max_speed': 15.0,
117
  'draw_trail': False,
118
+ 'max_history': 50,
119
+ 'width': 800,
120
+ 'height': 600,
121
+ 'boundary_margin': 100.0,
122
+ 'boundary_turn_factor': 0.05
123
  }
124
 
125
  # Streamlitのサイドバーでパラメータを調整
 
134
  params['draw_trail'] = st.sidebar.checkbox("Draw Trails")
135
  if params['draw_trail']:
136
  params['max_history'] = st.sidebar.slider("Trail Length", 10, 100, 50)
137
+ params['boundary_margin'] = st.sidebar.slider("Boundary Margin", 50.0, 300.0, 100.0)
138
+ params['boundary_turn_factor'] = st.sidebar.slider("Boundary Turn Factor", 0.01, 0.2, 0.05)
139
 
140
  # シミュレーション画面サイズ
141
  width, height = 800, 600
142
+ params['width'] = width
143
+ params['height'] = height
144
 
145
  # Boidsの初期化
146
  boids = []
 
183
  fig.add_trace(trail_scatter)
184
 
185
  # Streamlitのタイトル
186
+ st.title("Boids Simulation with Streamlit and Plotly")
187
+
188
+ # 説明セクション
189
+ st.header("群れアルゴリズムBoidsの数学的背景")
190
+
191
+ st.markdown(r"""
192
+ ### **Boidsアルゴリズムの概要**
193
+
194
+ Boidsアルゴリズムは、Craig Reynoldsによって1986年に提案された群れ行動のシミュレーション手法です。各エージェント(Boid)は単純なルールに従うことで、複雑な群れ行動を再現します。基本的な3つのルールは以下の通りです:
195
+
196
+ 1. **分離(Separation)**: 隣接するBoidから適切な距離を保ち、衝突を避ける。
197
+ 2. **整列(Alignment)**: 隣接するBoidの平均速度に自身の速度を合わせる。
198
+ 3. **結合(Cohesion)**: 隣接するBoidの中心に向かって移動する。
199
+
200
+ ### **数式によるモデルの定義**
201
+
202
+ Boidsの動作は、各エージェントの位置ベクトル \(\mathbf{p}_i(t)\) と速度ベクトル \(\mathbf{v}_i(t)\) で表されます。時間 \(t\) におけるエージェント \(i\) の位置と速度は、以下の微分方程式で記述されます:
203
+
204
+ \[
205
+ \frac{d\mathbf{p}_i(t)}{dt} = \mathbf{v}_i(t)
206
+ \]
207
+
208
+ \[
209
+ \frac{d\mathbf{v}_i(t)}{dt} = \mathbf{a}_i(t)
210
+ \]
211
+
212
+ ここで、加速度 \(\mathbf{a}_i(t)\) は以下の3つの力の合成です:
213
+
214
+ \[
215
+ \mathbf{a}_i(t) = \mathbf{a}_{\text{separation}} + \mathbf{a}_{\text{alignment}} + \mathbf{a}_{\text{cohesion}}
216
+ \]
217
+
218
+ #### **1. 分離(Separation)**
219
+
220
+ Boidが他のBoidと衝突しないようにするための力。エージェント \(i\) と近傍エージェント \(j\) との間の距離を \(d_{ij}\) とすると、分離力 \(\mathbf{a}_{\text{separation}}\) は以下のように定義されます:
221
+
222
+ \[
223
+ \mathbf{a}_{\text{separation}} = \sum_{j \in N(i)} \frac{\mathbf{p}_i - \mathbf{p}_j}{d_{ij}^2}
224
+ \]
225
+
226
+ ここで、\(N(i)\) はBoid \(i\) の近傍にいるBoidの集合です。
227
+
228
+ #### **2. 整列(Alignment)**
229
+
230
+ Boidが周囲のBoidと同じ方向に移動するようにするための力。近傍Boidの平均速度 \(\mathbf{v}_{\text{avg}}\) を計算し、Boid \(i\) の速度をそれに合わせるための力は以下の通りです:
231
+
232
+ \[
233
+ \mathbf{a}_{\text{alignment}} = \frac{\mathbf{v}_{\text{avg}} - \mathbf{v}_i}{\tau}
234
+ \]
235
+
236
+ ここで、\(\tau\) は調整パラメータです。
237
+
238
+ #### **3. 結合(Cohesion)**
239
+
240
+ Boidが周囲のBoidの中心に向かって移動するようにするため��力。近傍Boidの中心 \(\mathbf{C}_{\text{avg}}\) を計算し、Boid \(i\) がそこに向かうための力は以下の通りです:
241
+
242
+ \[
243
+ \mathbf{a}_{\text{cohesion}} = \frac{\mathbf{C}_{\text{avg}} - \mathbf{p}_i}{\sigma}
244
+ \]
245
+
246
+ ここで、\(\sigma\) は調整パラメータです。
247
+
248
+ ### **アルゴリズムの更新ルール**
249
+
250
+ 各Boidの位置と速度は、離散的な時間ステップ \( \Delta t \) に基づいて更新されます。更新ルールは以下のようになります:
251
+
252
+ \[
253
+ \mathbf{v}_i(t + \Delta t) = \mathbf{v}_i(t) + \mathbf{a}_i(t) \Delta t
254
+ \]
255
+
256
+ \[
257
+ \mathbf{p}_i(t + \Delta t) = \mathbf{p}_i(t) + \mathbf{v}_i(t + \Delta t) \Delta t
258
+ \]
259
+
260
+ これらの式に基づき、各Boidは分離、整列、結合の力を計算し、それに基づいて速度と位置を更新します。
261
+
262
+ ### **追加機能の説明**
263
+
264
+ 本シミュレーションでは、以下の追加機能を実装しています:
265
+
266
+ 1. **境界回避(Boundary Avoidance)**: シミュレーション領域の端にBoidが近づくと、Boidが逆方向に加速度を受けて領域内に留まるようにします。これにより、Boidが画面外に出ることを防ぎます。
267
+
268
+ 2. **トレイル描画(Trail Drawing)**: Boidの過去の位置をトレイルとして表示し、動きの軌跡を視覚化します。これにより、Boidの動きのパターンを追跡することが容易になります。
269
+
270
+ ### **パラメータの追加とその役割**
271
+
272
+ - **Boundary Margin (\(M\))**: シミュレーション領域の端からBoidが回避を開始する距離。
273
+ - **Boundary Turn Factor (\(\gamma\))**: 境界回避力の強さを調整する係数。
274
+
275
+ これらのパラメータにより、Boidが領域の端に近づいた際の挙動を細かく制御できます。
276
+
277
+ """, unsafe_allow_html=True)
278
 
279
  # アニメーションの表示領域
280
  animation_placeholder = st.empty()
 
292
  velocity = [np.cos(angle), np.sin(angle)]
293
  boids.append(Boid(position, velocity))
294
 
295
+ # アニメーションの実行ループ
296
  while True:
297
  # Boidsの更新
298
  for boid in boids:
 
323
  animation_placeholder.plotly_chart(fig, use_container_width=True)
324
 
325
  # フレームレート調整
326
+ time.sleep(sleep_time)