对于Matlab处理数值积分与Scipy的方式,我感到有些沮丧。我在下面的测试代码中观察到以下差异:
- Matlab的版本平均运行速度比我的python 快24倍!
- Matlab的版本能够在没有警告的情况下计算积分,而python返回
nan+nanj
关于上述两点,我该怎么做才能确保在python中获得相同的性能?根据文档,这两种方法都应使用“全局自适应正交”来近似积分。
下面是这两个版本中的代码(尽管python要求创建一个积分函数以便它可以处理复杂的被积数,但两者非常相似。)
蟒蛇
import numpy as np
from scipy import integrate
import time
def integral(integrand, a, b, arg):
def real_func(x,arg):
return np.real(integrand(x,arg))
def imag_func(x,arg):
return np.imag(integrand(x,arg))
real_integral = integrate.quad(real_func, a, b, args=(arg))
imag_integral = integrate.quad(imag_func, a, b, args=(arg))
return real_integral[0] + 1j*imag_integral[0]
vintegral = np.vectorize(integral)
def f_integrand(s, omega):
sigma = np.pi/(np.pi+2)
xs = np.exp(-np.pi*s/(2*sigma))
x1 = -2*sigma/np.pi*(np.log(xs/(1+np.sqrt(1-xs**2)))+np.sqrt(1-xs**2))
x2 = 1-2*sigma/np.pi*(1-xs)
zeta = x2+x1*1j
Vc = 1/(2*sigma)
theta = -1*np.arcsin(np.exp(-np.pi/(2.0*sigma)*s))
t1 = 1/np.sqrt(1+np.tan(theta)**2)
t2 = -1/np.sqrt(1+1/np.tan(theta)**2)
return np.real((t1-1j*t2)/np.sqrt(zeta**2-1))*np.exp(1j*omega*s/Vc);
t0 = time.time()
omega = 10
result = integral(f_integrand, 0, np.inf, omega)
print time.time()-t0
print result
Matlab的
function [ out ] = f_integrand( s, omega )
sigma = pi/(pi+2);
xs = exp(-pi.*s./(2*sigma));
x1 = -2*sigma./pi.*(log(xs./(1+sqrt(1-xs.^2)))+sqrt(1-xs.^2));
x2 = 1-2*sigma./pi.*(1-xs);
zeta = x2+x1*1j;
Vc = 1/(2*sigma);
theta = -1*asin(exp(-pi./(2.0.*sigma).*s));
t1 = 1./sqrt(1+tan(theta).^2);
t2 = -1./sqrt(1+1./tan(theta).^2);
out = real((t1-1j.*t2)./sqrt(zeta.^2-1)).*exp(1j.*omega.*s./Vc);
end
t=cputime;
omega = 10;
result = integral(@(s) f_integrand(s,omega),0,Inf)
time_taken = cputime-t
4
您应该很高兴Python仅慢25倍(而不是250倍)。
—
stali 2014年
因为您是在循环中一次又一次地调用python函数(由隐藏
—
sebix 2014年
np.vectorize
)。尝试一次对整个数组进行计算。这是不可能的,看看numba或Cython,但我希望后者没有必要。
“全局自适应正交”表示它会自适应直到达到一定精度为止。为了确保您比较的是同一事物,请寻找设置精度并同时为两个精度设置的参数(肯定是一个)。
—
bgschaid 2014年
关于@bgschaid的评论,
—
horchler 2014年
integral
默认的绝对公差和相对公差分别为1e-10
和1e-6
。integrate.quad
将两者都指定为1.49e-8
。我看不到哪里integrate.quad
将其描述为“全局自适应”方法,并且它肯定与所使用的(自适应高斯-克朗罗德)方法不同integral
。我自己不确定“全局”部分的含义。此外,它是不是一个好主意来使用cputime
,而不是tic
/ toc
或time it
。
在开始之前,我先检查问题是算法还是语言:添加一个在函数内部递增的全局计数器变量。集成后,这应该告诉您每个函数的评估频率。如果这些计数器相差很大,那么至少部分问题是MATLAB使用了更好的算法
—
bgschaid 2014年