Transformarea Burrows-Wheeler

De la Wikipedia, enciclopedia liberă.
Salt la navigare Salt la căutare

Transformarea Burrows-Wheeler (prescurtată BWT ) este un algoritm utilizat în programele de compresie a datelor precum bzip2 . A fost inventat de Michael Burrows și David Wheeler. [1]

Când un șir de caractere este trimis către BWT, niciunul dintre ele nu se schimbă în valoare, deoarece transformarea permite doar ordinea caracterelor. Dacă șirul original conține multe repetări ale anumitor șiruri de caractere, atunci în șirul transformat vom găsi mai multe puncte în care același caracter se repetă de multe ori. Acest lucru este util pentru compresie, deoarece devine ușor să comprimați un șir în care apar secvențe lungi de caractere care sunt la fel.

De exemplu, șirul:

 TRINZECI. TRENTINIANI.

s-ar transforma în următoarele:

 OIIEEAEO..LDTTNN.RRRRRRTNTTLEAAIOEEEENTRDRTTETTTTATNNTTNNAAO .... OU.T

Transformatul

Transformarea se face prin ordonarea tuturor rotațiilor textului și apoi luând doar ultima coloană. De exemplu, textul „^ BANANA @ ” este transformat în „BNN ^ AA @ A” prin acești pași (caracterele roșii ^ și @ indică începutul indicatorului șir și, respectiv, sfârșitul indicatorului șir sau „EOF”):

Transformat
Intrare Toate
rotații
Linii în ordine

lexicografic

Ia

ultimul

coloană

Ieșire
 ^ BANANA @
^ BANANA @
@ ^ BANANA
A @ ^ BANAN
NA @ ^ BANA
ANA @ ^ BAN
NANA @ ^ BA
ANANA @ ^ B
BANANA @ ^
A NANA @ ^ B
A NA @ ^ BAN
A @ ^ BANAN
B ANANA @ ^
N ANA @ ^ BA
N A @ ^ BANA
^ BANANA @
@ ^ BANANA
ANANA @ ^ B
ANA @ ^ BA N
A @ ^ BANA N
BANANA @ ^
NANA @ ^ B A
NA @ ^ BAN A
^ BANANA @
@ ^ BANAN A
BNN ^ AA @ A

Următorul pseudocod arată o metodă ineficientă pentru a calcula BWT și inversul acestuia. Se presupune că șirul de intrare s conține un caracter special „EOF” care este întotdeauna ultimul caracter și nu apare niciodată în text și, prin urmare, este ignorat la sortare.

 Funcția BWT ( șiruri )
   creează o listă cu toate rotațiile posibile ale lui s
   puneți fiecare rotație pe un rând de masă pătrată mare
   sortează rândurile tabelelor în ordine alfabetică, tratând fiecare rând ca un șir
   afișează coloana din dreapta a tabelului
 
 funcția BWTinversa ( șiruri )
   creează un tabel gol, fără rânduri sau coloane
   repetă lungimea_de (de) ori
       introduceți s ca o nouă coloană în partea stângă a tabelului
       sortează rândurile tabelului în ordine alfabetică
   returnează linia care se termină cu caracterul „EOF”


Transformarea inversă

Cel mai interesant lucru despre BWT nu este că generează o ieșire care este mai ușor de comprimat decât originalul, ci și pentru că acest lucru ar putea fi realizat prin simpla plasare a caracterelor în ordine alfabetică, ci este reversibilitatea sa: documentul original este reconstruit începând doar din caracterele ultimei coloane.

Inversul poate fi înțeles în acest fel. Luați tabelul final al algoritmului BWT și ștergeți totul, cu excepția ultimei coloane. Având în vedere doar aceste informații, puteți reconstrui cu ușurință prima coloană. Ultima coloană vă spune care sunt toate caracterele textului, trebuie doar să le sortați pentru a obține prima coloană. Acum sunt cunoscute prima și ultima coloană și împreună vă oferă toate perechile succesive de caractere din document, unde perechile dau, ciclic, întotdeauna mai întâi ultimul și apoi primul caracter al perechii din documentul original. Sortând lista de perechi veți obține prima și a doua coloană. Continuând în acest fel, puteți reconstitui întreaga listă, prin urmare, linia cu caracterul „EOF” la sfârșit este textul original. Transformarea inversă a exemplului de mai sus arată astfel:

