sábado, 17 de marzo de 2012

CÓDIGO LEMPEL - ZIV
Objetivos:

  • Aprender acerca del código de compresión para poder utilizar menos espacio de almacenamiento y transmitir archivos más rápidamente, ahorrando así tiempo y costo.
  • Desarrollar nuevas técnicas que nos sean útiles y faciliten nuestro aprendizaje en la teoría de la información y codificación.
  • Analizar la metodología y procedimiento utilizado por este código para ejecutarlo correctamente.
HISTORIA
Los creadores de este clásico algoritmo de compresión fueron Abraham Lempel y Jacob Ziv en el año 1977, nacía el LZ77.
Un año después crearon el compresor de imágenes o cualquier dato que fuera binario llamado LZ78. En 1984, un ingeniero de la empresa Unisys llamado Terry Welch modificó el código para implementarlo en los controladores de disco duro dando su apellido al algoritmo LZW.
El compresor LZW es un sistema de compresión/descompresión muy rápido que se basa en la multiplicidad de los caracteres en la cadena que se va a codificar. A partir de la cadena creaba unos patrones que los integraba en un diccionario. El LZW trabaja con bits y no con bytes, lo que consigue gran compatibilidad a la hora de procesar datos. Este formato es muy utilizado en la comprensión de imágenes TIFF o GIF. Por otra parte, el PNG utiliza el LZ77 por tanto es totalmente libre.

COMPRESIÓN DE DATOS
 La compresión de datos es la reducción del volumen de datos tratables para representar una determinada información empleando una menor cantidad de espacio.
La compresión es un caso particular de la codificación cuya característica principal es que el código resultante tiene menor tamaño que el original.
La compresión de datos se basa fundamentalmente en buscar repeticiones en series de datos para después almacenar solo el dato junto al número de veces que se repite, para ello se utilizan algoritmos de compresión como el de Lempel Ziv .
El objetivo de la compresión es siempre reducir el tamaño de la información, intentando que esta reducción de tamaño no afecte al contenido. No obstante, la reducción de datos puede afectar o no a la calidad de la información:
  • Compresión sin pérdidas: en esta compresión los datos antes y después de comprimirlos son exactos,  pero una mayor compresión implica más tiempo de proceso.
  • Compresión con pérdidas: puede eliminar datos para reducir aún más el tamaño, con lo que se suele reducir la calidad. En este tipo de compresión no se obtiene la señal original una vez realizada la compresión. Se utiliza principalmente en la compresión de imágenes, videos y sonido.
COMPRESIÓN BASADA EN DICCIONARIO
Son técnicas que no requieren conocer de la probabilidad de aparición de cada símbolo. Por ello sera útiles en aquellas aplicaciones donde no sea posible conocer las probabilidades de los símbolos. Estos códigos se basan en algunas cadenas podrían ser sustituidas por una palabra  de un nuevo código que ocupe menos espacio.Para ello tanto el emisor como el receptor construirán tablas que contendrán toda la información necesaria para llevar a cabo la compresión y descompresión. Son códigos eficientes cuando se utilizan en ficheros y mensajes grandes.


EJEMPLO: Otra forma de realizar el código de Lempel Ziv. 
Tenemos una secuencia   S=00101011

Se los tabula, de forma que podamos hacer referencia a cada elemento de la secuencia fijándonos en el orden en el que aparece dentro de esta.
La primero fila de la figura indica la posición dentro del buffer y la segunda su contenido. Consideraremos la posición más a la izquierda como posición 1.





Supongamos también que los tres primeros elementos, 001, ya han sido codificados; en este momento nos da igual que hayan sido comprimidos o tomados como literales. Posteriormente nos ocuparemos de ese aspecto, pero ahora tenemos que codificar lo que sigue: 01011. Llamaremos a la secuencia ya codificada secuencia 1 y a la que está siendo codificada ahora secuencia 2.
Si a una persona normal le pedimos que encuentre en 01011 una secuencia que esté repetida a partir de lo que ya hemos codificado (001), nos dirá que los dos primeros elementos de la secuencia a codificar (posiciones 4 y 5 dentro del buffer) son iguales a los dos últimos de 001 (posiciones 2 y 3), y que ahí hay una repetición. Y tendrá razón, pero la genialidad de LZ está en darse cuenta de que se puede ir más allá y utilizar la propia secuencia a codificar como lugar donde seguir buscando repeticiones. ¡Eso a pesar de que aún no la hemos codificado!

