🎓 レベル:基礎 | 重要度:A(必須)
📎 前提:シミュレーションとは(決定的 vs 確率的) | 関連:離散事象シミュレーションとは
要点(BLUF)
- シミュレーションのモデル化は 系(system)・状態(state)・入力(input)・出力(output) の4要素に分解することから始まります。
- 入力に確率分布を割り当て、状態を時間発展させ、出力を集計する——これが確率的シミュレーションの共通骨格です。
- 単一窓口の待ち行列を例に平均待ち時間を実測すると 4.05 分。M/M/1 の理論値 4.00 分とよく一致します。
1. モデル化の4要素
現象を計算機の中で動かすには、まず対象を次の4つに切り分けます。
- 系(system):シミュレーションの対象となる範囲。境界を決めること(何を含め、何を外部とするか)が出発点。例:「1台の窓口とその待ち客」。
- 状態(state):ある時点の系を記述する変数の集合。例:「窓口が空きか塞がりか」「待ち人数」。次の瞬間の挙動は、現在の状態(と入力)で決まる。
- 入力(input):系を駆動する外部要因。確率的シミュレーションでは確率分布で与える。例:「客の到着間隔 ~ 指数分布」「サービス時間 ~ 指数分布」。
- 出力(output):知りたい性能指標。例:「平均待ち時間」「窓口の稼働率」。
flowchart LR
I["入力(確率分布)"] --> S["状態(時間発展)"]
S --> O["出力(性能指標を集計)"]
S -->|"次の状態を決める"| S
2. モデル化の流れ
- 目的の明確化:何を知りたいか(平均待ち時間?破綻確率?)。これが出力と必要精度を決める。
- 系の境界設定:どこまでをモデルに含めるか。
- 状態変数の選定:系を過不足なく記述する最小の変数群。
- 入力分布の決定:データやドメイン知識から確率分布を割り当てる。
- 時間発展ルールの記述:状態がどう更新されるか(次節の例なら「客はひとつ前の客が終わってからサービス開始」)。
- 出力の集計と検証:多数回(または長時間)走らせて統計量を取り、V&V で正しさを確かめる。
3. 具体例:単一窓口の待ち行列をモデル化する
役所の1窓口を考えます。客は平均到着率 人/分(到着間隔は指数分布)で来て、サービス時間は平均 分( 人/分の指数分布)。状態は「窓口がいつ空くか」、出力は「平均待ち時間」です。
番目の客のサービス開始時刻は「自分の到着時刻」と「前の客の退出時刻」の遅い方:
import numpy as np
# 乱数シードを固定
rng = np.random.default_rng(7)
n_cust = 100_000 # 客の人数
inter = rng.exponential(1/0.8, n_cust) # 到着間隔 ~ 指数(平均1/0.8分)
serv = rng.exponential(1/1.0, n_cust) # サービス時間 ~ 指数(平均1分)
arrival = np.cumsum(inter) # 各客の到着時刻
start = np.zeros(n_cust)
depart = np.zeros(n_cust)
start[0] = arrival[0]
depart[0] = start[0] + serv[0]
for i in range(1, n_cust): # 状態(窓口が空く時刻)を時間発展
start[i] = max(arrival[i], depart[i-1])
depart[i] = start[i] + serv[i]
wait = start - arrival # 各客の待ち時間
rho = 0.8 / 1.0
wq_theory = rho / (1.0 * (1.0 - rho)) # M/M/1 の平均待ち時間 Wq
print(f"平均待ち時間(シミュ)= {wait.mean():.3f} 分")
print(f"M/M/1 理論値 Wq = {wq_theory:.3f} 分")
出力:
平均待ち時間(シミュ)= 4.050 分
M/M/1 理論値 Wq = 4.000 分
出力の意味:10万人の客をシミュレートした平均待ち時間 4.05 分が、待ち行列理論(M/M/1)の理論値 4.00 分とほぼ一致。モデル化(入力=指数分布、状態=窓口が空く時刻、出力=待ち時間の平均)が正しく組めていることの確認になります。理論値との照合は次のV&Vの典型例です。
4. 時間の進め方:固定刻み vs イベント駆動
状態を時間発展させる方法は2通りあります。
- 固定時間刻み(time-stepping): ごとに状態を更新。物理シミュレーション(ODE)向き。
- イベント駆動(event-driven):状態が変わる瞬間(到着・退出など)だけを処理し、何も起きない時間は飛ばす。待ち行列など離散事象に効率的。上の例は実質イベント駆動です(離散事象シミュレーションとは)。
数式の直観的意味
は「窓口が空いている(前の客が帰った)か、自分が着いたか、遅い方からサービスが始まる」という当たり前の論理を式にしただけです。状態(窓口が空く時刻 )が次の客の挙動を決める——この状態の引き継ぎこそが、静的な確率計算とシミュレーションを分けるポイントです。理論値と一致するのは、入力分布が M/M/1 の仮定(ポアソン到着・指数サービス)を満たすからです。
⚠️ よくある誤解・落とし穴
- 「状態変数は多いほど正確」ではない:目的に必要な最小の状態で十分。余計な変数はバグと計算コストを増やすだけです。
- 「入力分布は正規分布でいい」ではない:到着間隔やサービス時間は正規だと負の値が出てしまう。指数分布・対数正規など、台が正の分布を選ぶ必要があります。
- 「1回走らせれば結果が出る」ではない:確率的シミュレーションの出力は分布。多数回(または長時間)走らせて平均と誤差を見ます(出力解析(過渡・定常・複製))。
- 「シミュレーションは現実そのもの」ではない:モデルは現実の抽象化。境界の外や省いた要因の影響は出ません。だから妥当性確認が要ります。
対応シミュレーション参照
本文の単一窓口待ち行列コード(np.random.default_rng(7))。離散事象としての一般化は離散事象シミュレーションとはへ。
関連ノート
- シミュレーションとは(決定的 vs 確率的)(前提・なぜ乱数で計算するか)
- 検証と妥当性確認(V&V)(次のトピック・モデルの正しさを確かめる)
- 離散事象シミュレーションとは(イベント駆動の一般論)
- 待ち行列のシミュレーション(この例の発展)
- 第1章 シミュレーションの基礎 目次
- シミュレーション・モンテカルロ法 全体目次