Parallele Algorithmen Sommersemester 2012 FU Berlin

Parallele Algorithmen Sommersemester 2012 FU Berlin 2 Inhaltsverzeichnis 1 Einleitung 1.1 Chronik der parallelen Algorithmenentwicklung 1.2 Drei B...
47 downloads 0 Views 561KB Size
Parallele Algorithmen Sommersemester 2012 FU Berlin

2

Inhaltsverzeichnis 1 Einleitung 1.1 Chronik der parallelen Algorithmenentwicklung 1.2 Drei Beispiele paralleler Algorithmen . . . . . . 1.2.1 Berechnung der Summe von n Zahlen. . 1.2.2 Berechnung von Pr¨afixsummen . . . . . 1.2.3 Addierer . . . . . . . . . . . . . . . . . . ¨ 1.3 Uberblick zur Vorlesung . . . . . . . . . . . . . 1.4 Literatur . . . . . . . . . . . . . . . . . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

2 Berechnungsmodell 2.1 Klassifikation nach Flynn (1972) . . . . . . . . . . . . . 2.2 Lese- und Schreibzugriff . . . . . . . . . . . . . . . . . 2.3 Ressourcen/Komplexit¨atsmaße . . . . . . . . . . . . . . 2.4 R¨ uckblick . . . . . . . . . . . . . . . . . . . . . . . . . 2.5 Optimalit¨at von Algorithmen . . . . . . . . . . . . . . 2.5.1 Beispiele f¨ ur Bret’s Theorem . . . . . . . . . . . 2.5.2 Weitere Rechnermodelle des parallelen Rechnens 2.5.3 Pseudocode und h¨ohere Programmiersprachen .

. . . . . . .

. . . . . . . .

. . . . . . .

. . . . . . . .

. . . . . . .

. . . . . . . .

. . . . . . .

5 6 8 8 10 13 19 19

. . . . . . . .

21 22 23 24 24 25 26 27 28

3 Elementare Techniken paralleler Algorithmen 3.1 Pointer Jumping . . . . . . . . . . . . . . . . . . . . . . . . . 3.1.1 Pr¨afixsummenberechnung in W¨aldern . . . . . . . . . . 3.2 List Ranking . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.2.1 Verwendung des vorherigen Algorithmus . . . . . . . . 3.2.2 Algorithmus von Anderson und Miller . . . . . . . . . 3.3 Mischen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.3.1 Schnelleres Mischen . . . . . . . . . . . . . . . . . . . . 3.3.2 Schnellerer, nicht kostenoptimaler Mischalgorithmus M3 3.3.3 Schnellerer und kostenoptimaler Mischalgorithmus M4 3.4 Sortieren . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3

31 31 32 33 33 33 41 45 48 50 51

4

INHALTSVERZEICHNIS

4 Parallele Graphenalgorithmen 4.1 Zusammenhangskomponenten . . . . . . . . . . . . . . . . . . 4.1.1 Algorithmus Z1 . . . . . . . . . . . . . . . . . . . . . . 4.1.2 Algorithmus Z2 . . . . . . . . . . . . . . . . . . . . . .

53 53 55 56

Kapitel 1 Einleitung

5

6

1.1

KAPITEL 1. EINLEITUNG

Chronik der parallelen Algorithmenentwicklung

Parallele Verfahren finden nicht nur in der Algorithmik und Informatik allgemein Anwendung, sondern sind im t¨aglichen Leben zu finden. Sobald mehrere Personen oder Maschinen parallel an der L¨osung eines Problems oder Erstellung eines Gegenstandes (z.B. Autobau, Konstruktion von Geb¨auden, etc.) arbeiten, ist dies ein paralleles Verfahren. In der Informatik basierte lange Zeit jeder Computer auf der Von-NeumannArchitektur, d.h. es gab eine einzelne CPU. Damit waren sequentielles Arbeiten und somit auch sequentielle Algorithmen erzwungen. Parallelit¨at gab es nur innerhalb der CPU durch verschiedene Schaltkreise, die nebeneinander arbeiten. In Algorithmen und Programmierung ist die Idee paralleler Algorithmen schon seit den 1960er Jahren vorhanden und z.B. in den B¨ uchern von Knuth zu finden. In den 1980er und fr¨ uhen 1990er Jahren wurde viel in dem Gebiet der parallelen Algorithmen und Architekturen geforscht und gearbeitet. Damals kam die Idee auf, anwendungsspezifische (special-purpose) parallele Architekturen zu entwickeln. Dazu wurden mehrere Prozessoren auf Gitterpunkten oder Kreisen angeordnet und auf bestimmte Art und Weise untereinander verbunden. Beispiel (Hyperwu ¨ rfel von Prozessoren): Die Prozessoren befinden sich auf den Gitterpunkten und sind mit den Nachbarn nach Vorschrift eines ddimensionalen W¨ urfels verbunden:

Abbildung 1.1: Drei- und vierdimensionaler Hyperw¨ urfel Beispiel (Connection Machines): Die Connection Machine CM1 bestand aus 65536 1-Bit Prozessoren, die in der Art eines 16-dimensionalen W¨ urfels angeordnet waren. Die Software war an der funktionalen Sprache

1.1. CHRONIK DER PARALLELEN ALGORITHMENENTWICKLUNG7 LISP ausgerichtet. Um parallele Algorithmen analysieren und vergleichen zu k¨onnen wurde ein paralleles Berechnungsmodell entwickelt. Dieses theoretische Modell ist eine Weiterentwicklung der RAM und wird als parallele RAM (PRAM) bezeichnet. Eine parallele Registermaschine (PRAM) besteht aus einer Menge von Prozessoren, einem gemeinsamen Speicher und einem Befehlssatz. Die Prozessoren kommunizieren u ¨ber den gemeinsamen Speicher miteinander. Prozessoren

gemeinsamer Speicher Abbildung 1.2: Idee der parallelen Registermaschine An der PRAM als Berechnungsmodell gab es die Kritik, dass die Anzahl der Prozessoren abh¨angig von der Eingabegr¨oße sein darf und die PRAM somit kein realistisches Modell ist. Allerdings gilt das Gleiche bei der Registermaschine in Bezug auf den Speicherplatz. Trotz der Kritik wird die PRAM das Berechnungsmodell f¨ ur die Analyse der Algorithmen sein, die in dieser Vorlesung vorgestellt werden, da sie die M¨oglichkeit einer gr¨oßtm¨oglichen Parallelisierung eines Problems liefert. Eine Simulation mit weniger Prozessoren ist dann ggf. leicht zu bewerkstelligen. Außerdem ist sie als Modell f¨ ur komplexe theoretische Betrachtungen sinnvoll und kann auch als Benutzerschnittstelle f¨ ur parallele Programmierung dienen. In den 1990er und 2000er Jahren wurde die Forschung auf dem Gebiet der parallelen Algorithmen und Architekturen fast eingestellt. Dies hatte mehrere Gr¨ unde. Aus theoretischer Sicht waren f¨ ur viele Standardprobleme parallele Algorithmen entwickelt worden. In der Praxis wurden mehr Fortschritte durch die Beschleunigung der CPUs durch h¨ohere Taktraten erreicht als durch die Entwicklung paralleler Architekturen. Außerdem war die bisherige Software historisch bedingt auf sequentielle Rechner ausgerichtet. Das Entwickeln und Erstellen paralleler Software war wesentlich schwieriger und teurer. Heutzutage ist fast jeder Rechner ein Parallelrechner mit mehreren Kernen (cores). Graphikkarten sind ”special purpose hardware“ und arbeiten parallel. Die Firma NVIDIA entwickelte die Programmiersprache CUDA mit der parallele Algorithmen programmiert und auf Graphikkarten ausgef¨ uhrt

8

KAPITEL 1. EINLEITUNG

werden k¨onnen. In dieser Vorlesung wird CILK f¨ ur die Implementierung paralleler Algorithmen verwendet, welches auf C bzw. C++ basiert.

1.2 1.2.1

Drei Beispiele paralleler Algorithmen Berechnung der Summe von n Zahlen.

Gegeben: nPZahlen a1 , . . . , an Berechne: ni=1 ai Werden die n Zahlen sequentiell aufaddiert wird Θ(n) Zeit ben¨otigt. Angenommen, es stehen hinreichend viele Prozessoren zu Verf¨ ugung, die parallel arbeiten k¨onnen, wie schnell kann das Problem dann gel¨ost werden? Wird die Summe in einer Art Baumstruktur berechnet, wobei auf jeder Ebene des Baumes die Operationen parallel ausgef¨ uhrt werden, so kann die Summe von n Zahlen in O(log n) Zeit mit n2 Prozessoren berechnet werden.

a1

a2

a3

+

a4

a6

a5

+

+

+

a8

a7

+

+

+ Abbildung 1.3: Schema zur parallelen Berechnung der Summe von n Zahlen. Der Gesamtaufwand eines parallelen Algorithmus berechnet sich als das Produkt der Laufzeit und der Anzahl der Prozessoren. In diesem Fall w¨are der Gesamtaufwand  also O(n  log n). Dies kann verbessert werden, indem nicht n Θ(n) sondern Θ log n viele Prozessoren verwendet werden. Die Folge der Zahlen wird zun¨achst in Bl¨ocke der Gr¨oße Θ(log n) unterteilt und die Summe

1.2. DREI BEISPIELE PARALLELER ALGORITHMEN

9