Veámoslo: la secuencia 2 empieza por 0101 (posiciones 4 a 7). Si empezamos a mirar en lo que ya hemos codificado, la secuencia 1, tenemos que finaliza en 01, pero si seguimos entrando en la secuencia 2 ahora veremos que empieza por 01. Si juntamos el final de la secuencia 1 con el principio de la secuencia 2, tenemos 0101, que es igual al comienzo de la secuencia a codificar o secuencia 2. Es decir: los elementos 4, 5, 6 y 7 de la secuencia total son una "repetición'' de los elementos 2, 3, 4 y 5. Por tanto se codificarán como un puntero a la posición número 2 más una longitud de 4. Luego veremos en un ejemplo cómo esto, aunque parezca imposible, funciona a la hora de decodificar.

La codificación se lleva a cabo introduciendo los datos dentro de un buffer de una longitud prefijada, n, dentro del cual se van buscando subcadenas ya repetidas haciendo uso del método que acabamos de explicar. En gzip, la longitud máxima de esas subcadenas, Ls, es de 258 bytes. Si una cadena no ocurrió dentro de los 32 Kbyte anteriores, se emite literalmente.

Un ejemplo ayudará a ver cómo se llevan a cabo la compresión y la descompresión. Utilizaremos una simplificación de uno propuesto por los creadores del algoritmo.

Supongamos que queremos codificar la secuencia:

S=001010210210212021021200...

Por razones didácticas (aunque no prácticas) usaremos un buffer de longitud n=18 y una longitud máxima de cadena Ls de 9. Inicialmente se llenan las n-Ls posiciones del buffer con ceros, y las Ls restantes con los primeros datos de la secuencia, con lo que el buffer en la posición inicial quedaría como se ve en la figura 2.



La extensión reproducible de Ls, empezando a buscar en la parte ya "codificada" (las n-Ls primeras posiciones del buffer), aparece en gris.

La primera subcadena a codificar se formará a partir de esa extensión reproducible, 00, seguida del siguiente elemento que ya no está repetido 1, luego S1=001.

La palabra código que representa a esa subcadena será, por convenio y en ese orden, el puntero al comienzo de la repetición menos 1, seguido de la longitud de la repetición, seguido del elemento final, que no entraba en la repetición. Es decir, para este caso: C1=021.
Puesto que S1 tenía longitud 3, todo el contenido del buffer es desplazado hacia la izquierda 3 posiciones. En esta situación 2 seguiremos, como siempre, a partir de la posición 10, buscando la extensión reproducible de 0102... La encontramos en la figura 3.



Aquí, la extensión periódica de los elementos a partir de la posición 10 se haya en la posición 8. Empezando tanto por 8 como por 10 encontramos la secuencia 010, así que S2 es la parte que se repite del comienzo de Ls, 010 (posiciones 10 a 12), más el siguiente elemento, 2, que ya no se repite (posición 13). Luego S2=0102, que se codifica como C2=732. Desplazamos 4 posiciones a la izquierda, que es lo que mide S2, y la "repetición'' de la secuencia Ls se encuentra en la zona marcada en la figura 4.



En ella se observa con claridad que, dado que Ls empieza por 10, había una repetición en las posiciones 5 y 6, que también son 10, que sin embargo no hemos marcado en negrita dentro de la figura. Esto es debido a que la secuencia formada por las posiciones 5 y 6, si bien representa una repetición de lo que aparece en Ls, no se trata de su extensión periódica ya que tiene longitud 2, mientras que la coloreada en la figura tiene longitud mayor: 7. Por ello S3=10210212 y C3=672. Por último, tras desplazar las 8 posiciones que ocupa S3, se obtiene S4=021021200 y C4=280 (figura 5).



