Seminar Zeichnen von Graphen

Werbung
Universität Konstanz
Fachbereich Informatik und Informationswissenschaft
Seminar: Zeichnen von Graphen
Simple and Efficient Bilayer Cross Count
Ausarbeitung zum gleichnamigen Artikel von Barth, Jünger und Mutzel
Proceedings of the 10th International Symposium on Graph Drawing (GD’2002)
Lecture Notes in Computer Science 2528, Springer-Verlag, pp. 130 - 141, 2002
Prof. Dr. Ulrik Brandes
von
Matthias Broghammer
[email protected]
Version vom 3. Mai 2005
Inhaltsverzeichnis
1 Einleitung
1.1 Motivation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1.2 Anwendungsbeispiel: Sugiyama-Layouter . . . . . . . . . . . . . . . . . . . .
1
1
1
2 Definitionen
2.1 Grundlegendes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.2 Inversionszahl . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2
2
3
3 Entwicklung eines effizienten Algorithmus
3.1 Naiver Ansatz . . . . . . . . . . . . . . . . . . . . . . . .
3.2 Geometrischer Ansatz . . . . . . . . . . . . . . . . . . .
3.3 Ansatz mittels Sortierverfahren . . . . . . . . . . . . . .
3.3.1 MergeSort . . . . . . . . . . . . . . . . . . . . . .
3.3.2 InsertionSort . . . . . . . . . . . . . . . . . . . .
3.4 Der effiziente und einfache O(|E| log |Vsmall |) Algorithmus
4
4
5
5
5
5
7
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
4 Implementation
10
5 Empirische Laufzeitanalyse
5.1 Testumgebung . . . . . . .
5.2 Dünne Graphen . . . . . .
5.3 Dünne große Graphen . .
5.4 Dichte Graphen . . . . . .
5.5 AT&T-Graphen . . . . . .
5.6 Zusammenfassung . . . . .
10
13
13
14
14
15
15
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
i
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
1
1.1
Einleitung
Motivation
Die Autoren Barth, Jünger und Mutzel beschäftigen sich im untersuchten Artikel [WB02] mit
dem Problem, die Zahl der Kantenkreuzungen bei einem bipartiten Graphen zu bestimmen,
wenn dieser auf folgende Weise gezeichnet wird:
Abbildung 1: Schematische Darstellung einer Zwei-Lagen-Zeichnung (Bilayer Drawing, BLD)
Die Knoten der beiden Mengen der Bipartition werden jeweils auf einer Strecke so verteilt,
dass sich keine Knoten überlappen. Die beiden Strecken werden dabei parallel untereinander
ausgerichtet und die Kanten ebenfalls als gerade Linien gezeichnet.
Um einen Graphen oder ein Netzwerk übersichtlich darzustellen, ist es in den meisten Fällen
unabdingbar, die Zahl solcher Kreuzungen möglichst gering zu halten.
Layout-Algorithmen versuchen dabei, eine Anordnung der Knoten des Graphen zu finden,
sodass die Kantenkreuzungszahl möglichst gering ist. Als klassisches Anwendungsbeispiel für
einen solchen Algorithmus soll im Folgenden kurz die Vorghensweise des Sugiyama-Layouters
vorgestellt werden.
1.2
Anwendungsbeispiel: Sugiyama-Layouter
Der Sugiyama-Layout-Algorithmus [KS81] läßt sich in 3 Phasen unterteilen:
Erste Phase: Die Knoten des Graphen werden m parallelen Lagen zugeordnet, sodass alle
Kanten jeweils zwei Knoten auf unterschiedlichen Lagen verbinden. Dabei wird für solche Kanten, die zwischen zwei nicht-benachbarten Lagen verlaufen, für jede überquerte
Lage ein künstlicher Knoten eingefügt.
Zweite Phase: Hierbei werden die Anordnungnungen der Knoten auf den einzelnen Lagen
bestimmt, um eine möglichst geringe Kantenkreuzungszahl zu erhalten.
Dritte Phase: Aus der endgültigen Anordnung wird eine geometrische Repräsentation bestimmt.
Dabei tritt das vorgestellte Problem in der zweiten Phase auf: Der Algorithmus betrachtet
typischerweise jeweils zwei benachbarte Lagen (Lf ixed , Lf ree ) und versucht, aus einer anfänglichen Permutation der Knoten mittels Heuristik eine neue zu bestimmen, bei der die Kantenkreuzungszahl geringer ist. Dabei verändert er jeweils nur die Knoten der Lage Lf ree , die Permutation der anderen Lage, Lf ixed , wird dabei nicht verändert. Der Algorithmus durchläuft
1
dabei solange die Lagen von unten nach oben und umgekehrt, bis keine Verbesserung mehr
erreicht wird.
Das Zweilagen-Kreuzungs-Minimierungsproblem ist N P-hart [PE94]. Es gibt jedoch gute
Heuristiken und es ist möglich, dieses Problem für Graphen mit bis zu 60 Knoten pro Lage
sehr schnell zu lösen [MJ97].
Das Zweilagen-Kantenkreuzungszahlproblem, also die Stelle im Algorithmus, bei welcher die
Zahl der Kantenkreuzungen zwischen zwei benachbarten Lagen gezählt wird, kann unter
Umständen den Flaschenhals der Gesamtlaufzeit des Sugiyama-Layout-Algorithmus darstellen [CW99].
Es ist also von Interesse, dieses Problem effizient zu lösen. Im Folgenden wird dazu ein
Algorithmus entwickelt, der nicht nur in vielen Anwendungsfällen effizienter als die bisher
bekannten ist, sondern dazu noch sehr leicht zu implementieren ist.
Abbildung 2: Eine Graphandarstellung nach Sugiyama-Layout (mit virtuellen Knoten)
2
2.1
Definitionen
Grundlegendes
Sei G = (N, S, E) ein bipartiter Graph mit disjunkten Knotenmengen N und S.
N bezeichne dabei die nördliche, und S die südliche Knotenmenge der Bipartition.
Zusätzlich gelte für jede Kanten e = (u, v) ∈ E, dass entweder u ∈ N, v ∈ S oder u ∈ S, v ∈ N
gilt. Das bedeutet, dass alle Kanten ausschließlich zwischen N und S verlaufen.
Desweiteren seien LN , LS ∈ R2 zwei diskunkte parallele Strecken, eine nördliche und eine
südliche.
2
Eine Zweilagen-Zeichnung BLD(G) (bilayer drawing) weist allen Knoten ni ∈ N = {n0 , n1 , . . . np−1 }
disjunkte Punkte P (ni ) auf LN , und allen Knoten sj ∈ S = {s0 , s1 , . . . , sq−1 } disjunkte Punkte P (Sj ) auf LS zu.
Den Kanten ek = (ni , sj ) ∈ E = {e0 , e1 , . . . , er−1 } werden Strecken mit Endpunkten P (ni )
und P (sj ) zugewiesen:
Abbildung 3: Darstellung eines Bilayer Drawings (BLD)
Die Zweilagen-Kantenkreuzungszahl BCC (bilayer cross count) ist dabei die Anzahl von
paarweisen, inneren Schnittpunkten der zu den Kanten zugehörigen Strecken.
Unser Beispiel aus Abbildung 3 hat also BCC(BLD(G)) = 12. Offensichtlich ist diese Zahl
einzig und allein von den relativen Positionen der Knotenpunkte auf LN und LS abhängig,
nicht von ihrer exakten Position.
Damit ist BCC(BLD(G)) nur von den Knotenfolgen πN von N und πS von S abhängig.
Wir wollen also ausgehend von gegebenem πN und πS die Zweilagen-Kantenkreuzungszahl
BCC(πN , πS ) effizient berechnen.
Dazu nehmen wir vereinfachend und o.B.d.A. an, dass es keine isolierten Knoten gibt und
dass q ≤ p, d.h. |S| ≤ |N | gilt.
2.2
Inversionszahl
Wir werden sehen, dass zwischen der Inversionszahl und der Kantenkreuzungszahl ein enger
Zusammenhang besteht, den wir ausnutzen werden.
In einer Folge π = ha0 , a1 , . . . , at−1 i von paarweise vergleichbaren Elementen ai , wird ein
Paar (ai , aj ) eine Inversion genannt, wenn gilt:
i<j
∧
3
ai > a j
Die Inversionszahl IN V (π) = |{(ai , aj ) | i < j ∧ ai > aj }| ist eine bekannte Maßzahl für den
Sortierungsgrad der Folge π.
In einem Zweilagen-Graphen mit Nordlagen-Folge πN = hn0 , n1 , . . . , np−1 i und SüdlagenFolge πS = hs0 , s1 , . . . , sq−1 i sei πE = he0 , e1 , . . . , er−1 i lexikographisch sortiert, so dass gilt:
ek = (nik , sjk ) < (nil , sjl ) = el
⇐⇒
ik < il oder ik = il ∧ jk < jl
Die Kanten in Abbildung 3 sind bereits lexikographisch sortiert.
Sei π = hj0 , j1 , . . . , jr−1 i die Folge der Positionen der südlichen Endknoten der Kanten aus
E. Dann ergibt sich für unser Beispiel:
π = h0, 1, 2, 0, 3, 4, 0, 2, 3, 2, 4i
Jede Inversion in π entspricht dabei genau einer paarweisen Kantenkreuzung in der ZweilagenZeichnung BLD(G).
3
Entwicklung eines effizienten Algorithmus
Der im Artikel vorgestellte Algorithmus mit einer Laufzeit in O(|E| log |Vsmall |) und Speicherbedarf in O(|E|) stellt derzeit nicht nur theoretisch die effizienteste Möglichkeit dar, die Kantenkreuzungszahl zu bestimmen, sondern ist auch in fast jeder Situation, also abhängig vom
Aufbau des Graphen, schneller als die bisherigen Algorithmen zur Lösung dieses Problems.
Diese verschiedenen Ansätze sollen im Folgenden kurz erwähnt werden und schließlich die
Entwicklung des Algorithmus aufgezeigt werden.
3.1
Naiver Ansatz
Eine einfache und naive Methode, die Kantenkreuzungszahl zu bestimmen, ist das Testen
aller Paare von Kanten, ob sich diese jeweils schneiden. Dabei vergleicht man einfach ihre
Endknoten-Positionen in LN und LS .
Dies führt offensichtlich zu einem Algorithmus mit Laufzeit in O(|E|2 ).
Dieser Algorithmus bestimmt nicht nur die Zahl der Kreuzungen, sondern die Kreuzungen
selbst, was für unser gegebenens Problem nicht notwendig ist.
Da die maximal mögliche Anzahl an Kreuzungen in Θ(|E|2 ) liegt, kann es hierfür keinen
asymptotisch besseren Algorithmus geben.
Daher sollte man sich lediglich mit dem Problem des Zählens von Kreuzungen beschäftigen, nicht mit der Bestimmung der Kreuzungen selbst.
4
3.2
Geometrischer Ansatz
Das Zweilagen-Kantenkreuzungsproblem kann als Spezialfall eines grundlegenden geometrischen Problems angesehen werden, das Zählen von paarweisen Kreuzungen einer Menge von
Strecken in der Ebene.
Sei C die Menge der paarweisen Kreuzungen. Der schnellste bekannte Algorithmus, der alle
Kreuzungen bestimmt, ist von Chazelle und Edelsbrunner [BC92] und liegt mit seiner Laufzeit in O(|E| log |E| + |C|) und der Speicherbedarf in O(|E| + |C|). Der schnellste bekannte
Algorithmus für das Zählen der Kreuzungen ist von Chazelle [Cha86] und liegt in O(|E|1.695 )
bei einem Speicherbedarf in O(E).
Ein anderer geometrischer Ansatz ist von Sander [San96] und basiert auf der Sweep-Line
Methode. Die Laufzeit dieses Algorithmus liegt in O(|E| + |C|) bei einem Speicherbedarf in
O(E).
Dieser Ansatz wurde von Waddle und Malhotra [BC92] noch verbessert, was zu einer Laufzeit in O(|E| log |V |) mit V = N ∪ S und wiederum einem Speicherbedarf in O(|E|) führte.
Dieser Algorithmus wird als Durchbruch angesehen, da nicht nur die theoretische, sondern
auch die praktische Laufzeit durch diesen Algorithmus erheblich verbessert wurde.
Die Autoren Barth, Jünger und Mutzel haben ausführliche Laufzeittests durchgeführt, auf
die in Kapitel 5 näher eingegangen wird.
3.3
Ansatz mittels Sortierverfahren
Wir erinnern uns, dass die Zahl der Kantenkreuzungen auch durch das Zählen von Inversionen bestimmt werden kann: BCC(πN , πS ) = IN V (π), wobei π die Folge der Positionen der
Endknoten aller Kanten in der südlichen Lage war.
Es ist bekannt, dass die Zahl dieser Inversionen in O(|E| log |E|) mit Speicherbedarf in O(|E|)
bestimmt werden kann.
3.3.1
MergeSort
Cormen, Leiserson und Rivest [THC90] schlagen beispielsweise eine Modifikation des MergeSortAlgorithmus vor. Die Berechnung der Folge π, also die lexikographische Sortierung der Kanten, liegt durch Verwendung von RadixSort sowohl von der Laufzeit als auch dem Speicherbedarf in O(|E|), was zu einer Gesamtlaufzeit in O(|E| log RUN(π)) und Speicherbedarf in
O(|E|) führt. Hierbei ist RUN(π) die Zahl der Durchläufe, in unserem Fall die Anzahl der
sortierten Teilfolgen in π.
3.3.2
InsertionSort
Mittels InsertionSort-Algorithmus kann die Inversionszahl und damit die Anzahl der Kantenkreuzungen mit Laufzeit in O(|E| + IN V (π)) und Speicherbedarf in O(|E|) bestimmt
werden, was zu einer Laufzeit in O(|E| + |C|) und Speicherbedarf in O(|E|) führt.
5
Aus diesem Ansatz wird nun der einfache und effiziente Algorithmus entwickelt. Die Funktionsweise des InsertionSort-Algorithmus soll an dem Beispiel-Graphen aus Abbildung 3 gezeigt
werden.
Der Algorithmus läßt sich dabei in 3 Teile gliedern:
1.) Sortiere die Kanten lexikographisch bzgl. πN und πS mittels RadixSort.
Dieser Schritt liegt bekanntlich in O(|E|) und wurde in unserem Beispiel (Abbildung
3) bereits durchgeführt.
2.) Um die Folge π zu erhalten, schreibe die Südknoten-Positionen in Sortierreihenfolge
der Kanten in ein Array.
Im Beispiel erhalten wir hierbei h0, 1, 2, 0, 3, 4, 0, 2, 3, 2, 4i.
3.) Führe den InsertionSort-Algorithmus auf dem Array durch und bestimme die Kantenkreuzungszahl, indem aufaddiert wird, um wieviele Positionen ein Element jeweils
bewegt wird.
Zum besseren Verständnis wurden in Abbildung 4 auch noch die Knoten aus N und
die Kanten eingezeichnet, was für diesen Schritt des Algorithmus nicht nötig ist.
Als Lösung erhält man eine Kantenkreuzungszahl von 2 + 4 + 2 + 1 + 3 = 12.
Die Korrektheit des Algorithmus folgt aus der Invariante:
Wird ein Element bewegt, so stehen in der aktuellen Folge die höher indizierten Elemente
direkt vor diesem.
Betrachtet man den ersten Schritt in Abbildung 4, so sieht man den Zustand der Folge
vor der ersten Sortierung. Die erste Inversion ist an 3. und 4. Stelle zu finden, da gilt: 3 < 4
aber 2 > 0.
Um diese Inversion aufzulösen, wird das vierte Element, s0 , zwei Positionen nach vorne
bewegt. Wir wissen damit, dass durch die relative Ordnung nun genau zwei Kreuzungen
verursacht wurden. Führt man dies für alle Inversionen aus und man folglich am Ende die
sortierte, d.h. ursprüngliche Folge der Südknoten-Positionen erhält, so wurden alle Inversionen und damit auch alle Kreuzungen gefunden und zur Gesamtkreuzungszahl aufaddiert.
Untersucht man nun die Laufzeit diesesAlgorithmus,
so weiß man bereits, dass InsertionSort
|E|
in O(|E| + |C|) liegt. Da es maximal 2 Inversionen geben kann, liegt der beschriebene
Algorithmus in O(|E|2 ).
Diese Laufzeit kann aber durch Verwendung eines Akkumulator-Baumes (accumulator tree)
erheblich verbessert werden, wodurch wir den gewünschten einfachen und effizienten Algorithmus mit Laufzeit in O(|E| log |Vsmall |) erhalten.
6
Abbildung 4: Zählen der Kantenkreuzungen mittels InsertionSort
3.4
Der effiziente und einfache O(|E| log |Vsmall |) Algorithmus
Sei T ein Akkumulatorbaum, d.h. ein balancierter Binärerbaum mit 2c Blättern. Die ersten
|S| Blätter seien dabei den Positionen der Knoten der südlichen Lage zugeordnet und sei
c ∈ N wie folgt definiert: 2c−1 < q = |S| ≤ 2c .
Für unser Beispiel (Abbildung 3) ergibt sich damit der Akkumulatorbaum in Abbildung
5.
Diesen Akkumulatorbaum speichert man in einem Array mit 2c+1 − 1 Einträgen. Wie bei der
Repräsentation von Binärbäumen ist die Wurzel an Position 0 zu finden, und jeder Knoten
an Position i hat seinen Vorgänger an Position b i−1
c. Alle Array-Einträge werden anfänglich
2
7
Abbildung 5: Akkumulatorbaum für unser Beispiel aus Abbildung 3
mit 0 initialisiert. Zusätzlich wird noch die aktuelle Kantenkreuzungszahl aufsummiert, welche auch mit 0 initialisiert wird.
Der Algorithmus speichert in den Blättern des Akkumulatorbaumes die Zahl der zugeordneten südlichen Endknoten und in jedem inneren Knoten die Summe der Anzahlen der Kinderknoten.
Diese Summen werden durch Abarbeiten der südlichen Endknoten in der durch π gegebenen
Reihenfolge gebildet:
Für jede solche Position startet man an dem zugeordneten Blatt des Baumes und durchläuft
den Baum bis hoch zur Wurzel und erhöht den Eintrag in jedem besuchten Knoten (einschließlich der Wurzel) um eins. Wird dabei ein linker Kindknoten besucht (ungerade Knotenposition), addiert man den Eintrag im rechten Nachbar von diesem zur Kantenkreuzungszahl
dazu.
Dies geschieht immer genau dann, wenn eine Kante zu einem weiter links liegenden südlichen
Endknoten eingefügt wird und dabei alle die Kanten kreuzt, die bereits eingefügt wurden
und mit Knoten rechts von dem aktuellen Süd-Knoten liegen. Dieser wichtige Sachverhalt
wurde bereits in Abbildung 4 verdeutlicht.
In Abbildung 6 sind die aktuellen Stände im Akkumulatorbaum nach Abarbeitung der jeweils ersten vier Positionen in π dargestellt. Bei der Abarbeitung der vierten Position wird die
Kantenkreuzungszahl bei Passieren der Knoten 3 und 1 jeweils um eins erhöht. In Abbildung
7 ist der Endstand zu sehen, die Kantenkreuzungszahl erhöht sich dabei beim Abarbeiten
der Positionen 4, 7, 8, 9, 10 und beträgt dabei entsprechend 2, 6, 8, 9 und schließlich 12.
Die Korrektheit dieses Algorithmus ist wie bei der obigen Variante gegeben. Wenn wir
o.B.d.A. annehmen, dass |S| ≤ |N |, also z.B. |Vsmall | = |S|, ergibt sich zusammen mit der
Tiefe des Akkumulatorbaumes eine Laufzeit in O(|E| log |Vsmall |), da wir insgesamt |E| Kanten einfügen und die Höhe des Akkumulatorbaumes durch log |Vsmall | beschränkt ist.
8
Abbildung 6: Akkumulatorbaum nach Abarbeitung der ersten vier Position in π
9
Abbildung 7: Akkumulatorbaum nach Abarbeitung aller Positionen in π
4
Implementation
Der beschriebene Algorithmus läßt sich sehr einfach, schnell und damit übersichtlich implementieren.
Abbildung 8 zeigt den Ausschnitt des Codes (Java), in dem der Baum angelegt wird, Abbildung 9 zeigt den Auschnitt des Codes, indem die Positionen in π durchlaufen und die
Kantenkreuzungszahl aufsummiert wird.
Eine weitere Besonderheit in der Implementierung stellt die Sortierung der Kanten dar. Um
die gewünschte Laufzeit zu erreichen, wird von den Autoren vorausgesetzt, dass diese Sortierung in Zeit O(|E|) zu bewerkstelligen ist. Diese Laufzeit kann z.B. durch das Sortierverfahren
RadixSort erreicht werden, dessen Implementation auch recht einfach realisiert werden kann,
wie Abbildung 10 zeigt.
5
Empirische Laufzeitanalyse
Um nun die Laufzeit des vorgestellten Algorithmus unter praktischen Gesichtspunkten zu
analysieren und mit den populärsten und bereits bekannten Algorithmen für das Zählen von
Kantenkreuzungen in einem Zweilagengraphen zu vergleichen, wurden von den Autoren verschiedene empirische Laufzeituntersuchungen unternommen.
Dazu wurden folgende Algorithmen in C implementiert:
10
Abbildung 8: Java Code Ausschnitt der Initialisierung des Akkumulatorbaumes
Abbildung 9: Java Code Ausschnitt der Abarbeitung der südlichen Endknoten-Positionen
11
Abbildung 10: Java Code Ausschnitt der Funktion RadixSort
12
Abkürzung
SAN
WAM
MER
INS
BJM
Algorithmus
Sander
Waddle und Malhotra
MergeSort-Variante
InsertionSort-Variante
Einfacher Algorithmus
Laufzeit-Schranke
O(|E| + |C|)
O(|E| log |V |)
O(|E| log RUN(π))
O(|E| + |C|)
O(|E| log |Vsmall |)
Quelle
[San96]
[BC92]
Kapitel 3.3.1
Kapitel 3.3.2
Kapitel 3.4
Desweiteren wurden die Algorithmen pro Test jeweils zweimal untersucht:
1.) Auf zufällig erzeugten Zwei-Lagen-Graphen, im Folgenden durch das Kürzel RAN
gekennzeichnet, und
2.) auf bereits vor-optimierten Zwei-Lagen-Graphen mittels Median-Heuristik [PE94], im
Folgenden durch MED gekennzeichnet.
Bei der Implementation wurde darauf geachtet, dass alle Algorithmen so gut und schnell
wie möglich implementiert wurden und dass alle über die selbe Schnittstelle / Parameter
verfügten:
• Zwei Integer-Zahlen, welche die Größe der Nord- bzw. Süd-Schicht angeben (p, q),
• Eine Integer-Zahl für die Anzahl der Kanten (r),
• Zwei Integer-Arrays (der Größe r), welche jeweils die Position des nördlichen bzw.
südlichen Endknoten in der entsprechenden Permutation πN bzw. πS (Nord bzw. Süd)
darstellen.
Jeder Datenpunkt in den folgenden Diagrammen entspricht einem Mittelwert von 100 Durchläufen
auf der gleichen Probleminstanz.
5.1
Testumgebung
Alle Laufzeittests wurden von den Autoren auf der selben Hardware ausgeführt (Sony Vaio
PCG-R600 Notebook mit Intel Pentium III Prozessor, 850 MHz und 256 MB Hauptspeicher). Zudem wurden alle Algorithmen mit dem selben Compiler (GNU gcc, Optimierungsoption 03 ) compiliert und alle Zufallszahlen von der Funktion gb unif rand aus der Stanford
GraphBase-Bibliothek [Knu93] generiert.
5.2
Dünne Graphen
Im ersten Laufzeittest wurden dünne Graphen von 1’000 bis 30’000 Knoten pro Lage und
2’000 bis 6’000 zufällig eingefügten Kanten als Eingabe verwendet.
Die wesentlichen Ergebnisse dieses Tests (Abbildung 11) sind:
• SAN und INS schneiden bei großen Problem-Instanzen sehr schlecht ab, während alle
anderen in ihren Laufzeiten deutlich besser sind und nah zusammen liegen.
• Außer bei SAN und INS gibt es zwischen den Laufzeiten bei Zufallsgraphen RAN und
vor-optimierten Graphen MED lediglich einen geringen Unterschied.
13
Abbildung 11: Laufzeiten für dünne Graphen
5.3
Dünne große Graphen
Dieses Verhalten zeigt sich auch, wenn man die Graphen entsprechend vergrößert. Dies ist
in Abbildung 12 zu sehen. Die Knotenzahl wurde schrittweise auf 500’000 pro Lage und
1’000’000 zufällig eingefügte Kanten erhöht.
Die beste Laufzeit wird dabei ab einer Knotenzahl von ca. 50’000 pro Lage von BJM erreicht.
5.4
Dichte Graphen
Im dritten Laufzeittest (Abbildung 13) wurde untersucht, wie sich die Laufzeiten verhalten,
wenn bei einer festen Knotenzahl von 1’000 pro Lage die Zahl der zufällig eingefügten Kanten
von 1’000 schrittweise auf 100’000 erhöht wird.
Ergebnisse dieses Tests:
• Wieder sind die Laufzeiten von SAN und INS gegenüber den anderen sehr hoch,
• Bis ca. 30’000 Kanten ist BJM der schnellste Algorithmus, ab dieser Kantenzahl ist
WAM etwas besser.
14
Abbildung 12: Laufzeiten für große dünne Graphen
5.5
AT&T-Graphen
Als letzte Testserie wurden noch einige Realwelt-Graphen aus der Graphen-Sammlung von
AT&T [Krü] verwendet. Dabei wurden jeweils mittels der Longest Path- und CoffmanGraham-Methode die Lagen-Paare extrahiert und als Eingabe für die Algorithmen verwendet.
Methode
Longest Path
Coffman-Graham
# Nordknoten
1 bis 6’556
1 bis 3’278
# Südknoten
1 bis 5’775
1 bis 3’278
# Kreuzungen
0 bis 10’155’835
0 bis 2’760’466
# Kreuzungen MED
0 bis 780’017
0 bis 2’2872
Wie man in Abbildung 14 sehen kann, führt der BJM-Algorithmus bei den Originaldaten,
während INS und SAN deutlich länger brauchen. Werden die Graphen aber mittels MedianHeuristik vor-optimiert, so schneiden INS und MER sehr gut ab. Dies ist auf die geringe
Kreuzungszahl zurückzuführen, von dessen Größe die Laufzeit dieser Algorithmen abhängt.
5.6
Zusammenfassung
Wählt man für das Zählen der Kantenkreuzungen den BJM, MER oder WAM-Algorithmus,
so erhält man stets gute Laufzeit-Resultate. Die Laufzeit ließe sich noch verbessern, wenn man
einen Hybrid-Algorithmus entwickelt, der entsprechend charakteristischer Graphenmerkmale
die optimale Methode wählt.
15
Abbildung 13: Laufzeiten für dichte Graphen
Dabei sollte beachtet werden, dass die Berechnung einer Median-optimierten Knotenfolge
laufzeittechnisch sogar minimal teurer als das Berechnen der Kantenkreuzungszahl mit einem der schnellen Algorithmen (BJM, WAM) ist.
Im untersuchten Artikel wurde somit eine Methode gezeigt, die Kantenkreuzungszahl in
einem Zweilagen-Graphen effizient zu lösen. Zusätzlich dazu ist der Algorithmus mit wenigen Programmzeilen zu realisieren, was ihn zu einer sehr interessanten Alternative zu den
bestehenden Algorithmen mit ähnlicher Laufzeit macht.
16
Abbildung 14: Laufzeiten für AT&T Graphen
Literatur
[BC92]
H. Edelsbrunner B. Chazelle. An optimal algorithm for intersecting line segments
in the plane. Journal of the ACM, 39:1–54, 1992.
[Cha86] B. Chazelle. Reporting and counting segment intersections. Journal of Computer
and System Sciences, 32:156–182, 1986.
[CW99] A. Malhotra C. Waddle. An e log e line crossing algorithm for levelled graphs. GD
1999, LNCS, 1731:59–70, 1999.
[Knu93] E. Knuth. The Stanford GraphBase: A platform for combinatorial computing.
Addison-Wesley, Reading, Massachusetts, 1993.
[Krü]
M. Krüger. http://www.graphdrawing.org, downloadquelle für at&t-graphen. MaxPlanck-Institut für Informatik in Saarbrücken.
[KS81]
M. Toda K. Sugiyama, S. Tagawa. Methods for visual understanding of hierarchical
system structures. IEEE Transactions on Systems, Man, and Cybernetics, 11:109–
125, 1981.
[MJ97]
P. Mutzel M. Jünger. 2-layer straight line crossing minimization: performance of
exact and heuristic algorithms. Journal of Graph Algorithms and Applications,
1:1–25, 1997.
[PE94]
N. Wormwald P. Eades. Edge crossings in drawings of bipartite graphs. Algorithmica, 11:379–403, 1994.
[San96]
G. Sander. Visualisierungstechniken für den Compilerbau. Pirrot Verlag & Druck,
Saarbrücken, 1996.
17
[THC90] R.L. Rivest T. H. Cormen, C. E. Leiserson. Introduction to algorithms. MIT Press,
Cambridge, 1990.
[WB02] P. Mutzel W. Barth, M. Jünger. Simple and efficient bilayer cross counting. GD
2002, LNCS, 2528:130–141, 2002.
18
Herunterladen