1

Is there a way to speed up this code:

import mpmath as mp
import numpy as np
from time import time as epochTime

def func(E):
    f = lambda theta: mp.sin(theta) * mp.exp(E * (mp.cos(theta**2) + \
                                                  mp.cos(theta)**2))
    return f

start = epochTime()
mp.mp.dps = 15
mp.mp.pretty = True

E = np.linspace(0, 10, 200)
ints = [mp.quadgl(func(e), [0, mp.pi]) for e in E] # Main Job
print ('Took:{:.3}s'.format(epochTime() - start))
4

2 回答 2

4

运行您的代码,我将其计时为 5.84 秒

使用Memoize和简化表达式:

cos = Memoize(mp.cos)
sin = Memoize(mp.sin)

def func(E):
    def f(t):
        cost = cos(t)
        return sin(t) * mp.exp(E * (cos(t*t) + cost*cost))
    return f

我第一次把它降到了 3.25 秒,在接下来的迭代中降到了大约 2.8 秒。

(一个更好的方法可能是lru_cache从标准库中使用,但我没有尝试计时)。

如果您多次运行类似的代码,它可能对Memoize()两者都是有意义funcf,因此计算变得微不足道(~0.364s)。

mp用cos/sin/exp替换后math,我降到了 ~1.3s,现在记忆使性能变得更糟,出于某种原因(~1.5s,我猜查找时间占主导地位)。

于 2013-06-28T08:51:05.860 回答
2

通常,您希望尽可能避免调用诸如 sin、cos、exp、ln 之类的超越函数,尤其是在像被积函数这样的“热”函数中。

  • 将 x**2 替换为 x*x(通常 x**2 调用 generic=slow exponentiation function)
  • 对多次使用的“昂贵”中间项使用变量
  • 变换你的方程以减少或消除超越函数
  • 典型参数值的特殊情况。整数指数是常见的候选者。
  • 预先计算所有不变的东西,espc。在参数化函数中

对于特定示例,您可以替换 z=cos(theta)。它是 dz = -sin(theta)dtheta。你的被积函数变成

-exp(E*(z^2 + cos(arccos(z)^2))

为您节省一些卓越的函数调用。边界 [0, pi] 变为 [1, -1]。还要避免 x**2,最好使用 x*x。

完整代码:

import mpmath as mp
import numpy as np
from time import time as epochTime

def func(E):
    def f(z):
        acz = mp.acos(z)
        return -mp.exp(E * (mp.cos(acz*acz) + z*z))
    return f

start = epochTime()
mp.mp.dps = 15
mp.mp.pretty = True

E = np.linspace(0, 10, 200)
ints = [mp.quadgl(func(e), [1.0, -1.0]) for e in E] # Main Job
print ('Took:{:.3}s'.format(epochTime() - start))
于 2013-06-28T09:20:03.217 回答