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 048, 149, 250, $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
a97 b98 c99
40