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
matlab
python
quadrature
numba
Dipolo
fuente
fuente
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 son1e-10
y1e-6
, respectivamente.integrate.quad
especifica estos dos como1.49e-8
. No veo dóndeintegrate.quad
se describe como un método "global adaptativo" y es ciertamente diferente del método (adaptable Gauss-Kronrod, creo) utilizado porintegral
. No estoy seguro de lo que significa la parte "global", yo mismo. Además, nunca es una buena idea usarlo encputime
lugar detic
/toc
otime it
.Respuestas:
La pregunta tiene dos preguntas muy diferentes. Me referiré solo al primero.
El segundo es subjetivo. Diría que dejarle saber al usuario que hay algún problema con la integral es algo bueno y que este comportamiento de SciPy supera al de Matlab para mantenerlo en silencio y de alguna manera tratar de tratarlo internamente de la manera que solo conocen los ingenieros de Matlab que Decidí que era el mejor.
Cambié el intervalo de integración para que sea de 0 a 30 (en lugar de 0 a np.inf ) para evitar la advertencia de NaN y agregué una compilación JIT. Para comparar la solución, repetí la integración 300 veces, los resultados son de mi computadora portátil.
Sin compilación JIT:
Con la compilación JIT:
De esta forma, agregar dos líneas de código conduce al factor de aceleración de aproximadamente 40 veces el código de Python en comparación con una versión que no sea JIT. Sin embargo, no tengo Matlab en mi computadora portátil para proporcionar una mejor comparación, si se adapta bien a su PC que 24/40 = 0.6, por lo que Python con JIT debería ser casi el doble de rápido que Matlab para este algoritmo de usuario en particular. Código completo:
Comente la línea @jit para ver la diferencia para su PC.
fuente
Algunas veces la función a integrar no se puede JITAR. En ese caso, usar otro método de integración sería la solución.
Yo recomendaría
scipy.integrate.romberg
(ref) .romberg
puede integrar funciones complejas y puede evaluar la función con una matriz.fuente