Codifiche di Lempel Ziv
Commenti
Transcript
Codifiche di Lempel Ziv
Codifiche di Lempel Ziv Michelangelo Diligenti Dipartimento di Ingegneria dell’Informazione Università di Siena Email: [email protected] http://www.dii.unisi.it/~diligmic/BDM2009 1 Idea di base Compressione limitata dal limite dell'entropia Utilizzare i singoli caratteri come simboli limita la polarizzazione della p(s) Nel caso del testo, potrei usare le parole Soluzione comune è usare sequenze di caratteri come simboli Ho un numero esponenziale di possibili frasi all'aumentare della lunghezza Nel caso del testo ho 256n blocchi possibili di lunghezza n Ma come scegliere le frasi? 2 Idea di base Ad esempio, 'and', 'the', 'or' per l'inglese Costruisco la distribuzione di probabilità sulle parole e non sui caratteri Se una parola non la ho, allora codifico carattere a carattere Se le possibili frasi sono troppe, si possono selezionare solo le più comuni Questo funziona bene ma non si adatta al meglio a documenti di tipo diverso Parole in documenti di sport non sono comuni in quelli di business, e viceversa La cosa si fa ancora più complessa per documenti non testuali. Come scelgo le parole? 3 Idea di base Una soluzione sarebbe costruire un dizionario ad-hoc sui dati da comprimere – Ma questo richiede un doppio passaggio sui dati – Poi il dizionario deve essere trasmesso e/o memorizzato e questo spreca spazio L'unica soluzone generale ed efficiente è di creare i dizionari in modo adattivo mentre si codificano i dati – Soluzione adottata da tutti i pacchetti generici per la compressione dei dati 4 Metodi basati su dizionari Creo dizionario con le stringhe già osservate nei dati precedenti Intrinsecamente adattivo Le “frasi” sono le sottostringhe del testo già elaborato Si crea un dizionario o 'codebook', che associa un codice ad una frase Ogni volta che ritrovo la frase, emetto il codice I metodi basti su dizionari, costruiscono le frasi direttamente guardando i dati Spesso protette da brevetti Tante varianti sono note 5 Metodi basati su dizionari Passo avanti rispetto ai metodi come Huffman o Aritmetica adattivi In tali metodi le probabilità erano stimate in modo adattivo Nei metodi basati su dizionari, è la tabella dei simboli a diventare adattiva 6 Metodi basati su dizionari In decompressione si ricostruisce il dizionario che il codificatore aveva generato in precedenza Ancora una volta non devo trasferire il dizionario visto che la codifica è causale ATTENZIONE: i metodi basati su dizionari non sono alternativi a Huffman o Aritmetica Ci dicono come costruire la tabella dei blocchi in modo adattivo Ma i dati devono sempre essere codificati e scritti Per questo anche i metodi di Lempel/Zip possono appoggiarsi alle codifiche come Huffman o Aritmetiche 7 Metodi basati su dizionari Gli algoritmi sono noti come LZ77 ed LZ78 Vedi per esempio il paper Vi sono centinaia di varianti Tutte riconducibili ai due algoritmi sviluppati dai ricercatori israeliani Lempel e Ziv nel 1977 e 1978 “A Universal Algorithm or Sequential Data Compression” in IEEE Transactions on Information Theory, 1977 8 LZ77 e le sue varianti Facile da realizzare Veloce in decodifica Usa poca memoria Genera triple contenenti Indice della frase o puntatore. Contando all'indietro dal simbolo attualmente elaborato Lunghezza della frase Carattere attualmente elaborato 9 aa bab aabb LZ77: esempio di codifica b Alfabeto {a,b} Stringa da codificare abaababaabb Codifica LZ77 a <0,0,a> <0,0,b> <2,1,a> <3,2,b> <5,3,b> Lunghezza della Frase Frase che inizia 2 caratteri prima dell'attuale 10 LZ77: decodifica Stringa da decodificare <0,0,x><0,0,y><2,1,z><2,1,x><5,3,z> <6,3,z><5,2,z> Stringa decodificata x y xz xx yxzz xxyz zxz 11 LZ77 e limiti ai valori Indice all'indietro ha un valore max Esempio 4096 o 12 bit Infatti è stato dimostrato che usare valori maggiori non ha vantaggi (per il principio di località dei dati) Tipicamente inutile andare oltre 16 o 4 bit Lunghezza delle parole riferite Ma ogni tripla usa più bits Si deve trovare compromesso Usare indici e lunghezze più lunghe permette di usare meno triple 12 LZ77: quanto comprime Per la lunghezza Nel caso del testo, ogni tripla contiene n+m+8 bits Per l'indice Per il carattere corrente numero_bit_totali = (n+m+8)*numero_triple fattore_compressione=Numero_bit_iniziali/Numero_bit_totali 13 LZ77: quanto comprime Se lunghezza max stringa puntata è 3 (2 bit) <0,0,0><0,0,1><2,1,0><0,0,2><2,1,$><7,2,1><5,2,$><6,4,1> 8*(3+3+8)=112 bits Stringa da codificare 18 bytes: 010020$0110$$01101 Numero max indice: 7 (3 bit) Lunghezza max stringa puntata: 7 (3 bit) Ogni carattere ascii 8-bit Codifica LZ77 Esempio <0,0,0><0,0,1><2,1,0><0,0,2><2,1,$><7,2,1><5,2,$><6,3,0><0,0,1> fattore_compressione=Numero_bit_iniziali/Numero_bit_totali=144/ 112 14 LZ77, algoritmo di codifica Cerca il match massimo per S[p...] in S[p-n, ..., p-1] Supponi il match sia in posizione p-i, con lunghezza l output la tripla <p-i, l, S[p+l ]> p=p + l + 1 S la stringa da comprimere, con lunghezza |S| n l'indice massimo ammesso nella codifica p=1 while p<|S| – – – – 15 LZ77, decodifica Decodifica una sequenza di N triple in una sequenza di byte S p=1 For each tripla<i,l,c> - S[p, ..., p + l + 1] = S[p - i, ..., p – i + l – 1] - S[p + l] = c -p=p+l+1 16 LZ77, alcune varianti recenti Le triple devono essere memorizzate – Che codifica uso? – Prima componente (indice) • Huffman coding, indici con valori bassi sono più probabili – Seconda componente • Huffman coding, lunghezze brevi sono più probabili – Terza componente • Se presente (vedremo varianti che non la usano), Huffman potrebbe essere una buona scelta 17 LZ77 e gzip Gzip è il più comune software di compressione per Unix/Linux – Creato da J. Gailly e M. Adler nel 1992 – www.gzip.org – Basato su variante di LZ77 – Software open-source distribuito dalla Free Software Foundation – Software per la compressione di dati generici 18 Gzip - implementazione Gzip usa tabelle hash – Permettono di cercare le occorrenze delle sequenze precedenti in modo veloce – Gzip usa una finestra di dimensione N – Tabella hash memorizza le occorrenze di tutte le sequenze di tre caratteri 19 Gzip - implementazione Gzip calcola valore hash dei prossimi 3 caratteri da codificare – Valore dell'hash è usato per lookup in tabella – Se lookup ha successo • Ritorna una lista degli indici delle occorrenze dei 3 caratteri nella finestra considerata • Si scorre la lista cercando il match più lungo • Il match trovato è usato per genere la tripla – Altrimenti • I tre caratteri sono codificati in modo raw (con codice ASCII) – Si aggiorna la tabella hash aggiungendo le nuove sequenze di tre caratteri 20 Gzip - implementazione La finestra in cui si cercano i match è al massimo 32KB La lunghezza delle sequenze puntate all'indietro è al massimo 256 La lunghezza delle liste ritornate dai lookup è limitata – Evita di consumare troppo tempo scorrendo le liste – Le liste sono ordinate in base agli inserimenti, si eliminano i match all'inizio della lista (vecchi) – Liste complete permettono di trovare sempre il match migliore • Compromesso velocità/fattore di compressione – Gzip permette di controllare il compromesso tramite un grado di ottimalità di compressione. Utente decide dove lavorare • Digita gzip –help, viene chiesto il grado di compressione tra [1,9] 21 Gzip – codifica delle triple Output di coppie <indice, lunghezza/carattere> e non triple – Coppia può essere <indice, lunghezza> – Oppure <0, carattere> Se indice è 0, non è un indice! 22 Gzip – codifica delle coppie Indice, lunghezza e carattere sono codificati tramite Huffman Codici di Huffman sono creati direttamente a partire dai dati scorrendo blocchi di 64KB di dati alla volta – Gzip non è propriamente ad un passo, ma nemmeno a due passi... – 64KB è poco, pertanto gzip carica in memoria l'intero blocco – Primo passo si costruiscono le coppie – Secondo passo, si contruiscono gli alberi di Huffman – Due scansioni ma la seconda sui dati compressi e tenuti in memoria principale. Si dice che gzip è 1.5 passi... – Infatti in genere il limite è la scansione da disco 23 Gzip ed ottimizazioni abacbcaab ...... abcaab – La seconda parte della stringa “abcaab” la posso scomporre come • ab + c + a + ab • Oppure a + bcaab La prima soluzione è “greedy” (avida). Quella che fornisce il match migliore al primo passo La seconda è peggiore guardando al primo carattere, ma è migliore globalmente perché codifica 5 simboli già incontrati con 1 coppia Se utente seleziona livello massimo d compressione, gzip cerca di fare ottimizzazione globale e non solo greedy che è il default 24 Zip e Winzip Basata su LZ77 e Huffman coding La più usata su Windows tramite il popolare Winzip Diffusa anche su Mac, default per l'archiviazione sul Finder Il formato CAB usato su Windows è molto simile al formato zip 25 LZ78 - Restringe le frasi che sono indicizzabili, solo un sottoinsieme di frasi va nel dizionario – In LZ77 qualsiasi sottostringa precedente era utilizzabile nel seguito della compressione - Decodifica più lenta di LZ77 ed usa più memoria + Permette di limitare in modo meno stringente la finestra in cui si indicizzano le frasi precedenti + La sua versione detta LZW è utilizzata in molti software commerciali e nel formato GIF 26 Stringhe refereziabili Del testo precedente alla posizione corrente solo le frasi nel dizionario possono essere referenziate Le frasi precedenti sono numerate in sequenza – Il numero fornisce l'indice per le referenze – L'uscita è una lista di coppie • <indice_frase, carattere> – Lunghezza non necessaria, l'indice referenzia una frase esatta – La coppia generata diventa una nuova frase 27 LZ78 – un esempio <null> a b aa ba baa <0,a> <0,b> <1,a> <2,a> <4,a> Output Stringa da codificare abaababaa Frasi 0 1 2 3 4 5 Solo le frasi esplicitamente nel dizionario sono referenziabili 28 LZ78 - memorizzare le frasi <null> a b aa ba baa bab a 1 3 a 0 5 a b a 2 4 b 6 Le frasi devono essere memorizzate in modo efficiente Usare un trie minimizza l'uso di memoria Ogni nodo corrisponde ad una frase nel dizionario Frasi 0 1 2 3 4 5 6 29 a 1 3 a 0 5 a b a 2 4 b 6 Si parte dal carattere attuale e si naviga il trie fino a trovare frase più lunga nel dizionario Si aggiunge un nodo con un nuovo carattere che forma la nuova frase nel dizionario Poiché le frasi sono aggiunte incrementalmente, un solo nodo deve essere aggiunto ogni volta LZ78 – memorizzare le frasi Frasi b 7 baab <5,b> <5,b> 30 LZ78 - problemi Il trie continua crescere, fino ad usare troppa memoria Periodicamente – Il trie viene reinizializzato da zero – Se troppo grande, il trie viene congelato senza aggiungervi nuove frasi/nodi – Oppure, viene ricostruito usando un blocco di dati recenti • Evita di reniziare da zero, che peggiora compressione • Maggior tempo di compressione 31 LZ78 - esercizio Codifica con LZ78 la stringa 0100101110101001011 <null> 0 1 00 10 11 101 01 001 011 32 SOLUZIONE <0,0><0,1><1,0><2,0><2,1><4,1><1,1><3,1><7,1> FRASI 0 1 2 3 4 5 6 7 8 9 LZ78 – variante LZW Popolare variante di LZ78 usata dal programma “compress” Codifica solo le frasi e non i caratteri da appendere – Possibile perché si inizializza il dizionario con una frase per ogni carattere dell'alfabeto – Nel caso del testo, si inizializza con 256 caratteri del codice ASCII – Nuove frasi sono inserite nel dizionario aggiungendo alla frase precedente al primo carattere della frase successiva 33 LZW - codifica a 97 128 128 129 LZW - decodifica 97 inserito già a 131 97 98 131 97 input: ba aba aba 133 ab 132 baa abaa ab 131 abb a 130 aba b 128 129 aa 134 ab ba output: a nuove frasi aggiunte Codificatore non ha usato le frasi subito dopo la loro creazione e la decodifica ha funzionato. È stata ricostruita la frase. 35 LZW – codifica errata LZW – decodifica non funzionante input: output: nuove frasi aggiunte Codificatore non deve usare le frasi subito dopo la loro creazione. Altrimenti il decodificatore non può decodificare perché non ha la frase disponibile. Vedi esempio 37 LZW - esercizio Codifica con LZW la sequenza 012201220122$0122$ Partendo dai codice 8-bit ASCII 048, 149, 250, $36 261 262 263 264 265 200 0122 2$ $0 0122$ SOLUZIONE 48 49 50 50 256 258 260 50 36 262 36 FRASI 25601 25712 25822 25920 260012 38 Lempel-Ziv: sommario <indice,lunghezza,carattere> LZW <indice, lunghezza/carattere> gzip LZ78 <frase> LZ77 <frase,carattere> 39 Lempel-Ziv: esercizio Codificare la stringa con LZ77,LZ78,LZW: abbbbaccabbbb Calcolare i fattori di compressione usando 4 bit per gli indici per e 7 (3 bit) come lunghezza massima dei match (solo per LZ77) Codici ASCII da utilizzare a97 b98 c99 40