# Elias-Fano-Kodierung

Die Elias-Fano-Kodierung (nicht zu verwechseln mit der Shannon-Fano-Elias-Kodierung) ist eine Kodierung, die eine sortierte Zahlenfolge so komprimiert, dass möglichst viele Operationen, die von sortierten Listen unterstützt werden, ähnlich effizient unterstützt werden.
Diese wurden vor kurzem wiederentdeckt und dienen meistens als eine Indexstruktur von beispielsweise invertierten Dateien.
Im Allgemeinen ist es immer eine Überlegung wert, falls der Platzbedarf wichtig ist und ein Problem eine große Menge an sortierten Daten besitzt, eine Elias-Fano Kodierung zu testen.

## Grundlagen

Die Elias-Fano Kodierung unterstützt auf der Kodierung einer $n$-elementigen sortierten Liste $[x_{1},x_{2},x_{3},...,x_{n}]$ aus dem Universum $U:=[0,u)$ mit $x_{n}<u=2^{w}$ im Wesentlichen vier verschiedene Operationen.
* Eine Dekomprimierung, die die ursprüngliche sortierte Liste erzeugt.
* Zugriff auf das $i$-te Element ${\textsf {access}}(i):=x_{i}$.
* Die Anzahl an Elementen, die kleiner als $k$ sind. Dies ist analog zu der Binären Suche auf einer sortierten Liste ${\textsf {lowerbound}}(k):=|\{i\in [1,n]\,|\,x_{i}<k\}|$.
** Analog hierzu ist es üblich, eine predecessor und successor Anfrage bereitzustellen, die für ein $k$ das größte $x_{i}\leq k$ bzw. das kleinste $x_{i}\geq k$ ausgibt, ${\textsf {pred}}(k):=\max _{i\leq n}\{x_{i}\leq k\}$ und ${\textsf {succ}}(k):=\min _{i\leq n}\{x_{i}\geq k\}$.
* Die Transformation in das Komplement der sortierten Liste (d. h. für jedes mögliche $k$ die Anzahl an Elementen, die kleiner als $k$ sind) ${\textsf {comp}}:=[{\textsf {lowerbound}}(0),{\textsf {lowerbound}}(1),...,{\textsf {lowerbound}}(u)]$.
Die Elias-Fano Kodierung benötigt $n*\left\lceil {\frac {u}{n}}\right\rceil +\Theta (n)$ bits Speicherplatz . Falls man dies mit der Delta-Kodierung vergleicht, benötigt diese erwartet $n*\left\lceil {\frac {u}{n}}\right\rceil$bits, ohne dass diese fortgeschrittenen Operationen unterstützt. D. h. man kann in nur $\Theta (n)$ Speichermehrbedarf sinnvolle zusätzliche Operationen hinzufügen.
Um eine Elias-Fano Kodierung zu implementieren, benötigt man ein Bitvektor welcher ${\textsf {rank}}_{i}(x)$ und ${\textsf {select}}_{i}(x)$ Anfragen in konstanter Laufzeit unterstützt und einen höchstens konstanten Platzmehrbedarf pro Bit aufweist. Die ${\textsf {rank}}_{1}(x)$ Anfrage gibt die Anzahl an gesetzten Bits vor dem Index $x$ zurück und ${\textsf {rank}}_{0}(x):=x-{\textsf {rank}}_{1}(x)$ gibt die Anzahl an nicht gesetzten Bits zurück. Die ${\textsf {select}}_{1}(x)$ Anfrage gibt den Index des $x$-ten gesetzten Bits zurück, wobei ${\textsf {select}}_{1}(0)=0$ ist.
Außerdem benötigt man noch einen Vektor, indem jede Zelle exakt $w$ bits breit ist, wobei $w$ zur Laufzeit bestimmt werden kann.

## Algorithmus

Zunächst ist eine $n$-elementige sortierte Liste $[x_{1},x_{2},x_{3},...,x_{n}]$ an Zahlen aus dem Universum $U:=[0,u)$ mit $x_{n}<u=2^{w}$gegeben.
Hierdurch kann ein Bitvektor der Länge $n+2^{\lceil \log _{2}(n)\rceil }\in \Theta (n)$ und ein Vektor der Länge $n$, dessen Zellen $\left\lceil \log _{2}\left({\frac {u}{n}}\right)\right\rceil =\lceil \log _{2}(u)-\log _{2}(n)\rceil$ bits breit sind, erzeugt werden.
Jedes $x_{i}$ wird in die vorderen $\lceil \log _{2}(n)\rceil$ und in die hinteren $\lceil \log _{2}(u)-\log _{2}(n)\rceil$ Bits aufgeteilt. Hierbei entsprechen die vorderen Bits der Zahl $u_{i}$und die hinteren Bits der Zahl $l_{i}$.
Nun wird die $u_{i}$-te Null des Bitvektors auf Eins gesetzt, bzw. der $(u_{i}+i)$-te Index auf Eins gesetzt und $l_{i}$in dem Vektor an Index $i$ gespeichert.
Der Bitvektor wird nicht überlaufen, da $u_{n}+n\leq 2^{\lceil \log _{2}(n)\rceil }+n$.

## Implementation
### Generierung eines Elias-Fano Kodierung

Diese Elias-Fano Kodierung generiert eine Bitmaske, um die unteren Bits zu extrahieren, die oberen Bits werden extrahiert, indem die unteren Bits „rausgeschoben“ werden.

### Anfragen

Hier ist eine access und eine predecessor Anfrage beschrieben. Die predecessor Anfrage sucht sich zunächst mithilfe des Bitvektors den Index ${\hat {i}}$, der höchstens $\left\lceil \log _{2}\left({\frac {u}{n}}\right)\right\rceil$ größer als der Zielindex $i$ ist. Deshalb ist es hinreichend, auf die Indizes im Intervall $[{\hat {i}}-\left\lceil \log _{2}\left({\frac {u}{n}}\right)\right\rceil ,{\hat {i}}]$ in der Kodierung zuzugreifen und davon den größtmöglichen (der kleiner als der gesuchte Wert ist) auszugeben. Die successor, predecessor und lowerbound Anfragen werden sehr ähnlich implementiert.
Man sieht, dass die access Anfrage eine Laufzeit von $O(1)$ und die predecessor eine Laufzeit von $O\left(\left\lceil \log _{2}\left({\frac {u}{n}}\right)\right\rceil \right)$ aufweist.

## Varianten
### Partitoned Elias-Fano Kodierung

Häufig tritt der Fall ein, dass in der sortierten Liste Intervalle mit einer hohen oder niedrigen Elementdichte existieren. Deshalb ist es sinnvoll, diese Liste in mehrere Teillisten zu partitionieren, die unabhängig voneinander Elias-Fano kodiert werden.