• Keine Ergebnisse gefunden

Anwendung: Kompression mit bzip2

Im Dokument Algorithmen auf Sequenzen (Seite 78-82)

4.7 Die Burrows-Wheeler-Transformation (BWT)

4.7.3 Anwendung: Kompression mit bzip2

Idee. Einer der weiteren Vorteile der BWT von strukturierten Texten ist, dass sie sich gut als Vorverarbeitungsschritt zur verlustfreien Kompression eignet.

Die Idee dabei ist, dass Teilstrings, die im Text oft wiederholt werden, in der BWT lange Runs desselben Buchstaben ergeben.

Beispiel: In einem Roman wird man h¨aufig das Wort

”sagte“ finden. Es gibt also (unter anderem) ein Intervall im Suffixarray, in dem die Startpositionen der Suffixe stehen, die mit

”agte“ beginnen. An den entsprechenden Stellen der BWT steht ein

”s“. Nun kann nat¨urlich auch”fragte“ h¨aufiger vorkommen, was auch zu mehreren

”agte. . .“-Suffixen f¨uhrt, die sich mit den anderen durchmischen, ebenso andere W¨orter wie

”betagte“, etc.

Insgesamt wird in diesem Bereich der BWT vielleicht h¨aufig ein

”s“, seltener ein

”r“, ganz selten ein

”t“ zu sehen sein, so dass der entsprechende Ausschnitt so aussehen k¨onnte:

. . .sssssrsrrsssssrrsstsssssssssrsssssrrrss. . .. Es liegt auf der Hand, dass sich solche Abschnitte relativ gut komprimieren lassen.

Nat¨urlich hat nicht jeder Text diese Eigenschaft. Zuf¨allige Strings sehen nach Anwendung der BWT immer noch zuf¨allig aus. Die Intuition ist, dass sich Wiederholungen, die man in strukturierten Texten immer findet, in der BWT in lange Runs eines oder zumindest weniger verschiedener Buchstaben

”ubersetzen“.¨

Das bekannte Kompressionsprogramm bzip2 basiert auf der BWT; wir schauen uns die einzelnen Schritte genauer an.

Blockweise Bearbeitung. Der Text ist immer eine Datei, die als eine Folge von Bytes (0..255) angesehen wird. Das Programmbzip2arbeitet blockweise, also nicht auf dem ganzen Text, sondern immer auf einem Block der Datei separat. Die einzeln komprimierten Bl¨ocke werden hintereinandergeh¨angt. Eine typische Blockgr¨oße ist 500 KB, was aus Zeiten stammt, als PCs noch (sehr) kleine Hauptspeicher von wenigen MB hatten. Nat¨urlich w¨are eine bessre Kompression m¨oglich, wenn man den gesamten Text auf einmal betrachten w¨urde. Da man allerdings das Suffixarray berechnen muss (und in bzip2 daf¨ur kein Linearzeitalgorithmus verwendet wird), hat man sich aus Platz- und Zeitgr¨unden entschieden, jeweils nur einen Block zu betrachten. Ein weiterer Vorteil der blockweisen Bearbeitung ist folgender: Sind (durch Materialfehler auf der Festplatte) irgendwann einige Bits in der komprimierten Datei falsch, k¨onnen die nicht betroffenen Bl¨ocke immer noch rekonstruiert werden.

Die Blockgr¨oße kann in Grenzen eingestellt werden (Optionen-1f¨ur 100k bis-9 f¨ur 900k).

Gr¨oßere Bl¨ocke ben¨otigen bei der Kompression und Dekompression mehr Hauptspeicher und

f¨uhren zu l¨angeren Laufzeiten (da ein nichtlinearer Suffixarray-Algorithmus verwendet wird), erreichen aber unter Umst¨anden eine wesentlich bessere Kompression bei großen Dateien.

Kompressionsschritte. Es werden f¨ur jeden Block folgende drei Schritte ausgef¨uhrt:

1. Berechne die BWT des Blocks. Es entsteht eine Folge von Bytes, die eine Permutation der urspr¨unglichen Folge ist.

