Leibniz Universität Hannover Fakultät für Elektrotechnik und Informatik Fachgebiet Datenbanken und Informationssysteme Studienarbeit im Studiengang Mathematik mit Studienrichtung Informatik Entwicklung und Optimierung eines Datenbankmoduls für Graphenalgorithmen 28. August 2006 Yvon Regis Tounkap Nkwate Matr.-Nr. 2143512 Prüfer: Prof. Dr. Udo Lipeck Betreuer: Prof. Dr. Udo Lipeck Inhaltsverzeichnis 1 Einleitung 1.1 Aufgabenstellung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.2 Gliederung dieser Arbeit . . . . . . . . . . . . . . . . . . . . . . . . . 4 4 4 2 Graphentheorie 2.1 Begriffe der Graphentheorie . . . . . . . . . . . . . . . . . . . . . 2.1.1 Definitionen und Beispiele . . . . . . . . . . . . . . . . . . 2.2 Transitive Hülle . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.2.1 Definition und Beispiel . . . . . . . . . . . . . . . . . . . . 2.2.2 Effiziente Berechnung der transitiven Hülle eines Graphen 2.3 Alle kürzesten Wege (“all sources shortest paths problem”) . . . . 5 5 5 7 7 7 8 . . . . . . . . . . . . 3 Darstellung der Graphen als Relationen und Implementierung der Algorithmen 10 3.1 Darstellung der Graphen als Relationen . . . . . . . . . . . . . . . . . 10 3.1.1 Darstellung eines Graphen als Relation für die Berechnung der transitiven Hülle . . . . . . . . . . . . . . . . . . . . . . . . . 11 3.1.2 Graphendarstellung zur Berechnung der kürzesten Wege . . . 12 3.2 Algorithmus zur Berechnung der transitiven Hülle bei einer vollständigen Speicherung eines Graphen als Relation . . . . . . . . . . . . . . . . . 13 3.3 Algorithmen zur Berechnung der transitiven Hülle bei einer unvollständigen Speicherung eines Graphen als Relation . . . . . . . . . . . 14 3.4 Algorithmen zur Berechnung aller kürzesten Wege von vollständig gespeicherten Graphen . . . . . . . . . . . . . . . . . . . . . . . . . . 17 3.4.1 Erster Algorithmus . . . . . . . . . . . . . . . . . . . . . . . . 17 3.4.2 Zweiter Algorithmus . . . . . . . . . . . . . . . . . . . . . . . 19 3.5 Algorithmen zur Berechnung aller kürzesten Wege von unvollständig gespeicherten Graphen . . . . . . . . . . . . . . . . . . . . . . . . . . 20 3.5.1 Erster Algorithmus . . . . . . . . . . . . . . . . . . . . . . . . 21 3.5.2 Zweiter Algorithmus . . . . . . . . . . . . . . . . . . . . . . . 22 3.5.3 Beispiel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24 3.5.4 Methoden für die Rekonstruktion der Wege . . . . . . . . . . 25 4 Tests der Algorithmen 26 4.1 Test der Algorithmen allshortestspathsA und AllshortestpathsB . . . 26 4.1.1 Bereitstellung der Testdaten . . . . . . . . . . . . . . . . . . . 26 2 Yvon Regis Tounkap Nkwate 4.2 4.1.2 Tests phen 4.2.1 4.2.2 4.2.3 4.2.4 4.2.5 4.2.6 5 Ausblick Kapitel 0 Studienarbeit Vergleich der Laufzeiten beider Algorithmen . . . . . . . . . der Algorithmen basierend auf unvollständig gespeicherte Gra. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Bereitstellung der Testdaten für die Berechnung der transitiven Hülle . . . . . . . . . . . . . . . . . . . . . . . . . . . . Vergleich der Laufzeiten der Algorithmen Floyd Warschall1/2/3 . . . . . . . . . . . . . . . . . . . . . Ausführungspläne der Hauptanfragen der Algorithmen . . . Bereitstellung der Testdaten für die Berechnung aller kürzesten Wege . . . . . . . . . . . . . . . . . . . . . . Vergleich der Laufzeit der Algorithmen Allshortestpaths1A/1B/2 . . . . . . . . . . . . . . . . . . . . Programmierung . . . . . . . . . . . . . . . . . . . . . . . . . 28 . 28 . 29 . 29 . 30 . 34 . 34 . 35 36 3 Kapitel 1 Einleitung 1.1 Aufgabenstellung Matrizen und Graphen sind als klassische Datenstrukturen mit dazu gehörenden Rechenoperationen und Algorithmen nicht mehr wegzudenken. Für bestimmte Anwendungsbereiche sind auch schon Matrixkonzepte in relationalen Datenbanksystemen umgesetzt worden. Ziel dieser Arbeit ist es für große Graphen, die in Datenbanken abgelegt sind, zu untersuchen, ob sich Algorithmen zur Berechnung der transitiven Hülle und zur Berechnung aller kürzester Wege (all sources shortest paths problem), die auf Adjazenzmatrizen basieren, effizient implementieren lassen. 1.2 Gliederung dieser Arbeit Die nachfolgenden Kapitel sind folgendermaßen gegliedert. Kapitel 2 erläutert grundlegende Begriffe der Graphentheorie. In diesem Kapitel wird die transitive Hülle eines gerichteten Graphen definiert und der Algorithmus von Floyd Warshall beschrieben. Dieser Algorithmus liefert eine effiziente Berechnung der transitiven Hülle eines gerichteten Graphen. Dann wird der Algorithmus zur Berechnung aller kürzester Wege und die Methoden zur Rekonstruktion dieser Wege vorgestellt. Kapitel 3 beschreibt zunächst die Darstellung der Graphen als Relationen. Dabei kann ein Graph vollständig oder unvollständig in einer Relation gespeichert werden. Für jede Speicherungsart werden verschiedene Algorithmen vorgestellt, die in PL/SQL die transitve Hülle und alle kürzeste Wege berechnen. In Kapitel 4 werden die aus dem vorherigen Kapitel vorgestellten Algorithmen getestet. Ihre Laufzeit werden verglichen um den besten Algorithmus zu bestimmen. Bei der Berechnung der transitiven Hülle von unvollständig gespeicherten Graphen werden Ausführungspläne der Hauptanfragen der Algorithmen kommentiert. Kapitel 5 gibt einen Ausblick über eine kritische Situation, die sich ergeben kann, und beschreibt eine mögliche Lösung, die noch untersucht werden soll. Kapitel 2 Graphentheorie In diesem Kapitel werden grundlegende Begriffe der Graphentheorie erläutert. Dann wird die transitive Hülle eines gerichteten Graphen definiert. Ihre effiziente Berechnung wird mit dem Algorithmus von Floyd-Warshall, basierend auf Adjazenzmatrizen, beschrieben. Zum Schluss wird der Algorithmus zur Berechnung aller kürzester Wege zusammen mit zwei Methoden zur Rekonstruktion dieser Wege vorgestellt. Für dieses Kapitel wurden Materialien aus [Li05-06] und [CT] entnommen. 2.1 2.1.1 Begriffe der Graphentheorie Definitionen und Beispiele Definition: Ein Graph ist in der Graphentheorie ein Gebilde aus Knoten (auch Ecken oder Punkte) genannt, die durch Kanten verbunden sein können. Somit ist ein Graph ein geordnetes Paar G = (V,E ) zweier Mengen V und E. Dabei bezeichnet V die Menge der im Graph enthaltenen Knoten. Knoten werden üblicherweise durch Zahlen oder Buchstaben bezeichnet. E bezeichnet die Menge der Kanten des Graphen. Eine Kante wird durch ein Paar, bestehend aus zwei verschiedenen Knoten, identifiziert. Die Bezeichnungen der Knotenmenge V und der Kantenmenge E stammen aus dem Englischen: V für vertices (engl. für Knoten) und E für edges (engl. für Kanten). Man unterscheidet in der Graphentheorie vor allem zwischen ungerichteten und gerichteten Graphen. Beispiel 1 a e b c d f Abbildung 2.1: ungerichteter Graph V = {a,b,c,d,e,f} ; E = {(a,b),(a,f),(b,c),(b,d),(e,d),(b,f)}. Yvon Regis Tounkap Nkwate Studienarbeit Beispiel 2 b a d c Abbildung 2.2: gerichteter Graph V = {a,b,c,d} ; E = {(a,b),(b,a),(b,c),(a,d)}. In einem gerichteten Graphen haben wir geordnete Paare, d.h. wir unterscheiden (a,b) und (b,a). Die Kanten eines Graphen können mit einer Marke (Gewicht, engl. weight) versehen werden, und man spricht dann von einem gewichteten Graph. Gewichte können zum Beispiel Abstände, Zeiten oder Kosten darstellen. Beispiel 3 4 1 6 2 3 Abbildung 2.3: gewichteter und gerichteter Graph Ein gerichteter Graph g (er kann auch gewichtet sein) kann als Adjazenzmatrix dargestellt werden. Eine Adjazenzmatrix von g ist eine Matrix M (mit n Zeilen und n Spalten falls |V | = n) , die zu jedem Paar von Knoten (i,j ) genau einen booleanEintrag hat: • M [i,j ]= T (oder 1) bedeutet, dass der Graph eine Kante (i,j ) hat. • M [i,j ]= F (oder 0) bedeutet, dass der Graph keine Kante (i,j ) hat. Falls der Graph gerichtet ist gilt: • M [i,j ]= Gewicht von (i,j ), falls (i,j ) ∈ E • M [i,j ]= +∞ falls es keine Kante (i,j ) ∈ E gibt. Beispiel: Der Graph in Abbildung 2.3 entspricht folgender Adjazenzmatrix: Kapitel 2 6 Yvon Regis Tounkap Nkwate Studienarbeit 1 2 1 +∞ +∞ 2 4 +∞ 3 +∞ +∞ 3 6 +∞ +∞ Tabelle 2.1: Darstellung des Graphen als Adjazenzmatrix Die folgenden Algorithmen setzen voraus, dass der Graph gerichtet (Berechnung der transitiven Hülle) und gewichtet ist (all sources shortest paths problem). 2.2 Transitive Hülle 2.2.1 Definition und Beispiel Definition Die transitive Hülle eines gerichteten Graphen G =(V,E ) ist der gerichtete Graph G + = (V,E + ) mit E + = {(u,v ) mit u,v ∈ V, u 6= v und es gibt einen gerichteten Pfad von u nach v }. Beispiel A B A C E D B C D E Abbildung 2.4: Die transitive Hülle G + (rechts) von G(links) 2.2.2 Effiziente Berechnung der transitiven Hülle eines Graphen Sei G ein Graph mit der Knotenmenge {1,...,n} als Adjazenzmatrix dargestellt. Falls also eine Kante (i, j ) in G existiert gilt G[i,j ] = 1, ansonsten G[i,j ] = 0. Die transitive Hülle von G, wird im Graph H, als Adjazenzmatrix dargestellt gespeichert. Ansatz: Die Kanten im schrittweise enstehenden Ergebnisgraphen (H ) sollen nach dem k -ten Durchlauf genau denjenigen Pfaden in G entsprechen, die nur Zwischenknoten aus der Menge {1,...,k } enthalten! Zum Schluss (k = n) sind alle Pfade erfasst. Kapitel 2 7 Yvon Regis Tounkap Nkwate 1 2 3 4 5 6 7 8 9 10 11 Studienarbeit algorithm Floyd-Warshall(G):Graph: Eingabe: gerichter Graph G mit Knoten 1,...,n als Adjazenzmatrix Ausgabe: transitive Hülle H = G + von G als Adjazenzmatrix H ← G; //kopiere G, so dass der Graph nicht verändert wird for k ← 1,2,...,n do for i, j ← 1,2,...,n do if (i 6= j and i 6= k and j 6= k then) if (H [i,j ] 6= 1 and H [i,k ] = 1 and H [k,j ] = 1) then H [i,j ] ← 1; return H ; Zum Kernschritt des Algorithmus: Ein Pfad vom Knoten i nach j nur über Zwischenknoten aus {1,...,k } kann sein: • entweder ein Pfad von i nach j nur über Zwischenknoten aus {1,...,k -1} • oder ein Pfad von i nach k nur über Zwischenknoten aus {1,...,k -1} gefolgt von einem Pfad von k nach j nur über Zwischenknoten aus {1,...,k -1}. j i k Abbildung 2.5: Zwischenknoten k In Abbildung 2.5 stellen die gestrichelten Linien die Pfade nur über Zwischenknoten aus {1,...,k -1} dar. Sofern es also in H für (i,j ) nicht schon eine Kante aus dem (k -1)-ten Durchlauf gibt (H [i,j ] 6= 1) , wird in H eine Kante im k -ten Durchlauf neu eingetragen (H [i,j ] ← 1), wenn es in H Kanten (i,k ) (and H [i,k ] = 1) und (k,j ) (and H [k,j ] = 1) aus früheren Schleifendurchläufen gibt. Beachte: der Algorithmus arbeitet in-place bzgl. H. Laufzeit: das Einfügen und das Feststellen der Existenz einer Kante benötigen bei einer Adjazenzmatrix O(1). Also hat Floyd-Warshall offensichtlich eine Laufzeit von O(n 3 ). 2.3 Alle kürzesten Wege (“all sources shortest paths problem”) Die Gewichte der kürzesten Wege (die Entfernungen) zwischen allen Knoten eines gerichteten gewichteten Graphen G kann man mit einer geschickten Variante des Floyd-Warshall-Algorithmus auf die Adjazenzmatrix von G berechnen, wiederum in O(n 3 ). Zudem sollen während des Algorithmus Informationen festgehalten werden, um die Wege rekonstruieren zu können. Kapitel 2 8 Yvon Regis Tounkap Nkwate Studienarbeit Sei G der Originalgraph mit n Knoten (Nummern) 1,...,n. H sei eine n×nAdjazenzmatrix zur Berechnung der Entfernungen zwischen allen Knoten; P sei eine n×n-Matrix, welche die maximalen Nummern von Zwischenknoten abspeichern soll. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 algorithm AllshortestPaths(G): Eingabe: gerichter gewichteter Graph G mit Knoten 1,...,n als Adjazenzmatrix Ausgabe: Graph H als Adjacentmatrix, in der die Länge der kürzesten Wege zwischen den Knoten von G gespeichert sind. Zusätzlich wird die Matrix P zur Rekonstruktion der kürzesten Wege ausgegeben. H ← G; //kopiere G, so dass der Graph nicht verändert wird for k ← 1,...,n do //analog Floyd-Warshall for i ← 1,...,n do for j ← 1,...,n do if (i 6= j and i 6= k and j 6= k ) then if (H [i,j ] + H [k,j ]) ≤ H [i,j ] then H [i,j ] ← H [i,k ] + H [k,j ]; // Erklärung (*) s.u. P [i,j ] ← k ; return H ; return P ; (*) Anstatt also eine neue Kante hinzuzufügen, wird geprüft, ob der Weg über einen Zwischenknoten k kürzer ist als der direkte Weg, und es wird der jeweils kürzere Weg eingetragen. Dabei können i und j auch adjazent sein. Die Matrix P enthält im Eintrag P [i,j ] den Knoten mit der maximalen Nummer auf dem kürzesten Weg von i nach j. Die Rekonstruktion dieses Weges funktioniert mit den rekursiven Methoden path und between: method path(i,j ) if H [i,j ] 6= ∞ then write(“von Knoten ”i ); between(i,j ); write( “nach Knoten ”j ); else write( “kein Weg ”) Hilfsmethode between: method between(i,j ): Knoten k ← P [i,j ]; if k 6= 0 then between(i,k ); write(“über Knoten ”k ); between(k,j ). . Kapitel 2 9 Kapitel 3 Darstellung der Graphen als Relationen und Implementierung der Algorithmen In diesem Kapitel wird zunächst beschrieben, wie gerichtete Graphen, deren transitive Hülle berechnet werden soll, in einer relationalen Datenbank gespeichert werden können. Ebenso wird für gerichtete gewichtete Graphen für die alle kürzesten Wege zwischen den Knoten ermittelt und rekonstruiert werden sollen, eine mögliche Darstellung als Relation vorgestellt. Dabei kann der Graph sowohl bei der Berechnung der transitiven Hülle als auch bei der Berechnung aller kürzesten Wege vollständig oder unvollständig (wie bei dünnbesetzten Matrizen) gespeichert werden. Im Falle einer vollständigen Speicherung wird für alle Knoten i, j aus der Knotenmenge eine Kante (i,j ) und die Information, ob sie existiert oder nicht, in der Relation eingetragen. Im Falle einer unvollständigen Speicherung, werden nur existierende Kanten eines Graphen gespeichert. Dann wird im Falle einer vollständigen Speicherung eines Graphen als Relation für die Berechnung der transitiven Hülle ein PL/SQL-Algorithmus vorgestellt. Für die Berechnung aller kürzesten Wege werden zwei Algorithmen vorgestellt. Im Falle einer unvollständigen Speicherung werden für die Berechnung der transitiven Hülle drei PL/SQL-Algorithmen vorgestellt . Für die Berechnung aller kürzesten Wege werden zwei Algorithmen vorgestellt, wobei einer davon in zwei Varianten geschrieben werden kann. Alle diese Algorithmen basieren auf dem Floyd Warschall-Algorithmus. Anschließend werden für die Rekonstruktion der berechneten kürzesten Wege zwei PL/SQLMethoden vorgestellt. 3.1 Darstellung der Graphen als Relationen In diesem Abschnitt soll festgelegt werden, wie gerichtete (und gewichtete) Graphen in Relationen gespeichert werden können. Möchte man nach der Berechnung aller kürzesten Wege auch diese Wege rekonstruieren, so soll vorher dafür gesorgt werden, daß Zwischenknoten auf einem kürzesten Pfad gespeichert werden. Diese Zwischenknoten sind bei der Berechnung der transitiven Hülle irrelevant. Dies führt Yvon Regis Tounkap Nkwate Studienarbeit uns zu einer unterschiedlichen Darstellung eines Graphen als Relation für die Berechnung der transitiven Hülle und die Berechnung aller kürzesten Wege. 3.1.1 Darstellung eines Graphen als Relation für die Berechnung der transitiven Hülle Ein Graph, dessen transitive Hülle berechnet werden soll, wird in einer Relation als Adjazenzmatrix gespeichert mit folgenden Spaltennamen und zugehörigen Datentypen. Spaltenname knoteni knotenj kanteij Datentyp number (eine natürliche Zahl größer als 0) number (eine natürliche Zahl größer als 0) number (Werte: 0 oder 1) Tabelle 3.1: Darstellung eines Graphen als Relation 1 Beschreibung der Spalten: • Die Spalte knoteni speichert die Nummer eines Knotens. • Die Spalte knotenj speichert die Nummer eines Knotens. • Die Spalte kanteij hat den Wert 1, falls es einen Weg von Knoten i nach Knoten j gibt und den Wert 0 sonst. Bemerkung: 1. Im Falle einer unvöllständigen Speicherung kann die Spalte kanteij nie den Wert 0 annehmen, da nur existierende Kante gespeichert werden. 2. Nach der Berechnung der transitiven Hülle wird für alle Knoten i, j mit j 6= i in der Relation eingetragen, ob es einen Weg von i nach j gibt. Da die transitive Hülle keine Information über mögliche Schleifen enthält muss gelten j 6= i ! Beispiel 1: Der Graph G = (V,E ) mit der Knotenmenge V={(1,2,3)} und Kantenmenge E ={(1,2),(1,3),(2,1)} 1 2 3 Abbildung 3.1: Beispiel 1 entspricht der Relation (vollständige Speicherung) Kapitel 3 11 Yvon Regis Tounkap Nkwate knoteni 1 1 1 2 2 2 3 3 3 Studienarbeit knotenj 1 2 3 1 2 3 1 2 3 kanteij 0 1 1 1 0 0 0 0 0 Tabelle 3.2: Graph als Relation 1 Bei unvollständiger Speicherung sind die Datensätze, in denen die Spalte kanteij den Wert 0 hat, nicht vorhanden. 3.1.2 Graphendarstellung zur Berechnung der kürzesten Wege Die gerichteten gewichteten Graphen, für die alle kürzesten Wege berechnet werden sollen, werden in Tabellen mit folgenden Spaltennamen und zugehörigen Datentypen gespeichert. Spaltenname knoteni knotenj kanteij zwischenknoten Datentyp number (eine natürliche Zahl größer als 0) number (eine natürliche Zahl größer als 0) number (eine positive reelle Zahl oder null) number (eine natürliche Zahl) Tabelle 3.3: Darstellung eines Graphen als Relation 2 Beschreibung der Spalten: • Die Spalten knoteni und knotenj speichern jeweils Knotennummern. • Die Spalte kanteij speichert das Gewicht der Kante, die von i nach j führt, falls sie existiert, sonst hat sie den Wert null. • Die Spalte zwischenknoten speichert die maximale Knotennummer auf dem kürzesten Weg von i nach j. Falls für ein Paar (i,j ) die Spalte den Wert 0 hat, bedeutet dies, dass es keinen Zwischenknoten k mit k 6= i, und k 6=j gibt auf dem kürzesten Weg von i nach j. Bemerkung: Bei einer unvollständigen Speicherung eines Graphen als Relation, kann die Spalte kanteij nie den Wert null annehmen. Kapitel 3 12 Yvon Regis Tounkap Nkwate Studienarbeit Beispiel 2: Der Graph G = (V,E ) mit der Knotenmenge V={(1,2,3)} und Kantenmenge E ={(2,1),(1,3)} 4 2 1 6 3 Abbildung 3.2: Beispiel 2 entspricht der Relation knoteni 1 1 1 2 2 2 3 3 3 knotenj 1 2 3 1 2 3 1 2 3 kanteij null null 6 4 null null null null null zwischenknoten 0 0 0 0 0 0 0 0 0 Tabelle 3.4: Graph als Relation 2 Bei einer unvollständigen Darstellung sind die Tupeln, deren Feld kanteij den Wert null hat nicht gespeichert. 3.2 Algorithmus zur Berechnung der transitiven Hülle bei einer vollständigen Speicherung eines Graphen als Relation Der folgende PL/SQL-Algorithmus basiert zwar auf dem Floyd-Warshall-Algorithmus, unterscheidet sich aber vom Algorithmus aus Kapitel 2 Abschnitt 2.2.2 (Seite 9). Der wesentliche Unterschied besteht darin, dass die (i,j)-Schleifen (von Seite 9) durch mengenorientierte Anweisungen ersetzt werden. Durch eine einzige SELECTAnfrage wird entschieden, ob sich zwei Knoten i und j (i 6= j ) durch einen Zwischenknoten k mit i 6= k und j 6= k verbinden lassen. Es gibt eine einzige for-Schleife, in der die Knotenmenge durchlaufen wird und alle Knoten als mögliche Zwischenknoten bearbeiten werden. Im k -ten Schleifendurchlauf werden durch eine SELECT-Anfrage die Knotenpaare (i,j ) mit i 6= k und Kapitel 3 13 Yvon Regis Tounkap Nkwate Studienarbeit j 6= k, die sich durch Zwischenknoten k verbinden lassen bestimmt. Die Spalte Kanteij wird dann durch eine UPDATE-Anweisung für diese Knotenpaare auf 1 gesetzt. Pseudocode zum Algorithmus. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 algorithm Floyd-WarshallA(G) Eingabe: gerichteter Graph G mit Knoten 1,...,n als Relation gemäß Darstellung im Abschnitt 3.1.1. Ausgabe: transitive Hülle H = G + von G als Relation gemäß Darstellung im Abschnitt 3.1.1. H ← G; for k ← 1,2,...,n do UPDATE H SET kanteij = 1 WHERE (knoteni,knotenj) IN (SELECT a.knoteni knoteni,b.knotenj knotenj FROM H a JOIN H b ON (a.knotenj = b.knoteni) WHERE a.knotenj = k AND b.knoteni = k AND a.kanteij = 1 AND b.kanteij = 1 AND a.knoteni <> b.knotenj); return H ; Kommentare zum Algorithmus • Von Zeile 8 bis Zeile 18: Im k -ten Schleifendurchlauf werden die Start (knoteni ) und Endknoten (knotenj ) von den Pfaden, die man mit Zwischenknoten aus der Menge 1,..k erhält bestimmt. In der Relation H wird im Datenfeld mit den betroffenen Start und Endknoten das Feld kanteij auf 1 gesetzt. • Die Bedingungen in Zeile 14 und 15 sorgen dafür, daß alle mögliche Pfade mit k als höchste Nummer eines Zwischenknoten bestimmt werden. • Die Bedingungen in Zeile 16 und 17 sorgen dafür, daß nur die existierenden Pfade mit k als höchste Nummer eines Zwischenknotens bestimmt werden. • Die Bedingung in Zeile 18 sorgt dafür, daß Start und Endknoten eines Pfades nicht übereinstimmen. (keine Schleife in der Ergebnisrelation!). 3.3 Algorithmen zur Berechnung der transitiven Hülle bei einer unvollständigen Speicherung eines Graphen als Relation Wir haben in diesem Abschnitt mit Graphen, die unvollständig gespeichert werden, zu tun. Da nur existierende Kanten dargestellt werden und somit die KnotennumKapitel 3 14 Yvon Regis Tounkap Nkwate Studienarbeit merierung nicht mehr fortlaufend ist, muss der vorige Algorithmus angepaßt werden. Wir benötigen wie vorher nur eine Schleife, um alle Knoten als mögliche Zwischenknoten zu bearbeiten. Im Gegensatz zum Algorithmus bei einer vollständigen Speicherung müssen nur Startknoten existierender Kanten als Zwischenknoten bearbeitet werden. Somit stimmt die Anzahl der Schleifendurchläufe mit der maximalen Nummer eines Startknotens einer existierenden Kante überein. Im k -ten Schleifendurchlauf (falls k Startknoten einer Kante ist) wird zunächst (durch eine SELECT-Anfrage) für jedes Paar (i,j ) mit i 6= k und j 6= k bestimmt, ob sich i und j durch k verbinden lassen. Ist dies der Fall, wird dann mit einer Insert-Anweisung das Tripel (i,j,1) in der Relation eingetragen. Aber es werden nur Tripel eingetragen, die es noch nicht in der Relation gibt. Durch geeignete Operationen (MINUS oder LEFT-OUTER-JOIN oder ANTI-SEMI-JOIN) werden dann die zulässigen Tripel gefiltert. Es ergeben sich somit drei mögliche Algorithmen. Erster Algorithmus (MINUS-Variante): 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 algorithm Floyd-Warshall1(G) Eingabe: gerichteter Graph G unvollständig als Relation gespeichert gemäß Darstellung im Abschnitt 3.1.1. Ausgabe: transitive Hülle H = G + von G als Relation gemäß Darstellung im Abschnitt 3.1.1. H ← G; number n ← SELECT MAX(knoteni) FROM H ; number k ← SELECT MIN(knoteni) FROM H ; for k <= n do INSERT INTO H (SELECT a.knoteni knoteni,a.knotenj knotenj,a.kanteij kanteij FROM H a JOIN H b ON (a.knotenj = b.knoteni) WHERE a.knotenj = k AND b.knoteni = k AND a.knoteni <> b.knotenj) MINUS SELECT knoteni,knotenj,kanteij FROM H x WHERE knoteni = x.knoteni AND knotenj = x.knotenj; k ← SELECT MIN(knoteni) FROM H WHERE knoteni > k ; return H ; Kommentare zum Algorithmus • Zeile 7 und Zeile 9: da die Knotennummerierung nicht mehr fortlaufend ist, ist nicht gewährleistet, dass für einen Graphen mit n Knoten, jeder Knoten Startpunkt einer ausgehenden Kante ist. Die Knoten, die als Zwischenknoten in Frage kommen, stehen in der Spalte knoteni und ihre Nummerierung ist nicht stetig. In Zeile 7 wird die maximale Nummer eines Knotens einer ausgehenden Kante bestimmt und in n gespeichert. Die Anzahl der Schleifendurchläufe Kapitel 3 15 Yvon Regis Tounkap Nkwate Studienarbeit muss n nicht überschreiten. In Zeile 8 wird der erte in Frage kommende Zwichenknoten (es muss nicht 1 sein!) bestimmt, zum ersten Schleifendurchlauf. • Von Zeile 11 bis Zeile 16: Es werden Startknoten und Endknoten von Pfaden mit k als Zwischenknoten bestimmt. • Von Zeile 17 bis Zeile 20: Von den berechneten Verbindungen werden diejenigen, die schon in der Tabelle vorhanden sind aussortiert (MINUS) und nicht mehr eingefügt. • In Zeile 21 wird die nächste Zwischenknotennummer für den nächsten Schleifendurchlauf bestimmt. Zweiter Algorithmus (ANTI-SEMI-JOIN-Variante): Der wesentliche Unterschied zwischen diesem Algorithmus und dem Vorigen besteht darin, dass statt der Benutzung eines MINUS-Operators, um schon in der Relation existierende Verbindungen nicht ein zweites Mal einzufügen, man einen ANTI-SEMIJOIN (in SQL mit NOT EXISTS umgesetzt) benutzt. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 algorithm Floyd-Warshall2(G) //Gleiche Anweisungen wie beim ersten Algorithmus ... INSERT INTO H (SELECT a.knoteni knoteni, a.knotenj knotenj, a.kanteij kanteij FROM H a JOIN H b ON (a.knotenj = b.knoteni) WHERE a.knotenj = k AND b.knoteni = k AND a.knoteni <> b.knotenj AND NOT EXISTS (SELECT knoteni, knotenj, kanteij FROM H x WHERE a.knoteni = x.knoteni AND b.knotenj = x.knotenj)); ... //Gleiche Anweisungen wie beim ersten Algorithmus. Dritter Algorithmus (LEFT-OUTER-JOIN-Variante): Dieser Algorithmus unterscheidet sich von den anderen dadurch, dass mit Hilfe eines LEFT OUTER JOIN mit geeigneter JOIN-Bedingung nur die Pfade, die noch nicht existieren, in die Relation eingefügt werden. Die restlichen Anweisungen sind zu den vorigen Algorithmen äquivalent. Kapitel 3 16 Yvon Regis Tounkap Nkwate 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 Studienarbeit algorithm Floyd-Warshall3(G) //Gleiche Anweisungen wie beim ersten Algorithmus ... INSERT INTO H (SELECT a.knoteni knoteni, a.knotenj knotenj, a.kanteij kanteij FROM H a JOIN H b ON (a.knotenj = b.knoteni) LEFT OUTER JOIN H c ON (a.knoteni = c.knoteni AND b.knotenj = c.knotenj) WHERE a.knotenj = k AND b.knoteni = k AND a.knoteni <> b.knotenj AND c.kanteij IS NULL) ... //Gleiche Anweisungen wie beim ersten Algorithmus. Bemerkung: Welcher Algorithmus der beste ist, wird sich im vierten Kapitel zeigen. Die Algorithmen werden mit einer großen Datenmenge getestet und wir werden ihre Laufzeiten vergleichen. 3.4 Algorithmen zur Berechnung aller kürzesten Wege von vollständig gespeicherten Graphen Die folgenden Algorithmen basieren wieder auf dem Floyd-Warshall Algorithmus. Diese Algorithmen verfolgen denselben Ansatz. Es wird im ersten Schritt für alle Knoten i,j, k mit i 6= j 6= k 6= i aus der Knotenmenge bestimmt, ob i und j sich durch k verbinden lassen. Im gleichen Schritt wird die Länge des Weges von i nach j über k berechnet und mit der alten Länge eines Weges zwischen diesen beiden Knoten verglichen. Kann vom Startknoten i über Zwischenknoten k, der Endknoten j mit einem kürzeren Weg erreicht werden, so muss das Tupel (i,j,Länge des Weges,k ) in der Relation stehen. Im zweiten Schritt wollen wir dafür sorgen, dass das vorher ermittelte Tupel (i,j,Länge des Weges,k ) richtig in der Relation eingetragen wird. Es ergeben sich zwei Möglichkeiten: Die erste benutzt nur mengenorientierte Operationen und die zweite arbeitet tupelweise. 3.4.1 Erster Algorithmus Dieser erste Algorithmus berechnet für einen Graph G, der vollständig in einer Relation gespeichert ist, alle kürzeste Wege. Diese Wege werden dann in einer Relation H gespeichert. Zunächst werden für alle Knoten k die Startknoten(i ), Endknoten(j ) und Länge der Wege (aij ), die man mit Zwischenknoten k erreichen kann, berechnet. Dies geschieht mit einer SELECT-Anfrage. Dann werden die Tupeln (i,j,aij,k ) durch eine INSERT-Anweisung in die Tabelle eingefügt. Da es nach dem Einfügen eines solchen Tupels ein anderes Tupel (x,y,axy,w ) mit i = x , j = y, aber axy Kapitel 3 17 Yvon Regis Tounkap Nkwate Studienarbeit > aij geben kann, wird das Tupel (x,y,axy,w ) aus der Tabelle gelöscht (mit einer DELETE-Anweisung) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 . 15 16 17 18 19 20 21 22 23 24 25 26 27 28 algorithm AllshortestpathsA(G) Eingabe: gerichteter gewichteter Graph G mit Knoten 1,...,n als Relation gemäß Darstellung im Abschnitt 3.1.2. Ausgabe: Graph H als Relation gemäß Darstellung im Abschnitt 3.1.2., in der die Länge der kürzesten Wege zwischen den Knoten von G gespeichert sind und diese Wege auch rekonstruiert werden können. H ← G; for k ← 1,2,...,n do INSERT INTO H SELECT a.knoteni knoteni, b.knotenj knotenj (a.kanteij + b.kanteij)kanteij, a.knotenj zwischenknoten FROM H a JOIN H b ON (a.knotenj = b.knoteni) JOIN H c ON (a.knoteni = c.knoteni AND b.knotenj = c.knotenj) WHERE (a.knotenj = k AND b.knoteni = k AND a.kanteij IS NOT NULL AND b.kanteij IS NOT NULL) AND ((a.kanteij + b.kanteij)< c.kanteij OR c.kanteij IS NULL) AND a.knoteni <> b.knotenj; DELETE FROM H WHERE (knoteni, knotenj, zwischenknoten) IN( SELECT b.knoteni, b.knotenj, b.zwischenknoten FROM H a, JOIN H b ON (a.knoteni = b.knoteni AND a.knotenj = b.knotenj) WHERE (a.kanteij < b.kanteij OR b.kanteij IS NULL AND a.kanteij IS NOT NULL AND a.zwischenknoten = k ); return H ; Kommentare zum Algorithmus • Von Zeile 9 bis Zeile 18: Es werden im k -ten Schleifendurchlauf Startknoten (i ), Endknoten (j ) und Länge der kürzesten Pfade (aij ), die man mit Zwischenknoten aus der Menge {1,..,k } erhält, bestimmt. Dann werden diese neuen Pfade (identiziert durch (i,j,k,aij ) und im folgenden k -Pfade genannt...) in die Tabelle H eingefügt, mit k als Wert für die Spalte zwischenknoten. • Von Zeile 20 bis 27: Da es nach dem Einfügen von k -Pfaden in H zwei Datenfelder geben kann mit gleichem Startknoten (Spalte knoteni ) und gleichem Endknoten (Spalte knotenj ), die sich aber in den Spalten kanteij und zwischenknoten unterscheiden, wird das Datenfeld mit größtem Wert in der Spalte kanteij (also der längste Pfad) oder mit null als Wert der Spalte kanteij (nicht vorhandene Verbindung) gelöscht. Kapitel 3 18 Yvon Regis Tounkap Nkwate Studienarbeit • die Bedingungen der WHERE-Klausel (Zeile 25-27) sorgen dafür, daß die existierenden Pfade mit ähnlichem Start- und Enknoten wie die k -Pfade, die aber länger sind, gelöscht werden. Falls die k -Pfade neue gefundene Wege zwischen zwei Knoten sind, wird die Information (das entsprechende Tupel), dass die betroffenen Knoten nicht verbunden waren, aus der Tabelle gelöscht. 3.4.2 Zweiter Algorithmus Der zweite Algorithmus bekommt wieder als Eingabe einen Graph G, der vollständig in einer Relation gespeichert ist und liefert die Tabelle H zurück, in der alle kürzesten Wege gespeichert sind. Diese Wege können auch anschließend rekonstruiert werden. G wird zunächst in H kopiert. Die Bestimmung der k -Pfade im k -ten Schleifendurchlauf geschieht mit der gleichen SELECT-Anfrage wie beim ersten Algorithmus. Im Gegensatz zum ersten Algorithmus werden diese Pfade nicht mit einer INSERTAnweisung eingefügt. Die DELETE-Anweisung, um nicht mehr gültige Verbindungen zu löschen, entfällt auch. Statt dessen werden zunächst in einem Cursor K die k -Pfade gespeichert. Für jeden k -Pfad (i,j,aij,k ) in dem Cursor K wird mit einer UPDATE-Anweisung in der Tabelle H das Tupel mit dem Feld knoteni = i und dem Feld knotenj = j in den Feldern kanteij und zwischenknoten mit den Werten i und aij aktualisiert. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 algorithm AllshortestpathsB(G) Eingabe: gerichteter gewichter Graph G mit Knoten 1,...,n als Relation gemäß Darstellung im Abschnitt 3.1.2. Ausgabe: Graph H als Relation gemäß Darstellung im Abschnitt 3.1.2., in der die Länge der kürzesten Wege zwischen den Knoten von G gespeichert sind und diese Wege auch rekonstruiert werden können. H ← G; Cursor K ; for k ← 1,2,...,n do K ←SELECT a.knoteni knoteni, b.knotenj knotenj (a.kanteij + b.kanteij)kanteij, a.knotenj zwischenknoten FR0OM H a JOIN H b ON (a.knotenj = b.knoteni) JOIN H c ON (a.knoteni = c.knoteni AND b.knotenj = c.knotenj) WHERE (a.knotenj = k AND b.knoteni = k AND a.kanteij IS NOT NULL AND b.kanteij IS NOT NULL) AND ((a.kanteij + b.kanteij)< c.kanteij OR c.kanteij IS NULL) AND a.knoteni <> b.knotenj; for r in K do UPDATE H SET kanteij = r.kanteij, zwischenknoten =r.zwischenknoten WHERE knoteni = r.knoteni and knotenj = r.knotenj return H ; Kommentare zum Algorithmus Kapitel 3 19 Yvon Regis Tounkap Nkwate Studienarbeit • Zeile 8: Der Cursor K wird definiert. Jede Zeile von K hat diegleiche Struktur wie eine Zeile der Tabelle H. • Von Zeile 10 bis Zeile 19: solange noch nicht alle Knoten bearbeitet wurden, werden im k -ten Schleifendurchlauf in dem Cursor K die k -Pfade gespeichert. • Die Bedingung in Zeile 16 sorgt dafür, daß alle mögliche Pfade mit k als höchste Nummer eines Zwischenknoten bestimmt werden. • Die Bedingung in Zeile 17 sorgt dafür, daß nur die existierenden Pfade mit k als höchste Nummer eines Zwischenknoten bestimmt werden. • die Bedingung in Zeile 18 sorgt dafür, daß von den existierenden Pfaden mit k als höchste Nummer eines Zwischenknoten, nur die kürzesten bestimmt werden. Es wird ein Vergleich zwischen der Länge der bisjehrigen Pfade (falls sie existieren) und der Länge der k -Pfade gemacht. Falls die k -Pfade kleiner sind, so werden sie in dem Cursor K eingefügt. Falls zwei Knoten nicht vorher verbunden waren, aber durch k verbunden werden, wird die neue Verbindung auch in K gespeichert. • Die Bedingung in Zeile 19 sorgt dafür, daß Start und Endknoten eines k -Pfades nicht übereinstimmen. • Von Zeile 20 bis 23: Mit Hilfe des Startknoten und des Endknoten eines berechneten kürzesten Weges, wird durch eine UPDATE-Anweisung in der Tabelle H an der richtigen Stelle die Länge des Weges und die zugehörige Zwischenknotennummer (k, im k -ten Schleifendurchlauf) eingetragen. Der Kursor K wird dabei geöffnet und Zeile für Zeile geleert (also keine Mengenoperation). Bemerkung: Welcher Algorithmus zu bevorzugen ist, wird sich im vierten Kapitel zeigen. Da werden beide Algorithmen mit großen Graphen getestet und ihre Laufzeiten verglichen. 3.5 Algorithmen zur Berechnung aller kürzesten Wege von unvollständig gespeicherten Graphen In diesem Abschnitt arbeiten wir mit gerichteten gewichteten Graphen, die unvollständig in Relationen gespeichert werden. Die Bestimmung aller kürzesten Wege geschieht anders, als bei vollständig gespeicherten Graphen. Zu beachten ist wieder, dass die Knotennummerierung nicht fortlaufend ist. Also nicht alle Knoten aus {1,...,n} sind Startknoten einer Kante. Startknoten von Kanten sind in der Spalte knoteni gespeichert. Wir benötigen wieder eine Schleife, um alle Starknoten von Kanten als Zwischenknoten zu bearbeiten und somit die k -Pfade zu bestimmen. Der wesentliche Unterschied mit den Algorithmen bei einer vollständigen Speicherung liegt in der SELECT-Anfrage zur Bestimmung der k -Pfade. Die k -Pfade Kapitel 3 20 Yvon Regis Tounkap Nkwate Studienarbeit sind entstanden, in dem wir im k -ten Schleifendurchlauf, für zwei Knoten i und j, aik (Gewicht der Kante von i nach k ) + akj (Gewicht der Kante von k nach j ) mit aij (Gewicht der Kante von i nach j ) verglichen haben. Dieser Vergleich wurde durch den letzen JOIN (mit passenden Bedingungen) zwischen den Relationen ermöglicht.Bei vollständig gespeicherten Graphen werden wir einen LEFT-OUTERJOIN benutzen um den Vergleich zu machen. Somit können auch gerade berechnete Verbindungen, die aber noch nicht im Graph existieren, nicht verloren gehen. Statt eines LEFT OUTER JOIN kann man auch einen ANTI-SEMI-JOIN benutzen. Unterschiede zwischen den folgenden Algorithmen werden sich, wie im Abschnitt dadurch 3.4 ergeben , daß der erste Algorithmus wieder mit INSERT und DELETE arbeitet, während der zweite Algorithmus wieder einen Cursor K benutzt. Der Kursor K behält wie im Abschnitt 3. 4 die gleiche Funktionalität. 3.5.1 Erster Algorithmus LEFT OUTER JOIN-Variante 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 algorithm Allshortestpaths1A(G) Eingabe: gerichteter gewichteter Graph G unvollständig in einer Relation gespeichert gemäß Darstellung im Abschnitt 3.1.2. Ausgabe: Graph H als Relation gemäß Darstellung im Abschnitt 3.1.2., in der die Länge der kürzesten Wege zwischen den Knoten von G gespeichert sind und diese Wege auch rekonstruiert werden können. H ← G; number n ← SELECT MAX(knoteni) FROM H ; number k ← SELECT MIN(knoteni) FROM H ; for k <= n do INSERT INTO H SELECT a.knoteni knoteni, b.knotenj knotenj (a.kanteij + b.kanteij)kanteij, a.knotenj zwischenknoten FROM H a JOIN H b ON (a.knotenj = b.knoteni) LEFT OUTER JOIN H c ON (a.knoteni = c.knoteni AND b.knotenj = c.knotenj) WHERE (a.knotenj = k AND b.knoteni = k AND ((a.kanteij + b.kanteij)< c.kanteij OR c.kanteij IS NULL) AND a.knoteni <> b.knotenj; Kapitel 3 DELETE FROM H WHERE (knoteni, knotenj, kanteij, zwischenknoten) IN( SELECT b.knoteni, b.knotenj, b.kanteij, b.zwischenknoten FROM H a,JOIN H b ON (a.knoteni = b.knoteni AND a.knotenj = b.knotenj) WHERE (a.kanteij < b.kanteij AND a.zwischenknoten = k ); 21 Yvon Regis Tounkap Nkwate 29 30 Studienarbeit k ← SELECT MIN(knoteni) FROM H WHERE knoteni > k ; return H ; Kommentare: • Von Zeile 11 bis Zeile 21: die k -Pfade werden berechnet und in der Tabelle H eingefügt. Dabei wird ein LEFT-OUTER-JOIN benutzt, um in der SELECTAnfrage aik + akj mit aij zu vergleichen, falls aij existiert, ansonsten wird der neue Pfad (i,j,(aik + akj ),k ) eingefügt. • Von Zeile 23 bis Zeile 29: Zwischen zwei Knoten der Tabelle wird ermittelt, ob es mehr als nur einen Pfad gibt (SELECT-Anfrage der DELETE-Anweisung). Falls ja, wird der längere Weg gelöscht (DELETE-Anweisung). ANTI-SEMI-JOIN-Variante Hier wird statt eines LEFT-OUTER-JOIN in der SELECT-Anfrage zur Bestimmung der k -Pfade, ein ANTI-SEMI-JOIN (also ..NOT EXISTS..) benutzt. Ansonsten gibt es keine weitere Änderung . 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 algorithm Allshortestpaths1B(G) // Anweisungen ähnlich wie bei der LEFT-OUTER-JOIN-Variante ... INSERT INTO H SELECT a.knoteni knoteni, b.knotenj knotenj (a.kanteij + b.kanteij)kanteij, a.knotenj zwischenknoten FROM H a JOIN H b ON (a.knotenj = b.knoteni) WHERE (a.knotenj = k AND b.knoteni = k AND a.knoteni <> b.knotenj; AND NOT EXISTS (SELECT c.knoteni, c.knotenj, c.kanteij, c.zwischenknoten FROM H c WHERE c.knoteni = a.knoteni AND c.knotenj = b.knotenj AND c.kanteij <= a.kanteij + b.kanteij) // Anweisungen ähnlich wie bei der LEFT-OUTER-JOIN-Variante ... 3.5.2 Zweiter Algorithmus Der zweite Algorithmus benutzt einen Cursor K, in dem wieder die k -Pfade gespeichert werden. Dafür benutzt der Algorithmus fast genau dieselbe SELECTAnfrage wie im ersten Algorithmus. Nur es wird zusätzlich das Gewicht aij des “alten Weges”von Knoten i nach Knoten j selektiert. Falls aij existiert, wird eine UPDATE-Anweisung ansonsten eine INSERT-Anweisung benutzt, um die k -Pfade in der Tabelle H einzufügen. Kapitel 3 22 Yvon Regis Tounkap Nkwate 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 Studienarbeit algorithm Allshortestpaths2(G) Eingabe: gerichteter gewichteter Graph G unvollständig in einer Relation gespeichert gemäß Darstellung im Abschnitt 3.1.2. Ausgabe: Graph H als Relation gemäß Darstellung im Abschnitt 3.1.2., in der die Länge der kürzesten Wege zwischen den Knoten von G gespeichert sind und diese Wege auch rekonstruiert werden können. H ← G; number n ← SELECT MAX(knoteni) FROM H ; number k ← SELECT MIN(knoteni) FROM H ; Cursor K ; for k <= n do K ←SELECT a.knoteni knoteni, b.knotenj knotenj (a.kanteij + b.kanteij)kanteij, a.knotenj zwischenknoten, c.kanteij ckanteij FROM H a JOIN H b ON (a.knotenj = b.knoteni) LEFT OUTER JOIN H c ON (a.knoteni = c.knoteni AND b.knotenj = c.knotenj) WHERE (a.knotenj = k AND b.knoteni = k AND ((a.kanteij + b.kanteij)< c.kanteij OR c.kanteij IS NULL) AND a.knoteni <> b.knotenj; for r in K do if r.ckanteij is null then INSERT INTO H VALUES (r.knoteni,r.knotenj,r.kanteij,r.zwischenknoten); else UPDATE H SET kanteij = r.kanteij, zwischenknoten = r.zwischenknoten WHERE knoteni = r.knoteni AND knotenj = r.knotenj; k ← SELECT MIN(knoteni) FROM H WHERE knoteni > k ; return H ; Kommentare zum Algorithmus • Von Zeile 12 bis Zeile 22: die k -Pfade zusammen mit dem Gewicht aij werden bestimmt und in K gespeichert. Eine Zeile von K hat dann die Struktur: (i, j, (aik + akj ), (aij oder null)) • Von Zeile 23 bis Zeile 30: jeder Record r in K wird gelesen und K geleert. Dabei werden die k -Pfade in H eingefügt. Falls aij nicht existiert (also Knoten i und Knoten j sind nicht durch einen Weg verbunden) , hat das Record-Feld ckanteij den Wert null. Mit einer INSERTAnweisung wird die neue Verbindung in H eingetragen. Falls aij schon vorhanden war (ckanteij is not null ) wird mit einer UPDATE-Anweisung die betroffene Zeile in H in den Feldern kanteij und zwischenknoten aktualisiert. Kapitel 3 23 Yvon Regis Tounkap Nkwate 3.5.3 Studienarbeit Beispiel Wir simulieren zwei Schritte (k = 1, 2) der Algorithmen Allshortestpaths1A und Allshortestpaths2. Dazu, sei G der folgende Graph: 1 2 4 1 3 3 3 1 1 4 Abbildung 3.3: Graph G Dieser Graph wird unvollständig gespeichert, und entspricht der Relation: knoteni 1 2 2 4 4 4 knotenj 2 3 4 1 2 3 kanteij 1 4 3 1 3 1 zwischenknoten 0 0 0 0 0 0 Schritt k = 1: • Allshortestpaths1A Die SELECT-Anfrage zur Bestimmung der 1 -Pfade (k = 1) liefert die Sicht: knoteni 4 knotenj 2 kanteij 2 zwischenknoten 1 Dieses Tupel wir mit der INSERT-Anweisung in die Tabelle eingefügt und das Tupel (4,3,2,0) wird mit der DELETE-Anweisung gelöscht. • Im Fall Allshortestpaths2 erhalten wir: K = knoteni 4 knotenj 2 kanteij 2 zwischenknoten 1 ckanteij 3 Da c.kanteij für dieses Tupel nicht den null-Wert hat, wird mit der UPDATEAnweisung das Datenfeld (4,3,2,0) zum Datenfeld (4,2,2,1) aktualisiert. Kapitel 3 24 Yvon Regis Tounkap Nkwate Studienarbeit Schritt k = 2: • Allshortestpaths1A Die SELECT-Anfrage zur Bestimmung der 2 -Pfade (k = 2) liefert die Sicht: knoteni 1 1 knotenj 3 4 kanteij 5 4 zwischenknoten 2 2 Diese zwei Tupel werden dann in die Tabelle eingefügt. • Im Fall Allshortestpaths2 erhalten wir: knoteni 1 K = 1 knotenj 3 4 kanteij 5 4 zwischenknoten 2 2 ckanteij null null Da ckanteij den Wert null für die beiden Tupel hat, werden diese beiden Tupeln mit der INSERT-Anweisung in die Tabelle eingefügt. 3.5.4 Methoden für die Rekonstruktion der Wege Die Rekonstruktion des kürzesten Weges zwischen zwei Knoten i und j des Graphen H geschieht mit Hilfe der Methoden weg und zwischen. 1 2 3 4 5 6 7 8 9 10 11 method weg(i,j,H ) var1 NUMBER; var1 = SELECT kanteij FROM H WHERE knoteni = i AND knotenj = j ; if var1 IS NOT NULL then DBMS OUTPUT.PUT LINE(’Von Knoten ’ki ); zwischen(i,j,H ); DBMS OUTPUT.PUT LINE(’Nach Knoten ’kj ); else DBMS OUTPUT.PUT LINE(’Kein Weg !’); 1 2 3 4 5 6 7 8 9 method zwischen (i,j,H ) var1 NUMBER; var1 = SELECT zwischenknoten FROM H WHERE knoteni = i AND knotenj = j ; if var1 <> 0 then zwischen(i,var1,H ); DBMS OUTPUT.PUT LINE(’über Knoten ’kvar1 ); zwischen(var1,j,H ); Kapitel 3 25 Kapitel 4 Tests der Algorithmen In diesem Kapitel werden die Algorithmen zur Berechnung der transitiven Hülle und die Algorithmen zur Bestimmung aller kürzesten Wege getestet und ihre Laufzeiten verglichen. Dazu werden passende Testsdaten aufbereitet und zur Beschleunigung des Zugriffs auf die Daten passende Indexe auf gewisse Spalten der Testtabellen angelegt. Zunächst stellen wir einen Algorithmus vor, der gerichtete und gewichtete Graphen vollständig in einer Relation speichert. Mit diesen Testgraphen werden die Algorithmen zur Berechnung aller kürzesten Wege von vollständig gespeicherten Graphen (AllshortestpathsA und AllshortestpathsB) getestet. Ihre Laufzeit bei wechselbarer Tabellengröße wird notiert, um den besten Algorithmus zu bestimmen. Dann werden die Algorithmen, die auf unvollständig gespeicherten Graphen basieren, getestet. Dazu werden wieder Testdaten aufbereitet und passende Indexe auf die Testtabellen angelegt. Die Laufzeiten der Algorithmen werden ebenfalls verglichen. Für die Berechnung der transitiven Hülle werden zusätzlich die Ausführungspläne der Haupt-SELECT-Anfragen der Algorithmen ausgegeben und kommentiert. 4.1 4.1.1 Test der Algorithmen allshortestspathsA und AllshortestpathsB Bereitstellung der Testdaten Die Testtabellen werden mit dem folgenden Algorithmus erzeugt. Dieser Algorithmus bekommt als Eingabeparameter die Anzahl der Knoten der Testtabelle: n und die Wahrscheinlichkeit (eine natürliche Zahl), mit der eine Kante zwischen zwei unterschiedlichen Knoten eingetragen wird: prob. Es gilt 0 6 prob 6 100. Die Funktion VALUE aus dem Package DBMS RANDOM liefert eine reelle Zahl aus dem Intervall [0,1). Diese reelle Zahl wird mit 100 multipliziert und wir erhalten eine Zahl x aus dem Intervall [0,100). Falls 1 6 x 6 prob, wird eine Kante zwischen zwei Knoten des Graphen eingetragen. Dabei ist das Gewicht der eingetragene Kante gleich x. Falls x > n wird keine Kante eingetragen (Spalte kanteij hat den wert null). Yvon Regis Tounkap Nkwate 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 Studienarbeit algorithm creategraph(n, prob) number i ← 1; number j ← 1; number x ; number aij ; tabelle Y ← CREATE TABLE Y (knoteni number, knotenj number, kanteij number, zwischenknoten number) while i 6 n do while j 6 n do x ← (100*DBMS RANDOM.VALUE); if i = j then INSERT INTO Y (knoteni, knotenj, zwischenknoten) VALUES(i,j,0); if x 6 prob and 1 6 x and i < j then INSERT INTO Y VALUES (i, j, x, 0); if x 6 prob and 1 6 x and i > j then aij ← SELECT kanteij FROM Y WHERE knoteni = i and knotenj = j ; if aij is not null then INSERT INTO Y VALUES(i, j, aij, 0); else //In PL/SQL wird eine NO DATA FOUND-Ausnahme //ausgelöst und abgefangen INSERT INTO Y VALUES(i, j, x, 0); else INSERT INTO Y (knoteni, knotenj, zwischenknoten) VALUES(i,j,0); return Y Kommentare zum Algorithmus: • Solange noch nicht alle Zeilennummer (i ) und Spaltennummer (j ) bearbeitet sind, wird (in Zeile 10) eine zufällige Zahl aus [0, 1) mit Hilfe der Funktion VALUE aus dem Package DBSM RANDOM generiert. Diese Zahl wird mit 100 multipliziert, um eine natürliche Zahl aus [0,100) zu erhalten, und anschließend in der Variable x gespeichert. • Von Zeile 11 bis Zeile 13: die Kante (i, j ) mit dem Gewicht null wird in Y eingetragen, falls i = j . Die Spalte zwischenknoten hat selbsverständlich immer den Wert 0. • Von Zeile 14 bis Zeile 15: die Kante (i, j ) mit i < j wird eingefügt, falls 1 6 x 6 prob. Dabei hat das Gewicht der Kante (i, j ) den Wert x. (je näher die gelieferte Zahl an der Wahrscheinlichkeit ist, desto höher ist das Gewicht). • Zeile 16 bis 23: falls eine Kante (i,j ) mit i > j eingefügt werden soll, wird zunächst überprüft, ob die Kante (j,i ) schon vorhanden ist (Zeile 17-18). Existiert schon die Kante (j,i ), so wird einfach eine Rückkante mit gleichem Gewicht eingetragen (Zeile 20). Ist die Kante (j,i ) nicht vorhanden, so wird die neue Kante (i,j ) mit dem Gewicht x eingetragen. Kapitel 4 27 Yvon Regis Tounkap Nkwate Studienarbeit • falls i 6= j und x > prob ist, so wird eine Kante mit Gewicht null eingefügt (Zeile 25-26). 4.1.2 Vergleich der Laufzeiten beider Algorithmen Die PL/SQL-Prozeduren, die beide Algorithmen implementieren, befinden sich unter den gleichen Namen, wie die Algorithmen in der elektronischen Abgabe dieser Arbeit. Dort befindet sich auch eine Implementierung des Algorithmus creategraph. Wir rufen die Prozedur creategraph mit unterschiedlichen Eingabeparametern auf, und auf die erzeugten vollständig gespeicherten Graphen, lassen wir die beiden Algorithmen AllshortestpathsA und AllshortestpathsB laufen. Folgende Laufzeiten wurden notiert: CREATEGRAPH(n,prob) allshotestspathsB allshotestspathsA CREATEGRAPH(100,20) 9 s 60 10 s 83 CREATEGRAPH(100,50) 9 s 37 13 s 65 CREATEGRAPH(100,90) 9 s 79 17 s 01 CREATEGRAPH(150,20) 33 s 05 50 s 07 CREATEGRAPH(150,50) 29 s 29 57 s 15 CREATEGRAPH(150,90) 29 s 73 01 min 08 s CREATEGRAPH(200,20) 01 min 19 s 02 min 18 s CREATEGRAPH(200,50) 01 min 07 s 02 min 36 s CREATEGRAPH(200,90) 01 min 04 s 03 min 13 s CREATEGRAPH(250,20) 02 min 48 s 05 min 56 s CREATEGRAPH(250,50) 02 min 18 s 06 min 07 s CREATEGRAPH(350,20) 03min 59 s 18 min 44 s Wie wir festellen können, ist der Algorithmus allshotestspathsB die bessere Umsetzung des Algorithmus zur Berechnung aller kürzesten Wege in PL/SQL(bei vollständig gespeicherten Graphen). Dies läßt sich dadurch erklären, dass wir im Algorithmus AllshortestpathsB die k -Pfade berechnen und direkt mit INSERT, oder UPDATE in der Tabelle einfügen. Das Durchlaufen der Datensätze eines Cursors ist auch wohl eine Operation, die weniger Zeit in Anspruch nimmt als erwartet. Im Algorithmus allshortestpathA berechnen wir die k -Pfade, fügen sie in die Tabelle ein, und mit der DELETE-Anweisung greifen wir noch einmal auf diese k -Pfade zu. Dies kann als Doppelarbeit von AllshortestpathsB angesehen werden. 4.2 Tests der Algorithmen basierend auf unvollständig gespeicherte Graphen In diesem Abschnitt möchten wir mit unvollständig gespeicherten (großen) Graphen, die Algorithmen zur Berechnung der transitiven Hülle und zur Bestimmung aller kürzesten Wege testen, und ihre Laufzeit vergleichen. Zunächst werden die Testdaten aufbereitet mit Hilfe zweier Prozeduren aufbereitet. Kapitel 4 28 Yvon Regis Tounkap Nkwate 4.2.1 Studienarbeit Bereitstellung der Testdaten für die Berechnung der transitiven Hülle Die Aufbereitung der Testdaten für die Berechnung der transitiven Hülle geschieht mit Hilfe der Tabelle HANBKG250 EDGE$, mit dem Besitzer TIEDGE(owner = ’tiedge’). Diese Tabelle stellt das Straßennetz der Region Hannover als Graph im Maßstab 1:250.000 dar. Die geometrischen Daten liegen allerdings in einem topologischen Datenmodell, das in der Arbeit [Tie03] entwickelt wurde. Die Daten in dieser Tabelle weisen eine besondere Struktur auf, nämlich der dargestelle Graph ist zwar gewichtet, aber nicht gerichtet und enthält Schleifen. So gibt es Kanten, deren Startknoten und Endknoten übereinstimmen. Zudem kann es mehr als nur eine Kante zwischen zwei Knoten geben. Die Testdaten werden in der Tabelle HANBKG250 EDGE$FloydW gespeichert. Diese neue Tabelle hat genau dieselbe Knotenmenge wie HANBKG250 EDGE$. Falls in der Tabelle HANBKG250 EDGE$ eine ungerichtete Kante von Knoten i nach Knoten j existiert, wird in der Tabelle HANBKG250 EDGE$FloydW eine Kante von i nach j und eine Kante von j nach i eingetragen. Schleifen, die in HANBKG250 EDGE$ vorhanden sind, werden in HANBKG250 EDGE$FloydW entfernt. Sind zwei Knoten durch mehr als nur eine Kante direkt verbunden , wird nur eine Kante (in beide Richtungen) zwischen beiden Knoten eingetragen . Zur Beschleunigung der Zugriffe auf die Testtabelle, werden Indexe auf die Spalten knoteni und knotenj angelegt. Statistiken der Tabelle werden ebenfalls erzeugt und im Data Dictionary gespeichert. Die Prozedur createGraph forFloydW, die sich in der elektronischen Abgabe befindet, erzeugt die Testtabelle HANBKG250 EDGE$FloydW. 4.2.2 Vergleich der Laufzeiten der Algorithmen Floyd Warschall1/2/3 Die Prozeduren, die konkret die Algorithmen Floyd Warschall1/2/3 implementieren sind in der elektronischen Abgabe auch zu finden. Zu der Testtabelle HANBKG250EDGE$FloydW gelten vorm Start der Algorithmen folgende Statistiken: • # Knoten: 1228 • # Kanten (Tabellengröße): 3198. Laufzeit der Prozeduren: Prozedur Laufzeit FLOYD WARSHALL1 41 Min 11 Sek FLOYD WARSHALL2 mehr als 10 Stunden FLOYD WARSHALL3 11 Min 20 Sek Die Testtabelle HANBKG250 EDGE$FloydW enthält 1465330 Kanten im Endzustand. Feststellen kann man, daß der Algorithmus floyd warshall3 (also LEFTOUTER-JOIN-Variante), wohl die bessere PL/SQL-Implementierung der transitiven Kapitel 4 29 Yvon Regis Tounkap Nkwate Studienarbeit Hülle für unvollständig gespeicherte Graphen ist. Der Allgorithmus floyd warshall2 ist am ineffizientsten. 4.2.3 Ausführungspläne der Hauptanfragen der Algorithmen Sei der Graph (die Tabelle HANBKG250 EDGE$FloydW) im Endzustand. Er besitzt insgesamt 1465330 Kanten. Wir möchten uns die Ausführungspläne der SELECTAnfrage der Algorithmen zur Bestimmung neuer Verbindungen anschauen und kommentieren. Dazu bestimmen wir einen Knoten, der die maximale Anzahl an ausgehenden Kanten (1210) besitzt. (zum Beispiel Knoten 531 ist Startknoten von 1210 Kanten). Wir simulieren also einen Schleifendurchlauf der Algorithmen mit dem Zwischenknotennummer 531 und erhalten folgende Ausführungspläne: SELECT-Anfrage des Algorithmus floyd warshall1 SELECT a.knoteni knoteni ,b.knotenj knotenj,a.kanteij kanteij FROM HANBKG250_EDGE$FLOYDW a JOIN HANBKG250_EDGE$FLOYDW b ON(a.knotenj = b.knoteni) WHERE a.knotenj= 531 AND b.knoteni = 531 AND a.knoteni<>b.knotenj MINUS (SELECT knoteni,knotenj,kanteij FROM HANBKG250_EDGE$FLOYDW x WHERE knoteni = x.knoteni AND knotenj = x.knotenj); Elapsed: 00:00:00.14 Execution Plan ---------------------------------------------------------0 SELECT STATEMENT Optimizer=ALL_ROWS (Cost=877 Card=89793 Byt es=2226334) 1 2 3 4 0 1 2 3 MINUS SORT (UNIQUE) (Cost=588 Card=89793 Bytes=1616274) HASH JOIN (Cost=72 Card=89793 Bytes=1616274) TABLE ACCESS (BY INDEX ROWID) OF ’HANBKG250_EDGE$FLO YDW’ (TABLE) (Cost=29 Card=229 Bytes=2290) 5 4 INDEX (RANGE SCAN) OF ’IDX2_HANBKG250_EDGE$FLOYDW’ (INDEX) (Cost=1 Card=229) Kapitel 4 30 Yvon Regis Tounkap Nkwate Studienarbeit 6 3 TABLE ACCESS (FULL) OF ’HANBKG250_EDGE$FLOYDW’ (TABL E) (Cost=42 Card=237 Bytes=1896) 7 8 1 7 SORT (UNIQUE) (Cost=289 Card=61006 Bytes=610060) TABLE ACCESS (FULL) OF ’HANBKG250_EDGE$FLOYDW’ (TABLE) (Cost=42 Card=61006 Bytes=610060) Statistics ---------------------------------------------------------190 recursive calls 0 db block gets 443 consistent gets 0 physical reads 320 redo size 336 bytes sent via SQL*Net to client 332 bytes received via SQL*Net from client 1 SQL*Net roundtrips to/from client 7 sorts (memory) 0 sorts (disk) 0 rows processed Kommentar zum Ausführungsplan: Zunächst wird auf die Tabelle HANBKG250 EDGE$FLOYDW zugegriffen. Dieser Zugrifff geschieht über die vom Index IDX2 HANBKG250 EDGE$FLOYDW (auf die Spalte knotenj angelegt) gelieferten Rowids. Ist für eine Zeile der Tabelle HANBKG250 EDGE$FLOYDW der Wert des Feldes knotenj gleich 531, so liefert der Index die zugehörige Zeilennummer. Die Tupel der Tabelle mit den entsprechenden Zeilennummern bilden die Kopie a. Dann wird auf die Tabelle HANBKG250 EDGE$FLOYDW ein Relationenscan durchgeführt, und die Kopie b erzeugt. Kopie a und Kopie b werden durch einen HASH-JOIN (mit JOIN-Bedingung: a.knotenj = b.knoteni ) verbunden. Von HANBKG250 EDGE$FLOYDW wird eine neue Kopie x (durch erneutes Relationenscan) erzeugt. Kopie ab und Kopie x werden sortiert, und die Operation Kopie ab MINUS Kopie x bildet das Endergebnis. Anschließend wird die Projektion der Endergebnismenge auf die gewünschten Spalten zurückgeliefert. SELECT-Anfrage des Algorithmus floyd warshall2 SELECT a.knoteni knoteni ,b.knotenj knotenj,a.kanteij kanteij FROM HANBKG250_EDGE$FLOYDW a JOIN HANBKG250_EDGE$FLOYDW b ON(a.knotenj = b.knoteni) WHERE a.knotenj= 531 AND b.knoteni = 531 AND a.knoteni<>b.knotenj AND NOT EXISTS (SELECT x.knoteni,x.knotenj,x.kanteij FROM HANBKG250_EDGE$FLOYDW x WHERE a.knoteni = x.knoteni AND b.knotenj = x.knotenj); no rows selected Elapsed: 00:00:00.04 Kapitel 4 31 Yvon Regis Tounkap Nkwate Studienarbeit Execution Plan ---------------------------------------------------------0 SELECT STATEMENT Optimizer=ALL_ROWS (Cost=115 Card=1 Bytes=2 6) 1 2 0 1 HASH JOIN (RIGHT ANTI) (Cost=115 Card=1 Bytes=26) TABLE ACCESS (FULL) OF ’HANBKG250_EDGE$FLOYDW’ (TABLE) ( Cost=42 Card=61006 Bytes=488048) 3 4 1 3 HASH JOIN (Cost=72 Card=89793 Bytes=1616274) TABLE ACCESS (BY INDEX ROWID) OF ’HANBKG250_EDGE$FLOYD W’ (TABLE) (Cost=29 Card=229 Bytes=2290) 5 4 INDEX (RANGE SCAN) OF ’IDX2_HANBKG250_EDGE$FLOYDW’ ( INDEX) (Cost=1 Card=229) 6 3 TABLE ACCESS (FULL) OF ’HANBKG250_EDGE$FLOYDW’ (TABLE) (Cost=42 Card=237 Bytes=1896) Statistics ---------------------------------------------------------1 recursive calls 0 db block gets 372 consistent gets 0 physical reads 0 redo size 336 bytes sent via SQL*Net to client 332 bytes received via SQL*Net from client 1 SQL*Net roundtrips to/from client 0 sorts (memory) 0 sorts (disk) 0 rows processed Kommentar zum Ausführungsplan: Zunächst wird auf die Tupel der Tabelle HANBKG250 EDGE$FLOYDW über Rowids (vom Index IDX2 HANBKG250 EDGE$FLOYDW zurückgeliefert) zugegriffen. Dabei werden die Tupel, mit 531 als Wert des Feldes knotenj zurückgeliefert. Die entstandene Menge nennen wir a. Dann wird durch ein Relationenscan die Kopie b von HANBKG250 EDGE$FLOYDW erzeugt, und mit a durch einen HASHJOIN (mit JOIN-Bedingung: a.knotenj = b.knoteni ) verbunden. Die Ergebnismenge ab wird mit der Kopie x von HANBKG250 EDGE$FLOYDW durch einen HASHJOIN (ANTI-SEMI-JOIN mit Bedingung: a.knoteni = x.knoteni and b.knotenj = x.knotenj ) verbunden. Die entstandene Menge abx wird auf die Spalten für die Ausgabe projiziert und zurückgeliefert. SELECT-Anfrage des Algorithmus floyd warshall3 Kapitel 4 32 Yvon Regis Tounkap Nkwate Studienarbeit SELECT a.knoteni knoteni ,b.knotenj knotenj,a.kanteij kanteij FROM HANBKG250_EDGE$FLOYDW a JOIN HANBKG250_EDGE$FLOYDW b on(a.knotenj = b.knoteni ) LEFT OUTER JOIN HANBKG250_EDGE$FLOYDW c ON (a.knoteni = c.knoteni and b.knotenj = c.knotenj) WHERE a.knotenj= 531 AND b.knoteni = 531 AND a.knoteni<>b.knotenj AND c.kanteij is null; Elapsed: 00:00:00.09 Execution Plan ---------------------------------------------------------0 SELECT STATEMENT Optimizer=ALL_ROWS (Cost=127 Card=290 Bytes =22910) 1 2 3 4 5 0 1 2 3 4 FILTER HASH JOIN (OUTER) (Cost=127 Card=290 Bytes=22910) VIEW (Cost=84 Card=290 Bytes=20010) HASH JOIN (Cost=84 Card=290 Bytes=5220) TABLE ACCESS (FULL) OF ’HANBKG250_EDGE$FLOYDW’ (TA BLE) (Cost=42 Card=237 Bytes=1896) 6 4 TABLE ACCESS (FULL) OF ’HANBKG250_EDGE$FLOYDW’ (TA BLE) (Cost=42 Card=480 Bytes=4800) 7 2 TABLE ACCESS (FULL) OF ’HANBKG250_EDGE$FLOYDW’ (TABLE) (Cost=42 Card=61006 Bytes=610060) Statistics ---------------------------------------------------------0 recursive calls 0 db block gets 552 consistent gets 0 physical reads 0 redo size 336 bytes sent via SQL*Net to client 332 bytes received via SQL*Net from client 1 SQL*Net roundtrips to/from client 0 sorts (memory) 0 sorts (disk) 0 rows processed Kommentar zum Ausführungsplan: Zunächst wird ein Relationenscan auf die Tabelle HANBKG250 EDGE$ FLOYDW durchgeführt, und die Kopie a erzeugt. Genauso wird die Kopie b erzeugt. Dann werden a und b durch einen HASH-JOIN (Bedingung: a.knotenj = b.knoteni ) verbunden. Das Ergebnis ist die Kopie ab. Dann wird durch ein Full-Table Scan eine dritte Kopie c der Tabelle HANBKG250 EDGE$FLOYDW erzeugt. ab und c werden danach durch HASH-JOIN (LINKER-OUTER-JOIN mit Bedingung a.knoteni = c.knoteni and b.knotenj = c.knotenj ) verbunden und die Ergebnismenge abc erzeugt. Anschließend geschieht eine Projektion auf die Spalten der Ausgabe. Kapitel 4 33 Yvon Regis Tounkap Nkwate Studienarbeit Bemerkung: Die SELECT-Anfrage der Algorithmen verhalten sich (im Endzustand des Graphen) ähnlich, da es nicht viele Unterschiede zwischen den Kosten in den Ausführüngsplänen gibt. Es wurde allerdings festgestellt, daß sich die Ausführungspläne während der Ausführung der Algorithmen nach einer bestimmten Zeit ändern und somit die Stichprobe (k = 531) nicht aussagekräftig über die gesamten Laufzeiten ist. 4.2.4 Bereitstellung der Testdaten für die Berechnung aller kürzesten Wege Ähnlich wie bei der Erstellung der Tabelle für die Berechnung der transitiven Hülle, werden die Testdaten für die Berechnung aller kürzesten Wege aus der Tabelle HANBKG250 EDGE$ entnommen. Die neue Tabelle heißt HANBKG250 EDGE$ALL S PATH. Die Anzahl der Knoten bleibt dieselbe wie bei HANBKG250 EDGE$. Da es zwischen zwei verschiedenen Knoten zwei (oder mehr) ungerichtete Kanten mit unterschiedlichen Gewichten geben kann, wird für die Berechnung der kürzesten Wege selbstverständlich die Kante mit dem kleinsten Gewicht gewählt und natürlich in beide Richtungen eingetragen. Da die geometrischen Daten der Tabelle HANBKG250 EDGE$ in einem topologischen Datenmodell liegen, wird für die Berechnung des Gewichts einer Kante die Funktion: SDO LENGTH(geom IN SDO GEOMETRY, dim IN SDO DIM ARRAY [, unit IN VARCHAR2]) RETURN NUMBER benötigt. Mit Hilfe dieser Funktion werden die Gewichte der Kanten bestimmt. Diese Funktion befindet sich im Package SDO GEOM der Erweiterung Oracle Spatial des DBMS Oracle 10g. Diese Erweitung von Oracle 10g stellt Packages bereit, die Funktionen und Prozeduren enthalten, mit deren Hilfe geometrische Objekte in der Datenbank gespeichert und angefragt werden können. Das Buch [MC] liefert mehr Informationen über Oracle Spatial. Die Prozedur createGraph forALL S PATH, die aus der Tabelle HANBKG250 EDGE$ die Testtabelle HANBKG250 EDGE$ALL S PATH erzeugt, befindet sich in der elektronischen Abgabe. 4.2.5 Vergleich der Laufzeit der Algorithmen Allshortestpaths1A/1B/2 Die Prozeduren, die konkret die Algorithmen Allshortestpaths1A/1B/2 implementieren sind auch in der elektronischen Abgabe zu finden. Zu der Testtabelle HANBKG250 EDGE$ALL S PATH gelten vorm Start der Algorithmen folgende statistiken: • Anzahl unterschiedlicher Knoten: 1228 • Tabellengröße(# Kanten): 3198. Laufzeit der Prozeduren: Kapitel 4 34 Yvon Regis Tounkap Nkwate Studienarbeit Prozedur Laufzeit Allshortestpaths1A 3 Stunden Min 03 Sek Allshortestpaths1B mehr als 10 Stunden Allshortestpaths2 1 Stunde 30 Min Sek Die Testtabelle HANBKG250 EDGE$ALL S PATH enthält im Endzustand 1465330 Kanten. Feststellen kann man, daß der Algorithmus Allshortestpaths2 (LEFT OUTER JOIN + KURSOR-Variante) wohl die bessere PL/SQL-Implementierung des “all sources shortest paths problem ”für unvollständig gespeicherte Graphen ist. Der Allgorithmus Allshortestpaths1B ist am ineffizientesten. 4.2.6 Programmierung Die PL/SQL-Prozeduren, die die vorgestellten Pseudocode-Algorithmen implementieren, sind in der elektronischen Abgabe zu finden. Viele Operationen wurden mit Dynamic-SQL-Techniken realisiert. . Kapitel 4 35 Kapitel 5 Ausblick In diesem Kapitel wird eine kritische Situation, die sich ergeben kann beschrieben, und eine mögliche Lösung geschildert. Eine Frage, die man sich stellen kann, ist: Würde ein Knoten nach der Berechnung der transitiven Hülle bzw. aller kürzesten Wege ausfallen, müßte man dann eine komplete neue Berechnung durchführen, um Verbindungen zwischen den Knoten wieder herzustellen? Die Algorithmen jedesmal in solch einer Situation neu zu starten würde sich für Echtzeitanwendungen (zum Beispiel Navigationssysteme von Fahrzeugen) als ungeeignete Lösung ergeben. Eine schnellere Lösung würde etwa so aussehen: Man könnte die Algorithmen umprogrammieren, sodaß alle mögliche Wege, die es überhaupt zwischen zwei verschiedenen Knoten geben kann, gespeichert werden. Man kann diese Idee umsetzen, in dem anstatt neue gefundene k -Pfade mit alten Verbindungen zu vergleichen, man sie sofort in der Tabelle einfügt. Besser gesagt, lassen sich zwei Knoten i und j durch einen Weg mit k als Zwischenknoten verbinden, so wird dieser Weg (von i nach j über k ) direkt in der Tabelle (INSERT) eingefügt, unabhängig davon, ob es einen kürzeren Weg gibt. Diese Methode würde viel Speicherplatz erfordern (also im schlechtesten Fall: ∀ i, j, k ∈ V i 6= j 6= k 6= i, gilt i kann mit j über k verbunden werden.): O(n3 ) (n.(n-1).(n-2)). Aber die Laufzeit würde sich kaum ändern, da anstatt UPDATE, INSERT benutzt wird. Die Methode zur Rekonstruktion der Wege müßte dann umgeschrieben werden. Also falls etwa Knoten i ausfällt, müssen in der Endtabelle zunächst alle Tupel, die i als Wert der Spalte knoteni oder knotenj haben, gelöscht werden. Für die Rekonstrüktion des (neuen) kürzesten Weges zwischen k und l, muss in den Methoden zur Rekonstruktion der Wege, in der Haupt-SELECT-Anfrage zusätzlich die Aggregierungsfunktion MIN(kanteij) eingefügt und eine Gruppierung nach k in jedem rekursiven Aufruf vorgenommen werden. Tabellenverzeichnis 2.1 Darstellung des Graphen als Adjazenzmatrix . . . . . . . . . . . . . . 3.1 3.2 3.3 3.4 Darstellung eines Graphen als Relation 1 Graph als Relation 1 . . . . . . . . . . . Darstellung eines Graphen als Relation 2 Graph als Relation 2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7 11 12 12 13 Abbildungsverzeichnis 2.1 2.2 2.3 2.4 2.5 ungerichteter Graph . . . . . . . . . . . . . gerichteter Graph . . . . . . . . . . . . . . . gewichteter und gerichteter Graph . . . . . . Die transitive Hülle G + (rechts) von G(links) Zwischenknoten k . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5 6 6 7 8 3.1 3.2 3.3 Beispiel 1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11 Beispiel 2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13 Graph G . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24 Literaturverzeichnis [Tie03] M.Tiedge: Entwicklung und Implematierung einer topologischen Erweiterung für objektbasierte räumliche Datenbanken. [Li05-06] Udo Lipeck: Vorlesung Datenstrukturen und Algorithmen (WS 2005/06) http://www.dbs.uni-hannover.de/dsalg0506.html [MC] Michele Cyran,Paul Lane, JP Polk Oracle Database Concepts, 10g Release 2 (10.2) c 1993, 2005, Oracle. All rights reserved. Copyright [CT] Cormen, Thomas H. / Leiserson, Charles E. / Rivest, Ronald L. Algorithmen – Eine Einführung, Oldenbourg-Verlag, München 2004