Transformarea inversă
Intrare
 BNN ^ AA @ A
adăuga Fel adăuga Fel
 B.
Nu.
Nu.
^
LA
LA
@
LA
LA
LA
LA
B.
Nu.
Nu.
^
@
BA
N / A
N / A
^ B
UN
UN
@ ^
A @
UN
UN
A @
BA
N / A
N / A
^ B
@ ^
adăuga Fel adăuga Fel
 INTERZICE
NAN
NA @
^ BA
ANA
ANA
@ ^ B
A @ ^
ANA
ANA
A @ ^
INTERZICE
NAN
NA @
^ BA
@ ^ B
BANA
NANA
NA @ ^
^ BAN
ANAN
ANA @
@ ^ BA
A @ ^ B
ANAN
ANA @
A @ ^ B
BANA
NANA
NA @ ^
^ BAN
@ ^ BA
adăuga Fel adăuga Fel
 BANAN
NANA @
NA @ ^ B
^ BANA
ANANA
ANA @ ^
@ ^ BAN
A @ ^ BA
ANANA
ANA @ ^
A @ ^ BA
BANAN
NANA @
NA @ ^ B
^ BANA
@ ^ BAN
BANANĂ
NANA @ ^
NA @ ^ BA
^ BANAN
ANANA @
ANA @ ^ B
@ ^ BANA
A @ ^ BAN
ANANA @
ANA @ ^ B
A @ ^ BAN
BANANĂ
NANA @ ^
NA @ ^ BA
^ BANAN
@ ^ BANA
adăuga Fel adăuga Fel
 BANANA @
NANA @ ^ B
NA @ ^ BAN
^ BANANĂ
ANANA @ ^
ANA @ ^ BA
@ ^ BANAN
A @ ^ BANA
ANANA @ ^
ANA @ ^ BA
A @ ^ BANA
BANANA @
NANA @ ^ B
NA @ ^ BAN
^ BANANĂ
@ ^ BANAN
BANANA @ ^
NANA @ ^ BA
NA @ ^ BANA
^ BANANA @
ANANA @ ^ B
ANA @ ^ BAN
@ ^ BANANA
A @ ^ BANAN
ANANA @ ^ B
ANA @ ^ BAN
A @ ^ BANAN
BANANA @ ^
NANA @ ^ BA
NA @ ^ BANA
^ BANANA @
@ ^ BANANA
Ieșire
 ^ BANANA @

Anumite optimizări pot face ca acești algoritmi să ruleze mai eficient fără a modifica rezultatul; nu este nevoie să păstrați întregul tabel în memorie, cu atât mai puțin pe disc și nu este necesar să repetați ordinea continuă a exemplului. Fiecare rând al tabelului este reprezentat în memorie cu un pointer simplu către caracterul său de început.


Exemplu de implementare

Notă: Scris în C

 #include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <stdio.h>

octet de caractere nesemnat typedef ;

octet * rotlexcmp_buf = NULL ;
int rotexcmp_bufsize = 0 ;

int rotlexcmp ( const void * l , const void * r )
{
    int li = * ( const int * ) l , ri = * ( const int * ) r , ac = rottexcmp_bufsize ;
    if ( li == ri ) returnează 0 ;
    while ( rotlexcmp_buf [ li ] == rotlexcmp_buf [ ri ])
    {
        if ( ++ li == routesxcmp_bufsize )
            li = 0 ;
        if ( ++ ri == rottexcmp_bufsize )
            ri = 0 ;
        dacă ( ! - ac )
            retur 0 ;
    }
    if ( rotlexcmp_buf [ li ] > rotlexcmp_buf [ ri ])
        retur 1 ;
    altceva
        retur -1 ;
}

