Physik auf dem Computer Sommersemester 2012

Transcription

Physik auf dem Computer Sommersemester 2012
Skript zur Vorlesung
“Physik auf dem Computer”
JP Dr. A. Arnold
Universität Stuttgart
Institut für Computerphysik
unter Mithilfe von
Dr. O. Lenz, H. Menke, M. Kuron, J. Landsgesell, K. Szuttor
Sommersemester 2012
Dies ist das Skript zur Vorlesung „Physik auf dem Computer“, die von Axel Arnold im
Sommersemester 2012 an der Universität Stuttgart gehalten wurde.
Dieses Skript und alle Quelldateien sind unter einer Creative Commons-Lizenz vom Typ
Namensnennung-Weitergabe unter gleichen Bedingungen 3.0 Deutschland zugänglich.
Um eine Kopie dieser Lizenz einzusehen, konsultieren Sie http://creativecommons.
org/licenses/by-sa/3.0/de/ oder wenden Sie sich schriftlich an Creative Commons, 444 Castro Street, Suite 900, Mountain View, California, 94041, USA.
BY:
C
CC
Inhaltsverzeichnis
1 Einleitung
1.1 Über dieses Skript . . . . . . . . . . . . . . .
1.2 Beispiel: Fadenpendel . . . . . . . . . . . . .
1.2.1 Modell . . . . . . . . . . . . . . . . . .
1.2.2 Näherung: der harmonische Oszillator
1.2.3 Numerische Lösung . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
7
8
10
10
11
12
2 Lineare Algebra I
2.1 Dreiecksmatrizen .
2.2 Gaußelimination .
2.3 Matrixinversion . .
2.4 LU-Zerlegung . . .
2.5 Cholesky-Zerlegung
2.6 Bandmatrizen . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
17
17
18
20
21
22
23
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
25
25
26
27
29
30
30
31
32
34
36
36
38
40
42
44
.
.
.
.
49
49
51
52
53
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
3 Darstellung von Funktionen
3.1 Horner-Schema . . . . . . . . . . . . . . . . . . . . .
3.2 Taylorreihen . . . . . . . . . . . . . . . . . . . . . . .
3.3 Polynom- oder Lagrangeinterpolation . . . . . . . . .
3.3.1 Lagrangepolynome . . . . . . . . . . . . . . .
3.3.2 Neville-Aitken-Schema . . . . . . . . . . . . .
3.3.3 Newtonsche Darstellung . . . . . . . . . . . .
3.3.4 Chebyshev-Stützstellen . . . . . . . . . . . . .
3.4 Splines . . . . . . . . . . . . . . . . . . . . . . . . . .
3.5 Ausgleichsrechnung, Methode der kleinsten Quadrate
3.6 Fourierreihen . . . . . . . . . . . . . . . . . . . . . .
3.6.1 Komplexe Fourierreihen . . . . . . . . . . . .
3.6.2 Reelle Fourierreihen . . . . . . . . . . . . . .
3.6.3 Diskrete Fouriertransformation . . . . . . . .
3.6.4 Schnelle Fouriertransformation . . . . . . . .
3.7 Wavelets . . . . . . . . . . . . . . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
4 Datenanalyse und Signalverarbeitung
4.1 Kontinuierliche Fouriertransformation . . . . . . . . . .
4.1.1 Spezielle Fouriertransformierte . . . . . . . . . .
4.1.2 Numerische kontinuierliche Fouriertransformation
4.1.3 Abtasttheorem . . . . . . . . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
3
Inhaltsverzeichnis
4.2
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
53
54
56
56
59
60
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
65
65
67
68
69
70
71
71
72
73
75
75
6 Numerisches Differenzieren und Integrieren
6.1 Numerisches Differenzieren . . . . . . . . . . . . . . . . . . . . .
6.1.1 Näherungen höherer Ordnung und höhere Ableitungen .
6.1.2 Genauigkeit . . . . . . . . . . . . . . . . . . . . . . . . .
6.1.3 Beispiel: Besselsche Differentialgleichung . . . . . . . . .
6.2 Quadratur: numerische Integration . . . . . . . . . . . . . . . .
6.2.1 Newton-Cotes-Formeln . . . . . . . . . . . . . . . . . . .
6.2.2 Zusammengesetzte Newton-Cotes-Formeln . . . . . . . .
6.2.3 Beispiel: Besselfunktion . . . . . . . . . . . . . . . . . .
6.2.4 Romberg-Integration . . . . . . . . . . . . . . . . . . . .
6.2.5 Beispiel: Fehlerintegral . . . . . . . . . . . . . . . . . . .
6.2.6 Gauß-Quadratur . . . . . . . . . . . . . . . . . . . . . .
6.2.7 Unendliche Integrale und Singularitäten . . . . . . . . .
6.2.8 Mehrdimensionale Integration, Monte-Carlo-Integration
6.2.9 Beispiel: Monte-Carlo-Integration von π . . . . . . . . .
6.2.10 Quasi-Monte-Carlo-Integration . . . . . . . . . . . . . .
6.2.11 Beispiel: Quasi-Monte-Carlo-Integration von π . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
79
79
80
81
82
84
87
89
91
92
93
96
98
99
101
101
104
7 Zufallszahlen
7.1 Pseudozufallszahlen . . . . . . . . . . .
7.1.1 Linearer Kongruenzgenerator .
7.1.2 Verzögerter Fibonaccigenerator
7.2 Andere Verteilungen . . . . . . . . . .
7.2.1 Verwerfungsmethode . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
107
107
108
110
112
113
4.3
4.4
Faltungen . . . . . . . . . . . . . . . .
4.2.1 Filter . . . . . . . . . . . . . .
4.2.2 Antwort zeitinvarianter linearer
Kreuz- und Autokorrelation . . . . . .
4.3.1 Autokorrelationsfunktion . . .
Messfehlerabschätzung . . . . . . . . .
. . . . .
. . . . .
Systeme
. . . . .
. . . . .
. . . . .
5 Nichtlineare Gleichungssysteme
5.1 Sukzessive Substitution . . . . . . . . . . .
5.1.1 Beispiel . . . . . . . . . . . . . . . .
5.2 Newtonverfahren in einer Dimension . . . .
5.2.1 Beispiel . . . . . . . . . . . . . . . .
5.2.2 Wurzelziehen . . . . . . . . . . . . .
5.2.3 Nullstellen von Polynomen . . . . . .
5.3 Sekantenmethode . . . . . . . . . . . . . . .
5.4 Bisektion . . . . . . . . . . . . . . . . . . .
5.5 Regula falsi . . . . . . . . . . . . . . . . . .
5.6 Newtonverfahren in mehreren Dimensionen
5.6.1 Gedämpftes Newtonverfahren . . . .
4
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
Inhaltsverzeichnis
7.3
7.4
7.5
7.2.2 Inversionsmethode . . . . . . .
7.2.3 Zufällige Punkte auf Kugel und
Qualitätsanalyse . . . . . . . . . . . .
Beispiel: Random walk . . . . . . . . .
Beispiel: Perkolation . . . . . . . . . .
8 Lineare Algebra II
8.1 Iterative Gleichungslöser . . . . . . . .
8.1.1 Jacobiverfahren . . . . . . . . .
8.1.2 Gauß-Seidel-Verfahren . . . . .
8.1.3 Relaxationsverfahren . . . . . .
8.2 QR-Zerlegung und Orthogonalisierung
8.2.1 Gram-Schmidt-Verfahren . . .
8.2.2 Householder-Verfahren . . . . .
8.2.3 Givens-Rotationen . . . . . . .
8.3 Eigenwerte . . . . . . . . . . . . . . .
8.3.1 Vektoriteration . . . . . . . . .
8.3.2 QR-Algorithmus . . . . . . . .
8.3.3 Inverse Iteration . . . . . . . .
. . . . . . . . . .
Kugeloberfläche .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
115
117
118
121
128
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
133
134
135
137
137
139
140
144
147
150
150
152
153
9 Optimierung
9.1 Ausgleichsrechnung und Pseudoinverse . . . . .
9.2 Nichtlineare Optimierung . . . . . . . . . . . .
9.2.1 Verfahren des steilsten Abstiegs . . . . .
9.2.2 Schrittweitensteuerung . . . . . . . . . .
9.2.3 CG-Verfahren . . . . . . . . . . . . . . .
9.2.4 Nebenbedingungen und Straffunktionen
9.3 Lineare Programme und Simplexalgorithmus . .
9.4 Globale Optimierung . . . . . . . . . . . . . . .
9.4.1 Simulated annealing . . . . . . . . . . .
9.4.2 Genetische Algorithmen . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
157
158
160
161
161
164
166
169
174
179
182
10 Differentialgleichungen
10.1 Gewöhnliche Differentialgleichungen . . . . . . .
10.1.1 Runge-Kutta-Verfahren . . . . . . . . . .
10.1.2 Beispiel: Lotka-Volterra-Gleichungen . . .
10.1.3 Velocity-Verlet-Verfahren . . . . . . . . .
10.2 Partielle Differentialgleichungen . . . . . . . . . .
10.2.1 Finite-Element-Methode . . . . . . . . . .
10.2.2 Wärmeleitungsgleichung . . . . . . . . . .
10.2.3 Lösung der Poisson-Gleichung . . . . . . .
10.2.4 Lösung der Poisson-Boltzmann-Gleichung
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
185
185
186
190
192
196
196
198
201
204
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
5
1 Einleitung
In dieser Vorlesung geht es darum, wie der Computer in der modernen Physik eingesetzt
wird, um neue Erkenntnisse zu gewinnen. Klassisch war die Physik ein Zusammenspiel aus
Experiment und Theorie. Die Theorie macht Vorhersagen, die im Experiment überprüft
werden. Umgekehrt kann im Experiment ein neuer Effekt beobachtet werden, für den
die Theorie eine Erklärung liefert. Durch den Einsatz von Computern ist dieses Bild
komplizierter geworden. In der folgenden Graphik sind die Bereiche farblich hinterlegt,
in denen heutzutage Computer zum Einsatz kommen, die hellroten Bereiche werden in
dieser Vorlesung behandelt:
Vorhersage
Auswertung
Symbolische Mathematik
Experiment
Theorie
Steuerung
Numerische Lösung
Überprüfung
Überprüfung
Vorhersage
Eichung
Vorhersage
Simulation
Zu den klassischen Säulen Theorie und Experiment ist die Simulation als Mittelding zwischen Theorie und Experiment gekommen. Computersimulationen stellen Experimente
im Computer nach, ausgehend von bekannten theoretischen Grundlagen. Praktisch alles
kann simuliert werden, von Galaxien bis hin zu Elektronen und Quarks. Dazu gibt es eine Vielzahl an unterschiedlichen Methoden. Simulationen erfüllen zwei Hauptaufgaben:
Simulationen können einerseits Experimente ziemlich genau reproduzieren, andererseits
kann man mit Ihrer Hilfe theoretische Modelle in ihrer vollen Komplexität untersuchen.
Simulationen, die an ein Experiment angepasst (geeicht) sind, können zusätzliche Informationen liefern, die experimentell nicht zugänglich sind. Zum Beispiel kann man
dort Energiebeiträge getrennt messen oder sehr kurzlebige Zwischenprodukte beobachten. Außerdem erlauben Simulationen, Wechselwirkungen und andere Parameter gezielt
zu verändern, und damit Vorhersagen über zukünftige Experimente zu machen.
Simulationen, die auf theoretischen Modellen basieren, sind oft ein gutes Mittel, um
notwendige Näherungen auf Plausibilität zu überprüfen oder um einen ersten Eindruck
vom Verhalten dieses Modells zu erhalten. Damit können Simulationen auch helfen, zu
entscheiden, ob notwendige Näherungen oder das Modell unvollständig ist, wenn Theorie
und Experiment nicht zu einander passen.
7
1 Einleitung
In der klassischen theoretischen Physik werden Papier und Bleistift zunehmend vom
Computer verdrängt, denn Computeralgebra ist mittlerweile sehr leistungsfähig und kann
zum Beispiel in wenigen Sekunden komplexe Integrale analytisch lösen. Und falls eine
Gleichung doch einmal zu kompliziert ist für eine analytische Lösung, so kann der Computer mit numerischen Verfahren oft sehr gute Näherungen finden.
In der experimentellen Physik fallen immer größere Datenmengen an. Der LHC erzeugt
zum Beispiel pro Jahr etwa 10 Petabyte an Daten, also etwa 200 Millionen DVDs, was
über mehrere Rechenzentren verteilt gespeichert und ausgewertet werden muss. Klar ist,
dass nur Computer diese gigantischen Datenmengen durchforsten können. Aber auch bei
einfacheren Experimenten helfen Computer bei der Auswertung und Aufbereitung der
Daten, zum Beispiel durch Filtern oder statistische Analysen. Viele Experimente, nicht
nur der LHC, sind aber auch so komplex, dass Computer zur Steuerung der Experimente
benötigt werden, was wir in dieser Vorlesung aber nicht behandeln können. Die Auswertung und Aufbereitung der Daten hingegen wird besprochen, auch weil dies genauso auch
für Computersimulationen benutzt wird.
Neben diesen direkten Anwendungen in der Physik ist der Computer mittlerweile natürlich auch ein wichtiges Mittel für den Wissensaustausch unter Physikern. Quasi alle
wissenschaftlichen Arbeiten, wie etwa dieses Skript, werden heute nicht mit der Schreibmaschine und Schablonen erzeugt, sondern auf dem Computer. Die großen Verlage verlangen mittlerweile auch, Manuskripte als elektronische Dokumente zur Publikation einzureichen. Umgekehrt stehen wissenschaftliche Arbeit, vor allem Zeitschriftentexte, normalerweise nur noch in elektronischen Bibliotheken zur Verfügung, dafür aber Texte aus
der gesamten Welt. Zur Suche in diesen riesigen Datenmengen dienen wiederum Computer. Und schließlich ist der Computer natürlich auch unverzichtbar, um international
zusammenzuarbeiten - Brief und Telefon wären schlicht zu langsam und unflexibel. Diese
Aspekte wurden aber schon in den Computergrundlagen behandelt, und sind nicht Teil
dieser Vorlesung.
Um den Computer für Simulationen, Auswertung von Daten oder auch Lösung komplexer Differenzialgleichungen nutzen zu können, sind neben physikalischen Kenntnissen
auch solche in Programmierung, numerischer Mathematik und Informatik gefragt. In diesem Skript geht es vor allem um die grundlegenden Methoden und wie diese angewandt
werden, daher dominiert die numerische Mathematik etwas. Anders als in einer richtigen
Vorlesung zur Numerik stehen hier aber die Methoden und Anwendungen anstatt der
Herleitungen im Vordergrund.
1.1 Über dieses Skript
Im Folgenden wird eine in der numerischen Mathematik übliche Notation benutzt. Wie
auch in den meisten Programmiersprachen werden skalare und vektorielle Variablen nicht
durch ihre Schreibweise unterschieden, allerdings werden üblicherweise die Namen i–l
für (ganzzahlige) Schleifenindizes benutzt, n und m für Dimensionen. Da Schleifen sehr
häufig auftreten, wird hierfür die Kurznotation Anfang(Inkrement)Ende benutzt. Zum
8
1.1 Über dieses Skript
Beispiel bedeuten
1(1)n = 1,2, . . . , n
n(−2)1 = n, n − 2, . . . , 3, 1.
Alle anderen Variablen sind reellwertige Skalare oder Vektoren, Rn bezeichnet dabei
den n-dimensionalen Vektorraum reller Zahlen. Mit ei wird dabei der Einheitsvektor der
i-ten Spalte bezeichnet, mit eTi seine Transponierte, also der Einheitsvektor der i-ten
Zeile. Bei komplexen Vektoren steht entsprechend der obere Index H für die Hermitesche
eines Vektors, also die Transponierte des Vektors, bei der alle Komponenten komplex
konjugiert sind. Für reelle Vektoren sind also H und T gleichbedeutend.
Integrale werden mit dem Volumenelement am Ende geschrieben, dessen Dimensionalität sich aus dem Integrationsbereich erschließt. Sehr häufig werden Abschätzungen mit
Hilfe der Landau-Symbole verkürzt. Wie üblich heißt für zwei Funktionen f und g
f = Ox→a (g)
⇐⇒
|f (x)|
< ∞.
x→a |g(x)|
lim
In den meisten Fällen ist a = 0 oder a = ∞ und aus dem Kontext klar, welcher Grenzwert
gemeint ist. Dann wird die Angabe weggelassen. Oft wird auch die Notation f = g +O(h)
benutzt, um f + g = O(h) auszudrücken. f (x)=g(x)
˙
schließlich bedeutet f (x) − g(x) =
Ox → 0(x).
Um einzelne Methoden konkret vorstellen zu können, wird in diesem Skript auf die
Sprachen Python und C zurückgegriffen. Im Bereich des Hochleistungsrechnens werden
vor allem die Sprachen Fortran und C/C++ eingesetzt, weil diese in Verbindung mit
guten Compilern sehr effizienten Code ergeben. Allerdings bieten diese Sprachen keine
nativen Datentypen wie zum Bespiel Listen oder Wörterbücher und verlangen die explizite Typisierung von Variablen, was Beispiele unnötig verkompliziert. Daher benutzt dieses
Skript die Programmiersprache Python1 mit den Erweiterungen NumPy und SciPy2 , die
eine leistungsfähige numerische Bibliothek und umfangreiche Visualisierungsmöglichkeiten bietet. Für elementare Beispiele hingegen greift dieses Skript auf das hardwarenähere
C zurück.
Zum Erlernen der Programmiersprachen Python und C sei auf die Materialien der
Veranstaltung „Computergrundlagen“ hingewiesen, die im Fachbereich Physik der Universität Stuttgart jährlich angeboten wird.
Die meisten der in diesem Skript vorgestellten numerischen Methoden werden von SciPy direkt unterstützt. Die Qualität dieser Implementationen ist mit eigenem Code nur
schwierig zu überbieten. Wo immer möglich, wird daher auf die entsprechend SciPyBefehle verwiesen. Zum Beispiel wird auf die Funktion „method“ im SciPy-Modul „library“ in der Form scipy.library.method(arg1, arg2,...) verwiesen. Trotzdem
sind viele Methoden auch als expliziter Code gezeigt, da man natürlich eine Vorstellung
davon haben sollte, was diese Methoden tun.
1
2
www.python.org
http://www.scipy.org
9
1 Einleitung
l
α
Frad
Ftan = FG sin(α)
FG = −mg
Abbildung 1.1: Schematisches Fadenpendel der Masse m, das an einem masselosen, steifen Faden der Länge l hängt.
1.2 Beispiel: Fadenpendel
Wir betrachten ein einfaches Beispielsystem, nämlich ein Fadenpendel. Wird dieses Pendel nun ausgelenkt, vollführt es eine periodische Schwingung um die Ruhelage, d.h., den
tiefsten Punkt. Unser Ziel als Physiker ist nun, die Position der Kugel als Funktion der
Zeit vorherzusagen. Das allerdings ist eine unmögliche Aufgabe — man stelle sich zum
Beispiel eine stark inhomogene Masse vor (oder ein Fadenpendel als Masse) oder dass
der Faden elastisch ist. Daher müssen wir zunächst ein geeignet vereinfachtes Modell
erstellen, auf das wir dann die bekannten physikalischen Gesetze anwenden können.
1.2.1 Modell
Als Modell wählen wir eine homogene Kugel der Masse m, die an einem masselosen,
steifen Faden der Länge l hängt (vergleiche Figur 1.1). Auf diese Kugel wirkt nur eine
Gewichtskraft der Größe mg senkrecht nach unten, alle anderen Kräfte vernachlässigen
wir komplett, insbesondere auch die Reibung.
Da der Faden unendlich steif sein soll, kann sich die Kugel lediglich auf einem Kreis mit
Radius l um die Aufhängung bewegen, d.h. die Position der Kugel ist durch die Auslenkung α aus dem tiefsten Punkt vollständig beschrieben. Weiter wird die Komponente der
Kraft parallel zum Faden komplett von diesem kompensiert, daher bleibt bei Auslenkung
α von der Gewichtskraft nur ihre Komponente
Ftan = FG sin(α) = −mg sin(α)
(1.1)
senkrecht zum Faden übrig. Das Newtonsche Gesetz besagt nun, dass die Tangentialbeschleunigung, also die Beschleunigung entlang α
lα̈ = Ftan /m = −g sin(α)
10
(1.2)
1.2 Beispiel: Fadenpendel
1.5
0.10
1.0
0.05
0.5
0.00
0.0
0.5
0.05
0.100.0
1.0
0.5
1.0
T
1.5
2.0 1.50.0
0.5
1.0
T
1.5
2.0
Abbildung 1.2: Lösungen für ein Fadenpendel der Länge l = 1m. Im linken Graphen ist
die Ausgangslage α = 1,5, im rechten α = 0,1; in beiden Fällen ist die Ausgangsgeschwindigkeit 0. Die durchgezogene grüne Linie markiert die analytische Näherungslösung (1.4)
für kleine Winkel. × markiert die Ergebnisse einer Integration mit dem einfachen Vorwärtsschritt (1.11) mit Zeitschritt 0,1s, die gestrichelte rote Linie mit Zeitschritt 0,01s.
+ markiert die Lösung mit Hilfe des Velocity-Verlet-Algorithmus und Zeitschritt 0,1s.
beträgt. Dies ist jetzt eine Differentialgleichung für die Auslenkung α(t) des Pendels als
Funktion der Zeit. Diese wiederum liefert uns die gewünschte Position (cos(α)l, sin(α)l)
der Kugel relativ zur Aufhängung als Funktion der Zeit. Leider hat selbst diese einfache
Differentialgleichung keine geschlossene Lösung, und wir müssen weitere Näherungen
einführen, um eine analytische Lösung zu erhalten.
1.2.2 Näherung: der harmonische Oszillator
Für kleine Winkel gilt sin(α) ≈ α, und damit
g
α̈ ≈ − α.
l
(1.3)
DiesepDifferentialgleichung beschreibt einen harmonischen Oszillator mit Eigenfrequenz
ω = g/l und hat die allgemeine Lösung
α(t) = A sin(ωt + φ)
(1.4)
wie leicht durch Einsetzen überprüft. Die Größen A und φ ergeben sich aus den Anfangsbedingungen, nämlich der Anfangsposition
α0 = A sin(φ)
(1.5)
11
1 Einleitung
und -geschwindigkeit
v0 = Aω cos(φ).
Ist zum Beispiel v0 = 0, so ist φ = π/2 und A = α0 , im allgemeinen Fall ist
α0
α0 ω
und A =
φ = arctan
.
v0
sin(φ)
(1.6)
(1.7)
Wir haben nun eine geschlossene Lösung für die Position des Pendels, so lange die Ausgangslage nicht zu sehr ausgelenkt ist. Um diese Lösung zu visualisieren, nutzt man heute
üblicherweise den Computer, siehe Graph 1.2.
1.2.3 Numerische Lösung
Was passiert nun, wenn das System stärker ausgelenkt ist? Mit sehr viel mehr Aufwand
lässt sich auch für diesen Fall eine analytische Lösung finden, allerdings in Form einer
Reihe, die nicht mehr so einfach zu zeichnen ist. Eine Alternative ist, die Differentialgleichung (1.2) mit Hilfe des Computers zu berechnen. Wir sagen, wir „simulieren“ das
Pendel. Dazu fixieren wir ein Einheitensystem, zum Beispiel eine Sekunde als Zeiteinheit und einen Meter als Längeneinheit. In diesem System ist also l = 1, g ≈ 9,81 und
ω ≈ 3,13, falls des Pendel einen Meter lang ist.
Zunächst müssen wir das Problem aber für den Computer anpassen, der ja nur mit
(endlich vielen) gewöhnlichen Zahlen rechnen kann, wir müssen das Problem diskretisieren. Wir betrachten nur die Zeitpunkte
tn = nδt, n = 1(1)N,
(1.8)
wobei der Zeitschritt δt frei wählbar ist. Je kleiner δt, desto genauer können wir α(t)
bestimmen, allerdings steigt natürlich die Anzahl der Schritte, die nötig sind, um eine
feste Gesamtzeit zu erreichen. Unsere Lösung, die Funktion α(t) wird also durch ihre
Werte α(tn ) an den diskreten Zeitpunkten dargestellt.
Um Gleichung (1.2) auf den Computer zu bringen, müssen wir uns allerdings noch
überlegen, wie wir mit der Ableitung verfahren. Da wir die Ausgangsposition und -geschwindigkeit gegeben haben, liegt es nahe, die Gleichung zu integrieren:
Z t+δt
v(t + δt) = α̇(t + δt) = v(t) +
−ω 2 sin α(τ ) dτ.
(1.9)
t
Da δt aber unser Zeitschritt ist, wir also nichts weiter über α(τ ) wissen, bietet sich die
folgende Näherung an:
v(t + δt) ≈ v(t) − ω 2 sin α(t)δt.
(1.10)
Analog ergibt sich dann durch nochmalige Integration:
α(t + δt) ≈ α(t) + v(t)δt.
(1.11)
Ausgehend von
α(0) = α0
12
und v(0) = v0
(1.12)
1.2 Beispiel: Fadenpendel
0.060
E
0.055
0.050
0.045
0.0400.0
0.5
1.0
T
1.5
11.0
10.5
10.0
9.5
9.0
8.5
8.0
7.5
2.0 7.00.0
0.5
1.0
T
1.5
2.0
Abbildung 1.3: Energie als Funktion der Zeit, wieder für l = 1m, und Ausgangslage
α = 1,5 (links) und α = 0,1 (rechts) in Ruhe. + markiert die Ergebnisse einer Integration
mit dem einfachen Vorwärtsschritt (1.11) mit Zeitschritt 0,1s, die gestrichelte rote Linie
mit Zeitschritt 0,01s. × markiert die Lösung mit Hilfe des Velocity-Verlet-Algorithmus
und Zeitschritt 0,1s, und die gestrichelte blaue Linie mit 0,01s.
lässt sich damit also α(t) numerisch bestimmen. Der Quellcode 1.1 zeigt, wie eine einfach
Implementation in Python aussehen könnte.
Wie kann man nun überprüfen, ob diese Lösung tatsächlich korrekt ist? Da das System
abgeschlossen ist, muss seine Energie
1
E = l2 v(t)2 + gl(1 − cos(α(t)))
2
(1.13)
erhalten sein. Lässt man sich diese allerdings ausgeben, stellt man fest, dass E(t) erheblich
schwankt, vergleiche Graph 1.3. Dies lässt sich durch Verringern des Zeitschritts beheben,
das kostet aber entsprechend mehr Rechenzeit.
Eine bessere Alternative ist, den Algorithmus zu verbessern, was wiederum etwas analytische Arbeit erfordert. Wir werden im Laufe der Vorlesung verstehen, wie mit Hilfe
von Taylorentwicklungen ein besseres Verfahren gefunden werden kann, der sogenannte
Velocity-Verlet-Algorithmus:
δt
δt
v t+
= v(t) + F (t)
(1.14)
2
2
δt
α(t + δt) = α(t) + δt v t +
(1.15)
2
δt
δt
v(t + δt) = v t +
+ F (t + δt),
(1.16)
2
2
13
1 Einleitung
der anders als die zuerst angegebene Vorgehensweise numerisch stabil ist und quasi keine
Energieschwankungen aufzeigt, vergleiche Graph 1.3. Interessant ist, dass formal die Geschwindigkeiten zu halben Zeitschritten eingehen. Im Quellcode 1.1 ist alternativ auch
dieser Integrator implementiert. Obwohl er nur unwesentlich komplizierter ist als der einfache Integrator zuvor, erreicht etwa dieselbe Genauigkeit wie dieser mit einem Zehntel
der Zeitschritte.
Als weiterer Test bietet sich an, bei kleinen Auslenkungen mit der analytisch bekannten Lösung zu vergleichen, die gut reproduziert wird, siehe Graph 1.2. Bei größeren
Anfangsauslenkungen oder -geschwindigkeiten ist die Abweichung allerdings sehr groß,
weil hier die analytische Näherung versagt. Im Rahmen ihrer Genauigkeit erlaubt also
die numerische Lösung, das vorgegebene Modell in einem größeren Parameterraum auf
sein Verhalten hin zu untersuchen, als analytisch möglich wäre.
14
1.2 Beispiel: Fadenpendel
# Simulation der Bahn eines Fadenpendels
############################################
import scipy as sp
import matplotlib.pyplot as pyplot
# Laenge des Pendelarms
l=1
# Erdbeschleunigung
g = 9.81
# Zeitschritt
dt = 0.01
# Zeitspanne
T = 2
# Methode, "simple" oder "velocity-verlet"
integrator="velocity−verlet"
# (Start-)Position
a = 0.1
# (Start-)Winkelgeschwindigkeit
da = 0
# Zeit
t = 0
# Tabellen fuer die Ausgabe
tn, an, En = [], [], []
# Kraft, die auf die Kugel wirkt
def F(a):
return -g/l*sp.sin(a)
while t < T:
if integrator == "simple":
da += F(a)*dt
a += da*dt
elif integrator == "velocity−verlet":
da += 0.5*F(a)*dt
a += da*dt
da += 0.5*F(a)*dt
t += dt
tn.append(t)
an.append(a)
En.append(0.5*(l*da)**2 + g*(l - l*sp.cos(a)))
# Ausgabe von Graphen
ausgabe = pyplot.figure(figsize=(8,4))
loesung = ausgabe.add_subplot(121)
loesung.set_xlabel("T")
loesung.set_ylabel("Winkel")
loesung.plot(tn, an)
energie = ausgabe.add_subplot(122)
energie.set_xlabel("Zeit")
energie.set_ylabel("Energie")
energie.plot(tn, En)
pyplot.show()
Listing 1.1: Python-Code zum Fadenpendel mit graphisch aufbereiteter Ausgabe mit Hilfe der matplotlib.
15
2 Lineare Algebra I
Lineare Gleichungssysteme sind die einfachste Art von Gleichungssystemen, für die sich
zum Beispiel leicht bestimmen lässt, ob und wie viele Lösungen es gibt. Daher führt
man auch die Lösung komplexerer Probleme, wie zum Beispiel Differentialgleichungen,
oft auf die Lösung eines Satzes von linearen Gleichungssystemen zurück. Lineare Gleichungssysteme sind in diesem Sinne eine der wesentlichen Grundlagen der numerischen
Mathematik. Der händischen Lösung der Systeme steht dabei vor allem ihre Größe im
Weg — Finite-Elemente-Rechnungen können leicht die Lösung von Gleichungssystemen
mit Millionen von Variablen erfordern. Mit modernen Algorithmen und Computern lassen
sich solche Gleichungssysteme allerdings schnell und zuverlässig lösen. In diesem Kapitel lernen wir die grundlegende Methode zum Lösen von Gleichungssystemen kennen,
nämlich die allgemeine, aber langsame Gaußelimination. Daneben lernen wir noch die
LU-Zerlegung und die Choleskyzerlegung kennen, die mit etwas Vorarbeit eine effizientere Lösung erlauben und im Folgenden oft zum Einsatz kommen werden.
Wir betrachten also folgendes Problem: Sei A = (aik ) ∈ Rm×n , b ∈ Rm . Gesucht ist
die Lösung x ∈ Rn des Gleichungssystems
a11 x1
a21 x1
..
.
+
+
a12 x2
a22 x2
..
.
+ ... +
+ ... +
a1n xn
a2n xn
..
.
=
=
b1
b2
..
.
(2.1)
am1 x1 + am2 x2 + . . . + amn xn = bm
oder kurz Ax = b. In dieser allgemeinen Form ist weder garantiert, dass es eine Lösung
gibt (z.B. A = 0, b 6= 0), noch, dass diese eindeutig ist (A = 0, b = 0).
2.1 Dreiecksmatrizen
Eine Matrix A ∈ Rn×n heißt eine rechte obere Dreiecksmatrix, wenn sie quadratisch ist
und aij = 0 für i > j. Analog kann man auch die linken unteren Dreiecksmatrizen
definieren, mit aij = 0 für i < j. In jedem Fall bilden rechte obere und linke untere
Dreiecksmatrizen jeweils Unteralgebren der Matrixalgebra, d.h., sie sind abgeschlossen
unter Addition und Multiplikation. Die Schnittmenge dieser Algebren ist wiederum die
Algebra der Diagonalmatrizen.
Ist A eine rechte obere Dreiecksmatrix, so hat das Gleichungssystem die Form
a11 x1 + a12 x2 + . . . + a1n xn = b1
a22 x2 + . . . + a2n xn = b2
..
..
..
.
.
.
ann xn = bn .
(2.2)
17
2 Lineare Algebra I
Dieses
Gleichungssystem hat genau dann eine Lösung, wenn A regulär ist, also det A =
Qn
i=1 aii 6= 0. Die Lösung kann dann durch Rücksubstitution direkt bestimmt werden:
!
n
X
1
bi −
xi =
aik xk
für i = n(−1)1.
(2.3)
aii
k=i+1
Für reguläre linke untere Dreiecksmatrizen ergibt sich die Lösung entsprechend durch
Vorwärtssubstitution:
!
i−1
X
1
bi −
aik xk
für i = 1(1)n.
(2.4)
xi =
aii
k=1
Für Diagonalmatrizen ist die Situation natürlich einfacher, es gilt
xi =
1
bi
aii
für i = 1(1)n.
(2.5)
SciPy stellt für Dreiecksmatrizen spezielle Löserroutinen zur Verfügung, scipy.
linalg.solve_triangular(A, b, lower=False), wobei lower angibt, ob A
eine linke untere statt rechte obere Dreiecksmatrix ist.
2.2 Gaußelimination
Die Gaußelimination ist ein Verfahren, um eine beliebiges Gleichungssystem Ax = b, mit
A ∈ Rm×n , auf die äquivalente Form
R K
x0 = b0
(2.6)
0 0
zu bringen, wobei R eine reguläre rechte obere Dreiecksmatrix und K ∈ Rk×l beliebig
ist, und x0 eine Permutation (Umordnung) von x. Dieses Gleichungssystem hat offenbar
nur dann eine Lösung, wenn b0i = 0 für i = m − k + 1(1)m.
Diese ist im Allgemeinen auch nicht eindeutig, vielmehr können die freien Variablen
n−k
xK = (x0i )ni=n−k+1 frei gewählt werden. Ist xR = (x0i )i=1
der Satz der verbleibenden
Lösungsvariablen, so gilt also
xL = R−1 b0 − R−1 KxK .
Die Lösungen ergeben sich daraus als
−1 0 R b
−R−1 Ki
0
x =
+
,
0
ei
(2.7)
wobei Ki die i-te Spalte von K und hi den aufgespannten Vektorraum bezeichnet. Die
Ausdrücke, die R−1 enthalten, können durch Rücksubstitution bestimmt werden.
Um das System Ax = b, das wir im Folgenden als A|b zusammenfassen, auf diese Form
zu bringen, stehen folgende Elementaroperationen zur Verfügung, die offensichtlich die
Lösung nicht verändern:
18
2.2 Gaußelimination
1. Vertauschen zweier Gleichungen (Zeilentausch in A|b)
2. Vertauschen zweier Spalten in x und A (Variablenaustausch)
3. Addieren eines Vielfachen einer Zeile zu einer anderen
4. Multiplikation einer Zeile mit einer Konstanten ungleich 0
Die Gaußelimination nutzt nun diese Operationen, um die Matrix spaltenweise auf die
gewünschte Dreiecksform zu bringen. Dazu werden Vielfache der ersten Zeile von allen
anderen abgezogen, so dass die Gleichung die Form
 (0) (0)

(0)
(0)
a11 a12 . . . a1n b1

(1)
(1)
(1) 
 0
a22 . . . a2n b2 
(1) (1)
 .
(2.8)
.. 
..
..
 .
 =: A |b
. 
.
.
 .
0
(1)
(1)
(1)
am2 . . . amn bm
annimmt, wobei
(1)
aik
(1)
bi
(1)
a1k
(0)
(1) (0)
= aik − li a1k
=
=
(0)
(1) (0)
bi − li b1
(0)
(1)
(0)
a1k , b1 = b1
für i = 2(1)n, k = 1(1)m
(0)
(1)
mit li
für i = 2(1)n
=
ai1
(0)
.
(2.9)
a11
sonst
Mit dem verbleibenden Resttableau wird nun genauso weiter verfahren:
(r)
aik
(r)
bi
(r)
aik
(r−1)
= aik
=
=
(r) (r−1)
− li ar,k
(r−1)
(r) (r−1)
bi
− li br
(r−1)
(r)
(r−1)
aik , bi = bi
für i = r + 1(1)n, k = r(1)m
für i = r + 1(1)n
(r−1)
(r)
mit li
sonst
=
air
(r−1)
.
arr
(2.10)
Das Verfahren ist beendet, wenn das Resttableau nur noch eine Zeile hat.
(r−1)
Ist während eines Schrittes arr
= 0 und
(r−1)
1. nicht alle air
= 0, i = r + 1(1)m. Dann tauscht man Zeile r gegen eine Zeile i
(r−1)
mit air
6= 0, und fährt fort.
(r−1)
(r−1)
2. alle air
= 0, i = r(1)m, aber es gibt ein aik
6= 0 mit i,k ≥ r. Dann vertauscht
man zunächst Zeile r mit Zeile i, tauscht anschließend Spalte k mit Spalte r, und
fährt fort.
(r−1)
3. alle aik
= 0 für i,k ≥ r. Dann hat A(r−1) |b(r−1) die gewünschte Form (2.6)
erreicht, und das Verfahren terminiert.
(r−1)
Das Element arr
heißt auch Pivotelement, da es sozusagen der Dreh- und Angelpunkt des iterativen Verfahrens ist. In der Praxis ist es numerisch günstiger, wenn dieses
Element möglichst groß ist. Das lässt sich erreichen, indem wie in den singulären Fällen
verfahren wird, also Zeilen oder Spalten getauscht werden, um das betragsmäßig maxi(r−1)
male aik
nach vorne zu bringen. Folgende Verfahren werden unterschieden
19
2 Lineare Algebra I
(r−1)
• kanonische Pivotwahl: es wird stets arr
gewählt und abgebrochen, falls dieses
betragsmäßig
zu klein wird. Diese Verfahren scheitert schon bei einfachen Matrizen
(z.B. 01 10 ), und kann daher nur eingesetzt werden, wenn die Struktur der Matrix
(r−1)
sicherstellt, das arr
stets hinreichend groß ist.
• Spaltenpivotwahl : es wird wie oben im 1. Fall nur in der Spalte maximiert, d.h. wir
wählen als Pivotelement
(r−1)
i0 = argmaxi>r |air |
(2.11)
und tauschen Zeilen i0 und r; die Variablenreihenfolge bleibt unverändert. Ist die
Matrix A quadratisch, bricht das Verfahren genau dann ab, wenn A singulär ist.
• Totalpivotwahl : wie oben im 2. Fall wird stets das betragsmäßig maximale Matrixelement im gesamten Resttableau gesucht, also
(r−1)
i0 ,k0 = argmaxi,k>r |aik
|.
(2.12)
Dann vertauscht man zunächst Zeile r mit Zeile i0 , und tauscht anschließend Spalte k0 mit Spalte r, wobei man sich noch die Permutation der Variablen geeignet
merken muss, zum Beispiel als Vektor von Indizes.
Unabhängig von der Pivotwahl benötigt die Gaußelimination bei quadratischen Matrizen im wesentlichen O(n3 ) Fließkommaoperationen. Das ist relativ langsam, daher werden wir später bessere approximative Verfahren kennenlernen. Für Matrizen bestimmter
Struktur, zum Beispiel Bandmatrizen, ist die Gaußelimination aber gut geeignet. NumPy bzw. SciPy stellen daher auch keine Gaußelimination direkt zur Verfügung. scipy.
linalg.solve(A, b) ist ein Löser für Gleichungssysteme Ax = b, der immerhin auf
der LU-Zerlegung durch Gaußelimination basiert. Dieser Löser setzt allerdings voraus,
dass die Matrix nicht singulär ist, also eindeutig lösbar.
2.3 Matrixinversion
Ist A ∈ Rn×n regulär, so liefert die Rücksubstitution implizit die Inverse von A, da
für beliebige b das Gleichungssystem Ax = b gelöst werden kann. Allerdings muss das
für jedes b von neuem geschehen. Alternativ kann mit Hilfe der Gaußelimination auch
die Inverse von A bestimmt werden. Dazu wird das Tableau A|I in das Tableau I|A−1
transformiert, wobei I die n×n-Einheitsmatrix bezeichnet. Die Vorgehensweise entspricht
zunächst der Gaußelimination mit Spaltenpivotwahl. Allerdings werden nicht nur die
Elemente unterhalb der Diagonalen, sondern auch oberhalb eliminiert. Zusätzlich wird
(i−1)
die Pivotzeile noch mit 1/aii
multipliziert, so dass das A schrittweise die Form


(2)
(2)
1 0 a12 . . . a1n

(2) 
 0 1 a(2)

22 . . . a2n 

 ..
(2)
(2) 
(2.13)
 . 0 a32 . . . a3n 
 . .

.
.
 . .
..
.. 
 . .

(2)
(2)
0 0 an2 . . . ann
20
2.4 LU-Zerlegung
annimmt. Das Verfahren ist allerdings numerisch nicht sehr stabil, und generell sollte die
explizite Berechnung der Inversen wann immer möglich vermieden werden. SciPy stellt
die Matrixinversion als Funktion scipy.linalg.inv(A) zur Verfügung.
Eine Ausnahme bilden Matrizen der Form I + A mit kAk = maxkAxk/kxk < 1. Dann
ist
(I + A)−1 = I − A + A2 − A3 + · · ·
(2.14)
eine gut konvergierende Näherung der Inversen.
2.4 LU-Zerlegung
Eine weitere Anwendung der Gaußelimination ist die LU-Zerlegung von bestimmten quadratischen Matrizen. Dabei wird eine Matrix A ∈ Rn×n so in eine ein linke untere Dreiecksmatrix L und eine rechte obere Dreiecksmatrix U zerlegt, dass A = L · U . Um
die LU-Zerlegung eindeutig zu machen, vereinbart man üblicherweise, dass lii = 1 für
i = 1(1)n. Das U steht übrigens für das englische „upper right“ und L für „lower left“.
Im Deutschen findet sich vereinzelt noch der Begriff LR-Zerlegung, wobei hier L für eine
linke untere und R für eine rechte obere Matrix steht.
Ist eine solche Zerlegung einmal gefunden, lässt sich das Gleichungssystem Ax = b für
beliebige b effizient durch Vorwärts- und Rücksubstitution lösen:
Ly = b, U x = y
=⇒
Ax = L U x = Ly = b.
(2.15)
Zunächst wird also y durch Vorwärtssubstitution berechnet, anschließend x durch Rückwärtssubstitution. Die Inverse lässt sich so auch bestimmen:
Lyi = ei , U xi = yi
für i = 1(1)n
=⇒
A−1 = (x1 , . . . , xn ) .
(2.16)
Die Determinante von A = L · U ist ebenfalls einfach zu bestimmen:
det A = det L det U =
n
Y
uii
(2.17)
i=1
Um die LU-Zerlegung zu berechnen, nutzen wir wieder die Gaußelimination. Kann bei
A ∈ Rn×n die Gaußelimination in kanonischer Pivotwahl durchgeführt werden, so ist die
LU-Zerlegung von A durch U = A(n−1) , also die finale, auf rechte obere Dreiecksform
transformierte Matrix, und durch die Matrix


1
0

l(0) 1

1
 (0) (1)



l
l
1
(2.18)
L=2
2

 ..

..
..
.
.

 .
(0)
ln
...
(n−1)
. . . ln
1
der Updatekoeffizienten aus (2.10) gegeben.
21
2 Lineare Algebra I
Wie bereits gesagt, ist die Voraussetzung, dass die Gaußelimination mit kanonischer
Pivotwahl
durchgeführt
werden kann, sehr restriktiv, und schließt selbst einfache Matri
zen wie 01 10 aus. Wie man sich leicht überlegt, besitzt diese Matrix allerdings keine
LU-Zerlegung.
Für manche Anwendungen ist es günstiger, wenn L und U normiert sind. Dann benutzt
man die LDU-Zerlegung A = LDU , mit L linker unterer Dreiecksmatrix, D Diagonalmatrix und U rechter oberer Dreiecksmatrix. Jetzt müssen lii = 1 und rii = 1 sein. Die
LDU-Zerlegung ergibt sich aus der LU-Zerlegung durch dii = uii und u0ik = uik /uii .
In SciPy ist die LU-Zerlegung in den Funktionen scipy.linalg.lu_factor(A
) oder scipy.linalg.lu(A) (zur Zerlegung der Matrix A) und scipy.linalg.
lu_solve((lu,piv), b) (zum Lösen des LGS) implementiert.
2.5 Cholesky-Zerlegung
Wir betrachten im Folgenden nur symmetrische, positiv definite Matrizen, wie sie gerade
in der Physik oft vorkommen. Auch in der Optimierung spielen diese eine wichtige Rolle.
Sei A = LDU eine LDU-Zerlegung einer symmetrischen Matrix, dann gilt
LDU = A = AT = (LDU )T = U T DLT ,
(2.19)
wobei T wie eingangs erwähnt die Transponierte von A bezeichnet. Da die LDU-Zerlegung
aber eindeutig ist und U T eine normierte, linke untere Dreiecksmatrix und LT eine normierte, rechte obere Dreiecksmatrix, so gilt U = U T , und damit
p
bT U
b mit U
b = diag( dii )U.
A = U T DU = U
(2.20)
Dies ist die Cholesky-Zerlegung. Anstatt die Gaußelimination durchzuführen, lässt sich
die Zerlegung aber auch direkt mit Hilfe des Cholesky-Verfahrens bestimmen: Sei A =
bT R
b eine Cholesky-Zerlegung. Da R
b unterhalb der Diagonalen nur 0 enthält, gilt
R
aik =
i
X
r̂li r̂lk
für i = 1(1)n, k = 1(1)n.
(2.21)
l=1
b direkt ablesen:
Daraus lässt sich die erste Zeile von R
√
a1k
r̂11 = a11 und r̂1k =
für k = 2(1)n.
r̂11
Die nächsten Zeilen lassen sich analog bestimmen, da für jedes i
v
u
i
i−1
X
X
u
2
t
aii =
r̂li
=⇒ r̂ii = aii −
r̂li2 .
l=1
(2.22)
(2.23)
l=1
Für die restlichen Elemente der Zeile gilt
r̂ik
22
1
=
r̂ii
aik −
i−1
X
l=1
!
r̂li r̂lk
für k = i + 1(1)n
(2.24)
2.6 Bandmatrizen
Das Cholesky-Verfahren ist wie die Gaußelimination von der Ordnung O(n3 ), braucht
aber nur halb so viele Operationen. In SciPy ist die Cholesky-Zerlegung als scipy.
linalg.cholesky(A) implementiert.
2.6 Bandmatrizen
Im Folgenden werden wir oft mit k-Bandmatrizen zu tun haben, also Matrizen, bei denen
nur die Diagonale und einige Nebendiagonalen besetzt sind. Diagonalmatrizen sind also
1-Bandmatrizen, eine Dreibandmatrix hat die Form


d1 t1
0
 b1 d2

t2




..
..
..
(2.25)

.
.
.
.




bn−2 dn−1 tn−1
0
bn−1 dn
Für Matrizen dieser Form ist die Gaußelimination mit kanonischer Pivotwahl sehr effizient, da pro Iteration jeweils nur die erste Zeile des Resttableaus verändert werden
muss. Dadurch ist der Rechenaufwand nur noch linear in der Matrixgröße bzw. Länge
der Bänder. Die Dreiecksmatrizen L und U der LU-Zerlegung sind zusätzlich (Drei-)
Bandmatrizen, wobei L nur auf der Haupt und der unteren Nebendiagonalen von Null
verschiedene Einträge hat, U nur auf der Diagonalen und der Nebendiagonalen oberhalb.
SciPy stellt für Bandmatrizen ebenfalls spezielle Löserroutinen zur Verfügung, scipy
.linalg.solve_banded((l,u), A, b), wobei l und u die Anzahl der Nebendiagonalen oberhalb und unterhalb angeben, und A die Matrix in Bandform angibt.
23
3 Darstellung von Funktionen
Auch moderne Prozessoren beherrschen nur die Grundrechenarten. Wie kann man also
auf einem Computer kompliziertere Funktionen berechnen, wie z.B. die Sinusfunktion?
Beispielsweise könnte man die Funktionen als Vektor von Funktionswerten speichern.
Für die graphische Darstellung reicht das aus, aber um Funktionen mit wenigstens sechs
Stellen Genauigkeit im Computer bereitzustellen, wären Millionen von Stützstellen nötig.
Daher müssen bessere Darstellungen für Funktionen genutzt werden. Um beliebige
Funktionen auf dem Computer berechnen zu können, führt man diese meist auf (stückweise definierte) Polynome zurück, die nur mit Hilfe der Grundrechenarten berechnet
werden können. Dies ist selbst dann der Fall, wenn ein Prozessor gewisse Funktionen
scheinbar in Hardware implementiert hat; tatsächlich führt dieser intern die notwendigen
elementaren Operationen durch.
3.1 Horner-Schema
Pn
i
Die naive Auswertung eines Polynoms
i=0 ci x mit n + 1 Termen bzw. vom Grad
n benötigt n Additionen und 2n Multiplikationen sowie einen Zwischenspeicher für die
Potenzen xi des Arguments x. Besser ist die Auswertung des Polynoms nach dem HornerSchema:
n
X
ci xi = c0 + x(c1 + x(c2 + x(. . . (cn−1 + xcn )))).
(3.1)
i=0
Wird dieser Ausdruck von rechts nach links ausgewertet, so muss das Ergebnis in jedem
Schritt nur mit x multipliziert und der nächste Koeffizient addiert werden, was nur n
Multiplikationen und Additionen benötigt. Auch muss kein Zwischenwert gespeichert
werden, was Prozessorregister spart. Als C-Code sieht die Auswertung des Hornerschemas
so aus:
double horner(double *series, int n, double x)
{
double r = series[n];
for(int i = n-1; i >= 0; --i)
r = r*x + series[i];
return r;
}
Die Polynomauswertung stellt NumPy als numpy.polyval(x, c) zur Verfügung.
c bezeichnet die Koeffizienten des Polynoms und x das Argument, für das das Polynom
ausgewertet werden soll.
25
3 Darstellung von Funktionen
Eine weitere Anwendung des Hornerschemas ist die Polynomdivision durch lineare
Polynome der Form x − x0 , die zum Beispiel wichtig für die iterative Bestimmung von
Nullstellen ist. Es gilt nämlich
!
n
n−1
X
X
i
i
P (x) =
ci x =
di+1 x (x − x0 ) + d0 ,
(3.2)
i=0
i=0
wobei di = ci + x0 (ci+1 + x0 (. . . (cn−1 + xo cn ))) die Zwischenterme des Hornerschemas bei
Auswertung an der Stelle x0 sind. d0 ist dabei der Divisionsrest; ist P (x) durch x − x0
teilbar, so ist d0 = 0.
Dies zeigt man durch Induktion: für P (x) = c1 x + c0 ist offenbar P (x) = c1 (x − x0 ) +
c0 + xc1 = d1 (x − x0 ) + d0 . Für Grad n ist also
!
!
n−1
n−2
X
X
i
0
i
0
P (x) = x
ci+1 x + c0 = x
di+1 x (x − x0 ) + d0 + d0
(3.3)
i=0
i=0
wobei
die d0i = ci+1 + x0 (ci+2 + x0 (. . . (cn−1 + xo cn ))) = di+1 bei der Polynomdivision
Psich
n−1
von i=0 ci+1 xi durch x − x0 ergeben. Daher ist
!
n−2
X
P (x) =
di+2 xi+1 + d1 (x − x0 ) + d0 + x0 d1 ,
(3.4)
i=0
was zu zeigen war.
3.2 Taylorreihen
Nachdem wir nun wissen, wie Polynome effizient ausgewertet werden können, stellt sich
die Frage, wie man ein gutes Näherungspolynom für eine Funktion bekommt. Dazu gibt
es viele verschiedene Ansätze, deren Vor- und Nachteile im Folgenden kurz besprochen
werden. Der älteste Ansatz, der auch in der Analytik weiten Einsatz findet, ist die Taylorentwicklung. Ist eine Funktion f um einen Punkt xo hinreichend gut differenzierbar,
lässt sie sich als bekannterweise lokal als Taylorreihe darstellen:
f (x) =
∞
X
f (i) (x0 )
i=0
i!
(x − x0 )i ,
(3.5)
wobei f (i) (x) die i-te Ableitung von f an der Stelle x bezeichnet. Falls die Ableitungen
existieren und x − x0 klein genug ist, so konvergiert diese Darstellung schnell, und einige
Terme genügen, um zufriedenstellende Genauigkeit zu erreichen. Lokal um den Entwicklungspunkt x0 is eine abgeschnittene Taylorreihe also eine gute polynomielle Näherung.
Leider gibt es für die meisten Funktionen einen Konvergenzradius, außerhalb dessen die
Reihe nicht einmal konvergiert. Daher eignen sich Taylorreihen vor allem gut für kleine
Umgebungen. Auch ist eine abgeschnittene Taylorreihe nur im Entwicklungspunkt x0
exakt; dort stimmen allerdings gleich die ersten i Ableitungen.
26
3.3 Polynom- oder Lagrangeinterpolation
1.5
1.0
0.5
0.0
0.5
1.0
1.5 3
1
2
1
0
2
3
Abbildung 3.1: Näherung der Sinusfunktion durch die abgeschnittene Taylorreihe. Als
schwarze durchgezogene Linie ist die tatsächliche Sinusfunktion dargestellt, blau gepunktet ist die Näherung erster Ordnung um Null, x, grün durchgezogen ist die kubische Näherung x−x3 /6, und rot gestrichelt x−x3 /6+x5 /120. Die Kurven nutzen die Symmetrie
der Sinuskurve, sind also an ±π/2 gespiegelt.
Um zum Beispiel die oben angeführte Sinusfunktion mit 7 Stellen Genauigkeit im
Intervall [0 : π/2] auszuwerten, genügen die ersten 7 Terme der Taylorreihe. Mit Hilfe der
Symmetrien der Funktion lässt sie sich damit bereits für alle Argumente auswerten. Da
sin0 (x) = cos(x) und
cos0 (x) = − sin(x),
ergibt sich die bekannte Reihe
sin(x) =
∞
X
sin(i) (0)
i=0
i!
xi =
∞
X
(−1)i 2i+1
x
.
(2i + 1)!
(3.6)
i=0
Wie gut diese Darstellung mit entsprechender Rückfaltung funktioniert, zeigt Abbildung 3.1. Für viele andere komplexe Funktionen ist es ebenfalls möglich, Taylorreihen
analytisch oder numerisch zu bestimmen, die dann zur Auswertung auf dem Computer
genutzt werden können.
3.3 Polynom- oder Lagrangeinterpolation
Wie besprochen ist eine abgeschnittene Taylorreihe nur im Entwicklungspunkt exakt
(dann allerdings auch die Ableitungen), innerhalb des Konvergenzradius nur eine Annäherung, und außerhalb des Konvergenzradius sogar divergent. Oft möchte man aber eher
27
3 Darstellung von Funktionen
1.5
1.5
1.0
1.0
0.5
0.5
0.0
0.0
0.5
4
2
0
2
4
0.5
4
2
0
2
4
Abbildung 3.2: Lagrange-Interpolation der Rungefunktion 1/(1+x2 ) (schwarze Linie). Im
linken Graph sind die Stützstellen äquidistant gewählt (markierte Punkte), die farbigen
Linien sind die interpolierenden Polynome durch 3 (rot), 5 (lila), 7 (blau) und 11 (grün)
Stützstellen. Mit steigender Ordnung wird die Interpolation am Rand immer schlechter,
das Polynom 10. Ordnung erreicht Werte bis nahe an zwei. Im rechten Graph sind für die
gleichen Ordnungen Chebyshev-Stützstellen gewählt worden, die den Interpolationsfehler
minimieren.
für einen größeren Wertebereich eine gute (oder wenn möglich exakte) Darstellung der
Funktion haben.
Eine Möglichkeit dazu bietet die Polynom- oder Lagrangeinterpolation. Dazu legt man
eine Anzahl von Punkten im gewünschten Wertebereich fest (die sogenannten Stützstellen). Wie sich zeigt, gibt es dann genau ein Polynom, dass die Funktion an diesen Punkten
exakt interpoliert. Genauer: seien Punkte (xi , yi ), i = 0(1)n
− 1 gegeben mit xi paarweise
Pn−1
verschieden. Dann gibt es genau ein Polynom P (x) = k=0 ak xk vom Grad n − 1, so
dass P (xi ) = yi , da die Gleichung
y1 = P (x0 ) = a0 + a1 x0 + · · · + an−1 xn−1
0
..
.
(3.7)
n−1
yn = P (xn−1 ) = a0 + a1 xn−1 + · · · + an−1 xn−1
genau eine Lösung hat.
Leider ist aber nicht gewährleistet, dass mit steigender Anzahl von Punkten die Funktion auch zwischen den Stützstellen immer besser angenähert wird. Tatsächlich hat Runge
ein einfaches Beispiel angegeben, nämlich die Rungefunktion 1/(1 + x2 ), für die die Näherung mit steigender Anzahl an äquidistanten Punkten immer schlechter wird, siehe
Abbildung 3.2.
28
3.3 Polynom- oder Lagrangeinterpolation
Bei der etwas allgemeineren Hermite-Interpolation können an den Stützstellen neben
den Funktionswerten auch Ableitungen vorgegeben werden. Das eindeutige interpolierende Polynom hat dann einen Grad, der der Gesamtanzahl an vorgegebenen Funktionswerten und Ableitungen entspricht. Ist zum Beispiel nur eine Stützstelle x0 gegeben und
neben dem Funktionswert n Ableitungen, so entspricht das Hermite-Polynom genau den
ersten n + 1 Termen der Taylorreihe.
Das interpolierende Polynom kann nicht nur zur Interpolation verwendet werden, also
der Bestimmung an Punkten zwischen den Stützstellen, sondern — mit Vorsicht — auch
zur Extrapolation, also um Werte außerhalb des Bereichs zu bestimmen. Da bei der
Hermite-Interpolation auch die Ableitungen insbesondere am Rand kontrolliert werden
können, ist diese hier tendenziell vorteilhafter. Extrapolation spielt eine wichtige Rolle,
wenn eine direkte Auswertung der Zielfunktion numerisch zu teuer oder unmöglich wird.
Bei Computersimulationen tritt dies insbesondere in der Nähe von kritischen Punkten
auf.
In SciPy liefert die Funktion scipy.interpolate.lagrange(x, y) das interpolierende Polynom durch die Stützstellen (x[i], y[i]).
3.3.1 Lagrangepolynome
Die Koeffizienten ai können im Prinzip als Lösung von Gleichung (3.7) mit geeigneten
Lösern für lineare Gleichungssysteme gefunden werden, was im Allgemeinen allerdings
recht langsam ist. Daher benutzt man besser eine direkte Darstellung mit Hilfe der Lagrangepolynome, die wie folgt definiert sind:
Li (x) =
Y x − xk
.
xi − xk
(3.8)
k6=i
Die Polynominterpolation wird daher auch Lagrange-Interpolation genannt. Wie man
leicht sieht, gilt Li (xk ) = δik , so dass das Polynom
P (x) =
n
X
yi Li (x)
(3.9)
i=1
das eindeutige interpolierende Polynom durch (xi , yi ) ist.
Diese Darstellung ist allerdings für praktische Zwecke nur sinnvoll, wenn sich die Stützstellen xi nicht ändern, da die Bestimmung der Lagrangepolynome Li (x) zeitaufwändig
ist. Geeigneter ist die baryzentrische Darstellung
P (x) =
n−1
X
i=0
yi µi
. n−1
X
i=0
µi
mit µi :=
1 Y
1
,
x − xi
xi − xk
(3.10)
k6=i
bei der lediglich der Quotient zweier rationaler Funktionen gebildet werden muss.
29
3 Darstellung von Funktionen
3.3.2 Neville-Aitken-Schema
Das rekursive Neville-Schema ist eine effiziente Möglichkeit, das interpolierende Polynom
auszuwerten ohne es tatsächlich zu berechnen. Das ist nützlich, wenn nur wenige Auswertungen nötig sind, wie zum Beispiel beim Romberg-Integrationsverfahren, bei dem
zur Schrittweite 0 extrapoliert wird.
Wir definieren Pi,k als das interpolierende Polynom der Ordnung k − 1 durch die
Stützstellen xj , j = i(1)i+k−1. Gesucht ist der Wert P (x) = P0,n (x) des interpolierenden
Polynoms an der Stelle x. Dann ist
Pi,1 (x) = yi
für i = 0(1)n − 1
(3.11)
und
Pi,k (x) =
Pi,k−1 (x)(xi+k−1 − x) + Pi+1,k−1 (x)(x − xi )
xi+k−1 − xi
für k = 2(1)n, i = 0(1)n − k,
(3.12)
da ja an den inneren Stützstellen xl , l = i + 1(1)i + k − 2, Pi,k−1 (xl ) = Pi+1,k−1 (xl ) = yl
gilt, und per Konstruktion Pi,k (xi ) = yi und Pi,k (xi+k−1 ) = yi+k−1 . Durch sukzessives
Berechnen zunächst der Pi,2 (x), dann der Pi,3 (x), usw. lässt sich das interpolierende
Polynom bequem an einer fixen Stelle auswerten. Als (Neville-)Schema sieht das so aus:
y0
y1
y2
y3
..
.
P0,2 (x)
P1,2 (x)
P2,2 (x)
..
.
P0,3 (x)
P1,3 (x)
..
.
P0,3 (x)
..
.
wobei die Pfeilpaare dividierte Differenzen gemäß (3.12) bedeuten.
3.3.3 Newtonsche Darstellung
Wir betrachten nun die Polynome P0,k des Nevilleschemas. Es gilt offenbar
P0,k (x) − P0,k−1 (x) = γk (x − x0 ) · · · (x − xk−2 ),
(3.13)
da die beiden Polynome in den Stützstellen x0 , . . . ,xk−2 übereinstimmen und die Differenz
ein Polynom vom Grad k − 1 ist, also höchstens k − 1 Nullstellen hat. Weiter ist γk der
führende Koeffizient des Polynoms P0,k (t), da P0,k−1 (t) ja einen niedrigeren Grad hat.
Daraus ergibt sich die folgende Newtonsche Darstellung des interpolierenden Polynoms:
n
X
P0,n (x) = y0 +
P0,k (x) − P0,k−1 (x)
k=2
= y0 + γ2 (x − x0 ) + γ3 (x − x0 )(x − x1 ) + · · · + γn (x − x0 ) · · · (x − xn−2 )
= y0 + (x − x0 ) γ2 + (x − x1 ) γ3 + · · · γn−1 + (x − xn−2 )γn · · ·
.
(3.14)
30
3.3 Polynom- oder Lagrangeinterpolation
Die letztere Umformung zeigt, dass sich die Newtonsche Darstellung effizient mit einem
leicht abgewandelten Hornerschema auswerten lässt:
def horner(x0, x, gamma):
r = 0
for k in range(len(x)-1, -1, -1):
r = r*(x0-x[k]) + gamma[k];
return r
Die Koeffizienten γi , i = 2(1)n lassen sich dabei bequem mit dem Nevilleschema bestimmen. γk ist ja der höchste Koeffizient von P0,k ist, der sich leicht aus (3.12) berechnen
lässt. Wenn γi,k den führenden Koeffizienten des Polynoms Pi,k bezeichnet, so erhalten
wir das Nevilleschema
γi,1 = yi für i = 0(1)n − 1 und
γi+1,k−1 − γi,k−1
γi,k =
für k = 2(1)n, i = 0(1)n − k.
xi+k−1 − xi
(3.15)
(3.16)
Da letztlich nur die γ0,k interessant sind, also die obere Diagonale des Nevilleschemas,
benötigt man für die Berechnung nur einen Vektor
γ 0 = (γ0,1 ,γ0,2 , . . . ,γ0,k−1 , γ0,k ,γ1,k , . . . ,γn−k,k ) ,
(3.17)
der wie folgt berechnet wird:
def neville(x, y):
n = len(x)
gamma = y.copy()
for k in range(1, n):
for i in range(n-k-1, -1, -1):
gamma[i+k] = (gamma[i+k] - gamma[i+k-1])/(x[i+k] - x[i])
return gamma
Man beachte, dass die Schleife über i herunterläuft, um benötigte Werte nicht zu überschreiben.
3.3.4 Chebyshev-Stützstellen
Bis jetzt haben wir wenig zur Wahl der Stützstellen gesagt. Oft liegt es auch nahe,
äquidistante Stützstellen zu verwenden wie im Fadenpendel-Beispiel. Man kann allerdings
zeigen, dass die Chebyshev-Stützstellen den Fehler der Polynominterpolation minimieren.
Diese sind definiert als die Nullstellen der Polynome (!)
Tn (cos φ) = cos(nφ),
(3.18)
die offensichtlich zwischen -1 und 1 liegen und daher geeignet skaliert werden müssen für
die Interpolation in einem allgemeinen Intervall. Die Chebyshev-Polynome Tn ,√n ≥ 0,
bilden eine orthogonale Basis der Funktionen über [−1,1] bezüglich des mit 1/ 1 − x2
31
3 Darstellung von Funktionen
gewichteten Skalarprodukts. Daher kann jede genügend glatte Funktion auf [−1 : 1] als
eine Reihe
∞
X
f (x) =
an Tn (x)
(3.19)
n=0
dargestellt werden, die sogenannte Chebyshev-Reihe (siehe auch z.B. Abramowitz und
Stegun [AS70]).
Explizit sind diese Nullstellen gegeben durch
2k + 1
xk,n = cos
π , k = 0(1)n − 1.
(3.20)
2n
Wird die Rungefunktion mit Chebyshevstützstellen interpoliert, so konvergiert das interpolierende Polynom, im Gegensatz zu äquidistanten Stützstellen.
3.4 Splines
Wie wir gesehen haben, kann unter ungünstigen Umständen die Güte der Polynominterpolation mit steigender Anzahl an Stützstellen sinken, vor allem, wenn diese äquidistant
verteilt sind. Oft ist das aber nicht zu vermeiden, zum Beispiel, wenn die Daten in einem Experiment regelmäßig gemessen werden. Das Problem ist, das die Koeffizienten des
Polynoms global gelten, sich glatte Funktionen aber nur lokal wie ein Polynom verhalten (Taylorentwicklung!). Daher ist es günstiger, statt der gesamten Funktion nur kleine
Abschnitte durch Polynome zu nähern.
Der einfachste Fall einer solchen Näherung ist die lineare Interpolation, bei der die
Stützstellen durch Geraden, also Polynome vom Grad 1, verbunden werden. Sind die
Stützstellen (xi , yi ), i = 1(1)n gegeben, so ist der lineare interpolierende Spline
P1 (x) =
(xi+1 − x)yi + (x − xi )yi+1
xi+1 − xi
für xi ≤ x < xi+1 .
(3.21)
Diese Funktionen sind aber an den Stützstellen im Allgemeinen nicht differenzierbar.
Soll die Interpolierende differenzierbar sein, müssen Polynome höherer Ordnung genutzt
werden. Solche stückweise definierten Polynome heißen Splines — das englische Wort
Splines bezeichnete dünne Latten, die vor dem Computerzeitalter benutzt wurden, um
glatte, gebogene Oberflächen vor allem für Schiffsrümpfe zu entwickeln. Der wichtigste
Spline ist der kubische oder natürliche Spline, der aus Polynomen dritten Grades zusammengesetzt und zweifach stetig differenzierbar ist. Seine allgemeine Form ist
1
1
P3 (x) = yi + mi (x − xi ) + Mi (x − xi )2 + αi (x − xi )3
2
6
für xi ≤ x < xi+1 .
(3.22)
Da die zwei rechten und linken zweiten Ableitungen an den Stützstellen übereinstimmen
müssen, gilt
Mi+1 − Mi
αi =
.
(3.23)
xi+1 − xi
32
3.4 Splines
1.0
0.8
0.6
0.4
0.2
0.0
4
2
0
2
4
Abbildung 3.3: Spline-Interpolation der Rungefunktion (durchgezogene schwarze Linie).
Die gestrichelte blaue Linie ist die lineare Spline-Interpolierende mit 7 Stützstellen, die
anderen Kurven sind kubische Splines mit 7 (grün gepunktet) und 11 Stützstellen (rot
gestrichelt). Mit 11 Stützstellen ist der Spline von der Rungefunktion praktisch nicht
mehr zu unterscheiden.
Aus der Gleichheit der Funktionswerte an den Stützstellen ergibt sich
mi =
yi+1 − yi
1
− (xi+1 − xi )(2Mi + Mi+1 ).
xi+1 − xi 6
(3.24)
Aus der Gleichheit der ersten Ableitungen ergibt sich schließlich ein Gleichungssystem
für die Mi . Hier kommen in den Gleichungen gleichzeitig Mi−1 , Mi und Mi+1 vor, daher
müssen für die Randwerte weitere Vorgaben gemacht werden. Sollen die Splines am Rand
festgelegte 2. Ableitungen M0 und Mn haben, so hat das Gleichungssystem die Form





6S1 − µ1 M0
M1
2 λ1
0
  M2 
µ2 2 λ2


6S2











.
.
..
..
..
..
(3.25)
  ..  = 

,
.
.
.











µn−2
2
λn−2
Mn−2
6Sn−2
0
µn−1
2
Mn−1
6Sn−1 − λn−1 Mn
mit
λi =
xi − xi−1
xi+1 − xi
, µi =
xi+1 − xi−1
xi+1 + xi−1
und Si =
yi+1 −yi
xi+1 −xi
−
yi −yi−1
xi −xi−1
xi+1 − xi−1
.
(3.26)
Auch periodische Funktionen können kubisch interpoliert werden, wobei dann die zusätzliche Bedingungen durch die Kontinuität über die periodische Grenze hinweg gegeben
33
3 Darstellung von Funktionen
sind. Die Gleichungen für αi und mi sind dabei unverändert, nur das Gleichungssystem
wird





2
λ1
µ1
6S1
M1
 µ2
 6S2 
  M2 
2 λ2
0







 . 


.
..
..
..
(3.27)

  ..  =  ..  ,
.
.
.











6Sn−2
0
µn−2
2
λn−2
Mn−2
6Sn−1
λn−1
µn−1
2
Mn−1
wobei die Funktion als xn − x1 -periodisch mit y1 = yn vorausgesetzt wird. Abbildung 3.3
zeigt die Spline-Interpolation der Rungefunktion, die für diesen Interpolationstyp keine
Probleme zeigt.
Die Gleichungssysteme (3.25) und (3.27) sind sehr gut konditioniert und mit einem
einfachen Gleichungslöser zu behandeln. Zum Beispiel ist die Gauß-Elimination ist für
die hier auftretenden einfachen Bandstrukturen sehr effizient. In SciPy gibt es selbstverständlich bereits eine fertige Routine für die Spline-Interpolation, nämlich scipy.
interpolate.interp1d(x, y, kind). (x,y) sind dabei die Stützstellen, und kind
eine Zeichenkette, die den Typ des Splines bestimmt. Mögliche Werte sind zum Beispiel
„linear“ und „cubic“ für lineare bzw. kubische interpolierende Splines.
3.5 Ausgleichsrechnung, Methode der kleinsten Quadrate
Interpolierende Polynome, Taylorreihen und Splines haben gemeinsam, das diese exakt
durch die gegebenen Stützstellen verlaufen. Oftmals ist das aber gar nicht gewünscht,
da die Daten selbst nicht exakt sind, zum Beispiel wenn diese aus einem Experiment
oder einer Simulation stammen. In diesem Fall hat man üblicherweise eine Vorstellung,
welche funktionelle Form die Daten annehmen, und möchte nun wissen, mit welchen
Parametern diese Funktion am besten mit den Daten verträglich ist. Dazu muss man den
Parametersatz bestimmen, so dass der Abstand der Daten von der Funktion minimiert
wird.
Seien also wieder Daten (xi , yi ), i = 1(1)n und eine Funktion fv (x) gegeben. Gesucht
ist dann derjenige Parametervektor v, der die Abweichung
X
∆(v) =
(fv (xi ) − yi )2
(3.28)
i
minimiert. Dieses Verfahren wird auch Methode der kleinste Quadrate genannt, da ja
die quadrierten Abweichungen minimiert werden sollen. Ist fa,b (x) = ax + b eine Gerade,
spricht man auch von linearer Regression. In diesem Fall lässt sich das Optimum einfach
bestimmen, da
0=
X
d
∆(a,b) =
2(axi + b − yi )xi = 2N a x2i + b hxi i − hyi xi i
da
(3.29)
i
und
0=
X
d
∆(a,b) =
2(axi + b − yi ) = 2N (a hxi i + b − hyi i) ,
db
i
34
(3.30)
3.5 Ausgleichsrechnung, Methode der kleinsten Quadrate
1.0
0.5
0.0
0.5
1.0
0
1
2
3
4
5
6
Abbildung 3.4: Methode der kleinsten Quadrate zum Fitten der Sinusfunktion y =
sin(x). 200 Datenpunkte zwischen 0 und 2π wurden als sin(x) + 0,1 sin(10x) + ξ erzeugt,
wobei ξ eine Gauß-verteilte Pseudozufallsvariable mit Varianz 0,01 war. Die resultierende
Sinusfunktion (rot gestrichelt) hat die Form a sin(bx + c), wobei die Koeffizienten auf gut
2% Genauigkeit a = b = 1 und c = 0 entsprechen. Die kleine höherfrequente Schwingung
kann durch einen Fit allerdings nicht zuverlässig erkannt werden.
wobei h·i den Mittelwert über alle Datenpunkte bedeutet. Daraus ergibt sich
a=
hyi xi i − hyi i hxi i
x2i − hxi i2
und b = hyi i − a hxi i ,
(3.31)
was sich einfach auf dem Computer berechnen lässt.
Auch für quadratische und andere einfache Funktionen lassen sich die Koeffizienten
geschlossen darstellen, aber bei allgemeinen Funktionen ist dies nicht immer der Fall.
Dann muss die nichtlineare Optimierungsaufgabe (3.28) numerisch gelöst werden, was wir
später behandeln werden. Für den Moment genügt uns, dass SciPy die Funktion scipy
.optimize.leastsq(delta, v0, (x, y)) dafür bereitstellt. (x, y) sind dabei
die Ausgangsdaten, die hier zu einem Tupel zusammengefasst sind. v0 ist der Startwert
für die Berechnung, der nicht zu weit vom (unbekannten) Optimum entfernt liegen darf.
delta ist eine Python-Funktion, die als Argumente v, xi und yi nimmt und fv (xi ) − yi
zurückliefert. Da fv (x) eine beliebig komplizierte Form annehmen kann, ist diese Aufgaben im Allgemeinen nicht lösbar, allerdings funktioniert ein solcher Fit für einfache
Funktionen meistens recht gut. Abbildung 3.4 zeigt einen solchen Funktionsfit an eine
verrauschte Sinusfunktion, die mit 200 Datenpunkten auf etwa 2% genau gefittet werden kann. Man beachte, das der Ausgangswert für den Fit mit Hilfe der SciPy-Funktion
leastsq a = 0, b = 1, c = 0 war; beim Startwert a = 0, b = 0, c = 0 bricht das Verfahren
35
3 Darstellung von Funktionen
ab. Das zeigt, dass man tatsächlich nicht zu weit vom Optimum starten kann, was ein
gewisses Verständnis der Zielfunktion voraussetzt.
Ist die Funktionsform, die den Daten zugrundeliegt, unbekannt, ist es normalerweise
keine gute Idee, die Form zu raten. Generell sollte auch die Anzahl der Parameter sehr
klein sein, da sich sonst fast alles „gut“ fitten lässt („With four parameters I can fit an
elephant and with five I can make him wiggle his trunk.“ — J. von Neumann).
Soll aber zum Beispiel für Visualisierungszwecke eine ansprechende Kurve entlang der
Daten gelegt werden, deren tatsächliche Abhängigkeit unbekannt ist, dann sind PadéFunktionen oft eine gute Wahl. Diese haben die Gestalt P (x)/Q(x), wobei P und Q
zwei Polynome mit paarweise verschiedenen Nullstellen sind. Üblicherweise lassen sich
schon für niedrige Polynomgrade ansprechende Fits finden, sofern die Grade der beiden
Polynome in etwa gleich gewählt werden.
3.6 Fourierreihen
Bis jetzt waren unsere Näherungsfunktionen auf Polynomen basierend, da diese einerseits vom Computer verarbeitet werden können und andererseits aufgrund der Taylorentwicklung glatte Funktionen meist gut approximieren. Für periodische Funktionen sind
Polynome aber an sich erst einmal wenig geeignet, da sie selbst nicht periodisch sind.
Splines können zwar auch periodisch gemacht werden, aber trotzdem sind trigonometrische Funktionen besser geeignet, um periodische Funktionen darzustellen. Fourierreihen
und -transformationen stellen Funktionen als trigonometrische Reihen dar, die meist gut
konvergieren und darüber hinaus einige nützliche Eigenschaften haben.
Es gibt zwei Hauptanwendungen der Fourierdarstellung: die Analyse und Aufbereitung
periodischer Signale und die Lösung von Differentialgleichungen. Bei periodischen Signalen dient die Fourierdarstellung zur Analyse des Spektrums des Signals. Diese gibt nützliche Informationen über die charakteristischen Zeitskalen von Strukturen im Signal, zum
Beispiel die Tonhöhe und die Obertonreihe eines Instruments. In dieser Frequenzdarstellung lassen sich auch gezielt einzelne Frequenzen dämpfen, was Rauschen unterdrücken
kann und im ursprünglichen Funktionsraum teure Faltungen erfordert. Bei Differentialgleichungen nutzt man aus, dass die Ableitung im Frequenzraum eine algebraische
Operation ist, und die Differentialgleichung somit in eine gewöhnliche algebraische (und
oft sogar lineare) übergeht.
3.6.1 Komplexe Fourierreihen
Wir betrachten eine periodische Funktion f (t) mit f (t + T ) = f (t) für alle t ∈ R, d.h. f
hat Periode T . Dann ist die Fourierdarstellung von f gegeben durch
X
fˆn einωt
(3.32)
f (t) =
n∈Z
mit ω = 2π/T . Die Koeffizienten fˆn lassen sich berechnen als
Z
1 T
ˆ
fn =
f (t)e−inωt dt
T 0
36
3.6 Fourierreihen
und sind im Allgemeinen komplex, auch wenn f reellwertig ist. Die Beiträge fˆ±n haben
dieselbe Frequenz ±n/T , unterscheiden sich aber in ihrer Phase. Die Leistung zu dieser
Frequenz ist fˆn fˆ−n .
(3.32) lässt sich auch so lesen, dass
e−inωt = cos(nωt) + i sin(nωt)
eine orthonormale Basis bezüglich des Skalarprodukts
Z
1 T
(f, g) =
f (t)g(t) dt
T 0
(3.33)
(3.34)
bilden. Ähnlich wie ein Vektor im Rn wird die Funktion f also durch die Fouriertransformation in ihre Schwingungskomponenten zerlegt. Insbesondere sind die Fourierkoeffizienten linear in der Funktion, d.h.
f\
+ λg n = fˆn + λĝn .
(3.35)
Die Voraussetzungen für die Konvergenz der Fourierreihe sind sehr schwach - solange
die Funktion wenigstens quadratintegrabel ist, konvergiert die Fourierreihe fast überall,
d.h.
N
X
N →∞
f (t) −
fˆn einωt −−−−→ 0.
(3.36)
n=−N
Daneben ist die Transformation f → fˆ eine Isometrie, genauer gilt das Parsevaltheorem
Z
X
1 t
2
ˆ
|fn | =
|f (t)|2 dt.
(3.37)
ω 0
n∈Z
Das Parsevaltheorem besagt auch, dass die Restbeiträge von großen n immer kleiner werden, so dass also eine abgeschnittene Fourierreihe eine Approximation an die gesuchte
Funktion darstellt. Anders als abgeschnittene Taylorreihen, die nur in einer schmalen
Umgebung um den Aufpunkt exakt sind, konvergiert die Fourierreihe gleichmäßig. Allerdings muss die abgeschnittene Fourierreihe im allgemeinen keinen einzigen Punkt mit
der Zielfunktion gemeinsam haben, anders als Taylorreihen oder Splines.
Weiter gilt:
• Die Fourierreihe über einem Intervall [0,T ) kann aus der Fourierreihe für das Intervall [0,2π) durch Streckung mit ω berechnet werden:
Z
Z 2π
1 T
1
0
−inωt
d
f (t)n =
f (t)e
dt =
f (t0 /ω)e−int dt0 ,
(3.38)
T 0
2π 0
• Es gilt
\
f (t
+ t0 )n = einωt0 fd
(t)n
(3.39)
die Phase kann also nach Belieben verschoben werden. Die Leistung fˆn fˆ−n bleibt
dabei natürlich erhalten.
37
3 Darstellung von Funktionen
• Für die komplexe Konjugation gilt stets fbn = fˆn , da die Fouriertransformation ja
linear ist.
• Ist Funktion f symmetrisch, also f (t) = f (−t) = f (T − t), so ist fˆ−n = fˆn , also fˆ
symmetrisch.
• Ist Funktion f ungerade, also f (t) = −f (−t) = −f (T − t), so ist fˆ−n = −fˆn , also
fˆ ungerade.
• Ist Funktion f reellwertig, also f (t) = f (t), so ist fˆ−n = fˆn . Allerdings sind die
Fourierkoeffizienten im Allgemeinen komplex!
• Ist die komplexwertige Funktion f (t) = g(t) + ih(t) mit g, h reellwertig, gilt also
cn
fˆn + fˆ n = 2g
c n.
und fˆn − fˆ n = 2ih
(3.40)
Dies bedeutet, dass sich die Fourierreihen zweier reellwertiger Funktionen zusammen berechnen und anschließend wieder trennen lassen. Da die Berechnung der
Fourierkoeffizienten sowieso komplex erfolgen muss, erspart dies bei numerischer
Auswertung eine Transformation.
• Die Ableitung der Fourierreihe ist sehr einfach:
\
X
X
d
df
inωt
ˆ
f (t) =
einωt
fn inωe
=
dt
dt n
n∈Z
=⇒
n∈Z
\
df
= inω fˆn .
dt n
(3.41)
3.6.2 Reelle Fourierreihen
Da die Fourieranalyse besonders zur Analyse und Bearbeitung von Messdaten genutzt
wird, sind die Fourierreihen reellwertiger Funktionen besonders wichtig. Ist die Funktion
f rellwertig, so ist
fˆn einωt + fˆ−n e−inωt = fˆn einωt + fˆ−n einωt = 2Re(fˆn einωt )
= 2Re(fˆn ) cos(nωt) − 2Im(fˆn ) sin(nωt). (3.42)
Daraus folgt, dass sich die Fourierreihe auch komplett reellwertig schreiben lässt:
∞
f (t) =
a0 X
+
an cos(nωt) + bn sin(nωt)
2
(3.43)
n=1
mit
an = 2Re(fˆn ) =
38
2
T
Z
T
f (t) cos(nωt) dt
0
(3.44)
3.6 Fourierreihen
1.5
1.0
0.5
0.0
0.5
1.0
1.50
1
2
3
4
5
6
3.5
3.0
2.5
2.0
1.5
1.0
0.5
0.0
0.50
1
2
3
4
5
6
Abbildung 3.5: Abgeschnittene Fourierreihen der Rechteckfunktion (links) und eines
Dreieckpulses (rechts). Die Funktionen sind jeweils als schwarze durchgezogene Linien
eingezeichnet, die Näherungen mit einem Term blau gestrichelt, mit zwei Termen rot
gepunktet, und mit 20 Termen grün durchgezogen. Für den Dreieckpuls ist letztere Näherung nicht mehr von der Funktion zu unterscheiden, während der Rechteckpuls noch
deutliche Artefakte an den Unstetigkeiten zeigt.
und
2
bn = −2Im(fˆn ) =
T
Z
T
f (t) sin(nωt) dt.
(3.45)
0
Für symmetrische Funktionen ist offenbar bn = 0, für ungerade Funktionen an = 0.
Einige reelle Fourierreihen sind zum Beispiel:
• Konstante f (t) = f0 :
a0 = 2f0 , an , bn = 0 sonst
• Rechteckfunktion
(
1
für 0 ≤ t < T2
f (t) =
=
−1 für T2 ≤ t < T
∞
4X 1
sin ((2n − 1)ωt)
π
2n − 1
(3.46)
(3.47)
n=1
• kurzer Rechteckpuls. Wir betrachten nun die auf konstanten Flächeninhalt normierte Funktion
(
1/S für 0 ≤ t < S
fS (t) =
,
(3.48)
0
für S ≤ t < T
39
3 Darstellung von Funktionen
deren Fourierreihe
fs (t) =
1
+
T
∞
2 X sin(nωS)
1 − cos(nωS)
cos(nωt) +
sin(nωt)
T
nωS
nωS
(3.49)
n=1
ist. Je kleiner S wird und damit der Träger von fS , desto langsamer konvergiert
ihre Fourierreihe, da die Funktion sin(x)/x immer dichter an der Null ausgewertet
wird. Für jede feste Frequenz n gilt schließlich
S→0 1
d
(f
−−→ = δ̂n
S )n −
T
für alle n ∈ Z
(3.50)
bzw. an → 2/T und bn → 0. Die δ-Funktion, die ja der formale Grenzwert der
fS ist, und den kleinstmöglichen Träger hat, hat also in gewisser Weise die am
schlechtesten (tatsächlich gar nicht!) konvergierende Fourierreihe.
• Dreiecksfunktion
(
t
für 0 ≤ t < T2
f (t) =
T − t für T2 ≤ t < T
=
∞
π
4X
1
cos ((2n − 1)ωt)
−
2 π
(2n − 1)2
n=1
(3.51)
Genau wie die komplexe Fourierreihe lässt sich natürlich auch die reelle Fourierreihe
abschneiden, um Näherungen für Funktionen zu bekommen, vergleiche Abbildung 3.5.
Es fällt auf, das die Fourierreihe besonders schlecht dort konvergieren, wo die Funktion
nicht differenzierbar ist bzw. einen Sprung aufweist.
3.6.3 Diskrete Fouriertransformation
Bei praktischen Anwendungen sind die Integrale zur Bestimmung der Koeffizienten oft
nicht analytisch lösbar, oder die Funktion ist von vornherein nur an diskreten Punkten
gegeben, etwa weil es sich um Messdaten handelt. In diesem Fall müssen die Integrale
numerisch approximiert werden. Wir betrachten nun also nicht mehr eine kontinuierliche
Funktion f , sondern Daten fk = f (tk ) mit tk = k∆, k = 0(1)N − 1 und Schrittweite
T
∆= N
. Dann ist
1
fˆn =
T
Z
T
f (t)e−inωt dt ≈
0
N −1
N −1
2π
1 X
∆X
gn
f (k∆)e−inωk∆ =
fk e−i N nk =: .
T
N
N
k=0
Die Koeffizienten
DFT(fk )n = gn =
(3.52)
k=0
N
−1
X
2π
fk e−i N nk
(3.53)
k=0
werden als die diskrete Fouriertransformierte bezeichnet, die sehr effizient berechnet werden kann, wie wir im Folgenden sehen werden. Analog wird die inverse diskrete Fouriertransformation
N
−1
X
gn i 2π nk
iDFT(gn )k = f (tk ) =
e N
(3.54)
N
n=0
40
3.6 Fourierreihen
1.0
10-1
0.5
10-2
0.0
10-3
0.5
1.0
0
10-4
1
2
3
4
5
-5
6 10 0
20
40
60
80
100
Abbildung 3.6: Diskrete Fouriertransformation von 200 diskreten Datenpunkten, die analog zu Abbildung 3.4 zwischen 0 und 2π als sin(x) + 0,1 sin(10x) + ξ erzeugt wurden.
Anders als der Funktionsfit erlaubt die DFT, auch die kleine zusätzliche Schwingung
gut vom Rauschen zu unterscheiden. Im Graphen ist das Leistungsspektrum |DF T (k)|2
gezeigt. Man erkennt die Amplitudenquadrate 0,25 bei 1 und 0,01 bei 10, auch wenn
letztere Frequenz durch das Rauschen etwas an Intensität verloren hat.
definiert, die aus den Koeffizienten wieder die Funktion f an den diskreten Eingangspunkten tk berechnet. Abbildung 3.6 zeigt die DFT der Summe zweier verrauschter Sinusfunktionen, aus der die beiden Basisfrequenzen und deren Amplituden klar gegenüber
dem Rauschen zu erkennen sind.
Die Koeffizienten sind offenbar periodisch, da
gn+N =
N
−1
X
k=0
fk e
−i 2π
(n+N )k
N
=
N
−1
X
k=0
2π
fk e−i N nk e|−2πik
{z } = gn .
(3.55)
=1
Insbesondere ist g−k = gN −k , und es gibt nur N echt verschiedene Koeffizienten bzw.
Frequenzen n/T . DFT-Bibliotheken speichern die Koeffizienten daher meist als Vektor
(g0 , . . . ,gN −1 ) bzw. (g0 , . . . ,gN/2−1 ,g−N/2 , . . . ,g−1 ). Ist f reell, so gilt noch dazu g−k = gk ,
sodass lediglich dN/2e Koeffizienten wirklich verschieden sind. Allerdings sind diese im
Allgemeinen komplex, so dass die N reellen Freiheitsgrade der Eingangsfunktion erhalten
bleiben.
Die endliche Anzahl der diskreten Fourierkoeffizienten bedeutet, dass bei einem reellen
1
Signal mit Schrittweite ∆ die maximal darstellbare Frequenz fNyquist = 2∆
beträgt, die
sogenannte Nyquist-Frequenz . Signale mit höherer Frequenz f werden zu scheinbaren
Signalen niedrigerer Frequenz
(
f mod 2fNyquist
falls f mod 2fNyquist < fNyquist
fscheinbar =
(3.56)
2fNyquist − f mod 2fNyquist falls f mod 2fNyquist ≥ fNyquist ,
41
3 Darstellung von Funktionen
0.5
1.0
0.4
0.5
0.3
0.0
0.2
0.5
1.0
0
0.1
1
2
4
3
5
0.00
6
1
2
4
3
5
6
7
Abbildung 3.7: Diskrete Fouriertransformation von 14 äquidistanten diskreten Datenpunkten (rote Punkte links) der Funktion sin(13t) (rote Kurve links) im Interval [0 : 2π].
Die Frequenz der Funktion 13/2π ist höher als die Nyquist-Frequenz fNyquist = 7/2π,
daher kommt es zu Aliasing-Artefakten. Die rekonstruierte Kurve ist links schwarz gepunktet eingezeichnet, ihr Spektrum rechts. Die abgetastete Funktion ist also scheinbar
sin(t), was einer Frequenz von 2fNyquist − 13/2π entspricht.
was auch als Aliasing bezeichnet wird. Sollen analoge Signale digital weiter verarbeitet
werden, kann es daher notwendig sein, höhere Frequenzen durch analoge Tiefpassfilter
zu unterdrücken. Abbildung 3.7 illustriert dieses Problem.
3.6.4 Schnelle Fouriertransformation
Die Berechnung der Fouriertransformierten nach (3.53) ist zwar möglich, aber ziemlich
langsam — jeder der N Koeffizienten benötigt offenbar O(N ) Operationen, so dass die
DFT insgesamt O(N 2 ) Operationen braucht. Das limitiert für praktische Anwendungen
N auf einige tausend, was für viele Anwendungen zu wenig ist. Die DFT konnte daher
nur durch die schnelle Fouriertransformation (FFT) von Cooley und Tukey zu breiter
Anwendung finden. Diese basiert auf der Beobachtung, dass für N = 2M
DFT(fk )n =
M
−1
X
2π
f2k e−i 2M n 2k +
k=0
M
−1
X
2π
f2k+1 e−i 2M n (2k+1)
(3.57)
k=0
2π
−i 2M
n
= DFT(f2k )n + e
DFT(f2k+1 )n ,
(3.58)
wobei DFT(f2k )n den n-ten Koeffizienten einer DFT auf den Datenpunkten f2k , k =
0(1)M − 1, bezeichnet. Gemäß (3.55) ist dabei DFT(f2k )n = DFT(f2k )n−M für n > M .
42
3.6 Fourierreihen
Die Fouriertransformierte der N Datenpunkte ergibt sich also als einfache Summe von
zwei Fouriertransformierten mit lediglich der halben Menge M an Datenpunkten, wobei
die ungerade Hälfte mit der Einheitswurzel
2π
wn := e−i 2M n
(3.59)
multipliziert wird. Ist nun M wieder durch zwei teilbar, so lassen sich diese Fouriertransformierten ebenfalls als Summe zweier nochmals halb so langer Fouriertransformationen
darstellen. Wenn nun N eine Zweierpotenz ist, kann man so fortfahren, bis M = 1 erreicht
ist, also DFT(f0 )0 = f0 . Dabei gibt es offenbar log2 (N ) viele Unterteilungsschritte, die
jeder O(N ) Operationen kosten. Insgesamt benötigt die FFT also lediglich O(N log N )
Operationen.
Schematisch funktioniert ein FFT-Schritt wie folgt:
f (0)
f (∆)
Halbe
FFT
f (2∆)
f (3∆)
Halbe
FFT
·1 g
0
·w0
·1 g
1
·w1
·1 g
2
·w2
·1 g
3
·w3
Aufgrund ihres Aussehens wird dieses Datenpfadschema auch als Butterfly-Schema genannt. Damit die beiden Unter-FFTs auf einem zusammenhängenden Satz von Daten
operieren können, müssen also auch die Eingabedaten fk umsortiert werden, ebenso wie
auch für die Unter-FFTs. Man kann sich leicht überlegen, dass dabei fk auf fk0 sortiert
wird, wobei die Bits k 0 in Binärdarstellung dieselben wie von k sind, nur in umgedrehter
Reihenfolge.
Die FFT erlaubt also die effiziente Zerlegung einer Funktion in ihre Schwingungskomponenten, was viele wichtige Anwendungen nicht nur in der Physik hat. Daher gibt
es eine Reihe sehr guter Implementierungen der FFT, allen voran die „Fastest Fourier
Transform in the West“ (FFTW, http://www.fftw.org). Selbstverständlich bietet
auch NumPy eine FFT, numpy.fft.fft(f_k), mit der inversen FFT numpy.fft
.ifft(g_n). Die Routinen sind so implementiert, dass bis auf Maschinengenauigkeit
iFFT(FFT(fk )) = fk .
Wichtige Anwendungsbeispiele der diskreten Fouriertransformation sind zum Beispiel
die Datenformate JPEG, MPEG und MP3, die alle drei auf einer Abwandlung der DFT
beruhen, der diskreten Cosinustransformation (DCT) für reelle Daten. Bei dieser wird
der Datensatz so in der Zeitdomäne verdoppelt, dass er in jedem Fall eine gerade Funktion repräsentiert, wodurch die Fourierreihe in eine reine Cosinusreihe übergeht mit nur
reellen Koeffizienten. Die DCT ist also eine Umwandlung reeller in reelle Zahlen. Wegen
Ihrer Wichtigkeit gibt es nicht nur extrem effiziente Implementierungen für die meisten
Prozessortypen, sondern auch spezielle Hardware.
43
3 Darstellung von Funktionen
1.0
0.5
0.0
0.5
1.0
0
1.0
0.5
0.0
0.5
1.0
0
1
2
3
4
5
6
1
2
3
4
5
6
1.0
0.5
0.0
0.5
1.0
0
1.0
0.5
0.0
0.5
1.0
0
1
2
3
4
5
6
1
2
3
4
5
6
Abbildung 3.8: Diskrete Wavelettransformation von 200 diskreten Datenpunkten, die
analog zu Abbildung 3.6 zwischen 0 und 2π als sin(x) + 0,1 sin(10x) + ξ erzeugt wurden.
Für die Transformation wurden die Wavelets von (0,1] auf den Bereich (0,2π] gestreckt.
Der linke obere Graph zeigt nochmals das Ausgangssignal, von rechts oben nach rechts
P
P j −1
(f,ψjk )ψjk , dann
unten folgen die Anteile der Stufen 0–3, also (f,φ0 )φ0 + 3j=0 2k=0
P5 P2j −1
Stufen 4 und 5 ( j=4 k=0 (f,ψjk )ψjk ) und schließlich Stufen 6–8, womit die Auflösung
der Ausgangsdaten erreicht ist.
3.7 Wavelets
Die Fouriertransformation wird vor allem deshalb für die Kompression von Audio- oder
Bilddaten genutzt, weil sie hochfrequente von niederfrequenten Signalen trennt und die
menschlichen Sinne die hochfrequenten Anteil meist nicht gut wahrnehmen können. Das
ist allerdings nicht ganz korrekt, tatsächlich können wir nur stark lokale Änderungen nicht
gut wahrnehmen. Dafür sind Fourierreihen an sich gar nicht so gut geeignet, da ja auch
die hochfrequenten Schwingungen alles andere als lokal sind. Als Alternative hat sich
die Multiskalenanalyse (MSA) oder diskrete Wavelettransformation etabliert, die auch
im transformierten Raum lokal ist.
Anders als bei der Fouriertransformation, die eine Zerlegung in trigonometrische Funktionen darstellt, gibt es für die MSA verschiedene Sätze von Basisfunktionen mit verschiedenen Eigenschaften wie Differenzierbarkeit und Lokalität. Im Folgenden soll die MSA
mit Hilfe des Haar-Wavelets dargestellt werden, dass das einfachste und älteste bekannte
Wavelet ist. Zunächst betrachten wir die Skalierungsfunktion
φ(x) = χ(0,1]
44
(
1 für 0 < x ≤ 1
=
0 sonst
(3.60)
3.7 Wavelets
sowie das Haar-Wavelet

1

−1 für 0 < x ≤ 2
ψ(x) = 1
für 12 < x ≤ 1


0
sonst,
(3.61)
aus denen wir die Basisfunktionen φk (x) := φ(x − k) der nullten Stufe und ψjk (x) :=
2j/2 ψ(2j x − k) der j-ten Stufe konstruieren. Durch die Skalierung mit 2j werden die
ψj,k also immer schmaler, sind aber wegen des Vorfaktors alle normiert, d.h. kψjk k = 1.
Ebenso sind auch die φk normiert. Zusätzlich sind sämtliche Basisfunktionen zu einander
orthogonal, wie man sich leicht überlegt. Daher lässt sich jede quadratintegrable Funktion
f wie folgt zerlegen:
X
XX
f (x) =
(f,φk )φk +
(f,ψjk )ψjk
(3.62)
k∈Z
j∈N0 k∈Z
Dies ist die Multiskalenanalyse von f . Die Koeffizienten der Stufe j werden auch Details der Stufe j genannt. In der Praxis ist das Signal durch endlich viele äquidistante
Datenpunkte gegeben, analog zur diskreten Fouriertransformation. In diesem Fall sind
die Summen endlich, da einerseits der Träger endlich ist und damit nur endlich viele
(f,φk ) 6= 0, und es andererseits keine Details unterhalb der Auflösung des Signals gibt.
Man skaliert dann die Wavelets und Skalierungsfunktion so, dass der Abstand der Datenpunkte gerade der halben Breite des Wavelets auf der feinsten Auflösung entspricht, und
φ = φ0 bereits das gesamte Interval überdeckt. Für eine nur auf [0,1] nichtverschwindende Funktion, deren Werte an 2N Punkten äquidistanten Punkten bekannt ist, reduziert
sich die Multiskalenanalyse zur diskreten Wavelettransformation
f (x) = (f,φ)φ +
j −1
N
−1 2X
X
(f,ψjk )ψjk .
(3.63)
j=0 k=0
Die Anzahl der Koeffizienten ist dann 1 + 1 + 2 + · · · + 2N −1 = 2N , also genau die Anzahl
der Eingabedaten. Genau wie die diskrete Fouriertransformation bildet die Wavelettransformation 2N Werte f (k/2N ) auf 2N Werte (f,φ) und (f,ψjk ) ab und besitzt eine exakte
Rücktransformation, (3.63).
Analog zur schnellen Fouriertransformation gibt es auch eine schnelle Wavelettransformation (FWT), die sogar linearen Aufwand hat, also O(N ) Schritte bei N Datenpunkten benötigt. Eine einfache Implementation der FWT und der inversen FWT für
das Haar-Wavelet zeigt Codebeispiel 3.1. Der Kern dieser Transformation liegt darin,
die Transformierte von der höchsten Detailauflösung herab aufzubauen, und dadurch die
die Integrale approximierenden Summen schrittweise aufzubauen (Downsampling). Für
genauere Informationen siehe zum Beispiel Daubechies [Dau92].
Abbildung 3.8 zeigt einige Detailstufen der Wavelet-Zerlegung der verrauschten Sinusfunktionen analog Abbildung 3.6. Auch hier lässt sich das Rauschen auf den höheren Detailstufen gut vom Nutzsignal trennen, allerdings kann die Oberschwingung nicht
detektiert werden. Das hängt allerdings vor allem daran, dass das Haar-Wavelet nicht
45
3 Darstellung von Funktionen
sehr geeignet ist, da es nicht glatt ist, im Gegensatz zum Nutzsignal. Daher sind in
den meisten Fällen glatte Wavelets besser geeignet. Das bekannteste Beispiel von glatten Wavelets sind die Daubechies-Wavelets, die daneben auch einen kompakten Träger
haben, also stark lokalisiert sind. Mit solchen Wavelets lassen sich sogar reale Musikdaten in Akkorde zurücktransformieren. Auch der JPEG-Nachfolger JPEG2000 basiert auf
einer Wavelettransformation statt einer Cosinustransformation, allerdings mit CohenDaubechies-Feauveau-Wavelets.
46
3.7 Wavelets
# Haar-Wavelet-Transformation
#############################
from scipy import *
def haar_trafo(data):
"Diskrete Wavelettransformation mit Hilfe des Haar−Wavelets."
# Daten mit kleinstem Integrationsschritt multiplizieren
c = data.copy() / len(data)
# Temporaerer Puffer, um benoetigte Werte nicht zu ueberschreiben
ctmp = zeros(c.shape)
width = len(c)/2
while width >= 1:
for n in range(width):
tmp1 = c[2*n]
tmp2 = c[2*n+1]
# Detail
ctmp[width + n] = tmp1 - tmp2
# Downsampling
ctmp[n]
= tmp1 + tmp2
# Puffer zurueckschreiben
c[:2*width] = ctmp[:2*width]
width = width / 2
return c
def inverse_haar_trafo(c):
"Inverse Diskrete Wavelettransformation mit Hilfe des Haar−Wavelets"
# Rueckgabewerte
data = zeros(len(c))
# phi mitnehmen auf der niedrigsten Stufe
data[0] = c[0]
width = 1
cstart = 1
while width <= len(c)/2:
for n in range(width-1, -1, -1):
tmp = data[n]
data[2*n]
= tmp + width*c[cstart + n]
data[2*n + 1] = tmp - width*c[cstart + n]
cstart += width
width = width * 2
return data
# Anwendungsbeispiel
x = linspace(0,1,256)
y = cos(x)
coeff = haar_trafo(y)
yrueck = inverse_haar_trafo(coeff)
print max(abs(yrueck - y))
Listing 3.1: Diskrete Wavelettransformation und ihre Inverse als Python-Code. Die Länge der Eingabedaten muss eine Zweierpotenz 2N sein. Die Details sind in einem Vektor c gespeichert, in der Form c = ((f,φ0 ), (f, ψ00 ), (f, ψ10 ), (f, ψ11 ), (f, ψ20 ), (f, ψ21 ),
(f, ψ22 ), . . . , (f, ψN −1,2N −1 −1 )).
47
4 Datenanalyse und Signalverarbeitung
In diesem Kapitel geht es darum, was man mit einem gemessenen Signal machen kann
und muss. Ein gemessenes Signal kann dabei entweder tatsächlich von einem Messgerät
kommen oder aber das Ergebnis einer Computersimulation sein. Zwei Fragen sind dabei
vor allem wichtig: Welche Eigenschaften hat das Signal, und wie vertrauenswürdig sind
die Werte?
Um die Eigenschaften von Signalen zu untersuchen, ist die kontinuierliche Fourieranalyse ein gutes Werkzeug, die das Signal vom Zeit- in den Frequenzraum überträgt. So
lassen sich zum Bespiel charakteristische Frequenzen und damit Zeitskalen bestimmen.
Außerdem bietet der Übergang in den Frequenzraum analytisch viele Vorteile, die sich
auch auf dem Computer nutzen lassen. So werden zum Beispiel langreichweitige Wechselwirkungen in Molekulardynamiksimulationen meist im Frequenzraum berechnet.
Als weiteres Werkzeug werden wir Faltungen kennen lernen, die erlauben, Signale nach
bestimmten Frequenzen zu filtern oder aber aus der (gemessenen) Antwort eines linearen
Systems auf ein einfaches Eingangssignal die Antwort auf beliebige Signale zu berechnen.
Sollen Signale mit dem Computer weiterverarbeitet werden, müssen diese digitalisiert
werden, also in eine Reihe von Zahlen übersetzt. Üblicherweise passiert dies dadurch,
dass das Signal nur zu äquidistanten Zeitpunkten ausgewertet, abgetastet wird. Das wirft
die Frage auf, welche Funktionen dadurch überhaupt gut gemessen werden können. Wie
wir sehen werden, beschränkt diese Abtastung die Frequenzen, die von einer digitalen
Auswertung erfasst werden können.
Die meisten Signale sind außerdem, durch Messungenauigkeiten und prinzipielle stochastische Prozesse, selbst stochastisch, d.h. die Verteilung der Ergebnisse vieler Messungen ist vorherbestimmbar, die einzelne Messung hingegen nicht. Trotzdem sind Messungen oft korreliert, zum Beispiel weil eine Observable sich nur kontinuierlich ändert.
Durch Korrelationsanalysen lässt sich bestimmen, wann Messungen wirklich unabhängig
sind. Dies gibt wiederum Aufschluss über die Zeitskalen wichtiger Prozesse im System,
ist aber auch wichtig für eine korrekte Abschätzung des Messfehlers, womit sich der letzte
Abschnitt beschäftigt.
4.1 Kontinuierliche Fouriertransformation
Für die Analyse zeitlich veränderlicher Signale besonders nützlich ist die Fouriertransformation, die ein kontinuierliches Signal in den Frequenzraum übersetzt. Dies gilt nicht
nur für periodische Signale, sondern zum Beispiel auch dann, wenn die Antwort eines
Systems auf ein komplexes Eingangssignal gefragt ist. Der tiefere Grund dafür ist, dass
die Fouriertransformation Differential- und Integraloperatoren in einfache algebraische
Operationen übersetzt.
49
4 Datenanalyse und Signalverarbeitung
Betrachten wir nochmals die Fourierreihe im Interval [−T /2,T /2)
!
X ∆ω Z T /2
−in∆ωt
f (t)e
dt ein∆ωt
f (t) =
2π −T /2
n∈Z
!
Z T /2
1 X
1
√
=√
f (t)e−iωt dt eiωt ∆ω (4.1)
2π n∈Z
2π −T /2
mit der Grundfrequenz ∆ω = 2π/T und ω = n∆ω. Im Grenzwert T → ∞ ergibt sich
Z ∞
1
f (t) = √
F(f )(ω)eiωt dω
(4.2)
2π −∞
mit
Z ∞
1
f (t)e−iωt dt.
(4.3)
F(f )(ω) = √
2π −∞
Die kontinuierliche Fouriertransformation F ist das Analogon der periodischen Fourierreihe, ist allerdings keine Transformation in eine Reihe mehr, sondern eine Abbildung
zwischen Funktionen. Für F gelten eine Menge sehr starker Aussagen, die wir zum großen
Teil in ähnlicher Art schon von der Fourierreihe kennen:
• F(f ) existiert, falls f quadratintegrabel ist, und bildet f auf eine quadratintegrable
Funktion ab. Für solche Funktionen mit der zugehörigen Norm kf k2 =
R∞
2
−∞ |f (t)| dt gilt dann sogar die Isometrie (Parsevaltheorem):
kF(f )k2 = kf k2
(4.4)
• F ist linear, d.h. F(f + λg) = Ff + λFg.
• F ist reziprok gegen Streckungen, d.h.
F[f (αt)](ω) =
ω 1
F(f )
.
|α|
α
(4.5)
Wird also eine Funktion α immer stärker gestaucht, so wird ihre Transformierte
immer weiter gestreckt.
Entsprechend wird aus Zeitumkehr Frequenzumkehr: F(f (−t))(ω) = F(f )(−ω).
• F ist invertierbar, die Umkehrfunktion F −1 ist durch (4.2) explizit gegeben. Offenbar ist auch die Umkehrung eine Isometrie, es gilt kF −1 (f )k2 = kf k2 .
• Weiter gilt F(F(f (t))) = F(f (−t)), und damit F 4 (f ) = f . Insbesondere ist auch
F −1 = F 3 .
• Eine zeitliche Verschiebung wird zu einer Frequenzmodulation und umgekehrt:
F(f (t − t0 ))(ω) = e−iωt0 F(f (t))(ω)
iω0 t
F(e
f (t))(ω) = F(f (t))(ω − ω0 ).
(4.6)
(4.7)
Wird also ein niederfrequentes Signal (Radioprogramm) auf ein hochfrequentes
Trägersignal aufmoduliert, verschiebt sich nur dessen Spektrum.
50
4.1 Kontinuierliche Fouriertransformation
• Aus der Linearität folgt, dass stets gilt: F(f )(ω) = F(f )(ω).
• Ist Funktion f gerade (symmetrisch), also f (t) = f (−t), so ist F(f )(−ω) =
F(f )(ω), also gerade (symmetrisch).
• Ist Funktion f ungerade (antisymmetrisch), also f (t) = −f (−t), so ist F(f )(−ω) =
−F(f )(ω), ungerade (antisymmetrisch).
• Ist Funktion f reellwertig, also f (t) = f (t), so ist F(f )(−ω) = F(f )(ω), aber im
allgemeinen komplexwertig!
• Für die Fouriertransformierte der Ableitung gilt
Z ∞
d
df
1
F
f (t) (ω) = √
(t)e−iωt dt
dt
2π −∞ dt
Z ∞
d
1
f (t) e−iωt dt = iωF(f (t))(ω).
=√
dt
2π −∞
(4.8)
Dies spielt eine wichtige Rolle beim Lösen von Differenzialgleichungen, weil diese
in gewöhnliche algebraische Gleichungen übergehen.
• Es gilt die Poissonsche Summenformel
√
X
2π X
2πn
2πn
F(f )
exp i
t0 .
f (t0 + k δ) =
|δ|
δ
δ
(4.9)
n∈Z
k∈Z
P
Diese Gleichung beruht darauf, dass t∈Z f (· + t δ) eine δ-periodische Funktion ist,
die durch eine Fourierreihe dargestellt werden kann. Wegen (4.6) reicht es dabei
o.B.d.A. δ = 1 zu betrachten:
X
k∈Z
f (t0 + k) =
XZ
1X
f (τ + k)e−2πinτ dτ e2πint0 =
n∈Z 0 k∈Z
∞
−2πinτ
XZ
f (τ )e
dτ e2πint0 =
n∈Z −∞
√
2π
X
F(f )(2πn) e2πint0 . (4.10)
n∈Z
Eine wichtige Anwendung der Poissonschen Summenformel ist die Summation
schlecht konvergenter Reihen. Fällt die Funktion f sehr langsam gegen unendlich
ab, so fällt ihre Fouriertransformierte wegen der Reziprozität (4.5) im Allgemeinen
schneller, so das aus einer langsam eine rasch konvergierende Reihe wird.
4.1.1 Spezielle Fouriertransformierte
Die Fouriertransformierte einer Gaußglocke ist
Z
1
1 −t2 /2
1 −ω2 /2 ∞ −(t−iω)2 /2
2
=
e
e
dt = √ e−ω /2
F √ e
2π
2π
2π
−∞
(4.11)
51
4 Datenanalyse und Signalverarbeitung
Die Gaussglocke ist also eine Eigenfunktion der Fouriertransformation zum Eigenwert 1.
Die Fouriertransformation hat tatsächlich sehr viel mehr echt verschiedene Eigenfunktionen, die Familie der Hermitefunktionen [Pin02]. Wegen der Isometrieeigenschaft kann
die Fouriertransformation aber nur Eigenwerte vom Betrag eins haben; tatsächlich hat
sie nur die vier Eigenwerte ±1 und ±i, da F 4 = 1. Daher ist jeder Eigenwert stark
degeneriert, und der Eigenraum zu jedem Eigenwert unendlichdimensional.
Die (formale) Fouriertransformierte der δ-Funktion ist
Z ∞
1
1
δ(t)e−iωt dt = √ ,
F(δ(t))(ω) = √
(4.12)
2π −∞
2π
√
also einfach die konstante Funktion 1/ 2π, die ebensowenig wie die δ-Funktion eine
quadratintegrable Funktion ist. Alternativ lässt sich die Beziehung aus der Fouriertransformierten der Gaußglocke mit sinkender Varianz herleiten.
4.1.2 Numerische kontinuierliche Fouriertransformation
Um die Eigenschaften der kontinuierlichen Fouriertransformation numerisch zu nutzen,
machen wir den Grenzübergang T → ∞ rückgängig und ziehen
uns auf ein für die
R
betrachtetete Funktion hinreichend großes T zurück, so dass |t|>T |f (t)|2 dt hinreichend
klein ist. Ist das Signal wie in der Praxis endlich, so könnte T zum Beispiel so groß sein,
dass das Signal vollständig abgedeckt ist. In jedem Fall ist das Signal eine Funktion f ,
die wir nur an auf einem äquidistanten Gitter tk = T − 12 + Nk , k = 0(1)N − 1 kennen.
Dann ist mit ω0 = 2π
T für n = −N/2(1)N/2
1
F(f )(ω0 n) ≈ √
2π
Z
T /2
−inω0 t
f (t)e
−T /2
=
N −1
1
k
T
1 X
dt ≈ √
f (tk )e−inω0 T (− 2 + N )
N
2π k=0
N −1
T e−2πin/2 X
T (−1)n
√
√
f (tk )e−2πink/N =
DFT(f (tk ))n (4.13)
N
N 2π
2π k=0
wobei DFT die diskrete Fouriertransformation aus (3.53) bezeichnet. Die Koeffizienten
der DFT sind periodisch, daher auch diese Näherung für F(f ). Tatsächlich sollten die
Koeffizienten aber nur als Frequenzen im Interval [−ω0 N/2,ω0 N/2] interpretiert werden, alle Frequenzen außerhalb dieses Intervals sollten als Null angesehen werden. Der
Grund dafür ist das Abtasttheorem, dass im folgenden Abschnitt besprochen wird. Dieses besagt, dass bei einem Zeitschritt ∆ = T /N nur Kreisfrequenzen bis ω0 N/2 = π/∆
eindeutig gemessen werden können. Daher ist die Beschränkung auf das innerste Interval
die natürliche Interpretation. Insbesondere ist diese Einschränkung wichtig, wenn N ungerade ist, da dann (−1)N −n 6= (−1)−n ist. Wenn nun die Ursprungsfunktion reell war,
würde für die Transformierte scheinbar f (−ω) = −f (ω) gelten, f wäre also scheinbar rein
imaginär! Bei rein reellen Signalen ist es daher günstiger, direkt die reellen Varianten der
FFT-Implementationen zu nutzen, die nur die positiven Koeffizienten bis N/2 benötigen
und damit das Problem umgehen.
52
4.2 Faltungen
Analog lässt sich auch die Rücktransformation nähern:
√ N
−1
n
2π (−1) fn
F (f )(tk ) ≈ iDFT
T
k
(4.14)
Die bekannten schnellen FFT-Routinen lassen sich also auch für die numerische Bearbeitung der kontinuierlichen Fouriertransformation nutzen. Auf diese Weise ist z.B.
Abbildung 4.1 entstanden.
4.1.3 Abtasttheorem
In der Praxis sind Signale meist als diskrete Werte an (endlich vielen) äquidistanten
Stellen beziehungsweise Zeitpunkten gegeben, zum Beispiel, weil ein Messgerät Daten in
regelmäßigen Abständen liefert. Eine wichtige Frage ist, wie gut man das reale Signal
und sein Frequenzspektrum aus den diskreten Datenpunkten rekonstruieren kann.
Hierzu betrachten wir zunächst ein bandbreitenbeschränktes Signal f , d.h. ein Signal,
dessen Fouriertransformierte einen kompakten Träger [−ωmax ,ωmax ] hat. Dann besagt
die Poissonsche Summenformel (4.9), dass für ω ∈ [−ωmax ,ωmax ]
F(f )(ω) =
1 X −iωn∆
F(e−iω· f ) (2kω0 ) = √
e
f (n∆)
2π
n∈Z
k∈Z
X
(4.15)
mit ∆ = π/ωmax . Die Fouriertransformierte eines bandbreitenbeschränkten Signals lässt
sich also exakt nur aus den Funktionswerten an den äquidistanten diskreten Stellen mit
Abtastrate ∆ berechnen. Dadurch kann natürlich auch die Funktion exakt aus ihrer
Fouriertransformierten rekonstruiert werden:
Z ωmax
∆ X
∆X
sin(ωmax (t − n∆))
f (t) =
f (n∆)
e−iω(t−n∆) dω =
f (n∆)
. (4.16)
2π
π
t − n∆
−ω0
n∈Z
n∈Z
Ist nun umgekehrt ein Signal f an äquidistanten diskreten Stellen n∆ gegeben, so
lässt sich diesem gemäß (4.16) ein kontinuierliches Signal zuordnen, dessen Fouriertransformierte nur in [−ωmax ,ωmax ] nicht verschwindet, wobei ωmax = π/∆. Das bedeutet,
1
max
dass bei Abtastrate ∆ nur Frequenzen bis zur Nyquist-Frequenz fNyquist = 2∆
= ω2π
eindeutig abgetastet werden können, ähnlich wie im periodischen Fall.
4.2 Faltungen
Die Faltung der quadratintegrablen Funktionen f und g ist definiert als
Z ∞
(f ? g)(t) :=
f (t0 )g(t − t0 ) dt0 .
(4.17)
−∞
Das negative Vorzeichen von t0 in der zweiten Funktion sorgt dafür, dass die Faltung
kommutativ ist. Weitere Eigenschaften der Faltung sind Linearität in den Komponenten
53
4 Datenanalyse und Signalverarbeitung
und sogar Assoziativität. Die Faltung verhält sich also so ähnlich wie die klassische Multiplikation und wird daher mit dem Zeichen ? bezeichnet. Vereinfacht gesagt, deponiert
die Faltung an jedem Punkt t die Funktion f , skaliert mit g(· − t). Daher ist z.B.
(δ(· − t0 ) ? g)(t) = g(t − t0 ).
(4.18)
Wird nun statt der unendlich dünnen δ-Funktion zum Beispiel eine Gaußglocke gewählt,
so wird die Funktion g verschmiert bzw. geglättet, siehe Abbildung 4.1.
Die Fouriertransformierte der Faltung zweier Funktionen ist
Z ∞Z ∞
1
f (t0 )g(t − t0 ) dt0 e−iωt dt
F(f ? g)(ω) = √
2π −∞ −∞
Z ∞Z ∞
1
0
=√
f (t0 )g(t)e−iω(t+t ) dt dt0
(4.19)
2π −∞ −∞
Z ∞
Z ∞
√
1
0
=√
g(t)e−iωt dt = 2πF(f )(ω)F(g)(ω).
f (t0 )e−iωt dt0
2π −∞
−∞
Die Faltung geht also in eine punktweise Multiplikation über. Im Fourierraum lässt sich
also sehr viel schneller falten, als im Realraum, wo ja für jeden Punkt ein Integral zu
lösen ist. Dies nutzt man auch numerisch, um Faltungen zu berechnen, in Verbindung
mit
(4.13). Seien also N Datenpunkte fk = f (tk ) und gk = mit tk = T − 21 + Nk gegeben.
Dann ist
√
(f ? g)(tk ) = 2πF −1 (F(f )(ω)F(g)(ω)) (tk )
2
N
T
n
≈ iDF T 2π (−1)
DFT(fk )n DFT(gk )n
T
2πN 2
k
T
= iDFT [(−1)n DF T (fk )n DF T (gk )n ]k . (4.20)
N
Wie im Abschnitt 4.1.2 gezeigt, ist der Faktor (−1)n durch den Aufpunkt T /2 bestimmt,
und n muss eine Frequenz im Bereich −N/2 bis N/2 sein. Dieser Faktor bleibt einmalig
von der Fouriertransformation übrig. Daher kann die eine der beiden Funktionen, etwa
g, im Prinzip beliebig verschoben sein, da sich etwaige Vorfaktoren durch die Vor- und
Rücktransformation ausgleichen. Nur die Funktion f sollte dann um die Null zentriert
gegeben sein. Die Faltung wird in diesem Fall natürlich nur im Definitionsbereich der
Funktion g berechnet. Mit anderen Worten, die Funktion g wird mit der Funktion f
gefiltert.
4.2.1 Filter
Außerdem lässt (4.19) noch eine weitere Interpretation der Faltung der Funktion g mit
der Funktion f zu: Ist f bzw. F(f ) reellwertig und symmetrisch, so werden die einzelnen
Frequenzkomponenten der Funktion g mit den Frequenzanteilen von f gestreckt bzw.
gestaucht, g also frequenzgefiltert. Man beachte, dass g für die Definition (4.19) nicht
quadratintegrabel sein muss, sofern der Filter f schnell genug abfällt. Insbesondere kann
g eine nur beschränkte, aber nicht abklingende Funktion sein, wie etwa ein Messsignal.
54
4.2 Faltungen
2.0
1.0
1.5
0.5
0.0
1.0
0.5
0.5
1.0
3
2
1 0
1
2
3 0.00
2
4
6
8
10
2
4
6
8
10
1.0
1.0
0.5
0.5
0.0
0.0
0.5
0.5
1.0
3
2
1 0
1
2
3 1.00
Abbildung 4.1: Oben links: Summe zweier Schwingungen cos(x)+0,25 sin(7,5x) (schwarze
Linie), die mit einer Gaußglocke (blau gepunktet) gefaltet wird. Das Ergebnis (rote dicke
Linie) ist die quasi ungestörte langsame Schwingung ohne die höherfrequente Schwingung,
die weggeglättet wurde. Oben rechts: Fouriertransformierte der Funktionen. Klar sichtbar
ist die hochfrequente Störung mit einer Frequenz von 7,5, die im gefilterten Signal fehlt.
In der unteren Reihe wurde eine frequenzverschobene Gaußglocke benutzt, um statt der
langsamen die schnelle Schwingung zu filtern; die Farbcodierung ist wie oben. Gemäß
(4.7) bewirkt die Frequenzverschiebung eine Modulation der Gaußfunktion.
55
4 Datenanalyse und Signalverarbeitung
Durch Wahl einer symmetrischen und reellwertigen Fouriertransformierten und Rücktransformation lassen sich also beliebige Frequenzfilter realisieren; in der Praxis wird
natürlich direkt im Fourierraum gefiltert. Später lernen wir die numerische diskrete Fouriertransformation kennen, die nicht zuletzt wegen dieser Filtereigenschaften so wichtig
ist. Abbildung 4.1 illustriert einen (gaußschen) Tiefpassfilter und einen Bandfilter, die
nur bestimmte Frequenzen passieren lassen. Daher wird beim Tiefpassfilter die aufgeprägte hochfrequente Schwingung unterdrückt, beim Hochpassfilter hingegen die an sich
dominante langsame Schwingung.
4.2.2 Antwort zeitinvarianter linearer Systeme
Eine weitere wichtige Anwendung der Faltung ist die Bestimmung der Antwort eines
zeitinvarianten linearen Systems auf ein beliebiges Eingangssignal. Einfach zu messen
ist typischerweise die Antwort Aθ (t) des Systems auf einen Einschaltvorgang, also ein
Eingangssignal der Form
(
0 für t < 0
θ(t) =
(4.21)
1 für t ≥ 0.
Um daraus die Antwort auf ein beliebiges Eingangssignal zu bestimmen, schreiben wir das
Eingangssignal f als f = f ? δ. Wegen der Linearität der Faltung und der Systemantwort
ist die Antwort auf das Signal f gegeben durch die Faltung Af (t) = f ? Aδ mit der
Antwort auf einen δ-Impuls. Diese Antwort wiederum lässt sich aus der Sprungantwort
durch einfach Ableitung erhalten, was mit Hilfe der Fouriertransformierten sehr bequem
zu berechnen ist:
Af (t) = f ? Aδ = f ?
√
d
Aθ = 2πF −1 iωF(f )F(Aθ ) .
dt
(4.22)
4.3 Kreuz- und Autokorrelation
Bis jetzt haben wir uns mit der Verarbeitung idealer Signale beschäftigt, die zu einem
gegebenen Zeitpunkt einen prinzipiell eindeutig vorherbestimmten Wert haben. Reale
Signale sind aber oft verrauscht, entweder durch Messungenauigkeiten, Bauteiltoleranzen oder prinzipielle stochastische Prozesse. Trotzdem möchte man oft wissen, ob zwei
gemessene Signale von einander abhängig, korreliert, sind. Zum Beispiel könnte man die
Position eines Elektrons und seinen Spin, die Menge der verkauften Eis- und Sonnencreme, oder auch die Position eines Pendels zu zwei verschiedenen Zeitpunkten betrachten.
In den beiden letzteren Fällen werden diese im Allgemeinen korreliert, also abhängig,
sein. Allerdings gibt dies keinen Aufschluss über den dahinterstehenden kausalen Mechanismus. Im Fall des Pendels rührt die Korrelation daher, dass es sich in kurzer Zeit nicht
beliebig weit von seiner Ausgangsposition bewegen kann. Bei der Eis- und Sonnencreme
wird es vermutlich auch eine Korrelation geben, aber weder erzeugt Eiscreme Sonnenbrand, noch macht Sonnencreme Lust auf Eis. Allerdings haben wir Menschen nunmal
bei strahlendem Sonnenschein mehr Lust auf Eis, aber brauchen auch Sonnencreme.
56
4.3 Kreuz- und Autokorrelation
Formal betrachten wir zunächst zwei Observablen A und B. Diese beiden heißen genau
dann unkorreliert, falls die Mittelwerte hA · Bi = hAi hBi bzw. h(A − hAi)(B − hBi)i = 0
erfüllen. Im Allgemeinen wird man aber vielleich nicht erwarten, dass sich die Änderung
einer Observablen unmittelbar in einer anderen niederschlägt, sondern erst nach einer
Zeit τ . Man betrachtet daher die Korrelation zwischen A und B mit einem zeitlichen
Versatz von τ , die Kreuzkorrelationsfunktion:
C(A,B)(τ ) := hA(0)B(τ )i ,
(4.23)
wobei die Signale A und B zeitinvariant sein sollen, so dass der Zeitpunkt t = 0 beliebig
gewählt sein kann. Für große τ dekorrelieren die Signale, daher gilt C(A,B) → hAi hBi für
τ → ∞. Wird stattdessen die normierte Kreuzkorrelation C(A−hAi , B−hBi) betrachtet,
verschwindet dieses also im Limit τ → ∞.
h·i bezeichnet in der Physik üblicherweise den Ensemblemittelwert, also den Mittelwert
über alle möglichen Realisationen des Experiments. Sind nun A = A(t) und B = B(t)
zeitliche Messreihen eines zeitinvarianten Systems, so ermittelt man die Mittelwerte üblicherweise als Zeitmittelwerte, also Integrale über die Zeit:
!
1
T →∞ T
Z
T /2
C(A,B)(τ ) = hA(0) · B(τ )i = lim
A(t)B(t + τ ) dt.
(4.24)
−T /2
Das Ausrufezeichen soll andeuteten, dass dies eine Annahme ist, denn die Gleichheit gilt
nur genau dann, wenn das System ergodisch ist, d.h., dass der Prozess bei einer unendlich langen zeitlichen Messung alle möglichen Realisationen einmal besuchen wird. Diese
Annahme wird meist gemacht, obwohl die Ergodizität für die meisten Systeme nicht bewiesen werden kann. Hinzu kommt, dass ja in der Praxis niemals über beliebig lange
Zeiträume gemittelt werden kann. Daher können auch endliche, aber hohe Energiebarrieren zu einem systematischen Fehler führen.
hAi bzw. hBi sind oft gar nicht genau bekannt, und müssen numerisch durch
(Zeit–)Mittelung der Daten bestimmt werden. Da hier aber normalerweise dieselben Daten zugrunde gelegt werden, die auch zu Berechnung der Kreuzkorrelation selber genutzt werden, sind diese notwendigerweise korreliert, was zu kleinen Abweichungen in
der Kreuzkorrelationsfunktion führt. Im häufigen Fall, dass eine Observable aus Symmetriegründen einen Mittelwert von Null haben muss, sollte daher auf keinen Fall der
numerische gemessene Mittelwert abgezogen werden, „um das Ergebnis zu verbessern“.
Diese übliche Praxis ist falsch, da sie ja erzwingt, dass der letzte Datenpunkt der gemessenen Kreuzkorrelationsfunktion notwendigerweise auf hAi hBi abfällt, selbst wenn
einfach nur das Messinterval zu kurz gewählt wurde. Daher führt diese Methode zu einer
Unterschätzung der Langzeitkorrelationen!
Analog zu (4.24) kann man die Kreuzkorrelation auch für endliche Signale definieren.
Für zwei quadratintegrable Signale f und g ist in Analogie die Kreuzkorrelationsfunktion
definiert als
Z
∞
C(f,g)(τ ) =
f (t)g(t + τ ) dt,
(4.25)
−∞
57
4 Datenanalyse und Signalverarbeitung
wobei wegen der Quadratintegrabilität auf die Normierung verzichtet werden kann. Diese
Kreuzkorrelation misst keine Korrelationen im stochastischen Sinne mehr, weil das Integral nun keine Zeitmittelung mehr darstellt. Stattdessen ist C(f,g)(τ ) in diesem Fall ein
Maß dafür, wie sehr sich die Signale f und g mit einem Zeitversatz τ im Verlauf ähneln.
Diese Form der Kreuzkorrelation ähnelt einer Faltung sehr. Tatsächlich ist
C(f,g)(τ ) = f ? g(−·) (−τ ) = f (−·) ? g (τ )
(4.26)
und kann damit effizient im Frequenzraum bestimmt werden:
√
C(f,g) = 2πF −1 F(f )(−ω)F(g)(ω) .
(4.27)
Kommen wir nun zu unserem Ausgangsproblem mit zwei stochastischen, zeitinvarianten Variablen A und B und dem Zeitmittel zurück. Wie üblich nehmen wir an, dass A
und B an endlich vielen, diskreten Zeitpunkten k∆, k = 0(1)n − 1, gemessen wurden.
Die Messung erstreckt sich also über den Zeitraum [0,T ] mit T = n∆. Dann ist eine
Näherung für die Kreuzkorrelation von A und B gegeben durch
N
−k
X
1
C(A,B)(k∆) = hA(0) · B(k∆)i ≈
A(l∆)B ((l + k)∆)
N −k
für k = 0(1)K − 1.
l=0
(4.28)
Die unterschiedliche Gewichtung 1/(N − k) ergibt sich durch die unterschiedliche Anzahl
an Messungen für den Versatz k. Für große Versätze ist die Anzahl der Messungen sehr
klein (für k = N − 1 nur noch eine), daher muss k N sein. Form (4.28) ist numerisch
allerdings nicht sehr effizient auszuwerten, da im allgemeinen 2N K viele Operationen
benötigt werden, und K meist einige hundert Datenpunkte beträgt. Daher liegt es nahe,
auch hier die FFT gemäß (4.20) zur Beschleunigung einzusetzen. Es ergeben für gleich
lange Messreihen A und B:
C(A,B)(k∆) ≈
1
iDFT DFT(A)(n) DFT(B)(n) (k).
N
(4.29)
Der Faktor (−1)n fehlt hier, weil in diesem Fall sowohl A als auch B als bei t = 0 startend
betrachtet werden. Man sollte beachten, dass durch die Benutzung der DFT das Signal
implizit mit Periode N ∆ periodisiert wird. Daher sollte C(A,B)(k∆) nur für k N/2
interpretiert werden. Die Berechnung der 2 DFTs sowie der inversen DFT braucht etwa
6N log N Operationen, was normalerweise wesentlich weniger als die 2N K der direkten
Berechnung ist.
In Python sieht die Berechnung der Kreuzkorrelation so aus:
import numpy
import numpy.fft as fft
def kreuzkorrelation(A, B):
ftA = fft.fft(A).conj()
ftB = fft.fft(B)
return numpy.real(fft.ifft(ftA*ftB))/A.shape[0]
58
4.3 Kreuz- und Autokorrelation
200
C(v,v)
150
100
50
0
500.0
0.2
0.4
t
0.6
0.8
1.0
Abbildung 4.2: Geschwindigkeitsautokorrelationsfunktion einer temperierten LennardJones-Flüssigkeit mit niedriger Dichte (rot gepunktet) und hoher Dichte (blau durchgezogen). Für die niedrige Dichte ist die Autokorrelationsfunktion im wesentlichen exponentiell abfallend, mit einer Korrelationszeit τc = 0.17, die durch die Kopplungszeit des
Thermostaten bestimmt ist.
4.3.1 Autokorrelationsfunktion
Im Spezialfall A = B spricht man von der Autokorrelationsfunktion. Diese ist offenbar
symmetrisch, daher sind nur Zeitversätze τ ≥ 0 von Interesse. Die Autokorrelationsfunktion misst gewissermaßen, wie lange es dauert, bis die Observable nicht mehr von ihrem
vorherigen Wert abhängt, wann es diesen sozusagen „vergisst“. In dem häufigen Fall, dass
die Autokorrelationsfunktion zunächst exponentiell abfällt, lässt sich dem Gedächtnis
eine Zeitkonstante τc , die Korrelationszeit, zuordnen. Diese kann man entweder durch
einen geeigneten Funktionsfit bestimmen, oder aber durch Integration aus
Z ∞
Z ∞
C(A,A)(τ ) dτ =
C(A,A)(0)e−τ /τc dτ = τc C(A,A)(0).
(4.30)
0
0
Abbildung 4.2 zeigt die Geschwindigkeitsautokorrelation C(v,v) einer temperierten
Lennard-Jones-Flüssigkeit bei zwei verschiedenen Dichten. Die Temperierung wird dabei
mit Hilfe eines Thermostaten erreicht, der die Teilchen stochastisch an ein Wärmebad
koppelt. Dadurch dekorreliert die Geschwindigkeit eines Teilchens in einer Korrelationszeit von etwa 1/6.
R∞
C(v,v) wird häufig dazu benutzt, um die Diffusionskonstante D = 0 C(v,v)(τ ) dτ des
Systems zu bestimmen, die also eng mit der Korrelationszeit des Thermostaten verwandt
ist. Bei niedriger Dichte ist das System annähernd ein ideales Gas, und die Teilchen dekorrelieren im wesentlichen nur durch den Einfluss des Thermostaten, der durch Zufallskräfte
59
4 Datenanalyse und Signalverarbeitung
wirkt, daher ist C(v,v) tatsächlich gut exponentiell abfallend. Formel (4.30) bestimmt
die Korrelationszeit mit guter Genauigkeit zu etwa τc = 0.17, wie durch den Thermostaten zu erwarten. Im Falle der dichteren Flüssigkeit hingegen kann diese Formel nicht
angewendet werden, da die Autokorrelation kein einfacher exponentieller Abfall mehr ist,
da auch Stoßprozesse eine wichtige Rolle spielen. Diese führen zum Durchschwingen der
Autokorrelationsfunktion.
4.4 Messfehlerabschätzung
In diesem letzten Abschnitt zur Datenanalyse geht es darum, wie der Messfehler bei der
Messung des Erwartungswerts einer stochastischen Observable abgeschätzt werden kann.
Wir betrachten also eine Messreihe xi , i = 1(1)N , die verschiedene Messungen einer
stochastischen Observablen x darstellen. Der Erwartungswert dieser Observablen lässt
sich dann bekanntermaßen als
hxi ≈ x̄ :=
N
1 X
xi
N
(4.31)
i=1
abschätzen. Doch was ist nun der Fehler, den wir mit dieser Schätzung machen? Dieser
ist die zu erwartende quadratische Abweichung
D
N
N
E
1 X
2 X
2 X
1
(x − hxi)2 = 2
x2 − hxi2
hxi xj i −
hxi i hxi + hxi2 = 2
hxi xj i +
N
N
N
N
i,j=1
i=1
i>j
(4.32)
An dieser Stelle nimmt man nun an, dass die Messungen paarweise unabhängig sind,
also, dass hxi xj i = hxi i hxj i für i 6= j. In der Praxis lässt sich das zum Beispiel durch
Betrachten der Autokorrelationsfunktion sicherstellen, indem nur Messwerte mit einem
zeitlichen Abstand berücksichtigt werden, der sehr viel größer als die Korrelationszeit
ist. Unter der Annahme, dass die Messungen xi alle paarweise unabhängig sind gilt also
weiter
1
1
N (N − 1)
1 2
2
2
2
2
(x − hxi)2 =
= σ 2 (x). (4.33)
−
hxi
=
−
hxi
hxi
+
x
x
N2
N
N
N
Sind die Messungen unabhängig voneinander, ist der quadratische Fehler von N Messungen also gerade ein N -tel der Varianz
D
2 E
σ 2 (x) = x − hxi
= x2 − 2 hhxi xi + hxi2 = x2 − hxi2 ,
(4.34)
die die erwartete quadratische Abweichung einer Messung vom Mittelwert angibt. Sie
ist eine Eigenschaft der zu messenden Observablen und daher nicht von der Anzahl der
Messungen abhängig.
Als Fehlerbalken wird üblicherweise die Standardabweichung der Messung x, angegeben. Diese ist durch
p
1
h(x − hxi)2 i = √ σ(x)
(4.35)
N
60
4.4 Messfehlerabschätzung
gegeben. Dies bedeutet, dass für eine Halbierung des Fehlerbalken bereits viermal soviele
Messungen durchgeführt werden müssen, und für eine Größenordnung an Genauigkeit
hundert Mal soviele. Besonders für Computersimulationen ist das ein Problem, da die
Rechenzeit im allgemeinen proportional zur Anzahl der Messungen ist. Dauert also eine
Simulation eine Woche, was nicht ungewöhnlich ist, so würde eine Messung mit einer
Größenordnung mehr Genauigkeit fast zwei Jahre in Anspruch nehmen!
Zur Berechnung des Fehlers benötigen wir noch eine Schätzung der Varianz, die im
Allgemeinen ebensowenig wie der Mittelwert bekannt ist und geschätzt werden muss.
Dazu ersetzt man die Mittelwerte in x2 − hxi2 durch den Schätzer (4.31). Für diesen
Ausdruck gilt:
D
n
E
1 X 2
N −1 2
1 X
x2 − x̄2 = x2 − 2
hxi xj i =
x − hxi2 ,
xi − 2
N
N
N
i=1
(4.36)
i6=j
wobei wir wieder annehmen, dass die Messungen unabhängig voneinander sind. Dass der
Ausdruck auf der linken Seite selber kein guter Schätzer ist, liegt also daran, dass für x̄
zweimal derselbe Datensatz benutzt wurde. Ein guter Schätzer für σ 2 (x) ergibt sich aus
der Umkehrung von (4.36):
1
N 2
σ (x) ≈
x − x̄2 =
N −1
N −1
2
N
X
!
x2i
− N x̄
2
.
(4.37)
i=1
Auf dem Computer lassen sich also hxi und σ 2 (x) bequem in einem Durchlauf der
Daten abschätzen:
sum = 0
sum2 = 0
for v in
sum
sum2
mittel =
sigma2 =
fehler =
x:
+= v
+= v*v
sum/len(x)
(sum2 - len(x)*mittel**2)/(len(x)-1)
sqrt(sigma2/N)
In der Praxis wird oft einfach angenommen, dass die Messungen unabhängig sind.
Was passiert nun, wenn dies nicht der Fall ist? Betrachten wir also eine Observable die
o.B.d.A. Mittelwert hxi = 0 habe. Dann ist wie oben gezeigt
(x − hxi)2 =
1
2 X
hxi xj i + σ 2 (x).
2
N
N
(4.38)
i>j
P
Der tatsächliche Fehler ist also um N22 i>j hxi xj i größer als man aufgrund der Varianz
erwarten würde. In die Abschätzung für die Varianz ging ebenfalls die Unabhängigkeit
61
4 Datenanalyse und Signalverarbeitung
ein, für diese gilt nun


X
1
−
hxi xj i
N
N
1 
x2 − x̄2 =
N x2 − x2
N −1
N −1
D
E
(4.39)
i6=j
X
2
hxi xj i ,
= σ 2 (x) −
N (N − 1)
(4.40)
i>j
1
d.h., die Varianz wird zusätzlich noch um (N −1)N
2
wird der quadratische Fehler also um ebenfalls
P
i6=j
hxi xj i unterschätzt. Insgesamt
E
1 N D 2
x − x̄2
N N −1
X
−j
N N
X
X
2
2
2
hxj xj+n i
=
+
hxi xj i =
N 2 (N − 1)N 2
N (N − 1)
F = (x − hxi)2 −
(4.41)
j=1 n=1
i>j
unterschätzt. Für eine Observable x, die in gleichmäßigen Zeitabständen ∆ gemessen
wird, lässt sich dieser Ausdruck mit Hilfe der Autokorrelationsfunktion C(τ ) = C(x,x)(τ )
abschätzen:
N
F ≈
X
2
N (N − 1)
j=1
Z
N −j
C(n∆) ≈
n=0
2
N
Z
∞
C(n∆) =
n=0
2τc σ 2 (x)
2 τc
C(0) =
,
N∆
∆ N
(4.42)
wobei τc die Korrelationszeit gemäß (4.30) ist und angenommen wurde, dass τc N ∆,
so dass die Erweiterung des Integrals bis unendlich keinen nennenswerten Beitrag mehr
liefert. Verglichen mit (4.33) erhält man mit korrelierten Daten eine Abschätzung für den
Fehler, die um einen Faktor 1 − 2τC /∆ zu klein ist, was sich durch noch so gute Statistik
nicht ausgleichen lässt! Daher lassen sich ohne Kenntnis der Korrelationszeit der Daten
keine verlässlichen Aussagen über die Güte der Daten machen. Nur, wenn ∆ τc , ist
der Fehler durch korrelierte Daten vernachlässigbar.
Abbildung 4.3 zeigt die scheinbare Varianz des weniger dichten thermalisierten
Lennard-Jones-Systems als Funktion der gewählten Schrittweite. Wie gezeigt ist die Korrelationszeit dieses Systems ≈ 0,17, so dass bei rascheren Messungen eine Unterschätzung
der Varianz und auch des Fehlers zu erwarten ist, was von der Abbildung bestätigt wird.
62
4.4 Messfehlerabschätzung
1.1
²-Schätzer
1.0
0.9
0.8
0.7
0.6
0.5
0.00 0.05 0.10 0.15 0.20 0.25 0.30
Abbildung 4.3: Geschätzte, scheinbare Varianz eines dünnen temperierten LennardJones-Systems als Funktion der gewählten Schrittweite ∆. Die schwarze Linie zeigt die
Abschätzung der scheinbaren Varianz gemäß (4.42) als (1 − 2τC /(∆N ))σ 2 (x), was gut
zu den gemessenen Daten passt.
63
5 Nichtlineare Gleichungssysteme
Im zweiten Kapitel hatten wir uns mit der Lösung linearer Gleichungssysteme beschäftigt,
die ja eine wesentliche Grundlage der numerischen Mathematik darstellen. Allerdings
tauchen in der Praxis, besonders in der Physik, leicht auch nichtlineare Gleichungssysteme
auf. In diesem Fall kann man meist keine allgemeine Aussage über Existenz und Anzahl
der Lösungen machen, und kann auch keine exakten Verfahren zur Lösung angeben.
Nichtlineare Gleichungssysteme werden typischerweise in zwei Formen betrachtet. Sei
eine Funktion f : M ∈ Rn → Rn gegeben. Dann suchen wir die Nullstellen
x,
so dass f (x) = 0,
(5.1)
also die Lösungen zur Gleichung f (x) = 0. Man beachte, dass anders als im Fall der
linearen Gleichungssysteme gefordert wird, dass der Bildraum wie auch der Ursprungsraum M zu einem Vektorraum derselben Dimension n gehören. Ohne diese Voraussetzung ist eine eindeutige Lösung im Allgemeinen unmöglich. Anders als im Falle der
linearen Gleichungssysteme ist es hier auch nicht ohne Weiteres möglich, den Lösungsraum anzugeben, falls die Lösung nicht eindeutig ist. Tatsächlich kann der Lösungsraum
ja eine beliebig komplexe Mannigfaltigkeit innerhalb M darstellen, die dann gar nicht
geschlossen parametrisiert werden kann. Das macht die numerische Bestimmung dieser
Lösungsmannigfaltigkeit sehr schwierig.
Alternativ können wir für eine Funktion g : M ∈ Rn → Rn die Fixpunkte suchen.
Diese sind
x, so dass g(x) = x,
(5.2)
also die Lösungen der Gleichung g(x) = x. Eine Fixpunktgleichung lässt sich natürlich
stets auch als Nullstellenproblem mit f (x) = g(x) − x formulieren; anders herum geht
dies im Allgemeinen nicht.
Die beiden Formulierungen unterscheiden sich allerdings im natürlichen Lösungsansatz. Die Nullstellengleichung (5.1) ähnelt dem linearen Gleichungssystem (2.1). Das
Newtonverfahren beruht auf einer lokalen Linearisierung und dem Lösen dieses linearen Gleichungssystems. Die Fixpunktgleichung hingegen legt nahe, den Fixpunkt durch
sukzessive Substitution zu suchen: x0 → g(x0 ) → g(g(x0 )) → . . ..
5.1 Sukzessive Substitution
Eine Abbildung g : M → M mit M ⊂ Rn heißt Lipschitz-stetig (L-stetig), falls es ein
L ∈ R gibt, so dass
kg(x) − g(y)k ≤ L kx − yk
∀x,y ∈ M.
(5.3)
65
5 Nichtlineare Gleichungssysteme
Alle auf M differenzierbaren Funktionen mit beschränkter Ableitung sind L-stetig, wenn
ihre Ableitung beschränkt ist. Die Lipschitzkonstante ergibt sich aus dem Mittelwertsatz
zu L = maxx∈M kg 0 (x)k. Es gibt allerdings noch mehr L-stetige Funktionen, zum Beispiel die in 0 nicht differenzierbare Betragsfunktion, die auf ganz R L-stetig mit L = 1
ist. Auf der anderen Seite ist offenbar jede L-stetige Funktion auch stetig, d.h., die Lstetigen Funktionen sind eine eigene Klasse zwischen den stetigen und differenzierbaren
Funktionen. Dabei ist es nicht wesentlich, welche Norm k·k genutzt wird. Sie kann für
das Problem geeignet gewählt werden, sofern sie die üblichen Bedingungen an eine Norm,
wie etwa die Dreiecksungleichung, erfüllt.
Hat eine Funktion g : M → M eine Lipschitz-Konstante L < 1, so heißt g kontrahierend, weil zwei verschiedene Punkte durch die Abbildung stets näher aneinander geschoben werden. Wir betrachten nun einen beliebigen Startpunkt x0 ∈ M und definieren
damit die Folge der sukzessiven Substitution:
xn := g(xn−1 ) für n ≥ 1.
(5.4)
Dann gilt für alle n,m ∈ N der Banachsche Fixpunktsatz
kxn+m − xn k =
m−1
X
xn+k+1 − xn+k
≤
k=0
m−1
X
kxn+k+1 − xn+k k
k=0
= kg(g(. . . g(xn+1 ))) − g(g(. . . g(xn )))k + · · ·
+ kg(g(xn+1 )) − g(g(xn ))k + kg(xn+1 ) − g(xn )k + kxn+1 − xn k
≤
m−1
X
Lk kxn+1 − xn k ≤
k=0
1
Ln
kxn+1 − xn k ≤
kg(x0 ) − x0 k .
1−L
1−L
(5.5)
Die sukzessive Substitution definiert also eine Cauchyfolge, die in M konvergiert, sofern
M abgeschlossen ist (z.B. M = Rn oder M Einheitskugel). Für den Grenzwert x dieser
Folge gilt
x = lim xn+1 = lim g(xn ) = g(x),
(5.6)
n→∞
n→∞
er ist also ein Fixpunkt. Das Verfahren wird abgebrochen, wenn |xn − xn−1 | =
|g(xn−1 ) − xn−1 | hinreichend klein ist.
Wir betrachten nun zwei Fixpunkte x und y. Dann gilt
kx − yk = kg(x) − g(y)k ≤ L kx − yk =⇒ x = y.
(5.7)
Das bedeutet, dass es nur genau einen Fixpunkt x von g in M gibt, und dass die sukzessive
Substitution für jeden Startwert global gegen x konvergiert. (5.5) gibt auche eine a prioriAbschätzung des Fehlers:
kx − xn k ≤
66
Ln
kg(x0 ) − x0 k
1−L
(5.8)
5.1 Sukzessive Substitution
0.5
0.4
0.3
0.2
0.1
0.00.0 x00.1
0.2
x2
0.3
0.4
4.0
3.5
3.0
2.5
2.0
1.5
1.0
0.5
x1
x10 x0
x9
0.5 0.00.0 0.5 1.0 1.5 2.0 2.5 3.0 3.5 4.0
Abbildung 5.1: Sukzessive Substitution mit Funktion g(r) = e−r /φ0 mit φ0 = 2 (links)
und φ0 = 1/4 (rechts). Blau durchgezogen ist die Funktion g, die Winkelhalbierende
ist schwarz dargestellt. Die Punkte auf der Winkelhalbierenden markieren die Punkte
(x1 ,x1 ), (x2 ,x2 ) usw., durch die das Lot auf g gefällt wird, um den nächsten Punkt der
sukzessiven Substitution zu erhalten. Im linken Graph sind die ersten sieben Glieder
dargestellt, die exponentielle Konvergenz ist gut zu sehen. Im rechten Graph konvergiert
das Verfahren nicht mehr.
sowie eine Abschätzung der Konvergenzrate:
kg(xn ) − g(x)k
kxn+1 − xk
=
≤ L < 1.
kxn − xk
kxn − xk
(5.9)
Die sukzessive Substitution konvergiert also linear.
Neben dieser globalen Konvergenzeigenschaft konvergiert die sukzessive Substituion
auch lokal: ist g : Rn → Rn eine differenzierbare Funktion und hat einen Fixpunkt x mit
kg 0 (x)k < 1, so gibt es eine Umgebung des Fixpunktes, in dem die sukzessive Substitution
gegen diesen Fixpunkt konvergiert.
5.1.1 Beispiel
Als Beispiel für eine Anwendung des Banachschen Fixpunktsatzes betrachten wir die dimensionslose Form des Yukawa- oder Debye-Hückel-Potentials φ(r) = e−r /r. Wir fragen
uns, wann für welches r dieses Potential einen gegeben Wert φ0 annimmt. Das führt zu
der Fixpunktgleichung
e−r
g(r) =
=r
(5.10)
φ0
67
5 Nichtlineare Gleichungssysteme
Die linke Seite ist eine auf [0,∞) L-stetige Funktion mit L = 1/φ0 , wie man durch
Ableiten leicht sieht.
Abbildung 5.1 zeigt die sukzessive Substitution für g(r). Graphisch lässt sich das Verfahren visualisieren, indem in jeder Iteration der Funktionswert xn+1 = y = g(xn ) an der
Winkelhalbierenden y = x auf die x-Achse zurückgespiegelt wird. Im linken Graph ist
φ0 = 2 und damit L = 1/2, so dass die sukzessive Substitution exponentiell konvergiert.
Für das letzte abgebildete Glied, x7 , gilt |x7 − x| ≤ 1/28 = 1/256. Im rechten Graph ist
φ0 = 1/4 und damit L = 4. Insbesondere ist auch im Fixpunkt g 0 ((x)) > 1. Abgebildet
sind die ersten zehn Glieder der sukzessiven Substitution, die hier nicht mehr konvergiert.
Wird hingegen φ0 so gewählt, dass g 0 ((x)) < 1, aber L > 1, so konvergiert das Verfahren
zwar noch, aber nicht mehr exponentiell.
5.2 Newtonverfahren in einer Dimension
Nachdem wir bis jetzt die sukzessive Substitution zur Bestimmung von Fixpunkten betrachtet haben, geht es nun um die Nullstellensuche. Sei also zunächst eine stetig differenzierbare Funktion f : [a,b] → R gegeben und deren Nullstellen x, f (x) = 0, gesucht.
Ähnlich wie bei der sukzessiven Iteration starten wir mit einem Startwert x0 . Um uns
nun der Nullstelle der Funktion zu nähern, linearisieren wir in der aktuellen Näherung
xn und lösen nach der Nullstelle xn+1 auf:
xn+1 = g(xn ) := xn −
f (xn )
f 0 (xn )
für n ≥ 0,
(5.11)
wobei wir annehmen, dass f 0 (x) 6= 0 auf [a,b]. Für eine Nullstelle x von f gilt offenbar
g(x) = x, d.h. wir suchen einen Fixpunkt von g, den wir wieder durch sukzessive Substitution annähern können. Man bricht das Verfahren wie auch die sukzessive Substitution
ab, wenn |xn − xn−1 | bzw. |f (xn )| hinreichend klein sind.
Ist nun f sogar zweifach stetig differenzierbar, so gilt
g 0 (x) = 1 −
f 0 (x)2 − f (x)f 00 (x)
f (x)f 00 (x)
=
=⇒ g 0 (x) = 0.
f 0 (x)2
f 0 (x)2
(5.12)
Das Newtonverfahren konvergiert also zumindest lokal gegen einen Fixpunkt x von g
beziehungsweise eine Nullstelle von f . Tatsächlich konvergiert das Verfahren wenigstens
quadratisch, wenn f zweifach differenzierbar ist, da
(xn − x)
(xn − x)f 0 (xn ) − f (xn )
f (xn ) − f (x)
0
xn+1 − x =
= 0
f (xn ) −
f 0 (xn )
f (xn )
xn − x
0
(xn − x) 0
(x
−
x)(x
n
n − ξ ) 00
= 0
f (xn ) − f 0 (ξ 0 ) =
f (ξ)
(5.13)
f (xn )
f 0 (xn )
und somit
68
maxξ∈[a,b] |f 00 (ξ)|
|xn+1 − x|
≤
minξ∈[a,b] |f 0 (ξ)|
|xn − x|2
(5.14)
5.2 Newtonverfahren in einer Dimension
20
0.5
0.4
15
10
5
0.3
0.2
0.1
0.0
0.1
0 x0 x1 x2 x3 x4 x5
0.0 0.1 0.2 0.3 0.4
x1
x2 x3
x0
0.2
0.5 0.50 0.75 1.00 1.25 1.50 1.75 2.00
Abbildung 5.2: Newtonverfahren für die Funktion f (r) = e−r /r − φ0 . Wie schon beim
Graphen zur sukzessiven Substitution ist links φ0 = 2, rechts φ0 = 1/4, allerdings konvergiert das Newtonverfahren für beide Werte. Blau dargestellt ist f , die roten, dicken
Linien stellen die Tangenten dar, deren Nullstellen die neuen Näherungen für die gesuchte
Nullstelle von f sind.
Ist f nur differenzierbar, so lässt sich ähnlich zeigen, dass das Newtonverfahren superlinear konvergiert. Das Newtonverfahren konvergiert also in jedem Fall schneller als die
sukzessive Substitution, erfordert allerdings eine mindestens stetig differenzierbare Funktion.
Bis jetzt haben wir nur die lokale Konvergenz des Newton-Verfahrens. Ist die Zielfunktion f ∈ C 1 ([a,b]) allerdings konvex bzw. konkav, also f 0 monoton wachsend bzw.
fallend und beschränkt, und hat f eine Nullstelle in [a,b], so kann man zeigen, dass das
Newtonverfahren global gegen eine Nullstelle x von f in [a,b] konvergiert. Dabei ist das
Verfahren nach dem ersten Schritt monoton, d.h. entweder x1 ≤ x2 ≤ . . . ≤ x oder
x1 ≥ x2 ≥ . . . ≥ x.
In SciPy gibt es natürlich auch das Newtonverfahren sowie einige verbesserte Algorithmen. Das Newtonverfahren ist als scipy.optimize.newton(f, x0, df) implementiert, wobei f und df die Funktion f und ihre Ableitung df/dx angeben, und x0
der Startwert des Newtonverfahrens.
5.2.1 Beispiel
Wir betrachten wieder die Aufgabe e−r /r = φ0 , bzw. f (r) = e−r /r − φ0 = 0. Die
Ableitung dieser Funktion ist −e−r (1+r)/r2 , f fällt also monoton. Daher konvergiert das
Newtonverfahren global und monoton, wie in Abbildung 5.2 zu sehen. Im linken Graphen
ist r0 < r, daher startet das Verfahren sofort monoton. Im rechten Graphen ist r0 < r.
69
5 Nichtlineare Gleichungssysteme
Hier wird im ersten Schritt r1 < r, und erst dann wächst die Näherung wieder monoton.
In jedem Fall konvergiert das Newtonverfahren, anders als die sukzessive Substitution,
für beide Werte von φ0 innerhalb weniger Schritte zuverlässig gegen die Nullstelle.
5.2.2 Wurzelziehen
Wir betrachten die Gleichung f (x) = xk − a = 0 auf der positiven Halbachse. Dann
konvergiert für jeden Startwert x0 > 0 das Newtonverfahren
xn+1
f (xn )
= xn − 0
=
f (xn )
1
1−
k
xn +
1 a
k xk−1
n
(5.15)
gegen die einzige Nullstelle, nämlich die k-te Wurzel aus a. Sinnvollerweise wählt
man da
1
her x0 = a als Startwert. Für k = 2 ergibt sich das Heron-Verfahren xn+1 = 2 xn + xan ,
das bereits im 2. Jhdt. vor Christus zum Wurzelziehen benutzt wurde.
Für die Wurzel aus a = 2 sind die ersten 5 Schritte des Heronverfahrens:
Schritt n
0
1
2
3
4
5
xn
1.000000000000000
1.500000000000000
1.416666666666667
1.414215686274510
1.414213562374690
1.414213562373095
Anzahl korrekter Stellen
1
1
2
5
11
15
Mit der auf Rechnern üblichen doppelten Genauigkeit ist das Verfahren damit auskonvergiert.
Die Anzahl der Rechenoperationen für n Schritte entspricht der Auswertung eines Polynoms mit 3n/2 Koeffizienten. Wäre man zum Beispiel nur an der Wurzel im Bereich [0,5]
interessiert und
√ würde hierzu ein interpolierendes Polynom mit 7 Chebyshev-Stützstellen
nutzen, wäre 2 ≈ 1.40966 mit gerade einmal einer korrekten Stelle.√Mit einer Taylorentwicklung um 1 würde es etwas besser. Bei 7 Termen liefert diese 2 ≈ 1.4214 mit 2
korrekten Stellen.
Für k = −1 wird aus der Wurzelaufgabe eine Division, da wir die Nullstelle der Funktion f (x) = x1 − a suchen. Die Lösung kann nur mit Hilfe der Grundrechenarten durch
die Iteration
f (xn )
xn+1 = xn − 0
= 2xn − ax2n
(5.16)
f (xn )
bestimmt werden. Allerdings ist die Ableitung von a/x unbeschränkt, daher konvergiert
das Verfahren nur für Startwerte, die hinreichend nah an der Lösung sind. Wie man
sich in diesem Fall leicht überlegt, konvergiert das Verfahren nur für xo ∈ (0, 2/a), was
schwierig zu erfüllen ist, ohne a−1 bereits zu kennen.
70
5.3 Sekantenmethode
5.2.3 Nullstellen von Polynomen
Ist p ein Polynom, so lassen sich dessen Nullstellen (approximativ) mit Hilfe des Newtonverfahrens bestimmen:
p(xn )
xn+1 = xn − 0
,
(5.17)
p (xn )
wobei p(xn ) und p0 (xn ) durch ein modifiziertes Hornerschema bestimmt werden können:
double newton_step(double *series, int n, double xn)
{
double p = series[n];
double dp = n*series[n];
for(int i = n-1; i >= 0; --i) {
p = p*xn +
series[i];
dp = dp*xn + i*series[i];
}
return xn - p/dp;
}
Das Newtonverfahren liefert natürlich nur eine Nullstelle des Polynoms. Durch die Polynomdivision, wieder mit Hilfe des Hornerschemas wie in Abschnitt 3.1, lässt sich diese
aber abspalten und das Newtonverfahren erneut starten, bis alle Nullstellen gefunden
sind.
5.3 Sekantenmethode
In vielen Fällen ist es nicht einfach oder unmöglich, die Ableitung einer Funktion zu
bestimmen. In diesem Fall kann man die Ableitung durch die dividierte Differenz annähern, wobei nun zwei Startpunkte x0 und x1 gebraucht werden. Dies führt dazu, dass
die Näherungsfunktion keine Tangente mehr ist, wie beim Newtonverfahren, sondern im
Allgemeinen eine Sekante. Daher rührt der Name der Sekantenmethode
xn+1 = xn − f (xn )
xn − xn−1
,
f (xn ) − f (xn−1 )
(5.18)
die nicht mehr quadratisch, aber wenigstens superlinear konvergiert.
Das Bestimmen der Ableitung von f ist immer dann unmöglich, wenn f sehr komplex ist. Ein Extremfall wäre eine Molekulardynamik-Computersimulation, bei der zum
Beispiel in Abhängigkeit vom aktuellen Volumen V der mittlere Druck P (V ) in einem
gegebenen System bestimmt wird. Den mittleren Druch nach V abzuleiten, ist vollkommen aussichtslos, wenn die Wechselwirkungen zwischen den Teilchen hinreichend komplex
sind. Dabei ist es von großem Interesse, dasjenige Volumen zu bestimmen, für das P (V )
gleich einem vorgegebenen Außendruck P0 ist, denn dies ist die natürliche Bedingung im
isobarischen Ensemble. Dies führt aber zur Nullstellengleichung P (V ) − P0 = 0.
Als Beispiel für die Sekantenmethode soll ein weiteres Mal die Funktion f (r) = e−r /r−
φ0 dienen. Für diese zeigt Abbildung 5.3 die erste paar Schritte der Sekantenmethode.
Unter geeigneten Umständen, nämlich, wenn die angenäherte Tangente hinreichend gut
71
5 Nichtlineare Gleichungssysteme
20
0.6
15
0.4
10
0.2
5
0
0.0
0.0 x
2
x1 x2 x3 x4 x5
0.1
0.2
0.3
0.4
x4 x3
x1
0.2
0.5 0.50 0.75 1.00 1.25 1.50 1.75 2.00
Abbildung 5.3: Sekantenmethode für die Funktion f (r) = e−r /r − φ0 . Wie zuvor ist links
φ0 = 2, rechts φ0 = 1/4. Blau dargestellt ist wieder f , die roten, gestrichelten dicken
Linien stellen die Sekanten dar, deren Nullstellen die neuen Näherungen für die gesuchte
Nullstelle von f sind. Durchgezogen ist der Abschnitt der Sekante durch xn−1 und xn ,
der von xn zu xn+1 führt.
mit der tatsächlichen über einstimmt, konvergiert die Sekantenmethode praktisch genauso
gut wie das normale Newtonverfahren. Sind die Startpunkte allerdings ungünstig gewählt,
wie im rechten Beispiel, so kann es passieren, dass diese abwechselnd um die Nullstelle
liegen, und damit nicht mehr monoton konvergieren.
In SciPy implementiert scipy.optimize.newton(f, x0) (also bei Nichtangabe
der Ableitung) die Sekantenmethode. f ist wieder die Funktion, deren Nullstelle gesucht
wird, und x0 ein Startwert. Der zweite wird hardcodiert in einer Umgebung von x0
gewählt, kann also vom Benutzer nicht gesetzt werden.
5.4 Bisektion
Wie wir gesehen haben, konvergiert das Newtonverfahren und seine Varianten sehr
schnell, allerdings oft nur unter der Voraussetzung, dass der Startwert hinreichend nah
an einer Nullstelle liegt. Wie aber kann man einen solchen Startwert finden? Hierfür wird
ein langsameres, robusteres Verfahren gebraucht, zum Beispiel das Bisektionsverfahren
in einer Dimension.
Sei also wieder f ∈ C([a,b]) eine stetige Funktion, und f (a)f (b) < 0. Dann hat f
gemäß Mittelwertsatz wenigstens eine Nullstelle im Interval [a,b], die wir suchen. Dazu
setzen wir zunächst a0 = a und b0 = b. Dann betrachten wir den Intervallmittelpunkt
mn =
72
an + bn
.
2
(5.19)
5.5 Regula falsi
Ist f (mn )f (an ) < 0, hat die Funktion also bei mn und an unterschiedliche Vorzeichen, so
muss eine Nullstelle im halb so großen Interval a1 = a0 , b1 = m0 liegen, mit dem wir nun
weiter verfahren. Anderfalls ist notwendigerweise f (mn )f (bn ) ≤ 0, und die Nullstelle ist
im neuen Interval a1 = m0 , b1 = b0 . Ist bn − an kleiner als die gewünschte Genauigkeit
für die Nullstelle, bricht man einfach ab. mn ist dann die endgültige Näherung für die
Nullstelle.
Das Verfahren halbiert in jedem Schritt die Intervallgröße und damit auch den maximalen Abstand der Näherung zur tatsächlichen Nullstelle x. Es gilt also
|mn+1 − x|
1
≤ ,
|mn − x|
2
(5.20)
das Verfahren konvergiert also nur linear, dafür aber global.
In der Praxis kombiniert man die Bisektion mit dem Newtonverfahren, indem zunächst
einige Schritte des Bisektionsverfahrens gestartet werden, und dann vom Intervallmittelpunkt aus das Newtonverfahren. Konvergiert dieses, so ist man fertig. Läuft das Newtonverfahren hingegen aus dem Bisektionsinterval heraus, verkleinert man dieses weiter
durch Bisektion, und versucht dann erneut, die Nullstelle mit dem Newtonverfahren zu
bestimmen.
In Abbildung 5.4 dient uns ein letztes Mal die Funktion f (x) = e−r /r − 2 als Beispiel
für die Bisektion. Mit sieben Schritten schließt diese bei Startinterval [0,1, 1] die Nullstelle
bis auf [0,3391, 0,3461], als etwa 10−2 genau ein. Zum Vergleich: das Newtonverfahren
mit Startwert 0,05 erreicht in sieben Schritten eine Genauigkeit von etwa 10−5 , und selbst
die Sekantenmethode 10−3 .
In SciPy implementiert scipy.optimize.bisect(f, a, b) mit der Funktion f
und Intervalgrenzen a und b die Bisektion. scipy.optimize.brentq(f, a, b)
implementiert die Brentsche Methode, die unter den selben Bedingung wie die Bisektion
konvergiert, aber meist wesentlich schneller.
5.5 Regula falsi
Sowohl die Bisektion wie auch die Sekantenmethode benötigen zwei Startwerte. Daher
liegt es nahe, die Verfahren zu kombinieren.
Bei der Regula falsi wird wie bei der Bisektion ein Interval [a,b] schrittweise verkleinert
so dass dieses stets wenigstens eine Nullstelle enthält. Anders als bei der Bisektion wird
der neue Randpunkt m allerdings nicht einfach als Intervalmitte bestimmt, sondern mit
Hilfe der Sekantenmethode, mit den beiden Intervalrandpunkten a und b als Stützstellen:
m = b − f (b)
b−a
f (b)a − f (a)b
=
.
f (b) − f (a)
f (b) − f (a)
(5.21)
Da f (a)f (b) < 0, schneidet die Sekante die Nulllinie immer im Interval. Dadurch verkleinert sich das Interval schneller, sofern die Nullstelle der Sekante dicht an der echten
Nullstelle liegt, und die Funktion im Intervall nicht streng konkav oder konvex ist, also
einen Wendepunkt hat. Diese Bedingung ist leider im Allgemeinen nicht gegeben, so dass
73
5 Nichtlineare Gleichungssysteme
1.0
1.0
0.5
0.5
0.0
0.0
0.5
0.5
1.0
1.0
1.50.0
0.2
0.4
0.6
0.8
1.0 1.50.0
0.2
0.4
0.6
0.8
1.0
Abbildung 5.4: Links: Bisektion für die Funktion f (r) = e−r /r − φ0 , hier nur mit φ0 = 2,
da die genaue Form der Funktion für diese Methode unerheblich ist. Blau dargestellt ist
wieder f , die grünen Balken markieren die nacheinander generierten, kleiner werdenden
Intervalle [an , bn ]. Die gestrichelten, schwarzen Linien markieren die Intervalmitten mn ,
die im nächsten Schritt eine der beiden Intervalgrenzen werden. Rechts: Regula falsi
für dieselbe Funktion. Die Funktion ist streng konvex, daher reagiert die Regula falsi
lethargisch und ist der Bisektion unterlegen; die Intervalle verkürzen sich praktisch nicht
mehr, da die untere Anfangsgrenze 1/4 nie versetzt wird, nur die obere Grenze.
oft die einfache Bisektion schneller ist. In diesem Fall wird die Regula falsi sehr langsam,
was auch als Lethargie bezeichnet wird. Dies ist zum Beispiel in Abbildung 5.4 rechts
gezeigt.
Die Regula falsi ist also die schnellste und stabilste Nullstellensuche, falls die Ableitung
der Funktion nicht bekannt ist. Insbesondere funktioniert diese Methode im Allgemeinen
auch noch einigermaßen zufriedenstellend, falls die Funktionswerte gar nicht mehr genau
bekannt sind. Dies wäre zum Beispiel bei der bereits angesprochenen Messung des Drucks
in einer Simulation der Fall, da dieser starken Schwankungen unterliegt. Dadurch kann
man meist den Druck in akzeptabler Rechenzeit nicht so gut mitteln, dass dessen Messfehler vernachlässigt werden kann. Trotzdem konvergiert die Regula falsi im Allgemeinen
zufriedenstellend, solange keine zu hohen Ansprüche an die Genauigkeit gestellt werden.
Die Methode muss in diesem Fall abgebrochen werden, sobald die Grenzen innerhalb des
Fehlerbalkens Null sind.
74
5.6 Newtonverfahren in mehreren Dimensionen
5.6 Newtonverfahren in mehreren Dimensionen
Bis jetzt haben wir das Newtonverfahren nur für eindimensionale Funktionen betrachtet.
Im mehrdimensionalen funktioniert das Verfahren aber sehr ähnlich, wobei die Ableitung
zur Jacobimatrix wird.
Sei also f ∈ C 1 (M, Rn ) eine stetig differenzierbare Abbildung von M ∈ Rn in den Rn .
Wir suchen nun eine Nullstelle x ∈ D, d.h. eine Lösung des nichtlinearen Gleichungssystems f (x) = 0.
Wie schon im Eindimensionalen starten wir mit einer Näherung x(0) ∈ M , und berechnen die nächste Näherung x(1) durch Linearisieren von f in x(0) . Die Linearisierung
ergibt sich aus der Taylorentwicklung:
F (x(1) ) =
˙ F (x(0) ) + F 0 (x(0) ) x(1) − x(0) ,
(5.22)
wobei

F 0 (x) =
d
Fk (x)
dxj
k,j

=
d
dx1 F1 (x)
...
..
.
d
F
dx1 n (x) . . .

d
dxn F1 (x)

..

.
d
dxn Fn (x)
(5.23)
die Jacobimatrix von f an der Stelle x bezeichnet. Die neue Näherung x(1) suchen wir als
!
Nullstelle der Linearisierung (5.22), also aus der Bedingung F (x(1) ) = 0. Da wir ja damit
nur die linearisierte Gleichung gelöst haben, linearisieren wir erneut im neuen Punkt x(1) ,
und so weiter. Ein Schritt des Newtonverfahrens ist dann also
x(m+1) = x(m) + d(m)
mit F 0 (x(m) ) d(m) = −F (x(m) ).
(5.24)
Die Newtonkorrektur d(m) wird als aus der Lösung eines linearen Gleichungssystems
gewonnen, zum Beispiel mit Hilfe der Gaußelimination. Allerdings ist f 0 im Allgemeinen
vollbesetzt, daher verwendetet man normalerweise schnellere, approximative Verfahren,
die wir später kennenlernen werden. Ist F 0 (x(m) ) in einem Schritt singulär, so bricht das
Verfahren ab. Ansonsten wird weiter iteriert, bis d(m) hinreichend klein ist.
Auch im mehrdimensionalen konvergiert dieses Verfahren lokal mindestens quadratisch, sofern in einer abgeschlossenen Umgebung der Nullstelle F 0 (x)−1 beschränkt
ist und f zweifach stetig differenzierbar. Allerdings gibt es kein langsames Verfahren
ähnlich der Bisektion, dass man dem Vefahren vorausschicken könnte, um die Nullstelle
einzugrenzen. Die globale Suche nach Nullstellen in mehreren Dimensionen ist also eine
schwierige Aufgabe. Eine Möglichkeit ist, zunächst mit Hilfe von Optimierungsverfahren
ein x0 zu finden mit möglichst kleiner Norm kf (x0 )k, und von dort das (gedämpfte) Newtonverfahren zu starten. Die globale Optimierung in vielen Dimensionen ist selber eine
sehr schwierige Aufgabe, allerdings existieren hierfür Ansätze wie genetische Algorithmen
oder Simulated Annealing, die wir später kennenlernen werden.
5.6.1 Gedämpftes Newtonverfahren
Leider ist im Mehrdimensionalen die Umgebung um die Nullstelle, in der das Verfahren
konvergiert, oftmals deutlich kleiner. Das Verfahren springt dann leicht über die Nullstelle
75
5 Nichtlineare Gleichungssysteme
hinweg, wie es im eindimensionalen nur am Anfang des Verfahrens vorkommt (z.B. Abbildung 5.2 rechts, im ersten Schritt). Um dies zu verhindern, kann man die Schrittweite
reduzieren, als den Schritt d(m) verkürzen. Die Iteration lautet dann
x(m+1) = x(m) + λd(m)
mit F 0 (x(m) ) d(m) = −F (x(m) ),
(5.25)
wobei die Dämpfung λ ∈ (0,1] so gewählt wird, dass F (xm+1 ) ≤ kF (xm )k. Dazu wird
zum Bespiel mit λ = 1 begonnen, und λ solange verringert, bis die Bedingung erreicht
ist.
76
5.6 Newtonverfahren in mehreren Dimensionen
# Gedaempftes Newtonverfahren
#############################
def gedaempfter_newton(f, fprime, x0, epsilon):
xn = x0
konvergiert = False
while not konvergiert:
# Newton-Korrektur
dn = solve(fprime(xn), f(xn))
if norm(dn) < epsilon:
konvergiert = True
else:
# Schrittweitendaempfung
lambda = 1.0
abstieg = False
while not abstieg:
# neue Naeherung
xneu = xn + lambda*dn
if norm(f(xneu)) < norm(f(xn)):
abstieg = True
else:
lambda = lambda / 2.0
xn = xneu
return xn
Listing 5.1: Gedämpftes Newtonverfahren in mehreren Dimensionen. f(x) muß eine vektorwertige Funktion sein, fprime(x) ihre Ableitung, d.h. eine matrixwertige Funktion.
77
6 Numerisches Differenzieren und
Integrieren
In diesem Kapitel geht es darum, wie eine Funktion, die an diskreten Stützstellen gegeben ist, numerisch differenziert und integriert werden kann. Die Grundlagen dazu wurden
bereits mit dem Kapitel “Darstellung von Funktionen” gelegt: für die numerische Ableitung liegt es nahe, aus der Taylorentwicklung geeignete Ausdrücke für die Ableitungen
zu gewinnen, und für die Integration bieten sich das interpolierende Polynom oder auch
ein Spline and, die sich mit dem Computer leicht analytisch integrieren lassen.
Numerisches Integrieren und Differenzieren kann dabei nicht nur dazu dienen, Integrale oder Ableitungen abzuschätzen, sondern erlaubt auch, einfache Differential- oder
Integralgleichungen numerisch zu lösen. Dazu muss die Gleichung mit Hilfe der hier vorgestellten Verfahren diskretisiert und das resultierende lineare Gleichungssystem gelöst
werden.
6.1 Numerisches Differenzieren
Die erste Ableitung einer Funktion f ∈ C 1 ([a,b]) ist definiert als
f (x + h) − f (x)
.
h→0
h
lim
(6.1)
Um den Grenzwert abzuschätzen, liegt es nahe, die Ableitung durch die dividierte Differenz
f (x) − f (y)
f 0 (ξ) ≈ f [x,y] :=
(6.2)
x−y
anzunähern, wobei x und y beide nahe bei ξ liegen sollten.
Doch an welchem Punkt ξ ist diese Näherung optimal? Gemäß Mittelwertsatz gilt auf
jeden Fall f [x,y] = f 0 (ξ) für ein ξ ∈ [x,y]. Man erwartet daher, dass f [x,y] am besten
in der Intervallmitte m = x+y
approximiert. Das ist tatsächlich so, wie wir nun per
2
Taylorentwicklung sehen werden. Mit Entwicklung um m und h = x − y gilt
f (x) − f (y)
1
h
h2
=
f (m) + f 0 (m) + f 00 (m) + O(h3 )
x−y
h
2
8
h 0
h2 00
3
− f (m) + f (m) − f (m) + O(h )
2
8
= f 0 (m) + O(h2 ).
(6.3)
79
6 Numerisches Differenzieren und Integrieren
Bei Ansatzpunkt x gilt hingegen nur
h2 00
f (x) − f (y)
1
0
3
f (x) + hf (x) + f (x) + O(h ) − f (x) = f 0 (x) + O(h).
=
x−y
h
8
(6.4)
In der Praxis ist die Funktion meist an an äquidistanten Stützstellen xi mit xi+1 −xi =
h gegeben. Dann ist, wie oben gezeigt, die beste Zweipunkt-Näherung für die Ableitung
die zentrale Differenz
f (xi+1 ) − f (xi−1 )
= f [xi−1 ,xi+1 ] = f 0 (xi ) + O(h2 ),
2h
(6.5)
während für die linken und rechten dividierten Differenzen gilt:
bzw.
f (xi+1 ) − f (xi )
= f [xi ,xi+1 ] = f 0 (xi ) + O(h)
h
(6.6)
f (xi ) − f (xi−1 )
= f [xi ,xi−1 ] = f 0 (xi ) + O(h).
h
(6.7)
6.1.1 Näherungen höherer Ordnung und höhere Ableitungen
Mit Hilfe von Taylorentwicklungen lassen sich auch Näherungen mit mehr Stützpunkten
und für höhere Ableitungen entwickeln. Wir betrachten zum Beispiel die Punkte für
k = −2(1)2, d.h. die 5 benachbarten Punkte, und suchen Koeffizienten ck derart, dass
c2 f (xi+2 ) + c1 f (xi+1 ) + c0 f (xi ) + c−1 f (xi−1 ) + c−2 f (xi−2 ) = f 0 (xi ) + O(h5 ),
(6.8)
unabhängig von der Form von f und seiner Ableitungen. Durch Einsetzen der Taylorentwicklung
f (x + kh) = f (x) + k hf 0 (x) + k 2
h3
h4
h2 00
f (xi ) + k 3 f (3) (x) + k 4 f (4) (x) + O(h5 ) (6.9)
2
6
24
können wir nun die obige Gleichung auf beiden Seiten als Vielfache von f (x), f 0 (x),
f 00 (x) usw. schreiben. Da unsere Koeffizienten unabhängig von diesen sein sollen, müssen
die Vorfaktoren vor diesen auf beiden Seiten übereinstimmen. Diese sind, beginnend bei
f (x):
c2 + c−2 + c−1 + c1 + c0 = 0
h [2(c2 − c−2 ) + c1 − c−1 ] = 1
h2
[4(c2 + c−2 ) + c1 + c−1 ] = 0
2
h3
[8(c2 − c−2 ) + c1 − c−1 ] = 0
6
h4
[16(c2 + c−2 ) + c1 + c−1 ] = 0.
24
80
(6.10)
6.1 Numerisches Differenzieren
Durch Lösen des Gleichungssystems folgt
−
1
2
2
1
f (xi+2 ) +
f (xi+1 ) −
f (xi−1 ) +
f (xi−2 ) = f 0 (xi ) + O(h4 ).
12h
3h
3h
12h
(6.11)
Auf diese Weise lässt sich auch die höhere Güte der zentralen Differenz verstehen: tatsächlich entspricht diese der optimalen Näherung durch xi−1 , xi und xi+1 , nur dass aus
Symmetriegründen der Koeffizient zu xi verschwindet.
Um nun zum Beispiel die zweite Ableitung zu berechnen, lösen wir (6.10), allerdings
mit einer 1 nicht in der zweiten, sondern dritten Zeile. Das ergibt
1
4
5
4
1
1
− f (xi+2 ) + f (xi+1 ) + f (xi ) + f (xi−1 ) − f (xi−2 ) = f 00 (xi ) + O(h4 ).
h2
12
3
2
3
12
(6.12)
Die Fehlerordnung ist hier um eins höher als man erwarten würde, da für den Term
dritter Ordnung der Vorfaktor ebenfalls verschwindet:
1
4 4
1
·8− + −
· 8 = 0.
12
3 3 12
(6.13)
Mit drei Stützpunkten ergibt sich die Näherung für die zweite Ableitung analog als
1
f (xi+1 ) − 2f (xi ) + f (xi−1 ) =
2
h
f (xi+1 )−f (xi )
h
−
h
f (xi )−f (xi−1 )
h
= f 00 (xi ) + O(h2 ).
(6.14)
Die mittlere Form zeigt, dass sich diese einfachste Form der zweiten Ableitung auch als
dividierte Differenz der dividierten Differenzen verstehen lässt. Technisch wird also die
zweite Ableitung also einfach in erster Ordnung aus der ersten Ableitung in erster Ordnung bestimmt. Analog lässt sich jede n-te Ableitung aus n+1 benachbarten Stützstellen
in erster Ordnung durch dividierte Differenzen approximieren.
6.1.2 Genauigkeit
Generell sind alle diese Näherungen numerisch instabil, da bei kleinen Abständen h auch
f (x) und f (x + h) sehr ähnlich sind. Sind diese betragsmäßig groß, kommt es zu Auslöschung, d.h., f (x + h) − f (x) hat deutlich weniger signifikante Stellen als Maschinengenauigkeit. Daher gibt es stets ein optimales h, das allerdings von der unbekannten zweiten
Ableitung der betrachteten Funktion abhängt.
Auch Verfahren höherer Ordnung sind nicht notwendigerweise genauer, da bei manchen
Funktionen die Ableitungen sehr rasch wachsen. Dann ist zwar h4 sehr viel kleiner als h2 ,
aber der Vorfaktor kompensiert das zunächst. Abbildung 6.1 illustriert dieses Verhalten
am Beispiel der Funktion sin(100x2 ). Erst, wenn die Schrittweite h unter die charakteristische Breite von etwa 600 sinkt, spielt die Ordnung des Verfahrens eine Rolle. Wird
allerdings h zu klein, zeigt sich die endliche Auflösung, mit der der Rechner arbeitet, und
der Fehler steigt wieder an.
81
6 Numerisches Differenzieren und Integrieren
103
102
101
100
10-1
10-2
10-3
10-4
10-5
10-6
10-7
10-8 -12 -10 -8 -6 -4 -2
10 10 10 10 10 10 100
h
Abbildung 6.1: Maximale Abweichung maxx∈[−π,π] |f 0 (x) − a(h; x)| für verschiedene Näherungen a(h; x), als Funktion der Schrittweite h. Die Funktion ist f (x) = sin(100x2 ).
Rot durchgezogen ist die linksseitige Differenz a(h; x) = (f (x) − f (x − h))/h, die zentrale Differenz a(h; x) = (f (x + h) − f (x − h))/2h ist grün gepunktet und die Näherung
4. Ordnung (6.11) blau gestrichelt. Der rechtsseitige Abfall der Kurven entspricht den
Ordnungen O(h) für die linksseitige Differenz, O(h2 ) für die rechtsseitige und O(h4 ) für
die Gleichung 4. Ordnung. Das linksseitige Verhalten ist methodenunabhängig und durch
die endliche Rechenauflösung bestimmt.
6.1.3 Beispiel: Besselsche Differentialgleichung
Wir betrachten die Besselsche Differentialgleichung, eine gewöhnliche lineare Differentialgleichung zweiter Ordnung:
x2
d2 f
df
+x
+ (x2 − ν)f = 0
2
dx
dx
(6.15)
für f ∈ C ∞ ([0,∞)). Die Besselsche Differentialgleichung spielt eine wichtige Rolle in
der Physik, weil sie den radialen Anteil der Laplacegleichung in Zylinderkoordinaten beschreibt. Für die Lösungen dieser Gleichung lassen sich schnell konvergierende Reihen
oder Integraldarstellungen angeben [AS70; Jac99], wir wollen aber zu Demonstrationszwecken diese Differentialgleichung für ν = 0 numerisch lösen. Hierzu definieren wir
fk := f (kh), k ≥ 0, und diskretisieren (6.15) mit Hilfe der finiten Differenzen (6.5) und
(6.14) in linearer Ordnung:
1
1
2
0 = k (fk−1 − 2fk + fk+1 ) + k
fk+1 − fk−1 + k 2 h2 fk
2
2
1
1
= k 2 − k fk−1 + k 2 (h2 − 2)fk + k 2 + k fk+1 .
(6.16)
2
2
82
6.1 Numerisches Differenzieren
1.0
0.5
0.0
0.5
0
2
4
6
8 10 12 14
Abbildung 6.2: Numerische Lösungen der Besselschen Differentialgleichung auf [0,15] mit
Schrittweite h = 0,5 und N = 31 Stützpunkten. Die durchgezogene schwarze Linie
markiert die analytische Lösung. Mit grünen Rauten ist die Lösung mit Hilfe von (6.16)
und Dirichletrandbedingungen dargestellt, für die roten Sterne wurden Funktionswert
und Ableitung bei 0 festgelegt. Blaue Punkte schließlich markieren den Löser dritter
Ordnung mit Dirichletrandbedingungen, der von der analytischen Lösung praktisch nicht
zu unterscheiden ist.
Für die Lösung f auf dem endlichen Intervall [0, (N − 1)h] sind das N − 2 Gleichungen,
da zumindest für die Randpunkte die zweite Ableitung so nicht abgeschätzt werden
kann. Dies ist aber auch nicht weiter verwunderlich, da wir ja die Randbedingungen
noch nicht festgelegt haben. Die natürlichen Randbedingungen der Diskretisierung sind
also Dirichlet-Randbedingungen, bei denen die fehlenden Randwerte vorgegeben werden:
f0 = f (0) = F0 und fN −1 = f ((N − 1)h) = FN −1 .
Wir erhalten das folgende lineare Gleichungssystem:




1
0
0
...
...
0
F0
1/2 −λ 3/2

  0 
0
...
0 




f0

 0 
0
3
−4λ
5
0
.
.
.
0
  ..  


(6.17)
  .  =  ..  ,

..
..
..


 . 
.
.
.
 fN −1



 0 
 0 ...
0
µn − νn
−µn λ
µn + νn 
0
...
0
1
FN −1
wobei λ = (2 − h2 ), µn = (N − 2)2 und νn = 21 (N − 2). Die beiden äußeren Zeilen
implementieren die Dirichletbedingungen, die restlichen Zeilen Gleichung (6.16) für k =
1(1)N − 1. Da die Matrix Bandstruktur hat, können wir dieses lineare Gleichungssystem
effizient mit dem Gaußverfahren lösen.
83
6 Numerisches Differenzieren und Integrieren
Beispielcode 6.1 zeigt ein Pythonskript zur Lösung dieses Gleichungssystems. Dessen
Lösung für h = 0,5 ist in Abbildung 6.2 mit grünen Rauten gezeigt und weicht noch signifikant ab, was allerdings durch die hohe Schrittweite bedingt ist. Mit einer Schrittweite
h < 0,1 gäbe es keine sichtbaren Abweichungen mehr.
Alternativ können wir statt der Dirichlet-Randbedingungen auch Funktion f (0) = F0
und Ableitung f 0 (0) = F00 am linken Rand festlegen. Das ergibt:

1
0
0
...
−1/h 1/h
0
...

 1/2 −λ 3/2
0

 0
3 −4λ
5


.
.
.
..

.
0
...
0
µn − νn
..
...
...
...
0 ...
0
0
0
0
−µn λ
µn + νn
.

 
F0


0


f0

F0 
  ..   0 
 .  =  .

 .. 
 fN −1
 . 

0
(6.18)
Dabei wird für die Ableitung am linken Rand statt der (nicht möglichen) zentralen Differenz der rechtsseitige Differenzenquotient benutzt. Allerdings zeigt Abbildung 6.2 dass
dies die Lösung am linken Rand nicht verbessert. Schuld ist die geringe Genauigkeit des
rechtsseitigen Differenzenquotienten. Da f 0 (0) = 0 sein soll, führt er dazu, dass f0 = f1
gefordert wird, wie man auch gut in der Abbildung sieht, was aber mit der tatsächlichen
Lösung nichts zu tun hat. Wird statt dessen f1 korrekt vorgegeben, ist die Lösung links
tatsächlich genauer, allerdings ist bei praktischen Problemen meist f (h) nicht bekannt
— sonst müsste man die Differentialgleichung ja nicht mehr lösen.
Generell zeigen allerdings sowohl Dirichlet- wie auch gemischte Randbedingungen noch
leichte Artefakte. Diese lassen sich durch natürlich durch kleinere Schrittweite verringern,
da die Lösung aber C ∞ ist, kann man aber stattdessen auch auf Ableitungsnäherungen
höherer Ordnung zurückzugreifen, etwa (6.12) und (6.11). Dann ist die Hauptgleichung
5
1
2
2
2
2
2
fk
0 = (−k + k)fk−2 + (2k − k)fk−1 + k h −
12
3
2
2
1
+ (2k 2 − k)fk+1 + (−k 2 + k)fk+2 .
(6.19)
3
12
Bei N Punkten lassen sich hierdurch nur N − 4 Gleichungen formulieren, weil ja am
linken und rechten Rand jeweils noch zwei Nachbarpunkte benötigt werden. Von diesen
benutzen wir zwei zum Beispiel als Dirichletbedingungen f0 = F0 und fN −1 = FN −1 ,
und generieren daraus über Gleichung (6.16) Näherungen für f1 und fN −2 . Die Lösung
dieses Gleichungssystem ist in Abbildung 6.2 blau gepunktet eingezeichnet und fast nicht
mehr von der analytischen Lösung zu unterscheiden. Dies zeigt den Nutzen von Ableitungsnäherungen höherer Ordnung.
6.2 Quadratur: numerische Integration
Bei der numerischen Integration geht es, analog zum Differenzieren, darum, aus endlich
vielen Stützwerten das Integral einer Funktion in einem endlichen Intervall abzuschätzen.
84
6.2 Quadratur: numerische Integration
Listing 6.1: Numerische Lösung der Besselschen Differentialgleichung mit Hilfe von finiten Differenzen linearer und kubischer Ordnung. Dieser Code erzeugt Abbildung 6.2
# Bessel-Naeherung durch Loesen der
# diskretisierten Differentialgleichung
############################################
from scipy import *
from scipy.linalg import *
from scipy.special import *
import matplotlib.pyplot as pyplot
# Ordnung der Besselfunktion
nu = 0
# Rechter Rand
xmax = 15.0
# Anzahl Punkte Differential
N = 31
# Schrittweite Differential
h = xmax/(N-1)
# Stuetzpunkte
x = arange(0,N)*h
# 3-Punkt-Stencil, Dirichlet-Randbedingung
############################################
b = zeros(N)
A = zeros((N, N))
# Startwerte an den Raendern
A[0, 0] = 1
b[0]
= jn(nu, 0)
A[1, N - 1] = 1
b[1]
= jn(nu, (N-1)*h)
# N-2 innere Punkte von 1 bis N-2 hinter den Startwerten
for n in range(1, N-1):
#
x^2 d^2f/dx^2 + x df/dx
+ (x^2 - nu^2)f
A[n + 1, n - 1] =
n**2
- 0.5*n
A[n + 1, n
] = -2*n**2
+ n**2*h**2 - nu**2
A[n + 1, n + 1] =
n**2
+ 0.5*n
fx3 = solve(A, b)
# 3-Punkt-Stencil, nur linker Rand
############################################
b = zeros(N)
A = zeros((N, N))
# Startwert am Rand
A[0, 0] = 1
b[0]
= jn(nu, 0)
# Ableitung vorgeben
A[1, 0] = -1.0/h
A[1, 2] = 1.0/h
# Formel fuer die Ableitung der Besselfunktionen
if nu == 0:
b[1]
= -jn(1, 0)
else:
b[1]
= 0.5*(jn(nu-1, 0)-jn(nu+1, 0))
85
6 Numerisches Differenzieren und Integrieren
# N-2 innere Punkte von 1 bis N-2
for n in range(1, N-1):
#
x^2 d^2f/dx^2 + x df/dx
A[n + 1, n - 1] =
n**2
- 0.5*n
A[n + 1, n
] = -2*n**2
A[n + 1, n + 1] =
n**2
+ 0.5*n
+ (x^2 - nu^2)f
+ n**2*h**2 - nu**2
fx3l = solve(A, b)
# 5-Punkt-Stencil, Dirichlet-Randbedingung
############################################
# alles wieder auf Null
b = numpy.zeros(N)
A = numpy.zeros((N, N))
# Startwerte an den Raendern, wie zuvor
A[0, 0]
= 1
b[0]
= jn(nu, 0)
A[1, N - 1] = 1
b[1]
= jn(nu, (N-1)*h)
# innere naechste 2 Punkte durch einfache Naeherung
for z,n in ((2, 1), (3, N-2)):
#
x^2 d^2f/dx^2 + x df/dx
+ (x^2 - nu^2)f
A[z, n - 1] =
n**2
- 0.5*n
A[z, n
] = -2*n**2
+ n**2*h**2 - nu**2
A[z, n + 1] =
n**2
+ 0.5*n
# N-4 innere Punkte von 2 bis N-3 hinter den Startwerten, alle auf Null
for n in range(2, N-2):
z = n + 2
#
x^2 d^2f/dx^2 + x df/dx
+ (x^2 - nu^2)f
A[z, n - 2] = -1./12*n**2
+ 1./12*n
A[z, n - 1] = 4./3 *n**2
- 2./3 *n
A[z, n
] = -5./2 *n**2
+ n**2*h**2 - nu**2
A[z, n + 1] = 4./3 *n**2
+ 2./3 *n
A[z, n + 2] = -1./12*n**2
- 1./12*n
fx5 = solve(A, b)
# Ausgabe
############################################
xfine = linspace(0, xmax, 200)
pyplot.plot(xfine, jn(nu, xfine), "k−",linewidth=0.5)
pyplot.plot(x, fx3, "gD")
pyplot.plot(x, fx3l, "r^")
pyplot.plot(x, fx5, "bo")
pyplot.show()
86
6.2 Quadratur: numerische Integration
Wir suchen also Gewichte αi ∈ R, so dass möglichst genau
Z
b
f (x) dx ≈
a
n−1
X
αi f (xi ),
(6.20)
i=0
wobei die αi von der Lage der Stützpunkte („Knoten“) xi abhängen, aber nicht von
f . Dadurch, dass die Funktion über dem ganzen Intervall [a,b] in das Integral eingeht,
wird man für die numerische Integration natürlich mehr Punkte als beim Differenzieren
einbeziehen wollen, und hat dementsprechend auch mehr Möglichkeiten, die Gewichte zu
wählen. Im Folgenden werden wir einige der gebräuchlichsten Verfahren kennenlernen.
6.2.1 Newton-Cotes-Formeln
Um eine an diskreten Stützstellen xi , i = 0(1)n − 1 gegebene Funktion f zu integrieren,
liegt es nahe, die Funktion mit Hilfe eines Polynoms zu interpolieren und dieses dann
analytisch zu integrieren:
Z
b
f (x) dx ≈
a
Z b n−1
X
a i=0
f (xi )Li (x) dx =
n−1
XZ b
i=0
a
|
Li (x)dx f (xi ).
{z
}
(6.21)
αi
Diese Newton-Cotes-Formeln integrieren offenbar alle Polynome bis Ordnung n exakt.
Allerdings verstärkt sich bei allgemeinen Funktion das Rungephänomen bei der Integration, und ab Ordnung n = 9 treten negative Koeffizienten αi auf, was die Näherung
verschlechtert. Daher sind nur kleine n sinnvoll, und in der Praxis werden nur Formeln
bis Ordnung n = 8 benutzt. Die gebräuchlichsten werden im Folgenden kurz diskutiert.
Trapezregel
Die Trapezregel benutzt als Stützstellen x0 = a und x1 = b, die
dementsprechend durch eine Gerade verbunden werden:
Z b
Z b
x−b
x−a
f (x) dx ≈
f (a)
+ f (b)
dx
a−b
b−a
a
a
Z b
Z b
x−b
x−a
= f (a)
dx + f (b)
dx
a a−b
a b−a
b − a
=
f (a) + f (b) .
(6.22)
2
Trapezregel
a
b
87
6 Numerisches Differenzieren und Integrieren
Weiter gilt für den Fehler der Trapezregel
Z b
Z b
b − a
x−b
x−a
f (x) dx −
f (x) − f (a)
f (a) + f (b) =
+ f (b)
dx
2
a−b
a−b
a
a
Z b
x − a
x − b
+ f (b) − f (x)
dx
=
f (x) − f (a)
a−b
a−b
a
Z b
1
f (x) − f (a) f (b) − f (x)
=
(x − b)(x − a) dx
+
|
{z
}
x−a
x−b
a a−b
<0 in [a,b]
=
f 00 (ξ)
2
Z
b
(x − b)(x − a) dx = −
a
(b − a)3 00
f (ξ) (6.23)
12
für ein ξ ∈ [a,b]. Gibt es also eine Abschätzung für die zweite Ableitung von f , so lässt
sich auch der Fehler der Trapezregel abschätzen. Ist f konvex auf [a,b], also f 00 (ξ) > 0,
so unterschätzt also die Trapezregel das Integral, ist f konkav, überschätzt sie es.
Simpsonregel
Simpsonregel
Analog wird die Simpsonregel für die drei Stützpunkte x0 = a,
x1 = m = a+b
2 und x2 = b definiert, die durch eine Parabel
verbunden werden:
Z b
b−a
f (x) dx =
(f (a) + 4f (m) + f (b))
6
a
(b − a)5 (4)
−
f (ξ)
(6.24)
2880
a
m
b
für ein ξ ∈ [a,b], wobei der letzte Term wieder der Fehlerterm ist.
Die Simpsonregel und die Trapezregel sind die meistgenutzten geschlossenen NewtonCotes-Formeln. Geschlossen heißen solche Formeln, die a und b als Stützpunkte beinhalten. Offene Formeln dagegen enthalten wenigstens einen der Punkte nicht. Naturgemäß
sind die beiden folgenden Einpunktformeln offen.
Rechteckregel
Rechteckregel
Wir benutzen x0 = a als Stützpunkt, und erhalten:
Z
b
f (x) dx = (b − a)f (a) +
a
(b − a) 0
f (ξ)
2
(6.25)
a
b
für ein ξ ∈ [a,b], wobei der letzte Term wieder der Fehlerterm ist.
Mittelpunktsregel
Mittelpunktsregel
88
a
m
b
6.2 Quadratur: numerische Integration
Wir benutzen x0 = m =
Z
a+b
2
als Stützpunkt, und erhalten:
b
f (x) dx = (b − a)f (m) +
a
(b − a)3 00
f (ξ)
24
(6.26)
für ein ξ ∈ [a,b], wobei der letzte Term wieder der Fehlerterm ist.
Ähnlich wie schon beim Differenzieren ist also der Intervallmittelpunkt ausgezeichnet,
da dieser bei gleicher Stützstellenzahl eine bessere Ordnung als etwa bei der Rechteckregel
ermöglicht.
6.2.2 Zusammengesetzte Newton-Cotes-Formeln
Wie weiter oben erwähnt, sind Newton-Cotes-Formeln höherer Ordnung numerisch noch
ungünstiger als die Polynominterpolation, auf der sie basieren. Im Allgemeinen konvergiert bei steigender Anzahl der Stützstellen die Näherung für das Integral nicht einmal.
Genauso wie bei der Interpolation liegt es nahe, auf stückweise Polynome, also Splines,
überzugehen, wenn die Funktion f an sehr vielen Stützstellen a = x0 < x1 < . . . < xN =
b gegeben ist.
Für die bei der Interpolation üblicherweise verwendeten kubischen Splines wird die
Stetigkeit der zweiten Ableitung zweier Teilstücke an den gemeinsamen Stützstellen gefordert. Diese Forderung ist bei der Integration unnötig. Zudem erfordert die Auswertung
der Splines die ziemlich aufwändige Lösung eines linearen Gleichungssystems. Daher greift
man bei der numerischen Integration üblicherweise auf stückweise Polynome niedrigerer
Ordnung ohne Anschlussbedingungen an den Stützstellen zurück.
Da die reinen, nicht zusammengesetzten Newton-Cotes-Formeln in der Praxis kaum
auftauchen, sind oft die jeweiligen zusammengesetzten Formeln gemeint, wenn man von
der Trapezregel oder der Simpsonregel spricht, insbesondere in englischsprachiger Literatur.
Zusammengesetzte Trapezregel
Zusammengesetzte
Trapezregel
Die zusammengesetzte Trapezregel für beliebig viele Stützstellen
xi , i = 0(1)N ist gegeben durch
Z
b
f (x) dx ≈
a
N
−1
X
i=0
=
xi+1 − xi f (xi ) + f (xi+1 )
2
a x1 x2 x3 b
N
−2
X
x1 − x0
xi+1 − xi
xN − xN −1
f (x0 ) +
f (xi ) +
f (xN )
2
2
2
(6.27)
i=1
Auf einem äquidistanten Gitter a + kh, k = 0(1)N mit h = (b − a)/N , verkürzt sich diese
89
6 Numerisches Differenzieren und Integrieren
Formel zu
Z
b
f (x) dx = h
a
N −1
f (x0 ) X
f (xN )
+
f (xi ) +
2
2
!
−
i=1
(b − a)3 00
f (ξ)
2
| 12N {z
}
(6.28)
=O(h2 )
für ein ξ ∈ [a,b], wobei der letzte Term wieder den Fehler angibt und üblicherweise
nicht berechnet werden P
kann. Hier konnten wir den Fehler der einfachen Trapezregel
N −1 00
übernehmen, da stets N1 i=0
f (ξi ) = f 00 (ξ) für ein ξ ∈ [a,b].
Eine einfache Implementation der Trapezregel in Python könnte so aussehen:
def trapez(f, a, b, N):
h = (b-a)/float(N)
summe = 0.5*(f(a) + f(b))
for x in a + numpy.arange(1, N)*h:
summe += f(x)
return h*summe
Die zusammengesetzte Trapezregel ist in Scipy als scipy.integrate.trapz(y,
x) implementiert. Man beachte dabei die umgedrehte Reihenfolge der Funktionswerte y
und Knoten x! Die Angabe der Knoten ist dabei optional, alternativ kann bei äquidistanten Daten nur die Schrittweite dx= h spezifiziert werden.
Zusammengesetzte Mittelpunktsregel
Analog zur Trapezregel lässt sich auch die zusammengesetzte Mittelpunktsregel für äquidistante Gitter formulieren:
Z
b
f (x) dx = h
a
N
−1
X
i=0
f (xi ) +
(b − a)3 00
f (ξ)
2
}
| 24N {z
(6.29)
=O(h2 )
wobei h = (b − a)/N , xi = a + h(i + 1/2), i = 0(1)N − 1, und ξ ∈ [a,b]. Die Stützpunkte xi sind also um h/2 gegenüber den Intervallenden versetzt. Abgesehen davon sind
Mittelpunktsregel und Trapezregel offenbar äquivalent, was sich auch in den ähnlichen
Fehlerformeln ausdrückt. Mittelpunkts- oder Trapezregel sollten danach ausgewählt werden, wie sich die vorhandenen Stützstellen in Bezug auf die Randpunkte verhalten. Meist
werden die Intervallenden einbezogen sein; dann setzt man die Trapezregel ein.
Zusammengesetzte Simpsonregel
Sei das Intervall [a,b] in geradzahlig viele Abschnitte unterteilt, also xi = a + hi,
i = 0(1)N , mit h = (b − a)/N und N gerade. Dann kann man je zwei Abschnitte zusammenfassen, und den mittleren Knoten als Intervallmitte des doppelt breiten Abschnitts
90
6.2 Quadratur: numerische Integration
benutzen, und so die Simpsonregel benutzen. Das führt zur Formel
Z

b
f (x) dx =
a
h
f (x0 ) +
3
N/2−2
X
i=1

(b − a)5 (4)
f (ξ)
2f (x2i ) + 4f (x2i+1 ) + f (xN ) −
4
|180N {z
}
=O(h4 )
(6.30)
für ein ξ ∈ [a,b]. Durch die höhere Potenz von N konvergiert dieses Verfahren schneller
als die zusammengesetzte Trapezregel, sofern f vierfach stetig differenzierbar ist.
Die zusammengesetzte Simpsonregel ist nicht identisch zur Integration mit kubischen
Splines, da hier nicht die Gleichheit der Ableitungen an der Stützstellen gefordert wird.
In Scipy ist die Regel als scipy.integrate.simps(y, x) implementiert. Wieder
ist die Reihenfolge der Funktionswerte y und Knoten x vertauscht und die Angabe der
Knoten optional, alternativ kann bei äquidistanten Daten nur die Schrittweite dx= h
spezifiziert werden. Ist die Anzahl der Stützstellen ungerade, so wird an den Rändern
mit der Trapezregel ergänzt.
6.2.3 Beispiel: Besselfunktion
Als Beispiel für die numerische Integration soll uns noch einmal die Besselfunktion erster
Ordnung Jν (x) dienen, also die Lösung der Besselschen Differentialgleichung. Wie man
durch Einsetzen in die Differentialgleichung „leicht“ sieht, ist J0 (x) gegeben durch das
bestimmte Integral
Z
1 π
J0 (x) =
cos(x sin(τ )) dτ,
(6.31)
π 0
das wir numerisch mit Hilfe der zusammengesetzten Trapez- und Simpsonregel berechnen wollen. Wie Abbildung 6.3 links zeigt, gelingt dies mit nur 20 Stützpunkten recht
zufriedenstellend, sechs Stützpunkte allerdings ist für beide Regeln nicht ausreichend.
Zum Vergleich: die numerische Lösung der Differentialgleichung mit dem Verfahren dritter Ordnung benötigt dreihundert Stützpunkte, liefert aber auch eine Abschätzung der
Funktion an jedem Stützpunkt, während das Integral für jeden Punkt neu gelöst werden
muss.
Der Grund, dass sechs Stützstellen nicht ausreichen, ist im Prinzip derselbe, wie wir
ihn schon bei Abbildung 6.1 gesehen haben: mit nur sechs Stützstellen lassen sich bei
höheren x die Schwingungen nicht mehr auflösen, siehe Abbildung 6.3 rechts. Dies lässt
sich auch durch das Verfahren höherer Ordnung nicht korrigieren, sondern nur durch eine
hinreichend kleine Schrittweite. In diesem Fall sollte h 2π/x bzw. N x/2 sein, so
dass
|x (sin(τ + h) − sin(τ ))| ≈ xh |cos(τ )| 2π,
(6.32)
damit der äußere Cosinus ausreichend aufgelöst wird. Für größere x als im Graphen
gezeigt wird also auch N = 20 nicht ausreichend sein.
91
6 Numerisches Differenzieren und Integrieren
1.5
1.0
0.8
1.0
0.6
0.4
0.5
0.2
0.0
0.0
0.2
0.4
0
0.5
2
4
6
8
10 12 14
1.00.0 0.5 1.0 1.5 2.0 2.5 3.0
Abbildung 6.3: Links: numerische Lösungen für das Besselintegral (6.31). Die durchgezogene schwarze Linie markiert die analytische Lösung. Blaue Plus-Symbole und gelbe
Rauten markieren Trapez- bzw. Simpsonregel mit jeweils 20 Stützstellen. Rote Punkte
und grüne Kreuze markieren dieselben Quadraturformeln, aber mit nur 6 Stützstellen.
Rechts: in schwarz ist der Integrand von (6.31) für x = 12 dargestellt. Die schwarzen
Punkte markieren darauf die 6 Stützstellen, durch die das Integral abgeschätzt werden
soll. Rot gepunktet sind die linearen Näherungen, die in der Trapezregel integriert werden,
grün gestrichelt die quadratischen Näherungen der zusammengesetzten Simpsonregel. Es
ist klar, dass diese keine zufriedenstellende Auflösung des Integrals liefern können.
6.2.4 Romberg-Integration
Ist f ∈ C 2k+2 ([a,b]) und

Tf (h) = h 
f (a)
+
2

(b−a)/h−1
X
f (a + ih) +
i=1
f (b) 
+ O(h2 )
2
(6.33)
die (zusammengesetzte) Trapezformel zur Schrittweite h, so gilt die Euler-McLaurinSummenformel
Z b
k
X
h2i αi + O(h2k−2 )
(6.34)
Tf (h) =
f (x) dx +
a
mit
i=1
b2i (2i−1)
f
(b) − f (2i−1) (a) .
(6.35)
(2i)!
b2i bezeichnet dabei die Bernoullizahlen, die αi hängen also nicht von h ab.
In anderen Worten bedeutet das, dass sich der die Trapezregel in einer Umgebung der
0 wie ein Polynom in h2 verhält! Damit können wir – sofern wir die Werte αi bestimmen
αi =
92
6.2 Quadratur: numerische Integration
können – durch Auswerten des Polynoms bei h = 0, also bei unendlich kleiner Schrittweite, das gesuchte Integral bis auf einen Fehler der Ordnung O(h2k−2 ) ausrechnen.
Für b − a-periodische C ∞ -Funktionen sind offenbar alle αi = 0, daher strebt die Trapezformel Tf (h) für diese schneller als jede Potenz von h gegen das gesuchte Integral.
Für nichtperiodische Funktionen kann man im Allgemeinen die αi nicht analytisch
bestimmen, weil das die Kenntnis hoher Ableitungen erfordert. Um das gesuchte Polynom
Tf (h), und damit die αi , trotzdem zu bestimmen, berechnet man zunächst Ti,0 = Tf (hi )
für paarweise verschiedene Schrittweiten h0 > h1 > . . . > hk > 0, und bestimmt dann
Tf (h) als das interpolierende Polynom durch diese Punkte. Dann kann man mit Hilfe
des Neville-Aitken-Schemas das interpolierende (Fehler-)Polynom in h2 an der Stelle 0
auswerten:
Ti+1,j−1 − Ti,j−1
Ti,j = Ti+1,j−1 +
für i = 0(1)k − j, j = 1(1)k.
(6.36)
h2i
−
1
2
h
i+j
Rb
Dann gilt T0,k = Tf (0) + O(h2k+2 ) = a f (x) dx + O(h2k+2 ). Eine solche Extrapolation
von Schrittweiten h > 0 auf die Schrittweite Null heißt auch Richardson-Extrapolation.
Wählt man nun hi = b−a
, so vereinfacht sich (6.36) zu
2i
Tij = Ti+1,j−1 +
4j Ti+1,j−1 − Ti,j−1
Ti+1,j−1 − Ti,j−1
=
,
4j − 1
4j − 1
(6.37)
was als Romberg-Integration bezeichnet wird. Diese Wahl der Schrittweiten hat auch den
Vorteil, dass die Summe für hi bei der Berechnung von hi+1 wiederverwendet werden
kann:
i −1
2X
1
1
Tf (hi+1 ) = Tf (hi ) + hi+1
f a + hi l +
(6.38)
2
2
l=0
Da sich der Aufwand für die Berechnung aller Tf (hi ) mit jeder Stufe verdoppelt, ist der
Gesamtaufwand nicht wesentlich größer als der Aufwand zur Berechnung der niedrigsten
Stufe Tf (hk ) alleine, bei deutlicher Verbesserung der Fehlerabschätzung. Codebeispiel 6.2
am Ende des Kapitels zeigt eine einfache, aber effiziente Implementation des Rombergverfahrens mit Hilfe von SciPy. Alternativ bietet auch SciPy selber eine Implementation
des Verfahrens, scipy.integrate.romberg(f, a, b).
6.2.5 Beispiel: Fehlerintegral
Als Beispiel für die Romberg-Integration ist das Besselintegral aus dem vorherigen Abschnitt wenig geeignet, da die zu integrierende Funktion b − a-periodisch und C ∞ ist.
Dadurch konvergiert bereits die einfache Trapezregel schneller als jedes Polynom, und
bereits mit nicht sehr kleinen Schrittweiten erreicht die Trapezregel Maschinengenauigkeit. Da andererseits die Schrittweite wie beschrieben hinreichend klein sein muss, bleibt
nicht genügend Raum, um durch Extrapolation noch
zu verbessern.
R 1 etwas
√
2
Stattdessen wollen wir hier das Fehlerintegral 0 e−x dx = π erf(1)/2 verwenden
(siehe Abbildung 6.4). Dabei sind die Randwerte bereits der ersten Ableitung stark verschieden, so dass Tf (h) tatsächlich polynomielle Form hat und um die Null herum in
93
∆Tf (h)
6 Numerisches Differenzieren und Integrieren
4.0 1e 3
3.5 10-2
3.0 10-4
2.5
10-6
2.0
10-8 -3
10
10-2 10-1
1.5
1.0
0.5
0.5
1.0
100
h
1.5
2.0
2.5
1e 1
R1
√
2
Abbildung 6.4: Romberg-Integration am Beispiel von 0 e−x dx = π erf(1)/2 =: T0 .
Aufgetragen ist der Fehler ∆Tf (h) = Tf (h) − T0 als Funktion der Schrittweite h (im Einschub in doppelt logarithmischer Skala). Sowohl Kreuze also auch blaue Kreise markieren
Berechnungen mit der Trapezregel. Durch die mit blauen Kreisen markierten Datenpunkte wurde dann das interpolierende Polynom bestimmt und rot gestrichelt eingezeichnet.
Während der beste benutzte Datenpunkt eine Genauigkeit von etwa 6 · 10−5 erreicht, hat
der extrapolierte Wert eine Genauigkeit von 3 · 10−16 .
94
6.2 Quadratur: numerische Integration
# Romberg-Integration
############################################
from scipy import *
from scipy.special import *
from scipy.interpolate import *
import matplotlib.pyplot as pyplot
def romberg(f, a, b, kmax):
"""Romberg-Integration der Funktion f von a bis b.
Die Schrittweiten reichen von (b-a) bis (b-a)*2**-kmax.
"""
# Romberg-Stuetzpunkte erzeugen
############################################
# aktuelle Schrittweite
h = b - a
# aktuelle Naeherung (fuer den Anfang Trapezregel auf 2 Punkten)
tf = h*(0.5*f(a) + 0.5*f(b))
# Stuetzpunkte fuer die Interpolation, verwendete Schrittweiten
# und abgeschaetzte Integrale
h_list = [ h ]
tf_list = [ tf ]
for i in range(0, kmax):
# Schaetzung mit der halben Schrittweite
tf = 0.5*tf + 0.5*h*sum(f(a + (arange(0,2**i) + 0.5)*h))
# Schrittweite nachziehen
h *= 0.5
# und alles speichern
tf_list.append(tf)
h_list.append(h)
tf = array(tf_list)
h = array(h_list)
# Auswerten des interpolierenden Polynoms im Nullpunkt
######################################################
return lagrange(h**2, tf)(0)
print "pi = %.16f" % (4*romberg(lambda x: 1.0/(1.0 + x**2), 0.0, 1.0, 8))
Listing 6.2: Romberg-Integration von 4(1 + x2 )−1 . Das Programm berechnet π auf 16
Stellen genau.
95
6 Numerisches Differenzieren und Integrieren
einer weiten Umgebung nahezu quadratisch ist. Daher kann die Extrapolation den Fehler signifikant senken. Im Beispiel werden Schrittweiten der Trapezregel von 1 bis 1/16
betrachtet. Bei Schrittweite 1/16 beträgt der Fehler der Trapezregel noch etwa 6,0 · 10−5 ,
während das Integral durch die Extrapolation von 5 Datenpunkten das Integral bis auf
3,3 · 10−16 korrekt bestimmt, also Maschinengenauigkeit.
6.2.6 Gauß-Quadratur
Bis jetzt hatten wir uns vor allem mit äquidistanten oder aber ganz freien Gittern beschäftigt. Wenn aber die zu integrierende Funktion analytisch gegeben ist, so können
wir die Stützpunkte frei wählen. Welche Stützpunkte sind dann optimal? Bei der GaußQuadratur suchen wir Stützstellen xi und dazugehörige Gewichte αi , so dass für Polynome f mit möglichst hohem Grad noch
Z 1
n
X
f (x) dx = In f :=
αi f (xi )
(6.39)
−1
i=1
gilt, also dies Polynome exakt integriert werden. Die feste Wahl der Integralgrenzen
a = −1 und b = 1 ist dabei keine Einschränkung, weil jedes endliche Integral auf diesen
Bereich transformiert werden kann:
Z b
Z
(b − a) 1
a+b
0b − a
f (x) dx =
f
+x
dx0 .
(6.40)
2
2
2
a
−1
Welchen Polynomgrad können wir so erreichen? Auf der einen Seite integrieren schon
die Newton-Cotes-Formeln mit n Stützstellen
Q Polynome bis Grad n − 1 exakt. Auf der
anderen Seite ist für das Polynom p(x) = ni=1 (x − xi )2 jede Näherung In p = 0, während
Rb
offenbar a p(x) dx > 0. Daher kann es also kein Verfahren geben, dass alle Polynome bis
Grad 2n exakt integriert. Ein Grad darunter, also 2n − 1 ist allerdings möglich, und wird
durch die Gauß-Quadratur erreicht.
Um ein Polynom 2n − 1 Grades eindeutig zu bestimmen, benötigen wir 2n Stützstellen. Da wir aber nur n Stützstellen benutzen wollen, liegt es nahe, an diesen auch die
Ableitungen einzubeziehen, was ein Spezialfall der Hermite-Interpolation ist. Wie man
leicht sieht, ist
p(x) =
n
X
n
o
L2i (x) f (xi ) 1 − 2L0i (xi )(x − xi ) + f 0 (xi )(x − xi )
(6.41)
i=1
das gesuchte Polynom 2n−1-Grades durch die Stützstellen (xi , f (xi ), f 0 (xi )). Li bezeichnet die Lagrangepolynome aus Gleichung (3.8). Daraus ergibt sich die Hermite-Quadratur
Z
1
Z
1
f (x) dx ≈
−1
p(x) dx =
−1
n
X
αi f (xi ) +
i=1
n
X
βi f 0 (xi )
(6.42)
i=1
mit
Z
1
αi =
−1
96
L2i (x)
1−
2L0i (xi )(x
Z
1
− xi ) dx und βi =
−1
L2i (x)(x − xi ) dx.
(6.43)
6.2 Quadratur: numerische Integration
Ziel ist nun, die Lage der Knoten xi so zu wählen, dass die Ableitungen, die wir ja im
Allgemeinen gar nicht kennen, aus der Näherungen entfallen:
!
0 = βi =
Y
k6=i
1
xi − xk
Z
1
Li (x)ω(x) dx,
(6.44)
−1
Q
mit ωn (x) := ni=1 (x − xi ). Da die Li eine Basis der Polynome vom Grad n − 1 bilden,
R1
bedeutet dies, dass ωn bezüglich des üblichen Skalarprodukts (f, g) = −1 f (x)g(x) dx
senkrecht auf dem Raum der Polynome vom Grad n − 1 stehen muss. Mit βi = 0 vereinfacht sich außerdem
Z 1
Z 1
2
0
αi =
Li (x) dx − 2Li (xi )βi =
L2i (x) dx.
(6.45)
−1
−1
Wir suchen also ein Polynom ωn mit Höchstkoeffizient 1 und Grad n, dass senkrecht
auf alles Polynomen vom Grad n − 1 steht. Die Nullstellen dieses Polynoms sind dann die
gesuchten Stützstellen xi . Die Existenz und Eindeutigkeit von ωn kann man mit Hilfe des
Gram-Schmidt-Orthogonalisierungsverfahrens konstruktiv zeigen, dass wir später genauer kennenlernen werden. Die Idee ist dabei, die Basisvektoren {1, x, x2 , . . .} schrittweise
so zu transformieren, dass sie senkrecht zu einanderstehen.
Dies ergibt, bis auf einen Vorfaktor, die Legendrepolynome, die rekursiv zum Beispiel
so berechnet werden können:
P0 (x) = 1
P1 (x) = x
1
Pn (x) =
(2n − 1)xPn−1 (x) − (n − 1)Pn−2 (x) .
n
(6.46)
Die Nullstellen der ersten dieser Polynome und die zugehörigen Gewichte sind
Grad
Nullstelle
Gewicht
1
x0 = 0
α0 = 2
2
p
x0,1 = ± 1/3
p
x0,2 = ± 3/5
x1 = 0
α0,1 = 1
3
α0,2 = 5/9
α1 = 8/9
In SciPy implementiert scipy.integrate.fixed_quad(f, a, b, n=5) die
Gauß-Quadratur mit den Nullstellen der Legendrepolynome. n gibt dabei die Anzahl
der Stützstellen an, die benutzt werden sollen.
Um andere Gauß-Quadraturen zu entwickeln, kann man gewichtete Skalarprodukte
betrachten. Wir definieren
Z 1
(f,g)w :=
f (x)g(x)w(x) dx
(6.47)
−1
97
6 Numerisches Differenzieren und Integrieren
als das zur Gewichtsfunktion w(x) > 0 gehörige Skalarprodukt. Dies ändert unsere Orthogonalitätsbeziehung (6.44) in
Z
!
1
Li (x)ω(x)w(x) dx.
0 = (Li ,ω)w =
(6.48)
−1
Wenn wir die ursprüngliche Hermite-Interpolation beibehalten wollen, bedeutet dies, dass
wir auch das Zielintegral entsprechend anpassen müssen, also nun
Z
1
Z
1
f (x)w(x) dx ≈
−1
p(x)w(x) dx
−1
n
X
αi f (xi ) +
i=1
berechnen mit
Z
n
X
βi f 0 (xi )
(6.49)
i=1
1
αi =
−1
L2i (x)w(x) dx.
(6.50)
Die Legendrepolynome bzw. deren Nullstellen gehören also zur Gewichtsfunktion
√
w(x) = 1. Die Gewichtsfunktion w(x) = 1/ 1−x2 hingegen liefert als Stützstellen die
Nullstellen der Chebyshev-Polynome Tn (x), vergleiche (3.18). Die Gewichte sind in diesem Fall sehr einfach, nämlich π/n. Um das offene Intervall (−∞,∞) zu betrachten,
2
kann die Gewichtsfunktion e−x benutzt werden, zu der die orthogonalen Polynome die
Hermitepolynome sind.
Als letztes soll noch erwähnt werden, dass die Gauß-Quadratur für alle Gewichtsfunktionen mit steigender Anzahl von Stützstellen gegen das tatsächliche Integral konvergiert,
im Gegensatz zu den Newton-Cotes-Formeln.
6.2.7 Unendliche Integrale und Singularitäten
Alle genannten numerischen Integrationsverfahren lösen Integrale mit Singularitäten nur
schlecht. Unendliche Integrationsgrenzen sind, bis auf die Gauß-Quadratur mit Hermitepolynomen, gar nicht möglich. In ersterem Falle müssen sehr viele Stützpunkte in der
Nähe der Singularität liegen, im zweiten Fall muss das unendliche Integral durch ein
möglichst großes, endliches Intervall approximiert werden. Allerdings ist es oft möglich,
solche Probleme durch Variablensubstitution zu umgehen. So ist zum Beispiel
Z ∞
Z 1 f (x) z= x1
1
f
dx = −
dz.
(6.51)
2
x
z
1
0
Fällt f 0 (x) für große x gegen 0 ab, so dass f gegen eine Konstante strebt, dann ist
die Ableitung von f (1/z) gegen 0 beschränkt, und die Funktion gut integrierbar. Im
Unterschied zum ursprünglichen Integral ist das neue Integral aber eigentlich und damit
mit den genannten Verfahren einfach zu lösen.
Als Beispiel soll die Berechnung von π/2 gemäß der Formel
Z ∞
π
1
=
dx
(6.52)
2
1 + x2
0
98
6.2 Quadratur: numerische Integration
2.0
1.8
1.6
1.4
1.2
200
400
b
600
800 1000
Rb 1
Abbildung 6.5: Romberg-Verfahren für das Integral 0 1+x
2 dx, als Funktion von b. Die
blau gepunktete Linie markiert die Ergebnisse des Verfahrens mit 128 Stützstellen, die
rote durchgezogene Linie mit 32 Stützstellen. Die schwarz gestrichelte Linie markiert π/2,
also den Grenzwert des Integrals gegen unendlich. Eine Kombination von b und Anzahl
Stützstellen zu finden, die diesen Grenzwert gut approximiert, ist also sehr schwierig.
dienen. Mit obiger Transformation folgt
Z
0
∞
1
dx =
1 + x2
Z
0
1
1
dx +
1 + x2
Z
0
1
1
z −2 dz = 2
1 + z −2
Z
0
1
1
dx.
1 + x2
(6.53)
Durch Romberg-Integration auf nur 32 Stützstellen kann der Ausdruck auf der rechten
Seite bis auf 14 Stellen genau ausgewertet werden.
AbbildungR 6.5 zeigt hingegen, was bei 32 bzw. 128 Stützstellen geschieht, wenn man
b 1
stattdessen 0 1+x
2 dx für große b mit Hilfe des Rombergverfahrens bestimmt. Das Ergebnis hängt stark von der Integrationsgrenze b ab, und so ist es praktisch unmöglich,
zu sagen, was der tatsächliche Wert des Integrals für b → ∞ ist. Durch Anpassen der
Anzahl der Stützpunkte an b und damit Konstanthalten der Schrittweite lässt sich zwar
das Integral stabilisieren, trotzdem müsste man mehrere Werte von b mit hohen Anzahlen
an Stützstellen ausprobieren, um eine gute Näherung sicherzustellen. Im Beispiel erreicht
keines der beiden Extrema vorne mehr als 3 Stellen Genauigkeit. Daher sollte man stets
lieber versuchen, das Integral durch Substitutionen auf eine endliche Form zu bringen.
6.2.8 Mehrdimensionale Integration, Monte-Carlo-Integration
Bis jetzt haben wir uns nur mit eindimensionalen Integralen beschäftigt. Im Prinzip ist
es nicht schwer, die obigen Verfahren auch auf höhere Dimensionen zu erweitern, etwa
99
6 Numerisches Differenzieren und Integrieren
die zusammengesetzte Mittelpunktsregel auf zwei Dimensionen:
Z bZ d
N −1 M −1
j
(b − a)(d − c) X X
i
. (6.54)
f (x, y) dx dy ≈
f a + (b − a) , c + (d − c)
NM
N
N
a
c
i=0 j=0
Hatte man allerdings bei einer hinreichend glatten Funktion bereits mit hundert Stützstellen gute Ergebnisse erzielen können, benötigt man nun etwa 1002 = 10,000 Stützstellen. Mit steigender Anzahl der Dimensionen wird dies schnell unmöglich zu handhaben.
Für die sogenannte Zustandssumme eines Vielteilchensystems zum Beispiel, einer zentralen Größe in der statistischen Physik, muss etwa über allen Koordinaten des Phasenraums
integriert werden. Bei nur hundert Teilchen entspräche das bereits 600 Dimensionen (3
Ortskoordinaten plus 3 Geschwindigkeiten pro Teilchen). Sollten in jeder dieser Koordinaten nur 2 Stützpunkte benutzt werden, wären insgesamt trotzdem über 2600 = 4 · 10180
Stützpunkte zu berücksichtigen! Für diesen exponentiellen Anstieg, der bei praktischen
allen hochdimensionalen Problemen auftritt, hat R. Bellman den Begriff „Curse of dimensionality“ geprägt.
Um solche hochdimensionalen Integrale trotzdem annähern zu können, kann man die
Monte-Carlo-Integration einsetzen. Diese benutzt, dass
*
+
Z
N
1 X
f (x) dx/|V |,
(6.55)
f (ξi ) = hf iV =
N
x∈V
i=1
wobei ξi verschiedene Ziehungen einer Zufallsvariablen sind, die gleichverteilt in V ist.
V ist dabei ein endliches Untervolumen des Rn , |V | sein Volumen. Daher lässt sich das
Integral von f als
Z
N
|V | X
f (x) dx ≈
f (ξi )
(6.56)
N
x∈V
i=1
nähern, wobei ξi hinreichend gute (Pseudo-)Zufallsvektoren aus V sein müssen. Wie diese
generiert werden, ist Thema des nächsten Kapitels. Was ist nun der Fehler dieser Näherung? Da die ξi gemäß Konstruktion unabhängig sind, lässt sich der
√ Fehler gut mit Hilfe
der Standardabweichung σ(f ) abschätzen, und beträgt |V |σ(f )/ N . Die Standardabweichung kennen wir im allgemeinen nicht, können sie aber gemäß (4.37) als

!2 
N
N
X
X
1 
σ 2 (x) ≈
f (ξi )2 − N
f (ξi ) 
(6.57)
N −1
i=1
i=1
zusammen mit der Integration abschätzen.
Als SciPy-Code sieht eine Monte-Carlo-Integration noch einfacher als die Trapezregel
aus. Hier ein Code, der zweidimensional über [a,b] × [c,d] integriert:
from numpy.random import uniform
def montecarlo(f, a, b, c, d, N):
volumen = (b-a)*(d-c)
return volumen*sum(f(uniform(a,b,N), uniform(c,d,N)))/N
100
6.2 Quadratur: numerische Integration
Da die Standardabweichung eine Konstante ist, fällt der Fehler der Monte-CarloIntegration im Allgemeinen wie O(N −1/2 ). Im Vergleich dazu fällt der Fehler der Trapezregel im eindimensionalen wie O(N −2 ), sofern f genügend glatt ist. Wenn man bei
der Trapezregel die Anzahl der Stützpunkte verdoppelt, dann muss man bei der MonteCarlo-Integration mehr als eine Größenordnung mehr Punkte aufwenden, um dieselbe
Verbesserung in der Genauigkeit zu erreichen!
Bei mehrdimensionalen Integralen sieht die Situation allerdings anders aus. Bei der
Trapezregel mit insgesamt N Stützstellen entfallen pro Dimension N 1/n viele Stützstellen, wenn diese auf einem Würfel gleichmäßig in allen Dimensionen verteilt werden. Die Genauigkeit ist damit O(N −2/n ). Ab fünf Dimensionen ist damit die MonteCarlo-Integration der Trapezregel überlegen. Ein anderer Fall, in dem die Monte-CarloIntegration der Trapezregel überlegen sein kann, ist wenn die Funktion f nicht genügend
glatt oder nicht einmal stetig ist.
6.2.9 Beispiel: Monte-Carlo-Integration von π
Als Beispiel soll diesmal eine andere Methode zur Bestimmung von π dienen, nämlich
die Integration der charakteristischen Funktion
(
1 falls x2 + y 2 < 1
(6.58)
χD2 (x, y) =
0 sonst
im Bereich [−1,1]2 . Das ergibt dann gerade den Kreisinhalt, also
Z
Z
χD2 (x, y) dx dy = π.
x∈[−1,1]
(6.59)
y∈[−1,1]
Abbildung 6.6 skizziert links die Monte-Carlo-Integration von χD2 , rechts zeigt sie
gemessene Fehler bei Monte-Carlo-Integration und Mittelpunktsregel. Dabei wurde neben χD2 auch χD5 integriert, also das Volumen der fünfdimensionalen Kugel (8π 2 /15).
Der Fehler der Monte-Carlo-Integration ist als mittlerer Fehler von zwanzig Aufrufen
gemessen, wobei durch die große Anzahl von Abtastungen die Schwankungen klein sind.
Für das ursprüngliche, zweidimensionale Problem (blaue Punkte und rote Kreuze)
ist die Trapezregel überlegen, auch wenn sie in zwei Dimensionen nicht die erwartete
Skalierung mit 1/N erreicht. Das ist zu erwarten, da die zu integrierende Funktion ja
nicht stetig ist. Auch der nichtmonotone Abstieg der Fehler ist durch die Unstetigkeit
und die Auflösung des Kreisrands bedingt. Beim fünfdimensionalen Problem aber sieht
es wie angekündigt anders aus, hier ist die Monte-Carlo-Integration besser. Tatsächlich
sind nicht nur die mittleren Abweichungen kleiner als bei der Trapezregel, sondern es
ist sogar sehr unwahrscheinlich, ein ebenso schlechtes Ergebnis zu erzielen. Für solche
Integrale ist also die Monte-Carlo-Methode in jedem Falle vorzuziehen.
6.2.10 Quasi-Monte-Carlo-Integration
Bei der Monte-Carlo-Integration nutzen wir (Pseudo-)Zufallszahlen, um durch zufällige
Abtastung möglichst gut den mittleren Wert der zu integrierenden Funktion zu bestimmen. Wie wir gesehen haben, sind im Mehrdimensionalen Zufallszahlen zu diesem Zweck
101
6 Numerisches Differenzieren und Integrieren
1.0
101
0.5
100
10-1
0.0
10-2
0.5
1.01.0
10-3
0.5
0.0
0.5
-4
1.010 101
102
103
N
104
105
106
Abbildung 6.6: Links: Illustration der Monte-Carlo-Integration. Die Funktion χD2 wird
über 200 zufällige Punkte (rote Kreise und grüne Kreuze) innerhalb [−1,1]2 gemittelt.
An den grünen Kreuzen ist χD2 = 1, für die roten Punkte ist es Null. Rechts: Genauigkeit der Integralnäherungen als Funktion der Anzahl der Stützstellen N . Blaue Punkte
markieren die mittlere Genauigkeit der zweidimensionalen Monte-Carlo-Integration wie
links skizziert, die roten Kreuze die entsprechende Mittelpunktsregel. Gelbe Rauten und
grüne Kreuze zeigen die Genauigkeiten von Monte-Carlo-Integration und Mittelpunktsregel für die 5-Kugel, bei der die Monte-Carlo-Integration schon klar überlegen ist. Die
durchgezogene Linie entspricht einer Skalierung von N −1/2 , wie man sie für die MonteCarlo-Integration erwartet.
besser geeignet als ein regelmäßiges Gitter — das entspräche ja der Trapezregel. Aber
sind Zufallszahlen optimal?
Tatsächlich nicht, denn etwa Abbildung 7.5 links zeigt, dass Zufallszahlen nicht so
homogen verteilt sind, wie man annehmen würde. Dies ist kein Fehler des betrachteten
Zufallszahlengenerators, sondern ein prinzipielles Problem echter Zufallssequenzen, die
sogenannte Diskrepanz. Unsere Erwartung an eine Reihe von N gleichverteilten Zufallszahlen ist, dass jedes Intervall [a,b] ⊆ [0,1] von etwa (b−a)N Zufallszahlen getroffen wird.
Dies ist aber bei echten Zufallszahlen erst bei sehr großen N der Fall. Das bedeutet, dass
es bei der Monte-Carlo-Integration immer Bereiche gibt, die von einer echten Zufallsreihe
über- oder unterrepräsentiert werden. Hat aber einer dieser Bereiche einen großen Anteil
am betrachteten Integral, führt dies zu entsprechenden Fehlern.
Quasizufallszahlen
Anstelle von Zufallszahlen benutzt man daher für die Monte-Carlo-Integration besser
Quasizufallszahlen, die nicht mehr wirklich zufällig sind, sondern eine möglichst geringe
102
6.2 Quadratur: numerische Integration
Diskrepanz bieten. Ziel ist es also, möglichst alle Bereiche mit genau so vielen Zahlen
abzudecken, wie man nach Gleichverteilung erwarten würde. Ein Beispiel ist die HaltonFolge, die eine Reihe mit niedriger Diskrepanz im Wertebereich [0,1] ist.
Um die Halton-Folge zu definieren, wählen wir für jede Dimension eine andere Primzahl p als Basis und schreiben die natürlichen Zahlen in Basis p. Um daraus die gewünschte Zerlegung des Intervalls [0,1] zu erhalten, benutzen wir einfach die Stellen der
p-Darstellung als Nachkommastellen, in umgekehrter Reihenfolge:
n
1
2
3
binär
1
10
11
Stellenumkehr
,1
,01
,11
Ergebnis
1/2
1/4
3/4
n
4
5
6
7
binär
100
101
110
111
Stellenumkehr
,001
,101
,011
,111
Ergebnis
1/8
5/8
3/8
7/8
Stellenumkehr
,21
,02
,12
,22
Ergebnis
7/9
2/9
5/9
8/9
Für p = 3 ergibt sich analog aus der ternären Darstellung
n
1
2
3
4
ternär
1
2
10
11
Stellenumkehr
,1
,2
,01
,11
Ergebnis
1/3
2/3
1/9
4/9
n
5
6
7
8
ternär
12
20
21
22
Die Umkehrung der Stellen hat den Vorteil, dass die pn -tel nacheinander möglichst gleichmäßig das Intervall füllen, was ja gerade einer niedrigen Diskrepanz entspricht. Die sich
ergebende Folge heißt eine van der Corput-Folge.
Die mehrdimensionale Halton-Folge ist dann die Folge, die aus der Verschränkung einer
van Corput-Folge für jede Dimension entsteht. Bei zwei Dimensionen mit Basen 2 und 3
ergibt sich also
(1/2, 1/3) , (1/4, 2/3) , (3/4, 1/9) , (1/8, 4/9) , (5/8, 7/9) , (3/8, 2/9) , (7/8, 5/9) , . . .
(6.60)
Die folgende Routine berechnet die ersten N Glieder der van der Corput-Folge zur
Basis p. Dazu wird solange von den natürlichen Zahlen 1,2, . . . ,N die unterste Stelle
abgezogen und mit der reziproken Potenz auf das Ergebnis addiert, bis alle Stellen von
auch der höchsten Zahl, N , bearbeitet wurden:
from numpy import *
def vanderCorput(N, p):
# zu wandelnde Zahlen
numbers = arange(1,int(N)+1)
# bitumgekehrtes Ergebnis
result = zeros(N)
# Wert der aktuellen, inversen Stelle
frac = 1.0 / p
# solange die groesste Zahl noch Stellen hat
while numbers[-1] > 0:
# unterste Stelle abschneiden
103
6 Numerisches Differenzieren und Integrieren
1.0
100
10-1
0.5
10-2
0.0
10-3
0.5
1.01.0
10-4
0.5
0.0
0.5
-5
1.010 101
102
103
N
104
105
106
Abbildung 6.7: Quasi-Monte-Carlo-Integration von π. Wie in Abbildung 6.6 sind links
die aus der Halton-Folge gezogenen Punkte dargestellt, wobei die ersten zehn Punkte rot
gefärbt sind, die nächsten hundert Punkte blau und die restlichen grün. Auf der rechten
Seite sind die Ergebnisse der Integration zu sehen, wobei blaue Kreise die Monte-CarloIntegration mit Pseudozufallszahlen angeben, grüne Kreuze die Trapezregel und rote
Rauten die Quasi-Monte-Carlo-Integration.
digit = numbers % p
numbers /= p
# ... und zum Ergebnis hinzufuegen
result += frac*digit
frac /= p
return array(result)
Um eine Monte-Carlo-Integration mit Quasizufallszahlen durchzuführen, müssen im
Beispielcode zum Abschnitt 6.2.8 lediglich die Aufrufe von uniform(a,b,N) durch
a + (b-a)*vanderCorput(N, p) ersetzt werden. Üblicherweise wählt man dabei p = 2
für die erste Dimension, p = 3 für die zweite, und so weiter.
6.2.11 Beispiel: Quasi-Monte-Carlo-Integration von π
Abbildung 6.7 zeigt nochmals die Integration von π mit Hilfe der Monte-CarloIntegration, allerdings diesmal nicht mit Pseudozufallszahlen, sondern der Halton-Folge,
also Quasizufallszahlen. Wie man gut sieht, sind die Quasizufallszahlen scheinbar zufällig, aber sehr viel homogener als echte oder Pseudozufallszahlen über das Quadrat
verteilt, insbesondere auch schon bei niedrigen Anzahlen von Punkten. Die Integration
mit Quasizufallszahlen wird kurz als Quasi-Monte-Carlo-Integration bezeichnet, und ist
104
6.2 Quadratur: numerische Integration
für die unstetige Indikatorfunktion nicht nur der Monte-Carlo-Integration mit Zufallszahlen überlegen, sondern auch der Trapezregel.
105
7 Zufallszahlen
Im letzten Kapitel wurden für die Monte-Carlo-Integration Zufallszahlen benötigt. In
diesem Kapitel wird besprochen, wie diese auf dem Computer generiert werden, welche
Arten es gibt, und wie die Qualität einer Zufallsreihe bestimmt werden kann. Außerdem
lernen wir weitere Anwendungen von Zufallszahlen kennen.
Zunächst aber klären wir, was Zufallszahlen im strengen Sinn sind. Wir betrachten ein
Experiment, dass wiederholt voneinander unabhängige Ergebnisse x ∈ M liefert. Dann
heißt ein Ergebnis einer solchen Messung eine Zufallszahl. Aufgrund der Konstruktion
ist für jede Zufallszahl x der Erwartungswert gleich und unabhängig von allen anderen
Messungen. Betrachtet wir eine unendliche Menge von Zufallszahlen, so sind die Zufallszahlen in dieser Menge stets gleich verteilt, und zwar mit einer Verteilung P (x), die durch
die Art des Experiments bestimmt ist.
Ein solches Experiment wäre zum Beispiel der Wurf eines Würfels, der Ergebnisse aus
M = {1, . . . ,6} liefert. Ist dieser Würfel ideal, so gilt P (x) = 1/6 für alle x ∈ M . Eine
konkrete Folge von Zufallszahlen wäre dann zum Beispiel
633142563552446623663665614512446522561664446144244634522555
523121622535453613443366636251342661262345213346341313326554
221663665263462152654312621424115144626242451444653655341323 . . .
und mit wachsender Folgenlänge würde der Anteil an Einsen, Zweien und so weiter gegen
jeweils 1/6 der Gesamtmenge konvergieren.
Um echte Zufallszahlen bereitzustellen, müsste der Computer vergleichbar ein (miniaturisiertes) Experiment mit bekannter, stochastischer Verteilung der Messergebnisse
durchführen. Wie Linux zeigt, ist so etwas durchaus möglich, indem viele verschiedene
Hardwaredaten kombiniert werden, wie etwa Bits aus dem Netzwerkverkehr oder der
Mausposition. Diese Daten werden noch so transformiert, dass sie gleichverteilte Bytes
ergeben, die unter /dev/random ausgelesen werden können. Wenn nichts weiter angegeben ist, wird auf dem Computer übrigens üblicherweise von einer Gleichverteilung der
Zufallszahlen ausgegangen, also P (x) = 1/|M |.
7.1 Pseudozufallszahlen
Für physikalische Anwendungen benutzt man allerdings keine echten Zufallszahlen, sondern sogenannte Pseudozufallszahlen. Dies sind deterministische Zahlenfolgen, die aber
„hinreichend“ zufällig aussehen; wir werden später sehen, was genau das heißt. Pseudozufallszahlen haben zwei Vorteile. Zum einen lassen sich solche Zahlen erheblich schneller
berechnen als etwa die echten Zufallszahlen des Linux-Kernels (um gut einen Faktor 80
107
7 Zufallszahlen
auf modernen Prozessoren), zum zweiten macht dies Computerexperimente exakt reproduzierbar. Beobachtet man also bei einem Durchlauf ein ungewöhnliches Verhalten, das
man genauer analysieren möchte, kann man das Experiment exakt wiederholen und dabei
zum Beispiel zusätzliche Messungen vornehmen.
Wie werden solche Pseudozufallszahlen generiert? Für diese Aufgabe gibt es verschiedene Algorithmen, sogenannte Zufallszahlengeneratoren (engl. random number generator
oder RNG). Diese liefern bei jedem Aufruf eine Zufallszahl, meist eine gleichverteilte
Ganzzahl. Die Bandbreite reicht vom sehr guten, aber aufwändigen Mersenne-Twister
bis zu den einfachen linearen Kongruenzgeneratoren, die wir nun kennenlernen werden.
Das Hauptmaß für die Güte eines solchen Zufallszahlengenerators ist seine Periode.
Denn da jeder Zufallsgenerator einen internen Zustand hat, der durch N viele Bits dargestellt wird, muss sich nach höchstens 2N Aufrufen der interne Zustand wiederholen.
Da es sich aber um einen deterministischen Algorithmus handelt, wiederholt sich die
folgende Reihe ab dann exakt. Daher sind alle Generatoren periodisch. Durch geeignete
Wahl des Algorithmus ist die Periode meist nahe dem theoretischen Maximum, also etwa
232 ≈ 4 Milliarden bei 32 Bit.
Das hört sich recht viel an, aber bei einer typischen Molekulardynamiksimulation werden pro Zeitschritt und Teilchen 3 Zufallszahlen benötigt. Bei zehntausend Teilchen werden damit pro Schritt 30,000 Zufallszahlen gezogen, und der Generator wiederholt sich
nach weniger als 200,000 Zeitschritten. Da sich die Teilchenpositionen in dieser Zeit
wahrscheinlich schon stark geändert haben, spielt dies in in der Praxis keine Rolle. Bei
Isingmodellen, bei denen zufällig Spins auf einem Gitter invertiert werden, betrachtet
man allerdings nicht selten Gitter von einigen Millionen Spins. In diesem Fall sind bessere Generatoren wesentlich. Der Mersenne-Twister-Generator hat zum Beispiel einen
internen Zustand von 2,5 Kilobyte und eine Periode von ≈ 106000 , was für die meisten
Anwendungen ausreichend sein dürfte.
In Python stellt das Modul random verschiedene effiziente und hochwertige Methoden
zur Zufallszahlenberechnung bereit. Die Methode random.randint(a,b) etwa liefert
eine gleichverteilte Zufallszahl aus dem Intervall [a,b]; anders als bei range etwa ist also
auch die obere Grenze einbegriffen. random.unifom(a,b) liefert analog eine gleichverteilte Fließkommazahl im Intervall [a,b]. random.gauss(mu, sigma) schließlich
liefert eine normalverteilte Fließkommazahl mit Erwartungswert mu und Standardabweichung sigma.
NumPy hat ein eigenes random-Modul, das zusätzlich Vektoren von Zufallszahlen
generieren kann, indem einfach neben den Parametern eine weitere ganze Zahl, die gewünschte Anzahl N von Zufallszahlen, angeben wird, also zum Beispiel numpy.random
.normal(mu, sigma, N). Achtung: anders beim random-Modul von Python ist bei
numpy.random.randint(a, b, N) b nicht eingeschlossen!
7.1.1 Linearer Kongruenzgenerator
Der (lineare) Kongruenzgenerator (LCG) ist der einfachste Typ eines Zufallszahlengenerators. Der interne Zustand ist dabei lediglich eine ganze Zahl xi von 0 bis m − 1, die
108
7.1 Pseudozufallszahlen
gemäß
xi+1 = (axi + b) mod m
(7.1)
in den neuen inneren Zustand xi+1 transformiert wird. Die eigentliche Zufallszahl sind
einige (oder alle) der Bits des Zustands xi . m, a und b sowie die Menge der für die
Zufallszahl benutzten Bits sind die Konstanten, die den Algorithmus festlegen, x0 der
Startwert oder Seed. Die Konstanten m, a und b sollten keinesfalls einfach zufällig gewählt
werden, da Knuth gezeigt hat, dass nur unter gewissen Bedingungen die Periode eines
solchen Generators tatsächlich m ist [Knu81]. Bei zufälliger Wahl der Konstanten wird
die Periode meist sehr viel kürzer sein.
Der Zufallsgenerator rand48 der POSIX-C-Bibliothek ist ein Beispiel eines LCGs. Er
benutzt einen Modul von m = 248 , a = 25,214,903,917 und b = 11. Als Zufallszahlen
werden dann die obersten 31 Bits von xi benutzt, also die Bits 17 bis 47. Ältere Versionen
der Standard-C-Bibliothek benutzten für die Funktion rand m = 232 , a = 1,103,515,245
und b = 12,345, wovon die unteren 31 Bit als Zufallszahl genutzt werden.
Die Wahl von m = 248 bzw. m = 232 hat den einfachen Grund, dass sich sehr einfach
modulo m = 2b rechnen lässt – man berücksichtigt einfach nur die ersten b − 1 Bits und
ignoriert alle höheren. Denn
!
∞
∞
b−1
X
X
X
b
i
i
b
b
bi 2 mod 2 =
bi 2 mod 2 mod2 =
bi 2i .
(7.2)
|
{z
}
i=0
i=0
i=0
=0 für i≥b
Daher kann der klassische rand in C etwa wie folgt implementiert werden:
unsigned int state = 1;
void rand_seed(unsigned int seed)
{
state = seed;
}
unsigned int rand()
{
const unsigned int a = 1103515245, b = 12345;
state = a * state + b;
return state & ((1u<<31) - 1);
}
Die Funktion rand_seed dient zum Setzen des internen Zustands, also x0 , rand liefert
dann bei jedem Aufruf eine neue Zufallszahl.
Dass die Modulo-Operation für eine Zweierpotenz als Modul ein einfaches Abschneiden
der hohen Bits ist, hat allerdings auch einen gewissen Nachteil. Die ersten k Bits der
Zufallszahl bleiben beim Abschneiden aller Bits k + 1, . . . übrig. Das bedeutet, dass
diese anscheinend von einem Generator mit kürzerer Periode 2k+1 generiert werden.
Insbesondere wechselt das unterste Bit mit jedem Schritt seinen Wert oder ist konstant.
Dies ist der Grund, warum rand48 die untersten 17 Bit verwirft.
109
7 Zufallszahlen
Dieses Problem lässt sich umgehen, indem der Modul als Primzahl gewählt wird. In
diesem Fall kann b = 0 gewählt werden, so dass
xi+1 = axi = ai x0 mod m,
(7.3)
wobei offenbar x0 6= 0 sein muss. Wenn a als eine primitive Einheitswurzel des endlichen
Körpers Fm gewählt wird, dann durchläuft diese Reihe einmal alle Elemente außer der
Null. Daher hat ein solcher Generator eine Periode von m − 1.
m wird meist als Mersennesche Primzahl, also von der Form m = 2b − 1, gewählt,
wobei b etwa so groß wie die Bitlänge des internen Zustands ist. Dadurch ist die Periode
des Generators nahezu maximal. Die Implementation ist allerdings etwas schwieriger,
weil jetzt die oberen Bits nicht einfach abgeschnitten werden können. Nach Park und
Miller ist ein Beispiel eines solchen Generators m = 231 − 1 und a = 16807, der auch als
MINSTD bezeichnet wird und wie folgt implementiert werden kann:
int state = 1;
void minstd_seed(unsigned int seed)
{
state = seed;
}
unsigned int minstd()
{
const int m = (1u << 31) - 1, a = 16807;
state = ((long int)state)*a % m;
return state;
}
Die Typumwandlung in long int stellt dabei sicher, dass das Produkt der beiden 32Bit-Zahlen in 64-Bit-Arithmetik gerechnet wird, so dass keine Stellen verloren gehen.
7.1.2 Verzögerter Fibonaccigenerator
Um eine längere Periode zu erzielen, könnte man im Prinzip zu immer größeren Moduln
m übergehen. Allerdings wird es immer schwieriger, entsprechende Konstanten zu bestimmen, und auch das Rechnung mit Zahlen großer Bitlänge ist aufwändiger. Eine einfache
Alternative sind verzögerte Fibonaccigeneratoren, die ähnlich wie ein LCG funktionieren,
aber mehrere vorherige Werte benutzen:
xn = (xn−a + xn−b ) mod m,
(7.4)
wobei diesmal m beliebig ist und im Allgemeinen einfach als die Bittiefe des Rechners
gewählt wird. Anstelle der Addition kann auch die bitweise Addition modulo 2 benutzt
werden. Diese Exklusiv-Oder-Operation war früher schneller als eine Addition und wurde
daher gern benutzt, bringt sonst allerdings eher Nachteile. Der interne Status des Zufallszahlengenerators besteht in diesem Fall aus max(a,b) vielen xi , die meist in einem
110
7.1 Pseudozufallszahlen
p + 10 − 7 mod 10 = 4
p=1
x30
x21
x22
x23
x24
x25
x26
x27
x28
x29
x24
x25
x26
x27
x28
x29
xn = xn−10 + xn−7
x30
x31
x22
x23
p0 = 2
Abbildung 7.1: Illustration eines Ringspeichers für b = 10 Werte. p gibt die aktuelle
Position des ältesten Elements im Ringspeicher an, im Beispiel steht an Stelle p = 1 der
Wert x21 . Das neueste Element ist x30 , daher wollen wir x31 = x21 + x24 berechnen.
x21 befindet sich gerade an der Stelle p, x24 dementsprechend 10 − 7 = 3 Positionen
weiter rechts, wobei Positionen jenseits des rechten Randes links wieder hereinlaufen. Im
nächsten Schritt ist dann p = 2, und das zweite Element an der Stelle 4. Die Folgenwerte
sind also wie auf einem Ring gespeichert.
Ringspeicher gespeichert werden. Um diesen zu Anfang zu füllen, benutzt man üblicherweise einen LCG, der nur einen Startwert braucht.
Im Fall a = b = 1 spricht man von einem Fibonaccigenerator, a und b sind ansonsten
die Verzögerungen. Der Name stammt von den Fibonaccizahlen, die ja der analogen
Rekursion xn = xn−1 + xn−2 genügen. Der Fibonaccigenerator selber, also a = b = 1, ist
nicht sehr geeignet, gerade für den in der Physik häufigen Fall von Dreierblöcken zeigt
er unerwünschte Korrelationen.
Anders sieht es bei den verzögerten Fibonaccigeneratoren aus. Sofern
xa + xb + 1
(7.5)
ein primitives Polynom modulo zwei ist, also nicht faktorisierbar, hat der verzögerte
Fibonaccigenerator eine Periodenlänge von mindestens 2a − 1. Um einen 32-Bit-LCG
an Periodenlänge zu übertreffen, sind also wenigstens 32 Registerplätze im Ringspeicher
nötig. Stoll und Kirkpatrick geben als Parameter a = 250, b = 103 an, eine andere
mögliche Kombination ist a = 521, b = 168.
In Code sieht ein einfacher verzögerter Fibonaccigenerator so aus:
/* Position des am weitesten verzoegerten Beitrags x_{n-250}
Dieser wird im Ringspeicher durch den neuen Wert ersetzt,
da nicht mehr gebraucht */
int position = 0;
// Der Ringspeicher
unsigned int state[250];
void r250_seed(unsigned int seed) {
// etwa minstd zur Initialisierung
minstd_seed(seed);
111
7 Zufallszahlen
for (int i = 0; i < 250; ++i)
state[i] = minstd();
position = 0;
}
unsigned int r250() {
const unsigned int m = (1u << 31) - 1;
unsigned int newval =
(state[position] + state[(position + 250 - 103) % 250]) % m;
state[position] = newval;
// Ringspeicher weiterschieben
position = (position + 1) % 250;
return newval;
}
Abbildung 7.1 illustriert dabei die Funktion und Indizierung des Ringspeichers.
7.2 Andere Verteilungen
Die bisher besprochenen Zufallszahlengeneratoren liefern stets ganze Zahlen in einem
gewissen Intervall, rand48 zum Beispiel im Intervall [0,231 − 1], MINSTD im Intervall
[1,231 − 1]. Um daraus gleichverteilte Ganzzahlverteilungen in beliebigen Intervallen zu
erzeugen, kann man die Zufallszahl einfach skalieren. Ist also ξ eine Zufallszahl, die gleichverteilt aus [a,b] gezogen wird, so ist
ξ0 =
ξ−a
b−a
(7.6)
gleichverteilt in [0,1] und umgekehrt
ξ 00 = a0 +
(b0 − a0 )(ξ − a)
b−a
(7.7)
gleichverteilt in [a0 ,b0 ]. Dabei muß bei Ganzzahlarithmetik zuerst multipliziert und dann
dividiert werden, da ξ 0 ≤ 1. Zusätzlich ist b meist knapp an der Bitlänge der Architektur,
daher muss das Produkt mit doppelter Bitzahl berechnet werden. Da die Prozessoren, die
zum wissenschaftlichen Rechen benutzt werden, meist auch sehr schnell Fließkommazahlen verarbeiten, kann alternativ auch ξ 0 in in Fließkommadarstellung berechnet werden
und daraus ξ 00 . Soll ξ 00 ganzzahlig sein, kann es dabei einfach gerundet werden. Diesen Weg
benutzt zum Beispiel Python. Auf diese Weise können natürlich auch (pseudo-)zufällige
gleichverteilte Fließkommazahlen erzeugt werden, insbesondere Standardzufallszahlen, also Fließkommazahlen im Bereich [0,1].
Wie aber können nun etwa normalverteilte Zufallszahlen erzeugt werden? Hierfür lernen wir nun mehrere Verfahren kennen, die Standardzufallszahlen in im Prinzip beliebige
andere Verteilungen umwandeln.
112
7.2 Andere Verteilungen
7.2.1 Verwerfungsmethode
Angenommen, wir wollen Zufallsvektoren gleichverteilt aus einer Kreisscheibe vom Radius 1 ziehen, d. h. , wir wollen Zufallsvektoren p = (x,y) ziehen, die gemäß der Dichte
(
1/π für x2 + y 2 ≤ 1
ρ(x, y) =
(7.8)
0
sonst
verteilt sind. Abbildung 6.6 links zeigt, wie man dies bewerkstelligen könnte: man zieht
zunächst zwei unabhängig gleichverteilte Zufallszahlen auf [−1,1] und interpretiert diese
als Koordinaten p = (x, y). Liegt p in der Kreisscheibe, akzeptieren wir dies als unseren Zufallsvektor, ansonsten versuchen wir es einfach erneut. Da die Wahrscheinlichkeit,
gezogen zu werden, für alle Kreisscheibenpunkte gleich ist, sind die zurückgelieferten p
gleichverteilt. Als Code sieht dies so aus:
from numpy.random import uniform
def kreisscheibe():
while True:
x = uniform(-1, 1)
y = uniform(-1, 1)
if x**2 + y**2 <= 1:
return (x, y)
Da wir im Mittel nur 1 − π/4 der gezogenen Punkte benutzen, brauchen wir 4/(4−π) mal
mehr Zufallszahlen, als wir als Koordinaten der Punkte zurückliefern. Im Falle des Kreises
ist der Verlust nicht sehr hoch, aber ist die zulässige Struktur kleiner, können sehr viele
Zufallszahlen zurückgewiesen werden, und die Verwerfungsmethode wird ineffizient.
Im Falle der Kreisscheibe war die Dichte ρ(x, y) der gesuchten Verteilung sehr einfach, nämlich entweder 0 oder 1/π. Die Verwerfungsmethode lässt sich aber auch bei
komplizierteren ρ anwenden. Wir betrachten nun eine Dichte ρ : Rn → [0,1], so dass ρ
außerhalb [0,1]n Null ist. Dann müssen die Punkte p mit relativen Wahrscheinlichkeiten
ρ(p) gezogen werden. Das lässt sich einfach bewerkstelligen, indem wir zunächst einen
Punkt p durch Ziehen von n Standardzufallsvariablen gleichverteilt in [0,1]n bestimmen.
Wir ziehen nun eine weitere Standardzufallszahl u und akzeptieren p nur dann, wenn
u ≤ ρ(p). Die Wahrscheinlichkeit, p tatsächlich zu ziehen, ist dann
P (u ≤ ρ(p)) = ρ(p).
(7.9)
Die korrekte Wahrscheinlichkeit für einen Punkt p im Würfel ist die infinitesimale
Dichte ρ(p) dxn . Da der Normierungsfaktor dxn für alle p gleich ist, können wir diesen
vernachlässigen, da die relativen Wahrscheinlichkeiten auf [0,1]n trotzdem korrekt sind.
Das bedeutet auch, dass die Eingabe-„Dichte“ ρ(p) gar nicht normiert sein muss — die
Verwerfungsmethode liefert stets Ergebnisse, die gemäß der normierten Dichte
Z
ρ̃(p) := ρ(p)/
ρ(q) dq n
(7.10)
[0,1]n
113
7 Zufallszahlen
1.0
3.0
0.8
2.5
2.0
ρ(x)
0.6
0.4
1.0
0.2
0.00.0
1.5
0.5
0.2
0.4
0.6
0.8
1.0
0.00.0
0.2
0.4
x
0.6
0.8
1.0
Abbildung 7.2: Verwerfungsmethode zur unnormierten Verteilung ρ(x) = x2 für 0 ≤
x ≤ 1. Links sind einige gezogene Punkte eingezeichnet, von denen die grünen Sterne
akzeptiert wurden, die roten Kreise abgelehnt. Der schwarze Strich stellt ρ(x) dar. Rechts
sind die beobachteten Häufigkeiten der Punkte als Balken dargestellt. Diese stimmen gut
mit der normierten Dichte 3x2 überein, die rot gestrichelt eingezeichnet ist. Hier werden
im Schnitt etwa drei Zufallszahlen pro Aufruf der Verwerfungsmethode benötigt.
verteilt sind. Damit können auch Dichten behandelt werden, die nicht in [0,1] liegen, so
lange sie beschränkt sind, denn man kann in diesem Fall
ρ0 (p) =
ρ(p) + minp∈[0,1]n ρ(p)
∈ [0,1]
maxp∈[0,1]n ρ(p) − minp∈[0,1]n ρ(p)
(7.11)
betrachten. Die Normierungseigenschaft ist auch sehr günstig, wenn die Normierungskonstante nicht einfach bestimmt werden kann, etwa bei sehr hochdimensionalen Räumen.
Dies ist die Grundlage des Metropolissampling, dass eine zentrale Rolle in der numerischen statistischen Physik spielt. Abbildung 7.2 illustriert die Verwerfungsmethode und
ihre Normierungseigenschaft.
Im Falle der Kreisscheibe hatten wir übrigens auch von der Normierungseigenschaft
Gebrauch gemacht, denn eigentlich ist ρ(p) Null außerhalb der Kreisscheibe und 1/π innerhalb. Da wir aber die Punkte innerhalb automatisch akzeptiert haben, haben wir formal
ein ρ0 betrachtet mit ρ0 (p) = 1 auf der Kreisscheibe. Dank der Normierungseigenschaft
haben wir damit trotzdem die korrekte Verteilung erzeugt.
Als Python-Code sieht die allgemeinere Verwerfungsmethode nicht wesentlich schwieriger aus:
from numpy.random import uniform
114
7.2 Andere Verteilungen
def verwerfungsmethode(rho, n):
while True:
p = uniform(0, 1, n)
u = uniform(0, 1)
if u < rho(p):
return p
rho muss dabei eine Pythonfunktion sein, die als einziges Argument ein n-dimensionales
Numpy-Array akzeptiert.
Die Verwerfungsmethode kann so erweitert werden, dass die benutzten Zufallszahlen
nicht gleichverteilt sind, sondern etwa normalverteilt. Das erlaubt, die Verwerfungsmethode auch bei über dem gesamten Rn nichtverschwindenden Dichten zu benutzen. Siehe
hierzu zum Beispiel Knuth [Knu81]. Wie man solche normalverteilten Zufallszahlen erzeugt, lernen wir nun kennen.
7.2.2 Inversionsmethode
Wegen der Beschränkung auf einen Würfel können wir die Verwerfungsmethode nicht
benutzen, um zum Beispiel normalverteilte Zufallszahlen aus gleichverteilten zu generieren. Wir benötigen also noch eine andere Methode, um auch unbeschränkte Verteilungen
erzeugen zu können. Hier bietet sich die Inversionsmethode an.
Sei ρ : R → R eine normierte Wahrscheinlichkeitsdichte, zu der wir passend Zufallszahlen ziehen wollen. Dann definieren wir die Verteilungsfunktion zu ρ als
Z x
Fρ (x) := P (uρ ≤ x) =
ρ(x0 ) dx0 ,
(7.12)
−∞
wobei uρ eine ρ-verteilte Zufallszahl ist. Fρ (x) gibt also die Wahrscheinlichkeit an, einen
Wert kleiner als x zu beobachten, und bildet daher die reelle Achse monoton wachsend
in das Intervall [0,1] ab. Das p-Quantil ist nun die Umkehrung Fρ−1 (p), also diejenige
Grenze x, bei der ein gezogener Wert mit Wahrscheinlichkeit p kleiner als x ist. Es gilt
also
Fρ Fρ−1 (p) = p.
(7.13)
Fρ−1 (u) ist eine ρ-verteilte Zufallsvariable, wenn u eine Standardzufallszahl ist, also
gleichverteilt auf [0,1]. Denn
P (Fρ−1 (u) ≤ x) = P (u ≤ Fρ (x)) = Fρ (x).
(7.14)
Sofern also die Quantilfunktion einfach zu invertieren ist, lassen sich so sehr bequem
Zufallszahlen erzeugen, indem Fρ−1 auf Standardzufallszahlen angewendet wird.
Box-Muller-Verfahren
Mit Hilfe der Inversionsmethode können wir nun auch normalverteilte Zufallszahlen erzeugen. Allerdings nicht auf direktem Wege, da das Integral der Gaußfunktion, die Fehlerfunktion, nicht einfach analytisch zu invertieren ist. Box und Muller gehen daher ähnlich
115
7 Zufallszahlen
1.0
3
0.8
2
1
y
u0
0.6
0.4
1
0.2
2
0.2
0.4
u
0.6
0.8
33
1.0
6
1.0
5
0.8
4
0.6
P(z)
φ
0.00.0
0
3
2
1
2
1
0
1
2
3
0
1
2
3
x
0.4
1
0.2
00.0 0.5 1.0 1.5 2.0 2.5 3.0 3.5 4.0
0.0 3
r
2
z
Abbildung 7.3: Illustration des Box-Muller-Verfahrens zur Erzeugung von normalverteilten Zufallszahlen. Die Punkte werden zunächst gleichverteilt auf [0,1]2 erzeugt (links
oben), dann gemäß (7.17) auf das Gebiet [0,∞) × [0,2π] transformiert (links unten),
und schließlich in kartesische Koordinaten (rechts oben). Die Punkte sind in allen drei
Graphen stets gleich gefärbt, und zwar mit wechselnder Farbe im Winkel und sinkender
Intensität nach außen. Rechts unten sind die gemessenen Verteilungen von x und y sowie
die erwartete Gaußverteilung gezeigt.
116
7.2 Andere Verteilungen
2
wie bei der Bestimmung des uneigentlichen Integrals von e−x vor und weichen auf zwei
Dimensionen aus.
1 − 12 (x2 +y 2 )
. In
Wir betrachten also einen Zufallsvektor (x, y) mit Dichte ρ(x, y) = 2π
e
Polarkoordinaten (φ,r) transformiert diese Dichte zu
ρ(φ, r) =
1 − 1 r2
e 2 r.
2π
(7.15)
Wir benötigen also einen gleichverteilten Zufallswinkel φ ∈ [0,2π], sowie einen Abstand
1 2
r ∈ [0,∞) mit Dichte ρr (r) = e− 2 r r. Die zugehörige Verteilungsfunktion ist
Z r
1 2
r2
e− 2 s s ds = 1 − e− /2 ,
(7.16)
Fρr (r) =
0
dessen Umkehrung, also das p-Quantil,
Fρ−1
(p) =
r
p
−2 log(1 − p).
(7.17)
Da, falls mit p auch p − 1 gleichverteilt auf [0,1] ist, ergibt sich durch Rücktransformation
in kartesische Koordinaten das Box-Muller-Verfahren als
p
(7.18)
z = −2 log(u) cos(2πu0 )
p
z 0 = −2 log(u) sin(2πu0 )
(7.19)
mit zwei Standardzufallszahlen u, u0 . Diese werden in zwei unabhängige, normalverteilte
Zufallszahlen z und z 0 transformiert. Anders als bei der Verwerfungsmethode erhält man
also genauso viele normalverteilte Zufallszahlen wie gleichverteilte verbraucht werden,
allerdings müssen diese immer paarweise erzeugt werden. Abbildung 7.3 illustriert die
Anwendung der Inversionsmethode zur Erzeugung normalverteilter Zufallszahlen.
7.2.3 Zufällige Punkte auf Kugel und Kugeloberfläche
Wie wir bereits gesehen haben, lassen sich mit Hilfe der Verwerfungsmethode gleichverteilt Positionen in der Kreisscheibe ziehen, und analog natürlich auch Positionen aus
jeder Kugel im Rn . Allerdings nimmt die Akzeptanzrate mit steigendem n rasch ab, da
die n-Kugel nur noch einen kleinen Teil von [−1,1]n belegt. Bis etwa n = 4 ist die Verwerfungsmethode allerdings sehr effizient, was für die meisten physikalischen Anwendungen
reicht.
Sollen Punkte auf der Kugeloberfläche gezogen werden, so können diese im Prinzip
aus über der Kugel gleichverteilten Punkten p gewonnen werden, indem diese auf die
Oberfläche projiziert werden, also p/ kpk betrachtet. Allerdings benötigt man auf diese
Weise n Zufallszahlen, um einen Zufallsvektor auf der nur n−1-dimensionalen Oberfläche
zu generieren, zusätzlich zu den Verlusten durch die Verwerfungsmethode. Daher ist es
im Einzelfall besser, eine geschickte Parametrisierung der Oberfläche zu nutzen.
Für die Oberfläche der zweidimensionalen Kugel, also den Kreis, ist dies sehr einfach,
da dieser über einen Winkel φ ∈ [0,2π] gleichmäßig parametrisiert wird. Wird also eine
117
7 Zufallszahlen
Standardzufallszahl u gezogen, so sind die Punkte
x = r sin(2πu)
y = r cos(2πu)
(7.20)
gleichverteilt auf einem Kreis vom Radius r um Null.
Für die Oberfläche der dreidimensionalen Kugel, also die 2-Sphäre, ist nicht etwa die
gebräuchliche Parametrisierung über zwei Winkel am besten, sondern die Parametrisierung in Zylinderkoordinaten φ und z. Der Winkel φ ist offenbar gleichverteilt und kann
als 2πu bestimmt werden, wobei u eine Standardzufallsvariable ist. z ist erstaunlicherweise ebenso gleichverteilt, da ρ(z) proportional zum Flächeninhalt des jeweiligen Rings
ist, dividiert durch den gesamten Flächeninhalt, also
s
2
p
p
1
1
d
2
2
2
2
ρ(z) =
2π r − z 1 +
=
r −z
(7.21)
2
4πr
dx
2r
für −r ≤ z ≤ r.
Um eine gleichverteilte Position auf der Kugeloberfläche zu ziehen, genügt es daher,
zwei Standardzufallszahlen u und u0 zu berechnen, und diese gemäß
z = r(2u0 − 1)
p
y = r2 − z 2 cos(2πu)
p
x = r2 − z 2 sin(2πu)
(7.22)
zu transformieren.
7.3 Qualitätsanalyse
Um die Qualität eines Zufallszahlengenerators zu testen, gibt es eine Vielzahl von Standardtests. Der Grund dafür ist, dass es leider keinen einzelnen Test gibt, der sicherstellt,
dass es keinerlei Korrelationen in der generierten Folge gibt. Ein solcher Test müsste jede
mögliche Teilmenge bilden und mit allen Zahlen korrelieren, was praktisch nicht möglich
ist. Daher sollte ein guter Zufallszahlengenerator möglichst viele der folgenden Tests erfüllen, auch wenn dies keine Garantie ist, dass er im Einzelfall nicht doch zu kritischen
Korrelationen führt, die im schlimmsten Fall das Ergebnis beeinflussen.
Für eine bestimmte Anwendung genügt es natürlich, wenn er nur die Tests erfüllt, deren
getestete Korrelationen Einfluss auf das System haben. Zum Beispiel werden bei einer
Molekulardynamiksimulation in drei Dimensionen Paarkorrelationen unwichtig sein, aber
Tripletkorrelationen problematisch. Bei einem zweidimensionalen Isingmodell hingegen
wird es genau umgekehrt sein. In jedem Fall aber sollte die Periode des Generators wie
besprochen groß genug sein.
Für die im Folgenden beschriebenen Tests nehmen wir an, dass der zu testende Zufallszahlengenerator Standardzufallszahlen liefert, also gleichverteilt im Intervall [0,1]. Solche
Zufallszahlen werden wie beschrieben standardmäßig auf dem Computer erzeugt und im
Bedarfsfall auf andere Verteilungen transformiert.
118
7.3 Qualitätsanalyse
14
14
12
12
10
10
8
8
6
6
4
4
2
2
0 0.40 0.45 0.50 0.55 0.60 0.65
0.35
0 0.40 0.45 0.50 0.55 0.60 0.65
0.35
P
Abbildung 7.4: Verteilung von x = 100
i=1 xi , ermittelt aus 20,000×100 Werten der Zufallsgeneratoren rand (links) und minstd (rechts). Rot gestrichelt ist jeweils die erwartete
√
Normalverteilung mit Varianz 1/ 1200 eingezeichnet.
Statistiktests
Sind die erzeugten Zufallszahlen xi tatsächlich gleichverteilt auf [0,1], so gilt für den
Mittelwertschätzer
*
+
N
1 X
1
hxi =
xi = hxi =
(7.23)
N
2
i=1
und für dessen Varianz nach (4.33)
1
1
.
σ(x) = √ σ(x) = √
N
12N
(7.24)
Für immer größere N sollte daher x gegen 1/2 konvergieren.
Wird x sehr oft für disjunkte Zufallszahlenmengen {xi , i = 1(1)N } gemessen, so sollte
x außerdem für große N gemäß dem Gesetz der großen Zahlen praktisch normalverteilt
sein, mit der oben angegebenen Varianz. Dies kann mit Hilfe von (4.37) überprüft werden,
man kann aber auch direkt das Histogramm der Verteilung von x darauf überprüfen, dass
es wie erwartet normalverteilt ist. Abbildung 7.4 zeigt die Verteilung von x am Beispiel
von MINSTD und rand, sowie die erwartete Normalverteilung. Diese Art von Test wird
auch als χ2 -Test bezeichnet.
Poincaré-Schnitte
Lineare Kongruenzgeneratoren haben nach einem Satz von Marsaglia die Eigenschaft,
dass im Rn n aufeinanderfolgende Zufallszahlen, als Vektor aufgefasst, auf Hyperebenen
119
7 Zufallszahlen
1.0
1.0
0.8
0.8
0.6
0.6
0.4
0.4
0.2
0.2
0.00.0
0.2
0.4
0.6
0.8
1.0
0.00.0
0.8
0.6
0.4
0.2
0.8
0.6
0.4
0.6 0.8 0.2
0.4 0.6 0.8 1.0
0.20.4
0.2
Abbildung 7.5: Quadrat- und Würfeltest mit 2,000 Auswertung am Beispiel des berüchtigten RANDU-Zufallszahlengenerators. Der zweidimensionale Poincaré-Schnitt ist homogen und unauffällig, aber in drei Dimensionen fallen die nur sehr wenigen Hyperebenen
des Generators deutlich auf.
liegen. Problematisch wird dies, wenn die Anzahl der Hyperebenen sehr klein ist. Für
n = 2 und 3 kann man das sehr bequem überprüfen, indem man den Poincaré-Schnitt
(xk , xk+1 ), k = 0,1, . . . bzw. sein dreidimensionales Äquivalent (xk , xk+1 , xk+2 ), k =
0,1, . . . betrachtet. Da alle Punkte in [0,1]2 bzw [0,1]3 liegen, heißen dieses Tests auch
Quadrat- oder Würfeltests. Diese Punktwolken sollten das Quadrat bzw. den Würfel
homogen füllen und keine Strukturen aufweisen. In zwei Dimensionen können wir das
sehr rasch erfassen, in drei Dimensionen muss man die Punktewolke rotieren, um nach
Hyperebenen zu suchen.
Abbildung 7.5 demonstriert dies für den berüchtigten RANDU-LCG (m = 231 , a =
65,539, b = 0). Dieser ist wegen des 231 -Moduls sehr schnell auf 32-Bit-Rechnern zu
implementieren und war daher früher sogar auf einigen Großrechnern zu finden. In der
zweidimensionalen Darstellung sind keine Auffälligkeiten zu sehen, aber ausgerechnet in
den physikalisch wichtigen drei Dimensionen zeigt sich, dass es lediglich eine Handvoll
verschiedener Hyperebenen gibt, so dass mit diesem Generator erzeugte 3d-Vektoren
kaum als zufällig gelten können.
Fouriertest
Wird eine lange Reihe von Standardzufallszahlen diskret Fourier-transformiert, so sollte
die 0-te Mode eine Amplitude von N/2 aufweisen, da diese ja die Summe der Zufallszahlen
angibt. Alle anderen Moden sollten vernachlässigbar kleine, gleichmäßige Amplituden
haben, entsprechend einem weißen Rauschen. Die Amplituden aller Frequenzen ungleich
120
7.4 Beispiel: Random walk
100
0.08
10-1
0.06
10-2
0.04
10-3
0.02
10-4
10-5
0.00
0
5
10
15
20
25
30
0
5
10
15
20
25
30
Abbildung 7.6: Spektraltest (links) und Autokorrelationsfunktion (rechts) für die Zufallszahlengeneratoren rand und MINSTD. rand ist als blaue Fläche bzw. gepunktet eingezeichnet, MINSTD rot gestrichelt. Im linken Graph sind die DFT-Amplituden normiert
dargestellt, also dividiert durch die Anzahl der Zufallszahlen, so dass die 0-te Mode 1/2
beträgt.
0 sollte außerdem mit der Länge der transformierten Zufallszahlenreihe sinken. Dieser
Test wird auch als Spektraltest bezeichnet. Abbildung 7.6 zeigt die DFT am Beispiel von
rand und MINSTD.
Autokorrelationstest
Neben der diskreten Fouriertransformierten kann man auch die Autokorrelationsfunktion
der Zufallsreihe u bestimmen, also
C(u,u)(k) =
1
iDFT DFT(u)(n) DFT(u)(n) (k).
N
(7.25)
Für eine Zufallsreihe sind alle paarweise verschiedenen Werte unkorreliert, also muss
C(u,u)(k) = σ 2 (u)δk =
1
δk
12
(7.26)
gelten. Dies ist in Abbildung 7.6 rechts demonstriert.
7.4 Beispiel: Random walk
Als Beispiel für die Anwendung von Zufallszahlen in der physikalischen Simulation soll
der Randomwalk („Irrfahrt“) dienen, der in vielen Problemen der statistischen Physik
121
7 Zufallszahlen
20
<xt2 >
15
10
xt
5
0
P(xt )
5
10
150
100
80
60
40
20
00
20 40 60 80 100
0.18
t
0.16
0.14
0.12
0.10
0.08
0.06
0.04
0.02
0.00 20 15 10 5 0 5 10 15 20
20
40
t
60
80
100
xt
Abbildung 7.7: Links: 3 mögliche Random walks gemäß (7.27), als Funktion der Zeit t.
Rechts oben ist das mittlere Verschiebungsquadrat als Funktion der Zeit gezeigt, gemittelt
über 1000 Random walks. Die gestrichelte Linie markiert dabei das analytisch erwartete
Ergebnis x2T = T . Rechts unten die Verteilungen der Positionen zu den Zeitpunkten
t = 5 (rote, gefüllte Balken) und t = 80 (blaue, offene Balken). Gestrichelt sind wieder
die jeweils erwarteten Normalverteilungen eingezeichnet.
eine Rolle spielt. Das klassische Beispiel ist die Brownsche Bewegung von Partikeln in
Wasser oder anderen Flüssigkeiten. Diese wird durch die unzähligen Stöße der Lösungsmittelmoleküle auf das betrachtete Teilchen erklärt.
Hat das betrachtete Teilchen einen Durchmesser von nur 1µm, so befinden sich an
seiner Oberfläche zu jedem Zeitpunkt ca. eine halbe Milliarde Lösungsmittelmoleküle.
Deren Bewegung explizit simulieren zu wollen, ist aussichtslos. Auf der anderen Seite
passieren selbst in kurzer Zeit genügend Zusammenstöße, so dass die zeitdiskretisierte
Kraft auf das Teilchen gut als zufällig und, wegen des Gesetzes der großen Zahlen, als
normalverteilt angenommen werden kann. Der Mittelwert ist dabei offenbar Null, da
die Zufallsstöße keine Vorzugsrichtung haben sollten, die Varianz werden wir mit der
Diffusionskonstanten in Verbindung bringen.
Um diesen Prozess zu simulieren, können wir uns zunächst auf ein eindimensionales
Modell beschränken, da die Stöße in den einzelnen Koordinaten unabhängig sind. Indem
wir das Gesetz der großen Zahl andersherum anwenden, können wir außerdem eine beliebige, aber symmetrische Verteilung der Stöße annehmen. Die einfachste Möglichkeit ist,
einfach mit gleicher Wahrscheinlichkeit dieselbe Distanz vor- oder zurückzugehen.
Wir betrachten also ein Teilchen mit Position xt zum Zeitpunkt t = 1, 2, . . ., so dass
(
−1 mit Wahrscheinlichkeit 1/2
xt+1 = xt +
(7.27)
+1 mit Wahrscheinlichkeit 1/2.
122
7.4 Beispiel: Random walk
Ein Random walk ist eine Folge xt , die durch eine solche einfache stochastische Bewegungsgleichung beschrieben wird. Abbildung 7.7 zeigt links drei mögliche solche Random
walks. Sie wurden durch eine Routine ähnlich der folgenden generiert:
def rw(N):
x = 0
xt = [ x ]
for move in randint(0,2,N):
if
move == 0: x += -1
elif move == 1: x += 1
xt.append(x)
return xt
Dieses Modell ist so einfach, dass wir seine statistischen Eigenschaften fast vollständig
analytisch berechnen können. So ist zum Beispiel
* t
+
X
hxt i =
(7.28)
us = 0,
s=1
wobei us = xs − xs−1 den s-ten Schritt des Random walks bezeichnet, und daher hus i =
0 gilt. Die mittlere Position des Random walks bleibt also stets am Ausgangspunkt.
Allerdings wird die Verteilung der Punkte xt mit t immer breiter, denn für das mittlere
Verschiebungsquadrat gilt
* t
+
t
X
X
2
us ur =
u2s = tσ 2 (us ) = t.
(7.29)
xt =
s,r=1
s=1
Für hinreichend große t kennen wir damit auch die Wahrscheinlichkeitsdichte der Positionen, die gemäß dem Gesetz der großen Zahlen praktisch Gaußsch ist:
1
x2
ρ(x, t) = ρ(xt ) ≈ √
exp − t2 .
(7.30)
2σ
2πσ 2
Die Varianz ist dabei σ 2 = σ 2 (xt ) = x2t , also das mittlere Verschiebungsquadrat.
Abbildung 7.7 zeigt rechts oben das mittlere Verschiebungsquadrat σ 2 (xt ), gemittelt
über 1,000 Random walks. σ 2 (xt ) ist tatsächlich mit guter Genauigkeit ungefähr t, wobei
die Abweichung für große t größer sind, da dort die Verteilung von xt breiter ist, und
damit auch der Fehlerbalken der Varianz. Rechts unten werden für t = 5 und t = 80 die
Verteilungen der Positionen gezeigt. Selbst für t = 5 werden diese gut durch die Gaußglocke beschreiben. Trotzdem sollte man sich erinnern, dass die Verteilung nicht wirklich
Gaußsch ist, da offenbar |xt | ≤ t gilt. Denn der maximale Abstand ist erreicht, wenn
wir t-mal nur nach links oder rechts gehen. Während also die Gaußverteilung prinzipiell beliebig hohe Werte mit sehr kleiner Wahrscheinlichkeit zulässt, ist die tatsächliche
Verteilung beschränkt.
Das Modell lässt sich leicht auf mehrere Dimensionen erweitern, denn die Zufallsbewegungen in den einzelnen Koordinaten sind ja unabhängig. Die mittlere Position des
123
7 Zufallszahlen
Abbildung 7.8: Kontinuierlicher Random walk als einfaches Polymermodell mit n = 100
Monomeren. Das Polymer wurde mit der Simulationssoftware ESPResSo [Esp] erzeugt
und dem Visualisierungstool VMD [Vmd] gezeichnet.
Random walks in n Dimensionen ist damit immer noch konstant gleich der Ausgangsposition, das mittlere Verschiebungsquadrat die Summe der Verschiebungsquadrate der
Koordinaten, also x2t = ntσ 2 (u), wobei σ 2 (u) das Verschiebungsquadrat der einzelnen
Dimensionen bezeichnet.
Diffusion
Was ist nun die Bedeutung der Konstanten σ 2 (u) = σ 2 (xt )/t? Wir verallgemeinern den
Random walk, der bisher in Zeit um ∆t = 1 und Raum um ±∆x = ±1 gesprungen ist,
auf beliebige Werte ∆x und ∆t. Dann gilt offenbar σ 2 (u) = ∆x2 /∆t. Wir betrachten
nun die Master-Gleichung der diskreten Wahrscheinlichkeitspopulationen
1
1
∆p(x, t + ∆t) = p(x, t + ∆t) − p(x, t) = p(x − ∆x, t) + p(x + ∆x, t) − p(x, t). (7.31)
2
2
Die erste Term der rechten Seite besagt, dass das Teilchen beim Sprung t → t + ∆ mit
Wahrscheinlichkeit 12 an der Stelle x landet, wenn es sich zum Zeitpunkt t an der Stelle
x − ∆x befand. Der darauffolgende Term bedeutet dasselbe für x + ∆, und der letzte
Term, dass das Teilchen nicht an der aktuellen Stelle bleiben kann.
Wir multiplizieren nun linker Hand mit ∆t−1 und rechter Hand mit ∆x−2 :
∆p(x, t + ∆t)
σ 2 (u)
=
(p(x − ∆x, t) + p(x + ∆x, t) − 2p(x, t)) .
∆t
2∆x2
(7.32)
Lassen wir nun ∆t → 0 und ∆x → 0 gehen, wird aus dieser Gleichung die Differentialgleichung
δ
δ2
p(x, t) = D 2 p(x, t)
(7.33)
δt
δx
mit D = σ 2 (u)/2. Dies ist nichts anderes als die Diffusionsgleichung mit Diffusionskonstante D. Die Varianz σ 2 (u) unseres Zufallsschritts ist also genau die doppelte Diffusionskonstante unserer makroskopischen Teilchen, und durch geeignete Wahl von σ 2 (u)
können wir die Diffusionskonstante unserer Random walk-Teilchen einstellen.
124
7.4 Beispiel: Random walk
Random walks als Polymermodell
Man kann für den mehrdimensionalen Random walk leicht zeigen, dass es keinen wesentlichen Unterschied macht, wenn die nächsten Positionen nicht diskret ±1 in allen
Dimensionen gewählt werden, sondern zum Beispiel kontinuierlich oder auf einer Sphäre,
d.h.,
xt+1 = xt + u mit kuk = 1, u gleichverteilt.
(7.34)
Ein solcher kontinuierlicher Random walk kann mit Hilfe von (7.22) leicht numerisch
erzeugt werden, ein Beispiel ist in Abbildung 7.8 gezeigt.
Die letztere Wahl ist ein einfaches Modell für Polymere unter bestimmten Voraussetzungen (in einem sogenannten θ-Lösungsmittel). In diesem Fall ist t allerdings keine
Zeitachse, sondern zählt einfach die Monomere entlang der Polymerkette durch.
In guten Lösungsmitteln streckt sich das Polymer etwas mehr. Auch dies lässt sich
durch einen Random walk modellieren, bei dem die Monomere eine endliche Ausdehnung
haben und nicht überlappen können. Ein solcher Random walk heißt auch Self avoiding
walk, weil er sich selbst nicht kreuzen kann. In unserem einfachen Random walk-Modell
(7.27) entspricht das der Bedingung xt 6= xs für alle s 6= t und ist auf dem Computer
relativ einfach zu erstellen.
Um einen Self avoiding walk zu generieren, erzeugt man einfach einen Random walk,
und überprüft mit jedem neuen Punkt, ob dieser einem anderen Monomer näher kommt
als die Größe der Monomere zulässt. In diesem Fall muss man allerdings ganz von vorne
beginnen, da sonst extrem ungünstige Konfigurationen bevorzugt werden. Bei diesen würde ja quasi beliebig lange probiert, den nächsten Punkt zu setzen, selbst wenn es nur eine
verschwindend geringe Wahrscheinlichkeit gibt, diesen Punkt zufällig zu treffen. Daher
werden taschenartige Konfigurationen sehr viel wahrscheinlicher, als sie zufällig auftreten
würden. Ab etwa 100 Monomeren ist die Wahrscheinlichkeit, einen Random walk abzulehnen, schon sehr hoch, und die Erzeugung eines Self avoiding walks dementsprechend
aufwändig.
Auch von der Theorie her ist der Self avoiding walk sehr viel komplizierter. So gilt
etwa x2N ∼ N 2ν mit ν ≈ 0.588, so dass das Polymer im Mittel tatsächlich etwas mehr
gestreckt ist als der Random walk mit ν = 1/2. Der Wert von ν für den Self avoiding
walk kann, anders als beim Random walk, nicht analytisch berechnet werden, sondern
nur aufwändig numerisch genähert.
Der Self avoiding walk wie auch der der einfache Random walk spielen nach wie vor
eine wichtige Rolle in der Polymerphysik, insbesondere beim Aufsetzen von Polymersimulationen. Daher besitzt etwa Simulationssoftware ESPResSo [Esp] einen eigenen
Befehl, um solche Zufallsketten zu erzeugen.
Diffusionslimitierte Aggregation
Eine weitere Anwendung des Random walks ist die diffusionslimitierte Aggregation, die
etwa die Bildung von Rußaggregaten modelliert. Dabei wird davon ausgegangen, dass
sich diese aus einem Keim durch Anlagerung von weiteren Teilchen bilden, die aus dem
Unendlichen heran diffundieren.
125
7 Zufallszahlen
80
160
70
140
60
120
50
100
40
80
30
60
30 40 50 60 70 80
60 80 100 120 140 160
Abbildung 7.9: Cluster aus diffusionslimitierter Aggregation mit N = 500 (links) und
N = 2000 (rechts) Teilchen. Die Teilchen sind in der Reihenfolge der Anlagerung farblich
codiert.
Für die Modellierung werden Random walks genutzt, die zufällig auf einer Kugelsphäre
um den Keim gestartet werden, bis sie entweder am Cluster anlagern oder sich zu weit
vom Kreis entfernt haben. Abbildung 7.9 zeigt zwei solche DLA-Cluster mit 500 und 2000
Teilchen auf einem zweidimensionalen Gitter. Die beiden Cluster haben eine sehr ähnliche
Struktur, auch wenn die Maßstäbe deutlich anders sind. Das hängt damit zusammen, dass
solche diffusionslimitierte Aggregate selbstähnliche Fraktale sind. Quelltext 7.1 zeigt den
Python-Code zur Erzeugung solcher zweidimensionaler DLAs.
Die zentrale Frage beim Studium von DLA-Clustern ist die nach ihrer fraktalen Dimension. In drei Dimensionen legen wir zu ihrer Bestimmung konzentrische Kugeln mit
Radius R um den Keim eines sehr großen Clusters, und zählen die Anzahl der Teilchen
N (R) in dieser Kugel. Die fraktale Dimension ist dann
d = lim
R→∞
log N (R)
.
log R
(7.35)
In der Praxis betrachtet man natürlich einfach mehrere große Cluster verschiedener
Größe, um d abzuschätzen. Wäre der Cluster solide mit Teilchendichte ρ, so wäre
3
N (R) = ρ 4π
3 R und
3
log ρ 4π
log ρ 4π
log N (R)
3 R
3
=
=3+
,
(7.36)
log R
log R
log R
die fraktale Dimension also wie erwartet 3. Der DLA-Cluster in drei Dimensionen hat
übrigens eine fraktale Dimension von ≈ 1,6, ist also bei weitem kein solides Objekt. Daher
126
7.4 Beispiel: Random walk
werden solche Cluster gerne als Katalysatoren verwendet, da sie eine entsprechend große
Oberfläche haben.
Listing 7.1: Code zur Erzeugung eines DLA-Clusters auf einem zweidimensionalen Gitter
world. Die Eingabeparameter sind die Größe M des Gitters, sowie die Anzahl der Punkte
des zu erzeugenden Aggregats N. Das Aggregat entsteht durch sukzessive Anlagerung
mit Hilfe von Random walks, die auf einem langsam wachsenden Kreis um das aktuelle
Aggregat starten. Der Radius R diese Kreises ist stets um 5 Gittereinheiten größer als
der Umkreis des Clusters.
# Diffusionslimitierte Aggregation (DLA) in 2D
##############################################
from scipy import *
from numpy.random import *
import matplotlib.pyplot as pyplot
seed(123)
#
M
#
N
Laenge einer Gitterseite
= 201
Anzahl der anzulagernden Teilchen
= 1500
# Zentrum, wo der Keim sitzt
ctr = (M+1)/2
# 2D-Simulationsgitter, 1 bedeutet besetzt
world = zeros((M,M))
# Der Keim ist schon da
world[ctr,ctr] = 1
# Anlagerung
##########################################
# angelagerte Punkte fuer die Ausgabe
pt_history = []
# Startradius, waechst mit der Zeit
R = 5
def center_dist(x, y):
return sqrt((x - ctr)**2 + (y - ctr)**2)
for n in range(N):
print "Anfuegen von Teilchen", n
attached = False
while not attached:
# Startpunkt auf Kreis um das Zentrum
phi = uniform(0, 2*pi)
x = int(round(ctr + R*cos(phi)))
y = int(round(ctr + R*sin(phi) + 0.5))
running = True
while running:
xalt, yalt = x, y
move = randint(0,4)
if
move == 0: x += -1
elif move == 1: x += 1
elif move == 2: y += -1
elif move == 3: y += 1
127
7 Zufallszahlen
if center_dist(x, y) >= 2*R or \
x < 0 or x >= M or y < 0 or y >= M:
# zu weit draussen, abbrechen und neu starten
running = False
elif world[x, y] == 1:
# Angelagert!
world[xalt, yalt] = 1
# Angelargertes Teilchen merken
pt_history.append((xalt, yalt))
# Radius anpassen
R = max(R, center_dist(xalt, yalt) + 5)
if R >= 0.4*M:
raise Exception("Radius bzw. N zu gross!")
running = False
attached = True
# Ausgabe
##########################################
# Liste von Paaren in Paar von Listen verwandeln
xx, yy = zip(*pt_history)
pyplot.hsv()
pyplot.scatter(xx, yy, c=range(len(xx)))
pyplot.axis((ctr-R,ctr+R,ctr-R,ctr+R))
pyplot.show()
7.5 Beispiel: Perkolation
Ein anderes Beispiel eines Zufallsalgorithmus ist die Perkolation, also die Frage, wann ein
Zufallsmedium einen durchgehenden Kanal zulässt oder nicht. Anwendungsbeispiele sind
etwa poröse Medien, die Flüssigkeiten nur passieren lassen, falls es einen durchgehenden
Hohlraum gibt, oder eine Mischung von Isolator und Leiter, die nur leitet, wenn es eine
leitende Verbindung gibt.
Modellieren lässt sich dies als ein Gitter, dessen Zellen mit einer gewissen Wahrscheinlichkeit p besetzt sind. Die Frage ist dann, ab welcher kritischen Wahrscheinlichkeit pc
es im Regelfall einen Cluster von benachbarten, besetzten Feldern gibt, der das gesamte
System in einer Richtung durchzieht, man sagt, perkoliert. Diese Grenze lässt sich durch
Untersuchen sehr vieler zufälliger Besetzungen untersuchen.
Die Besetzungen sind dabei natürlich durch stochastisches Belegen des Gitters sehr
einfach zu erzeugen, algorithmisch etwas schwieriger ist nur, zu bestimmen, ob es einen
perkolierenden Cluster gibt, also einen, der eine Seite mit der gegenüberliegenden verbindet.
Eine Möglichkeit ist, die Struktur von einer Seite aus gewissermaßen zu „fluten“, und
zu sehen, ob man dabei die gegenüberliegende Seite erreicht. Erreichen heißt hier, dass es
einen zusammenhängenden Pfad von paarweise benachbarten, besetzten Punkten gibt.
Um dies zu überprüfen, erzeugen wir zunächst eine Liste der besetzten Punkte am Startrand. Dann fügen wir zu dieser Liste alle benachbarten Punkte hinzu, und wiederholen
dies solange, bis keine neuen Elemente mehr zur Liste hinzugefügt wurden. Die Liste
128
7.5 Beispiel: Perkolation
1.0
40
Perkolationsw-keit
0.8
30
20
10
0
0.6
0.4
0.2
0
10
20
30
40
0.00.5
0.6
p
0.7
Abbildung 7.10: Ein perkolierender Cluster auf einem 502 -Gitter mit p = 0,6. Blaue
Punkte markieren den Cluster, Kreuze andere, mit diesem Cluster nicht verbundene, aber
besetzte Gitterpunkte. Im rechten Graph ist für L = 5 (grüne Sterne), L = 20 (blaue
Rauten) und L = 100 mit welcher Wahrscheinlichkeit bei Besetzung p ein perkolierender
Cluster gefunden wurde. Für L = 100 ist dies ein bereits sehr scharfer 0–1-Übergang in
Nähe von 0,6.
enthält dann alle Punkte, die Verbindung zum Startrand haben. Wir müssen nur noch
überprüfen, ob in dieser Liste Punkte am gegenüberliegenden Rand auftauchen.
In dieser Form wäre der Algorithmus recht langsam, weil man ständig wieder Punkte
hinzufügen würde, die bereits in der Liste sind, und diese erneut untersucht. Um dies zu
vermeiden, führt man einfach eine zweite Liste der Punkte, deren Nachbarn noch nicht
untersucht wurden. Ein Punkt, der noch nicht in der Liste der verbunden Punkte steht,
wird dann nicht nur zu dieser, sondern auch zur Liste der zu bearbeitenden Punkte hinzugefügt. Dann müssen nur die Nachbarn der Punkte in dieser Liste betrachtet werden,
und sobald die Nachbarn eines Punkts einmal untersucht wurden, kann dieser aus der
Liste der zu bearbeitenden Punkte gestrichen werden. Da er aber immer noch als verbunden markiert ist, wird er auch nie ein zweites Mal in die Liste der zu bearbeitenden
Punkte eingefügt werden. Der Algorithmus terminiert also, da die abzuarbeitende Liste
irgendwann leer ist. Ein entsprechendes Python-Skript ist in Listing 7.2 zu sehen.
Abbildung 7.10 zeigt links einen perkolierenden Cluster für ein Gitter mit Besetzungswahrscheinlichkeit p = 0,6, es sind also etwas mehr als die Hälfte der Punkte besetzt.
Rechts ist für verschiedene Besetzungswahrscheinlichkeiten aufgetragen, wie wahrscheinlich es ist, einen perkolierenden Cluster zu beobachten. Wie man sieht, ist p = 0,6 nicht
ohne Grund gewählt, denn dies ist sehr dicht am kritischen Perkolationsschwellwert. Der
tatsächliche Wert des Schwellwerts ist pc ≈ 0,593 im Limit unendlicher Gittergröße, wie
man zeigen kann. Mit steigender Kantenlänge wird der Übergang bereits bei endlichen
129
7 Zufallszahlen
Gittern relativ scharf, bei L = 100 ist der Grenzbereich weniger als 0,06 in p breit. Bei einer Besetzung von 0,56 ist Perkolation äußerst unwahrscheinlich, bei 0,6 gibt es hingegen
schon für die Mehrheit der Gitter einen perkolierenden Cluster.
Ähnlich wie beim Random walk kann auch die Perkolation in unzähligen Variationen
betrachtet werden, etwa andere zugrundeliegende Gitter, höhere Dimensionen oder auch
kontinuierliche Modelle.
130
7.5 Beispiel: Perkolation
Listing 7.2: Code zur Schätzung des Perkolationsschwellwerts auf einem zweidimensionalen quadratischen Gitter world. Die Liste connected enthält die alle Punkte, die mit
dem oberen Rand verbunden sind, die Liste connected_undone diejenigen verbundenen Punkte, deren Nachbarn noch untersucht werden müssen.
# Perkolation
##############################################
from scipy import *
from numpy.random import *
import matplotlib.pyplot as pyplot
seed(123)
# Laenge einer Gitterseite
M = 50
# Wahrscheinlichkeit einer Gitterzelle, besetzt zu sein
p = 0.55
# wie oft wir messen, um die W-keit zu bestimmen
samples = 100
def try_percolation(M, p):
# 2D-Simulationsgitter, 1 bedeutet besetzt
world = zeros((M,M))
# Besetzung
##########################################
# Liste der besetzen Punkte, fuer die Ausgabe
structure = []
for x in range(M):
for y in range(M):
u = uniform(0, 1)
world[x,y] = (u < p)
if world[x,y]:
structure.append((x,y))
# Flutung von oben nach unten
##########################################
# Liste der unbearbeiteten Punkte
connected_undone = []
# ... und der bearbeiteten wie unbearbeiteten
connected = []
# Initialisierung von oben
for x in range(M):
if world[x, M-1]:
connected_undone.append((x, M-1))
connected.append((x, M-1))
# Durchfluten
while connected_undone:
# zu bearbeitendes Element holen und als getan markieren
cx, cy = connected_undone.pop()
for (nx, ny) in (cx - 1, cy), (cx + 1, cy), \
(cx, cy - 1), (cx, cy + 1):
# 1. Index gueltig (wichtig gerade am Anfang!)
# 2. besetzt
# 3. noch nicht gesehen
if nx >= 0 and nx < M and ny >= 0 and ny < M and \
131
world[nx, ny] and \
(nx, ny) not in connected:
connected.append((nx, ny))
connected_undone.append((nx, ny))
# Ausgang unten suchen
percolating = False
for x in range(M):
if (x, 0) in connected:
percolating = True
return percolating, structure, connected
# Ausgabe
##########################################
successful = 0
for cnt in range(samples):
print "Test ", cnt
percolating, structure, connected = try_percolation(M, p)
if percolating:
successful += 1
# Erfolg merken fuer die Ausgabe
succ_structure = structure
succ_connected = connected
print "Perkolations−W−keit", float(successful)/samples
if successful > 0:
# Liste von Paaren in Paar von Listen verwandeln
xs, ys = zip(*succ_structure)
xc, yc = zip(*succ_connected)
pyplot.plot(xs, ys, "k+")
pyplot.plot(xc, yc, "bo")
pyplot.show()
8 Lineare Algebra II
Wie wir bereits an der Besselgleichung gesehen haben, lassen sich gewöhnliche Differentialgleichungen in einer Dimension recht einfach auf lineare Gleichungssysteme abbilden.
Diese haben Bandstruktur und sind effizient zu lösen. In mehr als einer Dimension ist
das allerdings im Allgemeinen nicht mehr der Fall. Betrachten wir zum Beispiel die Poissongleichung in zwei Dimensionen:
∆φ =
∂2φ ∂2φ
+ 2 = ρ.
∂x2
∂y
(8.1)
Wir diskretisieren nun wie gewohnt φ(x,y) in beiden Dimensionen zu φk,l = φ(kh, lh),
k,l = (1)N . Den Laplace-Operator erhalten wir dann in erster Ordnung als
∆φ(kh, lh) ≈
1
1
φk+1,l − 2φk,l + φk−1,l + 2 φk,l+1 − 2φk,l + φk,l−1
2
h
h
1
= 2 φk,l+1 + φk+1,l − 4φk,l + φk−1,l + φk,l−1 .
h
(8.2)
Der Einfachheit halber nehmen wir periodische Randbedingungen an, so dass wir diese
Gleichung für jeden Gitterpunkt aufstellen können. Allerdings wäre die resultierende Matrix singulär; um die Differenzialgleichung mit periodischen Randbedingungen eindeutig
lösen zu können, müssen wir einen Funktionswert vorgeben.
Diese Gleichungen sind im Moment noch auf der Matrix φk,l definiert, die wir nun
linearisieren müssen, um die Gleichung in der gewohnten Matrixform etwa an Python zu
übergeben. Hierzu speichern wir die Elemente von φk,l wie folgt:
Φk+N l = φk,l
für k,l = 1(1)N.
(8.3)
Wie man sich leicht überlegt, ist diese Zuordnung eindeutig, wir können also beliebig
zwischen Φn und φk,l wechseln und so etwa (8.2) auf den Vektor Φn übertragen. Dies
ergibt dann N 2 Gleichungen für alle Datenpunkte, die in Matrixform für N = 5 zum
Beispiel wie folgt aussehen:



 

0
Φ0 = φ(0,0)
Φ0


 5
  Φ1 = φ(h,0)   ρ(h,0) 


 
 


 
 
..
..




 
.
.
 10

 
 

 ·  Φ4 = φ(h,0)  =  ρ(h,0)  .
(8.4)


 
 
 15
  Φ5 = φ(0,h)   ρ(0,h) 


 
 


 
 
.
.
.
.
 20
 
 

.
.


ρ(4h,4h)
Φ24 = φ(4h,4h)
0
5
10
15
20
133
8 Lineare Algebra II
In der Matrix markieren grüne Punkte Einträge mit Wert 1/h2 , schwarze Punkte Einträge
mit Wert −4/h2 und das rote Kreuz den Normierungseintrag mit Wert 1. Alle anderen
Einträge sind Null.
Durch die periodischen Randbedingungen in x und y sind zwei Nebendiagonalen weiter
außen teilweise besetzt. Damit hat die entstehende Matrix zwar immer noch Bandstruktur hat und ist dünn besetzt, d.h. fast alle Einträge Null, allerdings ist sie nicht mehr
tridiagonal. Auch durch Umsortieren lässt sich dies nicht wesentlich ändern, daher muss
die volle Gaußelimination durchgeführt werden. Für Gitter von 5 × 5 Punkten ist das
zwar noch unproblematisch, bei einem Gitter von 100 × 100 Punkten hat die volle Matrix
allerdings bereits 100,000,000 Einträge, und die Gaußelimination wird zu langsam. Noch
schwieriger wird es in den meist benutzten drei Dimensionen, da die volle Matrix schnell
mehrere Milliarden Einträge hat.
Neben der Ineffizienz des Gaußverfahrens bringt das Arbeiten mit der vollen Matrix allerdings auch Speicherprobleme mit sich, denn eine volle Matrix aus dem R100,000×100,000
benötigt bei einfacher Genauigkeit über 37GB Speicher. Dünn besetzte Matrizen dieser Größe sind allerdings durchaus handhabbar, denn nur wenige Matrixelemente sind
überhaupt ungleich Null. Indem man nur diese Elemente geschickt speichert, lassen sich
sogar noch weitaus größere Matrizen bewältigen. Auf derartigen Datenstrukturen kann
die Gaußelimination allerdings nicht effizient eingesetzt werden, da diese die Matrixstruktur durch die Zeilenadditionen rasch zerstört.
Im Folgenden lernen wir nun schnellere, iterative Gleichungslöser kennen, mit denen
auch solche und größere Gleichungssysteme handhabbar werden. Außerdem können diese
Verfahren auch auf große, dünn besetzte Matrizen angewandt werden. Weiter lernen wir
die QR-Zerlegung als weitere Matrixzerlegung kennen, die eine wichtige Rolle bei der
Bestimmung von orthogonalen Basen und der Optimierung spielt. Sie kann auch zur Berechnung von Eigenwerten und -vektoren benutzt werden, was dieses Kapitel abschließt.
8.1 Iterative Gleichungslöser
Wir betrachten eine reguläre Matrix A ∈ Rn,n und einen Vektor b ∈ Rn . Gesucht ist
dann die Lösung x ∈ Rn mit
Ax = b.
(8.5)
Die Gaußelimination liefert diese bei unendlicher Genauigkeit exakt, allerdings mit dem
hohen Aufwand O(n3 ). Wir haben allerdings bereits gesehen, dass iterative Verfahren
wie etwa das Newtonverfahren zur Lösung nichtlinearer Gleichungssysteme quadratisch
konvergieren. Hierzu gibt es mehrere mögliche Ansätze, etwa das CG-Verfahren, das auf
einem Optimierungsproblem beruht und das wir später kennenlernen werden. Zunächst
suchen wir aber iterative Verfahren der Form
x(i+1) = G(x(i) ) = T xi + r
(8.6)
mit r ∈ Rn und T ∈ Rn,n , kT k < 1. Der Banachsche Fixpunktsatz gewährleistet, dass diese sukzessive Substitution für jeden Startwert konvergiert, wobei die Norm k·k wiederum
geeignet gewählt werden kann.
134
8.1 Iterative Gleichungslöser
Wie müssen wir nun T wählen, damit einerseits x(i) → x für i → ∞, andererseits
aber T und r einfach zu berechnen sind? Da kT k < 1 sein soll, muss r bereits eine
Näherungslösung sein. Es sollte also r = B −1 b sein, wobei B eine geeignete, einfach zu
invertierende Näherung von A ist. Dann gilt
!
x = T x + B −1 b = T x + B −1 A x = T + B −1 A x,
(8.7)
was sich offenbar durch Wahl von T = I − B −1 A erfüllen lässt. Solange also B −1 einfach
zu bestimmen ist, lassen sich sowohl T als auch r einfach berechnen.
8.1.1 Jacobiverfahren
Das erste Verfahren nach diesem Schema, dass wir kennenlernen, ist das Jacobiverfahren.
Die Matrix A wird dazu als Summe einer Diagonalmatrix sowie einer linken, unteren
und einer rechten oberen Dreiecksmatrix mit verschwindender Diagonale zerlegt, also
A = L + D + U mit
(
(
(
aik für i < k
aik für i = k
aik für i > k
lik =
, dik =
und uik =
. (8.8)
0
sonst
0
sonst
0
sonst
Die Diagonalmatrix D soll dabei die Rolle der leicht zu invertierenden Matrix übernehmen. Dazu müssen die Diagonalelemente alle von Null verschieden sein, was sich bei
einer regulären Matrix A durch Vertauschen von Zeilen und/oder Spalten immer erreichen lässt.
Setzen wir also T = I − D−1 A und r = D−1 b in (8.6) ein, so erhalten wir das Jacobiverfahren
x(i+1) = I − D−1 A x(i) + D−1 b
= −D−1 (L + U ) x(i) + D−1 b
mit der Diagonalmatrix D, so dass d−1
jj =
1
ajj .
Komponentenweise bedeutet dies, dass

(i+1)
xj
=
1 
bj −
ajj
(8.9)

X
(i)
ajk xk  .
(8.10)
k6=j
Mit anderen Worten, dass Jacobiverfahren löst jede Zeile nach der Variablen auf der
Diagonale auf.
Wann konvergiert dieses Verfahren? Eine gängige Voraussetzung ist, dass die Matrix
A strikt diagonaldominant ist, also
X
|aik | < |aii | für i = 1(1)n.
(8.11)
k6=i
Diese Bedingung ist sehr stark, zum Beispiel erfüllen weder die Matrix aus dem Eingangsbeispiel noch etwa die für die Spline-Interpolation benötigten Matrizen diese Bedingung,
135
8 Lineare Algebra II
da in beiden Fällen das Diagonalelement betragsmäßig die Summe der Nebenelemente
ist. Allerdings sind die bei der sogenannten Finite-Elemente Modellierung zur Diskretisierung von Differentialgleichungen entstehenden Matrizen meist strikt diagonaldominant.
Daher spielen Löser für diese Art von Matrizen auch kommerziell eine wichtige Rolle.
Ist A strikt diagonaldominant, so nutzen wir die Maximumsnorm
n
kAk∞ := max
i=1
n
X
|aik | ,
(8.12)
k=1
die eine Matrixnorm definiert. Dann gilt
kT k∞ = I − D−1 A
n
∞
= max
i=1
X |aik |
k6=i
|aii |
< 1,
(8.13)
die sukzessive Substitution und damit das Jacobiverfahren konvergieren also. Außerdem
ist die Konvergenz linear, genauer gilt
kxn+1 − xk∞ X |aik |
≤
,
(8.14)
kxn − xk∞
|aii |
k6=i
wobei kxk∞ := maxni=1 |xi | die Vektormaximumsnorm bezeichnet. Je größer also die
Diagonaleinträge gegenüber den Nebeneinträgen sind, desto schneller konvergiert das
Verfahren, zum Beispiel wenn die Matrix eine kleine Störung der Einheitsmatrix ist.
Indizierte Matrixspeicherung
Wie man an der komponentenweisen Darstellung (8.10) gut sieht, kann das Jacobiverfahren auch auf dünnbesetzten Matrizen implementiert werden. Zum einen wird die Matrix
A beim Verfahren nicht verändert, sondern nur der erheblich kleinere Lösungsvektor, zum
anderen wird nur zeilenweise summiert, was eine indizierte Speicherung ermöglicht. Dazu
wird für jede Zeile j lediglich der Diagonaleintrag ajj explizit gespeichert, sowie eine Liste
mit Einträgen (k, ajk ), die die restlichen Elemente 6= 0 enthält. Eine Implementation des
P
(i)
Jacobiverfahrens muss dann lediglich für jede Zeile die Summe k6=j ajk xk mit Hilfe
der zur Zeile gehörigen Liste bilden, von bj abziehen und durch ajj teilen.
In unserem einführenden Beispiel wären pro Zeile neben der Diagonalen maximal vier
weitere Einträge nötig, unabhängig davon, wie fein die Schrittweite gewählt wird. Die
Matrix (8.4) würde damit so dargestellt:
1, {} =
b (1, 0, . . . , 0)
4
1
1
1
1
1
4 1
− 2,
3, 2 , 1, 2 , 7, 2 , 22, 2
=
b
,
−
,
,
0,
0,
0,
1,
0,
.
.
.
,
0,
1,
0,
0,
0
h
h
h
h
h
h2
h2 h2
1
1
1
1
4
1
4 1
− 2,
4, 2 , 2, 2 , 8, 2 , 23, 2
=
b 0, 2 , − 2 , 2 , 0, 0, 0, 1, 0, . . . , 0, 1, 0, 0
h
h
h
h
h
h
h h
..
.
(8.15)
ajj , {(k1 , ajk1 ),(k2 , ajk2 ), . . .}
136
(8.16)
8.1 Iterative Gleichungslöser
8.1.2 Gauß-Seidel-Verfahren
(i+1)
Wird (8.10) zeilenweise abgearbeitet, so müssen die bereits berechneten Werte xj
(i)
zwischengespeichert werden, da für die restlichen Zeilen ja noch die alten Werte xk benötigt werden. Beim Gauß-Seidel-Verfahren werden stattdessen die bereits berechneten,
neueren Werte benutzt:


j−1
n
X
X
1 
(i+1)
(i+1)
(i)
xj
=
bj −
ajk xk
−
ajk xk  .
(8.17)
ajj
k=1
k=j+1
Dies erspart einerseits die getrennte Speicherung der neuen Näherungslösung xk , andererseits ist die neue Näherungslösung näher an der Lösung, so dass es durchaus sinnvoll
erscheint, diese neuen, besseren Werte für die verbleibenden Zeilen zu nutzen.
Mit der Zerlegung A = L + D + U wie beim Jacobiverfahren ergibt sich in Matrixschreibweise
x(i+1) = −D−1 Lx(i+1) − D−1 U x(i) + D−1 b =⇒ (D + L)x(i+1) = −U x(i) + b (8.18)
und damit
x(i+1) = −(D + L)−1 U x(i) − (D + L)−1 b.
(8.19)
Das Gauß-Seidel-Verfahren ist also auch vom Typ (8.6), mit der etwas komplexeren
Matrix B = D + L. Tatsächlich ist auch
T = I − (D + L)−1 A = (D + L)−1 (D + L − A) = −(D + L)−1 U.
(8.20)
Man kann zeigen, dass kT k∞ beim Gauß-Seidel-Verfahren kleiner ist als beim JacobiVerfahren. Das bedeutet allerdings im allgemeinen nicht, dass das Gauß-Seidel-Verfahren
schneller ist, trotz dessen, dass teilweise mit prinzipiell besseren Näherungen gerechnet
wird. Man spart allerdings den Speicherplatz, um x(i+1) zwischenzuspeichern.
Genauso wie das Jacobiverfahren kann auch das Gauß-Seidel-Verfahren auf indizierten
Matrixformaten benutzt werden, wobei die beiden Summen in (8.17) entweder gleichzeitig
aufaddiert werden, oder die Listen der Nichtdiagonalelemente in Elemente links und
rechts der Diagonalen aufgeteilt.
Insbesondere für die parallele Verarbeitung, die mit der heutigen weiten Verbreitung
von Mehrkern-Prozessoren ein wichtiger Faktor ist, ist das Gauß-Seidel-Verfahren allerdings ungeeignet, da die Berechnung jeder Zeile die Ergebnisse der vorherigen erfordert.
Das Jacobi-Verfahren kann hingegen auf so viele Prozessoren verteilt werden, wie die
Matrix Zeilen hat, was eine effiziente Verarbeitung selbst auf modernen Grafikkarten
ermöglicht.
8.1.3 Relaxationsverfahren
Beim Relaxationsverfahren (Successive over-relaxation, SOR) wird statt B = D + L die
Matrix B = D/ω + L mit einem Relaxationsfaktor ω betrachtet. Durch geeignete Wahl
von ω können dann auch nicht strikt diagonaldominante Matrizen behandelt werden.
137
Fehler
8 Lineare Algebra II
101
10-1
10-3
10-5
10-7
10-9
10-11
10-13
10-15
10-17 0 5 10 15 20 25 30 35 40
Schritte
101
100
10-1
10-2
0.0
0.5
1.0
1.5
2.0
Abbildung 8.1: Konvergenz von Jacobi-, Gauß-Seidel- und Relaxationsverfahren. Zum
einen wird die Matrix A aus (8.4) betrachtet, die wie gesagt nicht strikt diagonaldominant
ist. Zum anderen wird eine Matrix B mit genausovielen, normalverteilten
Einträgen,
P
betrachtet, die strikt diagonaldominant gemacht wurde, indem bi,i = 1+ k6=i |bik | gesetzt
wurde. Links sind die Fehler kBx − bk2 von Jacobi- und Gauß-Seidel-Verfahren für die
Matrix B mit blauen Punkten bzw. roten Rauten eingezeichnet. Die roten Kreuze zeigen
hingegen den Fehler des Gauß-Seidel-Verfahrens für die Matrix A, das nicht konvergiert.
Grüne Sterne schließlich zeigen den Fehler des SOR-Verfahrens, das mit ω = 1,63 auch
bei Matrix A konvergiert. Der rechte Graph zeigt den Fehler des SOR-Verfahrens in
Abhängigkeit von ω nach 20 Schritten.
Allerdings kann man nur zeigen, dass 0 < ω < 2 gelten muss, aber ein Wert ω, der zu
schneller Konvergenz führt, muss durch Ausprobieren gefunden werden.
In Matrixschreibweise gilt analog zu (8.20)
T = I − ω(D + ωL)−1 A =
(D + ωL)−1 (D + ωL − ωA) = −(D + ωL)−1 [ωU + (ω − 1)D] (8.21)
und damit
x(i+1) = −(D + ωL)−1 [ωU + (ω − 1)D] x(i) + ω(D + ωL)−1 b
(8.22)
beziehungsweise, analog zum Gauß-Seidel-Verfahren,
x(i+1) = −ωD−1 Lx(i+1) − ωD−1 U + (ω − 1)I x(i) + ωD−1 b.
(8.23)
In Komponentenschreibweise schließlich ergibt sich


j−1
n
X
X
ω
(i+1)
(i+1)
(i)
(i)
bj −
xj
=
ajk xk
−
ajk xk  + (1 − ω)xj .
ajj
k=1
138
k=j+1
(8.24)
8.2 QR-Zerlegung und Orthogonalisierung
Das SOR-Verfahren mit ω = 1 entspricht also genau dem Gauß-Seidel-Verfahren. Andere
Werte von ω gewichten zwischen der vorherigen Näherung und der nächsten Gauß-SeidelIterierten. Insofern ist es erstaunlich, dass auch Werte ω > 1 sinnvoll sein können, die
die vorherige Näherung quasi bestrafen.
In Python sieht das SOR-Verfahren in etwa so aus:
import numpy
def sor_step(A, b, omega, x):
n = A.shape[0]
for j in range(n):
s = b[j]
# diese Werte sind schon neu
s -= numpy.dot(A[j,:j], x[:j])
# und diese Werte sind noch alt
s -= numpy.dot(A[j,j+1:], x[j+1:])
# Ueberschreiben von x[j]!
x[j] = omega*s/A[j,j] + (1-omega)*x[j]
Die Routine erwartet als Eingabe eine quadratische n×n-Matrix A und einen n-Vektor b,
den Relaxationsfaktor omega und die aktuelle Näherung x. Diese wird in dieser Routine
wie beschrieben von der neuen Näherung überschrieben, die übergebene Variable x also
geändert.
Abbildung 8.1 zeigt das Fehlerverhalten von Jacobi-, Gauß-Seidel- und SOR-Verfahren
für die nicht strikt diagonaldominante Matrix A aus (8.4) im Eingangsbeispiel und eine
zufällige strikt diagonaldominante Matrix. Wie man sieht, konvergieren sowohl Jacobiwie auch Gauß-Seidel-Verfahren sehr schnell mit exponentieller Rate, sofern die Matrix
strikt diagonaldominant ist. Keines der beiden Verfahren konvergiert aber für die Matrix
A, im Gegensatz zum SOR-Verfahren, dass auch bei dieser Matrix mit exponentieller
Rate konvergiert.
Im rechten Graphen sieht man allerdings auch, dass die Wahl von ω die Konvergenz
stark beeinflusst. Die Matrix A ist ein Beispiel, bei dem ω in jedem Fall größer als 1
gewählt werden muss, um Konvergenz zu erzielen, die optimale Rate erreicht man in
diesem Fall mit ω = 1,63. Dabei ist die Konvergenz sehr sensitiv von ω abhängig –
bereits mit ω = 1,5 oder 1,75 ist der Fehler nach 20 Schritten um eine Größenordnung
schlechter.
8.2 QR-Zerlegung und Orthogonalisierung
Neben der LU-Zerlegung spielt in der Numerik noch eine zweite Zerlegung eine wichtige
Rolle, die QR-Zerlegung. Dabei wird eine Matrix A ∈ Cm,n in eine orthonormale Matrix
Q und eine rechte obere Dreiecksmatrix R zerlegt, so dass A = QR. Orthonormal bedeutet hier, dass die Spaltenvektoren von Q bezüglich des Skalarprodukts (u,v) := uH v
paarweise orthogonal und normiert sind. Das ist äquivalent zu QH Q = I, wobei der obere
Index H jeweils die Hermitesche bezeichnet.
Anders als bei der LU-Zerlegung existiert eine solche Zerlegung immer, ist aber dafür
nicht eindeutig. So gibt es Zerlegungen sowohl mit Q ∈ Cm,n und R ∈ Cn,n , als auch
139
8 Lineare Algebra II
q2
a2
q20
q1
Abbildung 8.2: Gram-Schmidt-Orthogonalisierung. a2 wird in den Vektor q20 transformiert, der zu q1 senkrecht steht, indem die Projektion von q1 auf a2 (blau gepunktet)
von a2 abgezogen wird. q20 wird schließlich noch normiert, um den nächsten Basisvektor
q2 zu erhalten.
mit Q ∈ Cm,m und R ∈ Cm,n . Wir werden Verfahren kennenlernen, die beide Formen
erzeugen. Die erstere Form kann dabei auch so verstanden werden, dass eine orthogonale
Basis gesucht wird, die denselben Raum aufspannt wie die Spaltenvektoren von A.
Ist A quadratisch, und regulär, so ist auch Q quadratisch und QH = Q−1 . Außerdem gilt |det Q| = 1. Eine solche Matrix heißt unitär. Praktisch kann man sich unitäre
Matrizen als Drehungen und Spiegelungen vorstellen. Daher sind alle wesentlichen Eigenschaften der Matrix A in R enthalten. Insbesondere kann die QR-Zerlegung auch benutzt
werden, um bequem Ax = b zu lösen, da ja
!
Ax = QRx = b
=⇒ Rx = QH b,
(8.25)
was durch einfach Rücksubstitution gelöst werden kann. Wir werden später sehen, dass
die QR-Zerlegung auch bei nichtquadratischen Matrizen bei der „Lösung“ von Ax = b
wichtig ist, weil sie bestimmte verwandte Optimierungsaufgaben löst.
8.2.1 Gram-Schmidt-Verfahren
Das Gram-Schmidt-Verfahren ist das älteste Verfahren zur QR-Zerlegung. Auf der anderen Seite ist es das allgemeinste Verfahren und kann in beliebigen Hilberträumen eingesetzt werden. Das Verfahren ist eigentlich nur eine Orthogonalisierung der Spaltenvektoren von A, die als Nebenprodukt eine QR-Zerlegung liefert. Daher ist das Verfahren auch
als Gram-Schmidt-Orthogonalisierung bekannt. Wir werden als Beispiel sehen, dass das
Verfahren etwa auch zur Konstruktion von orthogonalen Polynomen eingesetzt werden
kann.
Seien zunächst m linear unabhängige Vektoren {aj , j = 1(1)m} aus einem beliebigen
Hilbertraum H gegeben. Ziel ist es nun, diese in eine orthonormale Basis {qj , j = 1(1)m}
zu transformieren. Wir beginnen mit a1 , das wir lediglich normieren müssen:
q1 =
140
a1
.
ka1 k
(8.26)
8.2 QR-Zerlegung und Orthogonalisierung
Den nächsten Vektor, a2 , dürfen wir nun nicht einfach normieren und hinzufügen, da er
ja nicht notwendigerweise orthogonal zu q1 ist. Das können wir aber erreichen, indem wir
einfach die Anteile parallel zu q1 abziehen (vergleiche Abbildung 8.2):
q20 = a2 − (a2 , q1 ) q1
q2 =
q20
,
kq20 k
wobei (·,·) das Skalarprodukt des Hilbertraums H bezeichnet. Da a2 und a1 nach Voraussetzung linear unabhängig sein sollen, gilt dies auch für a2 und q1 , so dass q20 6= 0.
Mit den weiteren Vektoren verfahren wir genauso, ziehen also zunächst die Anteile der
bereits berechneten Basisvektoren ab und normieren den Rest:
qk0 = ak −
k−1
X
(ak , qi ) qi
(8.27)
i=1
qk =
qk0
.
qk0
(8.28)
Da wir lineare Unabhängigkeit der ai vorausgesetzt haben, ist dabei gesichert, dass qk0 6= 0
für alle k. Außerdem gilt
!
k−1
k−1
X
X
(ak , qi )qi , ql = (ak , ql ) −
(ak , qi ) (qi , ql ) = 0.
(qk0 ,ql ) = ak −
(8.29)
| {z }
i=1
i=1
=δil
Die zu qk0 parallelen qk sind damit paarweise orthogonal.
Gleichung (8.27) zeigt auch, dass die orthonormale Basis nicht eindeutig ist, denn wir
können genauso gut qk = −qk0 /kqk0 k wählen oder, im Falle eines komplexen Hilbertraums,
jeden beliebigen anderen anderen Faktor vom Betrag 1.
Das Gram-Schmidt-Verfahren benötigt zur Funktion lediglich das Skalarprodukt des
zugrundeliegenden Hilbertraums, und kann daher auch zur Orthonormalisierung etwa
von Polynomen eingesetzt werden, wie wir gleich sehen werden. Doch zunächst wollen
wir uns den Fall ansehen, dass A = (aj ) ∈ Cm,n eine Matrix mit linear unabhängigen
Spalten ist, und die Vektoren aj deren Spaltenvektoren. Offenbar muss m ≥ n gelten,
sonst sind die Spalten linear abhängig. Wir setzen Q = (qj ) ∈ Cm,n die Matrix der mit
dem Gram-Schmidt-Verfahren orthonormierten Spaltenvektoren, und R = (rik ) ∈ Cn,n
mit


(ak , qi ) falls i < k
rik = kqk0 k
(8.30)
falls i = k


0
sonst
Dann gilt wegen (8.27)
ak = qk
qk0
k−1
n
X
X
+
(ak , qi )qi =
qi rik
i=1
(8.31)
i=1
141
8 Lineare Algebra II
und damit A = QR mit QH Q = I. Ist m = n, so ist dann Q die gesuchte unitäre Matrix
und R die rechte obere Dreiecksmatrix der QR-Zerlegung.
Das Verfahren benötigt bei quadratischen Matrizen genauso wie die Gauß-Elimination
O(n3 ) Schritte, da für jeden Vektor O(n) Skalarprodukte berechnet werden müssen. Außerdem arbeitet das Verfahren auf vollen Matrizen, was, wie schon gesagt, bei dünn besetzten Matrizen ungünstig ist und die Anwendbarkeit bei großen Matrizen einschränkt.
Auch hier gibt es daher alternative Verfahren, von denen wir gleich die HouseholderSpiegelungen und Givensrotationen kennenlernen werden.
Beispiel: Legendrepolynome
Da sich das Gram-Schmidt-Verfahren auf beliebige Hilberträume anwenden lässt, können
wir zum Beispiel den Hilbertraum der Polynome betrachten, mit dem Skalarprodukt
Z 1
(f, g) :=
f (x)g(x) dx.
(8.32)
−1
1,x,x2 , . . .
Dann sind die Polynome
linear unabhängig, da die Koeffizientendarstellung
eines Polynoms ja eindeutig ist. Andererseits sind diese Polynome aber nicht orthonormal
bezüglich (·,·), da zum Beispiel
Z 1
1
(1, x) =
x dx = .
(8.33)
2
−1
Wir benutzen nun das Gram-Schmidt-Verfahren, um eine orthogonale Basis zu erzeugen. Da (1, 1) = 2 ist
1
q1 = √
(8.34)
2
Weiter ist
1
1
q20 = x − x, √
·√ =x
(8.35)
2
2
und damit wegen (x,x) = 2/3
r
r
3 0
3
q2 =
q1 =
x.
(8.36)
2
2
Analog erhalten wir
3
1
1
q30 = x2 − (x2 , x) · x − (x2 , 1) · 1 = x2 −
(8.37)
2
2
3
und
√
1
2
q3 = 458 x −
.
(8.38)
3
Bis auf Vorfaktoren sind dies die ersten drei Legendrepolynome, die sich auf diese Weise
berechnen lassen. Analog ergeben sich die Chebyshev-Polynome Tn , wenn für dieselbe
Basis bezüglich
Z 1
f (x)g(x)
√
(f, g)T :=
dx
(8.39)
1 − x2
−1
das Gram-Schmidt-Verfahren durchgeführt wird.
142
8.2 QR-Zerlegung und Orthogonalisierung
Modifiziertes Gram-Schmidt-Verfahren
Numerisch ist das Gram-Schmidt-Verfahren nicht sehr stabil, denn falls zwei Vektoren
aj beinahe parallel sind, kommt es durch Auslöschung bei der Berechnung der Projektionen zu großen Rundungsfehlern. Numerisch besser ist das modifizierte Gram-SchmidtVerfahren, bei dem die Projektion eines jeden neu erzeugten Vektors sofort von allen
anderen abgezogen wird. Wir setzen also Q(0) = A und weiter für k = 1(1)n:
(k)
(k−1)
(k)
ql
(k)
ql
(k−1)
ql
(k−1)
ql
qk = qk
=
/rkk
(k)
− rki qk
für l > k
(8.40)
rkk = qk
(k−1) (k)
(k)
rki = ql
, qk
= al , qk .
(8.41)
=
für l < k,
mit
(k−1)
Der folgende Python-Code führt das modifizierte Gram-Schmidt-Verfahren auf der
Matrix A aus, die schrittweise in die orthonormale Matrix Q transformiert wird, während
R mit berechnet wird. Dadurch, dass in jedem Schritt der neu berechnete Basisvektor
von allen weiteren abgezogen wird, ist der nächste zu berechnende Vektor qk bereits
orthogonal zu den bisherigen Basisvektoren und muss lediglich normalisiert werden:
from scipy import *
def gramschmidt(a):
"Modifizierte Gram−Schmidt−QR−Zerlegung fuer eine n x m−Matrix a"
q = a.copy()
n = a.shape[1]
r = zeros((n, n))
# Schleife ueber alle Spalten von a bzw. q
for k in range(n):
# Berechnen von rkk = kqk0 k
# und Normalisierung des neuen Basisvektors
r[k,k] = sqrt(dot(q[:,k], q[:,k]))
q[:,k] = q[:,k] / r[k,k]
# Berechnen der rki = (qi , qk ) = (ai , qk )
# und Abziehen der Projektionen von den verbleibenden Vektoren
for i in range(k+1, n):
r[k,i] = dot(q[:,i], q[:,k])
q[:,i] = q[:,i] - r[k,i] * q[:, k]
return q, r
143
8 Lineare Algebra II
v0
a1
v
− ka1 k e1
ka1 k e1
Abbildung 8.3: Illustration der Householder-Konstruktion. Der Vektor a1 soll mittels einer Spiegelung auf einen der Vektoren ± ka1 k e1 abgebildet werden. Die zugehörigen Householdervektoren sind dann gerade die beiden Winkelhalbierenden v = a + ka1 k e1 und
v 0 = a − ka1 k e1 . Bei der Spiegelung von v wird a1 auf ka1 k e1 abgebildet (durchgezogene
Linien), bei Spiegelung von v 0 auf − ka1 k e1 (gestrichelte Linien).
8.2.2 Householder-Verfahren
Wie bereits gesagt, sind unitäre Matrizen nichts anderes als verallgemeinerte Drehungen
und Spiegelungen. Insbesondere ist das Produkt von unitären Matrizen wieder unitär.
Die beiden folgenden Verfahren zur QR-Zerlegung konstruieren Q daher als Produkt von
l einfachen elementaren unitären Matrizen Qi , wobei l vom Verfahren abhängt, wie auch
der Typ der Matrizen Qi . Diese transformieren A schrittweise in rechte obere Dreiecksform:
QH R.
Ql · · · Q2 Q1 A = R
=⇒ A = QH
· · · QH
(8.42)
|1
{z l−1 l }
Q
Bei der QR-Zerlegung mittels Householder-Spiegelungen werden nun m Spiegelungen konstruiert, so dass nacheinander die Spalten von A unterhalb der Diagonalen Null
werden, und A auf rechte obere Dreiecksgestalt transformiert wird. Während also das
Gram-Schmidt-Verfahren die Matrix A in Q transformiert und dabei R als Nebenprodukt anfällt, wird hier A in R transformiert, und Q fällt als Nebenprodukt ab. Oft wird
Q gar nicht explizit benötigt, und es ist geschickter, nur die Householder-Spiegelungen
zu speichern, die wir nun zunächst definieren wollen.
Sei also v ∈ Rm ein Vektor mit kvk22 = v H v = 1. Dann ist die zugehörige HouseholderSpiegelung definiert als
Sv = I − 2vv H
(8.43)
Ist w = λv, so gilt Sv w = w − 2vv H w = −w, w wird also an der Null gespiegelt. Ist
hingegen w ⊥ v, also v H w = 0, dann ist Sv w = w. Sv lässt also die zu v senkrechte
Hyperebene invariant, während Vektoren parallel zu v gespiegelt werden. Außerdem gilt
SvH = Sv und SvH Sv = I − 4vv H + 4vv H vv H = I, damit auch Sv2 = I, und Sv ist unitär.
Wie können wir nun eine Householder-Spiegelung konstruieren, so dass diese die erste
Spalte a1 von A auf die erste Koordinatenachse abbildet? Wie man sich leicht überlegt,
144
8.2 QR-Zerlegung und Orthogonalisierung
muss dann v eine der beiden Winkelhalbierenden sein (vergleiche Abbildung 8.3). Diese
sind von der Form
a1 + λe1
v=
(8.44)
ka1 + λe1 k
mit
λ = ± ka1 k .
(8.45)
Für die numerische Stabilität ist es günstiger, Auslöschungen zu vermeiden, daher wählt
man
λ = sgn(a11 ) ka1 k ,
(8.46)
wobei sgn(a11 ) das Vorzeichen von a11 bezeichnet. Durch die Wahl dieses Vorzeichens ist
der unnormierte Spiegelvektor
(
sgn(a11 )(|a11 | + ka1 k2 ) für j = 1
ṽj =
(8.47)
aj
für j > 1,
so dass es zu keiner Auslöschung kommen kann. Der eigentliche Spiegelvektor ist der
normierte Vektor v = ṽ/ kṽk2 .
Bei der Implementation ist es natürlich wichtig, Sv nicht explizit zu berechnen. Es gilt
aber
Sv A = A − 2vv H A = A − 2v(v H A)
(8.48)
Man berechnet also lediglich einmal den Vektor t = v H A, und zieht dann das tj -fache
von vj von der Spalte aj ab. Um weitere Spalten von A auf rechte obere Dreiecksform
zu bringen, fixieren wir die bereits bearbeiteten Koordinaten, und betrachten nur noch
eine Spiegelung in den verbleibenden Koordinaten. Dann sieht für die k-te Spalte der
unnormierte Spiegelvektor so aus:


fürj < k

0
qP
(k)
m
2
ṽj = sgn(akk )(|akk | +
(8.49)
l=k al ) für j = k


a
für j > k,
j
und der normierte Spiegelvektor ist v (k) = ṽ (k) / ṽ (k) 2 . Die Wurzel entspricht der Norm
des Restvektors (akk , . . . ,amk ). Nach min(m,n) − 1 Schritten ist dann A auf Dreiecksform
transformiert.
Um die Matrix Q zu erhalten, müssen wir gemäß (8.42) das Produkt der Spiegelungen in umgekehrte Reihenfolge berechnen, da ja Sv = SvH . Wurden nacheinander die
Spiegelungen mit Vektor v1 , v2 , . . . ,vl angewandt, suchen wir also die Matrix
Q = SvH(1) SvH(2) · · · SvH(l) == I Sv(1) Sv(2) · · · Sv(l) .
(8.50)
Um diese zu berechnen, müssen wir nur die Identität von rechts mit den Spiegelungen
multiplizieren, was analog (8.48) geht:
ASv = A − 2Avv H = A − 2(Av)v H .
(8.51)
145
8 Lineare Algebra II
Vielfach ist es aber gar nicht nötig, Q explizit zu kennen, dann kann man einfach die
Vektoren v (k) speichern und bei Bedarf Qw für einen beliebigen Vektor w ausrechnen,
indem die Spiegelungen in umgekehrter Reihenfolge auf w angewandt werden.
In Python könnte eine QR-Zerlegung mittels Householder-Spiegelungen so aussehen:
from scipy import *
from scipy.linalg import *
def householder(a):
"Householder−QR−Zerlegung fuer eine n x m−Matrix a"
def multiplyleft(a, v):
"a mit Householder−Spiegelung S_v von links multiplizieren"
v_H_a = dot(v.transpose().conj(), a)
for k in range(a.shape[1]):
a[:,k] -= 2*v_H_a[k] * v
def multiplyright(a, v):
"a mit Householder−Spiegelung S_v von rechts multiplizieren"
a_v = dot(a, v)
for k in range(a.shape[1]):
a[:,k] -= 2*v[k].conj() * a_v
r = a.copy()
q = identity(r.shape[0])
# Schleife ueber alle Spalten von a bzw. r,
# die wenigstens ein Subdiagonalelement haben
for k in range(min(r.shape[0] - 1, r.shape[1])):
# Kopie von a_k, um Spiegelvektor zu bauen
v = r[:,k].copy()
# schon bearbeitete Komponenten auf Null
v[:k] = 0
# Spiegelvektor a + sgn(a1 ) kak e1 berechnen
# Probleme durch sign(0) = 0 vermeiden
if sign(v[k]) > 0:
v[k] += norm(v)
else:
v[k] -= norm(v)
# normieren
v = v / norm(v)
# Matrix r updaten
multiplyleft(r, v)
# und unitaeren Teil q
multiplyright(q, v)
return q, r
Die Funktionen multiplyleft und multiplyright implementieren (8.48) bzw. (8.51),
die Hauptschleife muss also nur den Spiegelvektor v (k) berechnen und auf R und Q
146
8.2 QR-Zerlegung und Orthogonalisierung
entsprechend anwenden.
Ist A nicht quadratisch oder singulär, dann müssen unter Umständen Spalten getauscht werden, wenn die gesamte führende Spalte der aktuellen Restmatrix Null ist. Spaltentauschmatrizen sind ebenfalls unitäre, selbstinverse Matrizen, werden allerdings von
rechts anmultipliziert. Anders als das Gram-Schmidt-Verfahren kann das HouseholderVerfahren also auf beliebige Matrizen angewandt werden. Man erhält dann eine allgemeine Zerlegung
0
R K
A=Q·
· S,
(8.52)
0 0
wobei R0 eine reguläre rechte obere Dreiecksmatrix ist, Q das unitäre Produkt der
Householder-Spiegelungen und S die unitäre Matrix der eventuell nötigen Spaltenvertauschungen.
Jedes Matrix-Update gemäß (8.48) benötigt im wesentlichen O(nm) Operationen, die
Methode insgesamt daher O(mn2 ) Operationen, bei quadratischen Matrizen also wie
auch das Gram-Schmidt-Verfahren O(n3 ) Schritte.
Die QR-Zerlegung mit Hilfe von Householder-Spiegelungen ist in SciPy als scipy.
linalg.qr(A) implementiert und liefert die Zerlegung Q und R zurück. Wird das
Schlüsselwortargument pivoting auf True gesetzt, werden zusätzlich noch Spalten
getauscht und die neuen Spaltenindizes zusätzlich zurückgegeben.
8.2.3 Givens-Rotationen
Spiegelungen sind prinzipiell Operationen, die die gesamte Matrix betreffen, wie (8.48)
zeigt. Wie das Gram-Schmidt-Verfahren ist daher auch das Householder-Verfahren nicht
für dünn besetzte Matrizen geeignet und schlecht zu parallelisieren. Daher setzt man in
der Praxis gerne Givens-Rotationen ein.
Eine Givensrotation ist eine Drehung in zwei Koordinaten, also eine Matrix der Gestalt:


I 0 ... 0 0

0 s 0
i → 0 c

 ..
.. 
Gi,k,φ =
(8.53)
. 0
I 0 .


k → 0 −s 0 c 0
0 0 ... 0 I
mit c = cos(φ) und s = sin(φ) und einem beliebigen Winkel φ. Die beiden Cosinusterme befinden sich stets auf der Diagonalen. Offenbar ist Gi,k,φ eine unitäre Matrix, als
GH
i,k,φ Gi,k,φ = I.
Wir können nun eine solche Drehung benutzen, um das linke untere Element an,1 einer
Matrix A auf 0 zu bekommen. Dazu drehen wir die beiden untersten Zeilen der Matrix
entsprechend:

  . .  . . 
..
..
. ..
I 0 0
 ! .

0 c s  · 
(8.54)
x . . . = r ? 
0 −s c
y ...
0 ?
147
8 Lineare Algebra II
(x,y)
r
φ
r cos(φ)
r sin(φ)
(r, 0)
Abbildung 8.4: Illustration der Givens-Konstruktion. Der Vektor (x,y) soll um den Winkel φpauf die x-Achse gedreht werden. Dann gilt cos(φ) = x/r und sin(φ) = x/r mit
r = x2 + y 2 .
p
mit x = an−1,1 und y = an,1 sowie r = x2 + y 2 . Die Sterne deuten dabei an, dass sich
die gesamten beiden letzten Zeilen potentiell ändern. Den Drehwinkel muss man dabei
gar nicht explizit bestimmen, da c = cos(φ) = x/r und s = cos(φ) = y/r (vergleiche
Abbildung 8.4).
Ist r allerdings klein, ist diese Formel numerisch nicht stabil. Im Falle, dass |x| ≥ |y|,
berechnet man daher besser
q
0
r = 1 + (y/x)2
1
c = sgn(x) 0
(8.55)
r
y
,
s=
|x| r0
und analog im umgekehrten Falle.
Nachdem wir nun das linke unterste Element an,1 auf Null gedreht haben, können
wir mit dem nächsthöheren Element an−1,1 fortfahren und dieses auf an−2,1 drehen. Wir
fahren fort, bis die erste Spalte mit Ausnahme des ersten Elements auf Nullen gedreht
ist. Analog können wir nun in den folgenden Spalten unten anfangend alle Elemente bis
auf das Diagonalelement auf Null drehen.
Auch die Givens-Rotationen werden dabei nicht als Matrix-Multiplikation berechnet,
da sich bei Multiplikation von links tatsächlich ja nur zwei Zeilen lesen und neu schreiben. Für die Berechnung von Q müssen wir nach (8.42) die hermiteschen der Rotationen von rechts anmultiplizieren, was einer Modifikation zweier Spalten entspricht. Die
Hermitesche bzw. Transponierte der Drehung ergibt sich einfach durch Drehung in der
umgekehrten Richtung, also Vorzeichenwechsel des Sinusterms.
148
8.2 QR-Zerlegung und Orthogonalisierung
In Python sieht das Givens-Verfahren so aus:
from scipy import *
from scipy.linalg import *
def givens(a):
"Givens−QR−Zerlegung fuer eine n x m−Matrix a"
def multiplyleft(a, i, j, c, s):
"Matrix a mit Givens−Rotation von links multiplizieren"
# eigentlich nur zwei Zeilen verdrehen
ai_gedreht = c*a[i,:] + s*a[j,:]
aj_gedreht = -s*a[i,:] + c*a[j,:]
a[i,:] = ai_gedreht
a[j,:] = aj_gedreht
def multiplyright(a, i, j, c, s):
"Matrix a mit Givens−Rotation von rechts multiplizieren"
# eigentlich nur zwei Spalten verdrehen
ai_gedreht = c*a[:,i] + s*a[:,j]
aj_gedreht = -s*a[:,i] + c*a[:,j]
a[:,i] = ai_gedreht
a[:,j] = aj_gedreht
def calccs(x, y):
if abs(x) >= abs(y):
r = sqrt(1 + (y/x)**2)
c = sign(x)/r
s = y/(abs(x)*r)
else:
r = sqrt(1 + (x/y)**2)
c = x/(abs(y)*r)
s = sign(y)/r
return c, s
r = a.copy()
q = identity(r.shape[0])
# Doppelschleife ueber alle Subdiagonalelemente von a bzw. r
for k in range(min(r.shape[0] - 1, r.shape[1])):
for i in range(r.shape[0] - 1, k, -1):
c, s = calccs(r[i-1,k], r[i,k])
# Matrix r updaten
multiplyleft(r, i-1, i, c, s)
# und unitaeren Teil q, hermitesch durch Vz-wechsel im Sinus
multiplyright(q, i-1, i, c, s)
return q, r
Die Routinen multiplyleft und multiplyright implementieren wieder die Multiplikation mit einer Givensmatrix von links bzw. rechts. Die Routine calccs implementiert
149
8 Lineare Algebra II
die stabilisierte Berechnung der Sinus- und Cosinusterme gemäß (8.55).
Bei einer vollbesetzten Matrix benötigt das Verfahren damit insgesamt O(mn) Drehungen, die allerdings jeweils nur zwei Zeilen der Matrix verändern, also O(n) Rechenaufwand
haben. Daher benötigt das Verfahren insgesamt wieder O(mn2 ).
Anders als das Householder-Verfahren eignen sich Givensrotationen aber auch für parallele Verarbeitung und dünn besetzte Gitter. Denn für das Verfahren ist es im Prinzip
egal, auf welche Zeile die zu entfernende gedreht wird, es müssen ja nicht notwendigerweise benachbarte Zeilen sein. Daher reicht es, nur die besetzten Elemente unterhalb
der Diagonalen jeweils nacheinander auf die Diagonale drehen. Bei der 5 × 5-Matrix des
Eingangsbeispiels (8.2) sind daher lediglich 50 statt 300 Drehungen nötig.
8.3 Eigenwerte
In der Quantenmechanik spielt die Berechnung von Eigenwerten- und vektoren, also von
Eigenenergien und -zuständen, eine zentrale Rolle.
Gegeben ist wieder eine Matrix A ∈ Rn,n . Wir suchen nichttriviale Vektoren v ∈ Rn
und Skalare λ, so dass
Av = λv
⇐⇒
(A − λI)v = 0.
(8.56)
Die Formulierung auf der rechten Seite zeigt, dass für alle Eigenwerte λ die Matrix A−λI
singulär sein muss, also
det(A − λI) = 0.
(8.57)
Die Determinante ist aber letztlich nichts weiter als ein Polynom n-ten Grades in λ, dessen
Nullstellen gerade die Eigenwerte sind. Das Newtonverfahren konvergiert für Polynome,
so dass wir mit seiner Hilfe die Eigenwerte im Prinzip bestimmen können.
Das Problem ist, dass λ eine Variable ist, so dass wir nicht auf die QR- oder LUZerlegung zurückgreifen können. Wir müssen also die Matrix zum Beispiel entlang der
ersten Zeile entwickeln, und n Unterdeterminanten der Größe n − 1 berechnen. Diese
wiederum erfordern n − 1 Unterdeterminanten der Größe n − 2, und so weiter. Ingesamt
also sind n! viele Unterteilungsschritte nötig, was selbst bei moderat großen Matrizen
nicht handhabbar ist und außerdem schnell zur Anhäufung von Fehlern führt. Daher
wird dieses einfache Variante nur bei Matrizen in bis zu vier Dimensionen genutzt, für
größere Matrizen hingegen Näherungsverfahren, die wir nun kennen lernen werden.
8.3.1 Vektoriteration
Sei die Matrix A zunächst diagonalisierbar, also A = Q diag(λ1 , . . . ,λn )QH mit einer
unitären Matrix Q. Dann gilt für eine beliebigen Vektor x(0) 6= 0
x̃
(i)
i (0)
:= A x
i
H (0)
= Q diag(λ1 , . . . ,λn ) Q x
n
X
=
(qk , x(0) )λik qk .
(8.58)
k=1
Ist nun |λ1 | > |λk | für alle k > 1, also der betragsmäßig größte Eigenwert λ1 nicht
entartet, so ist λi1 λik für große i. Daher wird x̃i mit wachsender Anzahl Iterationen
150
8.3 Eigenwerte
zunehmend parallel zu einem Eigenvektor zu λ1 . Allerdings wird dabei x̃i gleichzeitig
immer größer bzw. kleiner, wenn |λ1 | größer bzw. kleiner 1 ist. Um numerische Probleme
zu vermeiden, muss x̃i noch normiert werden.
Dies führt zum Verfahren der Vektoriteration oder von-Mises-Iteration. Man wählt
einen Startvektor x(0) 6= 0, und berechnet dann iterativ
x(i+1) =
Ax(i)
.
Ax(i) 2
(8.59)
Hat die Matrix A einen nicht entarteten betragsmäßig größten Eigenwert, so konvergiert
x(i) gegen einen dazugehörigen Einheitseigenvektor, falls x(0) nicht gerade exakt senkrecht
auf dem Eigenraum steht. In der Praxis ist dies aufgrund numerischer Ungenauigkeiten
H
wenigstens für eine der Iterierten immer der Fall. Außerdem konvergiert x(i) Ax(i)
gegen diesen Eigenwert.
Ist der betragsmäßig größte Eigenwert entartet, aber es gibt keine weiteren Eigenwerte
H
mit gleichem Betrag, so konvergiert x(i) Ax(i) immer noch gegen den betragsmäßig
größten Eigenwert. Gibt es mehrere betragsgleiche, aber unterschiedliche größte Eigenwerte (etwa ±1), konvergiert dieses Verfahren nicht.
Das Verfahren konvergiert vergleichsweise langsam, und findet nur den betragsmäßig
größten Eigenwert. Man könnte zwar versuchen, den neuen Startwert durch Orthogonalisierung senkrecht zum Eigenraum des größten Eigenvektors zu wählen, aber im Allgemeinen verhindern wieder numerische Ungenauigkeiten, dass das Verfahren gegen einen
anderen Eigenwert konvergiert.
Zumindest einen weiteren Eigenwert kann man finden, indem man die geshiftete Matrix
A − λ1 I betrachtet, für die λ1 notwendigerweise dem betragsmäßig kleinsten Eigenwert,
nämlich 0, entspricht. Der gefundene Eigenwert µ1 entspricht einen Eigenwert λ1 + µ1
der Ursprungsmatrix A.
Beispiel: Fibonaccizahlen
Die Fibonaccizahlen sind definiert als F0 = 0, F1 = 1 und Fi+2 = Fi+1 + Fi für i ≥ 0.
Dies lässt sich auch als Vektoriteration schreiben:
F0
Fi+1
0
0 1
Fi
=
und
=
·
.
(8.60)
F1
1
Fi+2
1 1
Fi+1
| {z }
A
In diesem Fall ist es natürlich möglich, die Eigenwerte und -vektoren von A analytisch
zu bestimmen. Die Eigenwerte sind die Nullstellen
1 2 5
det(A − λI) = −λ(1 − λ) − 1 = λ −
− ,
(8.61)
2
4
√ also λ± = 12 1 ± 5 . Davon ist λ+ > 1 der größere Eigenwert, und λ− < 1. Die
dazugehörigen Eigenvektoren sind
1√ .
(8.62)
x± = 1
2 1± 5
151
8 Lineare Algebra II
Der Startwert (0,1)T der Fibonaccireihe ergibt sich in der Basis der Eigenvektoren als
1
1
0
x0 =
= √ x+ − √ x− .
(8.63)
1
5
5
Betrachten nun die x-Komponente von Ai x0 , können wir die Fibonaccizahlen auch als
√ !i
√ !i
1 i
1
1+ 5
1
1− 5
1 i
−√
∈N
(8.64)
Fi = √ λ+ + √ λ− = √
2
2
5
5
5
5
√ i
1+ 5
schreiben. Insbesondere ist Fi = Oi→∞
, unabhängig davon, welche Start2
werte benutzt werden, solange diese nicht gerade parallel zu x− sind. Für ganzzahlige
Startwerte ist dies nur möglich, wenn F0 = F1 = 0.
8.3.2 QR-Algorithmus
Da die Vektoriteration nicht alle Eigenwerte und -vektoren liefert, brauchen wir noch ein
anderes Verfahren, das alle Eigenwerte berechnen kann. Dieser Abschnitt führt hierzu
den QR-Algorithmus von Francis und Kublanovskaya ein.
Grundlage dieses iterativen Algorithmus ist, wie der Name schon sagt, die QRZerlegung. Wir starten mit A(0) = A ∈ Cn,n . In jedem Iterationsschritt berechnen wir
eine QR-Zerlegung A(k) = Q(k) R(k) , und setzen
H
A(k+1) = R(k) Q(k) = Q(k)
A(k) Q(k) .
(8.65)
Die letztere Umformung zeigt, dass A(k+1) dieselben Eigenwerte wie A(k) und damit auch
A hat. Konvergiert dieses Verfahren, bedeutet dies, dass Q(k) ≈ I für große k, und damit
ist A(k+1) nahezu rechte obere Dreiecksmatrix, deren Eigenwerte wir von der Diagonalen
ablesen können. Hat A keine entarteten Eigenwerte, so konvergieren die A(k) sogar gegen
eine Diagonalmatrix. Dies gilt allerdings nur, solange der Algorithmus über komplexen
Matrizen durchgeführt wird, die stets eine Schursche Normalform haben. Der reellwertige
Algorithmus hingegen führt nur zu einer Matrix mit 2 × 2-Blöcken auf der Diagonalen,
die jeweils zwei komplex konjugierten Eigenwerten über C entsprechen.
Eine einfache Erweiterung des Verfahrens zerlegt nicht A(k) , sondern A(k) − µk I =
Q̃(k) R̃(k) , wobei µk eine Näherung für einen Eigenwert ist. Oft wird einfach µk = an,n
gewählt. Die nächste Iterierte ist dann
A(k+1) = R̃(k) Q̃(k) + µk I,
(8.66)
der Shift wird also einfach wieder rückgängig gemacht.
Der Algorithmus benötigt sehr viele, teure QR-Zerlegungen. Um den Rechenaufwand
zu vermindern, kann man die Matrix zunächst durch Householder-Spiegelungen auf
Hessenberg-Form bringen, die dann mit Hilfe von Givens-Rotationen sehr schnell QRzerlegt werden kann.
Eine einfache Implementation des QR-Algorithmus mit Shift für eine Matrix mit reellen
Eigenwerten kann wie folgt aussehen:
152
8.3 Eigenwerte
from scipy import *
from scipy.linalg import *
def qr_eigenwerte(A, tolerance):
n = A.shape[0]
I = identity(n)
Ak = A.copy()
converged = False
while not converged:
shift = Ak[-1,-1]
Q, R = qr(Ak - shift*I)
Ak = dot(R, Q) + shift*I
if max([abs(Ak[i,k]) for i in range(n) \
for k in range(i)]) < tolerance:
converged = True
return array([Ak[i,i] for i in range(n)])
Die Routine liefert einen Vektor aus Eigenwerten mit Hilfe des Householder-Verfahrens
von SciPy. tolerance gibt dabei den maximalen Betrag eines Subdiagonalelements
an, der noch akzeptiert wird. Hat A komplexe Eigenwerte, können auch Element eins
unter der Diagonalen nicht verschwinden. Dann muss zum einen das Kriterium muss
dann entsprechend angepasst werden, zum zweiten kann dann natürlich nicht einfach
die Diagonale zurückgeliefert werden. Echte, also reelle Eigenwerte sind dann solche,
die weder links noch unterhalb auf der Subdiagonalen Nachbarn haben, die anderen
entsprechen komplexen Eigenwerten.
8.3.3 Inverse Iteration
Die Eigenvektoren ergeben sich im Prinzip aus dem Produkt aller Q(k) . Einfacher ist es
aber, eine sogenannte inverse Iteration durchzuführen. Ist λ eine gute Approximation
eines Eigenwerts λ0 der Matrix A ∈ Cn,n , so ist µ = (λ0 − λ)−1 ein sehr großer Eigenwert
von (A − λI)−1 , und der Eigenvektor v zu µ ist auch ein Eigenvektor von A zu λ. Ist
zum Beispiel λ eine auf 5 Stellen genaue Näherung, so ist |µ| ≈ 100.000.
Da µ sehr groß ist, konvergiert die Vektoriteration für (A − λI)−1 sehr schnell. Dazu
wird natürlich nicht die Inverse berechnet, sondern man startet wie gewohnt mit einem
Startwert x(0) 6= 0 und löst
(A − λI)x̃(i+1) = x(i)
(8.67)
durch Gaußelimination mit Pivotisierung. Die neue Iterierte wird noch normiert:
x(i+1) =
x̃(i+1)
.
x̃(i+1) 2
(8.68)
Bei einer sehr guten Eigenwertnäherung oder auch durch kleine numerische Fehler kann
es passieren, dass das Pivotelement der Gaußelimination numerisch exakt Null ist. In
diesem Fall wird es einfach durch eine sehr kleine Zahl ersetzt. Da letztlich nur die
153
8 Lineare Algebra II
Richtung ausschlaggebend ist, konvergiert dieses Verfahren extrem schnell gegen den zu
λ gehörigen Eigenvektor.
Die inverse Iteration, die zu einem gegebenen nicht-entarteten Eigenwert den Eigenvektor bestimmt, sieht wie folgt aus:
from scipy import *
from scipy.linalg import *
def inverse_iteration(A, l, tolerance):
n = A.shape[0]
x = ones(n)
Ashift = A - l*identity(n)
converged = False
while not converged:
x = solve(Ashift, x)
x = x / norm(x)
if norm(l*x - dot(A, x)) < tolerance:
converged = True
return x
l ist hier der Eigenwert λ, zu dem der Eigenvektor gesucht wird. Hier gibt die Toleranz
an, wie sehr Ax von λx abweichen darf.
Beispiel: Fibonaccizahlen numerisch
(k)
Der QR-Algorithmus mit Shift an,n soll nun anhand des Fibonaccibeispiels illustriert
werden, für das dieser Algorithmus sehr schnell konvergiert, wie die folgende Tabelle
illustriert:
Iteration
0
1
2
3
4
A(k)
!
0.00000000 1.00000000
1.00000000 1.00000000
−0.50000000 0.50000000
0.50000000
0.02941176
0.00000509
1.61803399
1.61803399
0
0
0
3
3
10
10
15
17
!
!
−0.61803399 −0.00000000
0.00000000
0
!
1.61764706
−0.61803399 0.00000509
Stellen λ−
!
1.50000000
−0.61764706 0.02941176
Stellen λ+
Die letzten beiden Spalten geben die Anzahl der korrekt bestimmten Nachkommastellen des größten bzw. kleinsten Eigenwerts an. Nach dem vierten Schritt verbessert sich
daran nichts mehr, da beide Eigenwerte bis auf Maschinengenauigkeit bestimmt sind.
154
8.3 Eigenwerte
Um die zugehörigen Eigenvektoren zu bestimmen, können wir die inverse Iteration benutzen, die in diesem Fall für beide Eigenvektoren innerhalb von nur einem Schritt auf
Maschinengenauigkeit konvergiert.
Wie sieht es nun mit größeren Matrizen aus? Ist eine Matrix A ∈ R10,10 symmetrisch
mit Standardzufallszahlen gefüllt, konvergiert das Verfahren in etwa 200 Schritten so,
dass unterhalb der Diagonalen keine Werte betragsmäßig größer als 10−5 stehen. Auch
hier konvergiert die inverse Iteration innerhalb eines Schritts praktisch bis auf Maschinengenauigkeit gegen den zugehörigen Eigenvektor.
155
9 Optimierung
Bei der Optimierung betrachtet man eine Funktion f : M → R, die Zielfunktion, mit
einer beliebigen zulässigen Menge M . Gesucht ist x ∈ M , so dass f (x) ≤ f (x0 ) für alle
x0 ∈ M . Man schreibt kurz
min f (x).
(9.1)
x∈M
Die Menge M ist dabei oft eine Teilmenge des Rn , die zum Beispiel durch Nebenbedingungen der Form g(x) ≥ 0 beschrieben wird.
Ein Beispiel einer solchen Aufgabe haben wir bereits im Zusammenhang mit Funktionsfits kennengelernt. Bei diesem Problem sind Daten (xi , yi ) ∈ Rm × R, i = 1(1)n sowie
eine parametrisierte Funktion fv (x) gegeben, wobei v freie Parameter sind. Gesucht wird
min
v
n
X
(fv (xi ) − yi )2 .
(9.2)
i=1
Im Spezialfall, dass fv linear ist, also von der Form fṽ,v0 (x) = ṽ T x + v0 , ist dies in
Vektorschreibweise äquivalent zur Aufgabe
n
X
min
(ṽ,v0
mit
)∈Rm+1

v∈Rm+1
i=1

y1
 
b =  ... 
yn
(ṽ T xi − v0 − yi )2 = min kAv − bk2 .

(x1 )1
 ..
und A =  .
. . . (x1 )m
..
.
(9.3)

1
..  .
.
(xn )1 . . . (xn )m 1
Die klassische lineare Regression benutzt die 2-Norm und versucht damit, die mittlere Abweichung zu minimieren. Bei bestimmten Aufgaben ist aber nicht der mittlere,
sondern der maximale Fehler ausschlaggebend. Dies ist zum Beispiel der Fall bei der
Kraftfeldoptimierung für Molekulardynamiksimulationen, bei der eine Parametrisierung
eines Potentials gesucht wird, die bekannte experimentelle Daten möglichst gut wiedergibt. Offenbar ist die Güte einer solchen Näherung durch den maximalen Fehler in einer
Eigenschaft bestimmt und nicht durch den durchschnittlichen Fehler. Aus (9.3) wird dann
n
min kAv − bk∞ = min max |(Av)i − yi | .
v∈Rm+1
v∈Rm+1
i=1
(9.4)
Obwohl sich scheinbar nicht viel geändert hat, hat dieses Problem eine ganz andere
Struktur, für die andere Lösungsmethoden benutzt werden. Um dies zu verstehen, fügen
wir eine weitere Variable vm+2 zum Parameterraum hinzu. Diese soll vm+2 = kAv − bk∞
157
9 Optimierung
erfüllen, also vm+2 minimal mit −vm+2 ≤ (Av)i − yi ≤ vm+2 für i = 1(1)n. Damit wird
aus (9.4) eine Minimierungsaufgabe mit linearer Zielfunktion und Nebenbedingungen:
A e
b
min(0, . . . , 0, 1)T v unter der Bedingung
v≥
,
(9.5)
v
−A e
−b
wobei e = (1, . . . ,1)T . Eine solche Aufgabe heißt auch lineares Programm und wird mit
Verfahren wie den Simplexalgorithmus behandelt. Lineare Programme spielen auch in
der Spiele- und Wirtschaftstheorie eine große Rolle.
Die ursprünglich gestellte Aufgabe (9.1) oder auch (9.2) sehen in ihrer allgemeinen
Form natürlich auch nichtlineare Funktionen vor, etwa wenn eine Exponentialfunktion
an Daten angeglichen werden soll oder wenn das Minimum einer komplexeren Energiefunktion gesucht ist. In diesem Fall spricht man von nichtlinearer Optimierung. Sofern
die Zielfunktion zweifach stetig differenzierbar ist, ist aus der Analysis bekannt, dass im
Minimum die Ableitung verschwindet. Die Nullstellen der Ableitung lassen sich im Prinzip mit Hilfe des Newtonverfahrens finden, wir lernen aber bessere, auf die Optimierung
zugeschnittene Varianten kennen.
Eine nichtlineare Funktion kann mehrere Minima aufweisen. Ähnlich wie das Newtonverfahren konvergieren die Verfahren zur nichtlinearen Optimierung im Allgemeinen
nur lokal gegen das nächstgelegene Minimum. Solche Optimierungsverfahren heißen daher lokal. Falls eine Zielfunktion sehr viele lokale Minima hat, ist es für diese Verfahren
unter Umständen schwierig bis unmöglich, das globale Minimum (9.1) zu finden. Dies
gilt insbesondere, wenn Nebenbedingungen gegeben sind, weil sich dann das Minimum
auch irgendwo auf dem Rand der zulässigen Menge befinden kann. Trotzdem spielen lokale Optimierungsmethoden eine wichtige Rolle, etwa bei der Energieminimierung. Bei
diesem ersten Schritt typischer Molekulardynamiksimulationen werden die Teilchen zunächst so verschoben, dass die Energie lokal minimiert wird. Dadurch kann die eigentliche
Simulation mit größeren Zeitschritten begonnen werden. Eine globale Optimierung ist dabei unnötig, da das System während der Simulation sowieso nicht im Energieminimum
verharrt, sondern einen hoffentlich ausreichend großen Teil des Phasenraums besucht.
Die globale Optimierung, also die Suche nach dem kleinsten lokalen Minimum, ist
hingegen vor allem bei der Suche nach Grundzuständen wichtig. Auch viele praktische
Probleme, etwa die Fahrplanoptimierung, sind globale Optimierungsprobleme. Lokale
Verfahren setzen außerdem die Differenzierbarkeit der Zielfunktion voraus. Ist dies nicht
der Fall oder die zulässige Menge diskret, scheiden lokale Verfahren ebenfalls aus. Leider
gibt es für die allgemeine globale Optimierung mit nichtlinearen Zielfunktionen oder über
diskreten zulässigen Mengen keine Verfahren mit gesicherten Konvergenzaussagen, wir
werden aber zwei physikalisch bzw. biologisch motivierte Verfahren kennenlernen.
9.1 Ausgleichsrechnung und Pseudoinverse
Wir betrachten zunächst lineare Optimierungsprobleme der Form
min kAx − bk2 ,
x∈Rn
158
(9.6)
9.1 Ausgleichsrechnung und Pseudoinverse
d.h., wir suchen den Vektor x, so dass Ax möglichst nahe an b liegt, wobei A ∈ Rm,n und
b ∈ Rm . Solche Probleme ergeben sich zum Beispiel bei der Ausgleichsrechnung (9.3).
Ist m = n und A regulär, so ist die Lösung unmittelbar klar, nämlich A−1 b. Ist aber
m > n, dann ist das Gleichungssystem Ax = b im Allgemeinen nicht lösbar; (9.6) besagt
dann, dass wir dasjenige x suchen, dass das Gleichungssystem möglichst gut löst. Um
diese Aufgabe zu lösen, formen wir sie zunächst etwas um:
kAx − bk22 = (Ax − b)T (Ax − b) = xT AT Ax − 2bT Ax + bT b.
(9.7)
Es handelt sich also um eine quadratische Optimierungsaufgabe, deren Minimum x
∂
2
2
∇ kAx − bk2 =
kAx − bk2 = 2xT AT A − 2bT A = 0
(9.8)
∂xi
i
erfüllt. Hat A linear unabhängige Spalten, so ist AT A invertierbar, und wir finden die
Lösung als
x = (AT A)−1 AT b.
(9.9)
Ist in (9.6) m < n, so ist das Gleichungssystem im allgemeinen nicht eindeutig zu
lösen. Wir können aber die Lösung minimaler Norm kxk suchen. Dies führt zu der Optimierungsaufgabe mit Nebenbedingungen
min kxk2
x∈Rn
unter der Bedingung Ax = b.
(9.10)
Diese Aufgabe können wir ganz ähnlich wie im Falle m > n lösen. Hat A wenigstens
linear unabhängige Zeilen, so ist AAT invertierbar, und wir können
x = AT (AAT )−1 b
(9.11)
definieren. Dann erfüllt x offenbar die Nebenbedingung Ax = b, und alle anderen zulässigen x0 liegen in x + Kern(A) = x + Bild(AT )⊥ . Da x ∈ Bild(AT ), gilt kx0 k =
kxk + kx − x0 k ≥ kxk. Mit anderen Worten, x löst die Optimierungsaufgabe (9.10).
Die auftretenden Matrizen (AT A)−1 AT und AT (AAT )−1 sind Spezialfälle der Pseudoinversen oder Moore-Penrose-Inversen für allgemeine Matrizen. Der Name Pseudoinverse rührt daher, dass diese unter den gegebenen Nebenbedingungen die Gleichungen
invertieren, so gut es geht. Die Pseudoinverse findet also das x mit minimaler Norm unter
allen x, für die kAx − bk2 minimal ist. Moore und Penrose haben abstrakte Bedingungen für die Pseudoinverse definiert, die von den obigen Ausdrücken erfüllt werden. Die
Pseudoinverse für beliebige Matrizen kann durch eine sogenannte Singulärwertzerlegung
bestimmt werden kann. Diese kann in dieser Vorlesung leider nicht behandelt werden,
aber wir werden zumindest sehen, wie bei Matrizen mit maximalem Zeilen- oder Spaltenrang die Pseudoinverse mit Hilfe der QR-Zerlegung bestimmt werden kann, ohne AT A
oder AAT berechnen und invertieren zu müssen. In SciPy berechnet scipy.linalg.
pinv(A) bequem die Moore-Penrose-Pseudoinverse für eine beliebige Matrix A.
Sei also A ∈ Rm,n eine Matrix mit maximalem Spaltenrang, insbesondere m ≥ n. Aus
dem Householder- oder Givensverfahren erhalten wir
R1
A = Q1 Q2 ·
,
(9.12)
0
159
9 Optimierung
wobei R1 eine reguläre rechte obere n × n-Dreiecksmatrix ist, und Q1 die zugehörigen n
ersten Spalten der unitären Matrix Q. Dann ist
−1 T
(AT A)−1 AT b = (R1T QT1 Q1 R1 )−1 AT b = R1−1 R1T
A b,
(9.13)
was durch bequemes Vorwärts- und Rückwärtseinsetzen ohne Matrixinversion gelöst werden kann. Wie man sieht, wird in diesem Fall die Matrix Q nicht benötigt.
Hat umgekehrt A maximalen Zeilenrang, insbesondere also m ≤ n, dann zerlegen wir
T
A mit Hilfe von Householder- oder Givensverfahren wie oben in eine reguläre rechte obere m × m-Dreiecksmatrix R1 und orthonormale Matrizen Q1 ∈ Rn,m und Q2 ∈ Rn,n−m .
Dann gilt entsprechend
−1
AT (AAT )−1 b = AT (R1T QT1 Q1 R1 )−1 b = AT R1−1 R1T
b.
(9.14)
Für Zielfunktionen von der Form kAx − bk2 , also gewissermaßen das OptimierungsÄquivalent von linearen Gleichungssystemen, lässt sich also das Optimierungsproblem
mit Hilfe der Pseudoinversen geschlossen lösen.
9.2 Nichtlineare Optimierung
Für nichtlineare, aber wenigstens zweifach stetig differenzierbare Zielfunktionen f : Rn →
R gilt in freien Minima x
∇f (x) = 0.
(9.15)
Dies garantiert allerdings nicht, dass eine gefundene Nullstelle auch ein Minimum ist, dazu muss zusätzlich noch die Hessesche Matrix f 00 (x) positiv definit sein. Selbst in diesem
Fall ist der gefundene Punkt nur ein lokales Minimum, also nur in einer kleinen Umgebung sind alle anderen Punkte höher. Eine Funktion kann aber natürlich ohne weiteres
mehrere Minima haben, die sich nur durch erneute Suche finden lassen. Insbesondere ist
es praktisch unmöglich, das globale Minimum zu finden; damit werden wir uns später
noch einmal beschäftigen.
Für (9.15) können wir das mehrdimensionale Newtonverfahren formulieren. Wir wählen
also einen Startpunkt x(0) in der Nähe des Minimums und setzen
−1
(9.16)
x(k+1) = x(k) − f 00 x(k)
∇f x(k) ,
wobei

f 00 (x) =
∂2
f (x)
∂xj ∂xk
k,j

=

∂2
f (x)
∂x21
...
..
.
∂
∂x1 ∂xn f (x)
...
∂
∂x1 ∂xn f (x)


..
.
.

2
∂
f
(x)
∂x2
(9.17)
1
f 00 (x)
Bei großen Dimensionen n kann es rasch sehr aufwendig werden,
zu berechnen, dies
ist aber auch nötig, um zu überprüfen, ob das gefundene Extremum auch tatsächlich
ein Minimum ist. Daher ist dieses Verfahren nicht optimal. Besser sind die folgenden
Verfahren, die ohne f 00 (x) auskommen.
160
9.2 Nichtlineare Optimierung
9.2.1 Verfahren des steilsten Abstiegs
Da das Newtonverfahren, das wir oben auf die Ableitung angewendet haben, auf einer
Taylorentwicklung erster Ordnung basiert, basiert die Optimierung mit Hilfe des Newtonverfahrens in gewisser Weise auf einer Taylorentwicklung zweiter Ordnung. Was können
wir nun mit der praktikableren Taylorentwicklung erster Ordnung erreichen? Diese ist
zunächst einmal
f (x + λd) = f (x) + λ∇f (x)T d + O(λ2 )
(9.18)
für eine Richtung d und Schrittweite λ > 0. Anders als beim Newtonverfahren können
wir nun nicht das Minimum dieser Näherung als neue Iterierte benutzen, da die Näherung linear ist und daher kein Minimum hat. Daher können wir lediglich versuchen, f zu
verringern. Da λ > 0 ist und wir für kleine λ die quadratischen Anteile vernachlässigen
können, muss ∇f (x)T d < 0 gelten. Eine Richtung d, die dies erfüllt, heißt Abstiegsrichtung.
Den maximalen Abstieg erreichen wir, wenn d = −∇f (x); diese Richtung heißt daher
auch steilster Abstieg. Für das Verfahren des steilsten Abstiegs (auch Gradientenabstiegsverfahren wählt man zunächst einen Startwert x(0) und setzt dann
x(k+1) = x(k) − λ∇f x(k)
(9.19)
mit einer geeigneten Schrittweite λ > 0. Im einfachsten Falle ist λ eine kleine Konstante,
zum Beispiel 0,01.
9.2.2 Schrittweitensteuerung
Besser ist aber, die Schrittweite so zu wählen, dass das Verfahren sicher absteigt. Dafür gibt es verschiedene Verfahren, von denen hier nur die recht effizienten ArmijoSchrittweiten besprochen werden.
Entlang der festgelegten Richtung d ist die Optimierung nur noch ein eindimensionales
Problem, und wegen (9.18) gibt es für alle α < 1/2 eine kleine Umgebung von x, in der
f (x + λd) ≤ f (x) + αλ∇f (x)T d
(9.20)
gilt. Wir wählen λ so, dass diese Bedingung erfüllt ist, und natürlich möglichst groß.
α ∈ (0, 1/2) bestimmt dabei den Mindestabstieg, den wir erreichen wollen. Um λ zu
bestimmen, beginnen wir einfach mit λ0 = 1, und setzen anschließend λk+1 = ρλk ,
solange (9.20) nicht erfüllt ist. ρ ∈ (0,1) ist dabei eine weiter Verfahrenskonstante, die
bestimmt, wie rasch wir λ verkleinern. Um die Bedingung zu überprüfen, benötigen wir
lediglich die beiden reellen Konstanten ∇f (x)T d und f (x) und müssen in jedem Schritt
f (x + λd) neu auswerten. α wird meist eher klein gewählt, etwa 0,1, denn je strikter diese
Bedingung, desto kleiner wird die Schrittweite. Umgekehrt sollte man ρ nicht zu klein
wählen, weil sonst unnötig kleine Schrittweiten benutzt werden.
Die Schrittweitensteuerung setzt nur eine Abstiegsrichtung d voraus, und kann daher zum Beispiel auch auf das Newton-Verfahren angewandt werden, dessen Richtung
−1
d = −f 00 x(k)
∇f x(k) ist. Diese Richtung ist dann eine Abstiegsrichtung, wenn
161
9 Optimierung
−1
−1
∇f x(k) f 00 x(k)
∇f x(k) , also, wenn f 00 x(k)
positiv definit ist. Dies ist zumindest in einer Umgebung eines Minimums der Fall.
Beispiel: Gradientenabstiegsverfahren mit Schrittweitensteuerung
In Python sieht das Verfahren des steilsten Abstiegs mit Armijo-Schrittweiten so aus:
from scipy import *
from scipy.linalg import *
def armijo_steepest_descent(f, gradf, x0, alpha=0.1, rho=0.5,
tol=1e-5, maxiter = 1000):
x = x0.copy()
fx = f(x)
grad = gradf(x)
step = 0
while norm(grad) > tol:
d = -grad
# Armjio-Schrittweite berechnen
lmbda = 1
xneu = x + d
grad2 = dot(grad, d)
while f(xneu) > fx + alpha*lmbda*grad2:
lmbda = rho*lmbda
xneu = x + lmbda*d
step += 1
if step > maxiter:
# Abbruch, letzte Naeherung zurueckgegeben
return x
# mit dem gefundenen Schritt vorwaerts
x = xneu
fx = f(x)
grad = gradf(x)
return x
Die Funktion armijo_steepest_descent benötigt dabei als Eingabeparameter Pythonfunktionen f und gradf, die die zu minimierende Funktion und ihren Gradienten zurückliefern. Die Konstanten alpha und rho entsprechen den Konstanten α und ρ des
Armijo-Verfahrens. Die Vorgaben α = 0,1 und ρ = 0,5 sind übliche Werte, die meist zu
guter Konvergenz führen. Das Verfahren bricht ab, wenn ∇f (x(k) ) < tol, also die
Tangente hinreichend flach und damit ein Minimum hinreichend gut gefunden ist, oder
wenn eine maximale Anzahl an Schritten, maxiter, überschritten wird. Dies vermeidet
ein Einfrieren durch zu kleine Schrittweiten. Dies passiert insbesondere, wenn der Funktionswert im Minimum sehr groß oder klein ist, so dass nur wenige Stellen zur Optimierung
verbleiben.
162
9.2 Nichtlineare Optimierung
1.0
1.0
10
10
0.0
0.0
1
0.5
0.8
1.0
0.2
0.8
15 10
20
0.6
5
5
0.4
0.0
0.0
0.6
0.8
1.0
0.2
0.0
1.0
5
15
20 10
0.2
5
0.4
0.2
0.4
0.5
0.6
0.2
0.2
0.0
15 10
20
15
20 10
0.5
1
1.0 1.01.0
0.5
1
0.0
0
10
0
10
0.5
1.0
0.2
0.0
1
50
50
0.5
1.01.0
100
30
0.5
50
100
50
30
0.5
0.2
0.4
0.6
0.8
1.0
Abbildung 9.1: Verfahren des steilsten Abstiegs für eine quadratische Funktion (oben)
und die Rosenbrockfunktion (unten). Links werden Armijo-Schrittweiten mit α = 0,1
und ρ = 0,5, rechts eine konstante Schrittweite von 0,01 verwendet. Die roten Punkte
markieren die Iterierten x(k) , die Höhenlinien illustrieren die zu optimierende Funktion. Für die quadratische Funktion konvergieren beide Verfahren gegen das Minimum bei
(0, 0), und auch das Armijo-Verfahren wählt eine konstante Schrittweite von etwa 0,0078.
Durch diesen etwas kleineren Wert zielt das das schrittweitengesteuerte Verfahren weniger
über das Minimum hinaus und braucht nur 11 statt 35 Schritte für 10 Stellen Genauigkeit. Bei der Rosenbrockfunktion benötigt das schrittweitengesteuerte Verfahren etwa
1700 Iterationen dafür. Jeder 200. Punkt ist im Graphen grau gefärbt, um die extrem
langsame Konvergenz zu visualisieren. Für die konstante Schrittweite 0,01 konvergiert
das Verfahren gar nicht, wie die eingezeichneten ersten zehn Punkte zeigen.
163
9 Optimierung
Als Beispiel betrachten wir das Verfahren des steilsten Abstiegs für zwei auf der Ebene
definierte Funktionen. Die erste Funktion ist eine quadratische Funktion
f (x, y) = 40x2 + 30(x + y)2 + 20y 2 ,
(9.21)
die ihr Minimum bei (0,0) hat, die zweite Funktion ist die Rosenbrockfunktion
fRosenbrock (x, y) = (1 − x)2 + 100(y − x2 )2 .
(9.22)
Diese hat ihr Minimum offenbar bei (1,1), ist aber das Optimierungsäquivalent zur Rungefunktion. Denn während das Minimum in einem sehr steilen Tal liegt, ist der Gradient
entlang der Talsohle sehr flach. Die meist gierigen Optimierungsverfahren finden daher
sehr schnell in die Talsohle, kommen dort aber nur noch langsam ins Ziel, da die Hauptabstiegsrichtung vorwiegend in die Talsohle statt entlang dieser zeigt.
Abbildung 9.1 zeigt die Anwendung des Verfahrens des steilsten Abstiegs mit und
ohne Schrittweitensteuerung auf die beiden Funktionen und illustriert dabei die beiden
Hauptschwächen des Gradientenabstiegsverfahrens. Einerseits neigt es dazu, über das
Minimum hinauszuschießen, und sich dadurch langsam in das Minimum einzupendeln.
Dies lässt sich durch die Schrittweitensteuerung begrenzen. Andererseits muss der steilste
Abstieg nicht in Richtung des Minimums zeigen, in diesem Fall neigt das Verfahren
des steilsten Abstiegs dazu, sich dem Minimum in Zick-Zack-Kurven mit sehr geringer
Schrittweite zu nähern.
Bei zu großer Schrittweite kann das Verfahren sogar gar nicht konvergieren. Da von
vornherein die maximale Ableitung meist nicht bekannt ist, ist also eine Schrittweitensteuerung unerlässlich.
9.2.3 CG-Verfahren
Wir betrachten nun einen wichtigen Spezialfall, nämlich quadratische Funktionen der
Form
1
f (x) = xT Ax − xT b
(9.23)
2
mit positiv definiter Matrix A ∈ Rn,n . Dies bedeutet, dass A symmetrisch ist und xT Ax >
0 für alle Vektoren x 6= 0 erfüllt, etwa, weil alle Eigenwerte positiv sind. Positiv definite
Matrizen treten zum Beispiel bei quantenmechanischen Rechnungen auf.
Für Funktionen der Form (9.23) gibt es ein iteratives Verfahren, dass bei unbegrenzter
Genauigkeit in spätestens n Schritten gegen die exakte Lösung konvergiert. Dieses Verfahren ist das konjugierte Gradienten-Verfahren (englisch conjugate gradient, daher kurz
auch CG-Verfahren). Das Optimierungsproblem min f (x) kann dabei auch als Gleichung
aufgefasst werden, da
Ax = b
⇐⇒
1
x minimiert f (x) = xT Ax − xT b.
2
(9.24)
Daher wird das CG-Verfahren auch als effizienter Gleichungslöser für positiv definite
Matrizen behandelt.
164
9.2 Nichtlineare Optimierung
1.0
50
30
0.5
10
30
0.5
1
0.0
50
1.01.0
0.5
0.0
0.5
1.0
Abbildung 9.2: CG-Verfahren für die quadratische Funktion aus (9.21). Die Höhenlinien
stellen die zu optimierende quadratische Funktion dar, die roten Punkte markieren die
Iterierten des CG-Verfahrens, das in nur 2 Schritten konvergiert.
Um das Minimum iterativ zu suchen, starten wir mit einem beliebigen Startwert x(0)
(zum Beispiel 0), und verfeinern die aktuelle Näherung gemäß x(k+1) = x(k) + λ(k) d(k)
so, dass wir uns dem Minimum nähern. Wie wir gesehen haben, ist der steilste Abstieg,
also in Richtung des negierten Gradienten r(k) = b − Ax(k) , nicht ideal. Die Idee des
CG-Verfahrens ist nun, die Richtungen d(k) in gewisser Weise stets senkrecht zu einander zu wählen, so dass Hin- und Herpendeln oder Zick-Zack-Kurse ausgeschlossen sind.
Tatsächlich wählt man die Abstiegsrichtungen senkrecht in dem durch A induzierten SkaT
larprodukt, also so, dass (d(i) , d(k) )A := d(i) Ad(k) = 0 für i 6= k. Man sagt auch, dass
d(i) und d(k) A-konjugiert sind, daher der Name des Verfahrens.
Die d(k) werden konstruiert, indem die Gradientenabstiegsrichtungen r(k) mit Hilfe des
Gram-Schmidt-Verfahrens zueinander senkrecht bezüglich (·,·)A gemacht werden. Dabei
muss aufgrund der Wahl der Richtungen d(k+1) nur senkrecht zu d(k) gemacht werden,
zu den anderen bisherigen Richtungen steht d(k+1) dann automatisch senkrecht. Der
Vorfaktor kann dabei vereinfacht werden:
T
r(k+1) r(k+1)
(r(k+1) , d(k) )A
=−
.
(9.25)
T
(d(k) , d(k) )A
r(k) r(k)
Die Schrittweite kann bei einer quadratischen Funktion so bestimmt werden, das λ die
Funktion entlang der Richtung d, also
1
1
1
(x + λd)T A(x + λd) − bT (x + λd) = xT Ax − bT x + λdT (Ax − b) + λ2 dT Ad, (9.26)
2
2
2
165
9 Optimierung
minimiert. Es ergibt sich
T
d(k) r(k)
λ =
.
T
d(k) Ad(k)
Zusammengefasst ergibt sich das CG-Verfahren in Python als
(k)
(9.27)
from scipy import *
from scipy.linalg import *
def conjugate_gradient(A, b, x0, tol=1e-10):
x = x0.copy()
r = b - dot(A, x)
rr = dot(r,r)
d = r.copy()
while sqrt(rr) > tol:
lmbda = dot(d, r) / dot(d, dot(A, d))
x += lmbda*d
r -= lmbda*dot(A,d)
oldrr = rr
rr = dot(r,r)
# orthogonalisieren
d = r + rr/oldrr * d
return x
Das Verfahren bricht ab, wenn r(k) < tol, anstatt stur n Schritte zu berechnen, da
durch numerische Ungenauigkeiten unter Umständen 1-2 zusätzlich Schritte nötig werden
können. Umgekehrt können natürlich auch weniger Schritte notwendig sein, wenn der
Startwert günstig liegt.
Abbildung 9.2 illustriert das CG-Verfahren an der selben quadratischen Funktion, für
die das schrittweitengesteuerte Gradientenabstiegsverfahren 11 Schritte brauchte, um 10
Stellen Genauigkeit zu erreichen. Das CG-Verfahren hingegen konvergiert in nur zwei
Schritten auf Maschinengenauigkeit, also etwa 17 Stellen.
Da das Verfahren auch als Gleichungslöser sehr gute Eigenschaften hat und wegen der
überwiegenden Skalar- und Matrix-Vektorprodukte auch sehr einfach auf dünnbesetzten
Matrizen eingesetzt werden kann, ist es eines der meist genutzten Verfahren. Daher gibt
es natürlich auch eine SciPy-Implementation, scipy.sparse.linalg.cg(A, b).
9.2.4 Nebenbedingungen und Straffunktionen
Mit dem Verfahren des steilsten Abstiegs und den Armijo-Schrittweiten haben wir ein
stabiles und meist schnell konvergierendes Verfahren, um lokal freie Minima zu suchen.
Was aber kann man tun, wenn zusätzlich noch Nebenbedingungen gegeben sind? Wir
suchen nun also minx∈M f (x), wobei die zulässige Menge
M = {x|gi (x) ≥ 0, i = 1(1)m}
(9.28)
ist. Bekannte Verfahren sind etwa die sequenzielle quadratische Programmierung (SQP)
oder das Verfahren von Gill und Murray [GM78]. Hier lernen wir einen anderen, physikalisch motivierten Ansatz kennen.
166
9.2 Nichtlineare Optimierung
Dazu setzen wir voraus, dass nicht nur die zu minimierende Funktion f : Rn → R stetig
differenzierbar ist, sondern auch die Funktionen gi : Rn → R, die die Nebenbedingungen
definieren. Wäre nun gi (x) = −∞ für alle x ∈
/ M oder zumindest kleiner als das gesuchte
Minimum von f in M , so wäre
min f (x) = minn f (x) +
x∈M
x∈R
m
X
min(0, gi (x))2 .
(9.29)
i=1
In der Praxis ist einerseits gi (x) im Allgemeinen endlich, andererseits kennen wir aber
auch kein Verfahren, um eine höchst unstetige Funktion zu minimieren. Wenn wir uns
die Nebenbedingungen aber als Banden vorstellen, über die ein iterativer Algorithmus
nicht hinausschreiten darf, könnte man diese zunächst weicher gestalten, so dass der
Algorithmus den zulässigen Bereich etwas verlassen kann, und dann die Banden mit der
Zeit immer härter gestalten, so dass der Algorithmus schließlich in den zulässigen Bereich
gedrückt wird. Befindet sich das Minimum über M am Rand von M , wird die gefundene
Näherungslösung daher immer minimal außerhalb von M liegen. Ist dies ein Problem,
etwa weil f außerhalb M nicht ausgewertet werden kann, kann man stattdessen auf
Barrieremethoden ausweichen, bei denen die Banden bereits innerhalb von M beginnen
und am Rand von M singulär sind.
Beim Straffunktionsverfahren minimieren wir also die modifizierte Funktion
qσ (x) = f (x) +
m
X
min(0, σgi (x))2 .
(9.30)
i=1
P
2
Der hintere Teil pσ (x) = m
i=1 min(0, σgi (x)) wird dabei Straffunktion (Penalty function) genannt, weil er Punkte außerhalb des zulässigen Bereichs mit höheren Funktionswerten bestraft.
Um das Minimum zu finden, starten wir mit recht kleinem σ0 > 0. Auf qσ0 wenden wir
dann ein Optimierungsverfahren für freie Optimierung an, etwa das Verfahren des steilsten Abstiegs mit Schrittweitensteuerung. Aufgrund der Konstruktion ist der Gradient
von qσ recht einfach zu berechnen:
∇qσ (x) = ∇f (x) +
m
X
2σ 2 min(0, gi (x))∇gi (x).
(9.31)
i=1
Sinnvollerweise wählt man einen Startpunkt im Inneren von M . Ist im gefundenen,
freien Minimum von q bereits gi (x) ≥ −τ mit gewünschter Toleranz τ erfüllt, ist das
Minimum gefunden, und liegt sehr wahrscheinlich im Inneren vom M . Ansonsten wird
σk erhöht und erneut die Minimierung gestartet, allerdings naheliegenderweise mit dem
bereits gefundenen Minimum als Startwert. Die Lage des Minimums ändert sich dabei,
da ja wegen der Abbruchbedingung wenigstens eine Nebenbedingung noch nicht erfüllt
war, und sich diese durch die Änderung von σk ändert. Solange danach gi (x) ≥ −τ
nicht erreicht ist, passen wir σk an und iterieren weiter. σk kann auf verschiedene Weisen
gewählt werden, es muss nur σk → ∞ für k → ∞ gelten. Eine Möglichkeit ist etwa
σk = k a , wobei man a > 1 nicht zu groß wählen sollte, zum Beispiel a = 2.
167
9 Optimierung
1.5
10
1.0
8
0.5
0.0
6
0.5
4
1.0
1.5
2
2.0
2.5
2
1
0
1
2
03
2
1
0
1
2
Abbildung 9.3: Straffunktionsverfahren für einen Halbkreis. Die durchgezogenen, gestrichelten, und gepunkteten Linien markieren die Isolinien pσ (x) = 1/2 in den Schritten 1,2
und 5. Minimiert wird jeweils der Abstand zum den mit offenen Symbolen markierten
drei Punkten. Der rote Kreis liegt im inneren, das Verfahren braucht nur einen Aufruf
des freien Optimierers. Für die grünen und blauen Dreiecke sind jeweils mehrere Aufrufe
nötig, wobei das blaue, nach unten zeigende Dreieck so gewählt ist, dass das Minimum
in der Ecke liegt. Im rechten Graphen sind die Straffunktionen entlang der y-Achse, also
pσ (0,y), für dieselben Schritte gezeigt. Dünner grün sind die korrespondieren Zielfunktionen qσ (0,y) eingezeichnet.
Abbildung 9.3 illustriert das Verfahren am Beispiel einer Abstandsminimierung zu
einem Halbkreis. Wir suchen also
min kx − pk2
x∈M
mit M = {(x,y) | gi (x,y) ≥ 0, i = 1,2}
(9.32)
mit
g1 (x, y) = 4 − x2 − y 2
und g2 (x,y) = −10y.
Dies entspricht offenbar k(x,y)k2 ≤ 2 und y < 0, also dem Halbkreis. Im Beispiel werden drei verschiedene Punkte betrachtet und mit Hilfe des Straffunktionsverfahrens und
einem schrittweitengesteuerten Gradientenverfahren der nächste Punkt im Halbkreis gesucht. Der Straffaktor σ wurde als 0,1 k 2 gewählt, mit k = 1,2, . . . der Iterationsschritt.
p = (−1, −1) liegt selber im Inneren des Halbkreises und wird daher gleich im ersten Optimierungsschritt als nächster Punkt gefunden. Für die beiden anderen Punkte, p = (−1, 1)
und p = (2,5, 1), sind nur die Gerade beziehungsweise beide Ungleichungen gleichzeitig
aktiv; auch hier werden die nächsten Punkte am Rand des Halbkreises innerhalb weniger
Iterationen gefunden. Auf der rechten Seite sieht man, dass die Straffunktionen sehr steil
werden. Daher ist eine Schrittweitensteuerung hier besonders wichtig.
168
9.3 Lineare Programme und Simplexalgorithmus
z
x
y
Abbildung 9.4: Links: Illustration eines linearen Programms. Die Nebenbedingungen sind
x ≥ 0, y ≥ 0 und 1 − x ≥ y; die Schraffuren markieren den ausgeschlossenen Bereich.
Der Pfeil deutet den Gradienten der Zielfunktion an, die Linien im zulässigen Bereich
sind Isolinien des Potentials. Hier findet sich das Minimum in der mit einem Punkt
markierten rechten unteren Ecke. Rechts: Dreidimensionaler zulässiger Bereich x ≥ 0
mit weiterer Nebenbedingung. Ist eine Nebenbedingung aT x = b gegeben, so sind nur
Punkte mit Koordinaten ≥ 0 aus dieser Ebene zulässig, also aus dem grünen Dreieck.
Die Projektion dieses Dreiecks in die xy-Ebene entspricht dem zulässigen Bereich in der
linken Illustration. Die Ecken lassen sich durch die Menge der Koordinaten, die nicht
Null sind, vollständig beschreiben. Die unterste Ecke etwa hat nur y aktiv, die obere
z. Sind zwei Nebenbedingungen gegeben, so ist die resultierende zulässige Menge eine
Gerade (hier rot eingezeichnet). Die Ecken werden nun durch zwei aktive Koordinaten
beschrieben, hier y und z für die vordere Ecke, und x und z für die hintere.
9.3 Lineare Programme und Simplexalgorithmus
Wie wir in der Einleitung gesehen hatten, führt die lineare Regression mit Maximumsnorm zu einem ganz anderen Typ von Problem, bei dem die Zielfunktion linear ist.
Dadurch liegt das Minimum notwendigerweise auf dem Rand der zulässigen Menge. Sind
zusätzlich noch die Nebenbedingungs(un-)gleichungen linear (vgl. Abbildung 9.4), spricht
man von einem linearen Programm. Programm hat hier also erst einmal nichts mit Computern zu tun. Solche linearen Programme spielen auch in der Optimierung von Wirtschaftsprozessen eine wichtige Rolle („Operations research“), da Gewinn und produzierte
Mengen bei unverändertem Preis linear von einander abhängen.
Lineare Programme können in einer Vielzahl von Formen definiert werden, wir betrachten hier die Normalform
min cT x unter den Nebenbedingungen x ≥ 0, Ax = b
(9.33)
mit c ∈ Rn , A ∈ Rm,n und b ∈ Rm . Die Anzahl m der Gleichungsbedingungen ist dabei
nicht festgelegt. Da x ein Vektor ist, bedeutet x ≥ 0 einfach, dass alle Komponenten
größer als Null sein sollen. Alle linearen Nebenbedingungen lassen sich so formulieren,
eventuell unter Zuhilfenahme von weiteren Variablen.
Betrachten wir zwei Beispiele. Die in der Abbildung 9.4 gegebene Nebenbedingung
1 − x ≥ y ist nicht von der obigen Form. Wir führen deswegen eine neue Variable z =
169
9 Optimierung
1−x−y ein, die dann z ≥ 0 erfüllen muss. Wir erhalten die Normalform mit c0 = (c0 , c1 , 0),
da z ja nicht zur Zielfunktion beiträgt, sowie A = (1, 1, 1) und b = 1. Abbildung 9.4 rechts
zeigt den resultierenden zulässigen Bereich im dreidimensionalen Raum.
Auch das Problem
A e
b
T
min(0, . . . , 0, 1) v unter der Bedingung
v≥
,
(9.34)
v
−A e
−b
das sich bei der linearen Regression mit Maximumsnorm ergibt (vgl. (9.5)), ist nicht in
Normalform. Zum einen müssen wir die Nebenbedingungsungleichungen in Gleichungen
transformieren. Dazu führen wir einfach eine Schattenvariable zi = aTi v − bi pro Ungleichung aTi v ≥ bi ein. Dann ist zi ≥ 0 offenbar äquivalent zur ursprünglichen Ungleichung.
Zum anderen sind aber die Variablen v frei, während wir voraussetzen, dass v ≥ 0. Um
dies zu beheben, teilen wir jede Variable in v = v+ − v− mit v± ≥ 0 auf und ergänzen A
und c entsprechend. Das ergibt die äquivalente Aufgabe
v+
v−
z
min(0, . . . , 0, 1, 0, . . . , 0, − 1, 0, . . . , 0)T v
(9.35)
x
mit der neuen Variablen x = (v+ ,v− ,z) und den Nebenbedingungen x ≥ 0 und
v+
v−
z
A e − A −e − I 0
b
.
x=
−b
−A e
A
−e
0
−I
Wie können wir Aufgabe (9.33) lösen? Sofern die zulässige Menge beschränkt ist, beschreiben die Nebenbedingungen immer einen Polyeder. Man kann nun zeigen, dass sich
ein Optimum immer in einer der Ecken dieses Polyeders befindet. Der Simplexalgorithmus besucht nacheinander die Ecken des Polyeders, wobei die Zielfunktion ständig kleiner
wird. Da es nur endliche viele Ecken gibt, findet der Algorithmus das Minimum irgendwann. Es gibt pathologische Beispiele, in denen der Algorithmus alle Ecken absuchen
muss. Im Allgemeinen konvergiert der Simplexalgorithmus aber schnell.
Die Methode zerfällt dabei in zwei Phasen. In der ersten Phase muss eine gültige Ecke
bestimmt werden, in der zweiten Phase müssen wir dann von einer gültigen Ecke aus
eine neue, benachbarte Ecke mit niedrigerer Zielfunktion finden. Wir beginnen mit der
Beschreibung der zweiten Phase, da die die erste Phase die zweite Phase benutzt, um ein
erweitertes Problem zu lösen, dass erlaubt, eine erste Ecke zu finden.
Phase II
Wir nehmen an, dass die Matrix A maximalen Zeilenrang hat, also alle doppelten Gleichung eliminiert wurden; dies wird später die erste Phase übernehmen. Außerdem sei x
eine Ecke des Polyeders.
Wie stellen wir diese Ecke dar? Abbildung 9.4 illustriert, dass eine Ecke einfach durch
die Menge der aktiven, also von Null verschiedenen Koordinaten beschrieben werden
kann. Da wir angenommen haben, dass A ∈ Rm,n linear unabhängige Zeilen hat, beschreibt Ax = b einen n − m-dimensionalen Unterraum, dessen Ecken jeweils m aktive
Koordinaten haben.
170
9.3 Lineare Programme und Simplexalgorithmus
Sei B = {j1 , . . . ,km } die Menge der in der aktuellen Ecke aktiven Koordinaten, die
sogenannten Basiskoordinaten, und N = {1, . . . ,n}\B die Menge der Nichtbasiskoordinaten. AB = (aj1 , . . . ,ajm ) ∈ Rm,m sei die zu den Basisvariablen xB = (xji )i ∈ Rm
gehörende Teilmatrix, sowie AN analog die zu den Nichtbasisvariablen gehörende Teilmatrix. Dann gilt xN = 0 und damit AB xb = b. Der Zielfunktionswert in x ist deshalb
cT x = cTB xB = cB A−1
B b.
(9.36)
Wir betrachten nun eine beliebigen anderen Punkt u ∈ M , also u ≥ 0 und Au =
AB uB + AN uN = b. Dann ist
−1
ub = A−1
B (b − AN uN ) = xB − AB AN uN
(9.37)
und damit
T
−1 T
T
T
T
cT u = cTB (xB − A−1
A
u
)
+
c
u
=
c
x
+
c
−
A
A
c
un .
N
N
N
N
B
N
N
B
B
{z
}
|
(9.38)
r
Da uN ≥ 0 ist, kann die Zielfunktion nur verkleinert werden, wenn eine Komponente
rs < 0 ist. Ist dies nicht der Fall, haben wir also unser Optimum gefunden.
Sei nun also s so gewählt, dass rs < 0 minimal. Dann können wir unser Ergebnis
verbessern, indem wir us > 0 wählen, aber alle anderen Elemente von uN weiterhin
bei 0 belassen. Wir nehmen also s in die Basiskoordinaten B auf. Damit diese eine Basis
bleiben, müssen wir nun noch sehen, welche Gleichung dafür herausfällt. Aus (9.37) folgt,
dass uB = xB − us A−1
B as . Auch im neuen Punkt muss aber uB ≥ 0 gelten, daher können
wir uN nur so groß wählen, bis für die erste Basisvariable xt = us (A−1
B as )t gilt. Dann gilt
ut = 0, d.h. diese Basisvariable geht in die Nichtbasis über. Wir suchen also
(
)
x jk
x jt
us = min
|k ∈ B, (A−1
(9.39)
B as )k > 0 =:
−1
−1
(AB as )k
(AB as )t
Sind dabei alle (A−1
B as )k < 0, so dass das Minimum gar nicht existiert, können wir uB
unbegrenzt groß machen. Also ist der zulässige Bereich unbeschränkt, und wir müssen
abbrechen, da die Funktion beliebig klein werden kann und also kein Minimum hat.
Wir tauschen nun in der Basis B die gefundene beschränkende Basisvariable jt durch
s aus und erhalten die neue Basis B 0 . In AB wird dabei einfach die Spalte t durch as
ersetzt, also
AB 0 = AB + (as − ajt )eTt
(9.40)
Für die Rechnungen benötigen wir aber A−1
B , dass wir allerdings auch mit einer Rang-1Formel anpassen können. Die Sherman-Morrison-Formel liefert
−1
A−1
B 0 = AB −
A−1
B as − et
eTt A−1
B .
−1
(AB as )t
(9.41)
171
9 Optimierung
Phase I
Wie können wir nun eine zulässige erste Lösung mit zugehörigem Basissatz und A−1
B
finden? Die Idee ist, zunächst die Matrix noch einmal stark zu erweitern, sodass eine
gültige Ecke einfach zu finden ist, aber nur die Ecken des ursprünglichen zulässigen
Bereichs optimal. Phase kann dann genutzt werden, um eine solche Ecke zu finden.
Dazu betrachten wir das neue Problem
y
x
min(0, . . . , 0,, 1, . . . , 1)T z
(9.42)
z
mit der Variablen z = (x, y) ∈ Rn+m und den Nebenbedingungen z ≥ 0 und
à I z = b̃
Dabei sind die i-ten Zeilen von à und b̃ identisch mit denen von A und b, nur werden
die Vorzeichen getauscht, falls bi < 0. Dies ändert die Lösungen des Gleichungssystems
nicht, aber es gilt b̃ ≥ 0. Durch die Identität in den hinteren Spalten hat diese Matrix
unabhängig vom ursprünglichen A maximalen Zeilenrang.
Sofern die ursprüngliche zulässige Menge nicht leer war, ist das Minimum dieser Zielfunktion offenbar Null, nämlich dann, wenn alle y = 0 sind. Außerdem kennen wir einen
zulässigen Punkt des neuen Problems, nämlich (0, b̃), und die zugehörige Matrix AB = I.
Daher kennen wir auch A−1
B = I, das im Folgenden dann nur angepasst werden muss. Wir
können also die Phase I des Simplexalgorithmus unmittelbar auf diese Matrix anwenden.
Findet der Simplex-Algorithmus nun ein Minimum, dass von Null verschieden ist, ist
offenbar die ursprüngliche zulässige Menge leer gewesen, und wir müssen abbrechen. Ist
das Minimum hingegen Null und alle y = 0, also in der Nichtbasis, so haben wir unseren
Startwert für die Phase II gefunden. Es kann allerdings auch passieren, dass noch zu y
gehörige Indizes jt > n in der Basis vorkommen. Dann müssen wir eine echte Koordinate
s < n finden, die mit jt getauscht werden kann. Dazu suchen wir ein s mit A−1
B as )t 6= 0,
so dass wir wieder unsere Austauschformel (9.41) auf die Spalten s und jt anwenden
können. Finden wir kein solches s, dann kann man zeigen,dass die ursprüngliche Matrix
linear abhängige Zeilen hatte. In diesem Fall wird die jt − n-te Zeile gestrichen. In A−1
B
müssen entsprechend die jt − n-te Spalte und t-te Spalte eliminiert werden.
Quellcode 9.1 zeigt eine Implementation des Simplexverfahrens in Python.
Beispiel: Polynomapproximation
Als Beispiel für den Simplexalgorithmus und gleichzeitig noch einmal die Pseudoinversen
soll das Beispiel der Polynomapproximation
Gegeben Stützstellen xi , yi , i =
Pn−1 dienen.
i
1(1)m, suchen wir ein Polynom p(x) = i=0 ci x , so dass
kp(xi ) − yi k = kAc − bk
minimal ist. Die Matrix A ist dabei analog (3.7) definiert:


1 x1 x21 . . . xn−1
1


..
..
A =  ...

.
.
1 xm
172
x2m
...
xn−1
m
(9.43)
(9.44)
9.3 Lineare Programme und Simplexalgorithmus
3.0
0.06
2.5
0.05
2.0
0.04
1.5
0.03
1.0
0.02
0.5
0.01
0.01.0
0.5
0.0
0.5
1.0 0.001.0
0.5
0.0
0.5
1.0
Abbildung 9.5: Polynomapproximation von exp(x) (durchgezogene Kurve links) im Bereich [−1,1]. Die Punkte markieren die 10 Stützstellen. Anders als bei der Interpolation
ist hier nur ein Polynom zweiten Grades gesucht, dass exp(x) an den gegebenen Stützstellen möglichst gut annähern soll. Die rot gestrichelte Lösung ist dabei die Lösung
der kleinsten Quadrate, die grün gepunktete Lösung die mit minimaler maximaler Abweichung. Im rechten Graphen sind die absoluten Abweichungen zwischen den beiden
Polynomnäherungen und exp(x) gezeigt. Die zweite Lösung erkauft sich eine niedrigere
Abweichung am rechten Rand durch deutliche höhere Abweichung zwischen −0,8 und 0.
Die maximalen Fehler sind dadurch gleichmäßig über das Intervall verteilt.
und b = (yi )i . Ist m = n und die x-Koordinaten der Stützstellen xi paarweise verschieden,
fällt die Polynomapproximation mit der Interpolation zusammen, da der minimale Fehler
0 offenbar durch das eindeutige interpolierende Polynom erreicht wird.
Anders als bei der Interpolation wählt man aber im Allgemeinen m n, das Polynom
kann also nicht alle Stützstellen passieren, und wird im Allgemeinen keine Stützstelle
exakt treffen. Dafür vermeidet die Polynomapproximation das Rungeproblem, da die
zusätzlichen Stützpunkte verhindern, dass das Polynom zu weit von der Zielfunktion abweicht. Das Minimum und der Algorithmus, mit dessen Hilfe dieses berechnet werden
kann, hängen von der verwendeten Norm ab. Ist k·k die aus dem üblichen Skalarprodukt abgeleitete 2-Norm k·k2 , so kann man das Minimum mit Hilfe der Pseudoinversen
berechnen. Ist die Norm hingegen die Maximumsnorm, berechnet sich das Ergebnis mit
Hilfe von (9.5) bzw. (9.35) und dem Simplexalgorithmus.
Abbildung 9.5 zeigt die Ergebnisse für die Approximation von exp(x) in diesen Normen.
Beide Näherungen approximieren die Funktion hinreichend gut. Unterschiede zeigen sich
allerdings in den Absolutdifferenzen |p(x) − exp(x)|. Das in der 2-Norm approximierende
Polynom minimiert den mittleren Fehler, indem es einen kleineren Fehler im Intervall
< 0 durch eine höheren Fehler bei 1 erkauft. Da dies nur ein Punkt ist, wiegt der verrin-
173
9 Optimierung
2.0
10
1.5
φLJ(r)/²
1.0
6
0.5
σ
0.0
4
²
0.5
2
1.0
1.50.0
5000
4500
4000
3500
3000
2500
2000
1500
1000
500
0
8
0.5
1.0
r/σ
1.5
2.0
2.5 00
2
4
6
8
10
Abbildung 9.6: Links: das Lennard-Jones-Potential mit dem typischen Radius σ und der
Tiefe des attraktiven Tals von . Rechts: Energielandschaft für ein LJ-Teilchen in einer
zweidimensionalen LJ-Flüssigkeit. Rote Punkte markieren die Positionen anderer Teilchen, die Graustufen repräsentieren das Potential. Die gelben Kreuze markieren lokale
Minima. Um diese zu finden, wurde zunächst das Potential an 100 × 100 Punkten ausgewertet, und von allen Punkten mit einem Potential kleiner als 1000 aus eine lokale
Minimierung gestartet.
gerte Fehler bei negativen Zahlen schwerer. Die Minimierung der maximalen Abweichung
hingegen führt dazu, dass sich der maximale Fehler sehr gleichmäßig über das Intervall
verteilt, auch wenn dafür die Fehler bei negativen x deutlich größer sind.
9.4 Globale Optimierung
Die Ausgleichsrechnung, also min kAx − bk2 , und die linearen Programme sind zwei Spezialfälle von Optimierung, bei denen ein gefundenes Optimum stets auch ein globales
Minimum ist. Das hängt damit zusammen, dass die Zielfunktionen im Allgemeinen nur
ein (Ausgleichsrechnung) oder gar kein lokales Minimum (lineare Programmierung) haben. Im Gegensatz dazu finden das Newtonverfahren oder das Verfahren des steilsten
Abstiegs stets nur lokale Minima, also Punkte mit verschwindendem Gradienten, dafür
aber bei fast beliebiger Zielfunktion.
In der Praxis, und besonders in physikalischen Anwendungen, sind die Zielfunktionen
meist stark nichtlinear und besitzen zahlreiche lokale Minima. Suchen wir etwa Grundzustände eines komplexen Systems, müssen wir Minima der Energiefunktion finden, die
meist so viele lokale Nebenminima aufweist, dass es auch für einen Computer unmöglich
ist, alle zu untersuchen.
174
9.4 Globale Optimierung
Listing 9.1: Simplexalgorithmus zur Lösung des linearen Programms min cT x unter den
Nebenbedingungen Ax = b, x ≥ 0. Es werden keine besonderen Eigenschaften von A
vorausgesetzt, der Algorithmus eliminiert selbstständige redundante Zeilen.
from scipy import *
from scipy.linalg import *
def rank1update(Abinv, t, y):
"""
Update von Ab^{-1}, wenn in Ab Spalte t durch Ab*y ersetzt wird
"""
v = y.copy()
pivot = v[t]
v[t] -= 1
v /= pivot
u = Abinv[t]
for i in range(Abinv.shape[0]):
Abinv[:,i] -= v*u[i]
def minelement(x):
"""
sucht die kleinste Komponente von x und deren Index
"""
s = 0
minimum = x[0]
for i in range(1,len(x)):
if x[i] < minimum:
s, minimum = i, x[i]
return minimum, s
def maxelement(x):
"""
sucht die groesste Komponente von x und deren Index
"""
s = 0
maximum = x[0]
for i in range(1,len(x)):
if x[i] > maximum:
s, maximum = i, x[i]
return maximum, s
def minposelement(x, y, eps):
"""
sucht den Index der kleinsten Komponente von x_i/y_i,
wobei y_i > 0 sein soll.
"""
s = -1
for i in range(0,len(x)):
if y[i] > eps:
v = x[i] / y[i]
if s == -1 or v < minimum:
# erstes passendes Element
# oder spaeter ein kleineres
s, minimum = i, v
if s >= 0: return s
else:
return None
#
175
9 Optimierung
def phase2(c, A, b, basis, Abinv, eps=1e-10):
"""
Phase 2 des Simplexverfahrens. c ist der Kostenvektor der
Zielfunktion c^Tx, die Nebenbedingungen Ax=b, A habe maximalen
Zeilenrang. basis ist die Menge der Basiskoordinaten der aktuellen
Ecke, und Abinv die Inverse von A eingeschraenkt auf die
Basiskoordinaten. Liefert das Optimum x zurueck und passt die
Basis sowie Abinv an. eps ist die Toleranz des Algorithmus.
"""
#
n
#
m
Anzahl Variablen
= A.shape[1]
und Gleichungen
= A.shape[0]
# Nichtbasis berechnen
nichtbasis = []
for i in range(n):
if not i in basis:
nichtbasis.append(i)
while True:
An = A[:, nichtbasis]
cn = c[:, nichtbasis]
cb = c[:, basis]
xb = dot(Abinv, b)
# reduzierte Kosten
r = cn - dot(An.transpose(), dot(Abinv.transpose(), cb))
# beste Abstiegskoordinate s suchen
minc, spos = minelement(r)
if minc > -eps:
# keine Abstiegsrichtung, Minimum gefunden!
x = zeros(n)
x[basis] = xb
return x
s = nichtbasis[spos]
# rauszuwerfende Variable suchen
Abinvas = dot(Abinv, A[:,s])
t = minposelement(xb, Abinvas, eps)
if t == None:
# zulaessige Menge unbegrenzt!
raise Exception("zulaessige Menge unbeschraenkt!")
# Austausch von j_t und s
nichtbasis[spos] = basis[t]
basis[t] = s
#
176
# Update von Abinv
rank1update(Abinv, t, Abinvas)
9.4 Globale Optimierung
def phase1(c, A, b, eps=1e-10):
"""
Phase 1 des Simplexverfahrens. c ist der Kostenvektor der
Zielfunktion c^Tx, die Nebenbedingungen Ax=b. Liefert eine
zulaessige Basis, die zugehoerige Inverse sowie A und b zurueck,
wobei A und b nun maximalen Zeilenrange haben. eps ist
die Toleranz des Algorithmus.
"""
# Anzahl Variablen und Gleichungen
m, n = A.shape
# Problem erweitern, damit wir eine Loesung kennen
b = b.copy()
A = concatenate((A, identity(m)),axis=1)
c = concatenate((zeros(n), ones(m)))
# Ax = b positiv machen
for i in range(m):
if b[i] < 0:
b[i] = -b[i]
A[i,:n] = -A[i,:n]
# sichere Ecke
basis = range(n, n+m)
# Inverse
Abinv = identity(m)
# Loesung mit Hilfe von Phase 2 suchen
x = phase2(c, A, b, basis, Abinv, eps)
if dot(c, x) > eps:
raise Exception("zulaessige Menge ist leer!")
while True:
# pruefen, ob Basis noch Schattenvariablen enthaelt
maxb, t = maxelement(basis)
if maxb <= n: break
# echte Ersatzvariable suchen, die nicht in der Basis ist
for s in range(n):
if s in basis: continue
Abinvas = dot(Abinv, A[:,s])
if Abinvas[t] < 0:
# Ein Tauschpartner!
basis[t] = s
rank1update(Abinv, t, Abinvas)
break
else:
# Schleife durchgelaufen, ohne Ersatzvariable zu finden
# -> Matrix linear abhaengig, q-te Zeile streichen
del basis[t]
q = maxb - n
A = delete(A, q, 0)
b = delete(b, q, 0)
Abinv = delete(Abinv, q, 1)
Abinv = delete(Abinv, t, 0)
#
return basis, Abinv, A[:,:n], b
177
9 Optimierung
def simplex(c, A, b,
"""
Simplexverfahren
Nebenbedingungen
zurueck. eps ist
"""
eps=1e-10):
zur Minimierung von c^Tx unter der
Ax=b und x >= 0. Liefert das Optimum x
die Toleranz des Algorithmus.
basis, Abinv, A, b = phase1(c, A, b, eps)
return phase2(c, A, b, basis, Abinv, eps)
178
9.4 Globale Optimierung
Als Beispiel betrachten wir ein in der statistischen Physik sehr beliebtes Modell, das
Lennard-Jonesium (LJ). Dabei handelt es sich um Teilchen, die gemäß einem Potential
σ 12 σ 6
φLJ (r) = 4
−
(9.45)
r
r
wechselwirken
(vgl. Abbildung 9.6 links). Das Potential hat ein Minimum der Tiefe − bei
√
6
2σ und wird unterhalb σ rasch sehr groß. φLJ ist ein einfaches Modell für Edelgasatome
mit einem Durchmesser von etwa σ, die sich auf längere Abstände dispersiv (∼ r−6 )
anziehen.
In einer solchen zweidimensionalen Lennard-Jones-Flüssigkeit aus 100 Teilchen in einer
10σ × 10σ-Box wählen wir nun ein Teilchen aus und halten die Koordinaten aller anderen
Teilchen fest. Abbildung 9.6 rechts zeigt die potentielle Energie in Abhängigkeit von der
Position des ausgewählten Teilchens. Dies ist aber nichts anderes als ein zweidimensionaler Schnitt durch die potentielle Energie als Funktion aller Teilchenkoordinaten. Um die
lokalen Minima zu bestimmen, wurde zunächst auf einem 100 × 100-Raster das Potential
ausgewertet, und von allen hinreichend niedrigen Punkten aus eine lokale Minimierung
gestartet. Da bereits dieser Schnitt über 20 lokale Minima aufweist, kann man sich vorstellen, wie viele lokale Minima die Energie als Funktion aller 200 Teilchenkoordinaten
aufweist. Wegen des “Curse of dimension” ist es in diesem Fall nicht mehr möglich, eine
Rasterung vorzunehmen. Es ist also aussichtslos, sämtliche lokale Minima mit Hilfe eines
lokalen Minimierungsverfahrens zu suchen.
Im Folgenden lernen wir zwei heuristische Methoden kennen, die auch unter solchen
Bedingungen meist akzeptable Näherungen für das globale Minimum finden.
9.4.1 Simulated annealing
Simulated Annealing (Simulierte Abkühlung) basiert auf der Beobachtung, dass durch
gesteuerte, langsame Abkühlung das Wachstum besonders gleichmäßiger Kristalle gefördert wird. Dies macht man sich zum Beispiel bei der Härtung von Stahl zu Nutze.
Letztendlich ist Kristallisation aber nichts anderes als ein Optimierungsprozess, da der
Einkristall die energetisch minimale Struktur ist.
Um dies auf ein Optimierungsproblem zu übertragen, legt man die Boltzmann-Statistik
der statistischen Physik zugrunde, die besagt, dass bei Temperatur T alle Zustände gemäß
PT (x) ∼ e−βE(x)
(9.46)
verteilt sind, wobei E die potentielle Energie des Systems im Zustand x ist und 1/β =
kB T mit der Boltzmannkonstanten kB .
Sei nun x0 das globale Minimum der Energiefunktion E. Dann ist für alle x
PT (x) ∼ e−βE(x) = e−βE(xo ) eβ[E(x0 )−E(x)] ∼ e−β[E(x)−E(x0 )] ≤ 1,
(9.47)
da E(x) − E(x0 ) ≥ 0. Bei niedrigen Temperaturen ist β sehr groß, so dass alle Zustände
mit einer größeren Energie als E(x0 ) rasch sehr unwahrscheinlich werden. Durch Abkühlen wird es also tatsächlich sehr wahrscheinlich, das globale Minimum zu finden. Um
179
9 Optimierung
damit ein Optimierungsproblem minx E(x) global zu lösen, fassen wir die Elemente der
zulässigen Menge als Zustände auf, und die zu minimierende Funktion E als Energie
dieser Zustände.
Im Prinzip könnte man nun mit Hilfe der Verwerfungsmethode versuchen, PT -verteilte
zufällige Zustände zu erzeugen. Wie wir im Eingangsbeispiel gesehen haben, schwankt
die Energielandschaft allerdings oft stark, so dass die meisten Punkte extrem kleine Akzeptanzraten hätten. Dies sorgt für astronomisch hohe Verwerfungsraten, so dass es mit
dieser Methode unmöglich ist, die Boltzmann-Verteilung abzutasten. In der statistischen
Physik benutzt man als Ausweg das Monte-Carlo-Sampling von N. Metropolis.
Ziel dieser Methode ist es, nacheinander Punkte xi zu erzeugen, die PT -verteilt sind,
so dass die Folge xi unsere Verteilung repräsentiert. Nehmen wir nun an, dass unser
aktueller Punkt bereits PT -verteilt gezogen wurde, müssen wir also den nächsten Punkt
so wählen, dass wir die Verteilung nicht ändern. Dazu wählen wir zufällige Übergänge
xi → xi+1 so, dass für zwei beliebige Punkte x und y die Übergänge x → y und y → x
mit gleicher Wahrscheinlichkeit ausgewählt werden. Eine Möglichkeit ist der klassische
Metropolis-Schritt
y = xi + d, mit d gleichverteilt auf einer Kugel vom Radius r.
(9.48)
r ist dabei in gewisser Weise die maximale Schrittweite dieses Algorithmus. Dies erzeugt
eine Gleichverteilung der Punkte; um die korrekte Verteilung zu erzeugen, setzen wir
xi+1 = y mit Wahrscheinlichkeit proportional zu
p(y) = min(e−β[E(y)−E(xi )] , 1) = min(P (y)/P (xi ), 1).
(9.49)
Ist also E(y) ≤ E(xi ), akzeptieren wir den Schritt immer, ist E(y) > E(xi ), dann mit
Wahrscheinlichkeit e−β[E(y)−E(xi )] . Die Verwerfungsmethode liefert uns einen einfachen
Algorithmus, diese Verteilung zu erzeugen — wir ziehen eine Standardzufallszahl u und
setzen xi+1 = y, falls u < p(y) und xi+1 = xi sonst.
Beim Simulated Annealing werden die Punkte mit Hilfe der Metropolis-Methode PT verteilt erzeugt, und gleichzeitig die Temperatur langsam abgesenkt. Dadurch sollte die
Verteilung langsam gegen P0 konvergieren, in der nur noch das oder die globalen Minima eine nichtverschwindende Wahrscheinlichkeit haben. Dementsprechend konvergiert
die Folge xi gegen ein globales Minimum. Problematisch kann sein, dass die korrekte Verteilung der xi natürlich nur sichergestellt werden kann, wenn auch hinreichend viele xi
generiert werden. Das bedeutet, dass die Temperatur langsam abgesenkt werden sollte,
wobei “langsam” vom Problem abhängt.
Die funktionale Form der Temperaturkurve ist frei wählbar. Typischerweise wählt man
eine exponentielle Form
Ti+1 = (1 − δ)T
(9.50)
mit kleinem δ > 0 (etwa 10−6 ). Dann wird natürlich T = 0 nie erreicht, allerdings sind
kleine T meist ausreichend. Alternativ kann man eine lineare Form wählen
Ti+1 = Ti − δ, solange Ti > δ.
180
(9.51)
9.4 Globale Optimierung
0
10
20
30
² =0.1
² =0.05
40
50
60
² =0.01
² =0.001
70
103
104
105
Simulationsschritt
106
Abbildung 9.7: Simulated Annealing eines zweidimensionalen Salzschmelzemodells. Links
sind die gefundenen Grundzustände für verschiedene Abkühlraten gezeigt, rechts die
dazugehörigen potentiellen Energien als Funktion der Zeit (schwarz gepunktet = 0,1,
grün durchgezogen = 0,05, blau gestrichelt = 0,01 und magentafarbene Strichpunkte
= 0,005). Der eigentlich Grundzustand wäre ein NaCl-artiges Gitter, das aber nicht
gefunden wird, auch wenn die Simulationen immer größere Gitterflächen zeigen. Die
Unterschiede in den finalen Energien sind sehr klein, was nochmals zeigt, dass auch
dieses Problem sehr viele Nebenminima aufweist.
Simulated Annealing funktioniert nicht nur mit dem Metropolis-Schritt, sondern auch
mit allen anderen möglichen Monte-Carlo-Schritten, wie sie in der Vorlesung „Simulationsmethoden“ behandelt werden. Auch Molekulardynamik kann genutzt werden, um
Zustände im kanonischen Ensemble, also bei konstanter Temperatur, zu erzeugen.
Beispiel: zweidimensionale Salzschmelze
Als Beispiel zeigt Abbildung 9.7 Daten zur Kristallisation eines einfachen NaCl-Modells.
Hier wechselwirken die Teilchen mit einem Potential
( √
12
6
σ
σ
4 kxi −x
−
+ für kxi − xj k < 6 2σ
4σ
kxi −xj k
jk
φij = qi qj
(9.52)
+
r
0
sonst.
Die Hälfte der Teilchen haben dabei Ladung qi = 1, die andere Hälfte qi = −1. Der erste
Teil des Potentials ist das Coulombpotential aufgrund der elektrostatischen Anziehung
bzw. Abstoßung, der zweite besteht aus dem repulsiven Teil des LJ-Potentials und simuliert die Volumenausschlußwechselwirkung. Die Teilchen arrangieren sich aufgrund des
Volumenausschlusses recht schnell in einem Gitter, es kostet allerdings sehr viel Energie,
dann Plätze zu tauschen. Daher gibt es zahlreiche Nebenminima.
181
9 Optimierung
Im Beispiel wurde statt des Metropolisalgorithmus eine Molekulardynamiksimulation
mit Hilfe von ESPResSo [Esp] benutzt. Auch hier kann die Temperatur gesteuert werden.
Links zeigt Abbildung 9.7 die gefundenen Annäherungen für Grundzustände, rechts sind
deren Energien gezeigt. Trotz der recht langen Simulationszeiten sind die gefundenen
Grundzustände noch nicht optimal — das wäre ein quadratisches Gitter mit alternierender Besetzung. Eine Monte-Carlo-Simulation könnte hier übrigens deutlich effizienter
sein, allerdings nur, wenn auch sogenannte Identitätstauschschritte benutzt werden, bei
denen zwei beliebige Teilchen ihre Ladungen austauschen und so die Energiebarrieren
umgehen.
9.4.2 Genetische Algorithmen
Für die Untersuchung noch komplexerer Kristallstrukturen, etwa mit -3- und 5-wertigen
Ionen, ist der obige Ansatz immer noch nicht effizient genug, da er dazu neigt, in lokalen
Minima stecken zu bleiben. Besser wäre es, Elementarzellen des Kristalls durchzuprobieren, und nach derjenigen mit minimaler Energie zu suchen. Leider ist auch diese Optimierung noch sehr umfangreich, und die Menge der möglichen Kristallstrukturen lässt
sich nicht einfach als Vektorraum beschreiben.
In solchen Fällen sind genetische Algorithmen ein biologisch inspirierter Ansatz, um
trotzdem eine globale Minimierung durchführen zu können. Dabei ist das Genom nicht
mehr ein DNS-Molekül, sondern eine Zeichenkette aus reellen Zahlen, Bits oder ähnlichem, die jeweils ein Element der ursprünglichen zulässigen Menge codieren (also zum
Beispiel eine mögliche Elementarzelle). Wir erzeugen zu Beginn der genetischen Algorithmus zufällig eine große Menge von Individuen (etwa einige 1000), indem wir zufällige
entsprechende Zeichenketten generieren.
Wie bei der natürlichen Evolution sollen sich im Verlauf die „fittesten“ Individuen
sich vermehren und ungeeignetere aussterben. Dazu definieren wir eine Fitnessfunktion,
die die Güte eines Genoms bzw. des dadurch codierten Individuums misst. Im Falle der
Kristallgitteroptimierung wäre dies zum Beispiel die Energie eines Gitters, dass aus der
Elementarzelle entsteht, die vom Genom codiert wird.
Wie werden nun Individuen vermehrt? Einfach, indem zufällige, kleine Änderungen
am Genom des sich vermehrenden Individuums vorgenommen werden und dieses neue
Genom in den Pool der vorhanden Individuen aufgenommen wird. Dabei werden fittere
Individuen häufiger vermehrt. Das kann man auf verschiedene Weisen erreichen, zum
Beispiel, indem stets eine kleine Anzahl von Individuen zufällig ausgewählt wird, und
von diesen das fitteste vermehrt. Dabei gibt es zwei Typen von Änderungen am Genom:
Mutationen, also kleine zufällige Änderungen im Genom, und Kreuzungen zweier guter
Individuen. Dabei werden zufällig Abschnitte der beiden ausgewählten Individuen zu
einem neuen Genom kombiniert.
Um die Menge der Genome konstant zu halten, können bei diesem Prozess auch Genome entfernt werden. Werden etwa die fittesten Individuen einer zufällig gewählten
Gruppe zur Vermehrung herangezogen, kann gleichzeitig das am wenigste fitte Element
dieser Gruppe gelöscht werden.
L. Filion und M. Dijkstra [FD09] haben einen solchen Algorithmus benutzt, um die
182
9.4 Globale Optimierung
möglichen Kristallstrukturen in binären kolloidalen Kristallen mit verschiedenen Größen und Ladungen vorherzusagen. Dabei werden die Elementarzellen durch eine feste
Anzahl von Vektoren dargestellt. Hat die Elementarzelle n Elemente, stellen n − 1 Vektoren Bi die Relativpositionen der Elemente in der Zelle dar, und 3 Vektoren Li legen
die Relativpositionen der räumlichen Kopien der Elementarzelle fest. In den meisten
zufällig so erzeugten Gittern überlappen Teilchen, so dass auch in diesem Fall ein weiches Lennard-Jones-Potential die Volumenausschlusswechselwirkung modelliert. Dadurch
werden undefinierte Energiewerte vermeiden.
Zur Vermehrung werden zufällig zwei Individuen gewählt, deren Vektoren Bi zufällig
um maximal ±10% gestreckt werden. Dann wird zufällig B1 , . . . , Bk vom ersten Individuum mit Bk+1 , . . . , Bn vom zweiten kombiniert, und analog die Li . Zusätzlich wird sicher
gestellt, dass die Li linear unabhängig sind, also tatsächlich ein Gitter aufspannen. Um
die Chancen des neuen Genoms zu erhöhen, wird für dieses die Energie lokal minimiert,
indem die Darstellung geeignet verdreht wird. Es ist durchaus üblich, physikalisches Wissen in genetischen Algorithmen zu benutzen, um bessere Genome zu erzeugen.
183
10 Differentialgleichungen
Fast alle physikalischen Vorgänge können durch Differentialgleichungen (DGLs) beschrieben werden, von der Schrödingergleichung für Quantensysteme, über die Newtonschen
Bewegungsgleichungen bis hin zu den Navier-Stokes-Gleichungen für Strömungen. Auch
das einleitende Problem des Fadenpendels wurde durch die Differentialgleichung
g
α̈ = − sin(α)
l
(10.1)
beschrieben. Die analytische Lösung dieser und der meisten Differentialgleichungen ist
schwierig oder unmöglich, und daher sind numerische Verfahren zum Lösen von DGLs
wichtige Hilfsmittel, um diese trotzdem untersuchen zu können.
Im Folgenden werden wir numerische Löser für verschiedene Klassen von Differentialgleichungen kennenlernen. Für gewöhnliche Differentialgleichungen mit skalarer Variable
sind das die Runge-Kutta-Verfahren, sowie das bereits in der Einleitung besprochene,
sehr gebräuchliche Velocity-Verlet-Verfahren.
Schwieriger ist die Lösung partieller Differentialgleichungen, die mehrdimensionale Variablen und deren Ableitungen enthalten. Diese spielen in der Physik eine besonders
wichtige Rolle, weil sie bei bei zeit- und ortsabhängigen Prozessen quasi automatisch
auftreten. Sie werden meist mit Hilfe finiter Element-Methoden behandelt, die aber zu
komplex sind, um sie in dieser Vorlesung einzuführen. Wir lernen stattdessen einige Beispiele von partiellen DGLs kennen und wie diese mit Hilfe finiter Differenzen oder Fouriertransformationen numerisch gelöst werden können.
10.1 Gewöhnliche Differentialgleichungen
Wir betrachten Differentialgleichungen der Form
f (m) (t) = F (t, f (t), f˙(t), . . . , f (m−1) (t))
(10.2)
mit f : R → Rn . Diese heißen gewöhnlich, da sie nur von einer skalaren Variablen,
t, abhängen. Wie der Name t schon vermuten lässt, wird diese Variable meist mit der
Zeit assoziiert. Die spezielle Form (10.2) wird auch explizite gewöhnliche Differentialgleichung m-ter Ordnung genannt, da wir voraussetzen, dass sich die Gleichung global
nach f (m) (t) auflösen lässt, und m Ableitungen involviert sind. Implizite Gleichungen
der Form F (t, f (t), f˙(t), . . . , f (m) (t)) = 0 sind numerisch sehr viel schwieriger zu lösen,
tauchen aber in der Physik auch seltener auf, und werden daher hier nicht weiter besprochen.
185
10 Differentialgleichungen
Für die numerische Lösung beschränken wir uns weiter auf gewöhnliche Differentialgleichungen erster Ordnung, also von der Form
f˙(t) = F (t, f (t)), f (0) gegeben.
(10.3)
Dies ist keine wirkliche Einschränkung, da sich jede explizite Differentialgleichung m-ter
Ordnung in eine höherdimensionale Gleichung erster Ordnung transformieren lässt:

 

f (t)
f˙(t)
 

˙
f¨(t)
d 
 f (t)  

(10.4)

=

..
..
dt 
 

.
.
f (m−1) (t)
f (m) (t) = F (t, f (t), f˙(t), . . . , f (m−1) (t))
Die Differentialgleichung des einleitenden Beispiels
g
α̈(t) = − sin α(t),
l
(10.5)
wird so zum Beispiel zu
d
dt
α(t)
α̇(t)
=
.
α̇(t)
− gl sin α(t),
(10.6)
Der Startwert ist genau wie im Eingangskapitel (α(0), α̇(0)), also Anfangsposition und
-geschwindigkeit.
10.1.1 Runge-Kutta-Verfahren
Wir suchen suchen eine diskretisierte Näherung yn ≈ f (tn ) für das Problem (10.3) mit
äquidistanten Zeitpunkten tn = nh, n = 0,1, . . ., also Schrittweite h. Es gilt
Z tn +h
Z tn +h
˙
F [t, f (t)] dt.
(10.7)
f (t) dt = f (tn ) +
f (tn+1 ) = f (tn + h) = f (tn ) +
tn
tn
Da y0 = f (0) gegeben ist, liegt es nahe, y1 ≈ f (h) durch numerische Integration zu
bestimmen, dann y2 ≈ f (2h) durch numerische Integration aus y1 und so weiter. Das
Problem dabei ist, dass der Integrand F [t, f (t)] die zu findende Funktion f enthält. Um
also f (t) an Stellen t ∈ [tn , tn + h] annähern zu können, müssen wir einige Werte von
f in diesem Intervall wiederum durch Integration gewinnen. Dies führt zur allgemeinen
Form eines s-stufigen Runge-Kutta-Verfahrens
yn+1 = yn + h
s
X
bj kj
(10.8)
j=1
mit den Näherungen für F [tn + hcj , f (tn + hcj )]
kj = F (t + hcj , yn + h
s
X
k=1
186
ajk kk ).
(10.9)
10.1 Gewöhnliche Differentialgleichungen
b, c ∈ Rs und A = (ajk ) ∈ Rs,s sind dabei Konstanten, die das Verfahren beschreiben.
c gibt die Zeitpunkte an, an denen F [t, f (t)] im Intervall [t, t + h] angenähert wird, in
Vielfachen der Schrittweite h. ci = 0 besagt also, dass ki ≈ F [tn , f (tn )], ci = 1, dass
ki ≈ F [tn + h, f (tn + h)]. A gibt die Quadraturgewichte für die Zwischennäherungen an,
b die Quadraturgewichte der Endnäherung. Diese Konstanten sind dabei nicht nur von
F unabhängig, sondern auch von der Schrittweite h, so dass ein Runge-Kutta-Schema
durch Verkleinern der Schrittweite im Prinzip beliebig genau gemacht werden kann. Die
Zwischenwerte kj erscheinen auf beiden Seiten von (10.9), es handelt sich also um ein
gekoppeltes, implizites Gleichungssystem. Ist F (t, y) eine nichtlineare Funktion, ist eine
solche Gleichung nur aufwändig zu lösen.
Daher werden meist explizite Runge-Kutta-Verfahren verwendet, bei denen A eine linke untere Dreiecksmatrix mit Nulldiagonale ist, also ajk = 0 für k ≥ j. Dann werden zur
Berechnung von kj nur kk , k = 1(1)j − 1 benötigt, die bereits berechnet sind. Eine Implementierung eines Runge-Kutta-Verfahrens ähnelt dann sehr dem Gauß-Seidel-Verfahren,
dass ebenfalls die Zeilen der zu lösenden Matrix sequentiell abarbeitet.
Dass man trotzdem auch implizite Verfahren, also mit allgemeiner Matrix, in Betracht
zieht, hängt damit zusammen, dass diese stabiler sind, und auch sogenannte steife DGLs
lösen können. Ist A linke untere Dreiecksmatrix, aber die Diagonale nicht Null, spricht
man von DIRKs, diagonal-impliziten Runge-Kutta-Verfahren. Diese lassen sich noch mit
verhältnismäßig begrenztem Aufwand lösen, da pro kj lediglich eine eindimensionale
Gleichung gelöst werden muss.
Der Fehler von Runge-Kutta-Verfahren wird üblicherweise durch die Konvergenz- und
Konsistenzordnung beschrieben. Die Konvergenzordnung p besagt, dass die Näherung
gleichmäßig gegen f (tn ) konvergiert, also max kyn − f (tn )k = O(hp ). Die Konvergenz ist
meist schwer zu beweisen, einfacher ist die Konsistenzordnung p, die nur fordert, dass
kyn+1 − f (tn+1 )k = O(hp ), falls yn = f (tn ). Konsistenz besagt also lediglich, dass ein
Schritt prinzipiell konvergiert. Ist die Funktion F Lipschitz-stetig, also etwa genügend
glatt, dann gilt allerdings Konsistenzordnung = Konvergenzordnung.
Im Folgenden werden einige der gebräuchlicheren Runge-Kutta-Verfahren angegeben.
Dabei hat sich das Butcher-Tableau
c
A
bT
als kurze Darstellung etabliert. Die j-te Zeile gibt dabei an, zu welchen Zeitpunkt tn +hcj
die Näherung kj berechnet wird und welchen Quadraturgewichte benutzt werden. bj sind
die Quadraturgewichte der für die finale Integration zu yn+1 .
Die Konstanten ergeben sich im Prinzip aus den benutzten Quadraturformeln. Allerdings gibt es neben der Bedingung, dass die Formeln möglichst explizit sein sollten, noch
weitere Stabilitätsbedingungen, die hier aber nicht beschrieben werden können. Daher
kann man nicht einfach beliebige Quadraturformeln kombinieren, sondern sollte bei den
im Folgenden beschriebenen, gebräuchlichen Formeln bleiben.
187
10 Differentialgleichungen
Explizites Eulerverfahren
0
1
Dieses Butcher-Tableau besagt nichts anders, als dass
yn+1 = yn + hF (tn , yn ) ≈ f (tn ) + hf 0 (tn ).
(10.10)
Es handelt sich als um die direkte Integration per Rechteckregel, und damit um ein
Verfahren der Ordnung 1, d.h. mit globalem Fehler O(h). Dieses Verfahren entspricht
der einfachen Integration (1.11) im einleitenden Beispiel. Das explizite Eulerverfahren ist
nicht sehr genau und nur für global Lipschitz-stetige F stabil. Daher sollte man es bei
praktischen Anwendungen im Allgemeinen vermeiden.
Implizites Eulerverfahren
1
1
1
Wie der Name schon sagt, ist dies ein implizites Verfahren, genauer, ein DIRK, bei dem
in jedem Schritt die Gleichung
k1 = F (tn+1 , yn + hk1 )
(10.11)
gelöst werden muss, um die neue Näherung yn+1 = yn + hk1 zu berechnen. Durch Einsetzen ergibt sich
yn+1 = yn + hF (tn+1 , yn+1 ),
(10.12)
das implizite Eulerverfahren ist also ebenfalls eine Rechteckregel, aber mit dem neu zu
bestimmenden Punkt yn+1 als Aufpunkt. Die Ordnung dieses Verfahrens ist daher ebenfalls 1. Anders als das explizite Eulerverfahren ist das implizite Eulerverfahren allerdings
ziemlich stabil, auch wenn F nicht Lipschitz-stetig ist. Der Nachteil ist, dass in jedem
Schritt eine nichtlineare Gleichung gelöst werden muss, was das Verfahren recht aufwändig macht.
Das Runge-Kutta-Verfahren
0
188
1/2
1/2
1/2
0
1/2
1
0
0
1
1/6
1/3
1/3
1/6
10.1 Gewöhnliche Differentialgleichungen
Dies ist das klassische Runge-Kutta-Verfahren, das zuerst 1901 von Kutta beschrieben
wurde. Wird in der Literatur von „dem Runge-Kutta-Verfahren“ ohne weitere Angaben
gesprochen, ist daher dieses Verfahren gemeint. Bei genügend glattem f hat es Konvergenzordnung 4, ist also deutlich besser als die Eulerverfahren.
Wie können wir das Tableau verstehen? Wir setzen τ = h/2. Die zweite und dritte Zeile
bestimmen zwei Näherungen für F [tn + τ, f (tn + τ )], zunächst mit Hilfe der linken (k2 ),
und dann der rechten Ableitung (k3 ). k4 ist dann eine Näherung für F [tn + h, f (tn + h)].
Diese Näherungen werden in die Simpsonregel eingebracht, wobei k2 und k3 mit gleichen
Gewichten eingehen.
Beispielimplementation
Eine Python-Implementation des allgemeinen Runge-Kutta-Schemas für ẏ(t) =f[t, y(t)],
y(0) = y0 könnte wie folgt aussehen:
from numpy import *
def rk_explicit(verfahren, f, y0, tmax, h):
def step(hc, hA, hb, f, yn, tn):
"ein einzelner Schritt"
k = []
for i in range(len(hc)):
k.append(f(tn + hc[i], yn + dot(hA[i,:i], k[:i])))
return yn + dot(hb, k)
# Zur Beschleunigung skalierte Parameter vorberechnen
hA = h*verfahren[’A’]
hc = h*verfahren[’c’]
hb = h*verfahren[’b’]
# Startwert und -zeit
tn = 0.0
yn = y0.copy()
# Ergebnisvektor mit Zeit und Punkten
result = [ concatenate(((tn,), yn.copy())) ]
while tn < tmax:
yn = step(hc, hA, hb, f, yn, tn)
tn += h
result.append(concatenate(((tn,), yn.copy())))
return array(result)
Die Lösung y(t) kann dabei auch vektorwertig sein, dann müssen y0 und der Rückgabewert der Funktion f gleich große NumPy-Arrays sein. Die Integration findet stets von
t = 0 bis tmax statt, in Schritten der Weite h. Die Routine liefert das Ergebnis als Matrix aus den Zeit- und Lösungspunkten zurück. Die erste Spalte enthält den Zeitpunkt
tn , die zweite die erste Komponente von yn , die dritte die zweite Komponente usw.
Die Funktion rk_explicit kann beliebige, explizite Runge-Kutta-Verfahren durchführen. Dazu erwartet sie als ersten Parameter ein Wörterbuch, dass das Butchertableau
189
Populationen
300
250
200
150
100
50
00
300
250
200
150
100
50
00
500
400
2
4
6
8
10
Räuber
Populationen
10 Differentialgleichungen
300
200
100
2
4
6
8
Zeit in Jahren
10
00 50 100 150200 250 300 350 400
Beute
Abbildung 10.1: Lösungen der Lotka-Volterra-Gleichungen mit dem einfachen Eulerverfahren (oben links) und dem Runge-Kutta-Verfahren (unten links). Blau gepunktet ist
die Beutepopulation, rot gestrichelt die Räuberpopulation. Rechts das Räuber-BeuteDiagramm für das Eulerverfahren (blau gestrichelt) und das Runge-Kutta-Verfahren (rot
durchgezogen). Während das Verfahren vierter Ordnung die erwartete periodische Trajektorie ergibt, wächst mit dem Eulerverfahren die Spitzenpopulation immer weiter. Dies
zeigt die Instabilität des Eulerverfahrens.
für das zu benutzende Runge-Kutta-Verfahren beschreibt. Für das Eulerverfahren und
das klassische Runge-Kutta-Verfahren sehen solche Wörterbücher so aus:
# Butchertableau fuer das explizite Eulerverfahren
euler = { ’c’: array((0,)),
’A’: array(((0,),)),
’b’: array((1,)) }
# Butchertableau fuer das klassische Runge-Kutta-Verfahren
rk_klassisch = { ’c’: array((0,0.5,0.5,1)),
’A’: array(((0 , 0, 0),
(0.5, 0, 0),
(0 ,0.5, 0),
(0 , 0, 1),
)),
’b’: array((1./6,1./3,1./3,1./6))}
10.1.2 Beispiel: Lotka-Volterra-Gleichungen
Die Lotka-Volterra-Gleichungen sind nach A. J. Lotka und V. Volterra benannt, die diese
1925 als einfaches Modell für die Populationsdynamik eines Räuber-Beute-Systems ange-
190
10.1 Gewöhnliche Differentialgleichungen
geben hatten, also, wie sich die Populationsgrößen von Räubern und Beute im zeitlichen
Verlauf ändern. Die Gleichungen beruhen auf stark vereinfachenden Annahmen, nämlich,
dass den Beutetieren unbegrenzte Resourcen zur Verfügung stehen, während die Räuber
ausschließlich auf die Beutetiere angewiesen sind. Trotzdem lassen sich die qualitativen
Vorhersagen dieses Modells in der Natur verifizieren, an so unterschiedlichen Systemen
wie zum Beispiel Haie und Fische oder Wölfe und Hasen. Es gibt Erweiterungen mit begrenzten Resourcen, oder mehrstufigen Systemen (also etwa Haie, Fische und Plankton),
die aber nicht wesentlich mehr zum Verständnis beitragen.
Die klassischen Lotka-Volterra-Gleichungen sind zwei gekoppelte Differentialgleichungen für die Populationen NR der Räuber und NB der Beutetiere:
d NB
ANB − BNB NR
= F (NB , NR ) =
.
(10.13)
−CNR DNB NR
dt NR
Dabei gibt A die Vermehrungsrate der Beutetiere an, die nur von der aktuellen Populationsgröße abhängt und B die Rate, mit der ein Räuber ein Beutetier auffrisst. C gibt
die Sterberate der Räuber an, und D die Rate, mit der sich ein Räuber vermehrt, wenn
er ein Beutetier gefangen hat. Die Räuber müssen also Beutetiere fangen, um sich zu
vermehren, während die Beutetiere sich von selber vermehren. Sind also keine Räuber
vorhanden, vermehren sich die Beutetiere exponentiell, sind keine Beutetiere vorhanden,
sterben die Jäger exponentiell aus.
Im Folgenden betrachten wir ein solches System aus Hasen und Wölfen. Es sei A = 2
Hasen pro Jahr, d.h. ein Hasenpaar hat vier Nachkommen im Jahr, und B = 0,1, ein Wolf
fängt also im Schnitt alle 10 Jahre einen bestimmten Hasen. Die tatsächliche Fangrate
hängt natürlich von der Menge der Wölfe und Hasen ab. Gibt es viele Hasen oder Wölfe,
ist die Chance, dass irgendein Wolf irgendeinen Hasen fängt, gut. Die Wölfe hingegen
sind recht hungrig, wir setzen daher C = 12. Ein Wolf stirbt also in etwa einem Monat,
wenn er keinen Hasen fängt. Umgekehrt reicht ein Hase kaum, um sich zu vermehren,
daher setzen wir D = 0,1, so dass etwa 10 Hasen zur erfolgreichen Vermehrung gefressen
werden müssen.
Nachdem wir nun die Raten festgelegt haben, können wir zum Beispiel ein RungeKutta-Verfahren benutzen, um (10.13) zu lösen. Dazu müssen wir noch einen Startwert
festlegen, hier hundert Hasen und einen Wolf, und eine Schrittweite, die wir auf einen
Tag, also 1/365-tel, setzen. Abbildung 10.1 zeigt die resultierenden Populationen, einmal
als Funktion der Zeit und einmal als Räuber-Beute-Diagramm.
Charakteristisch für die Lotka-Volterra-Gleichungen ist ein periodisches Verhalten, wie
man analytisch zeigen kann. Dabei gibt es lediglich zwei Gleichgewichtszustände, den man
leicht bestimmen kann:
C
A
NB (A − BNR )
!
0=
=⇒ NB = NR = 0 oder NB =
und NR = .
(10.14)
NR (−C + DNB )
D
B
In unserem Fall wären die Populationen also bei NB = 120 und NR = 20 stabil. Unser
davon leicht abweichender Startwert sollte zu einer Trajektorie führen, die um diesen
Fixpunkt periodisch kreist. Dies ist auch tatsächlich der Fall, wenn das Runge-KuttaVerfahren, das vierte Ordnung hat, benutzt wird. Dabei ist gut zu beobachten, dass die
191
10 Differentialgleichungen
Wolfspopulation der Hasenpopulation folgt. Zunächst wächst die Hasenpopulation nahezu ungebremst exponentiell, bis die Wolfspopulation nachzieht. Daraufhin dezimieren
die Wölfe die Hasenpopulation rasch und sterben in der Folge selber nahezu aus. Dadurch nimmt die Hasenpopulation wieder exponentiell zu, und der Zyklus beginnt von
neuem. Das Nachlaufen der Räuberpopulation ist charakteristisch für die Lotka-VolterraGleichungen und kann auch in der Natur beobachtet werden.
Wird zur Integration statt des Runge-Kutta-Verfahrens das Eulerverfahren benutzt,
nehmen beide Populationen mit der Zeit immer weiter zu. Wie vorher gesagt, sind die
Lösungen der Lotka-Volterra-Gleichungen aber periodisch, sofern es Räuber gibt. Die Zunahme ist also nur ein numerisches Artefakt. Selbst wenn der Zeitschritt um einen Faktor
10 gesenkt wird, driften die mit dem Eulerverfahren berechneten Populationen während
der gezeigten 10 Jahre um etwa 10 Individuen. Dies zeigt eindrücklich die Instabilität
des Eulerverfahrens.
10.1.3 Velocity-Verlet-Verfahren
In der Einleitung hatten wir bereits besprochen, dass die Fadenpendelgleichung (10.5)
mit Hilfe des Velocity-Verlet-Verfahrens numerisch gelöst werden kann. Dieses dient zur
Lösung von Differentialgleichungen der Form
ẍ(t) = F [t, x(t)],
(10.15)
also gewöhnlichen Differentialgleichungen zweiter Ordnung, die nicht von der Geschwindigkeit x0 (t) = v(t) abhängen. Diese Form ist typisch für Bewegungsgleichungen mit konservativen Kräften, daher ist das Velocity-Verlet-Verfahren zum Beispiel das StandardVerfahren für die Propagation von klassischen Vielteilchensystemen und spielt eine wichtige Rolle in gängigen Programmen zur Molekulardynamik. Diese integrieren mit Hilfe
eben dieses Verfahrens die Bewegungsgleichungen für unter Umständen mehrere Milliarden Atome!
Auch bei dieser Methode wird die Lösung xn ≈ x(tn ) äquidistant mit Schrittweite h
diskretisiert und wie folgt berechnet:
h
F (tn , xn )
2
= xn + hvn+1/2
h
= vn+1/2 + F (tn+1 , xn+1 ).
2
vn+1/2 = vn +
xn+1
vn+1
(10.16)
Ähnlich wie bei den Runge-Kutta-Verfahren wird also ein Zwischenschritt bei h/2 eingelegt, allerdings nur für die Berechnung von vn+1/2 ≈ x0 (tn + h/2). Dabei wird dieselbe
Beschleunigung F (tn , xn ) in aufeinanderfolgenden Zeitschritten zweimal benötigt. In Molekulardynamiksimulationen mit vielen Atomen ist die Berechnung der Kräfte meist recht
teuer, daher speichert man die Kräfte üblicherweise zwischen.
192
10.1 Gewöhnliche Differentialgleichungen
Um die Ordnung dieses Verfahrens zu bestimmen, eliminieren wir die Geschwindigkeiten:
h2
F (tn , xn )
2
= xn + hvn−1/2 + h2 F (tn , xn )
xn+1 = xn + hvn +
= xn + xn − xn−1 + h2 F (tn , xn ) = 2xn − xn−1 + h2 F (tn , xn )
(10.17)
Die ist eine finite Differenz gemäß (6.14), für die
xn+1 − 2xn + xn−1
= F (tn , xn ) + O(h2 )
h2
(10.18)
gilt. Der Fehler in xn+1 ist also von der Größenordnung O(h4 ), sofern xn und xn−1 oder
vn exakt waren. Die Geschwindigkeiten haben offenbar einen Fehler der Ordnung O(h2 ).
Das Velocity-Verlet-Verfahren ist von der Implementation her vergleichbar einfach wie
das Eulerverfahren, aber anders als dieses recht stabil und hat, wie gezeigt, eine sehr
gute Konsistenzordnung, vergleichbar mit dem Runge-Kutta-Verfahren. Es hat aber noch
eine andere wichtige Eigenschaft: anders als die Runge-Kutta-Verfahren ist das Verfahren
symplektisch, was bedeutet, dass es keine Energiedrift zulässt, und zum anderen besonders
gut geeignet ist, in Molekulardynamiksimulationen Observablen über den Phasenraum
zu mitteln. Auch das Simulationspaket ESPResSo, mit dem zum Beispiel im vorigen
Kapitel die Simulationen zum Simulated Annealing durchgeführt wurden, oder das in
der Biophysik populäre NAMD [Nam] benutzen daher einen Velocity-Verlet-Integrator.
Beispielimplementation
Eine Python-Implementation des Velocity-Verlet-Verfahrens für ẍ(t) =F[t, x(t)] mit
x(0) = x0 und v(0) = v0 könnte wie folgt aussehen:
from numpy import *
def velocity_verlet(acc, x0, v0, tmax, h):
def step(acc, tn, xn, vn, h):
vn += 0.5*h*acc(tn, xn)
xn += h*vn
vn += 0.5*h*acc(tn, xn)
# Startwert und -zeit
tn = 0.0
xn = x0.copy()
vn = v0.copy()
# Ergebnisvektor
result = [ concatenate(((tn,), xn.copy(), vn.copy())) ]
while tn < tmax:
step(acc, tn, xn, vn, h)
tn += h
result.append(concatenate(((tn,), xn.copy(), vn.copy())))
return array(result)
193
10 Differentialgleichungen
Genau wie beim Runge-Kutta-Beispiel kann die Lösung x(t) auch vektorwertig sein, wenn
x0, v0 und der Rückgabewert der Beschleunigungsfunktion F gleichgroße NumPy-Arrays
sind. Integriert wird von t = 0 bis tmax in Schritten der Weite h. Die Routine liefert
das Ergebnis als Matrix aus den Zeit- und
Lösungspunkten sowie den Geschwindigkeiten
(k)
(k) (k)
(k)
zurück. Ein Eintrag hat also die Form t(k) , x1 , . . . ,xn , v1 , . . . ,vn .
Die obige Implementation ist nicht sehr effizient, da die Kraftfunktion in zwei aufeinanderfolgenden Zeitschritten zweimal an der selben Stelle ausgewertet wird, statt die
Werte zwischenzuspeichern.
Beispiel: 3-Körperproblem
Wir betrachten die klassischen Bahnen von Sonne, Erde und Mond unter Vernachlässigung anderer Himmelskörper und der nicht ganz korrekten Annahme, dass alle drei
Körper in einer Ebene kreisen. Dieses System hat den Vorteil, dass die Kreisbahn des
Mondes um die Erde sehr klein gegenüber der Kreisbahn des Erde-Mond-Systems um
die Sonne ist, so dass das Problem sehr unterschiedliche Längenskalen aufweist, die der
Integrator stabil integrieren muss.
Zwischen den Objekten mit Positionen ri und Massen mi wirkt die nichtrelativistische
Gravitationskraft
Gm1 m2
Fij = −
(ri − rj )
(10.19)
kri − rj k3
mit der Gravitationskonstanten G. Die gesamte Kraft auf ein Objekt berechnet sich als
X
Fi =
Fij .
(10.20)
j6=i
Letztere Gleichung gilt natürlich für ein beliebiges Mehrkörperproblem, nur die Paarwechselwirkungen Fij ändern sich je nach den wirkenden Kräften. Auf molekularer Ebene ist
die Gravitation vernachlässigbar, dafür wirken zum Beispiel elektrostatische und van der
Waals-Kräfte.
Wie eingangs besprochen, ist es sinnvoll, die Einheiten so zu wählen, dass die relevanten
Variablen in der Größenordnung von eins liegen, so dass man von einem Implementationsfehler ausgehen kann, wenn plötzlich sehr große Werte auftreten. In diesem Fall wählen
wir als Längeneinheit die astronomische Einheit, die dem mittleren Abstand zwischen
Sonne und Erde entspricht, und messen Zeiten in Jahren, was in etwa der Umdrehungszeit der Erde um die Sonne entspricht. Massen messen wir entsprechend in Erdenmassen
−2
mE . In diesem System ist zum Beispiel G = 1,1858 · 10−4 AU 3 m−1
E a . Die Sonne hat
333,000 Erdenmassen, der Mond wiegt hingegen nur 0,0123mE und befindet sich etwa 0,00257AU von der Erde entfernt. Das verdeutlicht nochmals die unterschiedlichen
Skalen, mit denen der Integrator zurechtkommen muss.
Abbildung 10.2 oben zeigt die resultierenden Bahnen der Erde um die Sonne und des
Monds um die Erde für die Dauer von 10 Jahren. Die Schrittweite beträgt ein 1/365-tel
Jahr, also etwa einem Tag, integriert wird mit dem Velocity-Verlet-Verfahren und dem
Runge-Kutta-Verfahren, die beide vierter Ordnung sind. Beide Verfahren reproduzieren
194
10.1 Gewöhnliche Differentialgleichungen
0.003
1.0
0.002
0.5
0.001
0.0
0.000
0.001
0.5
1.0
0.002
1.0
0.5
0.0
0.5
1.0 0.003
0.002
0.000
0.002
Gesamtenergie
56
58
60
62
64
0
20
40
Jahre
60
80
100
Abbildung 10.2: Oben: Simulierte Bahn der Erde um die Sonne während 10 Jahren (links)
und des Monds um die Erde während eines halben Jahres (rechts). Rot gestrichelt sind
die vom Velocity-Verlet-Verfahren berechneten Bahnen, blau gepunktet die des RungeKutta-Verfahrens. Rote Sterne bzw. blaue Rauten auf den Erdbahnen bezeichnen Punkte
im Abstand von 365 Tagen, also etwa einem Jahr. Aufgrund der kleinen Abstände sind
die Schwankungen in der Mondbahn größer, aber bei beiden Verfahren akzeptabel. Unten:
Energien bei einer Rechnung mit größerer Simulationslänge und Zeitschritt. Hier zeigt
sich die Symplektizität des Velocity-Verlet-Verfahrens, das die Energie im Mittel erhält,
während das Runge-Kutta-Verfahren driftet.
195
10 Differentialgleichungen
die Erd- und auch Mondbahnen recht gut, auch wenn die Mondbahn aufgrund der kleinen
Abstände stärkere Schwankungen zeigt. Auf der Erdbahn wurden Punkte im Abstand eines Jahres markiert, die, wie man erwarten würde, dicht beieinander liegen. Für die Qualität dieser Kurzzeitbahnen ist der Velocity-Verlet also mit dem Runge-Kutta-Verfahren
der gleichen Ordnung vergleichbar.
Im unteren Teil ist gezeigt, wie sich die beiden Verfahren verhalten, wenn nicht nur
deutlich länger, sondern auch mit größeren Zeitschritt simuliert wird. In diesem Fall ist
der Velocity-Verlet-Integrator überlegen, denn er zeigt zwar größere Energieschwankungen, erhält aber langfristig die mittlere Energie. Das Runge-Kutta-Verfahren hingegen
zeigt eine deutliche Energiedrift, die das System langfristig kollabieren lässt.
Man sollte allerdings beachten, dass für beide Integratoren die Mondbahnen vollkommen falsch sind, der Mond verlässt sogar seine Erdumlaufbahn! Für astrophysische Simulationen ist so etwas natürlich nicht akzeptabel, aber in der Molekulardynamik spielen die
exakten Trajektorien der Moleküle keine Rolle, da sie sowieso nicht gemessen werden können. Zudem sind molekulare Systeme hochchaotisch, d.h. selbst bei winzigen Störungen
weichen Trajektorien nach kurzer Zeit stark ab. In diesem Fall ist die Energieerhaltung
des Velocity-Verlet-Algorithmus sehr wichtig, denn sie garantiert, dass trotzdem das korrekte statistische Ensemble simuliert wird und die Messungen sinnvoll sind, selbst wenn
die Trajektoren selber nur auf sehr kurzen Zeitabschnitten sinnvoll sind.
10.2 Partielle Differentialgleichungen
Die numerische Lösung von partiellen Differentialgleichungen, also Differentialgleichungen in mehreren Variablen, ist erheblich komplexer. Meist werden diese Art von Differentialgleichungen über Finite-Element-Methoden (FEM) gelöst, andere Methoden sind
Finite-Volumen-Methoden (FVM) oder die Finite-Differenzen-Methode (FDM). In einigen Fällen können Differentialgleichungen auch durch schnelle Fouriertransformation
numerisch gelöst werden.
Die Finite-Differenzen-Methode hatten wir bereits bei der Lösung der Besselschen Differentialgleichung oder der Poissongleichung gesehen. Im Folgenden wird angerissen, wie
die Finite-Element-Methode funktioniert, sowie auf die Lösung einiger spezieller partieller
Differentialgleichungen eingegangen mit Hilfe finiter Differenzen oder Fouriertransformationen.
10.2.1 Finite-Element-Methode
Die Finite-Element-Methode (FEM) ist ein Verfahren zur Lösung partieller Differentialgleichungen der Form L · u = f , wobei L ein linearer Differentialoperator ist, f : Ω → Rn
eine konstante Funktion und u : Ω → Rn die gesuchte Lösung.
Die FEM beruht auf einer schwachen Formulierung der zu lösenden Differentialgleichung. Diese beschreibt u als diejenige, eindeutig bestimmte Funktion, die
Z
Z
Lu · v =
f · v ∀v ∈ C ∞ (Ω, Rn )
(10.21)
Ω
196
Ω
10.2 Partielle Differentialgleichungen
erfüllt. Schwach nennt man diese Formulierung, weil nur das zu Lu assoziierte Funktional
gleich dem zu f assoziierten Funktional sein soll, so dass die ursprüngliche Gleichung nur
noch fast überall erfüllt ist.
Nun wählt man statt der unendlich vielen Testfunktionen aus C ∞ (Ω, Rn ) einen endlichdimensionalen Unterraum V , zum Beispiel für n = 1 alle linearen Splines mit gegebenen, endlich vielen Stützpunkten. Sind die Funktionen vp , p = 1(1)N eine Basis dieses
Unterraums, dann lässt
P sich eine Näherungslösung u als Linearkombination in dieser Basis schreiben, u = N
p=1 up vp . Da L ein linearer Differentialoperator sein soll, wird aus
(10.21) ein gewöhnliches lineares Gleichungssystem:


Z
Z
N
N
X
X
!


f · vp = bp ∀p = 1(1)N.
(10.22)
uq vq · vP =
uq Apq =
L
Ω
q=1
Ω
q=1
Die Koeffizienten
Z
apq =
Lvq · vP
(10.23)
f · vp
(10.24)
Ω
und
Z
bp =
Ω
können wir zum Beispiel durch numerische Integration berechnen und das Gleichungssystem Au = b etwa mit dem SOR-Verfahren lösen.
Woher kommt der Name „finite Elemente“? Die FEM wird oft in Ingenieursanwendungen eingesetzt, also im n = 3-dimensionalen Raum. Dadurch enthält die Basis üblicherweise viele tausende Testfunktionen. Das bedeutet, dass wir das Koeffizientenintegral
(10.23) mehrere Millionen mal auswerten müssten. Um diesen Aufwand drastisch zu reduzieren, macht man sich zu Nutze, dass apq offenbar nur dann nicht verschwindet, wenn
sich die Träger von vp und vq , also die Bereiche, in denen die Funktionen nicht Null
sind, überschneiden. Daher wählt die Basisfunktionen so, dass sie nur sehr kleine Träger
haben.
Eine typische für die Testfunktionen sind lineare Splines. Dabei wird ein beliebiges
Dreiecksgitter über den Bereich Ω gelegt (Triangulierung), und die Testfunktionen als
linear auf diesen Dreiecken angenommen. Als Basis wählt man dann diejenigen Splines,
die nur an einem einzigen Stützpunkt ungleich Null sind, kleine Pyramiden sozusagen.
Dann gibt es nur dann Wechselwirkungen zwischen zwei Basisfunktionen, wenn diese eine
gemeinsame Kante haben, so dass fast alle Integrale apq = 0 sind, also A dünn besetzt.
Um die Genauigkeit zu verbessern, können zusätzliche Gitterpunkte eingefügt werden,
oder von vorne herein das Gitter dort feiner gewählt werden, wo die Funktion vermutlich
stark variiert (zum Beispiel in der Nähe einer Wärmequelle, wenn es um Wärmeleitung
geht). Dadurch sind FEM-Gitter sehr viel komplexer als die regulären kubischen Gitter,
die in dieser Vorlesung benutzt werden, und ihre Erzeugung selber schon eine Kunst. Da
FEM vor allem in den Ingenieurwissenschaften benutzt wird, gibt es aber sehr leistungsfähige, kommerzielle Softwarepakete für die FEM-Modellierung. Eine freie Alternative
ist das Softwarepaket DUNE [Ded+10; Ded+].
197
0.20
20
0.15
15
p(x,t)
p(x,t)
10 Differentialgleichungen
0.10
2.0
5
0
x
5
0 10
10
dt=0.010
dt=0.013
dt=0.014
1.5
1.0
m(t)
m(t)
10
5
0.05
0.00 10
t=5
t=20
t=80
t=500
0.5
0.00 10 20 30 40 50 60 70 80
t
140
120
100
80
60
40
20
00
5
0
x
5
10
100 200 300 400 500
t
Abbildung 10.3: Näherungen für die Diffusionsgleichung. Oben die Lösungen zu unterschiedlichen Zeitpunkten t für eine δ-verteilte Anfangsverteilung (links) und zwei Quellen
konstanter Rate 1 bei 0 und 1/2 bei -5 (rechts). Unten sind die korrespondieren Gesamtmassen angegeben. Für die δ-Verteilung sind die Gesamtmassen auch bei geringfügig
höheren Zeitschritten δt angegeben, wobei für δt = 0,014 die Näherung versagt.
10.2.2 Wärmeleitungsgleichung
Ist das interessante Gebiet Ω hinreichend einfach, reichen aber oft auch einfache finite
Differenzen, um partielle Differentialgleichungen zu diskretisieren. Wir betrachten nun
als Beispiel die Differentialgleichung
δ
δ2
p(x, t) = D 2 p(x, t).
δt
δx
(10.25)
Gesucht ist p : Rn × R → R, D ist ein freier Parameter, die Diffusionskonstante. Diese
Differentialgleichung hatten wir in Abschnitt 7.4 als Diffusionsgleichung kennengelernt.
Meist wird diese Gleichung aber als Wärmeleitungsgleichung bezeichnet, weil sie auch die
Wärmeleitung beschreibt. Auch die zeitabhängige Schrödingergleichung hat diese Form,
ist allerdings komplexwertig.
198
10.2 Partielle Differentialgleichungen
Um die Differentialgleichung zu lösen, diskretisieren wir wie gewohnt die Raumkoordinate äquidistant mit Abstand h. Für die zweite Ableitung kennen wir bereits eine einfache
Strategie: wir ersetzen sie durch eine finite Differenz auf dem Gitter, etwa (6.14). Das
ergibt die ortsdiskretisierte Differentialgleichung
δ
D
p(xn , t) = 2 (p(xn−1 , t) − 2p(xn , t) + p(xn+1 , t)) .
δt
h
(10.26)
Aus der partiellen Differentialgleichung ist eine gewöhnliche Differentialgleichung in t
geworden, mit Variablen p(x1 ,t), . . . ,p(xN , t), wobei N die Anzahl der Ortspunkte ist.
Diese DGL lösen wir nun mit dem Runge-Kutta-Verfahren. Das hat den großen Vorteil,
dass wir die Verteilungen p(xn , t), die bei großem N oder mehreren Dimensionen sehr
groß werden können, nur für wenige Zeitschritte speichern müssen.
Quellcode 10.1 zeigt den resultierenden Code, der die Runge-Kutta-Implementierung
aus diesem Kapitel als Black Box nutzt. Wir betrachten dabei nur das Intervall
[−L/2,L/2), dass wir mit N Punkten im Abstand h = L/N diskretisieren. Am Rand
benutzen wir diesmal keine periodischen Randbedingungen, sondern setzen die Funktion
außerhalb des Intervalls auf 0. Der Zeitschritt ist als δt = 0,01 gewählt, h = 0,1.
Abbildung 10.3 zeigt links die Diffusionsgleichung für D = 1/2 und eine δ-Verteilung
zum Zeitpunkt t = 0, was dem einfachen Random walk aus Abschnitt 7.4 entspricht.
In der Diskretisierung wird die δ-Funktion an der Stelle xn dadurch dargestellt, dass
p(xn ) = 1/h und p(xj ) = 0 sonst. Die beobachteten Verteilungen bei t = 5 und t = 80
entsprechen gut den entsprechenden Verteilungen in Abbildung 7.7.
In der unteren Reihe ist die zugehörige Gesamtmasse
Z L
X
p(x, t) dt ≈
hp(xn , t)
(10.27)
−L
aufgetragen. Bei unendlichem Intervall ist die Masse offenbar erhalten. In unserem Fall
ist die Masse ebenfalls zunächst erhalten und gleich 1, da wir ja mit einer δ-Verteilung
begonnen haben. Sobald die Verteilung am Rand des Intervalls ankommt, verlieren wir
dort wegen der Null-Randbedingung Masse.
Die Abbildung zeigt auch die (In-)Stabilität dieses Ansatzes. Durch geringfügige Vergrößerung des Zeitschritts von 0,01 auf 0,014 bei gleichem Gitterabstand wird die Lösung
nach nicht einmal hundert Schritten instabil und erreicht sogar negative Massen. Bei Änderung der Raumdiskretisierung muss der Zeitschritt ebenfalls angepasst werden. Je kleiner h, desto kleiner muss auch δt werden. Dies ist nicht durch das Runge-Kutta-Verfahren
bedingt, sondern eine Folge der finiten Differenzen in der Ortskoordinate.
Auf der rechten Seite ist die Lösung der Gleichung
δ
δ2
1
L
p(x, t) = D 2 p(x, t) + δ x +
+ δ(x)
(10.28)
δt
δx
2
4
mit zwei konstanten Teilchenquellen bzw. Heizungen dargestellt. Wir haben also eine
Quelle mit einem halben Teilchen pro Zeiteinheit bei −L/4 und eine zweite bei 0 mit
einem Teilchen pro Zeiteinheit. Wie man erwarten würde, nehmen die Verteilungen dabei
zu, bis eine stationäre Verteilung erreicht wird.
199
10 Differentialgleichungen
# Waermeleitungsgleichung mittels finiter Differenzen und RK4
#############################################################
from scipy import *
import matplotlib.pyplot as pyplot
from rk import rk_explicit, rk_klassisch
D = 0.5
L = 20.0
N = 200
tmax = 80
dt = 0.01
#
#
#
#
#
Diffusionskonstante
Kantenlaenge Simulationsbox
Punkte der Raumdiskretisierung
Zeitraum
Zeitschritt
# Raumdiskretisierung, Laplace mit 0-Randbedingung
h = L/N
Laplace = zeros((N,N))
for i in range(N):
if i > 0:
Laplace[i, i-1] = 1.0/h**2
Laplace[i, i]
= -2.0/h**2
if i < N-1: Laplace[i, i+1] = 1.0/h**2
# Startdichte: ein Teilchen in der Mitte
p0 = zeros(N)
p0[N/2] = 1.0/h
# p’ = f(t, p) = D*Laplace p
def f(t, p): return D*dot(Laplace, p)
tnpns = rk_explicit(rk_klassisch, f, p0, tmax, dt)
# Umpacken in getrennte Arrays fuer pyplot
# Nettomasse gleich mit berechnen
ts, ps, mass = [], [], []
for pt in tnpns:
ts.append(pt[0])
ps.append(pt[1:])
mass.append(sum(pt[1:]))
# Ausgabe
#############################################
figure = pyplot.figure(figsize=(8,6))
x = linspace(-L/2.0, L/2.0, N, endpoint=False)
# links: Verlauf
graph = figure.add_subplot(121)
for step in (int(5.0/dt), int(20.0/dt), int(tmax/dt)):
graph.plot(x, ps[step], label=("t=%0.1f" % ts[step]))
graph.legend()
# rechts: Masse
graph = figure.add_subplot(122)
graph.plot(ts, h*array(mass))
pyplot.show()
Listing 10.1: Python-Code zur Wärmeleitungsgleichung. Räumlich ist die Lösung mittels
finiter Differenzen erster Ordnung diskretisiert, zeitlich wird das Runge-Kutta-Verfahren
benutzt. Zusätzlich wird der Massenverlust durch die Randbedingungen dargestellt.
200
10.2 Partielle Differentialgleichungen
Diese lässt sich sogar analytisch bestimmen. Die stationäre Lösung erfüllt die PoissonGleichung
δ2
1
L
+ δ(x).
(10.29)
0 = D 2 p(x) + δ x +
δx
2
4
Die zugehörige Laplacegleichung hat aber im eindimensionalen Geraden als Lösung, die
die δ-Quellen verbinden. Die Steigungen ändern sich wegen der δ-Terme bei −L/4 um
0,5 und bei 0 um 1. Mit den Randbedingungen bei ±L/2 lassen sich die Steigungen
bestimmen, und damit auch die Masse 137,5 des Gleichgewichtszustandes, die in der
Simulation gut reproduziert wird.
10.2.3 Lösung der Poisson-Gleichung
Die eben schon genannte Poisson-Gleichung
∆Φ(x) = ∇ · ∇Φ(x) =
ρ(x)
(10.30)
spielt auch in der Elektrostatik eine zentrale Rolle, wobei Φ in diesem Fall das Potential,
ρ die Ladungsverteilung und die dielektrische Konstante ist. Im Kapitel 8 wurde bereits
erläutert, dass sich auch diese Gleichung gut mit Hilfe von finiten Differenzen lösen lässt,
und die Wiedergabe der stationären Lösung aus dem vorigen Abschnitt unterstreicht
dies.
Wie alle lineare partiellen Differentialgleichungen mit konstanten Koeffizienten, kann
Gleichung (10.30) unter periodischen Randbedingungen einfach in den Fourierraum überd = inω Φ̂. Zweimalige Anwendung ergibt
tragen werden, da ja ∇Φ
−n2 ω 2 Φ̂n = ρ̂n
(10.31)
wobei Φ̂n und ρ̂n die Fouriertransformierten von Φ und ρ gemäß (3.6.1) sind. Ist x mehrdimensional, wird entlang jeder Dimension nacheinander transformiert, und n2 entspricht
n · n = knk2 . Danach muss notwendigerweise ρ̂0 = 0 gelten, das System also ladungsneutral sein. Für die übrigen Frequenzen lässt sich die Poissongleichung nun ganz einfach
durch Φ̂n = −ρ̂n /(nω)2 lösen. Um also Φ(x) zu berechnen, transformieren wir eine diskrete Ladungsverteilung ρ mit Hilfe der FFT in den Fourierraum, lösen dort trivial die
Poissongleichung, und transformieren Φ̂ zurück.
Dieses Vorgehen spielt eine wichtige Rolle bei den sogenannten Particle-Mesh-EwaldMethoden zur Berechnung der Schwerkraft oder elektrostatischer Wechselwirkungen. Diese werden in den meisten Molekulardynamiksimulationen geladener System eingesetzt.
Kern dieser Methoden ist, die δ-Spitzen diskreter Punktladungen durch verschmierte,
normalverteilte Ladungen zu ersetzen, deren Wechselwirkung mit Hilfe von schnellen
Fouriertransformationen wie beschrieben im Fourierraum berechnet wird. Mit einer weiteren, kleinen Korrektur für die Ladungsverschmierung lassen sich so die elektrostatischen
Wechselwirkungen von Millionen von Teilchen in Bruchteilen von Sekunden auf einem
Großrechner berechnen.
Codebeispiel 10.2 zeigt die Lösung im Fourierraum für eine beliebige, zweidimensionale
Ladungsverteilung. In der Praxis ist die Umsetzung des Terms n−2 etwas komplizierter,
201
10 Differentialgleichungen
1.0
1.0
0.8
0.8
0.6
0.6
0.4
0.4
0.2
0.2
0.00.0
0.00.0 0.2 0.4 0.6 0.8 1.0
0.2
0.4
0.6
0.8
3.2
2.4
1.6
0.8
0.0
0.8
1.6
2.4
3.2
1.0
1.0
1.0
0.00200
0.00175
0.8
0.00150
0.00125
0.6
0.00100
0.4
0.00075
0.00050
0.2
0.00025
0.00.0 0.2 0.4 0.6 0.8 1.0 0.00000
0.8
0.6
0.4
0.2
0.00.0
0.2
0.4
0.6
0.8
1.0
Abbildung 10.4: Näherungslösung mit 50 × 50 Gitterpunkten für die Poissongleichung
∆Φ = ρ in freien Einheiten. Die Ladungsdichte ρ ist rechts oben gezeigt und beinhaltet
zwei normalverteilte Ladungen. Die Lösungen ΦFD mit finiten Differenzen (links oben)
und ΦFFT im Fourierraum mittels FFT (links unten) sind praktisch identisch. Dies zeigt
auch der relative Fehler |ΦFD − ΦFFT | / |ΦFFT | (rechts unten), der weniger als 2 Promille
beträgt.
202
10.2 Partielle Differentialgleichungen
# 2d-Poisson mittels Fourier
##############################################
from scipy import *
from numpy.fft import *
import matplotlib.pyplot as pyplot
L=1.0 # Kantenlaenge des Quadrats
N=50 # Punkte der Diskretisierung, gerade fuer FFT
h = L/N
# rho aufsetzen
rho = zeros((N, N))
s2 = 0.01 # Quadrat des Radius der Ladung im Zentrum
for i in range(N):
for k in range(N):
x, y = k*h, i*h
d2 = (x-0.5*L)**2 + (y-0.5*L)**2
rho[i, k] += 1/sqrt(2*pi*s2)*exp(-0.5*d2/s2)
# neutralisieren
rho -= sum(rho)/N**2
# Loesung per Fouriertransformation
##############################################
rho_fft = fft2(rho)
# Laplace-Operator (2 pi/n L)^2
for nx in range(N/2 + 1):
for ny in range(N/2+1):
if nx == 0 and ny == 0:
rho_fft[nx,ny] = 0
else:
n2 = (nx**2 + ny**2)*(2*pi/L)**2
rho_fft[
nx,
ny] /= n2
if nx > 0 and nx < N/2:
rho_fft[N-nx,
ny] /= n2
if ny > 0 and ny < N/2:
rho_fft[ nx, N-ny] /= n2
if nx > 0 and ny > 0 and nx < N/2 and ny < N/2:
rho_fft[N-nx, N-ny] /= n2
psi_fft = ifft2(rho_fft)
psi_fft = real(psi_fft)
# Ausgabe
#############################################
im = pyplot.imshow(psi_fft, interpolation="bilinear", origin="lower",
extent=(0,L,0,L))
pyplot.colorbar(im)
pyplot.show()
Listing 10.2: Lösung der Poisson-Gleichung im Fourierraum für = 1.
203
10 Differentialgleichungen
weil bei der diskreten Fouriertransformation die negativen Koeffizienten ja oberhalb der
positiven gespeichert sind (ρN −n = ρ−n ), und zwar in jeder Dimension. Falls N gerade
ist, ist außerdem ρN/2 = ρ−N/2 , so dass man Vorsorge treffen muss, dass dieser Wert nur
einmal durch n2 geteilt wird. Dies bedingt die Fallunterscheidungen in der Implementation des Laplace-Operators.
Die Ergebnisse stimmen bis auf eine additive Konstante gut mit den Berechnungen
mittels finiter Differenzen überein, wie Abbildung 10.4 zeigt. Die Konstante rührt daher,
dass die Lösung im Fourierraum stets eine verschwindende Null-Frequenz hat, also im
Mittel Null ist. Bei der Finite-Differenzen-Lösung wird hingegen der Wert von Φ an einer Stelle vorgegeben. Abgesehen davon beträgt der maximale Unterschied zwischen den
Lösungen weniger als 2 Promille, und zwar genau auf den Ladungen. Ist die Ladungsverteilung nicht glatt, so ist der Fehler größer, da die Fouriertransformation unstetiger
Funktionen ja nur langsam konvergiert.
10.2.4 Lösung der Poisson-Boltzmann-Gleichung
Als letztes Beispiel wollen wir eine wichtige Erweiterung der Poisson-Gleichung lösen,
die Poisson-Boltzmann-Gleichung. Für die Herleitung dieser Gleichung nehmen wir an,
dass neben der fixen Ladungsverteilung ρfix (x) noch ein gelöstes Salz aus einwertigen,
punktförmigen Ionen im System ist. Das Salz kann sich frei in einem Bereich Ω bewegen.
Dieser wird durch die charakteristische Funktion χ(x) charakterisiert, die für x ∈ Ω den
Wert 1 annimmt, und sonst 0 ist. Die räumliche Verteilung dieser Ionen im Gleichgewicht
ist durch die Boltzmannverteilung gegeben, also proportional zu e−qβΦ(x) , wobei β = kB T
mit der Boltzmann-Konstanten kB und Temperatur T . q ist dabei die Ladung der Ionen,
hier eine negative oder positive Elementarladung (für mehrwertige Salze kann man zeigen,
dass die Poisson-Boltzmann-Gleichung keine gute Näherung ist).
Das Potential erscheint also auch in der Verteilung der Ionen, so dass wir eine nichtlineare Differentialgleichung erhalten:


e Φ(x)
∆Φ(x) = −ρfix − c∞ qe e|−βq{z
} −qe
positive Ionen
e Φ(x)
 χ(x)
e|βq{z
}
negative Ionen
= −ρfix − 2c∞ sinh[−βqΦ(x)]χ(x).
(10.32)
c∞ ist dabei die Konzentration der Ionen weit von allen Ladungen entfernt, also dort, wo
Φ = 0. qe bezeichnet hier die Elementarladung, um einer Verwechslung mir der Eulerschen
Konstanten vorzubeugen. Durch die Multiplikation mit χ(x) befinden sich die Ionen nur
im zulässigen Bereich, unabhängig vom Potential.
Die Gleichung lässt sich etwas einfacher darstellen, wenn man die sogenannte Bjerrumlänge
qe2
lB =
(10.33)
4πkB T
einführt, und die dimensionslose Funktion ψ = βqe Φ sucht, für die dann
1
∆ψ(x) = −qfix − 2c∞ sinh[−ψ(x)]χ(x)
4πlB
204
(10.34)
10.2 Partielle Differentialgleichungen
2.0
2-
1.5
1.0
0.5
0.00.0
+
0.5
+
1.0
1.5
2.0
1.5
1.0
0.5
0.00.0
0.5
1.0
1.5
2.0
1.0
0.9
0.8
0.7
0.6
0.5
0.4
0.3
0.2
0.1
0.0
2.0
2-
1.5
1.0
0.5
0.00.0
1
0
1
2.5
2
2.0
3
1.5
4
1.0
5
0.5 1.80.0
0.0 1.6
0.5 1.4
1.2
1.0
1.0 0.8
1.5 0.6
0.4
2.0
0.2
0.00.0
+
0.5
+
1.5
1.0
2.0
1.0
0.9
0.8
0.7
0.6
0.5
0.4
0.3
0.2
0.1
0.0
0.5
1.0
1.5
2.0
0.5
1.0
1.5
2.0
Abbildung 10.5: Näherungslösung der Poisson-Boltzmann-Gleichung (10.34) mittels iterativer Lösung des diskretisierten Gleichungssystems. Die Ladungsdichte konvergiert innerhalb von zwanzig Schritten zu einer Genauigkeit von 10−2 . Links oben ist die resultierende Verteilung der negativen Ionen gezeigt, rechts oben der positiven Ionen. Da die
Ionen in die Bereiche der fixen Ladungen nicht eindringen können, ist dort die Ladungsdichte 0. Der ausgefranste Rand dieser Bereiche ist eine Folge der groben Diskretisierung.
Unten links ist das resultierende Potential dargestellt, rechts unten die Potentialverläufe
des Poisson-Boltzmann-Potentials (rot gestrichelt) und des reinen elektrostatischen Potentials (durchgezogen). Der obere der beiden Graphen zeigt ψ(1,y), der untere ψ(x, 1/2).
205
10 Differentialgleichungen
gilt. qfix = ρfix /qe gibt also die feste Ladungsverteilung in Elementarladungen an. lB ist
eine konstante, die das umgebende Medium beschreibt. Üblicherweise ist dieses Wasser,
für dass die Bjerrumlänge 0,7nm beträgt.
Die Poisson-Boltzmann-Gleichung wird zum Beispiel benutzt, um die Ladungsverteilung um makroskopische Ionen wie kolloidale Teilchen zu modellieren. Dadurch muss die
sehr große Menge an Salzionen nicht explizit modelliert werden, was die Zahl der Teilchen
in Grenzen hält. In der Biophysik wird die Poisson-Boltzmann-Verteilung auch gerne zur
Visualisierung der Ladungsverteilung von Proteinen benutzt.
Ist das Potential relativ flach, lässt sich die Poisson-Boltzmann-Gleichung mittels
sinh(ψ) ≈ ψ linearisieren und in manchen Geometrien analytisch lösen. Die volle, nichtlineare Poisson-Boltzmann-Gleichung muss aber numerisch gelöst werden. Dazu diskretisieren wir ψ wieder äquidistant in beiden Raumrichtungen, und ersetzen den LaplaceOperator durch eine finite Differenz. Im Prinzip könnten wir nun das Gleichungssystem
mit Hilfe des Newtonverfahrens lösen, einfach ist aber die iterative Lösung mittels
n
o
ψ (n+1) (x) = −∆−1 4πlB qfix + 2c∞ sinh[−ψ (n) (x)]χ(x) .
(10.35)
Dabei wird natürlich nicht die Inverse des diskretisierten Laplace-Operators berechnet,
sondern das Gleichungssystem gelöst. Da dies in jeder Iteration geschehen muss, berechnet man sinnvollerweise eine LR-Berechnung voraus, und benutzt in den Iterationen nur
eine schnelle Vorwärts- und Rückwärtssubstitution.
Listing 10.3 zeigt eine Implementation dieses iterativen Poisson-Boltzmann-Lösers, Abbildung 10.5 die Lösung für ein sehr einfaches System aus drei homogenen Ladungsscheiben in zwei Dimensionen (bzw. drei geladenen, unendlich langen Stäben). Die Scheibe
oben hat eine Gesamtladung von 2 Elementarladungen, die beiden unteren jeweils eine
Elementarladung. Das Salz ist 0,2-molar, die Längeneinheit entspricht einen Nanometer,
die Bjerrumlänge ist für Wasser gewählt, also 0,7nm. Wie erwartet finden sich die negativen Ionen bevorzugt in der Umgebung der beiden positiven Kugeln unten, die positiven
Ionen hingegen bei der größeren, negativen Kugel oben. In diesem Beispiel konvergiert
die Iteration in etwa zwanzig Schritten auf 10−2 Genauigkeit in der Ladungsverteilung.
Rechts unten zeigt Abbildung 10.5 schließlich zwei Schnitte durch das elektrostatische
Potential. Dies wurde einmal nur für die fixen Ladungen berechnet, und einmal für die
Poisson-Boltzmann-Lösung. Deutlich sichtbar ist, dass diese flacher ist als die das reine
elektrostatische Potential. Dies ist einfach zu verstehen, da die Ionen sich ja bevorzugt
um die entgegengesetzt geladenen Bereiche anlagern, und diese dadurch gegeneinander
abschirmen.
Obwohl im Beispiel die Auswirkungen auf das Potential scheinbar nur gering sind,
ist das Poisson-Boltzmann-Potential sehr verschieden vom klassischen elektrostatischen
Potential. Um dies zu zeigen, betrachten wir eine einzelne Punktladung. Dann ist das
Potential ψ radialsymmetrisch und erfüllt fern von der Ladung
∂2
2 ∂
ψ(r) = −8πlB c∞ sinh[−ψ(r)] ≈ 8πlB c∞ ψ(r),
(10.36)
ψ(r) +
2
∂r
r ∂r
wobei wir für die letzte Näherung annehmen müssen, dass ψ bereits hinreichend stark
abgefallen ist. Diese Gleichung, die sogenannte Debye-Hückel-Näherung, ist schließlich
∆ψ(r) =
206
10.2 Partielle Differentialgleichungen
√
analytisch lösbar und hat die Lösung ψ(r) = e−κr /r mit κ = 8πlB c∞ , wie man sich
leicht überzeugt. Das Coulomb-Potential ist also exponentiell gedämpft, wobei die charakteristische Länge der Dämpfung κ−1 ist. Für eine 0,1-molare Salzlösung (was in etwa
dem Zellplasma entspricht) beträgt sie nur etwa 1nm, d.h. es gibt praktisch keine elektrostatischen Wechselwirkungen über Distanzen größer als ein Nanometer.
207
10 Differentialgleichungen
# Einfacher iterativer Poisson-Boltzmann-Loeser
##############################################
from scipy import *
from scipy.linalg import *
import matplotlib.pyplot as pyplot
L
N
lb
cinf
tol
h
=
=
=
=
=
=
5.0
50
0.7
1e-3
1e-2
L/N
#
#
#
#
#
#
Kantenlaenge des Quadrats
Punkte der Diskretisierung
Bjerrumlaenge
Salzkonzentration am Rand, 1-mmolar
maximales Residuum
Schrittweite
# Fortran/NumPy-artige Indizierung
def linindex(x, y): return y + N*x
# Fixes rho und zugaenglichen Bereich aufsetzen.
# Ueberall dort, wo feste Ladung sitzt, geht es nicht hin
rho_fix, chi = zeros(N*N), zeros(N*N)
r = 0.1 # Radius der fixen Ladung im Zentrum
for i in range(N):
for k in range(N):
x, y = k*h, i*h
d = sqrt((x-0.5*L)**2 + (y-0.5*L)**2)
if d <= r:
rho_fix[linindex(i, k)] += 2/pi/r**2
chi[linindex(i,k)] = (rho_fix[linindex(i,k)] == 0.0)
# 2d-Laplace, 0-Rand (Neutral am Rand)
Laplace=zeros((N*N, N*N))
for y in range(N):
for x in range(N):
eqn = linindex(x,y)
Laplace[eqn, linindex(x,y)] = -4/h**2
if x < N-1: Laplace[eqn, linindex(x+1,y)] = 1/h**2
if x > 0:
Laplace[eqn, linindex(x-1,y)] = 1/h**2
if y < N-1: Laplace[eqn, linindex(x,y+1)] = 1/h**2
if y > 0:
Laplace[eqn, linindex(x,y-1)] = 1/h**2
# Iterativer Loeser
##############################################
psi = zeros(N*N) # Potential
lu = lu_factor(Laplace)
while True:
# aktuelle vollstaendige Ladungsdichte
rho = rho_fix + cinf*2*sinh(-psi)*chi
residual = dot(Laplace, psi)/(4*pi*lb) + rho
print "Residuum ist", norm(residual)
if norm(residual) < tol: break
psi = lu_solve(lu, -4*pi*lb*rho)
# Ausgabe der resultierende positiven Ionendichte
n = (cinf*exp(-psi)*chi).reshape((N,N))
im = pyplot.imshow(n, origin="lower", extent=(0,L,0,L))
pyplot.colorbar(im)
pyplot.show()
Listing 10.3: Python-Code zur Poisson-Boltzmann-Gleichung. Die Lösung wird räumlich
mittels finiter Differenzen erster Ordnung diskretisiert und anschließend durch Bestimmen des Potentials aus der aktuellen Ladungsdichte iterativ bestimmt.
208
Literatur
[AS70]
M. Abramowitz und I. Stegun. Handbook of mathematical functions. New
York: Dover Publications Inc., 1970.
[Dau92]
Ingrid Daubechies. Ten lectures on wavelets. Bd. 61. Society for Industrial
Mathematics, 1992.
[Ded+]
A. Dedner u. a. DUNE-FEM homepage.
http://dune.mathematik.uni-freiburg.de.
[Ded+10]
A. Dedner u. a. „A Generic Interface for Parallel and Adaptive Scientific
Computing: Abstraction Principles and the DUNE-FEM Module“. In:
Computing 90.3–4 (2010), S. 165–196.
[Esp]
ESPResSo homepage. url: http://espressomd.org.
[FD09]
L. Filion und M. Dijkstra. „Prediction of binary hard-sphere crystal
structures“. In: Physical Review E 79.4 (2009), S. 046714.
[GM78]
P.E. Gill und W. Murray. „Numerically stable methods for quadratic
programming“. In: Mathematical Programming 14.1 (1978), S. 349–372.
[Jac99]
J. D. Jackson. Classical Electrodynamics. Wiley, New York, 3rd edition,
1999.
[Knu81]
D.E. Knuth. The Art of Programming, vol. 2, Semi-Numerical Algorithms.
Addison Wesley, Reading, MA, 1981.
[Nam]
NAMD homepage. url: http://www.ks.uiuc.edu/Research/namd.
[Pin02]
Mark Pinsky. Introduction to Fourier Analysis and Wavelets. Brooks/Cole,
2002.
[Vmd]
VMD homepage. url: http://www.ks.uiuc.edu/Research/vmd.
209
Index
χ2 -Test
Symbols
. . . . . . . . . . . . . . . . . . . . . . . . . . . 119
A
Abtasttheorem . . . . . . . . . . . . . . . . . . . . . 53
Armijo-Schrittweite . . . . . . . . . . . . . . . 161
Ausgleichsrechnung . . . . . . . . . . . . . . . . 34
Autokorrelationsfunktion . . . . . . . . . . . 59
Autokorrelationstest . . . . . . . . . . . . . . 121
B
Banachscher Fixpunktsatz . . . . . . . . . 66
Bandmatrizen . . . . . . . . . . . . . . . . . . . . . . 23
Bisektion . . . . . . . . . . . . . . . . . . . . . . . . . . 72
Bisektionsverfahren . . . . . . . . . . . . . . . . 72
Box-Muller-Verfahren . . . . . . . . . . . . . 115
Butcher-Tableau . . . . . . . . . . . . . . . . . . 187
C
CG-Verfahren . . . . . . . . . . . . . . . . . . . . . 164
Chebyshev-Stützstellen . . . . . . . . . . . . . 31
Cholesky
-Verfahren . . . . . . . . . . . . . . . . . . . . . 22
-Zerlegung . . . . . . . . . . . . . . . . . . . . . 22
D
DFT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
Diagonalmatrizen . . . . . . . . . . . . . . . . . . 17
Differentialgleichung . . . . . . . . . . . . . . 185
explizite . . . . . . . . . . . . . . . . . . . . . . 185
gewöhnliche . . . . . . . . . . . . . . . . . . . 185
partielle . . . . . . . . . . . . . . . . . . . . . . 196
Differenzieren . . . . . . . . . . . . . . . . . . . . . . 79
Diffusionsgleichung . . . . . . . . . . . . . . . . 198
Diskrepanz . . . . . . . . . . . . . . . . . . . . . . . . 102
Dreibandmatrizen . . . . . . . . . . . . . . . . . . 23
Dreiecksmatrizen . . . . . . . . . . . . . . . . . . . 17
E
Eigenvektor . . . . . . . . . . . . . . . . . . . . . . . 150
Eigenwert . . . . . . . . . . . . . . . . . . . . . . . . . 150
Euler-McLaurin-Summenformel . . . . 92
Eulerverfahren
explizites . . . . . . . . . . . . . . . . . . . . . 188
implizites . . . . . . . . . . . . . . . . . . . . . 188
F
Fadenpendel . . . . . . . . . . . . . . . . . . . . . . . 10
Faltung . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
FEM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 196
FFT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
Fibonaccigenerator . . . . . . . . . . . . . . . . 110
verzögerter . . . . . . . . . . . . . . . . . . . 110
Filter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
Finite-Element-Methode . . . . . . . . . . 196
Fitting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
Fixpunktsuche . . . . . . . . . . . . . . . . . . . . . 65
Fourierreihen
komplexe . . . . . . . . . . . . . . . . . . . . . . 36
reelle . . . . . . . . . . . . . . . . . . . . . . . . . . 38
Fouriertest . . . . . . . . . . . . . . . . . . . . . . . . 120
Fouriertransformation
diskrete . . . . . . . . . . . . . . . . . . . . . . . . 40
komplexe . . . . . . . . . . . . . . . . . . . . . . 36
kontinuierliche . . . . . . . . . . . . . . . . . 49
reelle . . . . . . . . . . . . . . . . . . . . . . . . . . 38
schnelle . . . . . . . . . . . . . . . . . . . . . . . . 42
G
Gauß-Quadratur . . . . . . . . . . . . . . . . . . . 96
Gauß-Seidel-Verfahren . . . . . . . . . . . . 137
Gaußelimination . . . . . . . . . . . . . . . . . . . 18
211
Index
Givens-Rotation . . . . . . . . . . . . . . . . . . 147
Glättung . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
Gleichungssysteme
lineare . . . . . . . . . . . . . . . . . . . . 17, 133
nichtlineare . . . . . . . . . . . . . . . . . . . . 75
Gradientenabstiegsverfahren . . . . . . 161
Gram-Schmidt-Verfahren . . . . . . . . . . 140
modifiziertes . . . . . . . . . . . . . . . . . . 143
H
Halton-Folge . . . . . . . . . . . . . . . . . . . . . . 103
Horner-Schema . . . . . . . . . . . . . . . . . . . . . 25
Householder-Spiegelung . . . . . . . . . . . 144
Householder-Verfahren . . . . . . . . . . . . 144
I
Indexformat . . . . . . . . . . . . . . . . . . . . . . 136
indizierte Matrixspeicherung . . . . . . 136
Integration
Gauß-Quadratur . . . . . . . . . . . . . . . 96
Mittelpunktsregel . . . . . . . . . . 88, 90
Monte-Carlo- . . . . . . . . . . . . . . . . . . 99
Newton-Cotes-Formeln . . . . . 87, 89
numerische . . . . . . . . . . . . . . . . . . . . . 84
Quasi-Monte-Carlo- . . . . . . . . . . . 101
Rechteckregel . . . . . . . . . . . . . . . . . . 88
Romberg- . . . . . . . . . . . . . . . . . . . . . . 92
Simpsonregel . . . . . . . . . . . . . . . 88, 90
Trapezregel . . . . . . . . . . . . . . . . 87, 89
Interpolation . . . . . . . . . . . . . . . . . . . . . . . 27
Lagrange- . . . . . . . . . . . . . . . . . . . . . . 27
lineare . . . . . . . . . . . . . . . . . . . . . . . . . 32
Polynom- . . . . . . . . . . . . . . . . . . . . . . 27
Spline- . . . . . . . . . . . . . . . . . . . . . . . . . 32
interpolierendes Polynom
baryzentrische Darstellung . . . . . 29
Lagrangedarstellung . . . . . . . . . . . 29
Newtonsche Darstellung . . . . . . . . 30
inverse Iteration . . . . . . . . . . . . . . . . . . 153
Inversionsmethode . . . . . . . . . . . . . . . . 115
J
Jacobimatrix . . . . . . . . . . . . . . . . . . . . . . . 75
Jacobiverfahren . . . . . . . . . . . . . . . . . . . 135
212
K
Kongruenzgenerator
linearer . . . . . . . . . . . . . . . . . . . . . . . 108
konjugierter Gradient . . . . . . . . . . . . . 164
Korrelationsanalyse . . . . . . . . . . . . . . . . 56
Korrelationszeit . . . . . . . . . . . . . . . . . . . . 59
Kreuzkorrelationsfunktion . . . . . . . . . . 57
L
Lagrangepolynome . . . . . . . . . . . . . . . . . 29
LDU-Zerlegung . . . . . . . . . . . . . . . . . . . . 22
Legendrepolynome . . . . . . . . . . . . . . . . . 97
lineare Regression . . . . . . . . . . . . . . . . . . 34
lineares Programm . . . . . . . . . . . 158, 169
Lotka-Volterra-Gleichungen . . . . . . . 190
LR-Zerlegung . . . . . . . . . . . . . . . . . . . . . . 21
LU-Zerlegung . . . . . . . . . . . . . . . . . . . . . . 21
M
Matrixinversion . . . . . . . . . . . . . . . . . . . . 20
Mehrkörperproblem . . . . . . . . . . . . . . . 194
Messfehler . . . . . . . . . . . . . . . . . . . . . . . . . 60
Methode der kleinsten Quadrate . . . 34
Metropolis-Methode . . . . . . . . . . . . . . 180
Mittelpunktsregel . . . . . . . . . . . . . . . . . . 88
zusammengesetzte . . . . . . . . . . . . . 90
Monte-Carlo-Integration . . . . . . . . . . . 99
Monte-Carlo-Sampling . . . . . . . . . . . . 180
Moore-Penrose-Inverse . . . . . . . . . . . . 158
Multiskalenanalyse . . . . . . . . . . . . . . . . . 44
N
Neville-Aitken-Schema . . . . . . . . . . . . .
Newton-Cotes-Formeln . . . . . . . . . . . . .
geschlossene . . . . . . . . . . . . . . . . . . .
offene . . . . . . . . . . . . . . . . . . . . . . . . . .
zusammengesetzte . . . . . . . . . . . . .
Newtonverfahren . . . . . . . . . . . . . . . . . . .
gedämpftes . . . . . . . . . . . . . . . . . . . .
in mehreren Dimensionen . . . . . .
Nullstellensuche . . . . . . . . . . . . . . . . 65,
numerische Integration . . . . . . . . . . . . .
Nyquist-Frequenz . . . . . . . . . . . . . . . . . .
30
87
88
88
89
68
75
75
68
84
41
Index
O
Optimierung . . . . . . . . . . . . . . . . . . . . . .
globale . . . . . . . . . . . . . . . . . . . . . . .
lokale . . . . . . . . . . . . . . . . . . . . . . . . .
nichtlineare . . . . . . . . . . . . . . . . . . .
Orthogonalisierung . . . . . . . . . . . . . . . .
157
174
160
160
140
P
Parsevaltheorem . . . . . . . . . . . . . . . . . . . 37
kontinuierliches . . . . . . . . . . . . . . . . 50
Penalty function . . . . . . . . . . . . . . . . . . 166
Perkolation . . . . . . . . . . . . . . . . . . . . . . . 128
Pivotwahl . . . . . . . . . . . . . . . . . . . . . . . . . . 20
Poisson-Boltzmann-Gleichung 201, 204
Polynomapproximation . . . . . . . . . . . 172
Pseudoinverse . . . . . . . . . . . . . . . . . . . . . 158
Pseudozufallszahlen . . . . . . . . . . . . . . . 107
Qualitätsanalyse . . . . . . . . . . . . . . 118
Q
QR-Algorithmus . . . . . . . . . . . . . . . . . . 152
QR-Zerlegung . . . . . . . . . . . . . . . . . . . . . 139
Quadrattest . . . . . . . . . . . . . . . . . . . . . . . 119
Quadratur . . . . . . . . . . . . . . . . . . . . . . . . . 84
Quasi-Monte-Carlo-Integration . . . . 101
Quasizufallszahlen . . . . . . . . . . . . . . . . 102
R
Random walk . . . . . . . . . . . . . . . . . . . . . 121
kontinuierlicher . . . . . . . . . . . . . . . 125
Rechteckregel . . . . . . . . . . . . . . . . . . . . . . 88
Regula falsi . . . . . . . . . . . . . . . . . . . . . . . . 73
Rejection sampling . . . . . . . . . . . . . . . . 113
Relaxationsverfahren . . . . . . . . . . . . . . 137
Richardson-Extrapolation . . . . . . . . . . 93
Ringspeicher . . . . . . . . . . . . . . . . . . . . . . 111
Romberg-Integration . . . . . . . . . . . . . . . 92
Rosenbrockfunktion . . . . . . . . . . . . . . . 164
Runge-Kutta-Verfahren . . . . . . . . . . . 186
4. Ordnung . . . . . . . . . . . . . . . . . . . 188
explizite . . . . . . . . . . . . . . . . . . . . . . 187
Seed . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109
Sekantenmethode . . . . . . . . . . . . . . . . . . 71
Simplexalgorithmus . . . . . . . . . . . . . . . 169
Simpsonregel . . . . . . . . . . . . . . . . . . . . . . . 88
zusammengesetzte . . . . . . . . . . . . . 90
Simulated annealing . . . . . . . . . . . . . . 179
SOR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137
Spektraltest . . . . . . . . . . . . . . . . . . . . . . . 120
Spline . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
kubisch . . . . . . . . . . . . . . . . . . . . . . . . 32
natürlich . . . . . . . . . . . . . . . . . . . . . . . 32
Standardzufallszahl . . . . . . . . . . . . . . . 112
Straffunktion . . . . . . . . . . . . . . . . . . . . . 166
strikt diagonaldominant . . . . . . . . . . . 135
Successive over-relaxation . . . . . . . . . 137
sukzessive Substitution . . . . . . . . . . . . . 65
T
Taylorreihe . . . . . . . . . . . . . . . . . . . . . . . . . 26
Trapezregel . . . . . . . . . . . . . . . . . . . . . . . . 87
zusammengesetzte . . . . . . . . . . . . . 89
V
Vektoriteration . . . . . . . . . . . . . . . . . . .
Velocity-Verlet-Verfahren . . . . . . . . .
Verfahren des steilsten Abstiegs . . .
Verwerfungsmethode . . . . . . . . . . . . . .
150
192
161
113
W
Wärmeleitungsgleichung . . . . . . . . . . 198
Würfeltest . . . . . . . . . . . . . . . . . . . . . . . . 119
Wavelets . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
-transformation . . . . . . . . . . . . . . . . 45
Z
zeitinvariante lineare Systeme . . . . . . 56
Zufallszahlen . . . . . . . . . . . . . . . . . . . . . . 107
echte . . . . . . . . . . . . . . . . . . . . . . . . . 107
Pseudo- . . . . . . . . . . . . . . . . . . . . . . . 107
Zufallszahlengeneratoren . . . . . . . . . . 108
S
Schrödingergleichung . . . . . . . . . . . . . . 198
Schrittweitensteuerung . . . . . . . . . . . . 161
213

Documents pareils