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
matlab
python
quadrature
numba
Dipol
quelle
quelle
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
und1e-6
ist.integrate.quad
spezifiziert diese beiden als1.49e-8
. Ich sehe nicht, wointegrate.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 wirdintegral
. Ich bin mir nicht sicher, was der "globale" Teil bedeutet. Es ist auch nie eine gute Idee,cputime
anstelle vontic
/toc
oder zu verwendentime it
.Antworten:
Die Frage hat zwei sehr unterschiedliche Teilfragen. Ich werde nur den ersten ansprechen.
Der zweite ist subjektiv. Ich würde sagen, dass es eine gute Sache ist, den Benutzer wissen zu lassen, dass es ein Problem mit dem Integral gibt, und dieses SciPy-Verhalten übertrifft das des Matlab, um es still zu halten, und irgendwie zu versuchen, damit intern umzugehen, wie es nur den Matlab-Ingenieuren bekannt ist entschieden, dass es das Beste ist.
Ich habe die Integrationsspanne von 0 auf 30 geändert (anstatt von 0 auf np.inf) ), um NaN- zu vermeiden, und eine JIT-Kompilierung hinzugefügt. Um die Lösung zu bewerten, habe ich die Integration 300 Mal wiederholt. Die Ergebnisse stammen von meinem Laptop.
Ohne JIT-Kompilierung:
Mit JIT-Kompilierung:
Auf diese Weise führt das Hinzufügen von zwei Codezeilen zu einer etwa 40-fachen Geschwindigkeit des Python-Codes im Vergleich zu einer Nicht-JIT-Version. Ich habe kein Matlab auf meinem Laptop, um einen besseren Vergleich zu ermöglichen, aber wenn es gut auf Ihren PC skaliert als 24/40 = 0,6, sollte Python mit JIT fast doppelt so schnell sein wie Matlab für diesen bestimmten Benutzeralgorithmus . Vollständiger Code:
Kommentieren Sie die @ jit-Zeile aus, um den Unterschied für Ihren PC zu sehen.
quelle
Manchmal kann die zu integrierende Funktion nicht JIT-fähig sein. In diesem Fall wäre die Verwendung einer anderen Integrationsmethode die Lösung.
Ich würde empfehlen
scipy.integrate.romberg
(ref) .romberg
kann komplexe Funktionen integrieren und die Funktion mit Array auswerten.quelle