Syntax highlighting of Archiv/TIN066 Univerzální a perfektní hashování

{{TIN066 Skripta}}
{{TODO|Univerzální hashování. Důkazy a tak}}

= Univerzální hashování =

Naše hashovací funkce se pro některé vstupní množiny bude chovat dobře a pro jiné hůře. Abychom si vylepšili naše šance, zaveďme si místo toho obecnější třídu (rozumně různorodých) funkcí H; než začneme hashovat, vybereme z nich náhodnou funkci <math>h \in H</math> (ta se stane atributem konkrétní instance hashovací tabulky). Můžeme analyzovat chování přes celý prostor hashovacích funkcí H a nepotřebuji předpoklad rovnoměrně rozložených dat.

* Abychom měli snadnější práci, funkce si očíslujeme: <math>H = \{h_i|i \in I\}\colon U \to \{0,\ldots,m-1\}</math>
* Systém funkcí H je '''c-univerzální''' pro U, pokud <math>\forall x,y \in U, x \ne y: |\{h \in H|h(x) = h(y)\}| \le {c |H| \over m}</math>
** ekvivalentně pomocí pravděpodobnosti pro náhodně zvolené h,x,y: <math>P(h(x)=h(y)) \leq \frac{c}{m}</math>

Pro univerzální systém (= 1-univerzální) je pravděpodobnost kolize (= 1/m) stejná, jako kdybychom rozhodili x,y do přihrádek zcela náhodně.

Existuje takový systém? Pro <math>a,b \in U</math> mějme hašovací funkce dané předpisem:
* <math>h_{a,b}(x) = ((ax + b) \mod N) \mod m</math>
Těchto funkcí je <math>N^2</math>. Pro pevně daná různá <math>x, y \in U</math>, kolik funkci zobrazí x, y na stejný prvek? Když se zobrazí na stejný prvek, znamená to, že existuje <math>i \in \{0..m-1\}</math> (hodnota ''h'') a <math>r, s \in \{0.. \lceil \frac{N}{m}\rceil-1 \}</math> (násobky ''m'') takové, že:
* <math>(a x + b) \mod N = r \cdot m + i</math>
* <math>(a y + b) \mod N = s \cdot m + i</math>
To představuje dvě lineární rovnice v tělese <math>\mathbb{Z}_N</math> s neznámými a, b. Matice je regulární a soustava má právě jedno řešení. Rovnice se mohu lišit pravou stranou, každá pravá strana určuje jedno řešení (a, b). Počet pravých stran (= počet různých hodnot ''i, r, s'' = počet funkcí, zobrazujících x,y na stejný prvek) je <math>m \lceil \frac{N}{m}\rceil ^2</math>. Tento systém je c-univerzální, pokud:

* <math> m \lceil \frac{N}{m}\rceil ^2  \leq  {c |H| \over m} = c \cdot {N^2 \over m}</math>
Což platí pro hodnotu ''c'' :
* <math> c =  \frac{    m \lceil \frac{N}{m}\rceil ^2   }  {  \frac{N^2}{m}  } =  \frac{ \lceil \frac{N}{m}\rceil ^2   }  {  \frac{N^2}{m^2}  } </math>


{{TODO|Důkazy. Různé další vlastnosti.}}

Očekávaný čas operací MEMBER, INSERT, DELETE je <math>O(1+c\alpha)</math>.


Vybrat z H nějakou funkci nemusí být jednoduché, velikost <math>|H|</math> totiž dost rychle roste a tak to může začít být obtížné. Podívejme se, jaké nejmenší c-univerzální systémy dokážeme najít!

Můžeme snadno dokázat, že <math>|I|\ge {m \over c}(\lceil\log_m N\rceil - 1)</math>, takže velikost systému roste alespoň s logaritmem velikosti univerza.

Dá se také dokázat existence 5-univerzálního systému, funkce vypadnouz takové zvláštní prvočíselné konstrukce.

Nakonec c se dá zdola odhadnout: <math>c > 1 - m/N</math>

= Perfektní hashování =

Máme předem danou množinu S a chceme vyrobit perfektní hashovací funkci h takovou, aby nikdy negenerovala pro prvky množiny kolize. Typicky potřebujeme hodně rychlý MEMBER a vůbec nepotřebujeme INSERT/DELETE. Samozřejmě chceme, aby h byla rychlá a malá (ne třeba další tabulka ;-). Při generování h si můžeme klidně dát trochu na čas.

Mějme univerzum <math>U = \{ 0,\ldots,N-1 \}</math> a soubor funkcí <math>H\colon U \to \{0,\ldots,m-1\}</math>. H bude <math>(N,m,n)</math>-perfektní, když <math>\forall S \subseteq U: |S| = n</math> existuje perfektní <math>h \in H</math>.

Lze odhadnout, že:
<math>|H| \ge {{N \choose n} \over {m \choose n}(N/m)^n}</math>
<math>|H| \ge {\log N \over \log m}</math>

Důkaz existence se provádí maticemi, logaritmy, páčidly a integrály.

