http://www.columbia.edu/~ks20/4703-Sigman/4703-07-Notes-PP-NSPP.pdfに従って、もっと効率的な答えがあると思います。
あなたは大まかにします:
total_rate = sum(rates)
probabilities = [ r/total_rate for r in rates ]
arrivals = []
t = 0
while t < T:
t += random.expovariate(total_rate)
i = weighted_random(probabilities)
arrivals += (i, t)
この方法により、多数の異なる到着プロセスでコルーチンの状態を維持する必要がなくなります。「正味の」到着プロセスは 1 つだけです。配分は同じになります。
上記で weighted_random の実装を提供していないことに注意してください。ただし、私の意図は明らかであると想定しています。これは読者の演習として残しておきます ;-) -- またはhttp://eli.thegreenplace.net/2010/01/22/weighted-random-generation-in-pythonなどを参照してください。
次のこともできます。
arrivals = []
t = 0
while t < T:
dt_list = [ random.expovariate(r) for r in rates ]
(dt,i) = min((tau,i) for i,tau in enumerate(dt_list))
t += dt
arrivals += (i, t)
つまり、実際にはすべてのプロセスに対して個別の到着間隔を生成しますが、プロセスの状態を「覚えておく」必要はありません。レート r1 と r2 を持つ 2 つの独立した指数分布確率変数の最小値自体が、レート r1+r2 で指数分布することに注意してください ( http://ocw.mit.edu/courses/mathematics/18-440-probability-and- random-variables-spring-2011/lecture-notes/MIT18_440S11_Lecture20.pdf )、これは実際には前のコード スニペットと非常によく似ています。
ここで紹介した 2 つの方法のうち、最初の方法の方が優れていると思います。
- 最初は O( len(arrivals) * log(len(rates)) ) で、2 番目は O( len(arrivals) * len(rates) ) です。
- 1 つ目は到着ごとに基になるジェネレーターから 2 つの乱数を必要とし、2 つ目は到着ごとに len(rates) 個の乱数を必要とします。
- 1つ目は、到着ごとに1回のログ評価(指数確率変数が生成される方法だと思います)が必要ですが、2つ目は到着ごとにO(len(rates))回のログ評価が必要です。
また、上記のすべての Python 構文を大雑把に解釈して (私は実行していませんし、Python には慣れていません)、必要に応じて一時リストを削除してください。これは、実際には「疑似コード」を意味します。高速なモンテカルロ シミュレーションの場合は、とにかく C++ (および/または CUDA) を使用することになります。
おそらくこの回答が必要な時点を過ぎていることは承知していますが、この投稿を見つけた他の人に役立つことを願っています.