Estoy experimentando cierta frustración por la forma en que matlab maneja la integración numérica frente a Scipy. Observo las siguientes diferencias en mi código de prueba a continuación:
- ¡La versión de Matlab funciona en promedio 24 veces más rápido que mi equivalente en Python!
- La versión de Matlab es capaz de calcular la integral sin advertencias, mientras que Python regresa
nan+nanj
¿Qué puedo hacer para asegurarme de obtener el mismo rendimiento en Python con respecto a los dos puntos mencionados? Según la documentación, ambos métodos deberían usar una "cuadratura adaptativa global" para aproximar la integral.
A continuación se muestra el código en las dos versiones (bastante similar, aunque Python requiere que se cree una función integral para que pueda manejar integrandos complejos).
Pitón
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
). Intente hacer cálculos en toda la matriz a la vez. Si eso no es posible, eche un vistazo a Numba o también a Cython, pero espero que esto último no sea necesario.
integral
las tolerancias absolutas y relativas predeterminadas son 1e-10
y 1e-6
, respectivamente. integrate.quad
especifica estos dos como 1.49e-8
. No veo dónde integrate.quad
se describe como un método "global adaptativo" y es ciertamente diferente del método (adaptable Gauss-Kronrod, creo) utilizado por integral
. No estoy seguro de lo que significa la parte "global", yo mismo. Además, nunca es una buena idea usarlo en cputime
lugar de tic
/ toc
o time it
.