bwt_encode void (byte * buf_in, octet * buf_out, int size, int * primary_index)
{
    indici int [ dimensiune ];
    int i ;

    pentru ( i = 0 ; i < dimensiune ; i ++ )
        indici [ i ] = i ;
    rotlexcmp_buf = buf_in ;
    rottexcmp_bufsize = dimensiune ;
    qsort ( indici , dimensiune , sizeof ( int ), rotlexcmp );

    pentru ( i = 0 ; i < dimensiune ; i ++ )
        buf_out [ i ] = buf_in [( indici [ i ] + mărime -1 ) % mărime ];
    pentru ( i = 0 ; i < dimensiune ; i ++ )
    {
        if ( indicii [ i ] == 1 ) {
            * primar_index = i ;
            întoarcere ;
        }
    }
    afirmă ( 0 );
}

void bwt_decode (octet * buf_in, octet * buf_out, dimensiune int primary_index)
{
    octet F [ mărime ];
    găleți int [ 256 ];
    int i , j , k ;
    indici int [ dimensiune ];

    pentru ( i = 0 ; i < 256 ; i ++ )
        găleți [ i ] = 0 ;
    pentru ( i = 0 ; i < dimensiune ; i ++ )
        găleți [ buf_in [ i ]] ++ ;
    pentru ( i = 0 , k = 0 ; i < 256 ; i ++ )
        pentru ( j = 0 ; j < găleți [ i ]; j ++ )
            F [ k ++ ] = i ;
    afirmă ( dimensiunea k == );
    pentru ( i = 0 , j = 0 ; i < 256 ; i ++ )
    {
        while ( i > F [ j ] && j < dimensiune )
            j ++ ;
        cupe [ i ] = j ; // va primi valori false dacă nu există i în F, dar
                        // asta nu ne va aduce probleme
    }
    pentru ( i = 0 ; i < dimensiune ; i ++ )
        indici [ găleți [ buf_in [ i ]] ++ ] = i ;
    pentru ( i = 0 , j = index_primar ; i < dimensiune ; i ++ )
    {
        buf_out [ i ] = buf_in [ j ];
        j = indici [ j ];
    }
}

int main ()
{
    byte buf1 [] = "Polska Wikipedia" ;
    int size = strlen (( const char * ) buf1 );
    octet buf2 [ dimensiune ];
    octet buf3 [ dimensiune ];
    int primar_index ;

    bwt_encode ( buf1 , buf2 , size , & primary_index );
    bwt_decode ( buf2 , buf3 , size , primary_index );

    afirmă ( ! memcmp ( buf1 , buf3 , dimensiune ));
    printf ( "Rezultatul este același cu intrarea, adică: <%. * s> \ n " , dimensiune , buf3 );
    // Imprimați codificarea / decodarea rezultatelor:
    printf ( "Intrare: <%. * s> \ n " , dimensiune , buf1 );
    printf ( "Ieșire: <%. * s> \ n " , dimensiune , buf2 );
    retur 0 ;
}

Implementare Perl:

 #! / usr / bin / perl

# o implementare Oromis92

while ( $ text = <> ) {
    chomp $ text ;
    @text = split // , $ text ;
    $ lungime = lungime ( $ text );
    @array = ( $ text );
    pentru ( $ j = 0 ; $ j < $ lungime ; $ j ++ ) {
        pentru ( $ i = 0 ; $ i < $ lungime ; $ i ++ ) {
            $ string . = $ text [ ( $ i - ( $ j + 1 ) ) ]];
        }
        $ array [ $ j + 1 ] = $ șir ;
        $ string = "" ;
    }
    pop ( @array );

    @array = sort ( @array );

    $ text = "" ;
    pentru ( $ k = 0 ; $ k <= $ # matrice ; $ k ++ ) {
        $ text . = substr ( $ array [ $ k ], ( $ length ) - 1 , 1 );
    }
    tipăriți „$ text \ n” ;
}

Notă

  1. ^ Burrows M și Wheeler D, Un bloc de sortare a algoritmului de compresie a datelor fără pierderi , Raport tehnic 124, Digital Equipment Corporation, 1994.
Informatică Portal IT : accesați intrările Wikipedia care se ocupă cu IT