Transformata Burrowsa-Wheelera
Algorytm kompresji z sortowaniem bloków używany w bzip2 i innych zaawansowanych kompresorach.
Zmiana Paradygmatu w Kompresji Bezstratnej
W naszej podróży przez algorytmy kompresji bezstratnej, napotkaliśmy dwie główne filozofie. Metody statystyczne, takie jak kodowanie Huffmana, doskonale radzą sobie, analizując częstotliwość występowania poszczególnych symboli. Metody słownikowe, takie jak rodzina Lempel-Ziv, osiągają kompresję poprzez znajdowanie i odwoływanie się do dokładnych powtórzeń całych ciągów. Oba podejścia są niezwykle potężne, ale działają na odrębnych rodzajach redundancji. Rodzi to frapujące pytanie: czy istnieje podejście, które mogłoby uchwycić bardziej subtelny, kontekstowy rodzaj nadmiarowości, który nie dotyczy tylko tego, jak często dany znak się pojawia, ale w jakich otoczeniach się pojawia?
Tutaj na scenę wkracza . Wynaleziona przez Michaela Burrowsa i Davida Wheelera w 1994 roku, BWT sama w sobie nie jest algorytmem kompresji. Jest to natomiast genialny i intensywny obliczeniowo krok wstępny, odwracalna transformacja, która przestawia dane w bloku. Magia BWT polega na tym, że nie miesza ona danych losowo; reorganizuje je w głęboki sposób, grupując znaki, które mają tendencję do pojawiania się w podobnych kontekstach obok siebie. Ten proces przekształca subtelne, długodystansowe wzorce kontekstowe w proste, wysoce zlokalizowane powtórzenia, które są trywialne do obsłużenia dla innych, prostszych algorytmów kompresji. BWT jest głównym silnikiem popularnego archiwizatora `bzip2`, znanego z tego, że często osiąga lepsze współczynniki kompresji niż tradycyjne metody oparte na DEFLATE, takie jak `gzip`, na dużych plikach.
Transformata Prosta BWT: Sortowanie i Ekstrakcja
Aby zrozumieć BWT, kluczowe jest prześledzenie transformacji prostej krok po kroku. Proces opiera się na sortowaniu blokowym, co oznacza, że operuje na całym fragmencie danych naraz, zamiast strumieniować go bajt po bajcie. Przekształćmy przykładowy ciąg ANANAS$. Znak '$' jest specjalnym markerem końca ciągu, który jest leksykograficznie mniejszy od wszystkich innych znaków, co gwarantuje unikalność rotacji.
Krok 1: Utwórz Wszystkie Rotacje Cykliczne
Najpierw musimy stworzyć listę wszystkich możliwych przesunięć cyklicznych, czyli rotacji, ciągu wejściowego. Przesunięcie cykliczne to to, co otrzymujemy, przenosząc pierwszy znak na koniec ciągu, wielokrotnie.
ANANAS$
NANAS$A
ANAS$AN
NAS$ANA
AS$ANAN
S$ANANA
$ANANAS
Krok 2: Posortuj Leksykograficznie Rotacje
Następny, najbardziej znaczący obliczeniowo krok, to posortowanie tej listy rotacji alfabetycznie. Nazywa się to , tak samo jak sortuje się słowa w słowniku.
| Indeks | Posortowana Rotacja |
|---|---|
| 0 | $ANANAS |
| 1 | ANANAS$ |
| 2 | ANAS$AN |
| 3 | AS$ANAN |
| 4 | NANAS$A |
| 5 | NAS$ANA |
| 6 | S$ANANA |
Krok 3: Wyodrębnij Wyjście - Ostatnią Kolumnę
Główne wyjście BWT jest zaskakująco proste: jest to sekwencja znaków z ostatniej kolumny tej posortowanej tabeli. Ta kolumna jest często określana jako .
L = S$NNAAA
Zwróć uwagę na to, co się stało. Oryginalny, wymieszany ciąg "ANANAS$" został przekształcony w "S$NNAAA". Transformata zgrupowała identyczne znaki razem. Wszystkie 'A' znajdują się teraz w ciągłej serii, która jest niezwykle łatwa do skompresowania przez prosty kompresor, taki jak Kodowanie Długości Serii. To grupowanie jest całym celem transformacji.
Krok 4: Zapisz Indeks Pierwotny
Potrzebujemy jeszcze jednej kluczowej informacji do zapisania. Aby transformata była odwracalna, musimy wiedzieć, który wiersz w posortowanej tabeli odpowiada naszemu oryginalnemu, nieposortowanemu ciągowi. W naszym przykładzie oryginalny ciąg "ANANAS$" znajduje się w wierszu 1 posortowanej tabeli. Dlatego nasz indeks pierwotny, często oznaczany jako , wynosi 1.
Kompletny wynik prostej transformaty Burrowsa-Wheelera dla "ANANAS$" to para: ("S$NNAAA", ).
Odwrotna Transformata BWT: Odtwarzanie Oryginału
Proces odwrotny na pierwszy rzut oka wydaje się przerażający. Jak możemy odtworzyć oryginalny ciąg, używając tylko ostatniej kolumny i numeru indeksu? Klucz leży w niezwykłej i nieoczywistej właściwości, która łączy pierwszą i ostatnią kolumnę posortowanej macierzy.
Właściwość Mapowania Ostatni-do-Pierwszego (LF-Mapping)
Spójrzmy ponownie na naszą posortowaną macierz. Nazwijmy pierwszą kolumnę , a ostatnią .
$ S
A $
A N
A N
N A
N A
S A
Zauważ, że to po prostu posortowana wersja znaków oryginalnego ciągu ($-A-A-A-N-N-S). To kluczowa obserwacja: możemy odtworzyć po prostu sortując znaki !
Kluczowa właściwość, która sprawia, że BWT jest odwracalna, to Mapowanie Ostatni-do-Pierwszego (LF-Mapping):
To mapowanie pozwala nam "przeskoczyć" od znaku w do jego odpowiadającej pozycji w , a ponieważ każdy znak w jest początkiem posortowanej rotacji, to w efekcie pozwala nam odtworzyć oryginalny ciąg wstecz.
Szczegółowy Proces Odwrotny
Odtwórzmy "ANANAS$" używając tylko otrzymanych informacji: "S$NNAAA" i .
- Krok 1: Odtwórz Pierwszą Kolumnę (F): Posortuj znaki alfabetycznie. Sortowanie "S$NNAAA" daje nam "$AAANNS".
- Krok 2: Zacznij od Indeksu Pierwotnego: Nasz indeks mówi nam, że oryginalny ciąg kończył się znakiem z . Patrząc na nasz ciąg , to '$'. Zatem ostatnim znakiem naszego oryginalnego ciągu jest '$'.
- Krok 3: Zastosuj Mapowanie LF: Znak, który właśnie znaleźliśmy ('$') jest pierwszym '$' w kolumnie L. Zgodnie z właściwością mapowania LF, odpowiada on pierwszemu '$' w kolumnie F. Pierwszy '$' w jest pod indeksem 0. To mówi nam, jaki jest następny krok. Następnym wierszem, na który musimy spojrzeć, jest wiersz 0.
- Krok 4: Wstecz - Iteracja 2: Przejdź do wiersza 0. Znak w to 'S'. To przedostatni znak naszego oryginalnego ciągu. Jak dotąd mamy: S$ (czytając od końca).
- Krok 5: Powtórz Mapowanie LF: Znak, który właśnie znaleźliśmy ('S'), jest pierwszym 'S' w kolumnie L. Odpowiada on pierwszemu 'S' w kolumnie F, które jest pod indeksem 6. Nasz następny wiersz to 6.
- Krok 6: Kontynuuj Iteracje (odtwarzając wstecz):
- . Weź = '$'. To ostatni znak. Pierwsze '$' w L mapuje się na pierwsze '$' w F (indeks 0). Nowe . Odtworzony ciąg: $.
- . Weź = 'S'. To przedostatni znak. Pierwsze 'S' w L mapuje się na pierwsze 'S' w F (indeks 6). Nowe . Odtworzony ciąg: S$.
- . Weź = 'A'. To trzeci znak od końca. Trzecie 'A' w L mapuje się na trzecie 'A' w F (indeks 3). Nowe . Odtworzony ciąg: AS$.
- . Weź = 'N'. To czwarty znak od końca. Pierwsze 'N' w L mapuje się na pierwsze 'N' w F (indeks 4). Nowe . Odtworzony ciąg: NAS$.
- . Weź = 'A'. To piąty znak od końca. Drugie 'A' w L mapuje się na drugie 'A' w F (indeks 2). Nowe . Odtworzony ciąg: ANAS$.
- . Weź = 'N'. To szósty znak od końca. Drugie 'N' w L mapuje się na drugie 'N' w F (indeks 5). Nowe . Odtworzony ciąg: NANAS$.
- . Weź = 'A'. To siódmy znak od końca. Pierwsze 'A' w L mapuje się na pierwsze 'A' w F (indeks 1). Nowe . Odtworzony ciąg: ANANAS$.
Kompletny Proces Kompresji (BWT to Dopiero Etap 1)
Jak wspomniano, BWT jest tylko pierwszym, kluczowym krokiem w wieloetapowym procesie używanym przez kompresory takie jak bzip2.
- Etap 1: Transformata Burrowsa-Wheelera (BWT): Dane wejściowe są przetwarzane w blokach, a każdy blok jest przekształcany, aby zgrupować znaki o podobnym kontekście, tworząc kolumnę L i indeks.
- Etap 2: Transformata Move-to-Front (MTF): Wynik BWT, który teraz ma długie serie identycznych znaków, jest przetwarzany przez transformatę MTF. MTF utrzymuje listę alfabetu. Dla każdego przetwarzanego znaku wypisuje jego obecną pozycję na liście, a następnie przesuwa ten znak na początek listy. Rezultatem jest strumień małych liczb (głównie zer, jedynek i dwójek), który jest jeszcze bardziej statystycznie redundantny.
- Etap 3: Kodowanie Długości Serii (RLE): Strumień małych liczb z MTF jest teraz przetwarzany przez RLE, aby zakodować liczne serie zer, które zostały utworzone.
- Etap 4: Kodowanie Entropijne: Ostateczny strumień symboli z etapu RLE jest kompresowany za pomocą kodowania Huffmana (lub czasami arytmetycznego), aby wyprodukować ostateczne skompresowane wyjście.
Wnioski: Elegancka Transformacja
Transformata Burrowsa-Wheelera to głęboki i elegancki algorytm, który stanowi kamień milowy w kompresji danych. Pokazuje on, że poprzez odwracalne przestawienie danych możemy odsłonić głębszą warstwę redundancji kontekstowej, niedostępną dla prostszych metod. Chociaż jej koszt obliczeniowy, zwłaszcza krok sortowania, czyni ją wolniejszą od algorytmów opartych na LZ, jej zdolność do osiągania lepszych współczynników kompresji dla wielu typów dużych plików zapewnia jej stałą aktualność. Proces BWT reprezentuje wieloetapowe, zaawansowane podejście do redukcji danych, gdzie sprytna transformacja przygotowuje dane dla kaskady prostszych, wysoce skutecznych etapów kompresji.