Důkaz, že <math>|H| \ge {\log N \over \log m}</math> je poměrně jednoduchý (analýza ve skriptech je náročnější). Nechť pro spor platí, že <math>|H| \le {\log N \over \log m}</math>, potom <math>|H| \log m \le \log N</math> a když se zbavíme logaritmů, dostanem <math>m^{|H|} \le N</math>. Z přihrádkového principu plyne, že musí existovat alespoň dva prvky z <math>S</math>, které všechny funkce z <math>H</math> nahašují do jednoho políčka a to je spor s tím, že <math>H</math> je perfektní systém.

== Konstrukce ==

{{TODO|Důkazy; neměly by ale zamlžit princip, možná by bylo lepší mít podrobnou konstrukci se všemi odvozeními na zvláštní stránce}}

Kterak sobě perfektní funkci poříditi? Existuje mnoho různých způsobů, ukazují se tři:

=== Velikánská tabulka, malá funkce, rychle nalezená ===

Nechť N je prvočíslo, zavedeme si
* sadu funkcí <math>h_k(x) = (kx \mod N) \mod m\quad k=1,\ldots,N-1</math>
* počet kolizí <math>b_i^k = |\{ x | h_k(x)=i\}|</math> (trochu hloupá symbolika)
* "míru" kolizí <math>B_m^k = \sum_{i=0}^{m-1} (b_i^k)^2</math>
Takže pokud funkce <math>h_k</math> není perfektní, nějaké <math>b_i^k \ge 2</math> a tedy <math>B_m^k \ge n + 2</math>.

Co potřebuji? Najít (m,k) takové, aby <math>h_k</math> vedoucí do tabulky velikosti m byla perfektní.
Potřebujeme odhadnout m, o kterém toto umíme dokázat, to se dělá přes nějaké omezení shora míry kolizí.
Dojdeme k tomu, že platí:
* Pro <math>m=n(n-1)+1</math> existuje deterministický algoritmus, který v <math>O(nN)</math> nalezne perfektní k. (Prostě zkouší všech N možností, ověřit jednu trvá O(n).)
* Pro <math>m=2n(n-1)</math> existuje pravděpodobnostní algoritmus, který v <math>O(n)</math> nalezne perfektní k s pravděpodobností alespoň 1/4. (Prostě střelíme náhodné <math>k</math> a v průměru po čtyřech pokusech se trefíme.)

=== Malá tabulka, velká funkce, celkem rychle nalezená ===

Výše popsaný postup je fajn, ale potřebuje ''fakt velkou'' (kvadraticky velkou) tabulku. Půjdeme na to tedy trochu jinak; před chvílí jsme ve skutečnosti dostali ještě dva výsledky:
* Pro <math>m=n</math> existuje deterministický algoritmus, který v <math>O(nN)</math> nalezne k takové, že <math>B_m^k < 3n</math>
* Pro <math>m=n</math> existuje pravděpodobnostní algoritmus, který v očekávaném čase <math>O(n)</math> nalezne k takové, že <math>B_m^k < 4n</math>
BÚNO konstruujme deterministický algoritmus. Najdeme k, aby <math>B_m^k < 3n</math>. Mějme:
* Množinu kolidujících prvků <math>S_i = \{s \in S|h_k(s) = i\}</math>
* Velikost segmentu tabulky <math>c_i = |S_i|(|S_i|-1)+1</math>
Teď stačí pro každou neprázdnou <math>S_i</math> najít perfektní funkci <math>h_{k_i}</math> a naskládat segmenty pro všechny i za sebe a vyrobíme odpovídající perfektní funkci.

Ok, cílová tabulka je <math>m<3n</math>, časová složitost <math>O(nN)</math>. Teď ale zase máme problém, že si musíme pamatovat hashovací funkce pro všechny segmenty, to je <math>O(n \log N)</math> (druhý člen je prostor potřebný pro samotné číslo jedné funkce).

=== Malá tabulka, malá funkce, za dlouho nalezená ===

Nechť <math>\phi_p(x) = x \mod p</math> pro prvočíslo p. Platí, že pro každou n-prvkovou S existuje prvočíslo p nejvýše <math>O(n^2\ln N)</math> takové, že funkce <math>\phi_p</math> je perfektní. (To je celkem těžké, ale dokazuje se.)

Deterministický algoritmus prostě zkusí všechna možná p. Ověřit, že nějaká <math>\phi_p</math> je perfektní, trvá <math>O(n\log n)</math> (duplicity odhalím setříděním všech nabytelných hodnot). Najít prvočíslo trvá málo (Rabin-Miller <math>O(\log^3 p)</math>). Takže celkem to bude trvat <math>O(n^3\log n\log N)</math>. Pravděpodobnostní algoritmus (střílí p náhodná) to zvládne v očekávaném čase <math>O(n\log n(\log n + \log\log N))</math>.

{{TODO|Chybí algoritmus}}

= Dynamické perfektní hashování =

Dynamizace pravděpodobnostních algoritmů.

Přístup přes hypergrafy.