Я испытываю некоторое разочарование по поводу того, как Matlab обрабатывает числовую интеграцию против Scipy. Я наблюдаю следующие различия в моем тестовом коде ниже:
- Версия Matlab работает в среднем в 24 раза быстрее, чем мой эквивалент на Python!
- Версия 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
np.vectorize
). Попробуйте выполнить вычисления для всего массива одновременно. Если это невозможно, взгляните на numba или Cython, но я надеюсь, что последнее не нужно.
integral
умолчанию абсолютные и относительные допуски равны 1e-10
и 1e-6
, соответственно. integrate.quad
указывает эти оба как 1.49e-8
. Я не вижу, где integrate.quad
описывается как «глобальный адаптивный» метод, и он, безусловно, отличается от (по-моему, адаптивного метода Гаусса-Кронрода) integral
. Я сам не уверен, что означает «глобальная» часть. Кроме того, никогда не стоит использовать cputime
вместо tic
/ toc
или time it
.