Я відчуваю деяке розчарування з приводу того, як 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
Матлаб
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
.