在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)
这种方法消除了为大量不同的到达过程保持协程状态的需要。只有一个“净”到达过程。分配将是相同的。
请注意,我没有在上面给出 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 的两个独立指数分布随机变量的最小值本身以速率 r1+r2 呈指数分布(根据http://ocw.mit.edu/courses/mathematics/18-440-probability-and- random-variables-spring-2011/lecture-notes/MIT18_440S11_Lecture20.pdf),所以这实际上与前面的代码片段非常相似。
在我在这里给出的两种方法中,我认为第一种更好:
- 第一个是 O( len(arrivals) * log(len(rates)) ) 而第二个是 O( len(arrivals) * len(rates) )
- 第一个每次到达需要来自底层生成器的 2 个随机数,而第二个每次到达需要 len(rates) 个随机数。
- 第一个需要每次到达对 log 进行 1 次评估(我假设这是生成指数随机变量的方式),而第二个需要每次到达对 log 进行 O(len(rates)) 评估。
此外,对上述所有 Python 语法持保留态度(我没有运行它,而且我对 Python 很生疏),如果你愿意,可以消除临时列表。这实际上是“伪代码”;对于快速的蒙特卡罗模拟,无论如何您可能都会使用 C++(和/或 CUDA)。
我知道你可能已经过了需要这个答案的地步,但我希望它对找到这篇文章的其他人有所帮助。