jedes Blocks wird von einem Prozessor sequentiell berechnet. Dies braucht insgesamt Θ(log n) Zeit f¨ ur alle Summen,  da die Prozessoren parallel arbei n ten. Dann wird die Summe der Θ log n Zahlen wie oben beschrieben parallel  berechnet.  Die Laufzeit ist Θ(log n) und damit ist der Gesamtaufwand n Θ log n log n = Θ (n). Algorithmus 1 beschreibt das vorgestellten Verfahren mit Hilfe von Pseudocode. Das Schl¨ usselwort par bezeichnet die parallele Ausf¨ uhrung der Anweisungen in der zugeh¨origen Schleife. Algorithmus 1 Summe der Zahlen A[0], . . . , A[n − 1] 1: for h := 0 to log n do 2: for i := 0 step 2h+1 to n − 2h+1 par do 3: A[i] := A[i] + A[i + 2h ]; 4: end for 5: end for 6: return A[0]; Um die Summe von n Zahlen zu berechnen, kann auch ein divide-&conquer Ansatz verwendet werden, der parallelisiert werden kann. In CILK und in unserem Pseudocode wird dazu der Befehl spawn vor den rekusiven Aufruf der Funktion geschrieben. Algorithmus 2 Summe der Elemente in A mit divide-&-conquer. function add (A, l, r) if l = r then return A[l]; else if l < r then c; m := b l+r 2 x :=spawn add (A, l, m); y :=spawn add (A, m + 1, r); return x + y; else return 0; end if end if

10

KAPITEL 1. EINLEITUNG

Laufzeit (bei hinreichend vielen Prozessoren): Sei n = r − l + 1. T (1) = c1 T (n) = T

l n m 2

+ c2 ,

f¨ ur Konstanten c1 und c2 . Wegen der Parallelit¨at wird das Maximum der Laufzeiten der beiden rekursiven Aufrufe betrachtet und nicht wie sonst die Summe der Laufzeiten. Die L¨osung der Rekursionsgleichung und somit die Laufzeit der Funktion add ist T (n) = O(log n) mit O(n) Prozessoren. Bemerkung: Der Algorithmus kann nicht nur f¨ ur die Addition verwendet werden, sondern funktioniert f¨ ur beliebige assoziative Operationen.

1.2.2

Berechnung von Pr¨ afixsummen

Als n¨achstes Beispiel betrachten wir die Berechnung der Pr¨afixsummen von einer Folge von n Zahlen. Gegeben: n Zahlen a1 , . . . , an P Berechne: n Zahlen s1 , . . . , sn mit sk = ki=1 ai Beispiel: a: 2 5

6

1

2

3

5

4

s : 2 7 13 14 16 19 24 28 Ein einfacher sequentieller Algorithmus arbeitet wie folgt: Algorithmus 3 Sequentielles Berechnen der Pr¨afixsummen. s0 := 0 for i:=1 to n do si := si−1 + ai ; end for Laufzeit: Jede Schleifeniteration ben¨otigt Θ(1) Zeit, somit ist die Gesamtlaufzeit Θ(n). Algorithmus 3 l¨asst sich nicht einfach durch das Hinzuf¨ ugen der Anweisung par parallelisieren, da die jeweiligen Ergebnisse der Berechnung in der Schleife nicht voneinander unabh¨angig sind.

1.2. DREI BEISPIELE PARALLELER ALGORITHMEN

11

Eine M¨oglichkeit eines parallelen Verfahrens zur Berechnung der Pr¨afixsummen ist durch das folgende Schema gegeben:

2

5

6

1

2

3

5

4

2

7

11

7

3

5

8

9

2

7

13

14

14

12

11

14

2

7

13

14

16

19

24

28

Im ersten Schritt wird die Summe zweier in der Folge benachbarter Zahlen berechnet und an der Stelle der 2. Zahl gespeichert. In den darauf folgenden Schritten werden jeweils die Summen zweier Zahlen mit Abstand zwei, vier, acht, etc. berechnet, bis im letzten Schritt die Summen zweier Zahlen mit Abstand n2 berechnet werden. Diese bilden dann das Ergebnis der Pr¨afixsummenfolge. Algorithmus 4 Paralleles Berechnen der Pr¨afixsummen. h := 1; for i := 1 to n par do si := ai ; end for while h ≤ n2 do for i := h + 1 to n par do ti := si + si−h ; end for h := h · 2; for i := 1 to n par do si := ti ; end for end while

Laufzeit: Da die Anweisungen in den for-Schleifen parallel ausgef¨ uhrt werden, und zusammen Θ(1) Zeit ben¨otigen, ist die Gesamtlaufzeit proportional zu der Anzahl der Schleifendurchl¨aufe der while-Schleife. Diese wird Θ(log n) mal durchlaufen, da h bei jedem Durchlauf verdoppelt wird. Die Laufzeit des parallelen Algorithmus’ zur Berechnung der Pr¨afixsummen von n Zahlen ist somit Θ(log n) mit n Prozessoren.

12

KAPITEL 1. EINLEITUNG

Divide & Conquer-Ansatz fu afixsummen ¨ r Pr¨ Als n¨achstes betrachten wir einen divide & conquer-Ansatz f¨ ur die L¨osung der Pr¨afixsummen. Algorithmus 5 Parallele Berechnung der Pr¨afixsummen mit dem divide & conquer-Ansatz. function praef (a1 , . . . , an ) if n = 1 then s1 := a1 ; else s1 . . . sb n2 c :=spawn praef(a1 . . . ab n2 c ); sb n2 c+1 . . . sn :=spawn praef(ab n2 c+1 . . . an ); end if for i := b n2 c + 1 to n par do si := si + sb n2 c ; end for Wie oben bereits erw¨ahnt, erzeugt der Befehl spawn einen eigenen Thread f¨ ur den nachfolgenden Befehl. parallele Laufzeit: T (1) = c1 T (n) = T

l n m

2 ⇒ T (n) = O(log n)

+ c2

f¨ ur die Konstanten c1 und c2 . Der erste Summand hat keinen Faktor 2, da beide Funktionen rekursiv ausgef¨ uhrt werden. Der zweite Summand c2 kommt von der for-Schleife. Anzahl der Prozessoren : F¨ ur Probleme der Gr¨oße 1 ben¨otigt man 1 Prozessor, f¨ ur Probleme der Gr¨oße n ist es m¨oglich, mit n Prozessoren auszukommen. Beweis(Induktion u ¨ber n): I.A.: n = 1X I.V.: Die Aussage ist f¨ ur Zahlen < n richtig. I.S.: Betrachte den else-Fall der if-Abfrage. Der erste rekursive Aufruf ben¨otigt nach I.V. b n2 c Prozessoren, der zweite d n2 e. In der Summe werden also n Prozessoren verwendet. Die for-Schleife ben¨otigt sogar nur d n2 e Prozessoren.

1.2. DREI BEISPIELE PARALLELER ALGORITHMEN

13

Bemerkungen: • Das Zeit-Prozessoranzahl-Produkt ist beim sequentiellen Algorithmus mit O(n) besser als beim parallelen mit Θ(n log n), es ist aber m¨oglich, eine Laufzeit von O(log n) mit O( logn n ) Prozessoren zu erhalten. • In der for-Schleife lesen n2 Prozessoren den Wert sb n2 c gleichzeitig. Dieses concurrent read kann in Wirklichkeit nicht in O(1) realisiert werden. Es ergibt sich also die Frage, ob man dies f¨ ur theoretische Betrachtungen trotzdem erlauben soll. • Der Algorithmus funktioniert nicht nur f¨ ur die +-Operation, sondern auch f¨ ur beliebige andere assoziative (zweistellige) Operationen. • Dies ist eine wichtige Technik beim parallelen Algorithmen.

1.2.3

Addierer

Als drittes und letztes Beispiel wollen wir einen Schaltkreis zum Addieren von zwei Bin¨arzahlen mit n Stellen an−1 , . . . , a0 und bn−1 , . . . , b0 mit ai , bi ∈ {0, 1}, i = 0, . . . , n − 1 betrachten. Schaltkreis(Schaltkreismodell): Wir betrachten Schaltkreise, die aus folgenden Bausteinen bestehen: “und”

“oder”

“nicht”

“exkl. oder”

Abbildung 1.4: Grundbausteine von Schaltkreisen.

Aus diesen Grundbausteinen l¨asst sich ein Volladdierer zusammensetzen, den wir symbolisch wie folgt darstellen: A BC VA ¨ Ubertrag

A⊕B⊕C

Abbildung 1.5: Symbolische Schreibweise eines Volladdierers.

14

KAPITEL 1. EINLEITUNG

A

B

C

¨ Ubertrag

S

Abbildung 1.6: Schaltkreis eines Volladdierers im Detail. Der Volladdierer kann aus den Gattern beispielsweise durch den Schaltplan in Abbildung 1.6 realisiert werden. Die Tiefe eines Schaltkreises ist die maximale Zahl der Gatter auf einem Weg von einem Eingang zu einem Ausgang und entspricht der parallelen Laufzeit. Die Gesamtzahl aller Gatter eines Schaltkreises nennt man seine Gr¨oße; sie entspricht dem Gesamtaufwand des Algorithmus. Aus n Volladdierern kann man nun einen sogenannten Carry-Ripple-Adder zum Addieren zweier n-Bit-Zahlen zusammensetzen: an−1

a1

bn−1

b0

b1 VA

VA

a0 0

VA

... sn+1

sn

s1

s0

Abbildung 1.7: Carry-Ripple-Adder. Dessen Gr¨oße ist mit O(n) gut, die Tiefe von Θ(n) ist dagegen schlecht.

1.2. DREI BEISPIELE PARALLELER ALGORITHMEN

15

