Estou com uma certa frustração com a maneira como o matlab lida com a integração numérica versus o Scipy. Observo as seguintes diferenças no meu código de teste abaixo:
- A versão do Matlab é executada em média 24 vezes mais rápido que o meu equivalente em python!
- A versão do Matlab é capaz de calcular a integral sem avisos, enquanto o python retorna
nan+nanj
O que posso fazer para garantir o mesmo desempenho em python em relação aos dois pontos mencionados? De acordo com a documentação, ambos os métodos devem usar uma "quadratura adaptativa global" para aproximar a integral.
Abaixo está o código nas duas versões (bastante semelhante, embora o python exija que uma função integral seja criada para que ele possa lidar com integrandos complexos).
Pitão
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
). Tente fazer cálculos em toda a matriz de uma só vez. Isso não é possível, dê uma olhada no numba ou também no Cython, mas espero que o último não seja necessário.
integral
as tolerâncias absolutas e relativas padrão são 1e-10
e 1e-6
, respectivamente. integrate.quad
especifica esses dois como 1.49e-8
. Não vejo onde integrate.quad
é descrito como um método "global adaptativo" e certamente é diferente do método (adaptável de Gauss-Kronrod, acredito) usado pelo integral
. Não sei ao certo o que significa a parte "global". Além disso, nunca é uma boa ideia usar em cputime
vez de tic
/ toc
ou time it
.