我需要计算简单连通域上的许多二维积分(大多数时候是凸的)。我正在使用python函数scipy.integrate.nquad
来进行此集成。然而,与矩形区域上的积分相比,此操作所需的时间明显较大。有没有可能更快的实现
这是一个例子;我首先在一个圆形域(使用函数内部的约束)上积分一个常量函数,然后在一个矩形域(默认的nquad
函数域)上积分
from scipy import integrate
import time
def circular(x,y,a):
if x**2 + y**2 < a**2/4:
return 1
else:
return 0
def rectangular(x,y,a):
return 1
a = 4
start = time.time()
result = integrate.nquad(circular, [[-a/2, a/2],[-a/2, a/2]], args=(a,))
now = time.time()
print(now-start)
start = time.time()
result = integrate.nquad(rectangular, [[-a/2, a/2],[-a/2, a/2]], args=(a,))
now = time.time()
print(now-start)
矩形域只需要0.00029
秒,而圆形域需要2.07061
秒才能完成
此外,循环积分给出以下警告:
IntegrationWarning: The maximum number of subdivisions (50) has been achieved.
If increasing the limit yields no improvement it is advised to analyze
the integrand in order to determine the difficulties. If the position of a
local difficulty can be determined (singularity, discontinuity) one will
probably gain from splitting up the interval and calling the integrator
on the subranges. Perhaps a special-purpose integrator should be used.
**opt)
加快计算速度的一种方法是使用^{} ,这是一种用于Python的即时编译器
@jit
装饰器Numba提供了一个^{} decorator 来编译一些Python代码,并输出可以在多个CPU上并行运行的优化机器代码。jit被积函数只需要很少的努力,并且会节省一些时间,因为代码经过了优化以运行得更快。人们甚至不用担心类型,Numba在幕后完成了所有这些
这确实运行得更快,在我的机器上计时时,我得到:
这将减少约50%的计算时间
Scipy的
LowLevelCallable
由于Python语言的性质,Python中的函数调用相当耗时。与C等编译语言相比,这种开销有时会使Python代码速度变慢
为了缓解这种情况,Scipy提供了一个^{} 类,可用于提供对低级编译回调函数的访问。通过这种机制,可以绕过Python的函数调用开销,进一步节省时间
注意,在
nquad
的情况下,传递给LowerLevelCallable
的cfunc
的签名必须是以下之一:其中
int
是参数的数量,参数的值在第二个参数中user_data
用于需要上下文操作的回调因此,我们可以稍微更改Python中的循环函数签名以使其兼容
用这种方法我得到
与原始版本相比,该函数减少了95%,与jitted版本相比,该函数减少了90%
定制的装饰师
为了使代码更整洁,并保持被积函数签名的灵活性,可以创建一个定制的装饰函数。它将jit被积函数,并将其包装成
LowLevelCallable
对象,然后可与nquad
一起使用任意数量的参数
如果参数的数量未知,那么我们可以使用Numba提供的方便的^{} function 将
CPointer(float64)
转换为Numpy数组相关问题 更多 >
编程相关推荐