LZ77 et LZ78

Un article de Wikipédia, l'encyclopédie libre.
Aller à : navigation, rechercher

LZ77 et LZ78 sont deux algorithmes de compression de données sans perte proposés par Abraham Lempel et Jacob Ziv en 1977 et 1978 (d'où leurs noms). Ces deux algorithmes posent les bases de la plupart des algorithmes de compression par dictionnaire, à tel point qu'on parle couramment d'algorithme LZ pour désigner un algorithme de compression par dictionnaire. Ces algorithmes reposent de manière essentielle sur une mesure de complexité pour les suites de longueur finie, la complexité de Lempel-Ziv.

LZ77[modifier | modifier le code]

Principe de l'algorithme LZ77[modifier | modifier le code]

LZ77 est un algorithme de compression par dictionnaire utilisant une fenêtre glissante ; les motifs déjà rencontrés dans la fenêtre sont remplacés par une référence à leur première apparition (typiquement, par une paire (distance, longueur)).

Par extension, LZ77 est aussi utilisé pour désigner la famille des algorithmes de compression par dictionnaire utilisant une fenêtre glissante, comme LZSS et LZMA.

LZ77 présente certains défauts, en particulier, si aucune chaîne n'est trouvée dans le dictionnaire, le symbole à compresser est alors codé par "position=0", "longueur=0", "nouveau symbole", c'est-à-dire qu'il occupe 3 octets au lieu d'un seul dans le fichier original. Ce défaut est supprimé dans la variante LZSS.

L'algorithme LZ77 est notamment utilisé dans l'algorithme deflate (avant un codage de Huffman) et pour la compression des fichiers dans le système de fichier Windows NTFS[1].

Description de l'algorithme LZ77[modifier | modifier le code]

Compression[modifier | modifier le code]

Etant donnée une séquence S à compresser, on l'écrit d'abord sous forme de plusieurs composantes Si juxtaposées. Pour ce faire, on choisit un entier LS qui sera la longueur maximale d'un Si et un entier n > LS qui sera la taille du buffer. On initialise les n-Ls caractères du buffer par des zéros et on complète le buffer par les LS premiers caractères de S.

L'entier n-Ls est la taille de la fenêtre glissante (initialisée avec des zéros comme indiqué précédemment). Pour trouver les Si, on réalise à chaque itération une production exhaustive de la sous-séquence de S la plus longue possible en prenant le contenu de la fenêtre glissante comme préfixe, avec ici la contrainte que la longueur de la séquence produite ne peut dépasser Ls.

Après initialisation de la fenêtre à zéro et en appliquant ce processus de production on obtient donc la séquence S1 de longueur L1<Ls puis on fait glisser la fenêtre en enlevant les L1 premiers caractères de la fenêtre glissante du buffer et en faisant entrer dans le buffer les L1 caractères suivants de S. On répète ce procédé (production puis glissement de la fenêtre) pour trouver les autres Si jusqu'à arriver au bout de la séquence S.

Cette décomposition découpe S sous forme de composantes comme dans le processus de calcul de la complexité de Lempel-Ziv.

A chaque étape i, après avoir trouvé Si par un processus de production, on lui affecte un mot de code qui sera sa représentation dans le fichier compressé. Ce mot de code n'est rien d'autre que le triplet (position, longueur, caractère) correspondant.

Chaque Si est ainsi codé par un triplet Ci,1Ci,2Ci,3 et sera représenté ainsi dans le fichier compressé. Le mode de représentation est donc le suivant :

  • Ci,1 est la représentation en base α(α étant la taille de l'alphabet des caractères de S) de pi-1, avec pi l'indice dans la fenêtre glissante où commence la copie qui correspond à Si (pi est le pointeur pour la production de Si).
  • Ci,2 est la représentation en base α de Li - 1 (la longueur de la production à cette étape)
  • Ci,3 est le dernier caractère de Si

Cet algorithme est étroitement lié au calcul de complexité de Lempel-Ziv. Après avoir fait précédé S de n-LS zéros, on ne fait en effet que décomposer S en composantes Si (qu'on remplace par leur mot de code) en prenant, à chaque étape, le contenu de la fenêtre glissante comme préfixe et en ayant une longueur maximale LS fixée pour toutes les composantes.

Vu que pi est un indice appartenant au préfixe (ici, la fenêtre glissante), il est compris entre 1 et n-LS et peut être représenté en base α par  \lceil  \log α (n-LS) \rceil caractères. De même, les Li étant bornés par LS, on a besoin de  \lceil  \log α (LS) \rceil caractères pour représenter Li-1. Ci,3 étant un caractère unique, chaque Si sera représenté dans le fichier compressé par LC = \lceil  \log α (n-LS) \rceil +  \lceil  \log α (LS) \rceil + 1 caractères.

Décompression[modifier | modifier le code]

La décompression est très semblable à la compression.

Initialisation :

  • on utilise une fenêtre de taille n-LS qui est initialisée avec des zéros,
  • on récupère pi - 1 (et donc pi) sur les  \lceil  \log α (n-LS) \rceil premiers caractères de Ci (Ci,1),
  • les  \lceil  \log α (LS) \rceil caractères suivants (Ci,2) donnent la valeur de Li - 1.

Après l'initialisation, à chaque étape i on répète Li -1 fois le processus suivant :

  • on recopie le caractère qui est à l'indice pi à la fin de la fenêtre,
  • puis on fait glisser la fenêtre vers la droite pour faire sortir son premier caractère et faire entrer le caractère qui vient d'être recopié dans la fenêtre.

Vu que les Li - 1 premiers caractères de Si sont juste une copie de la partie de la fenêtre commençant à l'indice pi, on récupère par le processus ci-dessus les Li -1 premiers caractères de Si. A ce stade, il ne nous manque que le dernier caractère de Si qui n'est rien d'autre que le dernier caractère (Ci,3) de Ci.

Ceci amène à la dernière phase de l'étape i qui consiste à :

  • recopier le dernier caractère de Ci (qui est le dernier caractère de Si) à la fin de la fenêtre avant d'effectuer un dernier décalage à droite, d'un caractère, de la fenêtre.

On obtient ainsi Si en récupérant les Li derniers caractères de la fenêtre. Après avoir appliqué ce processus à tous les mots de code Ci, la séquence S est obtenue en concaténant les Si.

Exemple[modifier | modifier le code]

LZ78[modifier | modifier le code]

LZ78 est un algorithme de compression par dictionnaire utilisant un dictionnaire implicite, construit de la même façon par le compresseur et le décompresseur, respectivement à la compression et à la décompression.

Par extension, LZ78 est aussi utilisé pour désigner la famille des algorithmes de compression par dictionnaire utilisant un dictionnaire implicite, comme Lempel-Ziv-Welch.

LZ78 a eu moins de succès que LZ77, pour des raisons d'efficacité, et parce qu'il a été protégé par un brevet logiciel aux États-Unis.

Voir aussi[modifier | modifier le code]

Références[modifier | modifier le code]

  1. NTFS