2. Wende auf die BWT die Move-to-front-Transformation an.

Hierbei entsteht eine neue Bytefolge, tendenziell aus vielen kleinen Zahlen, insbeson-dere Nullen bei vielen wiederholten Zeichen (runs).

3. Wende auf das Resultat die Huffman-Codierung an. Normalerweise ben¨otigt jedes Byte 8 bits. Die Huffman-Codierung ersetzt in optimaler Weise h¨aufige Bytes durch k¨urzere Bitfolgen und seltene Bytes durch l¨angere Bitfolgen. Da nach der Move-to-front-Transformation viele Nullen (und andere kleine Bytes) vorkommen, ergibt sich hierdurch eine erhebliche Einsparung.

Alle diese Transformationen sind invertierbar. Beim Dekodieren werden die Transformatio-nen in umgekehrter Reihenfolge ausgef¨uhrt.

Bemerkungen. Man sollte einmal die manual pages zu bzip2lesen.

Da jede Datei komprimierbar sein soll und eine Datei alle Byte-Werte enthalten kann, kann man kein besonderes Zeichen f¨ur das Stringende reservieren. Man muss also in der Imple-mentierung bei der Berechnung des Suffixarrays das Stringende besonders behandeln.

Es kann sich bei nat¨urlichsprachlichen Texten lohnen, nicht den Text selbst, sondern ihn r¨uckw¨arts gelesen zu komprimieren. Der Grund ist, dass man in der BWT die Zeichenvor den Suffixen betrachtet, und zwar ein paar Buchstaben es relativ gut erlauben vorherzusagen, was davor steht (zum Beispiel h¨aufig

”s“ bei

”agte“, aber noch besser erlauben vorherzusagen, was dahinter steht (zum Beispiel

”e“ bei

”sagt“), so dass die BWT des reversen Textes noch besser komprimierbar ist. Hierzu kann man selbst gut Experimente machen.

KAPITEL 5

Approximatives Pattern-Matching

Bisher haben wir stets nach exakten ¨Ubereinstimmungen zwischen Pattern und Text gesucht.

In vielen Anwendungen ist es jedoch sinnvoll, auch auf approximative ¨Ubereinstimmungen von Textteilen mit dem gegebenen Muster hinzuweisen, etwa bei der Suche nach

” Ressourcen-beschr¨ankung“ auch die (teilweise falsch geschriebenen) Varianten

”Resourcen-Beschr¨ankung“

oder”Ressourcenbeschraenkung“ zu finden. Bisher k¨onnen wir dieses Problem nur l¨osen, in-dem wir alle Alternativen aufz¨ahlen und diese sequenziell abarbeiten. Alternativ k¨onnten wir Algorithmen f¨ur Patternmengen anwenden (siehe Kapitel 7).

In diesem Kapitel

• definieren wir Abstands- und ¨Ahnlichkeitsmaße zwischen Strings,

• betrachten wir Algorithmen, die diese Maße zwischen zwei Strings berechnen,

• geben wir Algorithmen an, die alle Teilstrings in einem Text finden, die zu einem gegebenen Pattern h¨ochstens einen vorgegebenen Abstand aufweisen.

5.1 Abstands- und ¨ Ahnlichkeitsmaße

Wir definieren zun¨achst einige Distanzmaße. Nicht alle davon sind Metriken. Wir erinnern zun¨achst an die Definition einer Metrik.

5.1 Definition (Metrik). Sei X eine Menge. Eine Funktiond:X×X→R≥0 heißt Metrik genau dann, wenn

1. d(x, y) = 0 genau dann, wenn x=y (Definitheit), 2. d(x, y) =d(y, x) f¨ur alle x, y (Symmetrie),

3. d(x, y)≤d(x, z) +d(z, y) f¨ur alle x, y, z (Dreiecksungleichung).

Vergleicht man nur Strings gleicher L¨ange, bietet sich die Hamming-DistanzdHals Abstands-maß an. Formal muss man f¨ur jedes Alphabet Σ und jede Stringl¨angeneine eigene Funktion dΣHn definieren; der Zusatz Σn wird jedoch in der Notation weggelassen.

5.2 Definition(Hamming-Distanz). F¨ur jedes Alphabet Σ und jedesn≥0 ist aufX:= Σn die Hamming-Distanz dH(s, t) zwischen Strings s, t definiert als die Anzahl der Positionen, in denen sich sundt unterscheiden.

Man beachte, dass die Hamming-Distanz f¨ur |s| 6=|t| zun¨achst nicht definiert ist. Aus Be-quemlichkeitsgr¨unden kann man sie als +∞ definieren. Man sieht durch Nachweisen der Eigenschaften, dassdH eine Metrik auf Σn ist.

Die q-gram-Distanz dq(s, t) zwischen zwei beliegen Strings s, t ∈ Σ definiert sich ¨uber die insundt enthaltenenq-grams. Es ist durch Beispiele leicht zu sehen, dass es sich nicht um eine Metrik handelt, insbesondere kann man zwei verschiedene Strings mitq-gram-Distanz 0 finden.

5.3 Definition (q-gram-Distanz). F¨ur einen Strings∈Σ und einq-gramx∈Σqsei Nx(s) die Anzahl der Vorkommen vonxins. Dann ist dieq-gram-Distanz zwischensundtdefiniert als

dq(s, t) := X

x∈Σq

|Nx(s)−Nx(t)|.

Die Edit-Distanz (auch: Levenshtein-Distanz) ist das am h¨aufigsten verwendete Abstands-maß zwischen Strings.

5.4 Definition(Edit-Distanz, Levenshtein-Distanz). DieEdit-Distanzzwischen zwei Strings sundt ist definiert als die Anzahl der Edit-Operationen, die manmindestens ben¨otigt, um einen String in einen anderen zu ¨uberf¨uhren.Edit-Operationensind jeweils L¨oschen, Einf¨ugen und Ver¨andern eines Zeichens.

In einem gewissen Sinn sind Distanz- und ¨Ahnlichkeitsmaße symmetrisch und lassen sich (bei manchen Anwendungen) ¨aquivalent durch einander ersetzen. Manche Eigenschaften lassen sich jedoch nat¨urlicher durch Distanzen ausdr¨ucken (so wie oben), andere durch Ahnlichkeiten (so wie die folgenden).¨

5.5 Definition (L¨angster gemeinsamer Teilstring). Die L¨ange des l¨angsten gemeinsamen Teilstrings lcf(s, t) (

”f“ f¨ur factor) von s, t ∈ Σ ist die L¨ange eines l¨angsten Strings, der sowohl Teilstring vonsals auch vontist. EinTeilstringder L¨ange`vons= (s0, . . . , s|s|−1)∈ Σ ist ein String der Form (si, si+1, . . . , si+`−1) f¨ur 0≤i≤ |s| −`.

5.6 Definition (L¨angste gemeinsame Teilsequenz). Die L¨ange der l¨angsten gemeinsamen Teilsequenz lcs(s, t) vons, t∈Σ ist die L¨ange eines l¨angsten Strings, der sowohl Teilsequenz von s als auch von t ist. Eine Teilsequenz der L¨ange` von s= (s0, . . . , s|s|−1) ∈ Σ ist ein String der Form (si0, . . . , si`−1) mit 0≤i0< i1 <· · ·< i`−1<|s|.

Abstandsmaße kann man beispielsweise alsdlcs(s, t) := max{ |s|,|t| }−lcs(s, t) unddlcf(s, t) :=

max{ |s|,|t| } −lcf(s, t) erhalten. Sind diese Metriken?

Die obige Liste ist keinesfalls vollst¨andig; es lassen sich weitaus mehr sinnvolle und unsinnige Abstands- und ¨Ahnlichkeitsmaße auf Strings definieren.

Im Dokument Algorithmen auf Sequenzen (Seite 78-82)