Graphenalgorithmen und lineare Algebra Hand in Hand Henning Meyerhenke 1. September 2014 iii Inhaltsverzeichnis 1. Grundlegende Graphenalgorithmen 1.1. Dualität zwischen Graphen und Matrizen . . . . . . . . . 1.2. Starke Zusammenhangskomponenten . . . . . . . . . . . . 1.2.1. Definition . . . . . . . . . . . . . . . . . . . . . . . 1.2.2. Algorithmus . . . . . . . . . . . . . . . . . . . . . . 1.2.3. Konvergenz . . . . . . . . . . . . . . . . . . . . . . 1.3. Kürzeste Wege . . . . . . . . . . . . . . . . . . . . . . . . 1.3.1. Definitionen . . . . . . . . . . . . . . . . . . . . . . 1.3.2. Algorithmus von Bellman und Ford . . . . . . . . . 1.3.3. Paarweise kürzeste Distanzen . . . . . . . . . . . . 1.3.4. Paarweise kürzeste Wege mit dem Algorithmus von 1.4. Nicht erweiterbare unabhängige Mengen . . . . . . . . . . 1.5. Weiterführende Literatur . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 2 4 4 5 6 6 6 7 9 14 20 24 . . . . . . . . . . . . . . . . . . . . . . . 25 25 25 26 26 26 26 27 27 27 29 29 30 30 32 32 32 33 34 35 35 36 38 39 3. Clusteranalyse von Graphen 3.1. Label Propagation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.1.1. Der Algorithmus . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41 41 41 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Seidel . . . . . . . . 2. Datenstrukturen für dünn besetzte Matrizen 2.1. Cache-Effizienz . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.1.1. I/O-Modell . . . . . . . . . . . . . . . . . . . . . . . . . 2.1.2. Modell-Annahmen . . . . . . . . . . . . . . . . . . . . . 2.1.3. Grundlegende Algorithmen im I/O-Modell . . . . . . . . 2.2. Grundlegende Matrix-Operationen . . . . . . . . . . . . . . . . 2.2.1. Teilmatrizen addressieren (SpRef/SpAsgn) . . . . . . . . 2.2.2. Matrix-/Vektormultiplikation (SpMV) . . . . . . . . . . 2.2.3. Addition dünner Matrizen (SpAdd) . . . . . . . . . . . . 2.2.4. Sparse matrix-sparse matrix multiplication (SpGEMM) 2.3. Tripel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.3.1. Ungeordnete Tripel . . . . . . . . . . . . . . . . . . . . . 2.3.2. Zeilenweise geordnete Tripel . . . . . . . . . . . . . . . . 2.3.3. Zeilendominant geordnete Tripel . . . . . . . . . . . . . 2.4. CSR/CSC . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.4.1. CSR und Adjazenzlisten . . . . . . . . . . . . . . . . . . 2.4.2. Grundoperationen mit CSR . . . . . . . . . . . . . . . . 2.5. Multiplikation dünn besetzter Matrizen . . . . . . . . . . . . . 2.5.1. Der Sparse Accumulator . . . . . . . . . . . . . . . . . . 2.5.2. SpGEMM mit CSR . . . . . . . . . . . . . . . . . . . . . 2.6. Hyperdünne Matrizen . . . . . . . . . . . . . . . . . . . . . . . 2.7. DCSC . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.8. Multiplikation hyperdünner Matrizen . . . . . . . . . . . . . . . 2.9. Weiterführende Literatur . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . iv Inhaltsverzeichnis 3.2. 3.3. 3.4. 3.5. 3.1.2. Probleme . . . . . . . . . . . . . . . . . . . . . . . . 3.1.3. Komplexität . . . . . . . . . . . . . . . . . . . . . . . 3.1.4. Algebraische Formulierung . . . . . . . . . . . . . . . Markov Clustering . . . . . . . . . . . . . . . . . . . . . . . 3.2.1. Konvergenz des Markov Clustering Algorithmus . . . 3.2.2. Zusammenhänge zwischen Graphen und Eigenwerten Random Walks als Analysewerkzeug . . . . . . . . . . . . . Bildsegmentierung mit spektraler Clusteranalyse . . . . . . 3.4.1. Graphrepräsentation von Bildern . . . . . . . . . . . 3.4.2. Optimierungsproblem . . . . . . . . . . . . . . . . . 3.4.3. Relaxiertes Optimierungsproblem . . . . . . . . . . . 3.4.4. Laufzeit des NCut-Algorithmus . . . . . . . . . . . . 3.4.5. Verallgemeinerung auf k Segmente . . . . . . . . . . Weiterführende Literatur . . . . . . . . . . . . . . . . . . . . 4. Visualisierung von Graphen 4.1. Spektrales Zeichnen . . . . . . . . . . . . . . . . . . . . . 4.2. Kräftegesteuertes Zeichnen . . . . . . . . . . . . . . . . . . 4.2.1. Quadtree-Datenstruktur . . . . . . . . . . . . . . . 4.2.2. Multilevel-Verfahren für kräftegesteuertes Zeichnen 4.3. Weiterführende Literatur . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42 43 44 46 47 49 51 51 52 52 53 53 54 55 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57 57 58 60 61 62 5. Lastbalancierung paralleler Berechnungen 5.1. Parallelität . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.2. Dynamische Balancierung unabhängiger Lasten . . . . . . . . 5.2.1. Das Diffusionsverfahren erster Ordnung (FOS) . . . . 5.2.2. Weitere Verfahren zur dynamischen Lastbalancierung . 5.3. Balancierung abhängiger Lasten mittels Graphpartitionierung 5.3.1. Bubble-Framework . . . . . . . . . . . . . . . . . . . . 5.3.2. Gestörte Diffusion (FOS/C) . . . . . . . . . . . . . . . 5.3.3. Bubble-FOS/C . . . . . . . . . . . . . . . . . . . . . . 5.3.4. Theoretische Ergebnisse zu Bubble-FOS/C . . . . . . 5.3.5. DibaP . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.4. Weiterführende Literatur . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63 63 63 63 66 67 68 69 70 71 74 74 6. Ausdünnung von Graphen und Laplace-Löser 6.1. Schnitterhaltende Ausdünnung von Graphen . . . . 6.1.1. Definitionen . . . . . . . . . . . . . . . . . . 6.1.2. Der Sampling-Prozess . . . . . . . . . . . . 6.1.3. Konzentration um den Erwartungswert . . . 6.1.4. Das Hauptresultat . . . . . . . . . . . . . . 6.2. Spektrale Approximation . . . . . . . . . . . . . . . 6.2.1. Definitionen . . . . . . . . . . . . . . . . . . 6.2.2. Graphen und elektrische Netzwerke . . . . . 6.2.3. Algorithmus und Beweis des Haupttheorems 6.3. Kombinatorische Löser für Laplace-Systeme . . . . 6.3.1. Grundidee . . . . . . . . . . . . . . . . . . . 6.3.2. Flüsse, Energie und Baumzyklen . . . . . . 6.3.3. Der Algorithmus SimpleSolver . . . . . . . . 6.3.4. Konvergenz des Algorithmus . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75 75 75 76 77 79 81 81 82 83 86 86 86 89 90 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Inhaltsverzeichnis 6.3.5. Beweis des Haupttheorems . . . . . . . . . . . . . . . . . . . . . . . . . . . 6.4. Weiterführende Literatur . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . v 93 94 Literaturverzeichnis 94 A. Anhang A.1. Grundlagen der linearen Algebra . . . . . . . . . . . . . . . . . . . . . . . . . . . A.1.1. Spektrale Zerlegung einer symmetrischen Matrix . . . . . . . . . . . . . . 97 97 99 vii Vorwort Dieses Skript basiert im Wesentlichen auf der Vorlesung Graphenalgorithmen und lineare Algebra Hand in Hand, die ich im Sommersemester 2014 am Karlsruher Institut für Technologie (KIT) gehalten habe. Es sind jedoch teilweise zusätzlich Inhalte aus meinen anderen Vorlesungen bearbeitet worden und hier eingeflossen, u. a. aus Vorläuferskripten zu Vorlesungen von Robert Elsässer bzw. von Burkhard Monien an der Universität Paderborn. Das Skript erhebt keinen Anspruch auf Vollständigkeit, es ergänzt lediglich die Folien zur Vorlesung. Nehmen Sie zur Prüfungsvorbereitung auf jeden Fall sowohl Skript als auch Folien zur Hand. Beides zusammen ist wiederum nicht als Ersatz zum Besuch der Vorlesung gedacht, sondern als Hilfestellung bei der notwendigen Vor- und Nachbereitung. Sollten Sie auf Fehler stoßen, bitte ich um einen entsprechenden Hinweis. Auch für Verbesserungsvorschläge bin ich sehr dankbar. Mein großer Dank gilt den studentischen Hilfskräften Lukas Hartmann und Michael Wegner. Beide waren maßgeblich an der Anfertigung des Skriptes beteiligt. Karlsruhe, im Sommer 2014 Henning Meyerhenke ix Versionen Version 0.1 • Allgemein: Struktur der Vorlesung im Skript nachvollziehbar, auch wenn Inhalte fehlen • Kapitel 1 im Wesentlichen vollständig, beinhaltet auch den Algorithmus von Seidel, der nicht Teil der aktuellen Vorlesung (SS 2014) ist • Kapitel 1: Algorithmus von Seidel vorhanden, aber noch nicht gründlich auf Fehler überprüft • Kapitel 5: Dynamische Lastbalancierung mit Diffusion im Wesentlichen vollständig • Kapitel 5: Diffusionsbasierte Partitionierung nur in Ansätzen vorhanden (mehr folgt in Version 0.2.1) Versionen 0.2, 0.2.1. und 0.2.2 (15. bis 17. Juli 2014) • Kapitel 5: Enthält eine leicht erweiterte Fassung zur Diffusion • Kapitel 5: Diffusionsbasierte Partitionierung deutlich erweitert • Kapitel 6: Schnitterhaltende Ausdünnung Version 0.3 (23. Juli 2014) • Kapitel 6: Spektrale Ausdünnung, kombinatorischer Laplace-Löser sind nun enthalten. Weitere Verbesserungen in der Darstellung sind erst für spätere Versionen geplant. Version 0.4 und 0.4.1 (31. Juli und 4. August 2014) • Kapitel 2 Version 0.5 (6. August 2014) • Kapitel 3 Version 0.6 (1. September 2014) • Kapitel 4 Version 0.6.1 (Mitte/Ende September 2014) • Verbesserungen, Korrekturen der eingereichten Fehler 1 1. Grundlegende Graphenalgorithmen In dieser Vorlesung werden Sie eine Reihe von Algorithmen kennenlernen, die auf Graphen operieren. Ein Graph modelliert allgemein gesprochen eine Menge von Entitäten (dargestellt als Knoten) und die Beziehungen der Entitäten (dargestellt durch Kanten). Definition. Ein Algorithmus ist eine eindeutige Beschreibung eines Verfahrens zur Lösung einer bestimmten Klasse von Problemen. Genauer gesagt ist ein Algorithmus eine Menge von Regeln für ein Verfahren, um aus gewissen Eingabegrößen bestimmte Ausgabegrößen herzuleiten. Dabei muss dass Verfahren in einem endlichen Text beschreibbar sein. Jeder Schritt dieses Verfahrens muss auch tatsächlich ausführbar sein und darüber hinaus muss der Ablauf des Verfahrens zu jedem Zeitpunkt eindeutig definiert sein. Hier einige typische Beispielprobleme, in denen Graphenalgorithmen eine wichtige Rolle spielen: • Wie findet ein Navigationssystem gute Verbindungen zwischen zwei Orten? • Wie werden im Internet Informationen geroutet? • Wie berechnet ein Unternehmen eine möglichst gute Aufteilung seiner Ressourcen, um seinen Gewinn zu maximieren? • Wie finden Suchmaschinen Informationen schnell wieder? Um über die Qualität eines Algorithmus urteilen zu können, bedarf es bestimmter Kriterien, um entsprechende Urteile treffen zu können. 1. Algorithmen müssen korrekt sein. D.h. zu jedem Algorithmus gehört ein Korrektheitsbeweis, der in allgemeiner Form die Korrektheit der Berechnung der Ausgabegröße zu einer gegebenen Eingabegröße zeigt. 2. Algorithmen sollen zeit- und speichereffizient sein. Hierzu bedarf es Analysemethoden für den Zeit- und Speicherbedarf eines Algorithmus. Diese Analyse basiert in der klassischen Algorithmik nicht auf empirischen Untersuchungen, sondern auf mathematischen Analysen. Wir nutzen hierfür Pseudocode und Basisoperationen. Zum Entwurf eines Algorithmus gehören im Allgemeinen grundsätzlich drei Dinge: 1. Die Beschreibung des Algorithmus selbst in Pseudocode. 2. Ein vollständiger Korrektheitsbeweis. 3. Die Analyse des Zeit- und Speicherbedarfs des Algorithmus. In dieser Vorlesung (und somit auch in diesem Skript) wird aus Zeitgründen bei einigen Inhalten teilweise auf eine detaillierte Darstellung der obigen drei Punkte verzichtet. Diese Darstellung ist dann üblicherweise in der angegebenen Literatur zu finden. 2 1. Grundlegende Graphenalgorithmen 1.1. Dualität zwischen Graphen und Matrizen Für viele Graphenalgorithmen ist es vorteilhaft, die Dualität zwischen Graphen und ihren dazugehörigen Matrizen auszunutzen. Graphenalgorithmen können so zu Sequenzen von einfachen algebraischen Operationen umgeschrieben werden, meist Multiplikationen einer Matrix mit einem Vektor. In diesem Abschnitt werden die wichtigsten Verbindungen der beiden Konzepte vorgestellt. Grundlegend ist die Darstellung eines Graphen durch seine Adjazenzmatrix. Definition 1.1. Sei G = (V, E) ein ungewichteter Graph mit |V | = n. Die Adjazenzmatrix A ist eine n × n-Matrix, definiert durch: ( 1, die Knoten i und j sind adjazent Aij = 0, sonst. Betrachte als Beispiel den ungerichteten Graphen G aus Abbildung 1.1.1 und die zugehörige Adjazenzmatrix A. 0 1 A= 0 1 1 0 1 1 0 1 0 1 1 1 1 0 Abbildung 1.1.1.: Ungerichteter Graph G = (V, E) und die zugehörige Adjazenzmatrix A Eine weitere wichtige Verbindung besteht zwischen der Matrix-Vektor-Multiplikation und der Breitensuche (BFS). Sei ek ∈ Rn der k-te Einheitsvektor (d.h. alle Einträge bis auf die k-te Stelle haben den Wert null). Dann gilt: (AT ek )i = 1 genau dann, wenn der Knoten i vom Knoten k durch einen Schritt der Breitensuche erreichbar ist. Beachten Sie dabei, dass die transponierte Adjanzenzmatrix verwendet werden muss. Die Multiplikation mit ek „wählt” die Einträge der k-ten Spalte von AT , also die Einträge der k-ten Zeile von A aus. Ein Eintrag aki in der k-ten Zeile von A ist nach Definition genau dann 1, wenn k und i durch eine Kante verbunden sind, also der Knoten i in einem Breitensuchschritt von k erreichbar ist. Wir werden nun die Prinzipien der gewöhnlichen Matrix-Vektor-Multiplikation auf einen Halbring erweitern. Definition 1.2. Ein Halbring ist eine Menge M mit zwei binären Verknüpfungen + und ∗, genannt Addition und Multiplikation, sodass für alle x, y, z ∈ M gilt: • Addition und Multiplikation besitzen je ein neutrales Element 0 bzw. 1. • x + (y + z) = (x + y) + z (Addition ist assoziativ) • x ∗ (y ∗ z) = (x ∗ y) ∗ z (Multiplikation ist assoziativ) • x + y = y + x (Addition ist kommutativ) • x ∗ (y + z) = x ∗ y + x ∗ z und (x + y) ∗ z = x ∗ z + y ∗ z (Distributivität) • 0∗x=x∗0=0 1.1. Dualität zwischen Graphen und Matrizen 3 Die ganzen Zahlen Z und die reellen Zahlen R bilden bezüglich der gewöhnlichen Addition und Multiplikation einen Halbring. Fügen wir +∞ zu Z oder zu R hinzu, so erhalten wir einen Halbring bezüglich der Verknüpfungen ” min ” als Addition und ” + ”als Multiplikation. Lineare Algebra über diesem Halbring ist oft nützlich, um Kürzeste-Wege-Probleme zu lösen. Wir werden nun Vektor- und Matrix-Operationen auf einem allgemeinen Halbring (Rn , +, ∗) definieren. Definition 1.3. Seien c ∈ R, v ∈ Rm , w ∈ Rn und A = (aij )ij ∈ Rm×n . • Die Addition mit einem Skalar c + v wird punktweise ausgeführt, d.h. c + v = (c + v1, . . . , c + vn ). • Das dyadische ( manchmal: äußere) Produkt v ◦ w ist eine m × n-Matrix definiert durch (v ◦ w)ij = vi ∗ wj . • Ist m = n, so ist das innere Produkt oder Skalarprodukt v · w definiert durch X v·w = vi ∗ wi = (v1 ∗ w1 ) + · · · + (vn ∗ wn ). i • Das Matrix-Vektor-Produkte v T A ∈ Rn und Aw ∈ Rm ist gegeben durch X X (v T A)k = vi ∗ aik bzw. (Aw)k = aki ∗ wi . i i . In einem gegebenen Halbring, der nicht die gewöhnliche Addition und Multiplikation besitzt, werden wir die Matrix-Vektor-Multiplikation Aw auch als A + . ∗ w darstellen, z. B. A min . + w für die Multiplikation bezüglich ” min ” und ” + ”. A min . + w ist dann ein n-dimensionaler Vektor, dessen i-ter Eintrag gerade min(Aij + wj ; 1 ≤ j ≤ n) ist. Definition 1.4. Seien A = (aij )ij und B = (bij )ij Matrizen. • Die Addition mit einem Skalar c + A wird punktweise ausgeführt, d.h. (c + A)ij = c + aij . • Seien A ∈ Rm×n ,v ∈ Rm und w ∈ Rn , so sind die punktweisen Matrix-Vektor-Produkte v.∗A und A. ∗ w Matrizen in Rm×n gegeben durch (v. ∗ A)ij = vi ∗ aij bzw. (A. ∗ w)ij = wj ∗ aij . • Sind A, B ∈ Rm×n , so ist das punktweise Matrizenprodukt A. ∗ B von A und B eine Matrix in Rm×n mit (A. ∗ B)ij = aij ∗ bij . Analog definiere auch andere punktweise Operationen, wie A. + B. m×n und B ∈ Rn×p , dann ist das Matrizenprodukt AB ∈ Rm×p definiert durch • Sind A ∈ R P (AB)ij = k aik ∗ bkj . Auch beim Matrizenprodukt werden wir die Schreibweise A + . ∗ B benutzen, wenn wir die gegebenen Verknüpfungen explizit nennen möchten. 4 1. Grundlegende Graphenalgorithmen Mit Hilfe eines Halbrings lassen sich nun viele Graphenalgorithmen einfach durch Matrizen darstellen. So kann im Bellman-Ford-Algorithmus (siehe Abschnitt 1.3.2) für kürzeste Wege die Aktualisierung des Distanzvektors d als Multiplikation mit der Adjazenzmatrix A als d ← d min . + A geschrieben werden. Ein weiteres Anwendungsbeispiel ist die Bestimmung von Teilgraphen, welches sich mit Hilfe der Adjazenzmatrix auf ein Zeilen- und Spalten-Auswahlproblem zurückführen lässt. Sei dazu v ∈ Rn und diag(v) die Diagonalmatrix mit Dimension n × n, deren Einträge gerade die Werte von v sind. Dann können wir eine (gewichtete) Zeilen- oder Spaltenauswahl durch Matrizenmultiplikationen, bezüglich der gewöhnlichen Addition und Multiplikation, folgendermaßen darstellen: • Zeile auswählen: diag(u) A • Spalte auswählen: A diag(v) • Zeile und Spalte auswählen: diag(u) A diag(v) Als letztes Beispiel geben wir die Berechnung der Zeilen- und der Spaltensumme einer Matrix an. Sei A = (aij )ij ∈ Rm×n eine Matrix und u = (1, . . . , 1) ∈ Rm und v = (1, . . . , 1) ∈ Rn Vektoren mit Einträgen 1. Dann ist Av ein Vektor und es gilt X X (Av)i = aik vk = aik , k k d.h. der Eintrag (Av)i ist die Summe der Einträge der i-ten Zeile von A. Analog folgt, dass (uA)j gerade die Summe der Einträge der j-ten Spalte von A ist. 1.2. Starke Zusammenhangskomponenten 1.2.1. Definition Definition 1.5. Ein (möglicherweise) gerichteter Multigraph ist ein Paar G = (V, E) aus einer endlichen Menge V von Knoten und einer Multimenge E ⊆ V × V von Kanten. Eine Kante e ∈ {(v, v)|v ∈ V } heißt Schleife. Kanten e ∈ E mit #e = k > 1 (Mehrfachauftreten) heißen Multikanten. Einen Multigraphen, der weder Schleifen noch Multikanten besitzt, nennen wir schlicht. Wir werden nun den Zusammenhang und darauf aufbauend Zusammenhangskomponenten eines Graphen definieren. Definition 1.6. Sei G = (V, E) ein Multigraph. • G heißt stark zusammenhängend, wenn für jedes Paar (u, v) ∈ V ×V sowohl ein (gerichteter) (u, v)-Weg, als auch ein (v, u)-Weg in G existiert. • G heißt (schwach) zusammenhängend, wenn der zu G gehörige Multigraph stark zusammenhängend ist. Sei G nun ein ungerichteter Multigraph. • G heißt k-fach zusammenhängend, falls jeder durch Entfernen von höchstens k − 1 Knoten (und aller inzidenten Kanten) aus G entstehende Teilgraph zusammenhängend ist. 1.2. Starke Zusammenhangskomponenten 5 • G heißt k-fach kantenzusammenhängend, falls jeder durch das Entfernen von höchstens k − 1 beliebigen Kanten aus G entstehende Teilgraph zusammenhängend ist. Definition 1.7. Zu einem schlichten Multigraphen G heißt ein maximaler stark zusammenhängender Teilgraph starke Zusammenhangskomponente. Analog definieren wir eine schwache, k-fach zusammenhängende bzw. k-fach kantenzusammenhängende Zusammenhangskomponente. Ein Beispiel für starke Zusammenhangskomponenten kann unter folgender Adresse gefunden werden: http://www.cs.berkeley.edu/~vazirani/s99cs170/notes/lec12.pdf 1.2.2. Algorithmus Wir möchten nun einen Algorithmus entwickeln, um starke Zusammenhangskomponenten in einem gegebenen Graphen zu finden. Als Grundidee benutzen wir das nachfolgende Resultat: Theorem 1.8. Sei A die Adjazenzmatrix des Graphen G. Dann ist (Ak )ij die Anzahl der Wege der Länge k zwischen den Knoten i und j. Beweis. Wir beweisen das Theorem mittels Induktion über k. Für k = 1 ist ein Weg der Länge 1 genau eine Kante und damit gilt die Aussage nach Definition der Adjazenzmatrix. Sei nun die Aussage für ein k bewiesen. Dann gilt: X (Ak+1 )ij = Ail (Ak )lj . l Also ist (Ak+1 )ij die Summe aus der Zahl der Kanten von i nach l und dann (nach Induktionsvoraussetzung) der Wege der Länge k von l nach j. Die Kante von i nach l verlängert somit den Weg um 1, also gibt (Ak+1 )ij die Anzahl der Wege der Länge k + 1 von i nach j an. Sei nun die Matrix C mittels punktweiser oder-Funktion definiert als C = I ∨ A ∨ A2 ∨ A3 ∨ A4 ∨ . . . Nach Theorem 1.8 ist Cij genau dann 6= 0, wenn ein Pfad beliebiger Länge zwischen den Knoten i und j existiert. Beachten Sie dabei, dass wir hier auch triviale Wege der Länge 0 zulassen. Analog enthält C T somit einen Eintrag (C T )ij 6= 0 genau dann, wenn ein Pfad zwischen j und i existiert. Für C ∧ C T gilt folglich, dass (C ∧ C T )ij genau dann 6= 0 ist, wenn die Knoten i und j in der gleichen starken Zusammenhangskomponente liegen. Ist die Adjazenzmatrix A symmetrisch, so gilt auch C = C T und somit liefert uns die Matrix C bereits alle benötigten Informationen. Wir verwenden allerdings im Folgenden statt der Oder-Verknüpfung die Addition und definieren die Matrix D als D = I + A + A2 + A3 + A4 + . . . . Der Grund für die Verwendung der Addition statt der Oder-Verknüpfung liegt in der einfacheren Umformbarkeit und wird nachfolgend klar. Es gilt nun Dij = 0 ⇔ Cij = 0 und somit auch Dij 6= 0 genau dann, wenn die Knoten i und j durch einen Pfad verbunden sind. Weiterhin gilt mit F = (I − A)D: F = D −AD = = I I +A + A2 + A3 + A4 + . . . −A − A2 − A3 − A4 − . . . 6 1. Grundlegende Graphenalgorithmen Das bedeutet, dass D = (I − A)−1 gilt und sich so die benötigte Matrix D berechnen lässt. Allerdings konvergiert die Reihe D häufig nicht. 1.2.3. Konvergenz Um die Konvergenz der Reihe D zu erhalten, wandeln wir die Reihe etwas ab. Sei α > 0 und definiere D0 als D0 = I + (αA) + (αA)2 + (αA)3 + (αA)4 + . . . Die Matrix D0 besitzt noch immer die gewünschten Eigenschaften und für hinreichend kleines α konvergiert die Reihe. Wie α gewählt werden muss, wird in der nachfolgenden Aufgabe geklärt. Aufgabe 1.9. Die Zeilensummennorm einer Matrix A ist definiert als kAk∞ = max i=1,...,n n X k=1 |aik |. Es gilt: kBAk∞ ≤ kBk∞ kAk∞ für Matrizen A und B ∈ Rn×n (sogar noch allgemeiner). Außerdem gilt kα · Ak∞ = |α| · kAk∞ für α ∈ R. Leiten Sie eine passende Wahl von α her, so dass die Reihe limk→∞ Sie können z. B. das Quotientenkriterium von d’Alembert anwenden. Pk i=0 α i Ai konvergiert! 2 kAk∞ 1 Beweis. Wenn α < kAk , dann folgt: kα2 A2 k∞ = |α|2 kAk2∞ < kAk = 1. Dies gilt auch für 2 ∞ ∞ alle weiteren Reihenglieder. Also folgt nach dem Quotientenkriterium von d’Alembert, dass die Reihe konvergiert. Sei daher nun 0 < α < 1 kAk∞ . Setzen wir F 0 = (I − αA)D0 , dann ergibt sich: F 0 = D0 −αAD0 = = I I +(αA) + (αA)2 + (αA)3 + (αA)4 + . . . −(αA) − (αA)2 − (αA)3 − (αA)4 + . . . Also gilt D0 = (I − αA)−1 , wobei D0 konvergiert. Wir können nun D0 berechnen und zusammenfassend gilt (D0 + D0T )ij 6= 0 genau dann, wenn die Knoten i und j in der selben starken Zusammenhangskomponente liegen. 1.3. Kürzeste Wege 1.3.1. Definitionen In diesem Abschnitt betrachten wir das Problem kürzester Wege in gerichteten Graphen mit Kantengewichten. In einem unidirektionalen, zusammenhängenden Graphen G = (V, E) mit V = {1, . . . , n} und |E| = m als Eingabegrößen soll als Ausgabegröße für jedes Paar von Knoten u, v ∈ V die Distanz von u nach v, sowie ein kürzester Weg zwischen den beiden Knoten im Graphen G berechnet werden. Definition 1.10. Sei ein gerichteter und gewichteter Graph G = (V, E) mit der Gewichtsfunktion w : E → R gegeben. Das Gewicht eines Weges P = hv0 , v1 , . . . , vk i ist die Summe der 1.3. Kürzeste Wege 7 Abbildung 1.3.1.: Unidirektionaler, gewichteter Graph G = (V, E) Gewichte seiner Kanten: w(P ) = k X w(vi−1 , vi ). i=1 Definition 1.11. Das Gewicht eines kürzesten Weges P in einem gerichteten und gewichteten Graphen G = (V, E) zwischen den Knoten u, v ∈ V ist definiert als: ( min{w(P ) : v ist von u über P erreichbar}, δ(u, v) = ∞, falls v von u nicht erreichbar ist. Ein kürzester Weg zwischen u, v ∈ V ist dann ein Weg P mit w(P ) = δ(u, v). Die Eingabe wird als Gewichtsmatrix W = (wij )ij Die Matrix-Einträge wij sind wie folgt definiert: 0 wij = Gewicht der ger. Kante (i, j) ∞ dargestellt, die den Graphen repräsentiert. , wenn i = j , wenn i 6= jund (i, j) ∈ E , wenn i = 6 jund (i, j) ∈ /E Aus dieser Definition folgt für den Graphen G aus Abbildung 1.11 die Gewichtsmatrix wij , abgebildet in der nachfolgenden Tabelle. Tabelle 1.1.: Gewichtsmatrix W a b a 0 2 b ∞ 0 c ∞ ∞ d ∞ -4 e ∞ ∞ f ∞ ∞ zum c ∞ 4 0 6 8 ∞ Graphen d e 5 ∞ ∞ ∞ 1 ∞ 0 5 ∞ 0 ∞ ∞ G aus Abbildung 1.11 f ∞ ∞ 7 ∞ -1 0 1.3.2. Algorithmus von Bellman und Ford Der Algorithmus von Bellman und Ford berechnet von einem gegebenen Startknoten s ∈ V die kürzesten Wege in G (single-source shortest paths). Dabei wird auch erkannt, ob in G ein negativer Kreis existiert. In diesem Fall ist eine Berechnung nicht möglich und der Algorithmus bricht mit einer Fehlermeldung ab. Somit ist dieser Algorithmus im Gegensatz zu Dijkstras Algorithmus auch verwendbar, wenn der Eingabegraph negative Kantengewichte hat. Der komplette Algorithmus ist in Algorithmus 1 darstellt. 8 1. Grundlegende Graphenalgorithmen Für jeden Knoten v ∈ V wird in d(v) das Gewicht des bisher gefundenen kürzesten Weges von s nach v gespeichert. Initial setzen wir d(v) = ∞ für v ∈ V \ {s} und d(s) = 0. Der Algorithmus führt nun eine Reihe von Kantenrelaxierungen aus. Wird eine Kante e = (u, v) relaxiert, so wird überprüft, ob durch e ein besserer, d.h. kürzerer, Weg von s nach v verläuft. Wir setzen also d(v) ← min {d(v), d(u) + wuv } . Der Algorithmus besteht aus n − 1 Runden, in denen jeweils alle Kanten (in einer beliebigen Reihenfolge) relaxiert werden. Können die bis jetzt berechneten Distanzen nochmals verbessert werden, so existiert ein negativer Kreis im Graphen. Andernfalls gilt nach Berechnung die gewünschte Eigenschaft δ(s, v) = d(v). Um nicht nur das Gewicht des kürzesten Weges von s nach v zu erhalten, wird zusätzlich der Vaterknoten π(v) von v gespeichert, der vor v auf dem kürzesten Weg von s nach v liegt. Somit kann der kürzeste Weg rekonstruiert werden. Algorithmus 1 : Bellman-Ford Input : Graph G = (V, E), Gewichtsfunktion w, Startknoten s Output : Distanz des kürzesten Wegs d(v), Vaterknoten π(v) (für v ∈ V ) 1 foreach v ∈ V do 2 d(v) ← ∞ 3 π(v) ← N IL 4 5 6 7 8 9 10 11 12 d(s) ← 0 for k = 1 to n-1 do foreach (u, v) ∈ E do if d(v) > d(u) + wij then d(v) ← d(u) + wij π(v) ← u // Relaxierung der Kante (u, v) foreach (u, v) ∈ E do if d(v) > d(u) + wij then return Negativer Kreis existiert! Wir möchten nun den Algorithmus mit algebraischen Mitteln formulieren. Wir definieren dazu ( min {w(P ) : P ist Pfad von unach vmit |P | ≤ k} δk (u, v) = ∞, sonst als die Länge des kürzesten Weges zwischen u und v, der höchstens k Kanten benutzt. Falls δn (s, v) < δn−1 (s, v) für einen beliebingen Knoten v ∈ V gilt, dann gibt es einen Zyklus negativer Länge. Andernfalls gilt δ(s, v) = δn−1 (s, v) . Die Berechnung von δk (s, v) mittels δk−1 (s, v) ist äquivalent zur Relaxierung aller zu v inzidenten Kanten. Insbesondere gilt somit δk (s, v) = min {δk−1 (s, u) + wuv } . u∈N (v) Wir stellen ferner fest, dass δk alleine mit Hilfe von δk−1 und der gegebenen Gewichtsmatrix W berechnet werden kann. Alle vorher berechneten δi können folglich gelöscht werden. Sei dk ∈ Rn nun ein Vektor zum Speichern der Informationen von δk , d.h. es gilt dk (v) = δk (s, v). Dann lässt 1.3. Kürzeste Wege 9 sich dk und somit δk mittels Matrix-Vektor-Multiplikation berechnen durch dk = dk−1 min . + W, wobei wir initial d0 setzen als ( 0, v = s d0 (v) = . ∞, sonst Da wir nach obiger Überlegung δk−1 nach der Berechnung von δk nicht mehr benötigen, können wir die Informationen in einem einzigen Vektor d speichern und verwenden somit d ← d min . + W. Sofern der Graph keinen negativen Kreis besitzt, gilt folglich nach n − 1 Runden δ(s, v) = d(v). Zusammengefasst ergibt sich Algorithmus 2. Algorithmus 2 : Algebraischer Bellman-Ford-Algorithmus Input : Adjazenzmatrix A, Startknoten s Output : Distanzvektor d 1 d←∞ 2 ds ← 0 3 for k = 1 to n − 1 do 4 d ← d min . + A 6 if d 6= d min . + A then return Negativer Kreis existiert! 7 return d 5 1.3.3. Paarweise kürzeste Distanzen 1.3.3.1. Der Floyd-Warshall-Algorithmus Der Floyd-Warshall-Algorithmus basiert auf der Idee, das Problem schrittweise zu vergrößern. In Iteration k werden alle Wege berücksichtigt, die über Knoten aus der Menge {1, . . . , k} verlaufen (direkte Kanten des Graphen eingeschlossen). Nach Ende der äußersten Schleife hat k den Wert n überschritten, so dass alle möglichen Wege berücksichtigt worden sind. Algorithmus 3 : Floyd-Warshall-APSP Input : Graph G = (V, E) Output : Distanzmatrix 1 D (0) ← W 2 for k ← 1 to n do 3 for i ← 1 to n do 4 for j ← 1 to n do (k) (k−1) (k−1) (k−1) 5 dij ← min(dij , dik + dkj ) 6 return D(n) 10 1. Grundlegende Graphenalgorithmen Lemma 1.12. Sei G ein Graph ohne negative Zyklen und sei j von i aus erreichbar. Dann gibt es einen kürzesten i − j-Weg, der keinen Knoten doppelt benutzt. Theorem 1.13. Sei G = (V, E) ein Graph mit nicht-negativen Zyklen. Dann berechnet der Algorithmus von Floyd-Warshall die Entfernung zwischen jedem Knotenpaar in O(|V |3 ) Schritten. Die Beweise von Lemma 1.12 und Theorem 1.13 werdem dem Leser anhand der obigen Erläuterungen als Übung empfohlen. Bemerkung 1.14. Das als Algorithmus 3 angegebene Verfahren löst nur das Problem All-PairsDistances (APD), d.h. es werden die paarweisen Distanzen und nicht auch die zugehörigen kürzesten Wege berechnet. Eine entsprechende Erweiterung des Algorithmus für APSP wird dem Leser ebenfalls als Übungsaufgabe empfohlen. 1.3.3.2. Matrix-Multiplikation Wir betrachten nun ungerichtete Graphen G = (V, E) mit der Knotenmenge V = {1, ..., n}. Ein Graph G = (V, E) ist gegeben durch seine Adjazenzmatrix A. Im Folgenden betrachten wir zunächst das Problem der Matrixmultiplikation. Es seien D, W ∈ (R ∪ {∞})n×n quadratische Matrizen. Verwenden wir die Verknüpfungen (min, +) bei der Matrizenmultiplikation, so gilt bekanntlich: (DW )ij = min {Dik + Wkj } 1≤k≤n Diese Tatsache setzen wir nun ein, um mit Hilfe eines modifizierten Algorithmus zur Matrixmultiplikation die Distanzen aller paarweise kürzesten Wege zu berechnen. Die wichtige Idee dabei ist, D(n−1) = δn−1 (i, j) durch fortgesetzte Matrixmultiplikation zu berechnen: D(1) = W, D(2) = W 2 = W ∗ W, D(4) = W 4 = W 2 ∗ W 2 , ... D(2dlog n−1e) = D2dlog n−1e = Ddlog n−1e−1 ∗ Ddlog n−1e−1 Algorithmus 5 namens mmAPD zeigt nun, wie man durch fortgesetzte Aufrufe an eine Subroutine zur modifizierten Matrixmultiplikation die Distanzen der paarweise kürzesten Wege berechnen kann. Algorithmus 4 : MatrixMultiply Input : Matrizen A, B Output : Matrizenprodukt AB 1 for i = 1 to n do 2 for j = 1 to n do 3 Cij ← ∞ 4 for k = 1 to n do 5 Cij ← min{Cij , Aik + Bkj } 6 return C Momentan liegt die beste bekannte Laufzeit eines Algorithmus für Matrixmultiplikation bei O(n2.373 ) [LG14]. Eine bessere untere Schranke als Ω(n2 ) ist nicht bekannt, so dass hier eine noch nicht geschlossene Lücke zwischen unterer und oberer Laufzeitschranke klafft. Die obere Laufzeitschranke kann auf die Multiplikation von boolschen Matrizen angewandt werden, wie wir in Kürze sehen werden. Bedauerlicherweise folgt aus dieser Beobachtung aber 1.3. Kürzeste Wege 11 Algorithmus 5 : mmAPD Input : Gewichtsmatrix W Output : Distanzmatrix 1 D (1) ← W 2 m←1 3 while m < n − 1 do 4 D(2m) ← M atrixM ultiply(D(m) , D(m) ) 5 m ← 2m 6 return D(m) auch eine Laufzeit für das APD Problem, die größer als O(n2 ) ist (jedenfalls solange man über keinen Algorithmus mit quadratischer Zeitkomplexität zur Matrixmultiplikation verfïügt). Die Laufzeit des Algorithmus mmAPD ist O(mm(n) · log n), wobei mm(n) die Zeit ist, um zwei n × n Matrizen miteinander zu multiplizieren. Es gibt allerdings einen Nachteil, denn es gibt keine implizite Darstellung der kürzesten Wege, denn dazu wären alle Matrizen D1 , . . . , Dm notwendig und die Laufzeit würde auf O(mm(n) · n) ansteigen. 1.3.3.3. Distanzberechnung mit dem Algorithmus von Seidel Wir betrachten nun das Problem Distanzberechnungen in ungerichteten und ungewichteten Graphen. Problem APD: • Gegeben: Ungerichteter, ungewichteter Graph G = (V, E). • Gesucht: Matrix D = (δ(i, j))ij , wobei δ(i, j) die Distanz von i nach j in G ist. Wir werden zunächst einen alternativen Algorithmus kennenlernen, der das APD-Problem in Zeit O(mm(n) · log n) für ungewichtete, ungerichtete Graphen löst. Dieser Algorithmus wird anschließend so erweitert, dass auch die kürzesten Wege zu den Distanzen schnell berechnet werden können. Bemerkung 1.15. Es sei G(V, E) ein ungerichteter, ungewichteter Graph mit Adjazenzmatrix A. Ist Z = A2 , so ist Zij > 0 genau dann, wenn es einen Weg der Länge 2 von i nach j gibt. Zij gibt die Anzahl der verschiedenen Wege der Länge 2 von i nach j an, was aus Theorem 1.8 folgt. Damit können wir durch eine einfache Matrixmultiplikation eine Matrix Z berechnen, die es erlaubt, schnell einen Graphen G0 zu berechnen, in dem zwei Knoten i und j genau dann miteinander verbunden sind, wenn δ(i, j) ≤ 2 in G ist: 2 Z = A ( 1, falls i 6= j und (Aij = 1 oder Zij > 0) A0ij = 0, sonst G0 = 0 der durch A induzierte Graph Lemma 1.16. Es sei G = (V, E) ein ungerichteter, ungewichteter Graph mit Adjazenzmatrix 0 0 A. Ist A derart, dass Aij = 1 genau dann gilt, wenn i 6= j und (Aij = 1 oder Zij > 0), und ist 0 0 0 D die Distanzmatrix des durch A gegebenen Graphen G , so gilt: 12 1. Grundlegende Graphenalgorithmen 0 1. Dij = 2Dij , wenn Dij gerade ist und 0 2. Dij = 2Dij − 1, wenn Dij ungerade ist. Beweis. Wir betrachten die beiden Fälle: • Fall Dij = 2k ist gerade: ⇒ ∃ kürrzester Weg P = hi = i0 , i1 , ..., i2k−1 , i2k = ji von i nach j in G. 0 0 ⇒ P = hi = i0 , i2 , ..., i2k−2 , i2k = ji ist Weg von i nach j in G . 0 ⇒ Dij ≤ k 0 Wäre Dij = l < k, so existierte ein Weg Q von i nach j in G der Länge ≤ 2l (Widerspruch, 0 da Dij = 2k). Daraus folgt Dij = k. 0 Also Dij = 2k = 2Dij . • Fall Dij = 2k + 1 ungerade: ⇒ ∃ kürrzester Weg P = hi = i0 , i1 , ..., i2k , i2k+1 = ji von i nach j in G. 0 0 ⇒ P = hi = i0 , i2 , ..., i2k , i2k+1 = ji ist Weg von i nach j in G . 0 ⇒ Dij ≤ k + 1 0 Wäre Dij = l ≤ k, so existierte ein Weg Q von i nach j in G der Länge ≤ 2k (Widerspruch, 0 da Dij = 2k + 1). Daraus folgt Dij = k + 1. 0 Also Dij = 2k + 1 = 2Dij − 1. Die Idee für einen Algorithmus beläuft sich auf drei hauptsächliche Schritte: 0 0 1. Berechne die Distanzen D für G (rekursiv). 2. Berechne die Parität der Distanzen in G. 3. Dann liefert Lemma 1.16 eine Berechnungsvorschrift für die Distanzen D in G. Lemma 1.17. Betrachte ein beliebiges Paar disjunkter Knoten i, j ∈ V des Graphen G. 1. Für alle Nachbarn k ∈ Γ(i) gilt Dij − 1 ≤ Dkj ≤ Dij + 1. 2. Es existiert ein Nachbar k ∈ Γ(i) mit Dkj = Dij − 1. Beweis. Sei P = hi = i1 , i2 , ..., ip+1 = ji kürzester Weg von i nach j in G, also Dij = p. 1. Sei k ∈ Γ(i), d. h. {i, k} ∈ E. a) k = i2 ⇒ P1 = hk = i2 , ..., ip+1 = ji ist Weg von k nach j ⇒ Dkj ≤ p + 1 b) k 6= i2 ⇒ P2 = hk = i0 , i1 , ..., ip+1 = ji ist Weg von k nach j ⇒ Dkj ≤ p + 1 In jedem Fall: Dkj ≤ p + 1 = Dij + 1 c) Annahme: Dkj = q < Dij − 1. Dann existiert P3 = hk = k1 , k2 , ..., kq+1 = ji von k nach j ⇒ P4 = hi = k0 , k1 , k2 , ..., kq+1 = ji ist ein Weg der Länge q + 1 < Dij von i nach j (Widerspruch zur Definition von Dij ). 2. Folgt aus 1 (a) und (c). Lemma 1.18. Betrachte ein beliebiges Paar disjunkter Knoten i, j ∈ V des Graphen G. 1.3. Kürzeste Wege 0 13 0 1. Ist Dij gerade, so ist Dkj ≥ Dij für alle Nachbarn k ∈ Γ(i). 0 0 2. Ist Dij ungerade, so ist Dkj ≤ Dij für alle Nachbarn k ∈ Γ(i). Außerdem existiert ein 0 0 k ∈ Γ(i) derart, dass Dkj < Dij . Beweis. Wir betrachten die beiden Fälle: • Fall 1. Dij = 2l ist gerade. ⇒ ∀ Nachbarn k ∈ Γ(i): Dkj ≥ 2l − 1 |{z} Lemma 1.17 0 Dann ist Dij = l nach Lemma 1.16 a). 0 Weiter folgt aus Lemma 1.16 a,b), dass Dkj ≥ Dkj /2 ≥ l − 0 0 0 Dkj ist ganzzahlig ⇒ Dkj ≥ l = Dij 1 2 • Fall 2. Dij = 2l − 1 ist ungerade. ∀ Nachbarn k ∈ Γ(i): Dkj ≤ 2l ⇒ |{z} Lemma 1.17 0 Dann ist Dij = l nach Lemma 1.16 b). 0 Weiter folgt aus Lemma 1.16 a,b), dass Dkj ≤ (Dkj + 1)/2 ≤ l + 12 0 0 0 Dkj ist ganzzahlig ⇒ Dkj ≤ l = Dij 0 Weiter gilt, dass ein k ∈ Γ(i) mit Dkj = Dij − 1 = 2l − 2 existiert, also gilt Dkj = l − 1 < 0 l = Dij nach Lemma 1.16 a). Lemma 1.19. Betrachte ein beliebiges Paar disjunkter Knoten i, j ∈ V des Graphen G. P 0 0 1. Dij ist gerade genau dann, wenn k∈Γ(i) Dkj ≥ Dij · deg (i). P 0 0 2. D ist ungerade genau dann, wenn k∈Γ(i) Dkj < Dij · deg (i). Beweis. Es gilt: • Fall 1. Dij ist P Pgerade 0 0 0 ⇒ k∈Γ(i) Dij = deg(i)Dij . k∈Γ(i) Dkj ≥ |{z} Lemma 1.18 a) • Fall 2. Dij ist Pungerade0 P 0 0 ⇒ k∈Γ(i) Dkj ≤ k∈Γ(i) Dij − 1 = deg(i)Dij − 1. |{z} Lemma 1.18 b) Die jeweilige Rückrichtung ergibt sich durch die Betrachtung der beiden komplementären Fälle. Wir betrachten nun den Algorithmus APD, der die Distanzen Dij für alle Knotenpaare (i, j) für einen gegebenen ungerichteten Graphen G berechnet. Der Graph wird durch seine Adjazenzmatrix A repräsentiert. Theorem 1.20. Der Algorithmus APD berechnet die Distanzmatrix D eines n-Knoten Graphen G in Zeit O(mm(n) · log n) mit Hilfe der ganzzahligen Matrixmultiplikation, wobei die Einträge der Matrix nicht größer als O(n2 ) sind. 0 0 Beweis. Sei δ der Durchmesser von G. Dann hat G Durchmesser δ = dδ/2e. Sei T (n, δ) die Zeit, die APD auf Graphen mit n Knoten und Durchmesser δ benötigt. Ist δ = 1, so ist G vollständig. Ist δ = 2, so ist T (n, δ) = mm(n) + O(n2 ). Wegen δ < n, mm(n) = Ω(n2 ) und Rekursionstiefe 0 log n folgt die Laufzeit O(mm(n) log n). Wegen Dij < n und somit Dij < n sind die Einträge von S durch n2 nach oben beschränkt. 14 1. Grundlegende Graphenalgorithmen Algorithmus 6 : APD Input : Adjazenzmatrix A Output : Distanzmatrix D 1 Z ← A2 0 0 2 Berechne A mit Aij = 1 ⇔ i 6= j und (Aij = 1 oder Zij > 0) 0 // Aij = 1 ⇔ es ex. Weg der Länge 1 od. 2 v. i nach j 0 3 if Aij = 1 ∀i 6= j then 0 4 return D ← 2A − A // Rekursionsabbruch 0 5 6 7 0 D ← AP D(A ) 0 S ←A·D ( 0 2Dij , return D mit Dij = 0 2Dij − 1, 0 falls Sij ≥ Dij Zii 0 falls Sij < Dij Zii // Rekursion P 0 // Sij = k∈Γ(i) Dkj // Zii = deg(i) 1.3.4. Paarweise kürzeste Wege mit dem Algorithmus von Seidel Wir werden nun den Algorithmus von Seidel für das Problem APD so erweitern, dass nicht nur die Distanzen Dij , sondern auch für jedes Knotenpaar (i, j) ein kürzester Weg berechnet wird. Der erweiterte Algorithmus löst somit das Problem APSP : Problem APSP: • Gegeben: Ungerichteter, ungewichteter Graph G = (V, E). • Gesucht: Matrix D = (δ(i, j))ij wie bei APD und eine implizite Darstellung der kürzesten Wege. Dabei soll die Laufzeit des neuen Algorithmus subkubisch sein. Wir werden zeigen, dass das APSP-Problem in erwarteter Zeit O(mm(n) · log2 n) durch einen randomisierten Algorithmus lösbar ist. Das Problem ist jedoch, dass es Graphen G = (V, E) von der Gestalt gibt, dass Ω(n2 ) Knotenpaare Distanz Ω(n) haben. Beispiel 1.21. G = (V, E) ist eine „Linie”: V = {1, ..., n}, E = {(i, i + 1)|1 ≤ i < n}. Setze δ = n2 = Ω(n), dann haben n−δ X k=1 k= (n − δ + 1)(n − δ) n2 > = Ω(n2 ) 2 8 Knotenpaare mindestens den Abstand δ zueinander. Explizites Speichern der kürzesten Wege würde daher Platzbedarf Ω(n3 ), also auch Zeitaufwand Ω(n3 ), bedeuten. Daher werden die kürzesten Wege nur implizit gespeichert, indem zu jedem Knotenpaar (i, j) der Nachfolger Sij von i auf einem kürzesten Weg nach j gespeichert wird. S = (Sij ) hat O(n2 ) Einträge und ein kürzester Weg von i nach j kann in Zeit proportional zu seiner Länge bestimmt werden: Wir bezeichnen im Folgenden: • die boolsche1 Matrixmultiplikation mit ∧ als Multiplikation und ∨ als Addition durch "‘∗"’ 1 Da diese Bezeichnung auf George Boole (1815-1864) zurückgeht, findet man auch häufig die Schreibweise boolesche Matrixmultiplikation. 1.3. Kürzeste Wege 15 Algorithmus 7 : SPN Input : S, i, j 1 x0 ← i 2 k ←0 3 repeat 4 xk+1 ← Sxk j 5 k + +; 6 until xk = j 7 return {x0 , . . . , xk } und • die ganzzahlige Matrixmultiplikation mit "‘·"’. Definition 1.22. Es seien A, B ∈ {0, 1}n×n boolsche Matrizen, P = A ∗ B ∈ {0, 1}n×n das boolsche Produkt von A und B. Ein Zeuge für Pij ist ein Index k ∈ {1, ..., n} derart, dass Aik = 1 = Bkj . Bemerkung 1.23. Es gilt: 1. Pij = 1 ⇔ es gibt einen Zeugen k für Pij . 2. Ist C = A · B, so ist Cij die Anzahl der Zeugen für Pij . 3. Ist A Adjazenzmatrix eines Graphen G = (V, E), P = A ∗ A und C = AA, so ist Pij = 1 genau dann, wenn ein Weg der Länge 2 zwischen i und j existiert. Cij ist die Anzahl dieser Wege (vgl. Lemma 1.15). 4. Für P = A ∗ A ist ein Zeuge k für Pij = 1 Zwischenknoten auf einem Weg der Länge 2 von i nach j. 5. Für jedes Pij bzgl. P = A ∗ B kann es bis zu n Zeugen geben. Zeugen sind interessant, wenn man den APD-Algorithmus so erweitern will, dass er kürzeste Wege berechnet. Da Zeugen Zwischenknoten auf Wegen der Länge 2 darstellen, helfen sie bei der Konstruktion einer Nachfolgermatrix. Wie genau dies funktioniert, wird nachfolgend erläutert. Definition 1.24. Es seien A, B ∈ {0, 1}n×n boolsche Matrizen, P = A∗B ∈ {0, 1}n×n . Eine Zeugenmatrix (Bpwm = Boolean Product Witness Matrix) für P ist eine Matrix W ∈ {0, ..., n}n×n mit ( 0, wenn Pij = 0 Wij = k, k ist Zeuge für P {ij} = 1 Problem Bpwm: • gegeben: boolsche Matrizen A und B. • gesucht: eine Zeugenmatrix W für P = A ∗ B. Ein trivialer Algorithmus für Bpwm, der für alle (i, j) ∈ {1, ..., n}2 alle k ∈ {1, ..., n} testet, hat Zeitaufwand O(n3 ). Da wir einen niedrigeren Aufwand anstreben, vereinfachen wir zunächst das Problem Bpwm: 16 1. Grundlegende Graphenalgorithmen Problem UniqueBpwm: • gegeben: boolsche Matrizen A und B, so dass jeder Eintrag in P = A∗B einen eindeutigen Zeugen hat. • gesucht: die Zeugenmatrix W für P = A ∗ B. Lemma 1.25. Es seien A, B ∈ {0, 1}n×n boolsche Matrizen und die Matrizen  und W gegeben durch Âik = kAik und W = ÂB. Dann gilt: 1. Wij ist Zeuge für Pij , wenn Pij einen eindeutigen Zeugen hat. 2. Hat jeder Eintrag von Pij einen eindeutigen Zeugen, so ist W die Lösung von UniqueBpwm. Beweis. Es ist W = n X k=1 Beispiel 1.26. Âik Bkj = n X k=1 k · Aik Bkj falls genau ein Aik Bkj = 1 k, = 0, falls Aik Bkj = 0 ∀k > k, falls Aik Bkj = 1 und Ail Blj = 1 für ein l 6= k. 1 1 0 1 0 0 A = 1 0 0 , B = 1 1 0 , P 0 0 0 0 0 0 1 2 0 3  = 1 0 0 und W = 1 0 0 0 0 1 1 0 = 1 0 0 . 0 0 0 2 0 0 0 . 0 0 Die grünen und blauen Einträge von W sind schon korrekte Einträge für eine Zeugenmatrix, der rote jedoch nicht. Bemerkung 1.27. Das Problem UniqueBpwm kann durch eine ganzzahlige Matrixmultiplikation, also in Zeit O(mm(n)), gelöst werden. Problematisch ist nun, dass wir eine Zeugenmatrix W für P = A ∗ A mit einer Adjazenzmatrix A berechnen wollen. Dabei ist natïrlich nicht garantiert, dass die Zeugen immer eindeutig sind. Die Idee zur Lösung des Problems lässt sich so beschreiben: • Randomisierung liefert den gleichen Effekt wie eindeutige Zeugen für genügend viele Einträge Pij , denn bei einer zufälligen Auswahl von Kandidatenmengen trifft man wahrscheinlich auf eine Menge mit genau einem Zeugen. • Die wenigen verbleibenden Einträge werden dann mit dem trivialen Algorithmus berechnet. 1.3. Kürzeste Wege 17 1.3.4.1. Nicht eindeutige Zeugen Wir betrachten boolsche Matrizen A, B ∈ {0, 1}n×n , P = A ∗ B, C = AB und einen festen Eintrag Pij von P . Es sei w = Cij die Anzahl der Zeugen für Pij (OE w ≥ 2, denn nach den Vorbetrachtungen ist es einfach, einen eindeutigen Zeugen zu finden). Außerdem sei r ∈ N mit n 2 ≤ wr ≤ n. Ziel ist es, eine Menge R ⊂ {1, ..., n} mit |R| zu finden, die den eindeutigen Zeugen k für Pij enthält. Lemma 1.28. Es sei n ∈ N, w ∈ {1, ..., n}, r ∈ N mit n2 ≤ wr ≤ n. Eine Urne enthalte n Bälle, von denen w weiß und n − w schwarz sind. Zieht man zufällig r Bälle aus der Urne, ohne diese zwischendurch zurückzulegen, so ist: P r(genau ein weißer Ball wurde gezogen) ≥ 1 . 2e Beweis. Durch elementare Rechenoperationen kann die gesuchte Wahrscheinlichkeit wie folgt beschränkt werden: w n−w r! (n − w)! (n − r)! 1 r−1 = w n (r − 1)! n! (n − w − r + 1)! r ! w−1 w−2 Y 1 Y = wr (n − r − j) n−i i=0 j=0 w−2 wr Y n − r − j = n n−1−j j=0 w−2 Y wr n − r − j − (w − j − 1) ≥ siehe (*) n n − 1 − j − (w − j − 1) j=0 w−2 Y n − w − (r − 1) wr = n n−w j=0 wr r − 1 w−1 = 1− n n−w 1 w−1 1 ≥ 1− siehe (**) 2 w (*) Gilt faktorweise: a = n − r − j, b = n − 1 − j, c = w − j − 1. Dann ist a(b − c) ≥ b(a − c) ⇔ ac ≤ bc ⇔ a ≤ b. r−1 (**) n−w ≤ w1 ⇔ (r − 1)w ≤ n − w ⇔ rw ≤ n. Die letzte Ungleichung folgt von den Beobachtungen, dass wr/n ≥ 1/2 und (r−1)/(n−w) ≤ 1/w, was aus der Annahme, dass n/2 ≤ wr ≤ n, folgt. Beispiel 1.29. n = 8, w = 3, n − w = 5. Einzig mögliche Wahl für r mit • 3 Möglichkeiten, genau 2 weiße Bälle zu ziehen • 10 Möglichkeiten, genau 2 schwarze Bälle zu ziehen • 15 Möglichkeiten, genau 1 weißen und 1 schwarzen Ball zu ziehen n 2 ≤ wr ≤ n ist r = 2: 18 1. Grundlegende Graphenalgorithmen • 28 Möglichkeiten insgesamt. Damit ist P r(genau ein weißer Ball wurde gezogen) = 28−13 28 = 15 28 > 1 2 > 1 2e ≈ 0.184. Sei jetzt R ⊂ {1, ..., n} derart, dass R einen eindeutigen Zeugen für Pij enthällt. R sei gegeben durch einen Vektor R ∈ {0, 1}n mit Rk = 1 genau dann, wenn k ∈ R. Definiere: • eine Matrix AR ∈ Nn×n durch AR 0 ik = kRk Aik und R =R B • eine Matrix B R ∈ Nn×n durch Bkj k kj 0 Weiterhin sind die Matrizen  mit Âik = kAik sowie B und W =  · B so wie bereits weiter oben verwendet. AR ist die Matrix, die aus  entsteht, indem jede Spalte von Â, die zu einem Element k ∈ / R gehört, durch eine Nullspalte ersetzt wird und jede andere Spalte k mit k multipliziert wird. B R ist die Matrix, die aus B entsteht, indem jede Zeile von B, die zu einem Element k ∈ /R gehört, durch eine Nullzeile ersetzt wird. Lemma 1.30. Es seien A, B ∈ {0, 1}n×n boolsche Matrizen, AR und B R wie oben, W = AR ·B R . Wenn Pij einen eindeutigen Zeugen in R hat, so ist Wij Zeuge für Pij . P Pn P R Beweis. Wij = (AR ·B R )ij = nk=1 AR k∈R k ·Aik ·Bkj . Wenn k=1 k ·Rk ·Aik ·Rk Bkj = ik Bkj = R nur einen einzigen Zeugen enthält, folgt aus der Zeugeneigenschaft: Wij = k · Aik · Bkj = k, wobei k der eindeutige Zeuge ist. Die weiteren Ideen, die zum fertigen Algorithmus führen, lassen sich so umschreiben: • W = AR B R liefert Zeugen für alle Einträge in P = A ∗ B, die einen eindeutigen Zeugen in R haben. • Nach Lemma 1.28 ist die Wahrscheinlichkeit dafür, dass eine zufällig gewählte Menge R der Größe |R| = r einen eindeutigen Zeugen für einen Eintrag von P mit w Zeugen enthällt, 1 größer oder gleich der Konstanten 2e , wenn n2 ≤ wr ≤ n ist. • Wir wählen O(log n) Mengen R zufällig aus. Damit wird es sehr unwahrscheinlich, dass für einen Eintrag von P kein Zeuge identifiziert wird. • Zeugen für die Einträge, für die kein Zeuge identifiziert wird, werden mit dem trivialen Algorithmus berechnet. • Da nicht alle Einträge von P die gleiche Anzahl Zeugen haben, müssen Mengen R mit verschiedenen Kardinalitäten r benutzt werden. Es reicht jedoch, für r die Zweierpotenzen zwischen 1 und n zu benutzen, da nur die Bedingung n2 ≤ wr ≤ n erfüllt sein muss. Theorem 1.31. Der Algorithmus Bpwm ist ein Las-Vegas-Algorithmus für das Problem Bpwm mit erwarteter Laufzeit O(mm(n) log2 n). Beweis. Die Initialisierung benötigt O(mm(n)) Zeit. Der Algorithmus durchläuft die innere Schleife O(log2 n)-mal und führt jedes Mal eine ganzzahlige Matrixmultiplikation von n × n Matrizen durch. Die anderen Operationen in der Schleife sind weniger zeitaufwändig. Die Laufzeit O(mm(n) log2 n) folgt, wenn nicht zu oft der triviale Algorithmus aufgerufen werden muss. • Beh.: Ist Pij = 1, so wird im randomisierten Teil des Algorithmus ein Zeuge mit Wahrscheinlichkeit ≥ 1 − n1 gefunden. 1.3. Kürzeste Wege 19 Algorithmus 8 : BPWM Input : Boolsche Matrizen A, B ∈ {0, 1}n×n Output : Zeuge für P 1 W ← −AB // Wij < 0 ⇔ Zeuge für Pij muss noch gefunden werden 2 for t = 0, ..., blog nc do // teste alle Zweierpot. r = 2t zwischen 1 und n 3 r ← 2t 4 repeat d3.77 log ne times 5 Wähle R ⊆ {1, ..., n} mit |R| = r 6 Berechne AR und B R // vgl. Lemma 1.28 7 Z ← AR B R 8 forall the (i, j) do // teste, ob neuer Zeuge für Pij gefunden wurde 9 if Wij < 0 und Zij ist Zeuge für Pij then 10 Wij ← Zij 11 12 13 forall the (i, j) do if Wij < 0 then Berechne Wij mit dem trivialen Algorithmus // kein Zeuge für Pij gefunden • Bew.: Sei w die Anzahl der Zeugen für Pij . Die äußere Schleife wird mindestens einmal mit einem Wert r mit n2 ≤ wr ≤ n durchlaufen. In diesem Durchlauf ist die Wahrscheinlichkeit, 1 dass R keinen eindeutigen Zeugen für Pij enthällt, höchstens 1 − 2e nach Lemma 1.28. Damit ist die Wahrscheinlichkeit, dass kein Zeuge für Pij identifiziert wird höchstens (1 − 1 3.77 log n ≤ n1 . 2e ) Damit ist die erwartete Anzahl der nicht gefundenen Zeugen begrenzt durch n, anstelle der ursprïnglichen n2 . Somit benötigen alle Aufrufe des trivialen Algorithmus zusammen Zeit O(n2 ). 1.3.4.2. Randomisierter Algorithmus Wir schließen das Thema in diesem Abschnitt mit der Beschreibung des randomisierten Algorithmus ab, der anhand einer Zeugenmatrix eine Nachfolgermatrix berechnet. Zuvor muss noch festgelegt werden, wie genau diese Nachfolgermatrix berechnet wird. Definition 1.32. Es sei G = (V, E) ein Graph mit n Knoten. Eine Nachfolgermatrix S für G ist eine n × n-Matrix, so dass für alle i 6= j Sij ein Nachfolger von i ist, der auf einem kürzesten Weg von i nach j liegt. Weiter ist Sii = 0. Sei nun A die Adjazenzmatrix eines Graphen G = (V, E), D die Distanzmatrix von G. Seien i, j ∈ {1, ..., n}, i 6= j beliebig mit Dij = d. Sij = k ist genau dann möglich, wenn Dik = 1 und d = 1 genau dann, wenn D d Dkj = d − 1. Sei B d ∈ {0, 1}n×n mit Bkj kj = d − 1 (B kann aus D in Zeit O(n2 ) berechnet werden). Lemma 1.33. Es sei A Adjazenzmatrix eines Graphen G = (V, E) und B d ∈ {0, 1}n×n wie oben definiert. Der Aufruf Bpwm(A, B d ) liefert für alle i, j mit Dij = d Einträge Sij einer Nachfolgermatrix S für G. Der Beweis von Lemma 1.33 ist dem Leser zur Übung empfohlen. Das Problem ist, dass es n mögliche Werte für d gibt. Damit wäre die Laufzeit eines Algorithmus mindestens Ω(nmm(n)) und somit superkubisch. Aber es reichen drei Berechnungen von Zeugenmatrizen aus, denn: 20 1. Grundlegende Graphenalgorithmen • Für alle i, j und alle Nachfolger k von i gilt Dij − 1 ≤ Dkj ≤ Dij + 1. • Jeder Nachfolger k von i mit Dkj = Dij − 1 ist ein möglicher Eintrag für Sij . • Also: Jedes k mit Aik = 1 und Dkj ≡ Dij − 1 (mod 3) ist ein möglicher Eintrag für Sij . (s) • Für s = 0, 1, 2 definiere D(s) durch Dkj = 1 genau dann, wenn Dkj + 1 ≡ s (mod 3). • Eine Nachfolgermatrix S von A kann dann aus den Zeugenmatrizen für A ∗ D(s) , s = 0, 1, 2 berechnet werden. Algorithmus 9 : Apsp Input : Adjazenzmatrix A für G = (V, E) Output : Nachfolgematrix von G 1 Berechne Distanzmatrix D ← AP D(A) 2 for s = 0, 1, 2 do (s) 3 Berechne D(s) ∈ {0, 1}n×n derart, dass Dkj = 1 gdw. Dkj + 1 ≡ s (mod 3) 4 Berechne Zeugenmatrix W (s) ← BP W M (A, D(s) ) 5 (Dij (mod 3)) Berechne Nachfolgematrix S mit Sij = Wij Theorem 1.34. Der Algorithmus Apsp berechnet eine Nachfolgermatrix eines Graphen G mit n Knoten in erwarteter Zeit O(mm(n) log2 n). 1.4. Nicht erweiterbare unabhängige Mengen Definition 1.35. Sei G = (V, E) ein Graph. Eine Menge I ⊆ V heißt unabhängig, wenn je zwei beliebige Knoten aus V nicht adjazent sind. Eine unabhängige Menge I heißt nicht erweiterbar (engl.: maximal ), falls keine unabhängige Menge J existiert mit I ⊆ J und |I| < |J|. Der von einer unabhängigen Menge induzierte Subgraph besitzt folglich keine Kanten. Beachten Sie, dass eine nicht erweiterbare unabhängige Menge nicht notwendigerweise kardinalitätsmaximal unter allen unabhänigen Mengen ist! Ein sehr einfacher Algorithmus zur Berechnung einer nicht erweiterbaren unabhängigen Menge nimmt einen beliebigen Knoten v ∈ V , fügt ihn zu I hinzu und löscht v und N (v) aus dem Graphen. Dieses Vorgehen wird dann iteriert, bis der Graph leer ist. Zwar bekommt man auf diese Weise eine nicht erweiterbare unabhängige Menge. Aber das Verfahren ist inhärent sequentiell. Ein bekannter Algorithmus, der Parallelität nutzt, geht zurück auf Luby. Auch Lubys Algorithmus (Algorithmus 10) operiert in Phasen, aber in jeder Phase werden mehrere Knoten gleichzeitig in I eingefügt. Wir folgen hier der Darstellung von D. C. Kozen [Koz91]. Beachten Sie, dass wir im Schritt 1 des Algorithmus Knoten mit niedrigem Knotengrad bevorzugen. Hingegen werden in Schritt 2 Knoten mit hohem Knotengrad bessergestellt. Wir wollen nun das folgende Theorem beweisen. Theorem 1.36. Die erwartete Anzahl von Runden in Lubys Algorithmus ist O(log m). Wir werden dieses Theorem jedoch nicht vollständig beweisen. Vielmehr werden wir ein Hauptlemma zeigen, das besagt, dass in jeder Runde ein konstanter Anteil von Kanten aus dem aktuellen Graphen gelöscht wird. Wie man sich dann überlegen kann (was wir hier nicht tun), folgt daraus die logarithmische Rundenanzahl. Zum Beweis des Hauptlemmas benötigen wir zunächst einige Hilfsresultate. 1.4. Nicht erweiterbare unabhängige Mengen 21 Algorithmus 10 : Lubys MIS-Algorithmus 1. Berechne eine Menge S ⊆ V von Kandidaten für I, indem jeder Knoten v ∈ V parallel 1 mit Wahrscheinlichkeit 2d(v) in S eingefügt wird. 2. Prüfe für jede Kante e ∈ E, ob beide Endpunkte in S sind. Ist dies der Fall, lösche den Endknoten mit kleinerem Grad aus S. Löse evtl. Konflikte beliebig auf, z. B. gemäß Knotennummer. Füge die resultierende Menge zu I hinzu. 3. Lösche S und N (S) aus G und gehe zu 1., falls G nicht leer ist. Lemma 1.37. Für jeden Knoten u ∈ V gilt: P r(u ∈ I | u ∈ S) ≥ 12 . Beweis. Zum Beweis der Aussage werden wir das Gegenereignis P r(u ∈ / I | u ∈ S) von oben beschränken. Ein Knoten u ∈ S wird genau dann nicht in I aufgenommen, wenn ein Nachbar mit mindestens gleich großem Grad in S aufgenommen wird. Es gilt: P r(u ∈ / I | u ∈ S) = P r(∃v ∈ N (u) ∩ S, d(v) ≥ d(u) | u ∈ S) X ≤ P r(v ∈ S | u ∈ S) v∈N (u), d(v)≥d(u) ≤ ≤ ≤ X v∈N (u), d(v)≥d(u) X v∈N (u), d(v)≥d(u) X v∈N (u), d(v)≥d(u) ≤ d(u) · P r(v ∈ S) 1 2d(v) 1 2d(u) (da d(v) ≥ d(u)) 1 1 = . 2d(u) 2 Ein Knoten, der in S landet, wird also mindestens mit Wahrscheinlichkeit 21 auch in I in derselben Runde aufgenommen. Daraus ergibt sich eine weitere Abschätzung, wie wahrscheinlich es ist, dass ein Knoten in I aufgenommen wird. Lemma 1.38. Für jeden Knoten u ∈ V gilt P r(u ∈ I) ≥ 1 4d(u) . Beweis. Nach Definition der bedingten Wahrscheinlichkeit und mit Lemma 1.37 ergibt sich: P r(u ∈ I) = P r(u ∈ I | u ∈ S) · P r(u ∈ S) 1 1 ≥ · 2 2d(u) 1 ≥ . 4d(u) Für den Rest des Beweises benötigen wir zunächst eine weitere Definition. Definition 1.39. Wir sagen, dass ein Knoten u ∈ V gut ist, falls X v∈N (u) 1 1 ≥ . 2d(v) 6 22 1. Grundlegende Graphenalgorithmen Eine Kante ist gut, falls mindestens einer ihrer Endpunkte gut ist. Ein Knoten oder eine Kante sind schlecht, wenn sie nicht gut sind. Damit lässt sich ein weiteres Hilfsresultat folgern. Lemma 1.40. Falls u gut ist, dann gilt P r(u ∈ N (I)) ≥ 1 36 . Beweis. Wir betrachten zwei Fälle. Im ersten Fall existiere ein Knoten v ∈ N (u) mit d(v) ≤ 2. Nach Lemma 1.38 folgt P r(u ∈ N (I)) ≥ P r(v ∈ I) 1 ≥ 4d(v) 1 ≥ . 8 Der zweite Fall ist das Komplement und muss detaillierter untersucht werden. Es gilt also d(v) ≥ 3 1 für alle v ∈ N (u) und somit 2d(v) ≤ 61 . Da der Knoten u gut ist, gilt nach Definition 1.39 X v∈N (u) 1 1 ≥ . 2d(v) 6 (1.4.1) Da jeder Summand einzeln kleiner als 1/6 ist, lässt sich immer eine Teilmenge M (u) ⊆ N (u) derart finden, dass X 1 1 1 ≤ ≤ . 6 2d(v) 3 v∈M (u) Da nach dem Prinzip P des Ein- undPAusschließens für eine Menge von Ereignissen A die Ungleichung P r(∪A) ≥ A∈A P r(A) − A,B∈A, A6=B P r(A ∩ B) gilt, folgt in unserem Fall: P r(∃v ∈ M (u) ∩ I) ≥ Insgesamt ergibt sich somit: X v∈M (u) P r(v ∈ I) − X v,w∈M (u), v6=w P r(v ∈ I∧w ∈ I) (1.4.2) 1.4. Nicht erweiterbare unabhängige Mengen P r(u ∈ N (I)) ≥ P r(∃v ∈ M (u) ∩ I) X P r(v ∈ I) − ≥ v∈M (u) (nach 1.4.2) X 1 ≥ − 4d(v) v∈M (u) X v,w∈M (u), v6=w X v,w∈M (u), v6=w (nach Lemma 1.38) X X 1 ≥ − 4d(v) v∈M (u) v,w∈M (u), v6=w 23 P r(v ∈ I∧w ∈ I) P r(v ∈ S ∧ w ∈ S) P r(v ∈ S) · P r(w ∈ S) (wegen paarweiser Unabhänigkeit) X X X 1 1 1 ≥ − · 4d(v) 2d(v) 2d(w) v∈M (u) v∈M (u) w∈M (u) X X 1 1 1 ≥ − · 2d(v) 2 2d(w) v∈M (u) ≥ w∈M (u) 1 1 1 · = 6 6 36 (nach 1.4.1) Jetzt zeigen wir, dass mindestens die Hälfte aller Kanten gut sind. Lemma 1.41. Mindestens die Hälfte der Kanten in G sind gut. Beweis. Richte jede Kante zu ihrem Endpunkt mit höherem Knotengrad. Dabei werden die Konflikte so wie im Algorithmus aufgelöst. Jeder schlechte Knoten hat dabei mindestens doppelt so viele Kanten, die ihn verlassen, wie Kanten, die in ihn hineinführen. Wäre dies nicht der Fall, hätte mindestens ein Drittel der zu v adjazenten Knoten Grad d(v) oder niedriger. Das würde implizieren, dass v gut ist. Indem wir diese Tatsache nutzen, weisen wir jede schlechte Kante e, die in einen schlechten Knoten v hineinführt, einem Paar von Kanten (gut oder schlecht) zu, die aus v hinausführen. Dies geschieht derart, dass jede schlechte Kante an ein eindeutiges Paar zugewiesen wird. Dies impliziert, dass es mindestens doppelt so viele Kanten insgesamt wie schlechte Kanten gibt. Anders gesagt ist mindestens die Hälfte aller Kanten gut. Wir können nun das Hauptlemma beweisen. Lemma 1.42. Bezeichne die Zufallsvariable X die Zahl der Kanten, die in der aktuellen Phase gelöscht werden. Dann gilt: |E| E(X) ≥ . 72 Beweis. Sei EG die Menge der guten Kanten. Für e ∈ E definiere die Zufallsvariable ( 1, falls e gelöscht wird Xe = 0, sonst. 24 1. Grundlegende Graphenalgorithmen Dann folgt X = P e∈E Xe und wegen der Linearität des Erwartungswertes, E(X) = X E(Xe ) e∈E ≥ ≥ ≥ ≥ X E(Xe ) e∈EG X 1 36 (nach Lemma 1.40) e∈EG |EG | 36 |E| 72 (nach Lemma 1.41) Wir haben also gezeigt, dass in jeder Runde des Algorithmus ein konstanter Anteil der Kanten des jeweils aktuellen Graphen entfernt wird. Diese Feststellung impliziert, dass man nach erwartet logarithmisch vielen Runden fertig ist. 1.5. Weiterführende Literatur Eine ausführliche Darstellung zur Dualität von Matrizen und Graphen findet sich im Buch Graph Algorithms in the Language of Linear Algebra von Kepner und Gilbert (Hrsg.) [KG11]. Besonders in den ersten beiden Kapiteln dieses Buches wird verstärkt auf allgemeine Halbringe und Matrizenmultiplikationen und ihre Verwendung in Graphenalgorithmen eingegangen. Die Darstellung von Lubys Algorithmus sowie dessen Analyse folgt im Wesentlichen dem Lehrbuch von Kozen [Koz91]. 25 2. Datenstrukturen für dünn besetzte Matrizen Beim Entwurf und der Implementierung von Algorithmen spielt die Wahl der Datenstruktur eine zentrale Rolle. Hier bilden Algorithmen für dünn besetzte Matrizen (bzw. Graphen ohne reichhaltige semantische Informationen) keine Ausnahme, denn die Darstellung dünner Matrizen bestimmt nicht nur die Effizienz der eingesetzten Algorithmen. Sie wirkt sich auch auf den gesamten Entwurfsprozess aus. Aus softwaretechnischer Sicht ist zu beachten, dass die Details der Datenstruktur von den Algorithmen abgekapselt werden. In dem Fall lässt sich die Datenstruktur intern ändern, ohne dass man die Algorithmen anpassen muss. In diesem Kapitel werden wir die bekanntesten Datenstrukturen für dünn besetzte Matrizen kennenlernen. Für die grundlegenden Matrizenoperationen werden wir spezielle Algorithmen vorstellen, wobei der zusätzliche Speicherbedarf und die zusätzlichen Berechnungskosten berücksichtigt werden. 2.1. Cache-Effizienz Aufgrund der unregelmäßigen Verteilung von Einträgen und der verhältnismäßig hohen Speicherzugriffszeit auf den Hauptspeicher (RAM) ist die Cache-Effizienz bei Berechnungen auf dünn besetzten Matrizen besonders wichtig, insbesondere bei iterativen Algorithmen mit vielen Schleifendurchläufen. Deshalb wird in diesem Kapitel nicht nur auf die Berechnungskomplexität, sondern auch auf die Komplexität im I/O-Modell eingegangen, das je nach wissenschaftlicher Community auch EM-Modell (EM für external memory) genannt wird. 2.1.1. I/O-Modell Das I/O-Modell beschreibt ein hierarchisches Speichermodell, bei dem grundlegend zwischen zwei Arten von Speicher unterschieden wird, einem schnellen und einem langsamen. Der schnelle Speicher wird Cache genannt, der langsame Speicher normalerweise Disk. Manchmal findet man auch die Bezeichnungen Cache vs. RAM bzw. RAM vs. Disk. Wichtig ist eigentlich nur, dass die Einsichten meist für zwei beliebige aufeinanderfolgende Ebenen der Speicherhierarchie gelten. Wir wollen daher in unserem Fall beim schnellen Speicher vom Cache und beim langsamen Speicher vom Arbeitsspeicher oder RAM sprechen. Dabei sind beide Speicher in Blöcke derselben Größe L unterteilt. Benötigt der Prozessor Daten, die sich nicht im Cache befinden, tritt ein Cache miss auf und der ganze Speicherblock, der die benötigten Daten enthält, muss vom langsamen RAM geladen werden. Deshalb ist es wichtig, die Daten blockweise unter Ausnutzung von Lokalität abzuarbeiten, um die Anzahl der Cache misses zu minimieren. Definition. Unter der I/O-Komplexität eines Algorithmus versteht man die Anzahl der nötigen Speichertransfers zwischen dem schnellen und dem langsamen Speicher. Beispiel. Bei einer angenommenen Blockgröße von L hat das Lesen eines Speichers der Größe N eine I/O-Komplexität von N/L. 26 2. Datenstrukturen für dünn besetzte Matrizen Definition. Wir definieren scan(A) = nnz(A)/L als Abkürzung für die I/O-Komplexität, um alle Nichtnull-Einträge einer Matrix A zu lesen. 2.1.2. Modell-Annahmen Für das restliche Kapitel gelten die folgenden beiden Annahmen: Annahme: Für die Anzahl der Nichtnull-Einträge (nnz ) einer dünn besetzten Matrix der Dimensionen M × N gilt: nnz = Ω(N, M ). Dies vereinfacht die asymptotische Analyse der Algorithmen in diesem Kapitel, da wir nun bei Komplexitäten, die die Dimension der Matrix enthalten, auf diese verzichten und stattdessen stets nnz verwenden können. Annahme: Der schnelle Speicher ist nicht groß genug, um eine Datenstruktur der Größe O(N ) zu halten, wobei N die Dimension der Matrix ist. Ein Beispiel soll zeigen, dass die zweite Annahme gerechtfertigt ist: Bei der kleinsten Repräsentation einer dünn besetzten Matrix haben die Nichtnull-Einträge eine Größe von 16 Byte (8 Byte zur Indizierung, 8 Byte für die Daten). Das ergibt 230 /16 = 226 Nichtnull-Einträge pro GB. Eine quadratische, dünn besetzte Matrix mit 8 Einträgen pro Zeile füllt demnach ein GB RAM, wenn sie die Dimension 223 ×223 besitzt. Ein dichter double-Vektor der Dimension 223 würde demnach 64 MB L2 Cache pro GB benötigen, was üblicherweise deutlich größer als ein typischer L2 Cache ist. 2.1.3. Grundlegende Algorithmen im I/O-Modell 2.1.3.1. Sortieren Folgt. 2.1.3.2. Minimaler Spannbaum Folgt. 2.2. Grundlegende Matrix-Operationen In diesem Abschnitt werden die grundlegenden Operationen auf dünn besetzten Matrizen und ihre Entsprechungen bei Graphen beschrieben. Die meisten Operationen auf dünn besetzten Matrizen sind durch die numerische lineare Algebra motiviert, einige sind aber auch für Graphenalgorithmen nützlich: 2.2.1. Teilmatrizen addressieren (SpRef/SpAsgn) Die Abkürzung bezieht sich auf die englischen Ausdrücke sparse matrix indexing and assignment. Diese Operationen entsprechen der Auswahl eines Teilgraphen. • SpRef: B = A(p, q) : Speichert eine Teilmatrix von A in B. • SpAsgn: B(p, q) = A : Zuweisung einer Matrix an eine Teilmatrix B. Diese Operatoren können recht mächtig aber auch kompliziert sein, wenn p und q beliebige Vektoren von Indizes sein können. Deshalb beschränken wir uns in diesem Kapitel auf zeilenweise (A(i, :)), spaltenweise (A(:, i)) und elementweise (A(i, j)) Indizierung, welche auch am häufigsten Gebrauch finden. 2.2. Grundlegende Matrix-Operationen 27 Abbildung 2.2.1.: Links die Operation SpRef, rechts SpAsgn 2.2.2. Matrix-/Vektormultiplikation (SpMV) Die Abkürzung bezieht sich auf den englischen Ausdruck sparse matrix dense vector multiplication. Wie wir bereits in Kapitel 1 gesehen haben, entspricht SpMV einem Schritt einer Breitensuche im Graphen. Eine dünn besetzte Matrix kann von rechts (y = Ax) oder von links (y 0 = x0 A) mit einem dichten Vektor multipliziert werden. In diesem Skript beschränken wir uns auf die Multiplikation von rechts. Es ist im Allgemeinen einfach, die entsprechenden Algorithmen für die Matrixmultiplikation von links umzuformulieren. Einige Vertreter von Graphalgorithmen, die SpMV nutzen, sind PageRank, BFS, Bellman-Ford und Prim’s MST-Algorithmus. 2.2.3. Addition dünner Matrizen (SpAdd) Die Abkürzung bezieht sich auf den englischen Ausdruck sparse matrix addition. Die Operation entspricht der Vereinigung von Graphen und berechnet C = A ⊕ B. Dabei steht die Operation für einen beliebigen punktweisen, binären Operator ⊕ zwischen zwei Matrizen. Beispiele sind Addition, Subtraktion, MIN & MAX (Minimum bzw. Maximum der Operanden), logisches UND und logisches ODER. 2.2.4. Sparse matrix-sparse matrix multiplication (SpGEMM) Die Abkürzung bezieht sich auf den englischen Ausdruck generalized sparse matrix-matrix multiplication. Diese Operation entspricht aus Graphen-Sicht einem Schritt einer Breitensuche von mehreren Startknoten gleichzeitig aus bzw. APSP. Sie berechnet C = AB, wobei die Eingabematrizen A ∈ RM ×K und B ∈ RK×N beide dünn besetzt sind. SpGEMM findet häufig Verwendung beim Arbeiten auf großen Graphen, z.B. bei der Graphenkontrakion, bei der algebraischen Formulierung von Peer Pressure Clustering (das wir in Kapitel 3 in der Variante Label Propagation behandeln) oder Markov-Clustering sowie bei iterativen APD-Formulierungen (siehe z.B. Abschnitt 1.3.3.3). Für die Berechnung der Matrixmulitplikation gibt es mehrere Möglichkeiten. Eine übliche Methode berechnet den Eintrag C(i, j) mit Hilfe des Skalarproduktes der Zeile i von A und der Spalte j von B (siehe Algorithmus 11). Angelehnt an das Skalarprodukt, wird dieser Ansatz auch als inner product matrix multiply bezeichnet. Eine andere Möglichkeit besteht darin, das Matrixprodukt als Summe von n Matrizen mit Rang eins zu berechnen. Jede dieser Matrizen mit Rang eins ist das dyadische Produkt (outer product) einer Spalte k von A und einer Zeile k von B (siehe Algorithmus 12 und Abbildung 2.2.2). Eine weitere Möglichkeit ist die zeilen- bzw. spaltenweise Berechnung des Matrixprodukts. Algorithmus 13 zeigt die spaltenweise Formulierung, hierbei wird die Spalte j von C als Linearkombination aus Spalten von A und den Nichtnull-Einträgen der Spalte j von B berechnet. Abbildung 2.2.3 veranschaulicht dieses Konzept. Analog wird bei der zeilenweisen Formulierung 28 2. Datenstrukturen für dünn besetzte Matrizen Algorithmus 11 : Matrixmultiplikation mit Hilfe des Skalarprodukts Input : A : RM ×K , B : RK×N Output : C : RM ×N 1 for i = 1 to M 2 for j = 1 to N 3 C(i, j) ← A(i, :) · B(:, j); 4 return C Algorithmus 12 : Matrixmultiplikation mit Hilfe des dyadischen Produkts Input : A : RM ×K , B : RK×N Output : C : RS(M ×N ) 1 C ←0 2 for k = 1 to K 3 C ← C + A(:, k) · B(k, :); 4 return C Abbildung 2.2.2.: Schematische Matrixmultiplikation mit Hilfe des dyadischen Produkts 2.3. Tripel 29 Abbildung 2.2.3.: Schematische Darstellung der spaltenweisen Matrixmultiplikation die Zeile i von C als Linearkombination aus Zeilen von B und Nichtnull-Einträgen der Zeile i von A berechnet. Algorithmus 13 : Spaltenweise Matrixmultiplikation Input : A : RM ×K , B : RK×N Output : C : RM ×N 1 C ←0 2 for j = 1 to N 3 for k where B(k, j) 6= 0 4 C(:, j) ← C(:, j) + A(:, k) · B(k, j); 5 return C 2.3. Tripel Das Tripel- oder Koordinatenformat ist die einfachste Art, dünn besetzte Matrizen darzustellen. Hierbei wird für jeden Nichtnull-Eintrag A(i, j) 6= 0 ein Tripel (i, j, A(i, j)) gespeichert. Jeder Eintrag eines Tripels wird üblicherweise in einem der drei Arrays A.I (Zeilenindizes), A.J (Spaltenindizes) oder A.V (Werte) gespeichert, die die komplette§ Matrix A repräsentieren. Der Speicherverbrauch pro Tripel beträgt bei 8-Byte-Integers 8 + 8 + 8 = 24 Byte pro NichtnullEintrag. In modernen Programmiersprachen ist die Repräsentation von Tupeln als Struktur in einem Array einfacher und kann auch den Cache besser ausnutzen, da oft alle Werte eines Tripels von Interesse sind und so nicht aus drei unterschiedlichen Arrays gelesen werden muss. Bei drei unterschiedlichen Arrays kann es nämlich passieren, dass alle drei in dieselbe Cachezeile geladen werden und sich gegenseitig verdrängen. Diese Cache-Optimierung wird auch als array merging bezeichnet. In diesem Kapitel werden wir das Tripelformat mit unterschiedlichen Ordnungen der Einträge kennenlernen. 2.3.1. Ungeordnete Tripel Die Tripel werden nicht sortiert, der Verwaltungsaufwand der Tripel ist somit sehr gering. Allerdings besteht daher beim Zugriff auf die Einträge einer Zeile oder Spalte keinerlei Lokalität, d.h. im schlechtesten Fall müssen alle Tripel durchsucht werden, um einen bestimmten Eintrag zu finden. Ein Beispiel einer Matrix in ungeordneter Tripeldarstellung zeigt Abbildung 2.3.1. Bei der Berechunng von SpMV (y = Ax) spielt die Ordnung der Einträge aus theoretischer Sicht keine Rolle, d.h. die RAM-Komplexität ist schon bei ungeordneten Tripeln optimal. Wenn der Cache zuvor keine Einträge von A enthält, treten O(scan(A)) Cache-Fehlzugriffe auf. Zusätzlich wird für jedes Tripel (i, j, A(i, j)) ein Zugriff auf den j-ten Eintrag von x benötigt und 30 2. Datenstrukturen für dünn besetzte Matrizen das Ergebnis dieser Multiplikation muss nach y(i) geschrieben werden. Nach unserer ModellAnnahme passen die dichten Vektoren x und y allerdings nicht in den Cache. Pro Tripel treten also bis zu zwei zusätzliche Cache-Fehlzugriffe auf, d.h. die I/O-Komplexität von SpMV ist nnz(A)/L + 2 · nnz(A) = O(nnz(A)). 19 0 11 0 0 43 0 0 A= 0 0 0 0 0 27 0 35 A.I 1 4 2 4 1 A.J 1 2 2 4 3 A.V 19 27 43 35 11 Abbildung 2.3.1.: Matrix in ungeordneter Tripeldarstellung 2.3.2. Zeilenweise geordnete Tripel Falls die Tripel nach ihrer Zeilenzugehörigkeit geordnet werden, bleibt die Indizierung ineffizient. Ein schneller Zeilenzugriff ist ohne die Kenntnis des Startindex nicht möglich. Um auf die Einträge einer Zeile i zuzugreifen, wird zunächst eine binäre Suche auf A.I verwendet. Diese findet einen (beliebigen) Eintrag der Zeile i, von dem aus anschließend in beide Richtungen in den restlichen Nichtnull-Einträgen dieser Zeile gesucht wird. Analog zu zeilenweise geordneten Tripeln funktionieren auch spaltenweise geordnete Tripel. Falls die Einträge einer Zeile Spaltenindizes mit großem Abstand zueinander haben, kann sich die fehlende Sortierung auch hier negativ auswirken, etwa bei SpMV. 2.3.3. Zeilendominant geordnete Tripel Die dritte Möglichkeit der Tripeldarstellung ist die der zeilendominant geordneten Tripel. Hierbei werden die Einträge zunächst wie bei zeilenweise geordneten Tripeln nach der Zeile sortiert und anschließend innerhalb jeder Zeile noch nach der Spalte. Der Zugriff auf eine komplette Zeile erfolgt wie bei den zeilenweise geordneten Tripeln, jedoch ist die Referenzierung eines einzelnen Eintrags A(i, j) schneller. Hierfür reicht eine gewöhnliche Binärsuche allerdings nicht aus, da Anfang und Ende der i-ten Zeile im Voraus nicht bekannt sind. Deshalb wird wie folgt verfahren: 1. Finde mittels binärer Suche ein Tripel das zur i-ten Zeile der Matrix gehört. 2. Führe von diesem Tripel eine unbeschränkte binäre Suche in beide Richtungen aus. Dabei wird die Schrittgröße nach jeder Iteration verdoppelt. Die Suche terminiert, wenn in der entsprechenden Richtung ein Tripel gefunden wird, das nicht zur i-ten Zeile gehört. Diese beiden Tripel (eines aus jeder Richtung) bilden die Grenze. 3. Führe eine normale binäre Suche zwischen den beiden Grenztripeln aus. Abbildung 2.3.2 veranschaulicht das Verfahren. Die RAM-Komplexität für die Referenzierung beträgt O(log nnz(A) + log nnz(A(i, :)). Im I/O-Modell kann eine einfache lineare Suche auf einem sortierten Array schneller sein als die unbeschränkte binäre Suche. Das Suchen eines Elements in einer geordneten Menge mit N Elementen im I/O-Modell kostet mit Hilfe von B-Bäumen (siehe [BM72]) Θ(logL N ). Wird dafür 2.3. TripelSparse Matrices for Graph Algorithms Chapter 13. Implementing 304 31 Step 3 A.I 10 11 11 12 12 12 12 12 12 12 12 12 13 13 13 A.J 18 5 12 2 3 4 7 10 11 13 16 18 2 9 11 A.V 90 76 57 89 19 96 65 21 11 54 31 44 34 28 28 Step 2 Abbildung 2.3.2.: Referenzierung vonIndexing A(i, j) im zeilendominant geordneten Tripelformat Figure 13.4. row-major triples. Element-wise indexing of A(12, 16) on row-major ordered triples. values. Accesses to x are also with increasing indices, which is an improvement over row ordered triples. However, memory strides when accessing x can still be high, depending on the number of nonzeros in each row and the bandwidth of the matrix. In the worst case, each access to x might incur a cache miss. Bender et al. came up with cache-efficient algorithms for SpMV, using the column-major layout, that have an optimal number of cache misses [Bender et al. 2007]. From a high-level view, their method first generates all the intermediate triples of y, possibly with repeating indices. Then, the algorithm sorts those intermediate triples with respect to their row indices, performing additions on the triples with same row index as they occur. I/O optimality of their SpMV algorithm relies on the existence of an I/O optimal sorting algorithm. Their complexity measure assumes a fixed k number of nonzeros per column, leading to I/O complexity of ! " Abbildung 2.3.3.: Schematische Darstellung von SpAdd auf zeilendominant geordneten Tripeln N O scan(A) logZ/L (13.10) max{Z, k} SpAdd is now more efficient even without using any auxiliary data structure. A scanning-based array-merging algorithm is sufficient as long as we do not forget allerdings ein normales Array verwendet, so treten bei der Suche im schlechtesten Fall log N to sum duplicates while merging. Such an implementation has O(nnz (A)+nnz (B)) Cache-Fehlzugriffe auf, was mehr sein kann als scan(N ). Deshalb werden die Kosten der Suche RAM complexity and O(scan (A) + scan(B)) I/O complexity.* in einer geordneten Zeile einer Matrix folgt definiert: Row-major ordered tripleswie allow outer product and row wise SpGEMM implementations at least as efficiently as row ordered triples. Indeed, some finer imsearch(A(i, = min {log :)), scan(A(i, :))}In the case of provements are possibly by:))exploiting the nnz(A(i, more specialized structure. row wise SpGEMM, a technique called finger search [Brodal 2005] can be used to improve the RAM complexity. While enumerating all triples (i, k, A) ∈ A(i, :), they Für denare Spaltenzugriff sowie ergibt sich gegenüber genaturally sorted withSpAsgn-Operationen increasing k values. Therefore, accesses to B(k,dem :) arezeilenweise also ordneten Tripelformat Verbesserung. Bei SpMV = Ax) wirdfrom sowohl auf A als auch auf with increasingkeine k values. Instead of restarting the(y binary search the beginning of B, one can use fingers and only search the yet zugegriffen. unexplored subsequence. y mit überwiegend konsekutivem, aufsteigendem Index Auch auf x Note wird mit auf- steigendem Index zugegriffen, was eine Verbesserung gegenüber zeilenweise geordneten Tripeln * These bounds are optimal only if nnz (A) = Θ(nnz (B)); see [Brown & Tarjan 1979]. darstellt. Jedoch kann die Anzahl der Cache-Fehlzugriffe trotzdem hoch sein, abhängig von der Anzahl der Nichtnull-Einträge in jeder Zeile und der Bandbreite der Matrix. Im schlimmsten Fall kann jeder Zugriff auf x ein Cache-Fehlzugriff sein. SpAdd mit zeilendominanten Tripeln ist ohne zusätzliche Hilfsdatenstruktur effizienter als SpAdd auf zeilenweise geordneten Tripeln. Das Scannen und Verschmelzen der sortierten Arrays Downloaded 09 Dec 2011 to 129.174.55.245. Redistribution subject to SIAM license or copyright; see http://www.siam.org/journals/ojsa.php genügt, wobei Duplikate addiert werden (siehe Abbildung 2.3.3). Daraus ergibt sich eine RAMKomplexität von O(nnz(A) + nnz(B)) und eine I/O-Komplexität von O(scan(A) + scan(B)). Die dyadische und zeilenweise Matrix-Matrix-Multiplkation SpGEMM ist bei zeilendominant geordneten Tripeln mindestens so effizient wie bei zeilenweise geordneten Tripeln. 32 2. Datenstrukturen für dünn besetzte Matrizen 2.4. CSR/CSC Die populärsten und am häufigsten eingesetzten Formate dünn besetzter Matrizen sind Compressed Sparse Row (CSR) und Compressed Sparse Column (CSC). Beispielsweise verwendet MATLAB das CSC-Format, um dünn besetzte Matrizen zu speichern [GMS92]. Wir beschränken uns in diesem Skript auf das CSR-Format, das Gustavson 1972 als sparse row wise representation eingeführt hat [Gus72]. Das CSC-Format ist symmetrisch zum CSR-Format. Das CSC-Format schauen wir uns dann in verallgemeinerter Form für hyperdünne Matrizen genauer an. 2.4.1. CSR und Adjazenzlisten Im Prinzip ist das CSR-Format fast identisch zur Adjazentlisten-Darstellung gerichteter Graphen. Man spricht daher auch manchmal von Adjazenz-Arrays. Allerdings hat das CSR-Format in der Praxis eine deutlich bessere Cache-Effizienz als Adjazenzlisten. Denn CSR verwendet statt verketteter Listen insgesamt drei Arrays. Wegen des kontinuierlichem Speicherlayouts der Arrays ist dies cacheeffizienter als N verkettete Listen. Die drei Arrays von CSR sorgen dafür, dass die Einträge der Adjazenzlisten einer Matrix A ∈ RN×M kontinuierlich hintereinander gespeichert werden: • JC der Größe nnz speichert die Spaltenindizes der Nichtnull-Einträge • NUM der Größe nnz speichert die Werte der Nichtnull-Einträge • IR der Größe N +1 speichert für jede Zeile den Index des Zeilenstarts in den beiden anderen Arrays Im Sinne der Dualität zwischen dünn besetzter Matrix und Graphen ist es sinnvoll, bei IR vom Knoten-Array zu sprechen und bei JC vom Kanten-Array. Das Knoten-Array speichert für jeden Knoten den Offset (also die Startposition) im Kanten-Array. Demnach sind die NichtnullEinträge der i-ten Zeile in NUM(IR(i)) bis NUM(IR(i + 1) - 1) gespeichert und die entsprechenden Spaltenpositionen in dieser Zeile sind in JC(IR(i)) bis JC(IR(i + 1) - 1) gespeichert. In Abbildung 2.4.1 ist die CSR-Darstellung der Matrix A von Abschnitt 2.3.1 angegeben. Die Pfeile in der Adjazenzliste repräsentieren Zeiger auf die Speicherstellen während sie im CSR-Format Indirektionen über die Offset-Indizierung des IR Arrays darstellen. Die bessere Cache-Effizienz gegenüber Adjazenzlisten ist durch die moderne Computer-Architektur zu erklären. Um auf alle Nichtnull-Einträge einer gegebenen Zeile i zuzugreifen, entstehen im CSR-Format maximal dnnz(A(i, :))/Le Cache-Fehlzugriffe. Ein gleicher Zugriff auf das AdjazenzlistenFormat erzeugt im worst-case nnz(A(i, :)) Cache-Fehlzugriffe. Die gesteigerte Cache-Effizienz kommt allerdings zu einem Preis: Das Einfügen und Löschen von Nichtnull-Einträgen ist ineffizient und sollte möglichst vermieden werden. Daher ist das CSR-Format am besten für statische Graphen geeignet. Dies stellt aber keine große Einschränkung dar, da außer SpAsgn alle grundlegenden Operationen aus Abschnitt 2.2 mit statischen Graphen arbeiten. 2.4.2. Grundoperationen mit CSR Im Gegensatz zum Tripel-Format ermöglicht das CSR-Format eine Zeilenindizierung in konstanter Zeit. Das Iterieren über alle Einträge einer Zeile i hat im RAM-Modell eine Komplexität von O(nnz(A(i, :)) und im I/O-Modell O(scan(A(i, :)). Diese Eigenschaft macht das CSR-Format zu einer sehr guten Datenstruktur für zeilenweises SpRef. Der Zugriff auf einen einzelnen NichtnullEintrag A(i, j) benötigt mit Hilfe einer binären Suche sowohl im RAM- als auch im I/O-Modell maximal O(log nnz(A(i, :))) Zeit, jedoch kann eine lineare Suche in der Praxis, insbesondere bei 2.5. Multiplikation dünn besetzter Matrizen 33 Abbildung 2.4.1.: Matrix A als Adjazenzliste (links) und im CSR-Format (rechts) Knoten mit kleinem Grad, bezüglich der Cache-Performance besser sein. Beim spaltenweisen Zugriff ist das CSR-Format hingegen ineffizient. Ein solcher Zugriff sollte daher vermieden werden. Hier bietet CSR gegenüber dem Tripel-Format keinerlei Vorteile. Für manche Algorithmen ist ein schneller Zugriff auf das Diagonalelement wichtig. Hierfür existieren unterschiedliche Abwandlungen des CSR-Formats, z.B. können die Diagonaleinträge zusätzlich in einem separaten Array gespeichert werden oder es wird das normale CSR-Format genutzt, wobei das erste Element jeder Zeile immer den Diagonaleintrag repräsentiert (auch wenn dieser 0 ist). 2.4.2.1. SpMV Algorithmus 14 zeigt, wie SpMV bei einer dünn besetzten Matrix A im CSR Format ausgeführt werden kann. SpMV im CSR-Format bietet im Vergleich zum zeilendominant geordneten Tripelformat ähnliche Performance. Wenn N nnz gilt, dann hat das CSR-Format einen Vorteil, da innerhalb einer Zeile nur ein Index (A.JC(k)) pro Iteration ausgewertet werden muss und beim Tripelformat zwei Indizes (A.I(k) und A.J(k)). Daher hat das CSR-Format bis zu Faktor 2 weniger Cache-Fehlzugriffe als das zeilendominant geordnete Tripelformat. Außerdem benötigt es weniger Speicher, wenn die Zahl der Nichtnull-Einträge deutlich größer ist als die Zahl der Zeilen bzw. Knoten. Algorithmus 14 : SpMV (y = Ax) im CSR-Format 1 2 3 4 5 Input : A : RM ×N , x : RN Output : y : RM y←0 for i = 1 to M do for k = A.IR(i) to A.IR(i) − 1 do y(i) ← y(i) + A.N U M (k) · x(A.JC(k)) return y 2.5. Multiplikation dünn besetzter Matrizen In diesem Abschnitt wollen wir die Matrixmultiplikation auf dünn besetzten Matrizen (SpGEMM) im CSR-Format genauer betrachten. Dabei wird eine Hilfsdatenstruktur eingeführt, die zur Berechnung der Zwischenergebnisse dient. Hinsichtlich des Produkts von zwei dünn besetzten Matrizen C = A · B ist zu erwähnen, dass C nicht wieder dünn besetzt sein muss. Außerdem muss das Produkt zweier symmetrischer Matrizen A und B nicht symmetrisch sein. 34 2. Datenstrukturen für dünn besetzte Matrizen Da der Zugriff auf eine Zeile und die Iteration über eine Zeile im CSR-Format sehr effizient möglich sind, ist die zeilenweise Matrixmultiplikation die beste Wahl. 2.5.1. Der Sparse Accumulator Die meisten Algorithmen zur Ausführung von Matrixoperationen, die als Ergebnis wieder eine Matrix liefern, berechnen diese Zeile für Zeile. Daher ist es sinnvoll, die gerade zu berechnende Zeile in einer geeigneten Datenstruktur abzuspeichern, die das Indizieren einer Spalte in dieser Zeile in konstanter Zeit erlaubt, um Einträge schnell einfügen zu können. Die Sparse Accumulator (SPA) Datenstruktur erfüllt diese Anforderung und speichert temporär die jeweils aktive Zeile. Da es ein abstrakter Datentyp ist, existieren unterschiedliche Varianten des SPA. Für diese Vorlesung verwenden wir die folgende Definition: w ist der dichte Vektor der Werte, b ist der dichte, boolesche Vektor für „Besetzt”-Einträge und LS ist die Liste, welche eine ungeordnete Liste von Indizes der Nichtnull-Einträge speichert. Abbildung 2.5.1 veranschaulicht die Datenstruktur. Die Accumulate-SPA Funktion, die in Algorithmus 15 definiert ist, addiert einen Skalar (value) zu einer bestimmten Position (pos) des SPA. Diese Funktion arbeitet in konstanter Zeit. Um die Nichtnull-Einträge des SPA auszugeben, wird O(nnz(SP A)) Zeit benötigt. Der Pseudocode für Output-SPA ist in Algorithmus 16 beschrieben. Dabei greift der SPA nur auf Werte zu, die auch tatsächlich vorhanden sind. Es ist wichtig, den Sparse Accumulator nur einmal am Anfang zu initialisieren, da dies O(M ) Zeit benötigt. Das Zurücksetzen des SPA für eine neue Zeile geht in O(nnz(SP A)), da hierfür die Einträge in LS verwendet werden können, um alle NichtnullEinträge der vorherigen Zeile zu erreichen und nur diese Indizes von w und b zu löschen. In der Praxis treten bei dieser Datenstruktur allerdings häufig Cache-Fehlzugriffe auf. Da der SPA Arrays der Größe N speichert (bei einer M × N Matrix) passt die Datenstruktur nach der zweiten Modell-Annahme in Abschnitt 2.1.2 nicht komplett in den Speicher weshalb im worst-case pro flop ein Cache-Fehlzugriff auftritt. Zusätzlich treten bis zu scan(A) weitere CacheFehlzugriffe beim Zugriff auf die Nichtnull-Einträge von A auf, also insgesamt O(scan(A)+f lops) Cache-Fehlzugriffe im worst-case. Abbildung 2.5.1.: SPA Datenstruktur Algorithmus 15 : AccumulateSPA Input : SPA, value, pos 1 if SPA.b(pos) then 2 SP A.w(pos) ← SP A.w(pos) + value 3 else 4 SP A.w(pos) ← value 5 SP A.b(pos) ← true 6 Insert(SP A.LS, pos) 2.6. Hyperdünne Matrizen Algorithmus 16 : OutputSPA Input : SPA, val, col, nzcur Output : nzi 1 cptr ← head(SP A.LS) 2 nzi ← 0 3 while cptr 6= N IL do 4 5 6 7 35 // number of nonzeros in the current row of C col(nzcur + nzi) ← element(cptr) val(nzcur + nzi) ← SP A.w(element(cptr)) nzi ← nzi + 1 Advance(cptr) // for all entries in SPA.LS // set column index // set value 2.5.2. SpGEMM mit CSR Die zeilenweise Matrixmultiplikation im CSR-Format erfolgt mit Hilfe des Sparse Accumulators und ist in Algorithmus 17 dargestellt, Abbildung 2.5.2 stellt eine Iteration der äußersten Schleife dar und Abbildung 2.5.3 zeigt ein Beispiel mit Zahlen. Algorithmus 17 : CSR-SpGEMM Input : A : RN ×K , B : RK×N Output : C = AB 1 SetSPA(SP A) // set w = 0, b = 0 and create empty list LS 2 C.IR(1) ← 1 3 for i ← 1 to M do 4 for k ← A.IR(i) to A.IR(i + 1) − 1 do 5 for j ← B.IR(A.JC(k)) to B.IR(A.JC(k) + 1) − 1 do 6 value ← A.N U M (k) · B.N U M (j) 7 AccumulateSPA(SP A, value, B.JC(j)) 8 9 10 nznew ← OutputSPA(SP A, C.N U M, C.JC, C.IR(i)) C.IR(i + 1) ← C.IR(i) + nznew ResetSPA(SP A) // reset w = 0, b = 0 and empty LS 2.6. Hyperdünne Matrizen Definition. Eine Matrix A ∈ RN×M ist hyperdünn (engl.: hypersparse), wenn nnz(A) < N gilt. Hyperdünne Matrizen kommen im Bereich der linearen Algebra – zumindest in sequentiellen Algorithmen – eher selten vor, da eine Matrix mit vollem Rang bereits nnz ≥ N erfüllt. Bei Graphen sind hyperdünne Matrizen allerdings ein häufiges Muster. So bilden beispielsweise unzusammenhängende Graphen mit vielen Einzelknoten hyperdünne Matrizen. Aber auch bei der 2D-Partitionierung eines Graphen bzw. einer Matrix für die Parallelverarbeitung ergeben sich häufig hyperdünne Matrizen. Große Matrizen müssen häufig verteilt gespeichert werden, da sie entweder zu groß für den Hauptspeicher eines einzelnen Rechners sind oder sie sind zu groß, um eine ausreichend schnelle Berechnung auf einem einzelnen Rechner zu gewährleisten. Dabei sind zwei verschiedene Partitionierungsvarianten üblich: 36 2. Datenstrukturen für dünn besetzte Matrizen Abbildung 2.5.2.: Ein Iterationsschritt des CSR-SpGEMM Algorithmus • 1D-Partitionierung: Jeder Prozessor erhält bestimmte Zeilen der Matrix. Dies entspricht einer Knotenpartitionierung des Graphen. • 2D-Paritionierung: Jeder Prozessor erhält einen Block der Matrix. Dies entspricht einer Kantenpartitionierung des Graphen. Wie bereits erwähnt, ergeben sich insbesondere bei der 2D-Partitionierung häufig Blöcke mit sehr wenigen Nichtnull-Elementen. Obwohl CSR bzw. CSC recht effiziente Speicherformate für dünn besetzte Matrizen mit nnz = Ω(N ) sind, eignen sie sich weniger gut für solche hyperdünne Matrizen. Betrachten wir beispielsweise das CSC-Format bei einer 2D-Partitionierung. Nehmen √ √ wir dafür an, dass jeder Prozessor einen quadratischen Block der Größe (N/ p) × (N/ p) der Matrix erhält (p :=# Prozessoren). Wenn nun jede dieser Teilmatrizen im CSC-Format √ gespeichert wird, beläuft sich der parallele Gesamtspeicherverbrauch auf O((N/ p) · p + nnz) = √ O(N p + nnz). Speichert man die Matrix hingegen sequentiell auf einem einzigen Prozessor, beträgt der Gesamtspeicherverbrauch im CSC-Format nur O(N + nnz). Wenn die Anzahl der √ Prozessoren steigt, so wird der N p Term dominant und der Speicherverbrauch im parallelen Fall steigt. Es ist allerdings sehr wünschenswert, dass der Speicherverbrauch unabhängig von der Zahl der Prozessoren ist. Neben der Skalierbarkeit der Problemgröße hat diese Ineffizienz von CSC nämlich auch Einfluss auf die Skalierbarkeit von Algorithmen. Darum definieren wir im folgenden Abschnitt eine neue Datenstruktur für hyperdünne Matrizen. 2.7. DCSC Die DCSC-Datenstruktur (DCSC steht für doubly compressed sparse columns) hat die folgenden Eigenschaften: • Speicherverbrauch von O(nnz), d.h. unabhängig von der Anzahl der Prozessoren und der Matrixdimension • Schneller Zugriff auf die Spalten der Matrix • SpGEMM skaliert mit zunehmender Anzahl von Null-Einträgen 2.7. DCSC 37 Abbildung 2.5.3.: Zeilenweise Matrix-Matrix-Multiplikation (SpGEMM) Als Beispiel betrachten wir die 9×9 Matrix A mit 4 Nichtnull-Einträgen, die in der Tripeldarstellung in Abbildung 2.7.1 zu sehen ist. Abbildung 2.7.2 zeigt die Matrix im CSC-Format; hier gibt es redundate Einträge im Array JC. Die wesentliche Idee des DCSC-Formats ist die Verwendung der von CSC bekannten Arrays IR und NUM und der Komprimierung des JC-Arrays, um Wiederholungen zu vermeiden. Dafür braucht es zusätzlich ein Array CP, welches die Startindizes für IR und NUM der Spalten mit Nichtnull-Einträgen bzw. die kumulierte Anzahl aller NichtnullEinträge bis zur jeweiligen Spalte angibt (Indizes beginnen bei 1). Die Matrix A im DCSC-Format ist in Abbildung 2.7.3 zu sehen. Das AUX-Array wird nur bei Bedarf angelegt, um eine schnelle Spaltenindizierung zu ermöglichen. Es speichert Zeiger auf Nichtnull-Spalten (also Spalten, die mindestens einen Nichtnull-Eintrag enthalten). Die Gesamtanzahl der Nichtnull-Spalten wollen wir mit nzc bezeichnen. Jeder Eintrag im AUX-Array bezieht sich auf einen Spaltenblock der Größe d(N + 1)/nzce und zeigt auf die erste Nichnull-Spalte in diesem Block. Das DCSC-Format hat somit einen Speicherverbrauch von O(nnz), da für die Größen der verwendeten Arrays gilt: |NUM| = |IR| = nnz, |JC| = nzc, |CP| = nzc und |AUX| ≈ nzc. A.I 6 8 4 2 A.J 1 1 7 8 A.V 0.1 0.2 0.3 0.4 Abbildung 2.7.1.: Matrix A im Tripel Format 38 2. Datenstrukturen für dünn besetzte Matrizen JC = 1 3 IR = 6 0.1 NUM = 3 3 3 3 3 4 8 4 2 0.2 0.3 0.4 5 5 Abbildung 2.7.2.: Matrix A im CSC Format AUX = JC = CP = IR = NUM = 1 1 1 6 0.1 2 7 3 8 0.2 4 8 4 4 0.3 4 5 2 0.4 Abbildung 2.7.3.: Matrix A im DCSC Format 2.8. Multiplikation hyperdünner Matrizen In diesem Abschnitt wollen wir die sequentielle Matrixmultiplikation C = A · B auf hyperdünnen Matrizen (HypSpGEMM) kennen lernen. Diese basiert auf der Summierung von dyadischen Produkten, weshalb die Operation schnellen Zugriff auf die Zeilen von B benötigt. Hierfür könnte man jede Eingabematrix sowohl im DCSC- als auch im DCSR-Format (entspricht der Transponierten im DCSC-Format) speichern, was allerdings den Speicherverbrauch verdoppelt. Hier verwenden wir eine Lösung, bei der B in einem Vorverarbeitungsschritt transponiert wird (Kosten: trans(B)). Die tatsächliche Laufzeit für das Transponieren beträgt je nach Implementierung O(N + nnz(B)) oder O(nnz(B) · log nnz(B)). Als erste Beobachtung fällt uns beim DCSC-Format auf, dass das JC-Array bereits sortiert ist, d.h. A.JC gibt uns die sortierten Indizes der Nichnull-Spalten und B T .JC gibt uns die sortierten Indizes der Nichtnull-Zeilen. Der naive Algorithmus berechnet jeweils das dyadische Produkt Ck der k-ten Spalte von A und der k-ten Zeile von B für alle k ∈ N und summiert die so erhaltenen N Rang-1 Matrizen zu C auf. Um nur die Indizes zu berücksichtigen, deren dyadisches Produkt nichttrivial ist, wird ein Vorverarbeitungsschritt benötigt, der Isect := A.JC ∩B T .JC berechnet. Dieser Schritt benötigt O(nzc(A) + nzr(B)) Zeit, da |A.JC| = nzc(A) und |B T .JC| = nzr(B). Abbildung 2.8.1 veranschaulicht die Bestimmung der Menge Isect. Für die Nichtnull-Einträge der Matrix Ck gilt: (Ck )ij = Aik · Bkj 6= 0 ⇐⇒ Aik 6= 0 ∧ Bkj 6= 0. Daher werden im nächsten Schritt |Isect| kartesische Produkte gebildet und in fiktiven Listen der Größe nnz(A(:, k)) · nnz(B(k, :)) gespeichert. In Abbildung 2.8.2 ist dieser Schritt anhand eines Beispiels zu sehen. Die Listen sind fiktiv, da sie nicht explizit gespeichert werden. Sie können sortiert erstellt werden, da die Nichtnull-Einträge in einer Spalte bzw. Zeile aufsteigend nach dem Zeilen- bzw. Spaltenindex sortiert sind. Nun verschmilzt der Algorithmus die sortierten Listen, wobei die Einträge mit gleicher Position (i, j) in C aufsummiert werden. Diese Phase entspricht dem k-fachen Verschmelzen (k-way multiway merge) sortierter Liste, wie es etwa aus MergeSort bekannt ist. Der einzige Unterschied besteht darin, dass die Listen nie explizit erstellt werden, sondern jeder Eintrag auf Anforderung berechnet wird. Das Verschmelzen benutzt eine Prioritätswarteschlange mit binärem Heap der Größe ni := |Isect|. Der Wert eines Eintrags ist der NUM-Wert und der Schlüssel das Indexpaar (i, j) in spaltendominanter Reihenfolge. Die Idee besteht darin, wiederholt das Minimum min aus der Warteschlange zu entfernen und das nächste Element aus der fiktiven Liste von min einzufügen. Mehrere Elemente mit demselben Schlüssel werden dabei akkumuliert. Für jede arithmetische Operation pro Eintrag in C wird eine Extract-Min Operation benötigt, d.h. die Zeitkomplexität P dieser Phase beträgt O(f lops · log ni ), wobei f lops = k∈Isect nnz(A(:, k)) · nnz(B(k, :)). Die 2.9. Weiterführende Literatur 39 Abbildung 2.8.1.: Bestimmung der Menge Isect Speicherkomplexität beträgt O(nnz(C) + ni) - nnz(C) für die Ausgabematrix und ni für die Prioritätswarteschlange. Die Ausgabe dieser Phase ist eine Warteschlange mit NUM-Werten in spaltendominanter Sortierung. Als letzter Schritt erstellt der Algorithmus aus der Warteschlange der vorherigen Phase die DCSC-Datenstruktur für die Matrix C, was noch einmal O(nnz(C)) Zeit und Speicher benötigt. Die Gesamtzeitkomplexität beträgt O(trans(B) + nzc(A) + nzr(B) + f lops · log ni). Der Term nnz(C) taucht hier nicht auf, da nnz(C) ≤ f lops gilt. Es ist noch zu erwähnen, dass die Kosten für das Transponieren der Matrix B (trans(B)) in der Praxis bei Amortisierung vernachlässigbar sind. Algorithmus 18 zeigt den kompletten Pseudocode der HypSpGEMM-Operation. Die Funktion CartM ultInsert generiert das nächste Element der j-ten fiktiven Liste und fügt es in die Prioritätswarteschlange ein. Die Funktion IncrementList verschiebt den Zeiger auf das nächste Element der j-ten fiktiven Liste oder löscht die Liste, wenn sie leer ist. 2.9. Weiterführende Literatur Dieses Vorlesungskapitel basiert vor allem auf den Kapiteln 13 und 14 im Buch Graph Algorithms in the Language of Linear Algebra [KG11]. Dort finden Sie auch eine ausführlichere Betrachtung zur parallelen Multiplikation von dünn besetzten Matrizen. 40 2. Datenstrukturen für dünn besetzte Matrizen Abbildung 2.8.2.: Bestimmung der kartesischen Produkte und Speicherung in fiktiven Listen Algorithmus 18 : HypSpGEMM Input : A : RN ×K , B : RK×M Output : C = AB 1 isect ← Intersection(A.JC, B T .JC) // intersection of sorted column arrays 2 for j ← 1 to |isect| do // create first element of fictitious list and insert it into PQ 3 CartMultInsert(A, B T , P Q, isect, j) 4 IncrementList(isect, j) 5 6 7 8 9 10 11 12 13 14 15 while IsNotFinished(isect) do (key, value) ← ExtractMin(P Q) (product, j) ← Unpair(value) if key 6= Back(Q) then Enqueue(Q, key, product) else UpdateBack(Q, product) // extract next element from PQ // insert non-existing element // update existing element on the fly if ISN OT EM P T Y (isect(j)) then // insert appropriate list element into PQ CartMultInsert(A, B T , P Q, lists, isect, j) IncrementList(isect, j) ConstructDCSC(Q) 41 3. Clusteranalyse von Graphen In diesem Kapitel wollen wir uns mit der Clusteranalyse in Graphen beschäftigen. Dabei handelt es sich um die Problemstellung, „natürliche” Gruppen in Graphen zu bestimmen. Salopp könnte man dazu auch „Strukturierung des Chaos” im Graphen sagen. Das Bestimmen von Clustern ist eine weitverbreitete Analysemethode, sie findet unter anderem Anwendung in den Bereichen Marketing und Werbung, in der Strukturvorhersage, im Maschinellen Lernen und im Data Mining, bei der Bildsegmentierung sowie in vielen weiteren Gebieten. In der Forschung werden die Begriffe Clusteranalyse, Clustering und Community Detection oft anhand verschiedener Eigenschaften der Problemstellung und/oder der eingesetzten Algorithmen unterschieden. Der Einfachheit halber wollen wir das in diesem Kapitel nicht tun und die Begriffe synonym verwenden, was auch nicht selten in Forschungsarbeiten zum Thema geschieht. Clustering-Algorithmen lassen sich in zahlreiche Algorithmenklassen einteilen, einige dieser Algorithmen wollen wir in diesem Kapitel kennen lernen. Bevor wir uns mit den Algorithmen zur Clusteranalyse beschäftigen können, benötigen wir zunächst eine formale Definition einer Clusterung bzw. eines Clusters. Definition 3.1. Sei G = (V, E) ein ungerichteter, einfacher (schlichter) Graph. Eine Clusterung C = (C1 , . . . , Ck ) ist eine Partitionierung der Knotenmenge V in nicht-leere, disjunkte Teilmengen, deren Vereinigung V überdeckt. Eine solche Teilmenge Ci heißt Cluster. Korollar 3.2. Jede Clusterung C kann eindeutig durch die Äquivalenzrelation (reflexiv, symmetrisch, transitiv) u ∼C v :⇔ ∃Ci ∈ C : u, v ∈ Ci beschrieben werden. Die Cluster Ci entsprechen genau den Äquivalenzklassen. 3.1. Label Propagation Die Idee des Label-Propagation-Algorithmus (LPA) besteht darin, jedem Knoten bereits von Anfang an eine Clusternummer (Label ) zuzuordnen. Iterativ übernimmt jeder Knoten dann das Label, das die meisten seiner direkten Nachbarn haben. Ein Beispiel davon ist in Abbildung 3.1.1 zu sehen, bei dem Knoten 4 noch zum falschen Cluster (blau) gehört. 3.1.1. Der Algorithmus Gegeben ist also ein Graph G = (V, E) mit einer initialen Clusterung C. Als initiale Clusterung wird, wie im klassischen Label Propagation Algorithmus, jeder Knoten einem eigenen Cluster zugeordnet (Ein-Knoten-Clusterung), oder sie kann von einem anderen Algorithmus stammen, z.B.: • Ausführung einer Runde des Luby-Algorithmus zur Berechnung einer maximal unabhängigen Menge (Maximum Independent Set). Die Zuordnung der restlichen Knoten, die nicht zur unabhängigen Menge gehören, erfolgt an den nächstgelegenen Knoten, der in der unabhängigen Menge enthalten ist. 42 3. Clusteranalyse von Graphen 6 8 7 4 2 1 5 3 Abbildung 3.1.1.: Beispielgraph mit Clusterung • Berechnung einer Startlösung durch ein Multilevel-Verfahren. Hierbei wird der Graph zunächst rekursiv vergröbert um dann auf der gröbsten Ebene eine Startlösung zu berechnen. Während der Rückkehr aus der Rekursion wird die Lösung stufenweise verbessert. Die experimentelle Erfahrung zeigt allerdings, dass LPA auf einem Graphen mit guter ClusterStruktur robust gegenüber der initialen Clusterung ist. Gesucht ist nun eine bessere Clusterung C 0 . Der Algorithmus geht dabei iterativ (oder rekursiv) wie folgt vor: • Stimmabgabe: Jeder Knoten stimmt dafür, dass seine Nachbarn zum eigenen Cluster gehören. • Zuweisung: Jeder Knoten wird nach der Berechnung aller Stimmabgaben dem benachbarten Cluster mit den meisten Stimmabgaben zugeordnet, dies kann natürlich auch das eigene Cluster sein. Ist der Einfluss bzw. die Stimmanzahl verschiedener benachbarter Cluster gleich hoch, so wird dieser Konflikt beliebig aufgelöst, bspw. indem der Cluster mit der kleinsten Clusternummer gewählt wird. Der Pseudocode ist in Algorithmus 19 abgebildet und Abbildung 3.1.2 zeigt einen Schritt des Algorithmus mit der Ausgangssituation von Abbildung 3.1.1. Dabei wurden die Anzahl der Kanten von jedem Cluster zu jedem Knoten gezählt. Für jeden Knoten wurde dabei implizit eine Schleife mitgezählt. 3.1.2. Probleme Ein Problem des Algorithmus liegt in den unterschiedlichen Knotengraden, die im Graphen vorkommen können. Besonders bei Netzwerken der realen Welt wie beispielsweise sozialen Netzwerken oder manchen Transportnetzwerken treten stark unterschiedliche Knotengrade auf. Besonders wichtig ist dies bei gerichteten Netzwerken bzw. Graphen (Ein- und Ausgangsgrad können hier sehr unterschiedlich sein). Dieses Problem hat zur Folge, dass einige Knoten sehr starken Einfluss bei der Stimmabgabe haben. Eine mögliche Lösung besteht darin, eine Normalisierung der Abstimmung durchzuführen. Hierfür werden beispielsweise die Kantengewichte der ausgehenden Kanten jedes Knotens durch die Summe aller ausgehenden Kantengewichte geteilt um die Stimmen jedes Knotens auf 1 zu normalisieren. Ein weiteres Problem stellen Knoten mit Grad 1 dar. Hier ist nicht klar, ob diese einen eigenen Cluster bilden sollen oder beser zum Cluster des Nachbarn hinzugefügt werden sollten. 3.1. Label Propagation Algorithmus 19 : Label Propagation Input : G = (V, E) : Graph, θ : Konvergenz-Schranke Output : ζ : V → N : Communities 1 for v ∈ V do 2 ζ(v) ← id(v) 3 4 5 6 7 8 9 10 11 12 13 14 15 updated ← |V | Vactive ← V while updated > θ do updated ← 0 for v ∈ {u ∈ VactiveP: deg(u) > 0} do l∗ ← argmaxl { u∈N (v):ζ(u)=l ω(v, u)} 43 // Initiale Clusterung // Stimmabgabe // Zuweisung if ζ(v) 6= l∗ then ζ(v) ← l∗ updated ← updated + 1 Vactive = Vactive ∪ N (v) else Vactive ← Vactive \ {v} return ζ Bei einem kleinen Cluster ist es wahrscheinlich, dass dieser von einem anderen Cluster “aufgesogen” wird, wenn zu diesem mehrere Kanten existieren. Es ist in diesem Fall anwendungsabhängig, ob man diesen Effekt verhindern will oder nicht. Eine Möglichkeit, dieses Phänomen zu verhindern, besteht wiederum in der Normalisierung der Abstimmung, allerdings unter Berücksichtigung der Clustergröße. Dafür wird der Einfluss bzw. die Anzahl der Stimmen mit einem Stärkeexponenten skaliert, genauer werden die ausgehenden Kantengewichte jedes Knotens durch die Größe seines Clusters, potenziert um einen Wert 0 ≤ p ≤ 1, geteilt. Der Exponent p kann während der Laufzeit verändert werden um die Änderungen in Anzahl und Größe der Cluster widerzuspiegeln. 3.1.3. Komplexität 3.1.3.1. Raumkomplexität Werden die Stimmen als Liste an jedem Knoten verwaltet, so reichen insgesamt |E| Listeneinträge über alle Kanten gesehen, da jede Kante in jeder Iteration einmal Einfluss nehmen kann. 3.1.3.2. Zeitkomplexität Der Vorteil des LPA liegt in der Laufzeit. Jede Iteration benötigt O(|E|) Zeit und es konnte empirisch gezeigt werden, dass der Algorithmus bereits nach wenigen Iterationen, typischerweise O(1), einen stabilen Zustand erreicht, wenngleich dies bisher noch nicht mathematisch bewiesen wurde. In der Praxis hat sich gezeigt, dass die Anzahl der Iterationen eher von der Struktur des Graphen abhängt und weniger von dessen Größe. Wenn der Graph eine gute Cluster-Struktur besitzt, so ergibt sich (zumindest aus empirischer Sicht) eine Gesamtlaufzeit von O(|E|). 44 3. Clusteranalyse von Graphen B: 1 R: 2 B: 0 R: 3 B: 4 R: 1 B: 5 R: 0 B: 2 R: 3 B: 3 R: 0 B: 1 R: 3 B: 3 R: 1 B: 0 R: 3 B: 4 R: 1 B: 1 R: 4 B: 0 R: 3 B: 3 R: 0 B: 4 R: 1 B: 3 R: 1 B: 0 R: 4 Abbildung 3.1.2.: Iterationsschritt des Algorithmus 3.1.4. Algebraische Formulierung |V |×|V | Definition 3.3. Sei C ∈ F2 die Matrix, für die gilt: Cij = 1 gdw. Knoten j befindet sich in Cluster i. C repräsentiert also die Clusterung des Graphen. Bemerkung. Als Startlösung wird C = I gewählt. Definition 3.4. Sei A die gewichtete Adjazenzmatrix des Graphen. Dann definieren wir T = CA als die Stimmauszählungsmatrix (engl.: tally matrix ). Bemerkung. Es gilt Tij = k gdw. es k Stimmen für den Knoten j in Cluster i gibt. Ist die Stimmabgabe abgeschlossen, erfolgt die Zuweisung der Clusterung wie folgt: m = T max. C = m . == T |V | Hier wird für jeden Knoten in m ∈ R+ die maximale Anzahl Stimmen, die er in einem der Cluster besitzt, gespeichert und anschließend daraus die neue Clusterung C generiert. Algorithmus 20 zeigt den Pseudocode für die algebraische Formulierung des LPA. Weitere Operationen sind: • Normalisierung 1 (Entschärfung verschiedener Knotengrade): 3.1. Label Propagation 45 Algorithmus 20 : Algebraische Formulierung des Label Propagation Algorithmus |V |×|V | 1 2 3 4 5 6 7 |V |×|V | Input : G = A : R+ , Ci : F2 |V |×|V | Output : Cf : F2 T ← Ci A m ← T max. Cf ← m . == T if Ci == Cf then return Cf else return LabelPropagation(G, Cf ) w = A +. A = 1/w .x A • Normalisierung 2 (kleine Cluster und Einzelknoten erhalten): w = C +. A = (1/w .ˆp) .x A • Konflikte: Finde in jeder Spalte von T das erste Maximum 3.1.4.1. Raumkomplexität Algorithmus 20 verwendet die folgenden Variablen: Name Typ Anzahl Elemente A T Ci Cf m |V |×|V | R+ |V |×|V | R+ |V |×|V | F2 |V |×|V | F2 |V | R+ O(|E|) O(|E|) O(|V |) O(|V |) O(|V |) T benötigt nur O(|E|) Einträge, da jede Kante einer Stimme entspricht und es demnach nicht mehr Stimmen als Kanten im Graphen geben kann. Der Gesamtspeicherverbauch der algebraischen Formulierung beläuft sich demnach auf O(|E|). 3.1.4.2. Zeitkomplexität Da jede Kante genau einer Stimme entspricht benötigt die Stimmabgabe O(|E|) Operationen, gleiches gilt für die Auszählung. Wenn der Algorithmus p Durchläufe benötigt, beträgt die Gesamtlaufzeit O(p·|E|). Wird wie beim normalen Label Propagation Algorithmus davon ausgegange, dass nur wenige Iterationen nötig sind (also p eine Konstante ist), so hat auch die algebraische Formulierung eine Laufzeit von O(|E|). 46 3. Clusteranalyse von Graphen 3.2. Markov Clustering Ein alternativer Ansatz ist das sogennante Markov-Clustering. In diesem Abschnitt wollen wir diesen Ansatz vorstellen und ihn mit dem LPA vergleichen. Definition 3.5. Ein Random Walk ist ein Pfad, der auf einem beliebigen Knoten j startet und dann zufällig und gleichverteilt über einen Nachbarn i von j verläuft. Von Knoten i wird dieser Prozess fortgesetzt. Abbildung 3.2.1.: Schematische Darstellung eines Random Walks in einem Graphen Abbildung 3.2.1 zeigt schematisch einen Random Walk in einem Graphen. Der Markov-ClusteringAlgorithmus (MCL) basiert auf Random Walks. Die Idee dabei ist, dass ein Random Walk mit hoher Wahrscheinlichkeit lange in einem dichten Gebiet (also einem Cluster) verweilt, bevor er eine der wenigen externen Kanten findet, über die er das Gebiet verlassen kann. Definition 3.6. Eine n × n Matrix M heißt Markov-Matrix, wenn alle Einträge nichtnegativ sind und die Summe jeder Spalte 1 ergibt. Man nennt M dann auch spaltenstochastisch. Definition 3.7. Sei G ein gewichteter Graph und A die gewichtete Adjazenzmatrix von G. Weiter sei D die Diagonalmatrix der Spaltensummen von A. Dann definieren wir M := AD−1 als Transitionsmatrix von G. Bemerkung 3.8. Die Transitionsmatrix M von G ist eine Markov-Matrix. Beweis. Betrachte die j-te Spalte von M . Es gilt: Mij = n X −1 −1 Aik Dkj = Aij Djj k=1 und damit: n X i=1 Mij = n X i=1 Pn Aij −1 Aij Djj = Pni=1 =1 A i=1 ij 3.2. Markov Clustering 47 Demnach definiert Mij die Wahrscheinlichkeit des Übergangs von Knoten j nach Knoten i. Die e-fache Matrix-Matrix-Multiplikation der Matrix M mit sich selbst liefert uns also die Matrix M e , wobei Mije die Wahrscheinlichkeit ausdrückt, einen Pfad der Länge e von Knoten j nach Knoten i zu gehen. Algorithmus 21 zeigt das Markov Clustering Verfahren. Der Algorithmus besteht im Wesentlichen aus zwei Schritten. Zunächst wird eine Expansion durchgeführt, d.h. es wird mit Hilfe von Random Walks der Graph erkundet. Dies geschieht durch die Potenzierung der Markovmatrix mit einem Exponenten e ≥ 2. Anschließend werden die Einträge der Matrix punktweise mit einem Skalar r > 0 potenziert. Dies führt zu einer Verstärkung guter und zur Abschwächung schwacher Bindungen zwischen den Knoten. Dieser Schritt wird auch als Inflation bezeichnet. Da durch den Infaltionsschritt die Matrix nicht mehr spaltenstochastisch ist, folgt in einem letzten Schritt noch eine Normalisierung der Spalten, um wieder eine Markovmatrix zu erhalten. Dieser Prozess wird bis zur Konvergenz wiederholt. Der MCL Algorithmus wird beim Start mit der Markovmatrix Ci := M = AD−1 aufgerufen, bei der die Schleifenwahrscheinlichkeit optional größer Null sein kann. Algorithmus 21 : Markov Clustering Input : Ci : Markovmatrix, e : Expansionsexponent, r : Inflationsexponent 1 Cf ← Cie // Expansion: Matrix-Matrix-Multiplikation 2 Cf ← Cf . ∧ r // Inflation: Punktweise Potenzierung 3 w ← Cf .+ // Spaltensummen 4 Cf ← Cf . × 1/w // Spaltennormalisierung 5 if Ci == Cf then 6 return Cf 7 else 8 return MarkovClustering(Cf , e, r) Es bleibt zu zeigen, dass der Algorithmus konvergiert. Das wollen wir im nächsten Abschnitt mit Hilfe der Eigenwerte und Eigenvektoren der Markovmatrix beweisen. Eigenwerte und Eigenvektoren bieten uns eine Möglichkeit zur Analyse der wiederholten Anwendung eines Operators auf einen Vektor. Im Anschluss an den Beweis der Konvergenz des MCL Algorithmus wollen wir noch einige weitere Eigenschaften eines Graphen anhand der Eigenwerte bzw. Eigenvektoren kennen lernen. 3.2.1. Konvergenz des Markov Clustering Algorithmus Wir müssen zeigen, dass sich die Einträge der iterativ berechneten Markovmatrix ab einem bestimmten Zeitpunkt nicht mehr ändern. Da die Markovmatrix eine Wahrscheinlichkeitsverteilung für einen Random Walk auf dem Graphen beschreibt, ist die Konvergenz des Random Walks gegen eine bestimmte Wahrscheinlichkeitsverteilung damit äquivalent. Die Eigenvektoren und Eigenwerte der Markovmatrix M = AD−1 geben uns dafür wichtige Informationen über die Struktur von G. Aus der linearen Algebra ist bekannt, dass die Eigenvektoren einer symmetrischen Matrix eine orthonormale Basis bilden (siehe Anhang A.1). Allerdings ist M im Allgemeinen nicht symmetrisch. Wir verwenden deshalb die Matrix S := D−1/2 AD−1/2 = D−1/2 M D1/2 . Demnach besitzt S die spektralen Zerlegung S= n X i=1 λi vi viT , 48 3. Clusteranalyse von Graphen wobei ω1 ≥ ω2 ≥ · · · ≥ ωn die Eigenwerte von S und z1 , . . . , zn die zugehörigen und normierten Eigenvektoren sind. Dann gilt für alle i = 1, . . . , n M (D1/2 zi ) = D1/2 SD−1/2 D1/2 zi = D1/2 Szi = D1/2 ωi zi = ωi (D1/2 zi ). Daraus folgt, dass M dieselben n Eigenwerte ωi besitzt wie S und D1/2 zi die zugehörigen Eigenvektoren sind. Theorem 3.9. Ist G zusammenhängend und ungerichtet, dann hat der größte Eigenwert ω1 von M = AD−1 • die Vielfachheit 1, • den Wert 1 und • Eigenvektor d = (d(1), . . . , d(n). Beweis. Zunächst werden wir durch einfaches Nachrechnen überprüfen, dass d ein Eigenvektor von M zum Eigenwert 1 ist. Ist d ein Eigenvektor von M , so existiert ein Eigenwert z von S mit √ D1/2 z = d ⇔ z = d. Dann gilt: √ √ √ Sz = S d = D−1/2 AD−1/2 d = D−1/2 A = d = 1 · z. Somit ist d ein Eigenvektor von M zum Eigenwert ω1 = 1. Weiter gilt für einen bel. Eigenvektor ω und den korrespondierenden Eigenvektor v von M : ||M || = sup x6=0 ||M x|| ||wv|| ||v|| ≥ = |w| = |w|. ||x|| ||v|| ||v|| Da M eine Markovmatrix ist, gilt ||M ||1 = 1 und damit |w| ≤ 1, daher ist ω1 der größte Eigenwert von M . Es bleibt noch zu zeigen, dass ω1 die Vielfachheit 1 besitzt. Hierfür verwenden wir den Satz von Perron-Frobenius, der besagt, dass der größte Eigenwert einer positiven Matrix (alle Einträge sind positiv) ein einfacher Eigenwert ist. Folgerung 3.10. Sei G wie in Theorem 3.9 definiert und sei ωn > −1. Dann konvergiert der Random Walk auf G gegen die Verteilung d . v d(v) π=P Der Beweis von Folgerung 3.10 kann in der einschlägigen Literatur nachgelesen werden, zur Übung kann die Aussage aber durch das Nachrechnen von M π = π überprüft werden. Nun wissen wir, dass der Markov Clustering Algorithmus konvergiert, allerdings würden wir noch gerne eine Aussage über die Konvergenzgeschwindigkeit machen. Sei dazu pt ∈ Rn die Wahrscheinlichkeitsverteilung, die für jeden Knoten j die Wahrscheinlichkeit angibt, dass der Pfad des Random Walks nach t Schritten an j endet. Der Wahrscheinlichkeitsverteilung p0 wird dabei meist auf einen Startknoten a gesetzt, also p0 (a) = 1. Für t > 0 gilt dann pt = M pt−1 . 3.2. Markov Clustering 49 Theorem 3.11. Sei der Startknoten des Random Walks Knoten a. Dann gilt für jeden Knoten b: s d(b) |pt (b) − π(b)| ≤ (max{|ω2 |, |ωn |})t d(a) Beweis. Der Beweis funktioniert auf ähnliche Weise wie der Beweis von Theorem 5.6. Damit konvergiert der MCL Algorithmus eher langsam. Der Grund dafür ist zugleich der Ansatz des gesamten Algorithmus, die Random Walks überwinden Flaschenhälse nur schlecht. 3.2.2. Zusammenhänge zwischen Graphen und Eigenwerten In diesem Abschnitt wollen wir noch einige weitere interessante Zusammenhänge zwischen einem Graphen bzw. der Matrixrepräsentation des Graphen und den Eigenwerten erwähnen. 3.2.2.1. Eigenwerte und Zusammenhang des Graphen Theorem 3.12. Sei L die Laplacematrix eines ungerichteten Graphs G. Dann enspricht die Zahl der Zusammenhangskomponenten von G der Häufigkeit des Eigenwerts 0 von L. Beweisskizze. Wir führen eine vollständige Induktion über die Zahl k der Zusammenhangskomponenten von G. • Fall 1. k = 1: P P Sei v ein Eigenvektor zum Eigenwert 0. Dann gilt: 0 = v T ·0 = v T Lv = 21 ni=1 nj=1 wij (v(i)− v(j))2 . Knoten derselben Zusammenhangskomponente haben den gleichen Wert in v. Da nach Voraussetzung nur eine Zusammenhangskomponente existiert, ist demnach v ein konstanter Vektor. • Fall 2. k > 1: Da die Reihenfolge der Knoten keinen Einfluss auf die Eigenvektoren bzw. die Eigenwerte hat, können wir L in eine Blockmatrix überführen. Dabei entspricht jeder Block einer Zusammenhangskomponente und stellt für diese eine Laplacematrix dar. Nun sind wir für jeden Block in Fall 1 und (0, . . . , 0, vi (1), . . . , vi (ni ), 0, . . . , 0)T ist ein Eigenvektor des i-ten Blocks (mit der korrekten Anzahl Nullen an den Stellen der anderen Blöcke). Insgesamt haben wir also k solcher Blöcke mit linear unabhängigen Eigenvektoren, weshalb der Eigenwert 0 von L die Vielfachheit k besitzt. 3.2.2.2. Eigenwerte und Konnektivität Definition 3.13. Partition Sei G = (V, E) ein ungerichteter Graph. Dann ist (V1 , V2 ) mit • V1 , V2 ⊂ V , • V1 ∩ V2 = ∅ und • V1 ∪ V2 = V eine Partition von G. Dabei müssen V1 und V2 nicht zwingend zusammenhängend sein. Eine Partition (V1 , V2 ) heißt balanciert, wenn ||V1 | − |V2 || ≤ 1 gilt. 50 3. Clusteranalyse von Graphen Bei einer Partitionierung in zwei Teile spricht man auch von einer Bipartition. Definition 3.14. Schnitt Die Menge Ext(V1 , V2 ) = {{u, v} ∈ E; u ∈ V1 , v ∈ V2 } beschreibt die Kanten, die zwischen V1 und V2 verlaufen und wird Schnitt der Partition genannt. Abbildung 3.2.2 zeigt den Schnitt eines Graphen. Abbildung 3.2.2.: Schnitt in einem ungerichteten Graphen Definition 3.15. Bisektionsweite Sei G = (V, E) ein ungerichteter Graph. Die Bisektionsweite σ(G) ist definiert als: σ(G) := min{|Ext(V1 , V2 )|; (V1 , V2 ) ist eine balancierte P artition von G} Theorem 3.16. Untere Schranke für σ Sei G = (V, E) ein ungerichteter Graph mit gerader Knotenanzahl n = |V | und λ2 der zweitkleinse Eigenwert der Laplacematrix L von G. Für die Bisektionsweite von G gilt dann: σ(G) ≥ n · λ2 4 Beweis. Da (1 . . . 1) ein Eigenvektor zum kleinsten Eigenwert 0 der Laplacematrix ist, müssen folglich alle Eigenvektoren von λ2 orthogonal zu diesem Vektor sein, d.h. ist x ein Eigenvektor Pn zu λ2 , so gilt hx, (1 . . . 1)i = 0, also i=1 xi = 0. Mit Hilfe des Rayleigh-Quatienten und des Courant-Fisher Theorems folgt dann, dass λ2 = min Px6=0 xi =0 hLx, xi . hx, xi Nun sei V1 , V2 eine minimale, balancierte Partition von G, also |V1 | = |V2 | = n/2 und |Ext(V )1 , V2 )| = σ(G). Weiterhin sei y ∈ Zn ein Indikatorvektor für den gilt: ( −1, falls vi ∈ V1 yi = +1, falls vi ∈ V2 Damit gilt offensichtlich Pn i=1 yi = 0 und darum gilt auch: 3.3. Random Walks als Analysewerkzeug λ2 ≤ 51 hLy, yi hy, yi P wobei hy, yi = ni=1 yi2 = n. Im Folgenden bezeichne N (i) die Nachbarschaft von Knoten vi . Für einen beliebigen Vektor x ∈ Zn gilt dann: hLx, xi = = n X n X ( Lij xj )xi i=1 j=1 n X n X ( i=1 j=1 = n X i=1 = n X liixi − X xj )xi vj ∈N (i) (|N (i)| · xi − ( X X xj )xi vj ∈N (i) (xi − xj ))xi i=1 vj ∈N (i) X = {vi ,vj }∈E = X {vi ,vj }∈E ((xi − xj )xi + (xj − xi )xj ) (xi − xj )2 Es ist yi = yj für alle Kanten, die nicht zum Schnitt der Partitionen V1 , V2 gehören. Für die Schnittkanten gilt: |yi − yj | = 2 und somit: X X hLy, yi = (yi − yj )2 = 22 = 4 · σ(G). {vi ,vj }∈E {vi ,vj }∈ Ext(V1 ,V2 ) Insgesamt erhalten wir also: λ2 ≤ 4 · σ(G) n hLy, yi = =⇒ σ(G) ≥ λ2 · hy, yi n 4 3.3. Random Walks als Analysewerkzeug Folgt. 3.4. Bildsegmentierung mit spektraler Clusteranalyse Eine sehr anschauliche Anwendung des Graphclusterings ist die Segmentierung von Bildern. Hierbei besteht die Aufgabe darin, ein Bild in inhaltlich zusammenhängende, homogene Bereiche zu zerlegen. Die graphbasierte Bildsegmentierung ist nur eine von vielen Algorithmenklassen, die zur Lösung dieses weitverbreiteten Problems in der Bildverarbeitung verwendet wird. Die Wahl des „richtigen” Algorithmus ist dabei stark anwendungsabhängig. In diesem Abschnitt wollen wir am Beispiel der Bildsegmentierung die spektrale Clusteranalyse kennenlernen. 52 3. Clusteranalyse von Graphen Abbildung 3.4.1.: Minimaler Schnitt einer schlechten Clusterung 3.4.1. Graphrepräsentation von Bildern Zunächst müssen wir definieren, wie ein Bild als Graph repräsentiert werden kann. Die Idee dabei ist, jeden Pixel (i, j) des Bildes durch einen Knoten darzustellen. Kanten existieren dann von jedem Knoten zu seiner lokalen Nachbarschaft im Bild. Oft wird dabei die 8-Nachbarschaft jedes Pixels gewählt, es können aber auch noch größere Nachbarschaften definiert werden. Die Kantengewichte berücksichtigen dabei die Distanz des jeweiligen Pixels zu seinem Nachbarn sowie den Farbunterschied. Definition 3.17. Wir definieren das Kantengewicht einer Kante (u, v) des Bildgraphen G = (V, E) wie folgt: −||F (u) − F (v)||22 w(u, v) := exp · σI2 ( 2 exp −d(u,v) σ2 X 0 falls v in Nachbarschaft von u sonst wobei F : V → [0, 255]3 den RGB-Farbwert eines Pixels und d(u, v) die Distanz von Pixel u zu Pixel v angibt. Mit Hilfe der beiden Konstanten σI und σX können die beiden Faktoren zusätzlich gewichtet werden. Für F sind auch andere Funktionen wie beispielsweise die Helligkeit eines Pixels denkbar, dies ist selbstverständlich anwendungsabhängig. Damit repräsentiert das Kantengewicht w(u, v) die Wahrscheinlichkeit, dass Pixel u zum selben Objekt wie Pixel v gehört. Die Aufgabe eines Clusteringalgorithmus besteht nun darin, eine geeignete Partitionierung der Knotenmenge zu finden, sodass die Objekte eines Bildes jeweils eine Partition bilden. 3.4.2. Optimierungsproblem Nach der Definition der Kantengewichtsfunktion sollten in einer Partitionierung möglichst wenige schwere Kanten, d.h. Kanten mit hohem Gewicht, geschnitten werden. Dies entspricht dem Finden eines minimalen Schnitts zwischen den Partitionen. Allerdings schneidet der Algorithmus mit dieser Zielfunktion bevorzugt kleine Mengen isolierter Knoten. Abbildung 3.4.1 zeigt ein Beispiel, in dem im Falle einer Bisektionierung stets ein einzelner isolierter Knoten der rechten Hälfte einen kleineren minimalen Schnitt ergibt, als der eigentlich für ein Clustering bessere Schnitt, der hier gestrichelt gekennzeichnet ist. Dieses Verhalten wollen wir bei der Bildsegmentierung vermeiden, denn sehr kleine Cluster decken meist einzelne Objekte eines Bildes nicht vollständig ab. Um diese Bedingungen zu berücksichtigen, definieren wir den normalisierten Kantenschnitt Ncut (A, B) nach Shi und Malik [SM00] wie folgt: 3.4. Bildsegmentierung mit spektraler Clusteranalyse Definition 3.18. (Normalisierter Kantenschnitt) Sei vol(X) := der gewichteten Knotengrade der Knoten in X. Dann ist Ncut (A, B) := P u∈X,v∈V 53 w(u, v) die Summe cut(A, B) cut(A, B) + . vol(A) vol(B) Wir wollen nun mit Hilfe von spektralem Clustering auf dem Bildgraphen G = (V, E) Partitionen A und B finden, für die V = A ∪ B und A ∩ B = ∅ gilt, sodass die Funktion Ncut (A, B) annähernd minimal ist. Definition 3.19. Sei n = |V | und x ∈ {−1, 1}n der Indikatorvektor, für den xi = 1 gilt, wenn Knoten i in A enthalten ist und analog xi = −1 gilt, wenn Knoten i in B liegt. Weiter sei 1 der n × 1 dimensionale Einsvektor und b ∈ R, sowie y ∈ {1, −b}n ein weiterer Indikatorvektor. Sei außerdem D die Gradmatrix von G und L die Laplacematrix, also L = D − W , wobei W die gewichtete Adjazenzmatrix ist. Lemma 3.20. (Minimaler, normalisierter Kantenschnitt in algebraischer Form) Unter der Bedingung y T D1 = 0 gilt für den minimalen, normalisierten Kantenschnitt: minx Ncut (x) = miny y T Ly y T Dy (3.4.1) Die Herleitung dieses Ergebnisses kann in der Publikation von Shi und Malik nachgelesen werden [SM00]. Man beachte, dass der Quotient in 3.4.1 dem Rayleigh-Quotienten entspricht. 3.4.3. Relaxiertes Optimierungsproblem Die Lösung des Optimierungsproblems aus 3.4.2 unter den Bedingungen b ∈ R, y ∈ {1, −b}n (diskret!) und y T D1 = 0 ist NP-schwer. Deshalb nehmen wir eine Relaxierung des Problems vor, indem wir y ∈ [−b, 1]n erlauben. Dies führt mit Hilfe des Courant-Fischer-Theorems auf das verallgemeinerte Eigenwertproblem: Ly = λDy. Dieses Problem kann mit Hilfe eines Eigenlösers wie zum Beispiel dem Lanczos-Verfahren approximativ gelöst werden. Da wir in diesem Fall meist nur am Vorzeichen der Einträge in den Eigenvektoren interessiert sind, muss die benötigte Präzision des Eigenlösers nicht sonderlich hoch sein [SM00]. Algorithmus 22 zeigt den kompletten NCut-Algorithmus nach Shi und Malik. 3.4.4. Laufzeit des NCut-Algorithmus Die Laufzeit wird vom Lösen des Eigenwertproblems dominiert. Das Lösen mit einem Standardverfahren wie beispielsweise dem QR-Verfahren benötigt O(n3 ) Operationen. Allerdings berechnet dieses Verfahren alle Eigenvektoren, was wir im NCut-Algorithmus nicht benötigen – wir sind lediglich an einem Eigenvektor interessiert. Zudem spielt die Genauigkeit nur eine untergeordnete Rolle. Hinzu kommt, dass die Bildgraphen aufgrund der Konstruktion meist dünn besetzt sind. Darum bietet sich das bereits erwähnte Lanczos-Verfahren an, das eine Laufzeit von O(tn + t · M V M ult(n)) besitzt. Hierbei bezeichnet t die maximale Anzahl benötigter Matrix√ Vektor-Multiplikationen (t ≈ O( n)) und M V M ult die dabei anfallenden Kosten pro Aufruf (= O(n)). Demnach beträgt die Gesamtlaufzeit typischerweise O(n1.5 ). 54 3. Clusteranalyse von Graphen Algorithmus 22 : NCut-Algorithmus nach Shi und Malik [SM00] Input : G = (V, E, w) : ungerichteter Graph mit wij ≥ 0 Output : C : Clusterung von G 1 D ← DegreeMatrix(G) 2 L ← LaplacianMatrix(G) 3 v2 ← SolveEigenProblem(L, D) // Eigenvektor v2 zum zweitkleinsten EW 4 p ← FindSplitPoint(v2 ) // Finde guten Splitting-Punkt 5 foreach i in V do 6 if v2 (i) ≥ p then 7 C1 ← C1 ∪ {i} 8 else 9 C2 ← C2 ∪ {i} 10 11 12 13 if recursivePartition then // Falls nötig, partitioniere rekursiv weiter else C ← C ∪ C1 ∪ C2 return C 3.4.5. Verallgemeinerung auf k Segmente Im vorangegangenen Abschnitt haben wir den NCut-Algorithmus kennen gelernt, der mit Hilfe von spektralem Clustering rekursiv 2-Partitionierungen eines Graphen berechnet, der aus einem Bild generiert wird. Der Nachteil des rekursiven Vorgehens ist, dass er sehr rechenaufwändig ist. Zudem enthalten die nächsten Eigenvektoren nach dem zweitkleinsten ebenfalls hilfreiche Partitionierungsinformationen, die ungenutzt bleiben. In diesem Abschnitt möchten wir dieses Verfahren deshalb auf eine k-Partitionierung verallgemeinern, indem nicht nur ein Eigenvektor, sondern k Eigenvektoren verwendet werden. Um für jedes Pixel zu entscheiden, welcher der k Eigenvektoren als Indikator für dieses Pixel dienen soll, wird im Raum der Eigenvektoren ein geometrisches Clustering angewandt. Shi und Malik verwenden dafür den k-means-Algorithmus, der auch als Lloyds Algorithmus bekannt ist. 3.4.5.1. k-means Algorithmus von Lloyd Die Idee des k-means-Algorithmus ist die folgende: Gegeben eine Menge von Beobachtungspunkten (p1 , . . . , pn ), wobei jeder der Punkte d-dimensional ist, teilt der k-means Algorithmus die n Punkte in k Cluster C = {C1 , . . . , Ck } ein, wobei die Summe der quadratischen Abstände zum Zentrum innerhalb eines Clusters minimiert wird: min C k X X i=1 pj ∈Ci ||pj − µi ||2 , wobei µi das Zentrum bzw. der Schwerpunkt der Punkte in Ci ist. Der Algorithmus wird dazu mit einer initialen Belegung der Zentren µi aufgerufen. Diese kann zufällig gewählt werden, es existieren aber auch bessere Methoden. Anschließend werden folgende Schritte iterativ ausgeführt: • Zuweisung jedes Punktes pi zu einem der Cluster Cj , bei dem der quadratische Abstand zum Zentrum µi des Clusters (||pj −µi ||2 ) minimiert wird. Dieser Schritt entspricht der Par- 3.5. Weiterführende Literatur 55 titionierung der Punkte anhand des Voronoi-Diagramms, das von den Zentren der Cluster induziert wird. • Neuberechnung der Zentren als Schwerpunkt jedes einzelnen Clusters anhand der Punkte, die im vorigen Schritt in jedes Cluster eingeteilt wurden. Abbildung 3.4.2 veranschaulicht die Schritte des Algorithmus. Die Iteration wird beendet, sobald sich keine neuen Änderungen mehr ergeben. Der Algorithmus konvergiert, da in jedem Schritt die Zielfunktion optimiert wird und es nur eine endliche Anzahl solcher Partitionen gibt. Es ist allerdings nicht sichergestellt, dass der Algorithmus in ein globales Optimum konvergiert. Abbildung 3.4.2.: Schematische Darstellung des k-means Algorithmus von Lloyd Algorithmus 23 zeigt den KWay-NCut-Algorithmus. Algorithmus 23 : KWay-NCut-Algorithmus Input : G = (V, E, w) : ungerichteter Graph mit wij ≥ 0 Output : C : Clusterung von G 1 D ← DegreeMatrix(G) 2 L ← LaplacianMatrix(G) 3 4 5 6 // Berechne generalisierte Eigenvektoren v2 , . . . , vk+1 {v2 , . . . , vk+1 } ← SolveEigenProblem(L, D) U ← (v2 v3 . . . vk+1 ) // Fasse Eigenvektoren als Spalten v. U auf // Interpretiere Zeilen v. U als k-dim. Punkte und wende geom. Algorithmus an // Übertrage das Ergebnis auf Knoten des Graphen C ← k-means(U (1, :), . . . , U (n, :)) return C 3.5. Weiterführende Literatur Der Abschnitt zur Bildsegmentierung basiert auf einem Paper von Shi und Malik [SM00]. Mehr folgt. 57 4. Visualisierung von Graphen In diesem Kapitel möchten wir nun für einen Graphen ohne Koordinateninformationen eine gute visuelle Repräsentation finden, durch die die Struktur des Graphen für einen Menschen schnell ersichtlich wird. Die Visualisierung soll also übersichtlich sein und je nach Anwendungsfall bspw. wenige Überschneidungen oder wenige Knicke besitzen. Typische Anwendungsgebiete sind UBahn-Pläne und technische Zeichnungen, aber auch die Darstellung von Datenrelationen, wie z.B. von sozialen Netzwerken oder das Debugging von Graphenalgorithmen. In jedem Fall suchen wir somit für jeden Knoten i ∈ V eine Koordinate xi im R2 oder R3 , sodass die davon induzierte Zeichnung die gewünschten Eigenschaften besitzt. Welcher Algorithmus zur Visualisierung eingesetzt werden sollte, hängt stark von der Klasse des Eingabegraphen ab. So lassen sich Graphen mit einem geringen Durchmesser oft schlecht darstellen. Für sehr große Graphen hingegen benötigt man eine hierarchische Auflösung, da eine sinnvolle Zeichnung des kompletten Graphen viel zu viel Platz einnehmen würde. Der FacebookFreundschaftsgraph würde auf normalen Bildschirmen mehrere zehntausend Kanten pro Pixel benötigen! 4.1. Spektrales Zeichnen In diesem Abschnitt stellen wir eine Methode vor, die mit dem spektralen Clustering des letzten Kapitels verwandt ist. Grundidee ist hierbei eine Erkenntnis von Hall: Es lassen sich viele Abfolge- und Platzierungsprobleme durch Minimierung der quadrierten Distanzen zwischen den Koordinaten charakterisieren. Sei LG die gewichtete Laplace-Matrix des Graphen G. Dann ist in unserem Szenario das Minimierungsproblem gegeben durch X minn w(i, j)||xi − xj ||2 = minn xT LG x x∈R unter der Nebenbedingung x∈R (i,j)∈E n X x2l = 1. l=1 Die Nebenbedingung impliziert hierbei x 6= 0. Dies ist wichtig, da in der trivialen Lösung alle Knoten auf den gleichen Punkt abgebildet würden. Nach dem letzten Kapitel müssen wir somit diejenigen Eigenvektoren als Koordinaten verwenden, die zu den zwei kleinsten positiven Eigenwerten gehören. Bezeichnen wir diese mit v1 und v2 , so setzen wir also xi = ((v1 )i , (v2 )i ). Wir betrachten nun allgemein, warum die Eigenvektoren der betragsmäßig größten Eigenwerte besonders nützlich sind. Sei A ∈ Rn×n eine symmetrische Matrix mit den Eigenwerten α1 ≥ α2 ≥ . . . ≥ αn und (v1 , . . . , vn ) eine Orthonormalbasis aus dazugehörigen Eigenvektoren. Dann lässt sich A darstellen durch seine spektrale Zerlegung: A= n X αi vi viT . i=1 Wir möchten nun mit Hilfe der Eigenwerte eine möglichst gute Approximation B von A erstellen, 58 4. Visualisierung von Graphen für die die Operatornorm ||A − B|| bzw. die Frobeniusnorm ||A − B||F klein ist. Dabei sind die Normen gegeben durch sX ||M x|| ||M || = maxn ||M ||F = Mij2 . x∈R ||x|| i,j Als Hilfsmittel dient uns dabei das Courant-Fischer-Theorem, das wir hier nicht beweisen: Theorem 4.1. Sei A eine symmetrische Matrix mit Eigenwerten α1 ≥ α2 ≥ . . . ≥ αn . Dann gilt: αk = = max S⊆Rn ,dim(S)=k xT Ax x∈S,x6=0 xT x min xT Ax T ⊆Rn ,dim(T )=n−k+1 x∈T,x6=0 xT x min max Da wir nur nichttriviale Lösungen betrachten wollen, werden wir die Forderung x 6= 0 nicht mehr explizit erwähnen. Nach dem Courant-Fischer-Theorem gilt somit für die extremen Eigenwerte α1 und αn : xT Ax xT Ax α1 = maxn T αn = minn T x∈R x∈R x x x x Als für uns wichtige Folgerung aus dem Courant-Fischer-Theorem P erhalten wir, dass die beste (k) Approximation von A durch eine Matrix mit Rang k gerade A := ki=1 αi vi viT ist. Der Beweis dieser Folgerung sei dem Leser als Selbstübung überlassen. Der Approximationsfehler ||A − A(k) || ist daher so klein wie möglich und dies erklärt, warum die k betragsmäßig größten Eigenwerte und ihre Eigenvektoren bereits sehr viel Information über A enthalten. 4.2. Kräftegesteuertes Zeichnen In diesem Abschnitt werden wir für das Zeichnen eines großen ungerichteten Graphen G = (V, E) einen weiteren Ansatz vorstellen. Wir modellieren dazu G als ein physikalisches System, auf das bestimmte Kräfte wirken und für das wir einen stabilen Gleichgewichtszustand (Äquilibrium) finden möchten. Wir gehen dazu wie folgt vor: 1. Berechnung von Kräften, die auf die Knoten wirken. 2. Bewegung der Knoten entlang der Richtung der Kräfte. 3. Wiederholung der beiden Operationen, bis ein Äquilibrium erreicht ist. Zur Modellierung der Kräfte benutzen wir das Feder-elektrische Modell. Dabei stellen wir uns die Knoten als elektrisch geladen vor sowie die Kanten als Federn, durch die die Endknoten einer Kante gegenseitig angezogen werden. Gleichzeitig wirken die elektrischen Kräfte auf jedes Paar von Knoten, gleichgültig ob durch eine Kante verbunden oder nicht, voneinander abstoßend. Die anziehende Kraft Fa zwischen Nachbarn i und j soll hierbei proportional zur quadratischen Distanz zwischen i und j sein. Wir setzen daher Fa (i, j) = − ||xi − xj ||2 xi − xj · , K ||xi − xj || wobei K ein Skalierungsparameter ist, abhängig von der gewünschten Größe der endgültigen Zeichnung. Die abstoßende Kraft Fr (r für engl. repulsive) zwischen allen Knotenpaaren (i, j) 4.2. Kräftegesteuertes Zeichnen 59 soll hingegen invers proportional zur Distanz zwischen i und j sein, sodass wir Fr (i, j) = xi − xj K2 · ||xi − xj || ||xi − xj || setzen. Hierbei ist K erneut der eingeführte Skalierungsparameter. Die Energie E in unserem Feder-elektrischen Modell ist gegeben durch: X X E(x) = ||xi − xj ||3 /3K − K 2 ln(||xi − xj ||) i6=j ij∈E Beispiel 4.2. Sei xi = (5; 1) die Koordinate von Knoten i und xj = (2; 5) die Koordinate von Knoten j. Als Skalierungsparameter wählen wir K = 10. Wir möchten nun die auf das Tupel (i, j) wirkenden Kräfte berechnen. Es ergibt sich: 25 (3, −4) · = (−1.5, 2) 10 5 100 (3, −4) · = (12, −16) 5 5 Fa (i, j) = − Fr (i, j) = Die anziehende Kraft Fa (i, j) entspricht somit einer Translation um −1.5 in x-Richtung und 2 in y-Richtung, während Fr (i, j) einer Translation um 12 in x-Richtung und −16 in y-Richtung entspricht. Für unseren Algorithmus können wir grundsätzlich ein beliebiges initiales Layout der Knoten wählen, z.B. eine zufällige Platzierung der Knoten in der Ebene. Dann werden wiederholt die verschiedenen Kräfte berechnet und eine Verschiebung durchgeführt, bis der Algorithmus konvergiert. Die Verschiebung wird dabei durch eine abnehmende Schrittlänge skaliert. Zusammengefasst ergibt sich Algorithmus 24. Algorithmus 24 : Algorithmus ForceDirected Input : Graph G = (V, E), Skalierungsparameter K, iniatiales Layout x, Toleranz tol Output : Kräftebasiertes Layout x 1 converged ← f alse 2 step ← initialStepLength 3 while converged 6= true do 4 x(0) ← x 5 for i ∈ V do 6 f ←0 // berechne Kraftvektor f 7 foreach j ∈ N (i) do 8 f ← f + Fa (i, j) 9 10 11 12 13 14 for j 6= i, j ∈ V do f ← f + Fr (i, j) xi ← xi + step · (f /||f ||) // Normalisierung wird nur einmal ausgeführt! step ← updateStepLength(step, x, x0 ) if kx − x(0) k < tol · K then converged ← true Der angegebene Algorithmus funktioniert auf kleineren Graphen recht gut. Eine mögliche Verbesserung wäre die adaptive Aktualisierung der Schrittgröße. Für große Graphen ergeben sich 60 4. Visualisierung von Graphen Abbildung 4.2.1.: Beispiel für einen Quadtree, http://upload.wikimedia.org/wikipedia/de/a/ a7/Quadtree.png dann allerdings noch immer einige Probleme: Zum einen können viele lokale Minima auftreten. Der Algorithmus läuft dann häufig in ein schlechtes lokales Minimum. Dies könnte mit einem Multilevel-Ansatz umgangen werden, dessen Prinzip wir in Abschnitt 4.2.2 vorstellen werden. Zum anderen tritt bei der Berechnung von Fr quadratische Zeitkomplexität auf. Um dies zu umgehen, werden wir nachfolgend eine geometrische Datenstruktur zur Approximation von Fr benutzen. Für weit entfernte Knoten berechnen wir dann nur einen Näherungswert. Die Laufzeit kann dann auf O(n log n + m) gedrückt werden. 4.2.1. Quadtree-Datenstruktur Wie bereits erwähnt, besitzt die Berechnung von Fr eine quadratische Laufzeit. Dies kommt daher, dass Algorithmus 24 eine verschachtelte Schleife ist, bei der außen über jeden Knoten iteriert wird und im Inneren für Fr über alle anderen Knoten iteriert wird. Ähnlich dem nKörper-Problem in der Physik verwenden wir zur Approximation den Ansatz, dass wir weit entfernte Knoten in der gleichen Region als einen Superknoten auffassen. Wir realisieren dies mit Hilfe eines Quadtrees im zweidimensionalen bzw. mit einem Octree im dreidimensionalen Fall. Ein Quadtree ist eine rekursive Baum-Datenstruktur, die wie folgt aufgebaut wird: • Der Wurzelknoten repräsentiert die gesamte Ebene (bzw. den gesamten zu betrachtenden Ausschnitt). • Falls das zum aktuellen Knoten gehörende Rechteck zu viele Punkte (Schwellwert als Parameter) enthält, dann teile die zu einem Knoten v im Baum gehörige Fläche wird in vier gleich große Rechtecke, die jeweils einem der vier Kinder von v zugeordnet werden. • Verfahre rekursiv so lange weiter, bis die gewünschte Auflösung erreicht ist, also z.B. die Anzahl der Punkte pro Rechteck unter dem Schwellwert liegt. In Abbildung 4.2.1 ist beispielhaft die Aufteilung eines Rechtecks und der dazugehörige Quadtree dargestellt. Falls ein Knoten j in unserem Ausgangsgraphen G weit weg ist für die Kraftberechnung Fr (i, j), so genügt zur Approximation schon ein innerer Baumknoten des Quadtrees, es muss kein Blatt oder j selbst sein. Ein innerer Baumknoten repräsentiert dabei eine Menge S von Knoten des P Graphen G am Schwerpunkt xS = j∈S xj /|S| von S. Die abstoßende Kraft von Knoten i zum Superknoten S ist dann K2 xi − xS Fr (i, S) = · . ||xi − xS || ||xi − xS || Eine Möglichkeit, um das Kriterium „weit weg” zu formalisieren, besteht in dem Barnes-HutKriterium: Ein Superknoten S ist weit weg von Knoten i, wenn die Breite ds des Rechtecks, das 4.2. Kräftegesteuertes Zeichnen 61 zu S gehört, klein ist im Vergleich zum Abstand von xS und xi . Dies bedeutet, es gibt ein θ ≥ 0, sodass gilt dS /||xi − xS || ≤ θ. Je kleiner dabei θ gewählt wird, umso genauer ist die Näherung. In der Praxis haben sich hierfür die Werte θ = 1 und θ = 2 bewährt. Betrachten wir nun, wie sich die Verwendung eines Quadtrees in Algorithmus 24 auf die Berechnung der abstoßenden Kraft Fr auswirkt. Dabei nehmen wir an, dass die Punkte im Quadtree geeignet verteilt sind. Die Konstruktion des Quadtrees benötigt O(n log n) Zeit. Die Bestimmung aller Superknoten für einen Knoten im Ausgangsgraphen G kann in O(log n) durchgeführt werden. Die Laufzeit der Bestimmung der abstoßenden Kraft reduziert sich somit von O(n2 ) auf O(n log n). Weitere Verbesserungen sind sogar noch möglich, wenn wir nicht nur zwischen einem Blatt und einem Superknoten approximieren, sondern jeweils zwischen Paaren von Superknoten. Mit Hilfe der Datenstruktur des Quadtrees haben wir somit das Problem der quadratischen Zeitkomplexität pro Iteration umgangen. Allerdings können noch immer viele lokale Minima der Energiefunktion existieren. Hierfür werden wir im nächsten Abschnitt den Multilevel-Ansatz kennenlernen. 4.2.2. Multilevel-Verfahren für kräftegesteuertes Zeichnen Ein Mehrebenen- oder Multilevel-Verfahren besteht aus drei Phasen. In einem ersten Schritt wird der Eingabegraph G rekursiv vergröbert, d. h. es entsteht eine Hierarchie von Graphen G = G0 , G1 , . . . , Gk , den k + 1 Ebenen des Verfahrens. Je höher der Index einer Ebene, desto weniger Knoten und Kanten soll der zugehörige Graph besitzen. Trotz Vergröberung soll dabei die Struktur des Eingabegraphen weitgehend erhalten bleiben. Auf der stärksten Vergröberungsstufe Gk wird dann eine initiale Lösung berechnet. Abschließend wird durch Interpolation der initialen Lösung und lokaler Optimierung auf jeder Ebene eine Lösung für den Eingabegraphen errechnet. In unserem Szenario laufen die drei Phasen folgendermaßen ab: 1. Rekursive Vergröberung: Zur Vergröberung des ungerichteten Graphen Gi existieren verschiedene Möglichkeiten. Oft wird dazu ein nicht erweiterbares Matching benutzt. Die Kanten des Matchings und deren Endknoten werden dabei zu einem neuen Knoten verschmolzen. Sei e = uv eine solche Kante. Wir bilden dann einen neuen Superknoten x in Gi+1 mit w(x) = w(u) + w(v) und entfernen die Kante e. Kanten von einem Knoten y ∈ / {u, v, x} zu u oder v werden in Gi+1 auf den Superknoten x „umgebogen”. Dabei verschmelzen wir parallele Kanten und addieren ihre Gewichte: w(yx) = w(yu) + w(yv). Eine alternative Möglichkeit zur Vergröberung besteht in der Berechnung einer unabhängigen Knotenmenge U mit geeignet gewichteten Kanten zwischen den Knoten in U . 2. Initiales Layout: Durch die Vergröberung in Phase 1 ist der resultierende Graph Gk sehr klein. Es kann somit ein beliebiger Algorithmus zur Berechnung eines initialen Layouts gewählt werden. Der im vorherigen Abschnitt vorgestellte ForceDirected-Algorithmus bietet sich hierfür an, da er auf kleinen Graphen gute Lösungen erreicht. Wegen der kleinen Größe von Gk ist die Wahrscheinlichkeit groß, dass der Algorithmus das globale Optimum für Gk erreicht. 3. Interpolation und Verbesserung: In dieser Phase wird die Rekursion aus Phase 1 wieder rückabgewickelt. Im Graphen Gi expandieren wir die in Gi+1 verschmolzene Kante e = uv wieder, indem die alte Adjazenzinformation wiederhergestellt wird. Die beiden Endknoten u und v erhalten im Layout für 62 4. Visualisierung von Graphen Gi zunächst die Position ihres Superknotens. Lokale Verbesserungen können nun, z.B. mit dem ForceDirected-Algorithmus, durchgeführt werden. Bei letzterem Algorithmus muss beachtet werden, dass sich die relative Position von u und v zueinander nicht mehr ändert, falls die Nachbarschaften der beiden Knoten gleich sind. In diesem Fall sollten alternative Platzierungen bei der Expansion von e erwogen werden. Verwenden wir den Algorithmus ForceDirected in einem Multilevel-Verfahren, so können wir durch die lokalen Verfeinerungen in Phase 3 auch weitgehend das Problem umgehen, dass viele lokale Minima im Graphen auftreten können. Das Multilevel-Verfahren bietet somit sowohl eine globale Sicht (durch Phase 2), als auch eine lokale Sicht (durch Phase 3) auf das Problem. Nichtsdestotrotz bleibt es eine Heuristik, die nicht garantiert, dass wir die global optimale Lösung finden. Für viele kombinatorische Optimierungsprobleme sind Multilevel-Verfahren jedoch sehr effektiv. 4.3. Weiterführende Literatur Eine ausführlichere Darstellung des spektralen Zeichnens und zu spektralen Methoden findet sich im Kapitel Spectral Graph Theory von Spielman im Buch Combinatorial Scientific Computing [NS12] von Naumann und Schenk (Hrsg.). Weitere Erklärungen zum DirectedForce-Algorithmus und Vergleiche mit anderen Visualisierungsalgorithmen sind ebenfalls im Buch Combinatorial Scientific Computing, im Kapitel Algorithms for Visualizing Large Networks von Hu zu finden. 63 5. Lastbalancierung paralleler Berechnungen 5.1. Parallelität Abschnitt folgt. 5.2. Dynamische Balancierung unabhängiger Lasten Gegeben sei ein Rechnernetz mit vielen Prozessoren. Jeder Prozessor hat gewisse Arbeitsaufgaben, die abzuarbeiten sind und die wir in der Folge als Last bezeichnen. Bis zur gemeinsamen Lösung eines Problems muss man immer auf den am längsten rechnenden Prozessor warten. Daher ist es für eine effiziente Nutzung eines Parallelrechners entscheidend, dass alle Prozessoren gleich stark ausgelastet sind. Algorithmisch stellen wir uns daher die Frage, wie eine möglichst schnelle Balancierung der Lasten erreicht werden kann. Unsere Modellannahme in diesem Abschnitt bezüglich des parallelen Systems und der Arbeitsaufträge ist, dass die Prozessoren in jedem Schritt nur ihre eigene Last und die ihrer Nachbarn kennen und mit ihnen in einer Runde Last austauschen können. Dies geschieht ohne zentrale Steuerung und nur über die Kommunikationskanäle, die Prozessoren direkt miteinander verbinden. Weiterhin sind die Lasten beliebig aufteilbar (also durch reelle Zahlen repräsentierbar). Ein entsprechendes Rechnersystem repräsentieren wir durch einen ungerichteten Graphen, in dem die Knoten die Prozessoren darstellen und die Kanten Kommunikationskanäle zwischen den Prozessoren. 5.2.1. Das Diffusionsverfahren erster Ordnung (FOS) Gegeben sei ein Graph G = (V, E) mit n Knoten und m Kanten und seiner Adjazenzmatrix A. Sei w der Vektor (w1 , . . . , wn )T , der die Arbeitslasten der Prozessoren (= Knoten) beschreibt, d. h., wi bezeichnet die Last des Knotens vi ∈ V . Setze den Diffusionsparameter α ∈ (0, maxi 1deg(i) ). (k) Weiter sei w(k) der Lastvektor nach k Iterationsschritten und sei yij der Fluss entlang der Kante (vi , vj ) im Schritt k. Dann führt das Diffusionsverfahren erster Ordnung (engl.: first order diffusion scheme, FOS) in Iteration k + 1 folgende Operationen aus: (k+1) yij (k+1) wi (k) (k) − wj ) X (k+1) (k) = wi − yij = α(wi j∈N (i) =w− In Matrixform: X j∈N (i) (k) α(wi (k) (k) − wj ) = (1 − di α)wi + X j∈N (i) (k) αwj 64 5. Lastbalancierung paralleler Berechnungen Abbildung 5.2.1.: 3 × 3-Torus aus Beispiel 5.2 (links) mit initialer Lastverteilung und dem Fluss, der durch das Diffusionsverfahren entsteht (rechts). (k+1) w1 (k+1) w2 .. . (k+1) wn = 1 − d1 α 0 0 1 − d2 α 0 .. . α | α α 0 0 ··· ··· α α ··· 0 ··· ··· 0 α {z 0 0 ··· ··· 0 ··· 0 n×n-Matrix M (k) w1 (k) w2 · . .. (k) 1 − dn α wn } α α .. . Bemerkung 5.1. Es gilt also w(k+1) = M w(k) , wobei M ∈ Rn×n mit M = I − αL und w(k) ∈ Rn . Es folgt w(k+1) = M k+1 w(0) . Weiterhin besitzt M nur reelle Eigenwerte und es gibt n aufeinander stehende Eigenvektoren z1 , . . . , zn , die eine Orthonormalbasis im Rn bilden. Beispiel 5.2. Der Graph in Abbildung 5.2.1 links ist ein 3 × 3-Torus. Die initiale Lastverteilung w(0) der Knoten sei in der Abbildung 5.2.1 rechts dargestellt. Dann liefert das Diffusionsverfahren denjenigen Fluss, der auf den Kanten dargestellt ist. (0) Lemma 5.3. Sei wn die initiale Lastverteilung in einem Graphen G = (V, E) und sei w= n X wj j=1 n (1, . . . , 1) die zugehörige balancierte Lastsituation. Sei w(0) = Pn j=1 βj zj , dann gilt: w = β1 · z1 . Beweis. Es gilt λ1 = 1 > λ2 (falls G zusammenhängend), und z1 = a · (1, . . . , 1), wobei a ∈ R. 5.2. Dynamische Balancierung unabhängiger Lasten 65 Dann gilt: D w(0) , w E = * n X βj zj , w j=1 = = * n X * βj zj , j=1 + n X wj j=1 β 1 z1 , n X j=1 n + (1, . . . , 1) + wj (1, . . . , 1) n (da (1, . . . , 1)zu allen Eigenvektoren außer z1 senkrecht steht) * + n X wj = β1 a(1, . . . , 1), (1, . . . , 1) n j=1 Nehmen wir nun die Gleichheit an, wobei w = b · β1 · z1 . Dann folgt: D w (0) ,w E = D E 1 w(0) , w = hw, wi b P j=1 wj (1, . . . , 1) (w1 , . . . , wn ), n P Pn n X ( nj=1 wj )2 j=1 wj = = wj · n n j=1 P P j=1 wj j=1 wj (1, . . . , 1), (1, . . . , 1) hw, wi = n n P P X j=1 wj 2 ( nj=1 wj )2 = =n· n n2 i=1 ⇒b = 1 Insgesamt gilt also w = β1 · z1 . Seien µ1 ≥ µ2 ≥ . . . ≥ µn die Eigenwerte von M und λ1 ≤ λ2 ≤ . . . ≤ λn die Eigenwerte der Laplace-Matrix L. Sei zi der Eigenvektor der Matrix L zum Eigenwert λi . Dann folgt: M · zi = (I − αL)zi = Izi − αLzi = zi − αλi zi = (1 − αλi )zi . Der Vektor zi ist daher auch Eigenvektor von M zum Eigenwert 1 − αλi . Da die Eigenwerte von L alle nicht-negativ sind, ist L positiv semidefinit. Wie bereits festgestellt, gilt λ1 = 0 und der zugehörige Eigenwert ist z1 = (1, . . . , 1). Wir haben bereits im Zusammenhang mit spektraler Clusteranalyse gezeigt, dass 0 ein einfacher (d.h. einfach vorkommender) Eigenwert von 0 genau dann ist, wenn G zusammenhängend ist. Definition 5.4. Sei (k) = w(k) − w der Fehler nach k Iterationsschritten. Lemma 5.5. Sei G =P(V, E) ein Graph und sei w(0) die initiale Lastsituation in G. Seien β1 , . . . , βn ∈ R: w(0) = ni=1 βi zi . Dann gilt: (0) = n X i=2 βi zi . 66 5. Lastbalancierung paralleler Berechnungen Beweis. Es gilt: (0) =w (0) −w = n X i=1 βi · zi − w = n X i=1 βi zi − β1 z1 (k) = w(k) − w = M k w(0) − M k w = M k (w(0) − w) = M k · (0) Theorem 5.6. Sei G = (V, E) ein Graph, sei w(0) die initiale Lastsituation und führe Diffusion mittels der Diffusionsmatrix M durch. Dann gilt: k(k) k2 ≤ max{|µ2 |, |µn |}k · k(0) k2 Beweis. Zunächst gilt M w̄ = w̄, da mit Lemma 5.3 folgt M w̄ = M β1 z1 = β1 z1 = w̄. Setze γ := max {|µ2 |, |µn |}. Nach Definition von (k) gilt ||(k) ||2 = ||w(k) − w̄||2 = ||M k w(0) − w̄||2 = ||M k w(0) − M k w̄||2 = ||M k (w(0) − w̄)||2 = ||M k (0) ||2 Weiterhin gelten die Zusammenhänge M (0) n n X X = M( βj zj ) = β j µj z j j=2 n X M k (0) = M k ( j=2 j=2 n X β j zj ) = βj µkj zj j=2 Insgesamt folgt somit die Behauptung durch ||(k) ||2 = || ≤ || n X j=2 n X j=2 βj µkj zj ||2 βj γ k zj ||2 = ||γ k n X j=1 βj zj ||2 = ||γ k (0) ||2 = γ k ||(k) ||2 Definition 5.7. Ein Fluss-Vektor y heißt `2 -minimal, wenn kyk2 = min{kxk2 | x balanciert die Last in G mit initialem Lastvektor w(0) }. Theorem 5.8. Das Diffusionsverfahren FOS berechnet einen `2 -minimalen Fluss y ∈ Rm . Bemerkung 5.9. Das Diffusionsverfahren kann durch Berücksichtigung der vorletzten Iteration √ auf einfache Weise so abgewandelt werden, dass die Lastsituation bereits nach O( log(1/) ) Schrit1−γ ten -balanciert ist. Darüber hinaus gibt es weitere Diffusionsverfahren mit noch deutlich besserem Konvergenzverhalten. Dazu benötigt man unter anderem die Eigenwerte der Laplace-Matrix des Graphen. 5.2.2. Weitere Verfahren zur dynamischen Lastbalancierung Es gibt eine Reihe weiterer Verfahren für das oben beschriebene Szenario (beispielsweise Dimension Exchange oder Work Stealing), auf die hier (zunächst) nicht genauer eingegangen werden soll. 5.3. Balancierung abhängiger Lasten mittels Graphpartitionierung 67 Abbildung 5.3.1.: Veranschaulichung zur Balancierung abhängiger Lasten und ihre Entsprechung bei der Partitionierung eines Graphen. 5.3. Balancierung abhängiger Lasten mittels Graphpartitionierung Im vorigen Abschnitt sind wir davon ausgegangen, dass die Arbeitslasten des parallelen Systems unabhängig voneinander waren. Nun ändern wir das Szenario in dieser Hinsicht. Die Arbeitslasten und deren Abhängigkeiten repräsentieren wir dabei als Graphen, dessen Knoten (Lasten) durch eine Kante verbunden sind, wenn zwischen ihnen eine Abhängigkeit besteht. Eine typische Anwendung sind iterative Algorithmen, die bei der Berechnung des Wertes an einem Knoten v in Iteration i auf die Werte der Nachbarn von v in Iteration i−1 zurückgreifen muss. Will man diese Algorithmen parallelisieren, muss man sich im Allgemeinen überlegen, wie man die Daten auf die verschiedenen Prozessoren aufteilt, um möglichst wenig zwischen Prozessoren kommunizieren zu müssen. Dies führt uns zum Graphpartitionierungsproblem. Bei der Partitionierung eines Graphen G = (V, E) soll die Knotenmenge V in fast gleich große, zusammenhängende Teilmengen aufgeteilt werden. Typische Anwendungsbereiche sind Teile-undHerrsche-Algorithmen oder auch Lastbalancierung für verteilte parallele Graphenalgoirthmen, wie z.B. beim wissenschaftlichen Rechnen oder der Analyse riesiger Netzwerke. In Abbildung 5.3.1 Mitte ist ein Graph dargestellt, der die Abhhänigkeiten in einem System repräsentieren soll. Die Werte in den Knoten sind dabei die initialen Lasten. Der auf den Kanten aufgeführte Fluss (Werte gerundet) balanciert das System so, dass jeder Knoten genau 92 Einheiten Last erhält. Interessant dabei ist, dass der Knoten links unten als initiale Last 67 < 92 besitzt und für den balancierten Fluss dennoch Last abgeben muss. Der Fluss könnte mittels Diffusion ausgerechnet werden. Allerdings ist dies auch durch Partitrionierungen möglich, die dem Lastproblem entsprechen: In Abbildung 5.3.1 links ist die dem initialen Zustand entsprechende Partitionierung dargestellt und rechts die Partitionierung, die den balancierten Zustand induziert. Definition 5.10. Eine Abbildung Π : V → {1, . . . , k} induziert eine disjunkte Aufteilung V = π1 ∪π2 ∪. . .∪πk mit πi = {v ∈ V | Π(v) = i}. Eine solche Abbildung Π nennen wir Partitionierung und die π Blöcke von Π. Sie heißt -balancierte Partitionierung, wenn |πi | ≤ (1 + )d|V |/ke gilt. Definition 5.11. Der Kantenschnitt cut(Π) einer Partitionierung Π eines ungerichteten Graphen G = (V, E, ω) ist definiert als: X cut(Π) := ω({u, v}). {u,v}∈E: π(u)6=π(v) Der Kantenschnitt cut(Π) einer Partitionierung Π ist beispielhaft in Abbildung 5.3.2 dargestellt. 68 5. Lastbalancierung paralleler Berechnungen π2 π1 π3 Abbildung 5.3.2.: Ein Graph mit Partitionierung Π = π1 ∪ π2 ∪ π3 . Wir nehmen an, dass alle Kantengewichte 1 sind. Dann gilt für den von Π induzierten Kantenschnitt: cut(Π) = 7. Die Kanten, die dabei gezählt werden, sind rot dargestellt. Problem 5.12. Das Graphpartitionierungsproblem besteht in der Berechnung einer -balancierten Partitionierung mit minimalem Kantenschnitt. Bemerkung 5.13. Wird ein dynamischer Graph betrachtet, bei dem sich die Struktur über die Zeit ändert, so sprechen wir von einem Repartionierungsproblem. In diesem Fall möchten wir bei Eingabe von G und Π1 das Problem 5.12 lösen und Π2 berechnen. Dabei fordern wir zusätzlich, dass die Migrationskosten zwischen Π1 und Π2 minimiert werden sollen. Diese ergeben sich üblicherweise aus der Zahl der Knoten, die in Π2 einem anderen Block zugewiesen sind als in Π1 . Im Allgemeinen sind beide Probleme N P-schwer, sodass in der Praxis Heuristiken eingesetzt werden. Die Schwierigkeit des Optimierungsproblems liegt interessanterweise nicht in der Zielfunktion des minimalen Schnitts, sondern in der Nebenbedingung der Balancierung der Blöcke. Falls diese Nebenbedingung entfällt, können wir das bekannte MaxFlow-MinCut-Theorem anwenden und mit effizienten Flusslösern eine (im Allgemeinen natürlich unbalancierte) Lösung mit minimalem Schnitt in Polynomialzeit berechnen. 5.3.1. Bubble-Framework Eine Partitonierungsidee, die wir nachfolgend benutzen wollen, basiert auf der Idee von Lloyds kmeans Algorithmus: Gegeben sei eine Punktmenge in der Ebene. Wir wollen diese in k Bereiche zerlegen und für jeden Bereich ein Zentrum bestimmen, sodass die Summe über den quadratischen Abstand zu den Zentren minimal wird. Initial werden dabei k Zentren beliebig, z.B. zufällig, gewählt. Dann wird jeder Punkt dem nächstgelegenen Zentrum zugeordnet. Anschließend wird der jeweilige geometrische Schwerpunkt der entstandenen Bereiche neues Zentrum und ein weiterer Iterationsschritt beginnt. Dieses Verfahren ist schematisch in Abbildung 5.3.3 links dargestellt. Das Bubble-Framework überträgt diese Idee nun auf Graphen, indem der Abstand durch ein geeignetes Distanz- bzw. Ähnlichkeitsmaß ersetzt wird (siehe Abbildung 5.3.3 rechts). Dieses Ähnlichkeitsmaß soll zum Ausdruck bringen, wie gut zwei Knoten (oder allgemeiner: zwei Regionen) im Graphen miteinander verbunden sind. „Gut verbunden” wird hier nicht streng definiert, in der Literatur gibt es dazu verschiedene Ansätze. Im Allgemeinen versteht man darunter, dass zwischen den Knoten eine Vielzahl kurzer Pfade existieren. Letztlich nutzen wir hier wie bereits im Abschnitt zu MCL (Abschnitt 3.2) aus, dass geeignete Techniken auf Basis von Random Walks 5.3. Balancierung abhängiger Lasten mittels Graphpartitionierung 69 Abbildung 5.3.3.: Schematische Darstellung des k-means Algorithmus von Lloyd (links) und seine Übertragung auf Graphen durch das Bubble-Framework (rechts). Abbildung 5.3.4.: Schematische Darstellung des Abflusses bei der gestörten Diffusion. (oder auf Diffusion als speziellem Random Walk) in der Lage sind, dichte Gebiete in Graphen von dünnen zu unterscheiden. Das Bubble-Framework besteht aus der anfänglichen Prozedur DetermineInitialCenters und den beiden Prozeduren AssignPartition und ComputeCenters, die in jedem Iterationsschritt ausgeführt werden. Diese folgen, wie an den Namen zu erkennen ist, der generischen Struktur des k-means-Algorithmus. Bevor wir seine Details anschauen, führen wir zunächst das verwendete Distanz- bzw. Ähnlichkeitsmaß ein. 5.3.2. Gestörte Diffusion (FOS/C) In diesem Abschnitt ändern wir das FOS-Verfahren so ab, dass ein balancierter Zustand bei Konvergenz vermieden wird. Dazu fließt in jeder FOS-Iteration von jedem Knoten δ > 0 Last ab und anschließend wird der Gesamtabfluss auf die Menge der Quellknoten gleichmäßig verteilt, wie in Abbildung 5.3.4 dargestellt ist. Dabei geht keine Last im Graphen verloren, da sie nur umverteilt wird! Dieses Verfahren nennen wir gestörte Diffusion oder kurz FOS/C (engl.: f irst order diffusion scheme with constant drain). Definition 5.14. (Abflussvektor) Sei S ⊂ V die Quellmenge. Dann ist der Abflussvektor d gegeben durch: ( −δ, falls i ∈ /S di = n·δ |S| − δ, falls i ∈ S Definition 5.15. (Gestörte Diffusion FOS/C) Gegeben seien G = (V, E), eine Quellmenge ∅= 6 S⊂V von Knoten sowie der Diffusionsparameter 0 < α < max deg(G)−1 . Seien der Abfluss- 70 5. Lastbalancierung paralleler Berechnungen vektor d wie in Def. 5.14 sowie der initiale Lastvektor w(0) definiert durch: ( 0, falls i ∈ /S (0) wi = n |S| , falls i ∈ S Das gestörte Diffusionsverfahren FOS/C führt dann in Iteration k (i ≥ 1) die Berechnung w(k) = M w(k−1) + d aus. Hierbeit ist M = I − αL die bereits bekannte Diffusionsmatrix und L die Laplace-Matrix von G. Wie FOS konvergiert das FOS/C-Verfahren ebenfalls, sogar unabhängig vom (aus anderen Gründen) oben gewählten initialen Lastvektor. Allerdings erreicht es dabei im Unterschied zu FOS wie gewünscht keinen balancierten Zustand. Theorem 5.16. Sei G = (V, E) ein zusammenhängender, schlichter und ungerichteter Graph. Das FOS/C-Verfahren konvergiert auf G für jeden initialen Vektor w(0) . Betrachten wir die beiden ersten Iterationen: w(1) = M w(0) + d w(2) = M w(1) + d = M 2 w(0) + M d + d = M 2 w(0) + M (I + d). Wenn wir dies iterativ fortführen, so ergibt sich w(k) = M w(0) + (M k−1 + . . . + M + I)d und somit durch die geometrische Reihe für Matrizen w(∞) = M ∞ w(0) + (I − M )† d = w̄ + (αL)† d. Im obigen Beweis ist L† die Pseudoinverse der Laplace-Matrix und w̄ der stationäre Zustand, also der balancierte Lastvektor, von FOS. Wäre L regulär, könnte man dort die echte Inverse einsetzen. Statt mit der oben dargestellten und im Beweis genutzten Form der Iteration kann der stationäre Zustand w(∞) folglich auch durch das Lösen eines linearen Gleichungssystems Lw = d mit w = αw(∞) bestimmt werden. Löser für lineare Gleichungssysteme wie CG (konjugierte Gradienten) konvergieren meist deutlich schneller als das iterative FOS/C-Verfahren. Letzteres ist daher eher als Mittel zum Verständnis und zur Analyse zu sehen, nicht als Basis einer effizienten Implementierung von FOS/C. 5.3.3. Bubble-FOS/C Wir werden nun das FOS/C-Verfahren mit dem Bubble-Framework verbinden, um mit dieser Kombination namens Bubble-FOS/C Graphen zu partitionieren. Wir betrachten zunächst, wie wir die einzelnen Methoden des Bubble-Frameworks mit Hilfe von FOS/C-Prozeduren implementieren. Unter einer FOS/C-Prozedur verstehen wir dabei den Lösungsvektor w im stationären Zustand eines konkreten FOS/C-Systems mit einer bestimmten Quellmenge S. Dabei sei C[i] das Zentrum von Block i. Wir führen zusätzlich zu AssignPartition und ComputeCenters die optionale Methode Consolidation ein, die in gewisser Weise die beiden vorigen Methoden kombiniert und oft zu einer besseren Balancierung und einer höheren Qualität der Partitionierung führt. 1. DetermineInitialCenters: Wir wählen k verschiedene, beliebige Knoten v1 , . . . , vk aus und setzen C[i] ← vi für 5.3. Balancierung abhängiger Lasten mittels Graphpartitionierung 71 i = 1, . . . , k. Alternativ kann auch ein anderes Verfahren gewählt werden, das k verschiedene Zentren bestimmt. Man kann bspw. nur ein Zentrum zufällig wählen und die übrigen Zentren möglichst weit weg von den bisherigen Zentren wählen. „Möglichst weit weg” gilt dabei in Bezug auf das Ähnlichkeitsmaß FOS/C. 2. AssignPartition: Zur Zuweisung eines Knotens an das nächstgelegene Zentrum lösen wir k FOS/C-Prozeduren. Die Quellmenge für Verfahren i ist dabei {C[i]}. Ein Knoten wird dem Zentrum zugeordnet, dessen System die meiste Last sendet. Algorithmisch wird dabei ausgeführt: • Löse das Gleichungssystem Lwi = di für i = 1, . . . , k • Π(v) ← argmaxi wi (v) 3. ComputeCenters: Die Berechnung neuer Zentren aus der bisheriger Partitionierung wird ebenfalls durch Lösen von k FOS/C-Prozeduren erreicht. Dabei ist die Quellmenge für Verfahren i der gesamte Block i. Neues Zentrum des Blocks i wird der Knoten mit höchster Last in System i. Algorithmisch bedeutet dies: • Löse das Gleichungssystem Lwi = di für i = 1, . . . , k. (nun andere Abflussvektoren!) • C[i] ← argmaxv wi (v) 4. Consolidation (optional): Diese Prozedur wird verwendet, um aus einer bestehenden Partitonierung eine neue zu berechnen. Dazu werden erneut k FOS/C-Verfahren berechnet. Die Quellmenge in System i ist der gesamte Block i. Ein Knoten wird zu dem Zentrum hinzugefügt, dessen Partition die meiste Last sendet. Diese Prozedur ist somit ein Mischung aus den Prozeduren AssignPartition und ComputeCenters. Um die Balancierung weiter zu verbessern, können zusätzliche Balancierungsschritte eingeführt werden. Beim ScaleBalance wird Last aus Systemen mit zu großen Partitionen entfernt und im Gegenzug Last zu Systemen mit zu kleinen Partitionen hinzugefügt. Dabei wird ein passender Skalierungsfakor βi berechnet, der die Menge der Last im System geeignet skaliert. Eine andere Möglichkeit ist FlowBalance. Hierbei wird mittels Diffusion ein balancierender Fluss bestimmt, der berechnet, wie viele Knoten von Block i nach Block j (1 ≤ i 6= j ≤ k) müssen, um die Balancebedingung einzuhalten. Unklar ist hingegen zunächst weiterhin, welche Knoten dies genau sind. Hierfür können jedoch die Lasten aus der Prozedur AssignPartition benutzt werden. Letzlich werden diejenigen Knoten verschoben, die die höchste Affinität zum Zielblock besitzen. Nachfolgend ist der Algorithmus Bubble-FOS/C dargestellt, der die oben beschriebenen Methoden benutzt. Passend dazu kann Konsolidierung oder Balancierung eingebaut werden. Dabei wird die Konsolodierung üblicherweise als letzte Methode in der Schleife integriert, die Balancierungs-Methoden noch dahinter in der Schleife oder – um Zeit zu sparen – nur hinter der Schleife. 5.3.4. Theoretische Ergebnisse zu Bubble-FOS/C In diesem Abschnitt zeigen wir zunächst, dass Bubble-FOS/C auf zusammenhängenden ungerichteten Graphen konvergiert. Der Beweis basiert auf Lastsymmetrie und einer Potentialfunktion, die es erlaubt, die Lösung des Algorithmus zu charakterisieren. Mit Hilfe dieser Charakterisierung können wir dann zeigen, dass Bubble-FOS/C den Kantenschnitt auf relaxierte Weise global optimiert. 72 5. Lastbalancierung paralleler Berechnungen Algorithmus 25 : Bubble-FOS/C Input : Graph G, Zahl der Partitionen k Output : Partitionierung Π 1 C ← DetermineInitialCenters(G, k) 2 Π ← AssignP artition(G, C, k) 3 for τ = 1 until convergence 4 C ← ComputeCenters(G, Π, k) 5 Π ← AssignP artition(G, C, k) 6 return Π Definition 5.17. Die Potentialfunktion F (Π, Z, τ ) zum Zeitpunkt τ ist wie folgt definiert: F (Π, Z, τ ) := k X X [w]zvc (τ ) , c=1 v∈πc (τ ) wobei πc (τ ) die c-te Partition und zc (τ ) das Zentrum der Partition in Iteration π ist. Wir wollen nun F maximieren. Es ist offensichtlich, dass F eine endliche obere Schranke besitzt, wenn der Graph endlich ist. Daher genügt es zeigen, dass die Operationen AssignPartition und ComputeCenters den Wert von F bezüglich der Eingabe maximieren. Für die Operation AssignPartition ist dies leicht einzusehen, da die Knoten jeweils der Partition zugeteilt werden, die die meiste Last sendet. Für ComputeCenters ist dies hingegen nicht offensichtlich, sodass wir zunächst folgendes Resultat beweisen werden: Lemma 5.18. Sei G = (V, E) ein Graph und u, v ∈ V zwei beliebige Knoten. Dann gilt: [w]uv = [w]vu . Beweis. Wir betrachten die FOS/C-Prozedur mit Quelle u. Dann ist der Flussvektor d definiert als d = (−δ, . . . , −δ, δ(n−1), −δ, . . . , −δ)T , wobei δ(n−1) der Eintrag in Zeile u ist. Die Iteration von FOS/C zum Zeitpunkt t + 1 für den Knoten v und Quelle u kann folgendermaßen dargestellt werden: [w(t+1) ]uv = [Mt+1 w(0) ]uv + [(I + M1 + . . . + Mt )d]uv Xt = [Mt+1 w(0) ]uv + nδ Mlv,u − (t + 1)δ. l=0 Wir haben in Abschnitt 5.2.1 gelernt, dass Mt+1 w(0) gegen w = (1, . . . , 1)T , die balancierte Lastverteilung, konvergiert. Dies gilt sogar, wenn die Kanten des Graphen gewichtet sind. Somit erhalten wir: X t [w]vu − [w]uv = nδ Mlu,v − Mlv,u . l=0 Da M und somit auch alle Potenzen von M symmetrisch sind, verschwinden alle Summanden auf der rechten Seite und wir erhalten die Aussage des Lemmas. Obiges Resultat ist in seiner Allgemeinheit überraschend, da man keine Lastsymmetrie in einem beliebigen Graphen ohne Symmetrie vermuten würde. Es ist daher beim gestörten Diffusionsschema FOS/C von besonderem Interesse. In unserem Fall hilft es uns dabei, das nächste wichtige Lemma zu beweisen. 5.3. Balancierung abhängiger Lasten mittels Graphpartitionierung 73 Lemma 5.19. Die Operation ComputeCenters maximiert den Wert der Potentialfunktion F für eine gegebene k-Partitionierung Π. Beweis. Sei Π die aktuelle Partitionierung. ComputeCenters berechnet für jede Partition πc , c ∈ {1, . . . , k}, eine FOS/C-Prozedur mit mehreren Quellen, wobei die gesamte Partition als Quellmenge fungiert. Betrachte die Partition πc und die dazugehörige Multi-Quellen-FOS/C-Prozedur, die w durch Lw = d berechnet. Dabei ist d der zugehörige Flussvektor. Wir wollen P nun diese Prozedur in Teilprozeduren aufteilen, die jeweils Lwi = di , i ∈ πc , berechnen mit i∈πc di = d. Solch eine Aufteilung L(w1 + w2 + · · · + w|πc | ) = d1 + d2 + · · · + d|πc | existiert. Beachten Sie dazu, dass jede Teilprozedur Lwi = di einer FOS/C-Prozedur mit einzelner Quelle entspricht, bei dem der Abflussvektor mit |π1c | skaliert wurde: [di ]v = ( δn δ |πc | − |πc | , − |πδc | , v ∈ πc , v Quelle in Teilverfahren i sonst P Es ist einfach zu zeigen, dass i∈πc di = d und di ⊥ (1, . . . , 1)T gilt, P sodass jede Teilprozedur eine Lösung besitzt. Zusammen mit der Linearität von L erhalten wir i∈πc wi = w. Das neue Zentrum von Partition πc ist nun der Knoten mit der größten Last im System der Multi-QuellenFOS/C-Prozedur. Mit den obigen Überlegungen folgt, dass dies P P der Knoten Pu sein muss, für den [w]u = i∈πc [w]iu maximal ist. Nach Lemma 5.18 gilt dann i∈πc [w]iu = i∈πc [w]ui , sodass das neue Zentrum zc derjenige Knoten u ist, für den die meiste Last in Peiner FOS/C-Prozedur mit einer Quelle in der Partition πc verbleibt. Folglich wird der Beitrag v∈πc [w]zvc für jede Partition πc in F maximiert. Theorem 5.20. Sei w der Lastvektor im stationären Zustand von FOS/C. Dann gehört die größte Last in w zur Quellmenge S. Nachdem k paarweise disjunkte Zentren initial gewählt wurden, existieren stets k verschiedene Zentren und genau k Partitionen während der Ausführung von Bubble-FOS/C. Beweis. Der stationäre Zustand in FOS/C ist äquivalent zu einem `2 -minimalem Fluss-Problem, bei dem die Quellen Last an die verbliebenen Knoten senden und somit eine höhere Last besitzen. Somit ist die erste Aussage klar. Für die zweite Aussage ist die Beziehung "≤" offensichtlich, sodass wir noch zeigen müssen, dass mindestens k verschiedene Zentren und Partitionen in jedem Iterationsschritt existieren. Beim initialen Festlegen der Zentren können wir einfach gewährleisten, dass k verschiedene Knoten ausgewählt werden. In jedem Fall gehören die Zentren, die von ComputeCenters ausgewählt werden, zu einer eigenen Partition und müssen somit verschieden sein. Weiterhin belässt AssignPartition jedes Zentrum in seiner aktuellen Position. Seien nun zi and zj zwei beliebiz ge, aber verschiedene Zentren. Nach Lemma 5.18 wissen wir bereits, dass [w]zji = [w]zzij gilt. Da z [w]zzii > [w]zzij gilt, erhalten wir [w]zzii > [w]zji und damit die gewünschte Aussage. Mit obigen Resultaten folgt nun direkt das Haupttheorem und damit die Konvergenz des Algorithmus. Theorem 5.21. Der Algorithmus Bubble-FOS/C konvergiert und berechnet eine k-Partitionierung. Diese Partitionierung ist lokal optimal bezüglich der Potentialfunktion F . Theorem 5.22. Bubble-FOS/C berechnet relaxierten Kantenschnitt. Der vollständige Beweis zu Theorem 5.22 findet sich im Artikel Beyond Good Partition Shapes: An Analysis of Diffusive Graph Partitioning von Meyerhenke und Sauerwald [MS12]. 74 5. Lastbalancierung paralleler Berechnungen 5.3.5. DibaP Folgt. 5.4. Weiterführende Literatur Folgt. [MMS09b] [MMS09a] 75 6. Ausdünnung von Graphen und Laplace-Löser Eine ganze Reihe von Graphenalgorithmen erwarten als Eingabegraphen einen dünnen1 Graphen. Dies liegt oft daran, dass für dünne Graphen gute Lösungen einfacher zu finden sind. Aus praktischer Sicht sind Software-Werkzeuge meist auf Anwendungsfälle mit dünnen Graphen optimiert, weil diese die üblichen Eingaben aus der Praxis darstellen. Doch was passiert, wenn der Eingabegraph dicht ist? Neben dem Speicherverbrauch steigt normalerweise die Rechenzeit stark an. Noch problematischer ist es allerdings, wenn die eingesetzten Algorithmen und Werkzeuge keine guten Lösungen mehr berechnen, weil sie für dünne Graphen optimiert sind. Wir möchten dann den Graphen geeignet ausdünnen, ohne dass dabei die wesentlichen Informationen des ursprünglichen Graphen verloren gehen. Schematisch ist dies in Abbildung 6.0.1 dargestellt. Abbildung 6.0.1.: Schematische Darstellung zur Ausdünnung eines Graphen. 6.1. Schnitterhaltende Ausdünnung von Graphen Eine Ausdünnung wird nicht in jedem Fall jede Eigenschaft eines Graphen erhalten können. In der Folge beschäftigen wir uns zunächst mit einem Ausdünnungs-Verfahren, das die Gewichte aller Schnitte eines Graphen approximativ erhält – zumindest mit einer gewissen Wahrscheinlichkeit. 6.1.1. Definitionen Die Bestimmung von minimalen Schnitten in einem Graphen besitzt vielfältige Anwendungsszenarien, wie wir bereits bei einigen vorher behandelten Themen angemerkt haben. Zu nennen sind z.B. Clusteranalyse, wissenschaftliches Rechnen oder Bioinformatik. Wir formalisieren die Problemstellung wie folgt: Definition 6.1. Sei G = (V, E, ω) ein ungerichteter Graph mit positiver Kantengewichtsfunktion u : E → R+ . Für S ⊆ V sei δG (S) = e = {u, v} ∈ E | u ∈ S, v ∈ S̄ 1 Die Definition von dünn ist sehr problemabhängig. Häufig versteht man darunter, dass m = O(n) gilt. In diesem Kapitel bezeichnen wir aber auch Graphen mit m = O(n · polylog(n)) als dünn. 76 6. Ausdünnung von Graphen und Laplace-Löser e Abbildung 6.1.1.: Beispiel für einen ungewichteten Graphen, bei dem Random Sampling kein geeignetes Ausdünnungsverfahren ist. der durch S induzierte Schnitt und w(δG (S)) = X w(e) e∈δG (S) das Gewicht des durch S induzierten Schnitts in G. Definition 6.2. Sei G = (V, E, wG ) ein Graph mit positiver Kantengewichtsfunktion wG : E → R+ . Als Ausdünnung von G mit approximativer Schnitterhaltung bezeichnen wir einen Graphen H = (V, F, wH ) mit F ⊂ E und |F | |E| sowie Gewichtsfunktion wH : F → R+ , falls wH (δH (S)) = (1 ± ) ωG (δG (S)) für alle S ⊆ V gilt. Also bleibt nach dieser Art der Ausdünnung der Wert eines Schnitts δ(S) in G auch in H approximativ erhalten. Einen ausgedünnten Graphen H = (V, F, wH ) können wir alternativ auch durch eine nicht-negative Gewichtsfunktion wH : E → R≥0 beschreiben, indem genau die Kanten entfernt werden, für die das Gewicht 0 ist. Den Graphen H, der durch Ausdünnung eines Graphen G entstanden ist, werden wir nachfolgend auch als H = S(G) schreiben. Ist ein (exakter) Algorithmus A auf G zu langsam, der Ausdünnungsalgorithmus S aber deutlich schneller, so bietet es sich an, den Algorithmus A auf den ausgedünnten Graphen S(G) anzuwenden. Wir erhalten somit einen Approximationsalgorithmus A(S(G)). (Die Approximationseigenschaft setzt natürlich voraus, dass A keine wesentlichen Informationen außer den Schnittgewichten verwendet.) Wir erarbeiten nun, wie sich die Ausdünnung S(G) berechnen lässt. 6.1.2. Der Sampling-Prozess Ein erster Ansatz wäre es, jeder Kante e ∈ E mit der gleichen Wahrscheinlichkeit (random sampling) zu entfernen und dies so lange zu betreiben, bis die Anzahl der verbliebenen Kanten klein genug ist. Dies führt jedoch schnell dazu, dass die wesentliche Struktur eines Graphen verloren geht, wie Abbildung 6.1.1 zeigt. Entfernen wir hier die Kante e, so zerfällt der Graph in zwei Komponenten. Wir müssen somit die Wichtigkeit einer Kante bezüglich Schnittbildung definieren und dürfen wichtige Kanten nicht einfach entfernen. Definition 6.3. Sei G = (V, E, w) ein Graph. Die Konnektivität ke einer Kante e ∈ E ist das minimale Gewichts eines Schnitts S ⊂ V, der e enthält, d. h. es gilt ke = min S⊂V,e∈δG (S) w(δG (S)). Mit dem Max-Flow-Min-Cut-Theorem folgt direkt, dass ke der Wert eines maximalen Flusses in einem geeigneten Flussproblem ist. Für e = {u, v} wählen wir hierfür als Quelle s = u, 6.1. Schnitterhaltende Ausdünnung von Graphen 77 als Senke t = v und ersetzen die ungerichteten Kanten durch jeweils zwei gerichtete Kanten mit Kapazität we . Somit kann ke für jede Kante e effizient berechnet werden. Kanten mit großer Konnektivität kommen in Schnitten mit vielen anderen Kanten vor, so dass diese weniger wichtig sind. In unserem Beispiel hat die Kante e eine Konnektivität von 1 und ist somit wichtiger als die restlichen Kanten. Nachfolgend betrachten wir zur einfacheren Darstellung den Fall, dass alle Kanten e ∈ E Gewicht 1 besitzen, d. h. es gilt w(F ) = |F | für F ⊆ E. Der allgemeine Fall lässt sich durch analoge Überlegungen nachvollziehen. Aufbauend auf der Definition der Kantenkonnektivität, erhalten wir den folgenden Algorithmus: Algorithmus 26 : Iteratives randomisiertes Sampling Input : Ungewichteter Graph G = (V, E), Anzahl der Runden ρ Output : Ausgedünnter Graph H = (V, F, w) 1 w ←0 2 foreach e ∈ E do 3 Berechne ke 4 5 6 for i = 1 to ρ do foreach e ∈ E do Mit Wahrscheinlichkeit 1/ke , erhöhe we um ke /ρ Ein Vorteil des vorgestellten Sampling-Prozesses ist, dass die Kantengewichte im Erwartungswert erhalten bleiben: Lemma 6.4. Für jede Kanten e ∈ E gilt: E [we ] = 1. Beweis. Der erwartete Zuwachs für we in Iteration i beträgt (1/ke ) · (ke /ρ) = 1/ρ. Da der Erwartungswert linear ist und insgesamt ρ Iterationen durchgeführt werden, gilt somit: E(we ) = ρ · 1 = 1. ρ Algorithmus 26 ist somit erwartungstreu hinsichtlich der Kantengewichte. Durch die Linearität des Erwartungswerts ergibt sich somit auch direkt das nachfolgende Resultat: Lemma 6.5. Sei F ⊆ E. Dann gilt: E [w(F )] = |F |. Das Gewicht eines Schnittes bleibt somit ebenfalls im Erwartungswert erhalten. Allerdings ist dieses Resultat noch zu schwach für unsere Zwecke. Wir möchten vielmehr, dass mit hoher Wahrscheinlichkeit das Gewicht eines Schnittes erhalten bleibt, d. h. dass w(F ) mit hoher Wahrscheinlichkeit nahe bei |F | = E [w(F )] liegt. Anders ausgedrückt, muss eine Konzentration von w(F ) um seinen Erwartungswert vorliegen. 6.1.3. Konzentration um den Erwartungswert Zunächst erinnern wir an die Chernov-Schranken aus der Wahrscheinlichkeitstheorie: Theorem 6.6. (Chernov-Schranken) Seien X1 , . . . , Xn Zufallsvariablen von n unabhängigen Bernoulli-Experimenten mit Erfolgswahrscheinlichkeit p, d. h. Xi ∼ Bin(1, p). Dann gilt: P • E [Anzahl der Erfolge] = E [ ni=1 Xi ] = pn 78 6. Ausdünnung von Graphen und Laplace-Löser • Für jedes δ > 0 gilt: Pr " n X i=1 • Für δ ∈ [0, 1] gilt: Pr # Xi ≥ (1 + δ) · pn ≤ exp − " n X i=1 # n 2o min δ, δ 3 δ2 Xi ≤ (1 − δ) · pn ≤ exp − pn 2 pn Betrachten wir einen beliebigen Schnitt δ(S) in G. Sei Xi,e die Bernoulli-Zufallsvariable, die angibt, ob Kante e in Iteration i ausgewählt wurde, i = 1, . . . , ρ und e ∈ δ(S). Dann ist das Gewicht w(δ(S)) des Schnitts δ(S) im Ausgabegraphen H gegeben durch die Zufallsvariable X mit ρ X X ke · Xi,e . X= ρ i=1 e∈δ(S) Da die Zufallsvariablen Xi,e unabhängig sind, können wir die Chernov-Schranken anwenden, um eine Konzentration von X um den Erwartungswert E [X] zu beweisen. Allerdings müssen für eine beidseitige Abschätzung die Zufallsvariablen (ke /ρ)·Xi,e in [0, 1] liegen. Da die Koeffizienten ke sehr groß und, was entscheidend ist, sehr unterschiedlich werden können, ist eine direkte Anwendung nicht möglich. Betrachten wir dazu das nachfolgende Beispiel: P Beispiel 6.7. Sei X = ni=1 n·Xi gegeben, wobei die Xi unabhängige Bernoulli-Zufallsvariablen sind. Obwohl der Koeffizient n groß ist, können P beiden Chernov-Schranken P wir dennoch die anwenden. Die Zufallsvariable X ist gerade n · ni=1 Xi und für ni=1 Xi sind die Koeffizienten jeweils 1. P Betrachten wir hingegen die Zufallsvariable Y = n·Y0 + ni=1 Yi und Y0 , . . . , Yn seien BernoulliZufallsvariablen mit Trefferwahrscheinlichkeit p = n1 . Dann ist E(Y ) = 2 und P r(Y ≥ n) ≥ n1 . Die Chernov-Schranken können folglich nicht angewendet werden. Um eine Konzentration dennoch zeigen zu können, werden einteilen, wir die Kanten in Gruppen deren Konnektivität ungefähr gleich ist. Sei dazu Ei = e ∈ E | 2i−1 ≤ ke < 2i , wodurch wir eine Partition E = E1 ∪ E2 ∪ . . . ∪ Elog(n) der Kantenmenge erhalten. Anstatt eine Konzentration von w(δ(S)) um E [w(δ(S))] direkt zu bestimmen, werden wir die Chernov-Schranken jeweils auf w(δ(S) ∩ Ei ) anwenden. Für e ∈ δ(S) ∩ Ei sind nach Konstruktion die Koeffizienten kρe ungefähr gleich. Eine Kantenmenge F der Form F = δ(S) ∩ Ei nennen wir nachfolgend eine schnittinduzierte Menge. Es könnte allerdings eine Knotenmenge S 0 ⊂ V geben mit F = δ(S) ∩ Ei = δ(S 0 ) ∩ Ei . Wir betrachten daher jeweils den Schnitt mit kleinster Kardinalität, da der Stichprobenfehler w(F ) klein gegenüber |δ(S)| sein soll und dies am schwierigsten ist, wenn |δ(S)| kleinstmöglich gewählt wird. Wir definieren weiterhin: q(F ) = min {|δ(S)| | S ⊂ V, δ(S) ∩ Ei = F }. Mit Hilfe der Chernov-Schranken erhalten wir dann das nachfolgende Lemma für die Menge F : Lemma 6.8. Sei F ⊆ Ei eine schnittinduzierte Menge. Dann gilt für > 0: · q(F ) 2 ρ · q(F ) P r |w(F ) − E [w(F )] | > ≤ 2 exp − . log n 3 · 2i log2 n Der Beweis dieses Lemmas bleibt dem Leser als Selbstübung durch Anwendung der ChernovSchranke überlassen. 6.1. Schnitterhaltende Ausdünnung von Graphen 79 6.1.4. Das Hauptresultat Wir möchten nun das Haupttheorem dieses Abschnitts beweisen, nämlich dass Algorithmus 26 tatsächlich eine approximativ schnitterhaltende Ausdünnung des Eingabegraphen berechnet: Theorem 6.9. Sei G = (V, E) ein ungerichteter Graph mit n Knoten. Dann produziert Algorithmus 26 mit Wahrscheinlichkeit ≥ 21 eine Gewichtsfunktion w : E → R≥0 , die den Wert aller Schnitte in G approximativ, d. h. bis auf den Faktor 1 ± , erhält und nur O(n log3 (n) /2 ) Nichtnulleinträge erzeugt. Durch eine weitergehende, kompliziertere Analyse lässt sich der Faktor log3 (n) auf log2 (n) reduzieren bzw. durch eine andere Herangehensweise sogar ganz eliminieren. Nachfolgend beschränken wir uns jedoch auf das oben genannte Resultat. Anzahl der Nichtnulleinträge. Die Anzahl der Nichtnulleinträge von w ist leicht zu analysieren. Wir setzen zunächst ρ = 100 log3 (n/2 ). Sei Xi,e erneut die Indikator-Zufallsvariable, die angibt, ob die Kante e in Iteration i ausgewählt Pρ Pwurde. Dann ist E [Xi,e ] = 1/ke . Die Anzahl der Nichtnulleinträge in w ist höchstens i=1 e∈E Xi,e und somit gilt E [Anzahl Nichtnulleinträge] = ρ X 1 = O(n log3 (n)/2 ), ke e∈E P da e∈E 1/ke ≤ n − 1 für jeden Graphen mit |V | = n gilt. Wir erinnern an die MarkovUngleichung aus der Wahrscheinlichkeitstheorie: Lemma 6.10. Sei X eine Zufallsvariable mit Werten in [0, ∞]. Dann gilt für beliebiges r > 0 die Abschätzung: 1 P r (X ≥ r · E [X]) ≤ . r Mit der Markov-Ungleichung folgt für r = 4 direkt, dass die Anzahl Nichtnulleinträge mit Wahrscheinlichkeit ≥ 3/4 kleiner als 4 O(n log3 (n)/2 ) ist. Konzentration um den Erwartungswert. Für den Beweis der Konzentration um den Erwartungswert, werden wir zeigen, dass für jede schnittinduzierte Menge F mit hoher Wahrscheinlichkeit q(F ) |w(F ) − |F || ≤ (6.1.1) log(n) gilt. Dann erhalten wir für jeden Schnitt C = δ(S) die folgenden Beziehungen: |w(C) − |C|| ≤ ≤ ≤ log Xn i=1 log Xn i=1 log Xn i=1 |w(C ∩ Ei ) − |C ∩ Ei || q(C ∩ Ei ) log n |C| = |C|. log n Dabei gilt die erste Ungleichung nach der Dreieckunsgleichung, die zweite folgt aus Formel 6.1.1 und die dritte Ungleichung aus der Tatsache, dass q(C∩Ei ) das Gewicht des kleinsten Schnitts ist, der C ∩ Ei induziert. Es gilt daher die gewünschte Eigenschaft, dass das Gewicht eines Schnittes 80 6. Ausdünnung von Graphen und Laplace-Löser durch die Ausdünnung approximativ erhalten bleibt. Es bleibt somit zu zeigen, dass Formel 6.1.1 tatsächlich gilt. Sei nachfolgend i ∈ {1, . . . , log n} fest. Seien ferner F 1 , F 2 , . . . die durch Ei schnittinduzierten Mengen. Ordne diese derart, dass q(F 1 ) ≤ q(F 2 ) ≤ . . . gilt. Ferner definieren wir pj durch 2 ρ · q(F j ) q(F j ) j j ≤ 2 exp − , pj := P r |w(F ) − E w(F ) | > log n 3 · 2i log2 (n) (6.1.2) wobei die Ungleichung nach Lemma 6.8 gilt. S P Mit der Bonferroni-Ungleichung (engl. „union bound”) P r ( i Ai ) ≤ i P r(Ai ) für Ereignisse Ai und der Definition der pj erhalten wir X P r(schnittinduzierte Teilmenge F ⊂ Ei erfüllt nicht 6.1.1) ≤ pj . j Wir können nun jedoch nicht direkt Lemma 6.8 anwenden, da es exponentiell viele Mengen F j geben kann. 2 Betrachten wir zunächst nur die ersten n2 schnittinduzierten Mengen F 1 , . . . , F n . Da jede Kante e ∈ F j auch zu Ei gehört, gilt folglich ke ≥ 2i−1 . Somit hat jeder Schnitt, der die Kante e enthält, mindestens Größe 2i−1 und damit q(F j ) ≥ 2i−1 . Setzen wir dies nun in Ungleichung 6.1.2 ein, so ergibt sich für unser gewähltes ρ = 100 log3 (n)/2 : 2 (100 log3 (n)/2 ) 2i−1 pj ≤ 2 exp − ≤ 2 exp (−16 log n) ≤ 2n−16 . 3 · 2i log2 (n) Es gilt also: Hilfslemma: Pn2 j=1 pj ≤ 2n−14 . Für die restlichen F j mit j > n2 benötigen wir das nachfolgende Lemma 6.11. Sei G = (V, E) ein Graph. Sei fener B ⊂ E und K ≤ min {ke | e ∈ B}. Dann gilt für jede reelle Zahl α > 1: | {δ(S) ∩ B : S ⊆ V ∧ |δ(S)| ≤ α · K} | < n2α . Anders ausgedrückt ist die Anzahl der Schnittmengen eines Schnitts δ(S), dessen Größe durch α·K beschränkt ist, mit einer beliebigen Kantenteilmenge B kleiner als n2α . Setzen wir in diesem Lemma B = Ei und K = 2i−1 , dann gilt für jedes α ≥ 1: | schnittiniduzierte Menge F ⊆ Ei mit q(F ) ≤ α · 2i−1 | < n2α . Also ist für α ≥ 1 die Anzahl der F j mit q(F j ) ≤ α · 2i−1 kleiner als n2α . Setzen wir nun α = ln j/(2 ln n) in Ungleichung 6.1.2 ein, so ergibt sich: 2 (100 log3 (n)/2 ) ln(j) 2i−1 pj ≤ 2 exp − < j −8 . 6 · 2i log2 (n) ln(n) Durch Summation über j > n2 erhalten wir nun −7 ∞ ˆ ∞ X X j −8 −8 pj < j ≤ j dj = − < n−14 . 7 2 2 n j=n 2 2 j>n j>n 6.2. Spektrale Approximation 81 Insgesamt ergibt sich also: X 2 pj = j n X j=1 pj + X pj < 2n−14 + n−14 < n−2 . j>n2 Wenn wir jetzt die Bonferroni-Ungleichung auf alle E1 , . . . , Elog n anwenden, dann erhalten wir P r(schnittinduzierte Teilmenge F erfüllt nicht 6.1.1) ≤ ≤ < log Xn P r(schnittinduzierte Teilmenge F ⊂ Ei erfüllt nicht 6.1.1) i=1 log Xn X i=1 log Xn i=1 pj j n−2 < 1 . n Die Ungleichung 6.1.1 gilt somit mit Wahrscheinlichkeit ≥ 1 − 1/n und damit ist auch unser Haupttheorem bewiesen. 6.2. Spektrale Approximation 6.2.1. Definitionen In diesem Abschnitt möchten wir ein Ausdünnungsverfahren kennenlernen, bei dem der ausgedünnte Graph H eine spektrale Approximation des Eingabegraphen G darstellt. Formalisieren lässt sich dies wie folgt: Definition 6.12. Sei G = (V, E, wG ) ein Graph mit positiver Kantengewichtsfunktion w : E → R+ und Laplace-Matrix LG . Als (1 + )-spektrale Ausdünnung von G bezeichnen wir einen Graphen H = (V, F, wH ) mit F ⊂ E, |F | |E| und Laplace-Matrix LH und Gewichtsfunktion wH : F → R+ , falls 1 T x LG x ≤ xT LH x ≤ (1 + )xT LG x 1+ für alle x ∈ Rn gilt. Beachten Sie, dass eine spektrale Ausdünnung automatisch auch eine Ausdünnung mit approximativer Schnitterhaltung ist. Die Umkehrung gilt im allgemeinen Fall nicht. Beide Aussagen werden dem Leser als einfache Übungsaufgabe empfohlen. Spektrale Approximation findet in verschiedenen Approximationsalgorithmen für Graphenprobleme Verwendung, z. B. zur Partitionierung oder zur Berechnung maximaler Flüsse. Es ist möglich, eine spektrale Ausdünnung H mit O(n/) Kanten in Laufzeit O(m) zu berechnen. In diesem Abschnitt begnügen wir uns jedoch mit einem etwas schwächeren Resultat, das das Haupttheorem dieses Abschnitts bildet. Theorem 6.13. Sei G = (V, E) ein Graph mit |V | = n und |E| = m. Ferner sei > 0. Dann existiert ein randomisierter Algorithmus, der mit Wahrscheinlichkeit ≥ 1 − 1/n eine spektrale Approximation von G mit O(n log(n)/2 ) Nichtnulleinträgen berechnet. Bevor wir einen Algorithmus angeben können, der das obige Theorem erfüllt, benötigen wir noch einige Einsichten, wie Graphen und elektrische Netzwerke zusammenhängen. 82 6. Ausdünnung von Graphen und Laplace-Löser Abbildung 6.2.1.: Beispiel für ein elektrisches Netzwerk. 6.2.2. Graphen und elektrische Netzwerke Sei G = (V, E) ein gerichteter Graph mit Gewichtsfunktion w. Wir können G wie folgt als elektrisches Netzwerk auffassen: • Jeder Kante e ∈ E ordnen wir einen Widerstand re = 1/we zu. • Jeder Knoten i ist eine Stromquelle, die dem System di Ampere Strom zuführt. • Einer der Knoten ist geerdet und über ihn verlässt Strom das System (für diesen Knoten ist di somit negativ). • Jeder Knoten besitzt ein Potential zi , mit dem der Stromfluss auf der Kante e = (i, j) genau (zi − zj )wij beträgt. Beispielhaft ist ein solches elektrisches Netzwerk in Abbildung 6.2.1 dargestellt. Der Potentialvektor z lässt sich durch Lösen des linearen Gleichungssystem Lz = d berechnen, wobei L die Laplace-Matrix von G und d = (d1 , . . . , dn ) der Vektor ist, der die Stromzu- und abflüsse (ins bzw. aus dem System) darstellt. Nach dem Kirchhoffschen Potentialgesetz ist für jeden Zyklus im Graphen G die Summe der Stromflüsse auf den Kanten des Zyklus gerade 0. Ferner heben sich die Zu- und Abflüsse auf einem Knoten nach dem Kirchhoffschen Flussgesetz auf, wenn man den Zu- und Abfluss aus dem Stromnetzwerk mit berücksichtigt. Dies ist ein Analogon zur Lastbalancierung mit Diffusion, die wir im letzten Kapitel erarbeitet hatten. Hier gibt ein Knoten, der zu viel Last hat, diesen Zufluss komplett ins Netzwerk ab. Der Abfluss aus dem Netzwerk am Knoten kommt in einen Knoten vom restlichen Netzwerk, der zu wenig Last hat. Für das weitere Kapitel ist die Größe des effektiven Widerstands einer Kante eine zentrale Größe, die wir effizient berechnen möchten. Diese werden wir für den randomisierten Algorithmus zur spektralen Approximation benötigen. Definition 6.14. Sei G = (V, E) ein gerichteter Graph und e = (u, v) ∈ E eine Kante. Sei z der Potentialvektor des Gleichungsysteme Lz = d, wobei der Stromflussvekor d gegeben ist durch: falls x = u 1, dx = −1, falls x = v 0 sonst Dann ist der effektive Widerstand Re der Kante e = (u, v) definiert durch R(u,v) = (zu −zv )w(u,v) . 6.2. Spektrale Approximation 83 Das Stromflussproblem in obiger Definition entspricht der Lösung von zwei FOS/C-Prozeduren, wobei u das Zentrum der ersten Prozedur und v das Zentrum der zweiten Prozedur ist. Seien d1 der Vektor, der an der Stelle u den Wert 1 hat und sonst nur aus 0 besteht, und d2 der Vektor, der an der Stelle v den Wert 1 hat und ansonsten nur 0. Dann entspricht die erste Prozedur dem Gleichungssystem Lz1 = d1 und die zweite dem Gleichungssystem Lz2 = d2 . Es gilt somit d = d1 − d2 und der in obiger Definition gesuchte Potentialvektor ergibt sich durch z = z1 − z2 . Der effektive Widerstand Re entspricht folglich einer Potentialdifferenz in z, so dass eine hohe Potentialdifferenz für einen „Flaschenhals” im System spricht. Wir möchten nun erarbeiten, wie wir den effektiven Widerstand alternativ berechnen können. Sei hierfür B ∈ {−1, 0, 1}m×n die Knoten-Kanten-Inzidenzmatrix 2 , d. h. es gilt falls v Endknoten von e 1, Be,v = −1, falls v Startknoten von e 0, sonst Für e = (u, v) kann der effektive Widerstand Re berechnet werden durch Re = (eu − ev )T L† (eu − ev ), wobei L† die Pseudo-Inverse der Laplace-Matrix und ei der i-te Einheitsvektor ist. Setzen wir nun Π := BL† B T , dann gilt somit Re = Πe,e , da (eu − ev )T gerade die Zeile von Π ist, die zur Kante e = (u, v) gehört. Die Matrix Π hat dabei einige interessante Eigenschaften, die wir (ohne Beweis) im nächsten Lemma zusammenstellen: Lemma 6.15. Sei Π = BL† B T . Dann gilt: 1. Π ist symmetrisch. 2. Π2 = Π 3. Die Eigenwerte von Π sind 0 oder 1. 4. P r (e ist Kante in zufälligem Spannbaum) = Re . 6.2.3. Algorithmus und Beweis des Haupttheorems Mit den erarbeiteten Definition des effektiven Widerstands Re einer Kante e können wir nun einen iterativen Algorithmus zur Berechnung der spektralen Approximation angeben (Algorithmus 27). Beachten Sie dabei, dass die Summe über alle Re genau n − 1 ist. Der Algorithmus erinnert vom Aufbau an den Algorithmus aus dem letzten Abschnitt über schnitterhaltende Ausdünnung. Da wir die effektiven Widerstände Re über die Matrix Π berechnen möchten, benötigen wir für den Beweis des Haupttheorems noch eine „Chernov-Schranke für Matrizen”: Theorem 6.16. Sei > 0 hinreichend klein und M ∈ Rm×m eine zufällige, symmetrische, positiv semidefinite Matrix mit E [M ] = Im . Seien ferner ρ := supM ||M || und M1 , . . . , MS stochastisch unabhänige Kopien von M . Dann gilt: " # S 1X S2 P r || Mi − Im || > ≤ 2m · exp − S 2ρ i=1 2 Beachten Sie, dass wir auf den Folien zu Kapitel 3 die Matrix B als B T (und umgekehrt) definiert hatten. Die Definition im Skript ist allerdings konsistent. 84 6. Ausdünnung von Graphen und Laplace-Löser Algorithmus 27 : Iteratives randomisiertes Sampling Input : Graph G = (V, E), Anzahl der Runden ρ Output : (1 + )-spektrale Approximation von G 1 w ←0 2 foreach e ∈ E do 3 Berechne Re 4 5 6 for i = 1 to ρ do foreach e ∈ E do Mit Wahrscheinlichkeit Re /(n − 1), erhöhe we um Re /ρ Mit den getätigten Vorarbeiten können wir nun Theorem 6.13 beweisen: Beweis. (Prüfungsrelevant ist die Beweisstruktur, die konkreten Inhalte der Formeln sind es nicht. Sie sollten aber das grundsätzliche Vorgehen und die dabei beteiligen Matrizen sowie deren Zweck und Aufbau kennen.) Sei G = (V, E) der Graph, für den eine spektrale Approximation berechnet werden soll. Wir wählen eine Orientierung für jede Kante e ∈ E und B sei die dazugehörige Knoten-KantenInzidenzmatrix. Weiter sei Π = BL† B T wie im vorherigen Abschnitt und Πe die Spalte von Π, die zur Kante e gehört. Sei Y eine Zufallsvariable mit P r (Y = e) = pe , wobei pe = Re /(n − 1) die Wahrscheinlichkeit √ aus Algorithmus 27 ist. Setze ve = Πe / pe und sei vY der durch Y induzierte Zufallsvektor, d. h. P r (vY = ve ) = pe . Wir definieren weiter eine Zufallsmatrix M = vY vYT ; ferner seien Mi = vYi vYTi stochastisch unabhänige Kopien von M , für i = 1, . . . , S. Dann gilt für die Matrix M : E[M ] = E[ve veT ] = X Πe ΠTe = Π e∈E Nach Lemma 6.15, Eigenschaften 1 P bis 3, ist die Matrix Π eine Projektionsmatrix und somit äquivalent zu einer Diagonalmatrix dj=1 ej eTj für ein d ≤ m, hierbei ist d die Vielfachheit des P Eigenwerts 1. Die „Chernov-Schranken für Matrizen” gelten ebenfalls, wenn E [M ] = dj=1 ej eTj für zu einer Diagonalmatrix der Form Pd ein d T≤ m gilt und sogar auch, wenn E [M ] äquivalent 2 j=1 ej ej mit d ≤ m ist. Da außerdem Re = ||Πe || gilt, folgt direkt ||ve ||2 = ||Πe ||2 Re = =n−1 pe pe und somit ||Mi || ≤ n − 1 für alle i. Wir können daher die Chernov-Schranke für Matrizen aus Theorem 6.16 anwenden. Wir erhalten die Abschätzung S2 , (6.2.1) P r(||Π̃ − Π|| > ) ≤ 2(n − 1) · exp − 2(n − 1) P P wobei die Matrix Π̃ durch Π̃ = S1 Si=1 Mi = S1 Si=1 vYi vYTi gegeben ist. Setzen wir S als Ω(n logn/2 ), so erhalten wir eine Fehlerwahrscheinlichkeit von n−Ω(1) . Wir möchten dieses nun auf die Laplace-Matrix LH des ausgedünnten Graphen H anwenden. Aus Π = BL†G B T folgt für eine Kante e ∈ E BL† be Πe ve = √ = √ G = BL†G ue , pe pe 6.2. Spektrale Approximation 85 √ wobei be die Zeile von B ist, die zur Kante e gehört, und ue = be / pe ist. Damit ergeben sich zusammen mit der Definition der Laplace-Matrix von H LH = S S 1X 1 X bYi bTYi = uYi uTYi S p Yi S i=1 i=1 die Zusammhänge Π̃ = = Π = S S 1X 1X vYi vYTi = BL†G uYi uTYi L†G B T S S i=1 BL†G LH L†G B T BL†G B T BL†G LG L†G B T i=1 Es gilt damit ||Π̃ − Π|| = sup | x6=0 xT BL†G (LH − LG )L†G B T x xT (Π̃ − Π)x | = sup | |. xT x xT x x6=0 Ist z ein Vektor mit Bz = 0, so muss z parallel zum Vektor 1 = (1, . . . , 1)T sein, da der Graph G zusammenhängend ist. Somit gilt für z 6= 0, dass aus hz, 1i = 0 direkt Bz 6= 0 folgt. Wir können somit in der obigen Gleichung den Vektor y durch Bz substituieren. Da für solch einen Vektor z die Eigenschaft LG L†G z = z gilt, erhalten wir: ||Π̃ − Π|| ≥ sup z6=0,hz,1i=0 | z T B T BL†G (LH − LG )L†G B T Bz | z T B T Bz z T LG L†G (LH − LG )L†G LG z = sup | | z T LG z z6=0,hz,1i=0 = sup z6=0,hz,1i=0 | z T (LH − LG )z | z T LG z Zusammen mit dem Resultat aus Formel 6.2.1 erhalten wir die gewünschte Eigenschaft ! z T (LH − LG )z sup | | > ≤ P r Pr || Π̃ − Π|| > = n−Ω(1) . z T LG z z6=0,hz,1i=0 Dies entspricht genau der Definition der (1+)-spektralen Approximation und unser Algorithmus berechnet eine solche mit Wahrscheinlichkeit ≥ 1 − 1/n. Der vorgestellte Algorithmus zur spektralen Approximation hat bei effizienter Implementierung eine Laufzeit von O(m log(1/)). Um die effektiven Widerstände Re für die Kanten effizient mittels der Matrix Π = BL† B T berechnen zu können, benötigen wir somit eine effiziente Berechnung der Matrix L† , der Pseudoinversen der Laplace-Matrix. Diese ist jedoch im Allgemeinen eine dichte Matrix! Die Zeitkomplexität entspricht somit einer Inversion einer Matrix und die Raumkomplexität ist O(n2 ). Alternativ zur Inversion kann es daher sinnvoll sein, die Re zu berechnen, indem wir Gleichungssysteme der Form Lz = d lösen. Einen schnellen Löser für solche Gleichungssysteme stellen wir im nächsten Abschnitt vor. 86 6. Ausdünnung von Graphen und Laplace-Löser Eine alternative Herangehensweise besteht darin, die Re durch einen Algorithmus mit konstanter relativer Güte approximieren zu lassen. Dieser soll eine Laufzeit von O(m log r) besitzen mit r = wmax /wmin . Hierbei gilt folgendes Resultat, das wir ohne Beweis benutzen. Theorem 6.17. Sei G = (V, E, w) ein gewichteter Graph und > 0. Dann gibt es einen Algorithmus mit Laufzeit O(m log r/2), der eine Matrix Z der Dimension (24 log(n/2)) × n derart berechnet, dass für jedes Knotenpaar (u, v) mit Wahrscheinlichkeit ≥ 1 − 1/n gilt: (1 − )R(u,v) ≤ ||Z̃(eu − ev )||2 ≤ (1 + )R(u,v) . 6.3. Kombinatorische Löser für Laplace-Systeme 6.3.1. Grundidee In diesem Abschnitt wollen wir erarbeiten, wie man ein Gleichungssystem der Form Lv = d effizient lösen kann, wobei L eine symmetrische, positiv semidefinite Matrix und d ein Vektor ist, dessen Einträge in der Summe 0 ergeben. Dazu stellen wir den kombinatorischen Löser KOSZ von Kelner, Orecchia, Sidford und Zhu vor, der nahezu lineare Laufzeit besitzt. Wir beschränken uns dabei sogar auf Systeme der Form Lv = es − et , wobei ei ein Vektor ist, der an der Stelle i eine 1 enthält und sonst nur aus Nullen besteht. Andere rechte Seiten lassen sich stets darauf reduzieren. Im Abschnitt zu Graphen und elektrischen Netzen haben wir bereits erarbeitet, dass die Lösung des obigen Gleichungssystem einem Potentialvektor in einem elektrischen Netzwerk entspricht. Potentialdifferenzen induzieren dabei einen balancierenden Fluss, der in unserem Fall gesucht ist. Denn der balancierende Fluss ist dual zum Potentialvektor v, der Lösunge des linearen Gleichungssystems. Wir werden daher einen Approximaionsalgorithmus entwickeln, der diesen Fluss berechnet und so auch das entsprechende Gleichungssystem löst. Nach dem Kirchhoffschen Potentialgesetz ist die Summe der Flüsse auf einem Zyklus gerade 0. Wir können daher den folgenden Ansatz wählen: • Starte mit einem zulässigen Fluss f zwischen den Knoten s und t. • Bestimme einen Zyklus C zufällig bezüglich einer gegebenen Wahrscheinlichkeitsverteilung. • Falls erforderlich, passe f auf C so an, dass die Summe des Flusses auf C gleich 0 ist. • Führe weitere Iterationen durch, bis eine Fehlerschranke erreicht ist. Wir werden nun das KOSZ-Verfahren erarbeiten, das diesen Ansatz verfolgt. 6.3.2. Flüsse, Energie und Baumzyklen Sei G = (V, E, w) ein gerichteter Graph mit |V | = n und |E| = m. Ferner setzen wir den Widerstand re = 1/we für jede Kante e ∈ E. Beachten Sie den Unterschied zwischen Widerstand (Kehrwert des Kantengewichts) und dem effektiven Widerstand (Stromfluss auf der Kante). Einen Fluss f auf den Kanten interpretieren wir als Vektor aus Rm . Es gilt dabei für alle e = (a, b) ∈ E, dass die Flussrichtung sich aus dem Vorzeichen ergibt und somit f (a, b) = −f (b, a). Sei B die Kanten-Knoten-Inzidenzmatrix, L die Laplace-Matrix von G und R = (rij ) ∈ Rm×m eine Diagonalmatrix definiert durch ( re , falls i = j = e rij = 0, sonst Dann gelten die folgenden Zusammenhänge: 6.3. Kombinatorische Löser für Laplace-Systeme 87 Lemma 6.18. Sei f ein Fluss, x ∈ Rn , a ∈ V und (a, b) ∈ E. Dann gilt: 1. [B T f ]a = P (b,a)∈E f (b, a) − 2. L = B T R−1 B P (a,b)∈E f (a, b) 3. [Bx](a,b) = xa − xb 4. xT Lx = P (a,b)∈E (xa −xb )2 r(a,b) Falls ein Graph ungewichtet ist, folgt somit aus Unterpunkt 2 die vereinfachte Gleichung L = B T B. Wir benötigen zunächst noch weitere Definitionen für spezielle Flüsse: Definition 6.19. Sei G = (V, E, w) wie oben und B die Kanten-Knoten-Inzidenzmatrix. • Ein Fluss f heißt Zirkulation, falls B T f = 0. • Die Energie Er (f ) eines Flusses f ist definiert als X Er (f ) = re · f (e)2 = f T Rf = ||f ||2R e∈E • Der Fluss fopt heißt elektrischer oder optimaler Fluss bezüglich des Bedarfsvektors d, falls gilt: fopt = argminB T f =d Er (f ) • Ein Fluss f heißt -approximativer elektrischer Fluss bezüglich des Bedarfvektors d, falls B T f = d und Er (f ) ≤ (1 + )Er (fopt ). Für einen Stromfluss f gilt nach dem Abschnitt über elektrische Netzwerke die Beziehung f (i, j) = (vi − vj )wij . Also gilt f (i, j)/wij = vi − vj und folglich fopt = R−1 Bvopt . Mit dem Kirchhoffschen Potentialgesetz können wir somit folgern: Lemma 6.20. Ein Fluss f ist genau dann optimal, wenn f T Rc = 0 für alle Zirkulationen c gilt. Lemma 6.20 werden wir nachfolgend noch vereinfachen und anhand von bestimmten Zyklen formulieren. Sei dazu T ein Spannbaum von G. Wir definieren darauf aufbauend Baumpfade und Baumzyklen: Definition 6.21. Seien a, b ∈ V . Der Baumpfad P(a,b) ist der eindeutige Pfad von a nach b, der nur Kanten von T benutzt. Der dazugehörige Fluss p(a,b) ist derjenige Fluss, der eine Flusseinheit von a nach b sendet und nur auf Kanten aus T von Null verschieden ist (also nur Kanten von T benutzt). Definition 6.22. Sei (a, b) eine Kante, die nicht in T vorkommt. Dann ist der Baumzyklus C(a,b) = (a, b) ∪ P(b,a) der eindeutige Kreis, der aus der Kante (a, b) und dem Baumpfad P(b,a) besteht. Die dazugehörige Zirkulation c(b,a) ist diejenige Zirkulation, die eine Flusseinheit auf C(a,b) sendet. Die Menge aller Zirkulationen c ∈ Rm | B T c = 0 nennen wir Zyklenraum. Eine Basis des Zyklenraums bilden dabei die Zirkulationen {ce | e ∈ E\T }, die durch einen Baumzyklus induziert werden. Wir erhalten somit folgende Charakterisierung. 88 6. Ausdünnung von Graphen und Laplace-Löser Abbildung 6.3.1.: Graph aus Beispiel 6.25. Die Kanten des Spannbaums sind rot gefärbt. Korollar 6.23. Ein Fluss f ist genau dann optimal, wenn f T Rce = 0 für alle von Baumzyklen induzierten Zirkulationen ce gilt. Korollar 6.23 ist zentral für den zu entwickelnden Algorithmus. Wie bereits oben skizziert, werden wir iterativ überprüfen, ob auf gewählten Baumzyklen von G die Summe der Flüsse Null ergibt. Jeden Baumzyklus Ce können wir ferner als „langen Widerstand” ansehen, der aus in Serie geschalteten Einzelwiderständen besteht. Für diesen definieren wir: Definition 6.24. Sei Ce ein Baumzyklus. Der Widerstand Re von Ce ist gegeben durch X Re = re0 = cTe Rce . e0 ∈Ce Das durch einen Fluss f auf Ce induzierte Potential ∆ce (f ) ist definiert als X f (e0 )re0 = f T Rce . ∆ce (f ) = e0 ∈Ce Mit obiger Definition lässt sich die Charaktiersierung eines optimalen Flusses umformulieren zu: Ein Fluss f ist genau dann optimal, wenn ∆ce (f ) = 0 für alle von Baumzyklen induzierten Zirkulationen ce gilt. Beispiel 6.25. Sei G = (V, E) gegeben wie in Abbildung 6.3.1 und die roten Kanten seien die Kanten eines Spannbaums T . Der Fluss f verschickt eine Einheit vom Knoten 1 an den Knoten 4. Es gilt somit f (1, 2) = 1, f (2, 4) = 1 und f (e) = 0 für alle anderen Kanten. Der Einfachhheit halber seien alle Kantengewichte 1, es gilt also re = 1 für alle Kanten e ∈ E. Die Kante (1, 5) ist eine Nichtbaumkanten und es gilt X R(1,5) = re0 = r(1,5) + r(5,4) + r(4,2) + r(2,1) = 4. e0 ∈C(1,5) Analog folgt R(1,6) = 4 und R(3,4) = 3. Berechnen wir nun die induzierten Flusspotentiale: Hier gilt X ∆c(1,5) (f ) = f (e0 )re0 = f (1, 2) · r(1,2) + f (2, 4) · r(2,4) = 2 e0 ∈C(1,5) und durch analoge Rechnung ∆c(1,6) (f ) = 1, sowie ∆c(3,4) (f ) = 1. Der Fluss f ist daher keinesfalls optimal. Im weiteren Verlauf möchten wir nur bestimmte Spannbäume von G betrachten, die niedrige Steckung gemäß der folgenden Definition besitzen. 6.3. Kombinatorische Löser für Laplace-Systeme 89 Definition 6.26. Sei P T ein Spannbaum vom Graphen G. Die Baum-Konditionszahl t(T ) ist definiert als t(T ) = e∈E\T (Re /re ). Die Streckung st(e) einer Kante e ∈ E ist gegeben durch P re0 0 st(e) = e ∈Pe re P und die Streckung st(T ) eines Spannbaums T durch st(T ) = e∈E st(e). Bevor wir nun die algorithmische Idee hinter dem KOSZ-Verfahren weiter untersuchen, benötigen wir eine letzte Definition. Definition 6.27. Sei T ein Spannbaum von G und f ein Fluss in G. Sei s ∈ V beliebig, aber fest. Dann ist die bauminduzierte Spannung v ∈ R|V | für a ∈ V definiert als X v(a) = f (e) · re . e∈P(a,s) Beispiel 6.28. Sei die Situation wie in Beispiel 6.25. Für die Baumkonditionszahl von T gilt mit den bereits berechneten Werten aus Beispiel 6.25: X X t(T ) = (Re /re ) = Re we = 4 + 4 + 3 = 11. e∈E\T e∈E\T Wir berechnen nun die Streckung st(e) einer Kante e ∈ E. Für e = (1, 5) gilt st(1, 5) = (1/r(1,5) ) X re0 = r(1,2) + r(2,4) + r(4,5) = 3. e0 ∈P(1,5) Die anderen Werte können ebenso berechnet werden. Für die Streckung st(T ) des Spannbaums P T ergibt sich dann st(T ) = e∈E st(e) = 13. Sei nun s = 1. Dann gilt für die bauminduzierte Spannung X v(5) = f (e) · re = f(4,2) + f(2,1) = −f(2,4) − f(1,2) = −2. e∈P(5,1) Insgesamt ergibt sich der Vektor v = (0, −1, −1, −2, −2, −1)T . Setzen wir hingegen s = 3, dann gilt v(5) = f(4,2) = −1 und wir erhalten den Vektor v = (1, 0, 0, −1, −1, 0)T . 6.3.3. Der Algorithmus SimpleSolver Unser Ziel wird es nun sein, einen zu dem Gleichungssystem Lv = d gehörenden, (1 + )approximativen elektrischen Fluss zu berechnen. Wir gehen dazu wie folgt vor: 1. Berechne zunächst einen Spannbaum mit niedriger Streckung. 2. Berechne damit einen initialen zulässigen Fluss. 3. Iterative Zyklenaktualisierung: Berechne einen neuen zulässigen Fluss, der die Energie senkt. • Wähle eine Nichtbaumkante e mit Wahrscheinlichkeit Re /re aus. • Überprüfe, ob für den Baumzyklus Ce die Eigenschaft f T Rce = 0 gilt. Falls nein, ändere f entsprechend ab. 90 6. Ausdünnung von Graphen und Laplace-Löser 4. Gebe den Fluss f und die Bauminduzierte Spannung v zurück. Dieser Algorithmus heißt SimpleSolver. Sein Pseudocode ist in Algorithmus 28 dargestellt. Der Name rührt daher, dass die Autoren in ihrer Arbeit einen weiteren Löser mit noch etwas besseren Eigenschaften angeben. Auf dessen Präsentation wird hier allerdings verzichtet. Algorithmus 28 : SimpleSolver Input : Graph G = (V, E, r), Bedarfsvektor d, Toleranz Output : -approx. elektr. Fluss f , zugeh. Potentialvektor v 1 T ← Spannbaum von G mit niedriger Streckung 2 f0 ← eindeutiger Fluss auf T mit B T f0 = d R 1 3 pe ← t(T ) · r e für alle Nichtbaumkanten e e st(T )·t(T ) 4 K ← dt(T ) log e 5 6 for i = 1 to K do Wähle zufällige Nichtbaumkante ei mit Wahrscheinlichkeit pei 7 8 fi ← fi−1 − ∆cei (fi−1 ) cei Rei return fK und zugeh. Potentialvektor vK Das Haupttheorem dieses Abschnitts besagt, dass SimpleSolver tatsächlich einen (1 + )approximativen elektrischen Fluss berechnet. Theorem 6.29. Die Ausgabe von SimpleSolver erfüllt E [Er (f )] ≤ (1 + )Ef (fopt ) und E[kv − L† dkL ] ≤ √ kL† dkL . Der Algorithmus kann so implementiert werden, dass seine Laufzeit O(m log2 (n) log log n log(−1 n)) ist. Um dieses Theorem zu beweisen, werden wir als ersten Schritt die Kovergenzgeschwindigkeit analysieren. 6.3.4. Konvergenz des Algorithmus In diesem Abschnitt werden wir zeigen, dass der Algorithmus SimpleSolver konvergiert und die Konvergenzgeschwindigkeit 1 − 1/t(T ) beträgt. Wir möchten daher folgendes Theorem beweisen: Theorem 6.30. Jede Iteration von SimpleSolver berechnet einen zulässigen Fluss fi derart, dass E [Er (fi )] − Er (fopt ) ≤ (1 − 1 i ) (Er (f0 ) − Er (fopt )). t(T ) Jede Iteration von SimpleSolver verringert also die Energie des aktuellen Flusses im Erwartungswert um (1 − 1/t) von der Energiedistanz zum optimalen Wert. Für einen zulässigen Fluss f können wir den durch Er (f ) gemachten Fehler senken, indem wir ein Vielfaches einer Zirkulation c zu f addieren. Das nachfolgende Lemma zeigt, wie wir die Energie bestmöglich erhöhen können. 6.3. Kombinatorische Löser für Laplace-Systeme 91 Abbildung 6.3.2.: Initialer Fluss f0 (links) und der daraus durch eine Iteration entstehende Fluss f1 (rechts) in Beispiel 6.33. T Rc Lemma 6.31. Für einen Fluss f , eine Zirkulation c und α∗ = − fcT Rc ∈ R gilt: argminα∈R Er (f + αc) = α∗ und Er (f + α∗ c) − Er (f ) = − (f T Rc)2 cT Rc Beweis. Nach Definition der Energie gilt Er (f ) = f T Rf . Für α ∈ R folgt somit Er (f + αc) = (f + αc)T R(f + αc) = f T Rf + 2αf T Rc + α2 cT Rc Wir bilden nun die partiellen Ableitungen bezüglich α und setzen diesen Ausdruck gleich 0. So erhalten wir 2f T Rc + 2α∗ cT Rc = 0. Dann erfüllt α = α∗ diese Gleichheit und minimiert folglich den Ausdruck Er (f + αc). Im Spezialfall eines Baumzyklus als Zirkulation, also c = ce für ein e ∈ E\T, entspricht obiges α∗ gerade der Zyklusaktualisierung unseres Algorithmus, da in diesem Fall cTe Rce = Re und f T Rce = ∆ce (f ) gilt. Wir können somit direkt folgendes Lemma zur Zyklusaktualisierung folgern: Lemma 6.32. Für einen zulässigen Fluss f und e ∈ E\T gilt: Er (f − ∆ce (f ) ∆c (f )2 ce ) − Er (f ) = − e Re Re Beispiel 6.33. Wir führen Beispiel 6.25 weiter: Sei f0 der initiale Fluss mit f0 (1, 2) = 1, f0 (2, 4) = 1 und f0 (e) = 0 für die anderen Kanten. Für alle Kanten e ∈ E gelte erneut re = 1. Nach einer Iteration im SimpleSolver-Algorithmus entstehe der Fluss f1 wie in Abbildung 6.3.2 dargestellt. Für die Energie der beiden Flüsse gilt dann: X Er (f0 ) = re · f0 (e)2 = f0 (1, 2)2 + f0 (2, 4)2 e∈E = 1+1=2 X Er (f1 ) = re · f1 (e)2 = f1 (1, 2)2 + f1 (2, 4)2 + f1 (1, 5)2 + f1 (5, 4)2 e∈E = 1 1 1 1 + + + =1 4 4 4 4 Die Energiedifferenz der beiden Flüssen beträgt daher Er (f0 ) − Er (f1 ) = 2 − 1 = 1. 92 6. Ausdünnung von Graphen und Laplace-Löser Definition 6.34. Die Lagrange-duale Lösung des optimalen Flusses fopt ist gegeben durch: max(2v T d − v T Lv). v∈Rn Für ein v ∈ Rn setzen wir ζr (v) = 2v T d − v T Lv und definieren die Dualitätslücke gap(f, v) durch gap(f, v) = Er (f ) − ζr (v). Lemma 6.35. Für einen zulässigen Fluss f und bauminduzierte Spannungen v gilt: gap(f, v) = X ∆c (f )2 e re e∈E\T Diesen Ausdruck der Zykluspotentiale werden wir benutzen, um den Abstand der Lösung des Algorithmus zur optimalen Lösung nach oben zu beschränken. Lemma 6.36. Für Iteration i des Algorithmus SimpleSolver gilt: E [Er (fi ) − Er (fi−1 ) | gap(fi−1 , vi−1 )] = − gap(fi−1 , vi−1 ) t(T ) Beweis. In jeder Iteration wählt der Algorithmus eine zufällige Kante ei ∈ E\T mit Wahrscheinlichkeit pei und addiert ein Vielfaches von cei auf fi−1 . Nach Lemma 6.32 verringert sich die Energie um ∆ce (fi−1 )2 /Re . Somit gilt: 2 X −∆ (f ) ce i−1 E [Er (fi ) − Er (fi−1 ) | gap(fi−1 , vi−1 )] = E pe · | gap(fi−1 , vi−1 ) Re e∈E\T 2 X ∆c (fi−1 ) Re · − e | gap(fi−1 , vi−1 ) = E t(T ) · re Re e∈E\T 1 = E · (−gap(fi−1 , vi−1 )) | gap(fi−1 , vi−1 ) t(T ) gap(fi−1 , vi−1 ) = − , t(T ) wobei der erste Schritt nach Lemma 6.32, der zweite Schritt durch die Beziehung pe = (1/t(T )) · (Re /re ) und der dritte Schritt schließlich mit Lemma 6.35 folgt. Mit Lemma 6.36 können wir nun das folgende Lemma beweisen, das den letzten Schritt zum Beweis von Theorem 6.30 darstellt. Lemma 6.37. Für alle i ≥ 0 sei die Zufallsvariable Di definiert durch Di = Er (fi ) − Er (fopt ). Dann gilt für alle Iterationen i ≥ 1: 1 E [Di ] ≤ (1 − )E [Di−1 ] t Beweis. Da Di eine diskrete Zufallsvariable ist, können wir das Gestz der totalen Wahrscheinlichkeit ausnutzen: X E [Di ] = E [Di | Di−1 = c] · P r (Di−1 = c) . c 6.3. Kombinatorische Löser für Laplace-Systeme 93 Wegen der Dualität wissen wir, dass Di ≤ gap(fi−1 , vi−1 ) gilt. Somit folgt nach Lemma 6.36: E [Di | Di−1 = c] ≤ c − t(Tc ) . Insgesamt gilt also nach der Definition des Erwartungswerts E[Di ] ≤ X c = (1 − 1 (1 − )c · P r(Di−1 = c) t(T ) 1 )E[Di−1 ] t(T ) Wenden wir nun das vorherige Lemma induktiv an, so erhalten wir nach Definition der Di schließlich die Aussage von Theorem 6.30. 6.3.5. Beweis des Haupttheorems Bevor wir den Beweis des Haupttheorems angehen werden, benötigen wir noch zwei Hilfslemmas. Lemma 6.38. Es gilt: Er (f0 ) ≤ st(T ) · Er (fopt ). Lemma 6.39. Sei f ein (primal) zulässiger Fluss mit Er (f ) ≤ (1 + )Er (fopt ) für ein > 0 und sei v der Vektor der bauminduzierten Spannungen. Dann gilt: p ||v − L+ d||L ≤ · t(T )||L+ d||L Beweis. Nach Lemma 6.36 und der Optimalität von fopt gilt Er (f ) − gap(f, v) ≥ Er (fopt ). t(T ) Nach Voraussetzung gilt dann gap(fopt , v) ≤ · t(T ) · Er (fopt ), denn: gap(fopt , v) = Er (fopt ) − ζr (v) ≤ gap(f, v) (wegen Optimalität) ≤ t(T ) · (Er (f ) − Er (fopt )) (nach oben) ≤ t(T ) · ((1 + )Er (fopt ) − Er (fopt )) (nach Voraussetzung) = · t(T ) · Er (fopt ) Mit den Beziehungen gap(fopt , v) = ||v − L+ d||2L = (v − L+ d)T L(v − L+ d) und Er (fopt ) = ||L+ d||2L = (L+ d)T L(L+ d) 94 6. Ausdünnung von Graphen und Laplace-Löser folgt schließlich ||v − L+ d||L = ≤ q q gap(fopt ) · t(T ) · Er (fopt ) (nach oben) p = · t(T ) · ||L+ d||L Nun haben wir alle Vorarbeiten geleistet, um unser Haupttheorem beweisen zu können. Beweis. Wir zeigen zuerst, dass der Algorithmus die gewünschte Güte besitzt. Wir müssen nun noch die Laufzeit des Algorithmus beweisen. Dazu analysieren wir die Laufzeit der einzelnen Berechnungsschritte: • Verwende einen Spannbaum T mit st(T ) = O(m log n log log n), der in Zeit O(m log n log log n) berechnet werden kann. Dann gilt ebenfalls t(T ) = O(m log n log log n). • Der initiale Fluss f0 wird in Zeit O(n) berechnet. • Re kann für alle Kanten mit Tarjans LCA-Algorithmus in O(m) oder durch eine eigene Datenstruktur in O(m log n) berechnet werden. • Die Initialisierung der Datenstruktur benötigt O(n log n). • Pro Iteration ist die Laufzeit einer Zyklusaktualisierung O(log n) und die Anzahl der Iterationen ist O(m log n log(n−1 ) log log n). Insgesamt ergibt sich daher die Laufzeit als O(m log2 (n) log log n log(n−1 )). 6.4. Weiterführende Literatur Folgt. 95 Literaturverzeichnis [BM72] Bayer, Rudolf ; Mccreight, EM: Organization and Maintenance of Large Ordered Indexes. In: Acta Informatica 1 (1972), S. 173–189 [Bos09] Bosch, Siegfried: Algebra. Springer, 2009 (Springer-Lehrbuch) [GMS92] Gilbert, John R. ; Moler, Cleve ; Schreiber, Robert: Sparse matrices in MATLAB: design and implementation. In: SIAM Journal on Matrix Analysis and Applications 13 (1992), Nr. 1, S. 333–356 [Gra09] Gramlich, G.: Lineare Algebra: Eine Einführung. Fachbuchverl. Leipzig im Carl Hanser Verlag, 2009 (Mathematik-Studienhilfen) [Gus72] Gustavson, Fred G.: Some basic techniques for solving sparse systems of linear equations. In: Sparse matrices and their applications. Springer, 1972, S. 41–52 [KG11] Kepner, Jeremy (Hrsg.) ; Gilbert, John (Hrsg.): Graph Algorithms in the Language of Linear Algebra. Society for Industrial and Applied Mathematics, 2011 [Koz91] Kozen, Dexter C.: The Design and Analysis of Algorithms. Springer New York, 1991 (Texts and Monographs in Computer Science) [LG14] Le Gall, François: Powers of Tensors and Fast Matrix Multiplication. In: CoRR abs/1401.7714 (2014) [MMS09a] Meyerhenke, Henning ; Monien, Burkhard ; Sauerwald, Thomas: A New Diffusion-based Multilevel Algorithm for Computing Graph Partitions. In: Journal of Parallel and Distributed Computing 69 (2009), Nr. 9, S. 750–761 [MMS09b] Meyerhenke, Henning ; Monien, Burkhard ; Schamberger, Stefan: Graph Partitioning and Disturbed Diffusion. In: Parallel Computing 35 (2009), Nr. 10–11, S. 544–569 [MS12] Meyerhenke, Henning ; Sauerwald, Thomas: Beyond Good Partition Shapes: An Analysis of Diffusive Graph Partitioning. In: Algorithmica 64 (2012), Nr. 3, S. 329–361 [NS12] Naumann, Uwe (Hrsg.) ; Schenk, Olaf (Hrsg.): Combinatorial Scientific Computing. Chapman & Hall/CRC, 2012 (Computational Science Series) [SM00] Shi, Jianbo ; Malik, Jitendra: Normalized cuts and image segmentation. In: Pattern Analysis and Machine Intelligence, IEEE Transactions on 22 (2000), Nr. 8, S. 888– 905 97 A. Anhang A.1. Grundlagen der linearen Algebra Dieser Abschnitt wiederholt einige Grundlagen aus der linearen Algebra, die typischerweise in Anfängervorlesungen wie Mathematik für Informatiker eingeführt werden. Eine vollständige Einführung von Notation und Grundlagen ist hier nicht vorgesehen. Für eine grundlegende und tiefergehende Wiederholung wird dem Leser die Lektüre gängiger Einstiegslehrbücher empfohlen. Das Buch von Bosch [Bos09] beispielsweise ist als Begleitung von universitären Vorlesungen gedacht. Sehr praktisch angelegt ist dagegen das Buch von Gramlich [Gra09]. Definition A.1. Seien im folgenden n ∈ N, x, y ∈ Rn und A = (aij ) ∈ Rn×n . 1. Das Skalarprodukt zweier Vektoren x und y ist definiert durch hx, yi = 2. Zwei Vektoren x und y heißen orthogonal, wenn gilt: hx, yi = 0. 3. Als Norm eines Vektors x verwenden wir die Summennorm ||x||1 = p die euklidische Norm ||x||2 = hx, xi. P Pn i=1 xi i |xi | · yi . bzw. meistens 4. Die Matrix AT = (aji ) ∈ Rn×n heißt transponierte Matrix von A. 5. Eine Matrix A heißt symmetrisch, wenn A = AT gilt. 6. Seien k1 , k2 ≥ 0, dann besitzt A eine Bandbreite von k1 + k2 + 1, wenn aij = 0 für j < i − k1 und j > i + k2 . P 7. Das Matrix-Vektorprodukt y = Ax ist definiert durch yi = nj=1 aij · xj = hAi• , xi. 8. Die Norm einer Matrix A ist durch ||A|| = supx6=0 ||Ax|| ||x|| definiert. 9. λ heißt Eigenwert der Matrix A, wenn Au = λ · u für ein u ∈ Rn , u 6= 0, gilt. Alle Vektoren u mit Au = λ · u heißen dann Eigenvektoren zum Eigenwert λ von A. 10. Die Eigenvektoren einer symmetrischen Matrix A bilden eine orthonormale Basis. A besitzt n Eigenwerte {λ1 , . . . , λn }, wobei diese mehrfach vorkommen dürfen, d.h. λ1 ≤ λ2 ≤ · · · ≤ λn . 11. Das charakteristische Polynom der Matrix A ist definiert durch fA (λ) = det(A − λEn ). Ohne Beweis geben wir die folgenden drei Theoreme an: Theorem A.2. Seien A, B ∈ Rn×n und x ∈ Rn . Dann gilt: 1. ||A · B|| ≤ ||A|| · ||B|| 2. ||Ax|| ≤ ||A|| · ||x|| Theorem A.3. Sei A ∈ Rn×n . λ ist genau dann ein Eigenwert von A, wenn λ eine Nullstelle des charakteristischen Polynoms fA ist. 98 A. Anhang Theorem A.4. Sei A ∈ Rn×n symmetrisch. Dann besitzt A nur reelle Eigenwerte und die Eigenvektoren zu verschiedenen Eigenwerten bilden eine Orthogonal-Basis des Rn . Theorem A.5. Sei A ∈ Rn×n symmetrisch und λ1 ≤ λ2 ≤ . . . ≤ λn die Eigenwerte von A. Dann gilt: hAx, xi hAx, xi λ1 = min und λn = max x6=0 hx, xi x6=0 hx, xi Beweis. Sei u1 , . . . , un eine Orthogonal-Basis aus Eigenvektoren von A zu den Eigenwerten λ1 , . . . , λn . Jedes x ∈ Rn lässt sich als Linearkombination der ui schreiben: x= n X αi ∈ R αi ui , i=1 n X =⇒ Ax = αi Aui = i=1 n X αi λi ui i=1 =⇒ hAx, xi = h n X i=1 αi λi ui , n X j=1 αj uj i = n X n X i=1 j=1 αi λi αj hui , uj i Da die Eigenvektoren paarweise senkrecht aufeinander stehen, gilt hui , uj i = 0 für i 6= j: hAx, xi = =⇒ n X i=1 hAx, xi ≤ λn hx, xi λi αi2 hui , ui i ≤ λn n X i=1 hαi ui , αi ui i = λn hx, xi ∀x 6= 0 Für x = un gilt ferner hAx,xi hx,xi = λn . Die Aussage für λ1 zeigt man entsprechend, indem man hAx, xi mit λ1 nach unten abschätzt. Korollar A.6. Sei A ∈ Rn×n und λn der größte Eigenwert der Matrix AT A. Dann gilt: p ||A|| = λn Beweis. AT A ist symmetrisch und aus dem Beweis zu Satz A.5 folgt für beliebige x ∈ Rn : ||Ax||2 = hAx, Axi = hAT Ax, xi ≤ λn hx, xi = λn ||x||2 p =⇒ ||A|| = λn , da für x = un die Gleichung ||Ax||2 = λn ||x||2 erfüllt ist. Definition A.7. Sei G = (V, E) ein beliebiger Graph mit n = |V | Knoten, V = {v1 , . . . , vn }. Die Laplace-Matrix LG = (lij ) ∈ Zn×n ist definiert durch: grad(vi ) , falls i = j −1 , falls (vi , vj ) ∈ E lij = 0 , sonst A.1. Grundlagen der linearen Algebra 99 Die Zeilensumme einer Laplace-Matrix LG ist nach Konstruktion immer 0. Es gilt also: 1 1 0 .. .. .. LG . = . = 0 · . 1 0 1 Somit ist 0 ein Eigenwert jeder Laplace-Matrix und (1 . . . 1) ein zugehöriger Eigenvektor. Offensichtlich ist die Laplace-Matrix von ungerichteten Graphen symmetrisch. Nach Satz A.4 sind daher alle Eigenwerte der Matrix reell und die zugehörigen Eigenvektoren bilden eine OrthogonalBasis. Man kann ferner zeigen, dass alle Eigenwerte größer gleich Null sind, 0 ist also der kleinste Eigenwert einer Laplace-Matrix. Ferner gilt, dass ein ungerichteter Graph genau dann zusammenhängend ist, wenn alle anderen Eigenwerte echt größer als Null sind. A.1.1. Spektrale Zerlegung einer symmetrischen Matrix Sei A eine symmetrische Matrix mit den Eigenwerten λ1 , . . . , λn und den zugehörigen Eigenvektoren v1 , . . . , vn . Dann gilt also Avi = λi vi ∀i. Sei weiterhin V die Matrix, die als i-te Spalte den i-ten Eigenvektor vi besitzt und Λ sei die Diagonalmatrix mit Λii = λi . Dann gilt: AV = V Λ. Durch die Multiplikation von V T von rechts ergibt sich aufgrund der Orthonormalität die spektrale Eigenzerlegung von A: X A = AV V T = V ΛV T = λi vi viT . i