Parallele Algorithmen Walter Unger, Dirk Bongartz Lehrstuhl für Informatik I 8. November 2006 Teil I Motivation 1 Einleitung NP-schwer 2 Zeit vs. Speicher poly-logarithmischer Zeit vs. Speicher 3 Erste Reduktionen Definition Generability Bemerkungen 4 Weitere Reduktionen CVP,MCVP,TSMCVP CFE LFMIS LFMC DFS MAXFLOW Einleitung Zeit vs. Speicher Erste Reduktionen Weitere Reduktionen NP-schwer Vergleich mit NP-schwer NP-schwer: schwersten Probleme aus N P. Theorie der NP-vollständigen Probleme wurde aufgebaut, da man für viele Probleme keine Polynomzeit Algorithmen kennt. Ein Problem ist NP-schwer ⇔: Man kann in Polynomzeit jedes andere Problem aus NP darauf reduzieren. Erste NP-schwere Problem: Hält eine nichtdeterministische TM in Polynomzeit? Alle anderen NP-schweren Problem sind davon reduziert worden. Man nimmt an, für diese gibt es keine Polynomzeit Algorithmen. Damit sind NP-schwere Probleme keine Kandidaten zum Parallelisieren, denn mit polynomial vielen Prozessoren ist die Laufzeit immer noch (vermutlich) exponential. Einleitung Zeit vs. Speicher Erste Reduktionen Weitere Reduktionen NP-schwer Beobachtungen für Problem aus P Problem aus P sind Kandidaten zum Parallelisieren. Ein Problem ist gut parallelisierbar, wenn es mit: mit polynomial vielen Prozessoren in poly-logarithmischer Zeit lösbar ist. Diese Klasse wird N C genannt (Nick’s Class). Klar ist: N C ⊂ P. ? Frage: Gilt N C = P? Wird nicht angenommen, d.h. man vermutet, es gibt Probleme, die sind nicht gut parallelisierbar. Daher Theorie der P-vollständigen Probleme Einleitung Zeit vs. Speicher Erste Reduktionen Weitere Reduktionen NP-schwer Reduktionen für P Erinnerung an N PC (bei der Abgrenzung von P): Schweres Problem: Hält nichtdeterministische TM in Polynomieller Zeit? Reduktion: Deterministisch in Polynomieller Zeit ausführbar. Allgemein: Schweres Problem: aus der “schweren Klasse”. Reduktion durch Berechung in der “leichten Klasse”. Nun analog für P (bei der Abgrenzung von N C): Schweres Problem: Hält deterministische TM in Polynomieller Zeit? Reduktion: mit polynomial vielen Prozessoren in poly-logarithmischer Zeit. Analoge Reduktion: mit poly-logarithmischem Speicher. Einleitung Zeit vs. Speicher Erste Reduktionen Weitere Reduktionen poly-logarithmischer Zeit vs. Speicher Wir hatten: Reduktion: mit polynomial vielen Prozessoren in poly-logarithmischer Zeit. Analoge Reduktion: mit poly-logarithmischem Speicher. Wir machen folgende Umformungen: Aus dem parallelen Algorithmus wird ein paralleles Schaltnetzwerk. Dies hat poly-logarithmische Tiefe und polynomiale Breite. Zum Bestimmen eines Wert im Schaltnetzwerk müssen nur die Werte auf einem Pfad zu einer Eingabe gespeichert werden. Also poly-logarithmischem Speicherbedarf. Einleitung Zeit vs. Speicher Erste Reduktionen Weitere Reduktionen Definition P-Vollständig Definition Ein Problem X ist P-Vollständig falls gilt: X ist in P. Jedes Problem Y aus P kann auf X mit poly-logarithmischem Speicherbedarf reduziert werden. D.h. eine Funktion f kann mit poly-logarithmischem Speicherbedarf rechnet werden, so dass gilt: ∀w ∈ Σ∗ : w ∈ X ⇔ f (w ) ∈ Y Einleitung Zeit vs. Speicher Erste Reduktionen Weitere Reduktionen Generability Erste Reduktion (Einleitung) Definition (Generability) Eingabe: Menge X mit binären Operator ⊙, T ⊂ X und s ∈ X . Ausgabe: Ist s im Abschluss von T bezüglich ⊙. Setze S ⊙ S := {a ⊙ b | a, b ∈ S}. Algorithmus für Generability (X , ⊙, S, s) in P: while S 6= S ⊙ S do S = S ⊙ S return s ∈ S. Wir zeigen zuerst P-Vollständigkeit für eine ternäre Operation. d.h. ⊙ wird ersetzt durch next(u, v , w ). Reduktion dabei vom Halteproblem einer deterministischen TM. Einleitung Zeit vs. Speicher Erste Reduktionen Weitere Reduktionen Generability Erste Reduktion Definition (Generability’) Eingabe: Menge X mit Funktion next(u, v , w ), T ⊂ X und s ∈ X . Ausgabe: Ist s im Abschluss von T bezüglich next. Definition (Einband TM) Eingabeband mit Postitionen 0, 1, 2, ·T (n) + 1. Mit c(i, j) ∈ Σ gibt Bandinhalt der Zelle i zum Zeitpunkt j an. Mit c(0, j) = c(T (n) + 1, j) = $ für alle Zeitpunkte j. Eine Funktion trans bestimmt die Übergänge der TM. D.h. c(p, t + 1) = trans(c(p − 1, t), c(p, t), c(p + 1, t)). Eingabe durch c(p, 0) (∀p : 1 6 p 6 T (n). Ausgabe durch c(1, T (n)) wobei # True kodiert. Einleitung Zeit vs. Speicher Erste Reduktionen Weitere Reduktionen Generability Erste Reduktion (Generability’) Theorem: Generability’ ist P-vollständig. Beweis: Ein TM kann in N C in die obige Form gebracht werden. Das Tripple (t, p, sym) bezeichne mit sym den Inhalt der p-ten Zelle zum Zeitpunkt t. Nun daraus Eingabe für Generability’ erzeugen: X = {0, 1, · · · , T (n)} × {0, 1, · · · , T (n) + 1} × Σ. T = {(0, i, c(0, i)) | 0 6 i 6 T (n) + 1} s = (T (n), 1, #) next = trans Kann in N C bestimmt werden. s ist im Abschluss von next gdw. TM hält mit Wert True. Einleitung Zeit vs. Speicher Erste Reduktionen Weitere Reduktionen Generability Erste Reduktion (Generability) Theorem: Generability ist P-vollständig. Beweis: Reduktion von Generability’ X ′ := X ∪ X 2 (X von oben) T = {(0, i, c(0, i)) | 0 6 i 6 T (n) + 1} s = (T (n), 1, #) Es reicht aus, aus next einen binären Operator ⊙ zu machen. u ⊙ v := (u, v ) und (u, v ) ⊙ w := next(u, v , w ) Einleitung Zeit vs. Speicher Erste Reduktionen Weitere Reduktionen Bemerkungen Bemerkungen Lemma: Falls ⊙ assuziativ ist, dann ist das zugehörige Generability-Problem in N C. Beweis: Wir transformieren das Problme auf das Erreichbarkeits-Problen in Graphen G . Falls x ⊙ z = y dann erzeuge Kante (x, y ) mit Label z. G = (X , E ) mit E = {(x, y ) | ∃z ∈ X : x ⊙ z = y } und ∀(x, y ) ∈ E : l(x, y ) := {z ∈ X | x ⊙ z = y }. Falls es nun einen Pfad von a ∈ T nach s gibt über Kanten mit Labels b, c, d, · · · dann kann s erzeugt werden durch: ((· · · (a ⊙ b) ⊙ c) ⊙ d) · · · ). Falls s aus Elementen aus T mit ⊙ erzeugt werden kann, dann auch in der Form: ((· · · (a ⊙ b) ⊙ c) ⊙ d) · · · ). Damit gibt es auch einen Pfad in dem konstruierten Graphen G . Einleitung Zeit vs. Speicher Erste Reduktionen Weitere Reduktionen CVP,MCVP,TSMCVP Reduktion (CVP) Definition (CVP) Eingabe: Ein boolscher Schaltkreis mit Eingabewerten. Ausgabe: Ist der Ausgabewert true. Theorem: Das CVP ist P-vollständig. Beweis Reduktion von Generability Problem. Die Elemente aus T ergeben die Eingaben des Schaltkreises mit den Werten true. Die Ausgabe ergibt sich durch das Element s. Einleitung Zeit vs. Speicher Erste Reduktionen CVP,MCVP,TSMCVP Fortsetzung der Reduktion (CVP) Für jedes Element x aus X \ T führe aus: Bestimme Paare aus X × X die x ergeben: (y1 , z1 ), (y2 , z2 ), (y3 , z3 ), · · · , (ykx , zkx ) D.h. yi ⊙ zi = x für alle 1 6 i 6 kx . Bilde Teil des Schaltkreises: x= kx _ yi ∧ zi i=1 Damit hat x den Wert true falls x erzeugt werden kann. Damit hat s den Wert true falls s erzeugt werden kann. Die Konstruktion ist in N C möglich. Weitere Reduktionen Einleitung Zeit vs. Speicher Erste Reduktionen Weitere Reduktionen CVP,MCVP,TSMCVP Reduktion (MCVP) Definition (MCVP) Eingabe: Ein boolscher Schaltkreis mit Eingabewerten und nur mit Operationen ∨ und ∧. Ausgabe: Ist der Ausgabewert true. Theorem: Das MCVP ist P-vollständig. Beweis Analoger Beweis wie beim CVP Problem. Einleitung Zeit vs. Speicher Erste Reduktionen Weitere Reduktionen CVP,MCVP,TSMCVP Reduktion (TSMCVP) Definition (TSMCVP) Eingabe: Ein boolscher Schaltkreis mit Eingabewerten, nur mit Operationen ∨ und ∧ und eine topologische Sortierung der Werte. Ausgabe: Ist der Ausgabewert true. Theorem: Das TSMCVP ist P-vollständig. Beweis Analoger Beweis wie beim CVP Problem, aber man beachte: Der Beweis für Generability’ enthielt topologische Sortierung. Dies war die lexicographische Ordnung der Elemente (t, p, sym). Diese Ordnung/Nummerierung kann leicht in den weiteren Reduktionsschritten aufrechtgehalten werden. Einleitung Zeit vs. Speicher Erste Reduktionen Weitere Reduktionen CFE Reduktion (CFE) Definition (CFE) Eingabe: Eine kontextfreie Grammatik G . Ausgabe: Erzeugt G das leere Wort ǫ. Theorem: Das CFE ist P-vollständig. Beweis (Reduktion von Generability Problem): Sei (X , T , ⊙, s) Eingabe vom Generability Problem. X sind die Nichtterminale von G . s das Startsymbol. Für jedes x ∈ T erzeuge Regel: x −→ ǫ. Falls y ⊙ z = x erzeuge Regel: x −→ yz. Bemerkung: Falls G keine ǫ-Regeln enthällt, dann ist CFE in N C. Einleitung Zeit vs. Speicher Erste Reduktionen Weitere Reduktionen LFMIS Reduktion (LFMIS) Definition (LFMIS) Eingabe:ungerichteter Graph G = (V , E ). Ausgabe:lexicographisch erste maximum unabhängige Menge (IS) von G . Theorem: Das LFMIS ist P-vollständig. Beweis (Reduktion vom MCVP Problem) Beachte Greedy-Verfahren löst LFMIS Problem. Seien V = {v1 , v2 , · · · , vn } Knoten des MCVP Problems in ihrer topologischen Sortierung. Seien {v1 , v2 , · · · , ve } die Eingabeknoten und vn der Ausgabeknoten. Wir konstruieren G = (V ′ , E ′ ) als Eingabe für LFMIS. Einleitung Zeit vs. Speicher Erste Reduktionen Weitere Reduktionen LFMIS Fortsetzung der Reduktion (LFMIS) v ′ ∈ IS ⇔ v v ′′ ∈ IS ⇔ v Sei V ′ = {v1′ , v1′′ , v2′ , v2′′ , · · · , vn′ , vn′′ } nummeriert von 1 bis 2n. Die Nummerierung von vi′ , vi′′ wird vertauscht, falls vi ein Oder-Knoten ist oder vi ein Eingabeknoten ist mit dem Wert false. Für alle 1 6 i 6 n erzeuge Kante {vi′ , vi′′ }. Damit ist nur einer der Knoten vi′ , vi′′ im IS. Falls v ein Und-Knoten in G mit Söhnen u und w , dann erzeuge Kanten {v ′ , u ′′ } und {v ′ , w ′′ }. Damit ist v ′ im IS nur wenn keiner der Knoten u ′′ , w ′′ im IS sind. Falls v ein Oder-Knoten in G mit Söhnen u und w , dann erzeuge Kanten {v ′′ , u ′ } und {v ′′ , w ′ }. Damit ist v ′′ im IS nur wenn keiner der Knoten u ′ , w ′ im IS sind. Damit folgt das LFMIS genau der Schaltkreisberechnung. Einleitung Zeit vs. Speicher Erste Reduktionen Weitere Reduktionen LFMC Reduktion (LFMC) Definition (LFMC) Eingabe: ungerichteter Graph G = (V , E ). Ausgabe: lexicographisch erste maximum Clique von G . Theorem: Das LFMC ist P-vollständig. Beweis Reduktion vom LFMIS Problem. Sei G = (V , E ) Eingabe vom LFMIS Problem. Dann ist G = (V , E ) Eingabe vom LFMC Problem. v ′ ∈ IS ⇔ v v ′′ ∈ IS ⇔ v Einleitung Zeit vs. Speicher DFS DFS Baum Gegeben G = (V , E ) Procedure DFS(v) if DFI (v ) = 0 then counter := counter + 1 DFI (v ) := counter forall w ∈ V : (v , w ) ∈ E do DFS(w) Erste Reduktionen Weitere Reduktionen Einleitung Zeit vs. Speicher Erste Reduktionen Weitere Reduktionen DFS Reduktion (DFS) Definition (DFS) Eingabe: Gerichteter Graph G = (V , E ) und V ∈ V . Ausgabe: Die Werte DFI (w ) des Aufrufs DFS(v ) für alle w ∈ V . Theorem: Das DFS ist P-vollständig. Beweis Reduktion vom CVP Problem mit ⊙ := x ∨ y = x ∧ y Ist leicht zu sehn, dieses CVP Problem ist auch P-vollständig. Idee: zu jedem Wert v in der Eingabe von CVP wird es im Graphen G = (V , E ) zwei Knoten s und t geben, mit v ist true g.d.w. DFI (s) < DFI (t) Einleitung Zeit vs. Speicher Erste Reduktionen Weitere Reduktionen DFS Fortsetzung der Reduktion (DFS) Seien v1 , v2 , · · · , vn die Knoten des Schaltkreises. Zu jedem vi wird ein Teilgraph Gi erzeugt. Die Teilgraphen Gi sind kantendisjunkt, aber nicht knotendisjunkt. Gi und Gj (i < j) können geneinsamen Knoten i#j haben. vi habe als Eingabeknoten vi1 und vi2 und die Knoten vo1 , vo2 , vo3 , · · · , vok nutzen vi als Eingabe. Dann hat Gi für k = 3 die im Folgenden angegebene Gestalt. Dabei wird die Reihenfolge der Kanten in den Adjazenzlisten durch die Anzahl der Pfeilspitzen angegeben. Falls vi ein Eingabeknoten des Schaltkreises ist und die Knoten vo1 , vo2 , vo3 , · · · , vok nutzen vi als Eingabe, dann ergibt sich ein vereinfachter Graph Gi . Dieser ist danach zu sehen. Einleitung Zeit vs. Speicher Erste Reduktionen DFS Fortsetzung der Reduktion (DFS) last(i − 1)r ? r first(i)@ @ R @ @ i1 #i i2 #i -r -r rs(i) 6 ? rH j @ j H HH @ Hir#o1 R @ @ 6 r @ vi ist intern j HH j H @ H ir#o2 H @ 6 @ rH j @ j H HH Hir#o3 @ 6 @ last(i)r @ r t(i) ? Weitere Reduktionen Einleitung Zeit vs. Speicher Erste Reduktionen DFS Fortsetzung der Reduktion (DFS) last(i − 1)r ? r first(i) - s(i) r ? vi ist Eingabe last(i)r ? rH j H HH Hri #o1 r HH j H H i #o2 Hr rH j H HH Hri #o3 r t(i) Weitere Reduktionen Einleitung Zeit vs. Speicher Erste Reduktionen Weitere Reduktionen DFS Fortsetzung der Reduktion (DFS) Der DFS Durchlauf wird bei first(1) starten. Nach last(i) wird als nächstes first(i + 1) besucht werden. Die Reihenfolge wie s(i) und t(i) in Gi durchlaufen werden gibt den Wert von vi an. Nachdem last(n) besucht wurde, ist jeder Graph Gi besucht worden, nur wenige Teile ggf. nicht. Einleitung Zeit vs. Speicher Erste Reduktionen Weitere Reduktionen DFS Fortsetzung der Reduktion (DFS) Lemma Wir betrachten eine DFS-Durchlauf in G vom Knoten first(1): Falls vi den Wert true hat, dann wird s(i) vor t(i) besucht und die Knoten i#o1 , i#o2 , · · · , i#ok werden nach first(i) und vor last(i) besucht. Falls vi den Wert false hat, dann wird t(i) vor s(i) besucht und keiner der Knoten i#o1 , i#o2 , · · · , i#ok wird im Intervall zwischen first(i) und last(i) besucht. Beweis Per Induktion: Induktionsanfang, betrachte alle Eingabeknoten. Induktionsschritt, Aussage gelte für alle Graphen Gj (1 6 j < i). Einleitung Zeit vs. Speicher Erste Reduktionen DFS Fortsetzung der Reduktion (Induktionsanfang) Falls vi den Wert true hat, dann wird s(i) vor t(i) besucht und die Knoten i#o1 , i#o2 , · · · , i#ok werden nach first(i) und vor last(i) besucht. last(i − 1)r first(i) ? r - rs(i) ? vi ist Eingabe last(i)r ? r HH j H i #o1 H Hr r HH j HH i #o2 Hr rH j H HH i #o3 Hr r t(i) Weitere Reduktionen Einleitung Zeit vs. Speicher Erste Reduktionen DFS Fortsetzung der Reduktion (Induktionsschritt) Falls vi den Wert true hat, dann wird s(i) vor t(i) besucht und die Knoten i#o1 , i#o2 , · · · , i#ok werden nach first(i) und vor last(i) besucht. Dann haben vi1 und vi2 den Wert false. last(i − 1)r ? s(i) #i #i r - i1r - i2rr first(i)@ @ 6 R @ ? rH @ j jH H @ Hir#o1 R @ @ 6 r vi ist intern @ j H jH H @ Hir#o2 @ 6 r j @ H jH H ir#o3 H @ 6 @ last(i)r @ r t(i) ? Weitere Reduktionen Einleitung Zeit vs. Speicher Erste Reduktionen DFS Fortsetzung der Reduktion (Induktionsschritt) Falls vi den Wert false hat, dann wird t(i) vor s(i) besucht und keiner der Knoten i#o1 , i#o2 , · · · , i#ok wird im Intervall zwischen first(i) und last(i) besucht. Dann hat einer der Knoten vi1 oder vi2 den Wert true. last(i − 1)r ? s(i) #i #i r - i1r - i2rr first(i)@ @ 6 R @ ? rH @ j jH H @ Hir#o1 R @ @ 6 r vi ist intern @ j H jH H @ Hir#o2 @ 6 r j @ H jH H ir#o3 H @ 6 @ last(i)r @ r t(i) ? Weitere Reduktionen Einleitung Zeit vs. Speicher Erste Reduktionen Weitere Reduktionen DFS Fortsetzung der Reduktion (DFS) Die Konstruktion ist eine NC-Reduktion. Die Konstruktion ist eine direkte Umformung der Berechnung des Schaltkreises. Die Konstruktion kann auch auf ungerichtete Graphen erweitert werden. Einleitung Zeit vs. Speicher Erste Reduktionen Weitere Reduktionen MAXFLOW Reduktion (MAXFLOW) Definition (MAXFLOW) Eingabe: Gerichteter Graph G = (V , E ), s, t ∈ V und Kapazitätsfunktion c : E 7→ IN. Ausgabe: Maximaler Fluss von s nach t, d.h. Funktion f : E 7→ IN. mit: ∀e ∈ E : f (e) 6 c(e) P P und: ∀v ∈ V \ {s, t} : e=(a,v )∈E f (e) = e=(v ,a)∈E f (e) Theorem: Das MAXFLOW ist P-vollständig. Beweis Reduktion von Problem CVP. Zeige, selbst die Parität des Flusses zu bestimmen (PMAXFLOW), ist P-vollständig. Einleitung Zeit vs. Speicher Erste Reduktionen MAXFLOW Fortsetzung der Reduktion (MAXFLOW) O.E.d.A. Ausgangsgrad der Eingangsknoten ist 1. O.E.d.A. Ausgangsgrad der Knoten höchstens 2. O.E.d.A. Schaltkreis revers topologisch sortiert, d.h. v0 ist Ausgabeknoten. O.E.d.A. v0 ist ein Oder. Gegeben Schaltkreisgraph G = (V , E ). Eingabe für PMAXFLOW: G ′ = (V ∪ {s, t}, E ′ ). E ⊂ E ′. E ′ ⊂ E ∪ {(s, v ), (v , t) | v ∈ V } Weitere Reduktionen Einleitung Zeit vs. Speicher Erste Reduktionen MAXFLOW Fortsetzung der Reduktion (MAXFLOW) ∀(i, j) ∈ E : c((i, j)) = 2i . Falls Wert von vi true dann: f ((i, j)) = 2i (∀(i, j) ∈ E ). Falls Wert von vi false dann: f ((i, j)) = 0 (∀(i, j) ∈ E ). Sei d(0) = 1 und sonst d(i) der Ausgangsgrad von vi . Sei (k, i), (j, i) ∈ E , setze surplus(i) := 2k + 2j − d(i)2i . ∀i ∈ V : c(s, i) = 2i falls Wert von vi true ist. ∀i ∈ V : c(s, i) = 0 falls Wert von vi false ist. ∀i ∈ V : c(i, t) = surplus(i) falls vi ein Und-Knoten ist. ∀i ∈ V : c(i, s) = surplus(i) falls vi ein Oder-Knoten ist. c(0, t) = 1. Weitere Reduktionen Einleitung Zeit vs. Speicher Erste Reduktionen Weitere Reduktionen MAXFLOW Fortsetzung der Reduktion (MAXFLOW) ∀i ∈ V : f (s, i) = c(s, i). ∀i ∈ V : f (i, j) = c(i, j) falls vi ein Eingabeknoten ist. ∀(i, j) ∈ E : f (i, j) = c(i, j) = 2i falls vi den Wert true hat. ∀(i, j) ∈ E : f (i, j) = 0 falls vi den Wert false hat. f (0, t) = 1 falls v0 der Wert true hat. overflow (i) sei der Unterschied zwischen bisherigen Eingangsfluss und Ausgangsfluss. f ((i, t)) = overflow (i) falls vi ein Und-Knoten ist. f ((i, s)) = overflow (i) falls vi ein Oder-Knoten ist. Bemerkung: die definerte Funktion f ist eine Flussfunktion. Einleitung Zeit vs. Speicher Erste Reduktionen Weitere Reduktionen MAXFLOW Fortsetzung der Reduktion (MAXFLOW) Lemma Der definierte Fluss ist maximal. Nutze erweiternde Pfade von s nach t: Ein Kante e = (i, j) in dem Pfad heißt Vorwärtskante falls f (e) < c(e). Ein Kante e = (j, i) in dem Pfad heißt Rückwärtskante falls f (e) > 0. Bekannt: Fluss ist maximal ⇔ es gibt keinen erweiternden Pfad. Angenommen: es gibt keinen erweiternden Pfad. Pfad startet bei s mit einer Rückwärtskante. Pfad endet bei t mit einer Vorwärtskante. Einleitung Zeit vs. Speicher Erste Reduktionen Weitere Reduktionen MAXFLOW Fortsetzung der Reduktion (MAXFLOW) Damit gibt es drei aufeinanderfolgende Knoten j, i, k mit: j 6= t. k 6= s. (j, i) ist eine Rückwärtskante. (i, k) ist eine Vorwärtskante. (i, j), (i, k) sind Kanten in E ′ . f ((i, j)) > 0 und f ((i, k)) < c((i, k)). vi kann kein Eingabeknoten sein. vi kann kein Und-Knoten sein, denn aus j 6= t und f ((i, j)) > 0 folgt alle ausgehenden Kanten sind ausgefüllt. vi kann kein Oder-Knoten sein, denn aus k 6= s und f ((i, k)) < c((i, k)) folgt alle ausgehenden Kanten sind ohne Fluss. Einleitung Zeit vs. Speicher Erste Reduktionen MAXFLOW Literatur zu diesem Kapitel Literatur: A. Gibbons, W. Rytter: Efficient Parallel Algorithms. Cambridge University Press 1990. Kapitel 7 Weitere Reduktionen