Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/326.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python/Numpy——加速放射性衰变的蒙特卡罗方法_Python_Performance_Numpy_Montecarlo - Fatal编程技术网

Python/Numpy——加速放射性衰变的蒙特卡罗方法

Python/Numpy——加速放射性衰变的蒙特卡罗方法,python,performance,numpy,montecarlo,Python,Performance,Numpy,Montecarlo,我试图优化放射性同位素蒙特卡罗衰变时间的生成。 给出了半衰期为t12的同位素原子的nsims,每个同位素何时衰变? 我试图通过使用单个numpy.random.random调用(我称此方法为并行)一次为所有未衰变原子生成随机数来优化此方法,但我希望仍能获得更多性能。我还展示了一种方法,该方法对每个同位素分别(系列)进行计算 我对任何比纯python的parallel函数(即不是cython)性能更好的建议感兴趣。 该方法已经大大改进了计算大型NSIM的serial方法 从最初的“并行”(矢量化是

我试图优化放射性同位素蒙特卡罗衰变时间的生成。 给出了半衰期为t12的同位素原子的nsims,每个同位素何时衰变? 我试图通过使用单个
numpy.random.random
调用(我称此方法为并行)一次为所有未衰变原子生成随机数来优化此方法,但我希望仍能获得更多性能。我还展示了一种方法,该方法对每个同位素分别(系列)进行计算

我对任何比纯python的
parallel
函数(即不是cython)性能更好的建议感兴趣。 该方法已经大大改进了计算大型NSIM的
serial
方法


从最初的“并行”(矢量化是正确的词)执行中,仍有一些速度提升

注意,这是一种微观管理,但它仍然会带来少量的性能提升

import numpy as np
t12 = 3.1*60.
dt = 0.01
ln2 = np.log(2)

s = 98765

def parallel(nsims):  # your code, unaltered, except removed inaccurate timing method
    decay_time = np.zeros(nsims)
    t = dt
    np.random.seed(s) # also had to add a seed to get comparable results
    while 0 in decay_time:
        inot_decayed = np.where(decay_time == 0)[0]
        idecay_check = np.random.random(len(inot_decayed)) > np.exp(-ln2*dt/t12)
        decay_time[inot_decayed[np.where(idecay_check==True)[0]]] = t
        t += dt
    return decay_time

def parallel_micro(nsims): # micromanaged code
    decay_time = np.zeros(nsims)
    t = dt
    half_time = np.exp(-ln2*dt/t12)  # there was no need to calculate this again in every loop iteration
    np.random.seed(s)  # fixed seed to get comparable results
    while 0 in decay_time:
        inot_decayed = np.where(decay_time == 0)[0]  # only here you need the call to np.where
        # to my own surprise, len(some_array) is quicker than some_array.size (function lookup vs attribute lookup)
        idecay_check = np.random.random(len(inot_decayed)) > half_time
        decay_time[inot_decayed[idecay_check]] = t # no need for another np.where and certainly not for another boolean comparison
        t += dt
    return decay_time
您可以使用运行计时测量。分析将告诉您这里的瓶颈是调用
np.where

知道瓶颈是
np。其中
,您可以这样摆脱它:

def parallel_micro2(nsims):
    decay_time = np.zeros(nsims)
    t = dt
    half_time = np.exp(-ln2*dt/t12)
    np.random.seed(s)
    indices = np.where(decay_time==0)[0]
    u = len(indices)
    while u:
        decayed = np.random.random(u) > half_time
        decay_time[indices[decayed]] = t
        indices = indices[np.logical_not(decayed)]
        u = len(indices)
        t += dt
    return decay_time
这确实会带来相当大的速度提升:

In [2]: %timeit -n1 -r1 parallel_micro2(1e4)
1 loops, best of 1: 7.81 s per loop

In [3]: %timeit -n1 -r1 parallel_micro(1e4)
1 loops, best of 1: 29 s per loop

In [4]: %timeit -n1 -r1 parallel(1e4)
1 loops, best of 1: 33.5 s per loop
完成优化后,不要忘记取消对
np.random.seed
的调用

In [2]: %timeit -n1 -r1 parallel_micro2(1e4)
1 loops, best of 1: 7.81 s per loop

In [3]: %timeit -n1 -r1 parallel_micro(1e4)
1 loops, best of 1: 29 s per loop

In [4]: %timeit -n1 -r1 parallel(1e4)
1 loops, best of 1: 33.5 s per loop