Anmerkung: Jeder n-Bit Addierer hat eine minimale Tiefe von Ω(log n), da der Ausgang sn+1 immer von allen Ausg¨angen abh¨angt, d.h. er muss mit allen verbunden sein. Wenn man alle Gatter betrachtet, die von sn+1 aus erreichbar sind, ergibt sich ein Bin¨arbaum, da jedes Gatter maximal zwei Eing¨ange hat (evtl. Knoten mit nur einem). Die Bl¨atter entsprechen den 2n Eing¨angen des Schaltkreises. Daraus ergibt sich eine minimale H¨ohe des Baumes von log(2n). Frage: Ist eine Tiefe O(log n) m¨oglich? ¨ Ja, dies ist durch Vorausberechnung der Ubertr¨ age m¨oglich und kann mit dem soganannten “Carry-Lookahead-Adder” realisiert werden. Um diesen zu konstruieren, definieren wir den Schaltkreis CLAn . F¨ uhre dazu zun¨achst eine neue Notation ein. Sei n eine Zweierpotenz. Dann bezeichne Si,l f¨ ur l = 0, . . . , log n und i = 0, . . . , 2nl − 1 das Segment von n − 1, . . . , 0, das von (i + 1)2l − 1 bis i2l reicht: n − 1 n − 2 ... ...

(i + 1)2l − 1 . . . Si,l (i-tes St¨ uck)

i2l

...

2

1 0

...

Der Schaltkreis CLAn berechnet zwei Bits, die wir wie folgt definieren: ¨ gi,l = 1, wenn das Segment Si,l von a und b einen Ubertrag “erzeugt” (wenn man beide addiert ohne die anderen Segmente zu betrachten) ¨ pi,l = 1, wenn das Segement Si,l einen Ubertrag propagiert, d.h., wenn von ¨ rechts ein Ubertrag in das Segment hineinkommt, dann wird links auch einer weitergegeben. Es gilt:

gi,0 = ai ∧ bi pi,0 = ai ∨ bi pi,l+1 = p2i,l ∧ p2i+1,l gi,l+1 = g2i+1,l ∨ (g2i,l ∧ p2i+1,l )

16

KAPITEL 1. EINLEITUNG

Der CLA l¨asst sich nun wie folgt rekursiv aufbauen: F¨ ur n = 1: ai bi

pi,0

gi,0

Abbildung 1.8: CLA f¨ ur n=1. Sonst (n > 1): an−1

...

bn−1

a n2 b n2

CLA n2 g1,L−1

g0,L

a n2 −1 b n2 −1

...

a0 b0

CLA n2 p1,L−1

g0,L−1

p0,L−1

p0,L

Abbildung 1.9: CLA f¨ ur n=1. Damit sind pi,l und gi,l f¨ ur l = 0, . . . , L und i = 0, . . . , 2nl − 1 in Tiefe O(log n) berechenbar.

1.2. DREI BEISPIELE PARALLELER ALGORITHMEN

17

¨ Mit Hilfe von pi,l und gi,l lassen sich nun die eigentlichen Ubertr¨ age berech¨ nen: Sei ci,l der Ubertrag am Ende vom Segment Si,l (bei der Gesamtaddition). Dann gilt: c2i,l = g2i,l ∨ (ci−1,l+1 ∧ p2i,l ) c0,L = g0,L c2i+1,l = ci,l+1 Die Rekursionsgleichungen k¨onnen wir nun zur Formulierung des Pseudoco¨ des f¨ ur den Schaltkreis der tats¨achlichen Ubertr¨ age nutzen: ¨ Algorithmus 6 Berechnung der eigentlichen Ubertr¨ age im CLA-Addierer. for l := L − 1 to 0 do for i := 1 to 2nl par do c2i+1,l = ci,l+1 ; c2i,l = g2i,l ∨ (ci−1,l+1 ∧ p2i,l ); end for end for Die innere for-Schleife braucht O(1) Zeit, da sie vollst¨andig parallel ausgef¨ uhrt wird. Die ¨außere for-Schleife braucht O(log n) Zeit. Also ergeben ¨ sich f¨ ur die Ubertr¨ age folgende Gr¨oßen: Tiefe: T (n) = log n n

Gr¨oße: G(n) =

L−1 X 2l X

O(1) = O(n)

l=0 i=1

¨ Mit den Ubertr¨ agen k¨onnen wir nun die endg¨ ultige Summe berechnen. Dabei bezeichnet sj die Summe an der Stelle j, mit 0 ≤ j ≤ n, und cj = ci,l den ¨ Ubertrag an der Stelle j, mit j = (2i + 1)2l − 1. Algorithmus 7 Berechnung der Summe. for j := 0 to n − 1 par do s j = aj ⊕ b j ⊕ c j ; end for Hiermit werden alle Stellen der Summe, bis auf die Letzte (n-te Stelle), ausgerechnet. Sind wir ebenfalls an dieser Stelle interessiert, so kann diese einfach durch sn = cn berechnet werden. Das berechnen der Summe ben¨otigt O(1)

18

KAPITEL 1. EINLEITUNG

Zeit; der zugeh¨orige Schaltkreis ist O(n) groß. Damit ergeben sich f¨ ur die insgesamte Tiefe und Gr¨oße des CLA-Addierers: Tiefe: T (n) = log n Gr¨oße: G(n) = O(n)

¨ 1.3. UBERBLICK ZUR VORLESUNG

1.3

¨ Uberblick zur Vorlesung

Die Vorlesung wird nach aktueller Planung folgende Themen ansprechen: • Einleitung • Rechnermodelle • Elementare Techniken in parallelen Algorithmen • Suchen und Sortieren • Graphen • Strings • Arithmetik • Parallele Komplexit¨atstheorie

1.4

Literatur

S. Aki The design and analysis of parallel algorithms J. Ja’ Ja’ Introduction to parallel algorithms F.T. Leighton Introduction to Parallel Algorithms and Architectures Cormen et. al. Introduction to Algorithms, Kapitel 27, 3. Auflage

19

20

KAPITEL 1. EINLEITUNG

Kapitel 2 Berechnungsmodell

21

22

KAPITEL 2. BERECHNUNGSMODELL

2.1

Klassifikation nach Flynn (1972)

Nach Flynn k¨onnen wir Rechnerarchitekturen wie folgt in grundlegende Klassen einteilen: { single, multiple } instruction { single, multiple } data Daraus ergeben sich die nachfolgenden vier Architekturen: SISD Single Instruction, Single Data Diese Klasse enth¨alt alle sequentiellen Einprozessor-Rechnerarchitekturen, wie z.B. Einprozessor-PCs: Hier wird nacheinander eine Operation auf ein einzelnes Datum angewandt. SIMD Single Instruction, Multiple Data Diese Architektur enth¨alt Architekturen, bei denen eine Operationen auf viele Daten gleichzeitig angewendet werden kann. Dies trifft zum Beispiel auf sog. Vektorrechner oder die parallelen Berechnungseinheiten einer GPU zu. MISD Multiple Instruction, Single Data Sehr unintuitive Klasse; hier werden mehrere Operationen auf dasselbe Datum angewendet. Diese Architektur findet man bei special-purposeSystemen, z.B. bei redundanter Berechnung zur Erh¨ohung der Fehlertoleranz. MIMD Multiple Instruction Multiple Data MIMD beinhaltet den Aufbau von Rechnernetzen bzw. verteilten Systemen, in denen allgemeine Threads/Prozesse modelliert werden k¨onnen. Hier k¨onnen verschiedene Operationen auf viele Daten vollparallel berechnet werden. In der Vorlesung werden wir ein MIMD-artiges theoretisches Modell f¨ ur parallele Algorithmen, die PRAM, nutzen. Die PRAM (Parallel Random Access Machine) besitzt beliebig viele Prozessoren, die jeweils auf einen unendlich großen Speicher zugreifen (lesen und schreiben) k¨onnen. Dabei ben¨otigt jeder Schritt genau eine Zeiteinheit, explizite Synchonisierung wird nicht ben¨otigt. Der Befehlssatz ist analog zu denen der normalenRegistermaschine, beinhaltet also lesen, schreiben, verschiede arithmetische und Vergleichsoperationen.

23

2.2. LESE- UND SCHREIBZUGRIFF Prozessoren

gemeinsamer Speicher Abbildung 2.1: Schematische Darstellung einer PRAM

2.2

Lese- und Schreibzugriff

Zus¨atzlich zur Architektur k¨onnen wir auch das Verhalten bzgl. parallelem Zugriff auf gleiche Register im gemeinsamen Speicher unterscheiden: { Exclusive, Concurrent } Read { Exclusive, Concurrent } Write Also k¨onnen wir vier Abstraktionen unterscheiden: 1. EREW 2. CREW 3. ERCW 4. CRCW Bei der Abstraktion CRCW unterscheidet man drei Verhaltensweisen bei gleichzeitigem Schreibzugriff auf dasselbe Register: beliebig (engl. arbitrary): Keine Kontrolle, wer schreibt. u ¨ bereinstimmend (engl. common): Schreiben nur dann erfolgreich, wenn alle dasselbe schreiben. vorrangig (engl. priority): Prozessor mit kleinerem Index schreibt.

24

KAPITEL 2. BERECHNUNGSMODELL

2.3

Ressourcen/Komplexit¨ atsmaße

Im Gegensatz zur sequentiellen Registermaschine k¨onnen bei der PRAM zus¨atzliche Ressourcen gemessen werden. Man unterscheidet: (parallele) Laufzeit bezeichnet die maximale Befehlsanzahl, die ein Prozessor ausf¨ uhrt. Zahl d. Prozessoren die aktiv werden. Speicherplatz bezeichnet die Anzahl der benutzen Register. Gesamtaufwand (engl. work ) ist die Summe der Befehle pro Prozessor und kann durch das Produkt Laufzeit · Zahl d. Prozessoren abgesch¨atzt werden. Wie u ¨blich wird der Ressourcenverbrauch als Funktion in der Gr¨oße der Eingabe angegeben. So betrachten wir als worst-case-Komplexit¨at das Maximum und als durchschnittliche Komplexit¨at den Mittelwert des ressourcenverbrauchs u ¨ber alle Eingaben der Eingabegr¨oße. Als Funktionsnamen verwenden wir T (n) P (n) S(n) W (n)

2.4

f¨ ur f¨ ur f¨ ur f¨ ur

Zeit Prozessoren Speicher Aufwand

Ru ¨ ckblick

Berechnungsmodell: PRAM als Grundlage: Beliebig viele Prozessoren mit gemeinsamen Speicher (shared memory). Alle Prozessoren k¨onnen auf den gesamten Speicher zugreifen. Prozessoren

gemeinsamer Speicher Wir sprachen u ¨ber verschiedene Modelle des Zugriffs auf den Speicher: EREW Exclusive Read, Exclusive Write

¨ VON ALGORITHMEN 2.5. OPTIMALITAT

25

CREW Common Read, Exclusive Write ERCW Exclusive Read, Common Write CRCW Common Read, Common Write Wir sprachen u ¨ber Ressourcen: T(n) parallele Laufzeit P(n) Anzahl von Prozessoren S(n) Speicherbedarf W(n) Aufwand bzw. Kosten (Gesamtzahl aller Operationen) Als obere Schranke der Kosten kann man W (n) = T (n) · P (n) annehmen.

2.5

Optimalit¨ at von Algorithmen

Wann ist ein Algorithmus optimal? Man k¨onnte z. B. nur die parallele Laufzeit optimieren T (n), ohne R¨ ucksicht auf die Zahl der Prozessoren P (n) oder die Kosten W (n). Dies f¨ uhrt jedoch oft zu wenig sinnvollen Konstruktionen der Maschiene. Bsp: Das Maximum von n Zahlen kann in konstanter Zeit auf einer CRCW-PRAM berechnet werden, ben¨otigt jedoch n2 Prozessoren und ist damit f¨ ur sinnvolle Eingabegr¨oßen nicht verwendbar. Die Anzahl von n2 Prozessoren ist illusiorisch f¨ ur die meisten Probleme. Meist gilt, dass die Zeit T (n) weniger kritisch ist als die Zahl der Prozessoren P (n). So stellt sich die Frage, bzgl. welchem Maß der Algorithmus zum Finden des Maximums verbessert werden k¨onnte. Hierzu betrachten wir den sequenziellen Algorithmus zur L¨osung des Problems. Dieser berechnet das Ergebniss in T (n) = O(n) mit P (n) = 1 Prozessoren. Somit ist W (n) = O(n) im Gegensatz zu O(n2 ) beim parallelem Algorithmus. Das heißt, dass der parallele Algorithmus nicht Kostenoptimal ist, im gegensatz zur sequenziellen Variante. Wir definieren: ,,optimaler Algorithmus“ heiße: • T (n) ist ,,gut“ • W (n) ist optimal, wobei meist der sequenzielle Algorithmus als Vergleichsmaß genommen wird.

26

KAPITEL 2. BERECHNUNGSMODELL

Wir betrachten einen kostenoptimalen Algorithmus, der ¨ahnlich zum bereits vorgestellen Algorithmus zur Addition von n Zahlen arbeitet. Man bestimme des Maximum von n Zahlen mit Laufzeit T (n) = O(logn) im n Bin¨arbaum bei einer Prozessorzahl P (n) = O( logn ). Da O(n) · O(logn) nicht Kostenoptimal ist, reduzieren wir die Zahl der Prozessoren so, dass jeder einen Block von Opertionen durchf¨ uhren muss. Somit ist der Algorithmus Kostenoptimal. Anmerkung: Das Produkt von P (n) und T (n) ist gr¨oßer oder gleich dem Gesamtaufwand W (n). Es ist gleich, wenn jeder Prozessor in jedem Schritt etwas berechnet. Jedoch sind die Kosten W (n) eines parallelen Algorithmus immer gr¨oßer/gleich der sequenziellen Variante, da eine RAM eine PRAM emulieren k¨onnte. Verallgemeinert: In der Realit¨at haben wir haben p Prozessoren, einen parallelen Algorithmus mit Laufzeit T (n) und Kosten W (n). Annahme: Im Schritt i sei der Aufwand Wi (n) f¨ ur 1 ≤ i ≤ T (n) und W (n) ist die Summe allerlTi (n).mDies k¨onnen wir auf p Prozessoren aufteilen. = Wi (n)−1 + 1.1 Der Schritt i kostet Zeit Wip(n) ≤ Wi (n)+p−1 p p Die Gesamtlaufzeit auf einem parallelem Rechner mit i Prozessoren ist somit T (n) 



X i=1

Wi (n) − 1 +1 p

 =

W (n) − T (n) + T (n) p

Es muss jeder Schitt simuliert werden. Brent’s Theorem: Ein paralleler Algorithmus mit Laufzeit T (n) und (n) Gesamtkosten von W (n) kann mit p Prozessoren in Zeit W (n)−T + T (n) p ausgef¨ uhrt werden.

2.5.1

Beispiele fu ¨ r Bret’s Theorem

Pr¨ afixsummenberechnung:

• Die Kosten sind W (n) = O(n). • Die Laufzeit ist T (n) = O(log n). • Es gibt P (n) = O(n) Prozessoren. 1

d·e da mache Prozessoren einen Schritt l¨anger brauchen k¨onnten, wenn die Eingabe nicht perfekt aufteilbar ist.

¨ VON ALGORITHMEN 2.5. OPTIMALITAT

27

n Prozessoren mit Zeit Diesen Algorithmus k¨onnen wir auf P (n) = logn n T (n) ≤ O( n/ log n + log n) = O(log n) ausf¨ uhren. Brent’s Theorem l¨asst jedoch die Prozessorallokalisation außer Acht. Welche Prozessoren f¨ uhren im i-ten Schritt welche Operation aus? Wie groß ist Wi (n)? Jeweils in Abh¨agigkeit von der Eingabe. Dieses Problem ist nicht trivial l¨osbar. Um Probleme aufzuteilen, m¨ ussen wir diese Frage beantworten k¨onnen.

2.5.2

Weitere Rechnermodelle des parallelen Rechnens

Schaltkreise Schaltkreise sind gerichtete azyklische Graphen.2 Die knoten sind mit Operationen beschriftet, z. B. boolesche oder arithmetische Operationen. Eigentlich kann jeder Algorithmus so dargestellt werden, indem man f¨ ur eine Eingabegr¨oße einen Schaltkreis angibt. Prozessornetze Prozessornetze sind zusammengeschaltete Prozessoren.

Dieser Prozessoren k¨onnen mittels unterschiedlicher Netzwerkarchitekturen miteinander verbunden sein. Diese k¨onnen als Kette (linear) also sogenannte ,,Message Passing Architecture“ oder als Gitter (Grid-Layout) angeordnet sein. Auch eine Anordnung als Hyperwu ¨ rfel mit d Dimensionen ist m¨oglich. Es wurde bereits am Anfang der Vorlesund die ,,Connectionen Mashine“ mit 16 Dimensionen erw¨ahnt. Die Kette hat einen Grad von 2. Die Prozessoren sind also mit jeweils zwei anderen Prozessoren verbunden. Der Gesamtdurchmesser, der die maximale 2

Auch DAG (,,directed acyclic graph“) genannt.

Abbildung 2.2: Message-Passingund Grid-Architektur

28

KAPITEL 2. BERECHNUNGSMODELL

minimale Entfernung zwischen zwei Prozessoren angibt, ist n bei n Prozessoren. Ein n × n Gitter hat Grad 4 bei einem Durchmesser von 2n. Der Durchmesser eines Hyperw¨ urfels ist der L¨angste Weg von A nach B innerhalb des W¨ urfels, ohne einen Knoten zwei mal besucht zu haben. Dieser ist n = 2d . Andersrum ist der Grad des Hyperw¨ urfels die Anzahl der Nachbarn eines Knotens, also d = log n. Es sind alle Prozessoren miteinander verbunden, deren Koordinaten einen Hemmingabstand von 1 haben.

1001 1000 0001 1101

0000 1011

1100 0101

1010 0100

0011

1111

0010

2.5.3 Pseudocode und ho ¨here Programmiersprachen

1110 0111 0110

Zur Beschreibung von Programmen und Algorithmen benutzen wir Pseudocode und Code einer h¨oheren Programmiersprachen. Abbildung 2.3: Hyperw¨ urfel F¨ ur die Analyse verwenden wir die Umsetz- mit Dimension 4 und 16 Protung auf der PRAM (s. bisherige Beispiele) . zessoren Wir verwenden typische Konstrukte h¨oherer Programmiersprachen: 1. Parallele rekursive Aufrufe sind in cilk mit dem Befehl spawn m¨oglich. 2. Divide-and-Conquere-Algorithmen sind gut zur Parallelisierung geeignet. Diese Programmiertechnik f¨ ur zu einem Baum rekursiver Aufrufe. 3. Dynamisches Programmieren Zur Analyse werden Rekursionsgleichungen f¨ ur Kosten, Zahl der Prozessoren und parallelen Aufzeit verwendet (s. Additionsbeispiel, Pr¨afixsumme . . . ). In der Praxis sollte die Rekursion bei der Anzahl der Prozessoren abgebrochen werden. Parallelit¨at ist jedoch nicht immer m¨oglich, so kann eine for-Schleife nicht immer parallel ausgef¨ uhrt werden. Dies genau dann nicht m¨oglich, wenn die Schleife inh¨arend Sequenziell ist.

¨ VON ALGORITHMEN 2.5. OPTIMALITAT Dies ist zum Beispiel beim naive Pr¨afixsummenalgorithmus gegeben: for i := 2 to n do si := si−1 + si end for

29

30

KAPITEL 2. BERECHNUNGSMODELL

Kapitel 3 Elementare Techniken paralleler Algorithmen Bisher haben wir Algorithmen gesehen, die den Divide and Conquer Ansatz zur L¨osung von Problemen verwendent haben. Diese Technik ist f¨ ur beliebige assoziative Operatoren anwendbar.

3.1

Pointer Jumping

Problem: Die Wurzel in einem Wald von B¨aumen finden. Gegeben: gerichteter Wald von Knoten mit Kind–Vater-Verweisen. Wir suchen die Nummer des Knotens, der die jeweilige Wurzel des Baumes ist. Aufgabe: F¨ ur jeden Knoten v mit Nummer i die Nummer s(i) des Baumes in dem sich v befindet. Frage: Was ist die Laufzeit? Algorithmus: Algorithmus 8 Die Wurzel in einem Wald von B¨aumen finden. for i := 1 to n par do s(i) := v(i) while s(i) 6= s(s(i) do s(i) := s(s(i)) end while end for Wir nehmen strikte Synchronisierung an. Initialisiert seien die s(i) mit ihrem jeweiligen Elter. 31

32KAPITEL 3. ELEMENTARE TECHNIKEN PARALLELER ALGORITHMEN

1

2

4

5

9

3

6

7

8

i

s(i)

1.S

2.S

1

1

-

2

1

-

3

1

-

4

2

1

-

5

2

1

-

6

3

1

-

7

3

1

-

8

3

1

-

9

5

2

1

Abbildung 3.1: Beispielhafter Wald und seine Abarbeitung Die Anzahl der u ¨bersprungenen Generationen im Baum wird in jedem Schritt der while-Schleife verdoppelt. Die Laufzeit ist O(log h), wobei h ≤ n die maximale H¨ohe eines Baumes im Wald ist. Wir ben¨otigen f¨ ur jeden Knoten in jedem Baum einen Prozessor, also P (n) = n. Der Gesamtaufwand ist somit O(n log n).

3.1.1

Pr¨ afixsummenberechnung in W¨ aldern

Gegeben: Ein gerichteter Wald wie vorher mit Gewicht w(i) f¨ ur jeden Knoten 1 ≤ i ≤ n. Berechne f¨ ur jeden Knoten v mit Nummer i die Summe t(i) der Gewichte auf dem Weg von v zur Wurzel seines Baumes. Wir verwenden f¨ ur dieses Problem fast den gleichen Algorithmus wie oben, jedoch summieren wir auf dem Weg zur Wurzel die Gewichte in einer Variablen f¨ ur jeden Knoten auf.

3.2. LIST RANKING

33

Algorithmus 9 Pr¨afixsummenberechnung in W¨aldern for i := 1 to n par do s(i) := v(i) t(i) := w(i) while s(i) 6= s(s(i) do s(i) := s(s(i)) t(i) := t(i) + t(s(i)) end while end for

3.2

List Ranking

Problem: Bestimmung des Rangs eines jeden Elements in einer Kette. Gegeben: Verkettete Liste o → o → o → . . . → o Aufgabe: F¨ ur alle Elemente entweder den Rang innerhalb der Liste oder umgekehrt, den Abstand zum letzten Knoten, finden.

3.2.1

Verwendung des vorherigen Algorithmus

Annahme: Die Elemente der Liste sind gegeben durch ein Feld von Zeigern auf das jeweils n¨achstes Element. Der vorherige Algorithmus l¨ost das Problem, in dem jedem Knoten das Gewicht 1 gegeben wird, mit n Prozessoren, O(log n) Zeit und O(n log n) Aufwand. Aus dem nicht-linearen Aufwand folgt allerdings, dass der parallele Algorithmus hier im Gegensatz zu einer sequentiellen Variante nicht kostenoptimal arbeitet. Eine kostenoptimale L¨osung war lange Zeit Forschungsgegenstand. Eine L¨osung lieferten Cole und Vishkin 1986 mit einem parallelen Algorithmus, der Θ( logn n ) Prozessoren verwendet und O(log n) Zeit ben¨otigt. F¨ ur diesen sehr komplizierten Algorithmus, welcher vermutlich noch nie implementiert wurde, ben¨otigt man tiefgehende Kenntnisse aus der Graphentheorie.

3.2.2

Algorithmus von Anderson und Miller

Unsere L¨osung des Problems ist ein einfacherer, randomisierter Algorithmus von Anderson und Miller.

34KAPITEL 3. ELEMENTARE TECHNIKEN PARALLELER ALGORITHMEN 1. Stelle neben Nachfolgezeiger next“ auch Vorg¨angerzeiger prev“ her. ” ” Initalisiere f¨ ur jedes Element v das Attribut v.dist := 1 2. Zerlege die Elemente aus der Liste in Bl¨ocke der L¨ange dlog ne und ordne jedem Block einen der d logn n e Prozessoren zu. Die Anordnung der Bl¨ocke bezieht sich dabei nicht auf die Liste, sondern auf die Reihenfolge der Elemente, in der sie vorliegen. Ein Block ist als Warteschlange“ ” des entsprechenden Prozessors zu sehen. 3. Die Prozessoren arbeiten ihre Warteschlange parallel ab. Sie versuchen in jedem Zeitschritt das n¨achste (bzw. erste) noch verbleibende Element aus ihrer Liste zu entfernen: (a) Jeder Prozessor betrachtetet das erste Element v seiner verbleibenden Warteschlange. Ein Entfernen ist m¨oglich, es sei denn v.next zeigt auf erstes Element einer anderen Warteschlange. In dem Fall w¨ urfeln beide konkurrierende Prozessoren ein Zufallsbit: • falls v eine 1 wirft und v.next eine 0, darf v entfernt werden • sonst entferne nichts

(b) Beim Entfernen von einem Element v: v.prev.dist := v.prev.dist + v.dist v.prev.next := v.next v.next.prev := v.prev

4. Wenn Liste leer ist, f¨ uge Element in umgekehrter Reihenfolge wieder ein und berechne den Rang: if v.next = ∅ then v.rang := v.dist else v.rang := v.dist + v.next.rang end if

35

3.2. LIST RANKING

v.prev

v.next v

Abbildung 3.2: Entfernen von Element v

5

3

2

8

6

4

1

7

1

2

3

4

5

6

7

8

1

2

3

4

5

6

7

8

2

7

3

0

4

Rang (Ergebnis)

1

5

6

(Wurzel)

Abbildung 3.3: Startbedingungen und gew¨ unschtes Ergebnis

36KAPITEL 3. ELEMENTARE TECHNIKEN PARALLELER ALGORITHMEN

Schritt 0

1

2

3

4

5

6

7

8

1

2

3

4

5

6

7

8

1

2

3

4

5

6

7

8

1

2

3

4

5

6

7

8

1

2

3

4

5

6

7

8

1

2

3

4

5

6

7

8

1

2

3

4

5

6

7

8

Schritt 1

Schritt 2

Schritt 3

Schritt 4

Schritt 5

Schritt 6

Abbildung 3.4: Algorithmus am Beispiel, Schritte 1-6 gepunktet : zu l¨oschender Zeiger gestrichelt : zu erzeugender Zeiger

37

3.2. LIST RANKING

Schritt

P1 P2 P3 71∅

1 2

12∅

3

226

4

336

816 43∅

5

546

6

64∅

Abbildung 3.5: Zwischenergebnisse der Prozessoren: Elementdist next

Element

Rang

1

rang∅ + 2 = 2

2

rang6 + 2 = 6

3

rang6 + 3 = 7

4

rang∅ + 3 = 3

5

rang6 + 4 = 8

6

rang∅ + 4 = 4

7

rang∅ + 1 = 1

8

rang6 + 1 = 5

Abbildung 3.6: R¨ange aller Elemente als Ergebnis

38KAPITEL 3. ELEMENTARE TECHNIKEN PARALLELER ALGORITHMEN Laufzeit 1. Jeder der d logn n e Prozessoren bearbeitet einen Block der L¨ange log n, was O(log n) Zeit ben¨otigt. 2. Die Prozessoren berechnen die Startpositionen ihrer zu bearbeitenden Bl¨ocke, was in in O(1) erfolgen kann. 3. Im schlechtesten Fall wird in jeder Iteration genau ein Element entfernt: Sind alle Zufallsbits 0 und bilden die aktiven Elemente eine Liste, so kann nur das letzte aktive Element dieser Liste entfernt werden, was jedoch stets m¨oglich ist, womit eine Laufzeit von O(n) garantiert ist. 1 Wir interessieren uns jedoch f¨ ur die erwartete Laufzeit. Diese analysieren wir im n¨achsten Abschnitt. 4. Die Laufzeit des vierten Schritts wird bestimmt von den L¨ange der Listen, die die Zeiger der Elemente nach dem dritten Schritt bilden: Tats¨achlich k¨onnten wir den dritten Schritt u ¨berspringen und den vierten Schritt auf die urspr¨ ungliche Liste anwenden, womit wir in O(n) die R¨ange berechnen w¨ urden. Das andere Extrem tritt auf, wenn in jeder Iteration des dritten Schritts genau ein Element entfernt wurde: Da hierdurch nach dem dritten Schritt kein Element mehr einen Nachfolger h¨atte, k¨onnten wir mit n Prozessoren in konstanter Zeit aus den Differenzen die R¨ange der Elemente bestimmen, mit d logn n e jedoch nur in O(log n). Allgemein stellen wir fest, dass der Nachfolgerzeiger eines Elements, das im dritten Schritt entfernt wird, auf ein Element zeigt, dass in einer sp¨ateren Iteration entfernt wird. Somit kann keine Kette von Elementen im vierten Schritt mehr als log n Elemente enthalten und der vierte Schritt l¨auft in O(log n) Zeit ab. Erwartete Laufzeit Im Folgenden wollen wir zeigen, dass die Wahrscheinlichkeit, dass ein Prozessor innerhalb einer bestimmten Anzahl von Runden seine Warteschlange nicht abgearbeitet hat, unterhalb einer gew¨ unschten Schranke liegt. Wir definieren zun¨achst einige Zufallsvariablen: Zq,i : Bin¨ar: Prozessor q entfernt in Runde i ein Element. Es gilt 1

H¨ atte jedes aktive Element ein anderes aktives Element als Nachfolger, existierte ein Kreis und die Eingabe w¨ are keine Liste.

39

3.2. LIST RANKING 1 P (Zq,i = 1) ≥ , 4

1 da im Falle eines aktiven Nachfolgers eine Chance von besteht, dass 4 sich die ben¨otigte Kombination von Zufallsbits ergibt, im Falle eines nicht aktiven Nachfolgers das Element jedoch garantiert entfernt wird. Xq,t : Anzahl der von Prozessor q nach t Runden entfernten Elemente. Xq,t =

t X

Zq,i

i=1

Damit gilt f¨ ur k ≤ log n: P (Xq,t < k) ≤ P

t X

! Zq,i < k ,

i=1

wobei wir f¨ ur k = log n und einen bestimmten Wert von t jene Wahr2 scheinlichkeit erhalten, von der wir zeigen wollen, dass sie klein ist. In dieser Form k¨onnen wir das Problem beinahe als Bernoulli-Experiment behandeln, doch hierf¨ ur m¨ ussten die Zq,i unabh¨angig sein, was nicht der Fall ist: Ist das von p1 bearbeitete Element Nachfolger des von p2 bearbeiteten Elements, k¨onnen nicht beide in der gleichen Runde entfernt werden, womit Zp1 ,i oder Zp2 ,i 0 sein muss bzw. nicht beide 1 sein k¨onnen. Da wir die Wahrscheinlichkeit nach oben absch¨atzen wollen, k¨onnen wir statt der Summe der Zq,i eine Summe im Erwartungswert kleinerer Quantit¨aten absch¨atzen, die somit wahrscheinlicher < k ist. Daher definieren wir 1 Z˜i mit P (Z˜i = 1) = ≤ P (Zq,i = 1): 4 ! ! t t X X P Zq,i < k ≤ P Z˜i < k i=1

i=1

In dieser Form k¨onnen wir nun die Chernoff-Schranke anwenden: Chernoff-Schranke: Sind X1 , . . . , Xt unabh¨angige und identischP verteilte bin¨are Zufallsvariablen mit P (Xi = 1) = q f¨ ur 1 ≤ i ≤ t und X = ti=1 Xi , so gilt f¨ ur γ ∈ [0, 1]: P (X < (1 − γ)qt) < e− 2

γ 2 qt 2

.

P (Xq,t < log n): Die Wahrscheinlichkeit, dass Prozessor q innerhalb von t Runden weniger als log n Elemente entfernt hat und somit seine Warteschlange noch nicht leer ist.

40KAPITEL 3. ELEMENTARE TECHNIKEN PARALLELER ALGORITHMEN 3 1 Wir w¨ahlen q = , t = 16 log n und γ = . 4 4 Zun¨achst versichern wir uns, dass die linke Seite der Ungleichung so die gew¨ unschte Form P (Xq,t < log n) erh¨alt:   3 1 1 1 (1 − γ)qt = 1 − 16 log n = · 16 log n = log n 4 4 4 4 Nun bestimmen wir, welche Absch¨atzung uns die Chernoff-Schranke liefert:

P (Xq,t

  2    3 1    · 16 log n    2 4 4 − γ 2qt < log n) < e = exp −   2         9 1 = exp − log n ≤ e−1·log n ≤ e− ln n = 8 n

Die Wahrscheinlichkeit, dass von Prozessor q nach 16 log n Runden weniger als log n Elemente entfernt wurden, seine Warteschlange also noch nicht 1 leer ist, betr¨agt also weniger als . n Der Wahrscheinlichkeit, dass irgendein Prozessor innerhalb dieser Anzahl Runden nicht fertig wird, ist somit 

1 1− 1− n

 logn n ≤

1 log n

Der geneigte Leser m¨oge u ufen, dass die letzte Ungleichung f¨ ur n ≥ 2 ¨berpr¨ gilt.

41

3.3. MISCHEN Also: 1 P ( # Schritte > 16 log n und ≤ 32 log n“) ≤ ” log n 1 P ( # Schritte > 32 log n und ≤ 16 log n“) ≤ ” log2 n ... 1 P ( # Schritte > 16k log n und ≤ 16(k + 1) log n“) ≤ ” logk n Somit betr¨agt die erwartete Laufzeit 2  ∞ X k+1 log n . T (n) ≤ 16 log n = 16 log n k log n − 1 n log k=0 Im Grenzwert ergibt sich so  lim

n→∞

log n log n − 1

⇒ T (n) ≤ 16 log n

2 →1 

log n log n − 1

2 = 16 log n · O(1) = O(log n)

Zusammenfassung: Der Anderson/Miller-Algorithmus l¨ost das Listranking-Problem im EREW-Modell mit d logn n e Prozessoren und einer erwarteten Laufzeit von O(log n) und somit kostenoptimal. Mo ¨gliche Verbesserungen: Die Konstante 16 vor dem log n in der asymptotischen Laufzeit kann verbessert werden, wenn im dritten Schritt der Algorithmus von Wyllie angewendet wird, sobald ≤ d logn n e Elemente u ¨brig sind. ¨ (Ubungsaufgabe)

3.3

Mischen

Mischen (wie beim Merge-Sort) Gegeben: Zwei Folgen (Felder) A = (a1 , a2 ,. . . , an ) mit a1 < a2 < . . . , an und B = (b1 , b2 ,. . . , bm ) mit b1 < b2 < . . . , bm Annahme: A ∩ B = ∅

42KAPITEL 3. ELEMENTARE TECHNIKEN PARALLELER ALGORITHMEN Problem: Mische A und B in eine sortierte Folge C. Dazu definieren wir: Rang(x, X) := |{a ∈ X|a ≤ x}| Rang(Y : X) := (r1 , ...rs ) mit Y = (y1 , ..ys ) wobei ri := Rang(yi , X) Idee: Suche mit Hilfe der Bin¨aresuche parallel nach den R¨angen aller Elemente von A in B. Algorithmus 10 Mischen 1 (M1) 1: for i := 1 to n + m par do 2: position := −1; 3: stelle := −1; 4: if i < n then 5: pos := binSuche(A[i], B, m); 6: stelle := pos + 1; 7: C[stelle] := A[i]; 8: else 9: j := i − n; 10: pos := binSuche(B[j], A, n); 11: stelle := pos + j; 12: C [stelle] := B[j]; 13: end if 14: end for Laufzeit: Die Bestimmung des Rangs von a ∈ A in B (Rang(a,B)) ist in O(log m) Zeit m¨oglich. Die Laufzeit von Rang(A:B) k¨onnen wir mit Hilfe der Bin¨arensuche und m + n Prozessoren in O(log m) Zeit bestimmen. Daraus ergibt sich der Gesamtaufwand von O ((n + m) log m) und dies ist nicht optimal, denn sequenziell ist es in O(n + m) Zeit m¨oglich.

43

3.3. MISCHEN Kostenoptimales Mischen Das kostenoptimale Mischen ist in O(log N ) Zeit mit m¨oglich, wobei N = m + n ist.

l

N log N

m

Prozessoren

Idee: Teile B in logmm gleich große Bl¨ocke. Bestimme den Rang der Blockgrenzelemente von B in A. Nachdem die R¨ange in A bestimmt wurden, teile A in Bl¨ocke mit den R¨angen als Grenzen. B0

B1 .............

Bk k = b logmm c

A0

A1

.............

Ak

Die Bl¨ocke B0 bis Bb m c und A0 bis Ab m c k¨onnten parallel gemischt log m log m werden mit je einem Prozessor, wobei Bi mit Ai gemischt wird, wenn |Ai | durch O(log N ) beschr¨ankt w¨are. Aber dies ist nicht immer der Fall, deshalb muss Ai in St¨ ucke der Gr¨oße log N aufgeteilt werden und 10 wird ausgef¨ uhrt.

44KAPITEL 3. ELEMENTARE TECHNIKEN PARALLELER ALGORITHMEN Algorithmus 11 Mischen 2 (M2) 1: l := dlog  m me; 2: k := l ; 3: j0 := 0; 4: jk := n; 5: B0 :=(b1 ,... bl ); 6: Bk :=(bkl+1 ,... bm ); 7: for i := 1 to k − 1 par do 8: bestimme ji := rang(bil , A) mit Bin¨arsuche 9: Bi :=(bil+1 ,...b(i+1)l ); 10: Ai :=(aji +1 ,...aji+1 ); 11: end for 12: for i := 0 to k par do 13: mische Bi mit Ai wie folgt 14: if |Ai | ≤ log n then 15: sequenziel mit einem Prozessor; 16: else 17: wende Zeile 7 bis 11 analog auf Ai und Bi an, danach weiter |{z} |{z} stattBi

stattAi

wie in Zeile 14; 18: end if 19: end for Laufzeit: (mit O( logNN ) vielen Prozessoren, wobei N = m + n) Seien die Zeilen 7 bis 11 Schritt (1), 12 bis 18 Schritt (2), wobei 14 bis 16 Schritt (2a) und 16 bis 18 Schritt (2b) sind.

Schritt: (1) O(log n) mit einer CREW-PRAM (2a) O(log n + log m) (2b) Schritt (1) analog auf Ai und Bi anwenden in O(log log m) Zeit mit i| O( log|A|A ) Prozessoren. i| Hieraus folgt, dass zwei sortierte Folgen der L¨ange n und m mit dem Algon m rithmus M2 in O(log m + log n) Zeit mit O( + ) Prozessoren und log n log m | {z } | {z } Schritt2

Schritt1

3.3. MISCHEN

45

dem Gesamtaufwand O(m + n) gemischt werden k¨onnen. Problem: Mergesort hat zurzeit O(log2 n) Laufzeit.

3.3.1

Schnelleres Mischen

Parallele Suche: Gegeben: Sortiertes Feld A = (a1 , a2 , ...an ) mit ai < ai+1 mit p Prozessoren und CREW-PRAM. Gesucht: ist i ∈ {1, . . . , n − 1} mit ai ≤ x < ai+1 und i = 1, . . . , n − 1  wobei i = 0 falls x < a1 = rang(x, A) oder i = n falls x > an  Idee: l m Bestimme den Rang(x,A), indem A in Bl¨ocke der L¨ange np geteilt wird. Nennen wir diese Bl¨ocke 1, . . . , p, wobei ri das letzte Element des jeweiligen Bl¨ockes ist. Nun vergleichen wir parallel ri mit x, wenn x < ri ist, schauen wir bei unserem linken Nachbarn nach ob dies bei ihm auch der Fall ist. Wenn x < ri−1 , dann ist x nicht in unserem Block enthalten.

46KAPITEL 3. ELEMENTARE TECHNIKEN PARALLELER ALGORITHMEN Algorithmus 12 Suchen 1 (S1) 1: if n < 4 then 2: Index i mit einem Prozessor berechnen; 3: else if x < a1 then 4: i := 0; 5: else if x ≥ an then 6: i := n; 7: else l m 8: l := np ; 9: for j := 1 to p par do 10: if j < p then 11: rj := j ∗ l; 12: else if j = p then 13: rj := n; 14: end if 15: if x = arj then 16: return rj ; 17: end if 18: if x < arj then 19: if (j = 1) ∨ (j > 1 ∧ x > arj−1 ) then 20: Durchsuche rekursiv den Block(arj−1 +1 , ...arj −1 ); 21: end if 22: end if 23: end for 24: end if Laufzeit:

  c1 f¨ ur n ≤ 4 j k T (n) ≤ n  T + c2 sonst p

Hieraus folgt:     n n T (n) ≤ T + c2 ≤ T + c2 + c2 p p2 .. .   n ≤ T + kc2 pk W¨ahle k so, dass

n pk

≤ 4 ist.

47

3.3. MISCHEN n k

w¨ahlen,  dann  folgt daraus:  n T (n) = O logp n = O log log p Das Suchen eines Elements in einer sortierten Folge, beziehungsweise die   log n Bestimmung des Ranges mit Algorithmus 12 geht in O log p Zeit mit p Prozessoren. Wenn wir k = logp

48KAPITEL 3. ELEMENTARE TECHNIKEN PARALLELER ALGORITHMEN Wie berechnet man die R¨ange von Elementen einer kurzen Folge in einer l¨angeren sortierten Folge? Gegeben: Sei X eine sortierte Folge mit unterschiedlichen Elementen und sei |X| = n. Und Y eine beliebige Folge mit |Y | = m = O(nε ). F¨ ur konstante ε : 0 < ε < 1 Gesucht: Wollen den Rang(Y:X) bestimmen. Annahme: Wir haben n Prozessoren zur verf¨ ugung. Idee: Bestimme den Rang(y,X) f¨ ur jedes y ∈ Y mit Algorithmus 12 parallel. n zur Verf¨ L¨ osung: F¨ ur jedes Elementvon Y stehen    m Prozessoren  ugung. log n log n n = O (1−ε) also kann man in Zeit: O log = O loglogn1−ε = O(1) n log n m

Hieraus folgt, dass man den Rang(Y : X) in O(1) Zeit mit n Prozessoren im CREW-PRAM Modell bestimmen kann.

3.3.2

Schnellerer, nicht kostenoptimaler Mischalgorithmus M3

Wie bisher sollen 2 sortierte Folgen A = (a1 , . . . , an ), B = (b1 , . . . , bm ) mit jeweils paarweise verschieden Elementen zu einer sortierten Folge C gemischt werden. Weiterhin sei N = n + m. Neu ist dabei die Verfahrensweise rang(B:A) zu berechnen. √ √ Idee: B wird in m Bl¨ocke der L¨ange m unterteilt. Von den Anfangsele√ menten dieser √ Bl¨ocke B1 , B2 , · · · , B m wird der Rang in A berechnet. Damit bilden sich m viele Bl¨ocke in A. Jetzt wird rekursiv der Rang der zueinandergeh¨origen Bl¨ocke Bi und Ai ermittelt und daraus der Rang der einzelnen Elemente aus B in der gesamten Menge A.

Der Algorithmus fu ¨ r die Berechnung von rang(B, A): 1. Falls m < 4 berechne rang(B,A) mit Algorithmus S1 mit p = N

49

3.3. MISCHEN B1

B2

B3

Bk

B

A1

A2

A3

Ak A

j1

j2

j3

jk

Abbildung 3.7: Algorithmus M3 √ 2. Sonst: Es sei k = m. Bestimme parallel √ die R¨ange von (bk , b2k , . . . , bk·k ) in A mit Algorithmus S1 mit jeweils N Prozessoren und setze ji =rang(bik , A). Es entstehen die Bl¨ocke Bi = (bik , . . . , b(i+1)k−1 ) und Aj = (aji +1 , · · · , aji+1 ). 3. Bestimme rekursiv rang(Bi : Ai ) f¨ ur i = 1, · · · , k parallel 4. F¨ ur l = 1, · · · , m berechne parallel: i=

√l m

rang(bl , A) = ji +rang(bl , Ai ) Laufzeit T (m): n 1. S1 kostet O( log ) bei Listenl¨ange n und p Prozessoren. Die Berechnung log p erfolgt also in O(1). n log√n 2. S1 kostet O( log ) bei Listenl¨ange n und p Prozessoren. Es gilt: O( log )= log p n O(1). √ 3. T ( m)

4. O(1) √ Insgesamt gilt demnach T (m) = T ( m) + O(1). F¨ ur k = log log m gilt 2k 2k−1 2k 0 T (2 ) = T (2 ) + O(1). Da f¨ ur T (2 ) = T (k) = T 0 (k − 1) + O(1) folgt, dass T 0 (k) = O(k) ist T (m) = O(log log m). Der Algorithmus bestimmt den rang(B:A) in O(log log m) Zeit mit O(n + m) = O(N ) Prozessoren und daher mit Aufwand von O((n + m) log log m).

50KAPITEL 3. ELEMENTARE TECHNIKEN PARALLELER ALGORITHMEN Algorithmus 13 Mischen 3 (M3) Berechne rang(B:A) wie gerade beschrieben Berechne rang(A:B) wie gerade beschrieben Mische A und B zu C wie bei M1 Diese schnellere Rangberechnung wird f¨ ur das Mischen von A und B eingesetzt: Der Algorithmus M3 mischt A und B in O(log log N ) Zeit mit O(N ) Prozessoren unter Einsatz von CREW. Der Aufwand ist O(N log log N ).

3.3.3

Schnellerer und kostenoptimaler Mischalgorithmus M4

Der Aufwand von O(N log log N ) des vorherigen Algorithmus ist nicht optimal. Der folgende Algorithmus M4 mischt mit Aufwand O(N ) bei geichbleibender Laufzeit O(log log N ). Bl¨ocke der L¨ange log log m unterteilt und A wird Idee: B wird in log m log m n in log log n Bl¨ocke der L¨ange log log n unterteilt. Von den Anfangselementen wird jeweils der Rang in der anderen Liste ermittelt. Damit bildet sich eine feinere Unterteilung von A und B. Zueinandergeh¨orende Abschnitte werden jeweils sequentiell gemischt.

p1

q1

p2

p3

A

B Abbildung 3.8: Algorithmus M4

Der Algorithmus M4 fu ¨ r das Mischen von A und B: 1. Teile A und B in d log nlog n e bzw. d log m e Bl¨ocke der Gr¨oße blog log nc log m

3.4. SORTIEREN

51

bzw. blog log mc. Seien p1 , p2 , . . . bzw. q1 , q2 , . . . die Anfangselemente dieser Bl¨ocke und A0 = (p1 , p2 , . . . ) bzw. B 0 = (q1 , q2 , . . . ). 2. Mische A0 und B 0 mit Algorithmus M3. Damit weiß jedes pi in welchen Block in B es geh¨ort (analog f¨ ur qi ). 3. F¨ ur jedes pi , qj wird parallel der genaue Rang in der jeweils anderen Liste durch sequentielle Suche innerhalb des ermittelten Blocks berechnet. Damit werden A und B in feinere Bl¨ocke der L¨ange ≤ log log N aufgeteilt. 4. F¨ ur alle zueinandergeh¨orende Blockpaare Ai ,Bi mische sequentiell Ai ) und Bi . (i = 1, . . . , log N log N Laufzeit T (N ): 1. O(1) . Ingesamt sind es demnach 2. Es gilt |A0 | = log nlog n sowie |B 0 | = log m log m N Elemente. M3 ben¨otigt also O(log log log N ) = O(log log N ) log log N log N N Zeit mit O( log log N ) Prozessoren. 3. Eine sequentielle Suche mit einem Prozessor pro Block braucht O(Blockl¨ange)= ) Prozessoren. O(log log N ) Zeit mit O( log N log N 4. Sequentielles Suchen kostet O(Blockl¨ange)= O(log log N ) Zeit mit O( log N ) log N Prozessoren. Der Algorithmus M4 mischt A und B in O(log log N ) Zeit mit O( log N ) log N Prozessoren unter Einsatz von CREW. Der Aufwand ist O(N ) und damit optimal.

3.4

Sortieren

Gegeben ist die Folge A = (a1 , · · · , an ), gesucht ist A aufsteigend sortiert. Die Sortierung erfolgt u ¨ber Mergesort und durch die Verwendung eines der bisherigen Mischalgorithmen. Die rekursiven Aufrufe von Mergesort erfolgen parallel zueinander. F¨ ur das Mischen wird M1, M2, M3 oder M4 verwendet. Laufzeit T (n):

52KAPITEL 3. ELEMENTARE TECHNIKEN PARALLELER ALGORITHMEN Algorithmus 14 Mergesort(A) if n ≤ 1 then return A else m = b n2 c A1 =Mergesort(a1 , . . . , am ) A2 =Mergesort(am+1 , . . . , an ) return Mische(A1 , A2 ) end if

Die Laufzeit des parallelen Mischens sei TM (n). Dann ist T (n) = T ( n2 ) + TM (n) + O(1). Bei Einsatz von M2 mit TM (n) = log n ist beispielsweise T (n) = O(log2 n).

Kapitel 4 Parallele Graphenalgorithmen Graphen werden im Allgemeinen definiert als ein geordnetes Paar G = (V, E), wobei V = {1, ..., n} die Knotenmenge und E die Kantemenge darstellt. Im Computer wird der Graph u ¨blicherweise durch eine Adjazenzmatrix oder je einer Adjazenzliste f¨ ur jeden Knoten dargestellt. Eine Adjazenzmatrix hat dabei an der Stelle i, j eine 1, wenn eine Kante zwischen dem Knoten i und dem Knoten j existiert und eine 0 sonst. Im folgenden wird von ungerichteten Graphen ausgegangen.

4.1

Zusammenhangskomponenten

Zusammenhangskomponenten von Graphen lassen sich sequentiell sehr einfach durch Breiten- bzw. Tiefensuche berechnen, wobei eine Laufzeit von O(n2 ) bei Adjazenzmatrizen und O(n + E) bei Adjazenzlisten m¨oglich ist. Zusammenhangsmatrix: n × n - Matrix   1, falls Weg von i nach j existiert Bij =  0, sonst

Bool’sche Matrizenmultiplikation: A, B sind n × n - Matrizen mit Eintr¨agen ∈ {0, 1}. Dann ist das Bool’sche Produkt der beiden Matrizen definiert als: (A · B)ij = ∨nk=1 (aik ∧ bkj ) 53

54

KAPITEL 4. PARALLELE GRAPHENALGORITHMEN

Dieses Produkt kann in O(log n) Zeit mit n3 Prozessoren berechnet werden. ¨ (siehe Ubung) Es ist aber auch m¨oglich den Gesamtaufwand auf O(n3 ) zu n3 reduzieren, in dem nur log Prozessoren verwendet werden. n Sei A Adjazenzmatrix von G = (V, E). Was ist A2 mit dem oben definierten Bool’schen Matrixprodukt? A2ij = ∨nk=1 (aik ∧ akj )

Der Eintrag A2ij ist also 1, wenn ein k ∈ {1, ..., n} existiert, so dass aik und akj wahr sind, also ein Weg von i nach k und ein Weg von k nach j existiert. Das bedeutet, dass ein Weg der L¨ange 2 zwischen den Knoten i und j im Graphen vorhanden ist. Per Induktion kann man beweisen, dass diese Aussage auch allgemeiner gilt: Akij = 1 ⇔ ∃ Weg der L¨ange k von i nach j Dabei ist k = 0, 1, 2, ... und A0 ist die Einheitsmatrix. Definition: A0 := A ∨ In Damit ist A0 die Matrix, dessen Eintr¨age jeweils 1 sind, wenn ein Weg der L¨ange ≤ 1 existiert. ⇒ (Ak0 )ij = 1 ⇔ ∃ Weg der L¨ange ≤ k von i nach j

Die eigentliche Frage ist jedoch nicht, ob ein Weg einer bestimmten L¨ange existiert, sondern ob u ¨berhaupt ein Weg existiert. Dies ist der Fall, wenn ein Weg der L¨ange ≤ n existiert. ∃ Weg von i nach j ⇔ (An0 )ij = 1 Damit ergibt sich der erste Algorithmus zum Berechnen der Zusammenhangsmatrix: Algorithmus 15 Zusammenhangsmatrix 1: X := A ∨ In ; 2: for i := 1 to dlog ne do 3: X := X 2 ; 4: end for 5: return X;

55

4.1. ZUSAMMENHANGSKOMPONENTEN Dabei ergibt sich eine Laufzeit von O(log2 n) mit

n3 log n

Prozessoren.

Das urspr¨ ungliche Problem ist damit noch nicht gel¨ost. Wir brauchen nicht die Zusammenhangsmatrix, sondern die Zusammenhangskomponenten. Eine M¨oglichkeit die Zusammenhangskomponenten darzustellen ist den Knoten Nummern zu geben, wobei jeder Knoten einer Komponente die gleiche Nummer bekommt. Diese Nummerierung muss mit Hilfe der Zusammenhangsmatrix berechnet werden. Beispiel:  1   0 B=  0  1

0 0 1 1 1 1 0 0

 1   0   0  1

Ordne jedem Knoten i die Nummer ci zu, wobei ci = min{j | Bij = 1}. (Kleinste Nummer j in Zeile i mit Bij = 1) Dies kann f¨ ur alle Zeilen i parallel berechnet werden, wobei n Prozessoren f¨ ur jede Zeile von B verwendet werden. Im Beispiel kommen also folgende Nummern heraus:   1     2     2   1 Die Laufzeit pro Zeile ist O(log n) mit insgesamt n2 Prozessoren.

4.1.1

Algorithmus Z1

Damit ergibt sich insgesamt ein Algorithmus Z1 f¨ ur die Berechnung der Zun3 ) sammenhangskomponenten mit einer Laufzeit von O(log2 n) und O( log n Prozessoren. Der Algorithmus l¨auft mit EREW. Der Gesamtaufwand betr¨agt O(n3 · log n), was im Vergleich zu den sequentiellen Algorithmen (Tiefen/Breitensuche mit O(n2 )) nicht besonders gut ist.

56

KAPITEL 4. PARALLELE GRAPHENALGORITHMEN

4.1.2

Algorithmus Z2

Auch dieser Algorithmus verwendet n2 Prozessoren um die Zusammenhangskomponenten eines Graphen zu berechnen. Der Graph ist wieder definiert als G = (V, E), V = {1, ..., n} mit der Adjazenzmatrix A. Er besteht im wesentlichen aus drei Schritten, die solange wiederholt werden, bis E = ∅: 1

7

9

2

6

5

8

3

4

Abbildung 4.1: Beispielgraph • Schritt 1: F¨ ur jeden Knoten v ∈ V : setze Zeiger auf cv = min{u | (u, v) ∈ E} F := der durch diese Zeiger entstehende Wald, k B¨aume mit Knotenmengen V1 , ..., Vk und Wurzeln r1 , ..., rk ∈ {1, ..., n} 1

8

2

3

4 9

6

5 7

Abbildung 4.2: Beispielgraph nach Schritt 1 • Schritt 2: Kontrahiere jedes Vi zu einem Superknoten mit Nummer ri und teile jedem urspr¨ unglichen Knoten, der zu Vi geh¨ort die Nummer ri mit

57

4.1. ZUSAMMENHANGSKOMPONENTEN

1

2

8

Abbildung 4.3: Beispielgraph nach Schritt 2 • Schritt 3: E := {(ri , rj ) | ∃u ∈ vi , v ∈ vj : (u, v) ∈ Ealt } 1

2

8

Abbildung 4.4: Beispielgraph nach Schritt 3

Korrektheit: Die Korrektheit des Algorithmus sollte intuitiv klar sein. So ist am Ende bei jedem Knoten die Nummer des kleinsten Knotens in der gleichen Zusammenhangskomponente gespeichert und man erh¨alt eine Darstellung wie im Algorithmus Z1. Ein genauerer Beweis kann mit einer Induktion u ¨ber die Anzahl der Iterationen durchgef¨ uhrt werden. Einzelheiten und Laufzeit: • Schritt 1: Analog zu Z1, ausgehend von einer Adjazenzmatrix ⇒ n2 Prozessoren in O(log n) Zeit (EREW) • Schritt 2: Hier wird Pointerjumping verwendet um jedem Knoten die Wurzel seines Baumes mitzuteilen. ⇒ O(log n) mit n Prozessoren (CREW) Außerdem lesen alle Knoten im Feld ihres momentanen Superknotens, ob eine neue Nummer erschienen ist. • Schritt 3: F¨ ur alle Knotenpaare u, v parallel: Zugeordnete Repr¨asentanten (ri , rj ) Falls (u, v) ∈ E und ri 6= rj , f¨ uge Kante (ri , rj ) hinzu 2 ⇒ O(1) mit n Prozessoren (CRCW, da mehrere Kanten zwischen zwei Superknoten existieren k¨onnen)

58

KAPITEL 4. PARALLELE GRAPHENALGORITHMEN

Also kann eine Iteration mit einer Laufzeit von O(log n) mit n2 Prozessoren berechnet werden. Damit bleibt nur noch zu kl¨aren, wie viele Iterationen n¨otig sind um die Zusammenhangskomponenten zu berechnen. Die Zahl der Knoten, die nach Schritt 1 in B¨aumen mit mehr als 1 Knoten liegen wird halbiert. Nach O(log n) Iterationen liegt demnach kein Knoten mehr in einem Baum mit mehr als einem Knoten. Sie sind alle isoliert und es gibt keine Kanten zwischen ihnen. Daraus folgt, dass sich die Zusammenhangskomponenten mit Z2 in O(log2 n) Zeit mit n2 Prozessoren berechnen lassen.