Comprobemos que la secuencia comprimida C=821732672280 puede decodificarse unívocamente dando como resultado la secuencia original S=001010210210212021021200. Es importante darse cuenta de que, si bien la longitud de las subcadenas no es fija (aunque sí limitada), la de las palabras código sí lo es: en este caso, 3 caracteres. Esto permite separar a partir de C palabra código de palabra código de forma simple. Incluso dentro de una misma palabra código, los tamaños asignados a una u otra función (posición a partir de la que empieza una repetición, longitud de esta y elemento siguiente a ella), son también fijos, y fácilmente separables.
La longitud de cada uno de estos campos, y de la palabra código como suma de todos ellos, está directamente relacionada con el tamaño del buffer, n, y con el de la máxima subcadena, Ls. Más detalles se pueden encontrar en el artículo de Lempel-Ziv.
Para descomprimir se emplea un buffer de longitud n-Ls donde se van guardando los símbolos descodificados. Inicialmente el buffer se pone todo a 0.
Seguidamente se van leyendo palabras código, lo cual puede hacerse sin especiales cuidados al tener todas la misma longitud. También en este caso ilustraremos la descompresión paso por paso. El primero se ilustra en la figura 6.




La primera palabra que se lee es '021'. El '0' sirve de puntero en el buffer, y lo llamaremos "p''. Se debe leer el carácter que está en la posición p+1, luego se lee el de la posición 1. Como inicialmente el buffer estaba puesto a 0, no sorprende que lo que encontremos en la posición 1 sea un '0'. Tal y como está el buffer, se desplazan todos sus elementos una posición hacia la izquierda, y en el hueco que queda a la derecha se introduce el carácter leído con anterioridad en esa posición 1. El segundo carácter de la palabra código es un '2'. Ello indica que la operación anterior de leer y desplazar se debe hacer dos veces, por lo que la repetimos: nuevamente se lee la posición 1.
Aunque la posición es la misma, el dato leído no tiene por qué serlo, ya que el buffer se desplazó hacia la izquierda. En este caso volvemos a tener un '0', y el buffer tiene el mismo aspecto que antes. Al segundo elemento de las palabras código lo llamaremos a partir de ahora "n''. Puesto que ya hemos hecho dos veces la operación, tantas como indicaba el n de la palabra código que estamos decodificando, ahora se desplaza una vez más a la izquierda, y en el hueco que ha aparecido se introduce el tercer carácter de la palabra código (a partir de ahora "c''), sin modificar: el '1'.

Al final de todas las figuras se resalta en negrita la parte del buffer que corresponde a la descodificación de la palabra código. Evidentemente, este tramo se encuentra siempre al final del buffer, y su longitud es bien simple de calcular: n+1.
La siguiente palabra a decodificar es 732. Como antes, y esta vez por 3 veces, se guarda el carácter de la posición 7+1 y se coloca a la derecha del buffer tras desplazarlo. El último carácter que se introduce por la derecha nos viene dado en la palabra código: ahora es un '2' (figura 7).


El proceso con las dos palabras código restantes es exactamente igual, y no requieren mayor explicación. No obstante, se ofrecen las figuras correspondientes para que el lector interesado pueda seguir el proceso hasta el final (figuras 8 ).










Extrayendo los tramos en negrita del final de cada paso, obtenemos 001, 0102, 10210212 y 021021200, que juntos vuelven a conformar la secuencia original S.


VÍDEO EJEMPLO CODIFICACIÓN LEMPEL-ZIV
INTEGRANTES
  • Guanopatín Cristian 
  • Loachamín Robinson
  • Rodríguez Angélica 
CRONOGRAMA DE ACTIVIDADES LEMPEL-ZIV 
http://cronograma-lempel-ziv.blogspot.com/ 


BIBLIOGRAFIA: