Ich bin etwas frustriert darüber, wie matlab mit numerischer Integration im Vergleich zu Scipy umgeht. Ich beobachte die folgenden Unterschiede in meinem Testcode:
- Matlabs Version läuft im Durchschnitt 24-mal schneller als mein Python-Äquivalent!
- Matlabs Version ist in der Lage, das Integral ohne Warnungen zu berechnen, während Python zurückkehrt
nan+nanj
Was kann ich tun, um sicherzustellen, dass ich in Bezug auf die beiden genannten Punkte dieselbe Leistung in Python erhalte? Laut Dokumentation sollten beide Methoden eine "globale adaptive Quadratur" verwenden, um das Integral zu approximieren.
Nachfolgend finden Sie den Code in den beiden Versionen (ziemlich ähnlich, obwohl für Python die Erstellung einer Integralfunktion erforderlich ist, damit komplexe Integranden verarbeitet werden können.)
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
). Versuchen Sie, Berechnungen für das gesamte Array gleichzeitig durchzuführen. Es ist nicht möglich, sich numba oder auch Cython anzuschauen, aber ich hoffe, letzteres ist nicht notwendig.
integral
die absoluten und relativen Standardtoleranzen gleich1e-10
und 1e-6
ist. integrate.quad
spezifiziert diese beiden als 1.49e-8
. Ich sehe nicht, wo integrate.quad
eine "globale adaptive" Methode beschrieben wird, und sie unterscheidet sich mit Sicherheit von der (meiner Meinung nach adaptiven Gauß-Kronrod-Methode), die von verwendet wird integral
. Ich bin mir nicht sicher, was der "globale" Teil bedeutet. Es ist auch nie eine gute Idee, cputime
anstelle von tic
/ toc
oder zu verwenden time it
.