Je ressens une certaine frustration quant à la façon dont matlab gère l'intégration numérique par rapport à Scipy. J'observe les différences suivantes dans mon code de test ci-dessous:
- La version de Matlab tourne en moyenne 24 fois plus vite que mon équivalent python!
- La version de Matlab est capable de calculer l'intégrale sans avertissements, tandis que python retourne
nan+nanj
Que puis-je faire pour m'assurer d'obtenir les mêmes performances en python par rapport aux deux points mentionnés? Selon la documentation, les deux méthodes devraient utiliser une "quadrature adaptative globale" pour approximer l'intégrale.
Vous trouverez ci-dessous le code dans les deux versions (assez similaire, bien que python nécessite la création d'une fonction intégrale pour pouvoir gérer des intégrales complexes.)
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
). Essayez de faire des calculs sur l'ensemble du tableau à la fois. Si ce n'est pas possible, jetez un œil à numba ou aussi à Cython, mais j'espère que ce dernier n'est pas nécessaire.
integral
les tolérances absolue et relative par défaut sont 1e-10
et 1e-6
, respectivement. integrate.quad
spécifie ces deux comme 1.49e-8
. Je ne vois pas où integrate.quad
est décrite comme une méthode "globale adaptative" et elle est très certainement différente de la méthode (adaptative Gauss-Kronrod, je crois) utilisée par integral
. Je ne sais pas trop ce que signifie la partie "globale". De plus, ce n'est jamais une bonne idée d'utiliser à la cputime
place de tic
/ toc
ou time it
.