4.1.2 Beispiel: Anzahl Elemente im Datenstrom Problem A NZAHL E LEMENTE IM DATENSTROM: Eingabe: Datenstrom mit Länge aus {0, . . . , n}. Länge vorab unbekannt. Aufgabe: Berechne n. Triviale Lösung: Zähler → Platz und Zeit pro Element O(log n). Kann man das noch toppen? Jedenfalls nicht deterministisch & exakt. . . 296 Satz 4.3: Für beliebige k benötigt jeder deterministische, exakte k -Runden-Datenstromalgorithmus für das Problem A NZAHL E LEMENTE IM DATENSTROM mindestens Speicherplatz ⌈log(n + 1)⌉. Beweis: Betrachte Datenströme mit Länge aus {0, . . . , n}. Idee: Algorithmus muss diese n + 1 Werte anhand des Speicherinhalts am Ende unterscheiden können. • Annahme: Algorithmus benutzt höchstens ⌈log(n + 1)⌉ − 1 Bits. • Dann höchstens 2⌈log(n+1)⌉−1 < n + 1 Speicherinhalte. • Für zwei Eingabelängen n1 , n2 ∈ {0, . . . , n} mit n1 6 = n2 hat Algorithmus am Ende selben Speicherinhalt, Fehler! 297 Erstaunlicherweise: Lösung des Problems mit nur O(loglog n) erwartetem Speicherplatz existiert → Randomisierung und Approximation benutzen. Erste Idee: Zähle jedes Element nur mit Wahrscheinlichkeit p ∈ [0, 1]. • Zählerinhalt am Ende ist Zufallsvariable X , EX = np. • Benutze X /p als Ausgabe, dann E(X /p) = n. Nicht so toll: • Erwarteter Speicherplatz um Faktor p besser, aber √ • mit positiver Wskt. relativer Fehler (1/ np) (hier ohne Beweis). 298 Ein echter Klassiker löst das Problem: Approximate Counting (Morris 1978). Idee: Speichere Logarithmus des Zählerstandes. Genauer: • Verwalte Registerwert r ∈ N0 , repräsentiert Zählerstand c(r ) = 2r − 1. • c(0) = 0 und c(1) = 1. Gut! • Aber: Bei Erhöhung i. A. kein passendes r ′ ∈ N, sodass c(r ′ ) = c(r ) + 1!? Abhilfe: • Mit Wskt. p(r ), passend gewählt: Registerwert inkrementieren und c(r + 1) darstellen. • Sonst r beibehalten und c(r ) darstellen. 299 Wie p(r ) passend wählen? 1 }| z z c(r ) = 2r − 1 { c(r + 1) − c(r ) }| c(r ) + 1 = 2r { c(r + 1) = 2r +1 − 1 Wähle p(r ) = 1 . c(r + 1) − c(r ) Dann für Zählerstand R ′ nach Update: ER ′ = p(r ) · c(r + 1) + (1 − p(r ))c(r ) = c(r ) + 1. 300 Algorithmus A PPROXIMATE C OUNTING: Initialisierung: r := 0. Update: Sei r aktueller Registerwert. • Wirf Münze mit Wskt. p(r ) für Kopf“. ” • Falls Kopf“, dann r := r + 1. ” Output: c(r ). Implementierungsdetail: Münzwurf mit Wskt. p(r )? Beachte dazu, dass 1 1 = 2−r . = r +1 p(r ) = r c(r + 1) − c(r ) 2 −1− 2 −1 Faire Münze r -mal werfen; Ausgabe 1“, wenn r -mal Kopf“; ” ” sonst Ausgabe 0“. Zeit O(r ), Platz O(log r ). ” 301 Satz 4.4: Sei Rn der Registerwert in A PPROXIMATE C OUNTING nach n Schritten und Cn := c(Rn ). Dann ist ECn = n und für alle ε > 0 gilt: 1 1 Pr |Cn − n| > εn ≤ . 1 − n 2ε2 Der erwartete Speicherplatz und die erwartete Zeit pro Element sind jeweils O(loglog n). Im Worstcase sind beide O(log n). Also (ε, δ)-Apprximation für Problem A NZAHL E LEMENTE. 302 Beweis: Erwartungswert, Varianz, Tschebbyscheff“. ” Zeige, dass für repräsentierten Zählerstand Cn gilt: ECn = n und V (Cn ) = (1/2)n(n − 1). Tschebbyscheff-Ungleichung allgemein für Zufallsvariable X , λ > 0. V (X ) Pr |X − EX | > λ ≤ . λ2 Anwendung hier: 1 1 (1/2)n(n − 1) 1 − = , Pr |Cn − n| > εn ≤ n ε 2 n2 2ε2 wie gewünscht. 303 Erwartungswert: Es ist C0 = 0. Für n > 0: E(Cn ) = n X r =0 E(Cn |Rn−1 = r ) · Pr{Rn−1 = r }, wobei Rn erwarteter Registerinhalt nach n-tem Schritt. Bereits vorab gezeigt: E(Cn |Rn−1 = r ) = c(r ) + 1. Damit folgt per Induktion: n X E(Cn ) = (c(r )+1)·Pr{Rn−1 = r } = E(Cn−1 )+1 = n. r =0 304 Varianz: Es gilt V (Cn ) = E(Cn2 ) − (ECn )2 . Mit derselben Idee wie beim Erwartungswert erhalten wir: n X E Cn2 |Rn−1 = r · Pr{Rn−1 = r } E Cn2 = = n X r =0 p(r )c(r + 1)2 + (1 − p(r ))c(r )2 · Pr{Rn−1 = r } r =0 n X = p(r ) c(r + 1)2 − c(r )2 + c(r )2 · Pr{Rn−1 = r } r =0 und außerdem gilt E 2 Cn−1 = n X r =0 c(r )2 · Pr{Rn−1 = r }. 305 Also folgt E Cn2 −E 2 Cn−1 = n X r =0 p(r ) c(r +1)2 −c(r )2 ·Pr{Rn−1 = r }. Es gilt (benutze die Definition p(r ) = 1/(c(r + 1) − c(r ))): p(r ) c(r + 1)2 − c(r )2 = c(r + 1) + c(r ) Außerdem ist c(r + 1) = 2r +1 − 1 = 2c(r ) + 1, damit p(r ) c(r + 1)2 − c(r )2 = 3c(r ) + 1. Einsetzen in obige Gleichung: E Cn2 −E 2 Cn−1 = n X r =0 (3c(r ) + 1) · Pr{Rn−1 = r } = 3E(Cn−1 ) + 1 = 3(n − 1) + 1 = 3n − 2. 306 Es folgt damit: E Cn2 = E = Cn2 n X i=1 −E C02 (3i − 2) = n X 2 2 = E Ci − E Ci−1 i=1 3 3 1 n(n + 1) − 2n = n2 − n. 2 2 2 Varianz insgesamt: 1 1 3 V (Cn ) = E Cn2 − (ECn )2 = n2 − n − n2 = n(n − 1). 2 2 2 Also auch Varianz wie behauptet. 307 Ressourcen: Erinnerung: ECn = n und Cn = c(Rn ) = 2Rn − 1. Benötigter Speicherplatz: Anzahl Bits für Registerwert, also ⌈log(Rn + 1)⌉ = log(log Cn + 1) + 1 . Erwartungswert dafür? Jensensche Ungleichung und Konvexität von − loglog. (Erinnerung: f (EX ) ≤ E(f (X )) für f konvex) E(⌈log(Rn + 1)⌉) = E log(log(Cn + 1) + 1) ≤ E(loglog Cn ) + 2 ≤ loglog(E(Cn )) + 2 (Jensen) = O(loglog n). Zeit pro Element linear in Platz, außerdem (Vorüberlegung) Münzwürfe kein Problem. 308 Ergebnis noch nicht wirklich toll, nichttriviale √ Fehlerschranke nur für relativen Fehler ε > 1/ 2 ≈ 0, 71 Verbessertes Verfahren: Repräsentierter Zählerstand für Registerwert r : c ′ (r ) = (1/α) (1 + α)r − 1 , α > 0 zusätzlicher Parameter. Hier bisher Spezialfall α = 1. Es gilt mit Beweis analog zu Fall α = 1: 1 α 1 − , Pr |Cn − n| > εn ≤ n 2ε2 Speicherplatz O(log(1/α) + loglog n). Damit (ε, δ)-Approximation von A NZAHL E LEMENTE mit Platz / Zeit pro Element O log(1/ε) + log(1/δ) + loglog n . 309 Verbessertes Ergebnis asymptotisch optimal: Satz 4.5: Für beliebiges k ∈ N und beliebige Konstanten ε, δ ∈ [0, 1) benötigt jeder randomisierte k -Runden-Datenstromalgorithmus, der eine (ε, δ)-Approximation eines Datenstromproblems mit möglichen Ausgabewerten {1, 2, . . . , r (n)} bei Eingabeströmen der Länge höchstens n berechnet, mindestens erwarteten Speicherplatz (loglog r (n)). Für A NZAHL E LEMENTE damit Platz (loglog n). 310 Beweisskizze: Zunächst: r (n) → r . Erster Schritt: Zeige, dass (log r ) Eingaben existieren, für die Algo. verschiedene Ausgaben produziert. Algorithmus-Ausgabe a ∈ R zulässig als Approximation von gewünschter Ausgabe y ∈ {1, 2, . . . , r }, falls (1 − ε)y ln(1 − ε) | {z } ≈−ε ≤ ≤ a ln a − ln y ≤ ≤ (1 + ε)y ⇔ ln(1 + ε) . | {z } ≈ε Also (approximativ) Bedingung: −ε ≤ ln a − ln y = (ln 2)(log a − log y ) ≤ ε. (∗) 311 Hatten: Algorithmus-Ausgabe a für gewünschte Ausgabe y , dann −ε ≤ ln a − ln y = (ln 2)(log a − log y ) ≤ ε. (∗) Betrachte Zahlen yj = 2j , j = 1, . . . , ⌊log r ⌋: • Für diese alle Ausgabe gemäß Bedingung (∗). • Jede Ausgabe kann nur konstant viele yj abdecken. Kann damit k = (log r ) der yj auswählen, für die verschiedene Ausgabewerte notwendig. 312 Zweiter Schritt: Zeige, dass Algorithmus logarithmisch viel Speicher in Anzahl der zu unterscheidenden Ausgabewerte benötigt. Dies war einfach für deterministische Algorithmen, hier aber randomisierte. Situation: • Eingabe ist Zahl yj , j ∈ {1, . . . , k } mit k = (log r ), diese aus Ausgabe des Algorithmus eindeutig rekonstruierbar. O. B. d. A. Ausgabe identisch mit diesen Zahlen. • Algorithmus codiert Information in Speicherinhalt S(yj ). Zufallsvariable. • Am Ende muss für Ausgabe A(S(yj )) gelten: Pr{A(S(yj )) = yj } ≥ 1 − δ. 313 Hatten: Pr{A(S(yj )) = yj } ≥ 1 − δ. Behauptung: Aus A lässt sich deterministischer Algorithmus konstruieren, der auf (1 − δ)-Anteil aller y1 , . . . , yk korrekt rechnet. Yaos Minimax-Prinzip, aka Durchschnittsargument“ ” (→ Komplexitätstheorie). Damit dann mindestens (1 − δ)k = (log r ) Zahlen, die anhand Speicherinhalt unterschieden werden, also (loglog r ) Bits Speicher und fertig. 314 Yaos Minimax-Prinzip: Betrachte Fehlermatrix: Mögliche Eingaben: Mögliche Zufallsbitstrings: z x F (x, z) F (x, y ) = 1, falls falsche Ausgabe auf Eingabe x bei Zufallsbits z; F (x, y ) = 0, sonst. • Bei Fehlerschranke δ höchstens δ-Anteil Einsen pro Zeile. • Insgesamt höchstens δ-Anteil Einsen in Matrix. • Es gibt eine Spalte mit höchstens δ-Anteil Einsen. 315 4.2 Algorithmische Techniken 4.2.1 Fakten zu endlichen Körpern Körper Fpr , p Primzahl – zwei Darstellungen der Elemente: • Vektoren in Fpr (gut für Addition). • Polynome mit Koeffizienten aus Fp , rechnen modulo irreduziblem Polynom vom Grad r (gut für Multiplikation). Proposition 4.6: Sei n = pr , p Primzahl. Körperoperationen in Fn mit Schulmethoden, falls irreduzibles Polynom gegeben: • Speicherplatz: O(r log p) = O(log n); • Zeit für Addition: O(r log p) = O(log n); • Zeit für Multiplikation: O r 2 log2 p = O log2 n . 316 Bemerkung: Mit schnellstem bekannten Multiplizierer für Fn Zeit O(n log n loglog n). Außerdem: Satz 4.7: Für r ∈ N und p Primzahl: Las-Vegas-Algorithmus, der in erwarteter Polynomialzeit in r und p irreduzibles Polynom vom Grad r über Fp berechnet. 317 4.2.2 Universelles Hashing Dictionaries mit Operationen I NSERT, D ELETE, S EARCH. Realisierung als Hashtabelle mit verketteten Listen ( offenes Hashing“): ” Hashfunktion h : U = {0, . . . , u−1} → M = {0, . . . , m−1}; bildet Schlüssel aus Universum U auf Tabellenindizes in M ab. Dabei |U| ≥ |M| (üblicherweise |U| ≫ |M|). Übliche Analyse (z. B. DAP2): • Schlüssel zufällig und werden von h gleichverteilt auf M abgebildet (ideales Hashing). • Erwartete Listenlänge O(1 + n/m) bei n Schlüsseln. Problematisch: Annahme über zufällige Schlüsselverteilung. 318 Idee (Carter, Wegman 1979): Zufällige Wahl der Hashfunktion bei Initialisierung der Tabelle (vgl. Min-Hashing). Zufällige Funktion aus Menge aller Funktionen U → M: Zu viele Bits für Beschreibung und Auswahl per Zufall. Abhilfe: Hashfunktion aus kleinerer Klasse von Funktionen, im Folgenden Hashklasse, die wichtigste Eigenschaften der Gleichverteilung über alle Funktionen rettet“. ” Hash-Analysen → Vermeidung von Kollisionen entscheidend, folgende Eigenschaft ausreichend. . . 319 Definition 4.8: Klasse H von Funktionen U → M, |M| = m, heißt universelle Hashklasse, falls für alle x, x ′ ∈ U mit x 6 = x ′ gilt: Prh∈H {h(x) = h(x ′ )} = |{ h | h(x) = h(x ′ )}| 1 ≤ . |H | m Also: Für verschiedene Schlüssel Wahrscheinlichkeit für Kollision der Hashwerte für zufälliges h ∈ H höchstens so groß wie bei zufälligem h aus allen Funktionen U → M. Kann zeigen: Erwartete Listenlänge wieder O(1 + n/m), aber jetzt Erwartungswert über Hashfunktionsauswahl. Keine Worstcase-Schlüsselmengen mehr! 320 Stärkere Variante der Universalität von Hashklassen: Definition 4.9: Klasse H von Funktionen U → M, |M| = m, heißt k -fach unabhängige Hashklasse, k ≥ 2, falls für alle paarweise verschiedenen x1 , . . . , xk ∈ U und beliebige y1 , . . . , yk ∈ M gilt: Prh∈H {h(x1 ) = y1 , . . . , h(xk ) = yk } = 1 . mk Für feste Wahl verschiedener Schlüssel x1 , . . . , xk und zufälliges h ∈ H sind damit Z1 = h(x1 ), . . . , Zk = h(xk ) unabhängige, über den m möglichen Werten gleichverteilte Zufallsvariablen. Beobachtung: H k -fach unabhängig, k ≥ 2 ⇒ H universell. 321