Comecei a ler um livro chamado Introdução à compactação de dados, de Guy E. Blelloch. Na página um, ele afirma:
A verdade é que, se qualquer mensagem for encurtada por um algoritmo, outra mensagem precisará ser prolongada. Você pode verificar isso na prática executando o GZIP em um arquivo GIF. De fato, é possível ir além e mostrar que, para um conjunto de mensagens de entrada de tamanho fixo, se uma mensagem for compactada, o comprimento médio das mensagens compactadas em todas as entradas possíveis sempre será maior que o original mensagens de entrada.
Considere, por exemplo, as 8 possíveis mensagens de 3 bits. Se uma é compactada em dois bits, não é difícil se convencer de que duas mensagens terão que se expandir para 4 bits, dando uma média de 3 1/8 bits.
Mesmo? Acho muito difícil me convencer disso. De fato, aqui está um exemplo contrário. Considere o algoritmo que aceita como entrada qualquer sequência de 3 bits e mapeia para as seguintes saídas:
000 -> 0
001 -> 001
010 -> 010
011 -> 011
100 -> 100
101 -> 101
110 -> 110
111 -> 111
Então, aqui está você - nenhuma entrada é mapeada para uma saída mais longa. Certamente não há "duas mensagens" que foram expandidas para 4 bits.
Então, o que exatamente o autor está falando? Eu suspeito que ou há alguma advertência implícita que não é óbvia para mim, ou ele está usando uma linguagem muito abrangente.
Isenção de responsabilidade: percebo que, se meu algoritmo for aplicado iterativamente, você realmente perderá dados. Tente aplicá-lo duas vezes na entrada 110: 110 -> 000 -> 0 e agora você não sabe qual das 110 e 000 foi a entrada original. No entanto, se você aplicá-lo apenas uma vez, parece-me sem perdas. Isso está relacionado ao que o autor está falando?
fonte
Respostas:
O que está faltando é que você precisa considerar todos os bits de tamanho 3 ou menos . Ou seja: se em um esquema de compactação para bits de tamanho 3 ou menos compactarmos uma das cadeias de 3 bits em uma cadeia de 2 bits, alguma cadeia de tamanho 3 ou menor terá que expandir para 3 bits ou mais.
Um esquema de compactação sem perdas é uma função de seqüências de bits finitas para seqüências de bits finitas que é injetável, isto é, se então , ou seja, determina unicamente .C C(x)=C(y) x=y C(x) x
Considere um esquema de compactação arbitrário e deixe ser um conjunto de cadeias binárias. Podemos expressar quão bem funciona em calculando a razão Uma pequena taxa de compressão é boa. Por exemplo, se for que significa que podemos em cadeias médias compressa em de 50% usando .C S C S
Se tentarmos comprimir todas as cadeias de comprimento no máximo , teremos problemas:n
Portanto, o melhor esquema de compactação do mundo é a função de identidade! Bem, somente se queremos compactar seqüências aleatórias de bits. As cadeias de bits que ocorrem na prática estão longe de serem aleatórias e exibem muita regularidade. É por isso que faz sentido compactar dados, apesar do teorema acima.
fonte
Apenas uma nota adicional à boa resposta de Andrej:
Você também pode dar uma olhada na complexidade de Kolmogorov :
Definição : Dada uma string , sua complexidade Kolmogorov relação a um modelo fixo de computação é o comprimento do programa de curto-circuito (por exemplo, máquina de Turing) que gera .s C(s) s
Informalmente, mede seu conteúdo de informação ou seu grau de redundância ; uma string é incompressível seC(s) s C(s)≥|s|
Dois teoremas fundamentais são:
1) independentemente do modelo de computação, existe uma constante tal que, para cada string : (informalmente, dada uma string você pode codificá-la em um programa que simplesmente a gera sem nenhum processamento ou compactação)c s C(s)≤|s|+c s
2) para todo existe uma string de comprimento incompressível:(análogo ao teorema descrito na resposta de Andrej).n s n C(s)≥|s|
A prova é simples: existem cadeias binárias de comprimento , mas menos descrições (programas) de comprimento :2n n <n
fonte
Seu contra-exemplo está errado.
Sua lista de valores compactados possui algumas informações ocultas que, na verdade, tornam o comprimento médio maior que 3 bits. A informação extra é o comprimento da sequência de saída.
Com nossos olhos, podemos ver na sua tabela que a primeira string de saída tem apenas 1 bit de comprimento e as outras têm 3 bits, mas você está trapaceando se não codificar explicitamente esse fato. Vamos codificar isso acrescentando mais um bit; 0 significa "comprimento = 1" e 1 significa "comprimento = 3".
Então sua mesa se torna realmente:
... com média de 3,75 bits.
EDITAR
Aqui está uma reflexão tardia, que ilustra o mesmo ponto. É uma boa pergunta:
O código Morse é composto apenas de pontos e traços. Vamos chamar o ponto 0 e o traço 1. Todas as letras maiúsculas são codificadas com no máximo quatro bits.
Existem 26 letras maiúsculas. Mas quatro bits devem ser capazes de codificar apenas 16 valores distintos. O que está acontecendo?
fonte
Contando o caso trivial de comprimento zero, existem cadeias de bits cujo comprimento é no máximo n (se se sabe que comprimentos são múltiplos exatos de oito, o número é menor, mas mais difícil de calcular). Assim, todas as cadeias de comprimento ou menos podem ser representadas usando cadeias de comprimento fixo . Se muitas seqüências de caracteres forem muito mais curtas que o comprimento máximo, no entanto, pode ser útil usar esquemas de codificação alternativos que adicionem mais de um ao comprimento das seqüências máximas, mas menos ao comprimento das seqüências mais curtas. Conseqüentemente, a quantidade de informações transmitidas pelo conhecimento do tamanho exato de uma string depende de quanto tempo alguém assumiria que a string poderia ter e de quão disposto alguém estaria em preencher cordas mais curtas.2n+1−1 n n+1
Como esses fatores dependem muito da aplicação, é útil assumir um modelo de computação no qual as cadeias de entrada devem conter informações que seriam suficientes para permitir que o leitor saiba onde elas terminam (mesmo se elas forem preenchidas com quantidades arbitrárias de dados arbitrários) e seqüências de saída são necessárias para fazer o mesmo. Esse modelo de computação permitirá que qualquer operação que funcione em registros de dados individuais funcione também em qualquer sequência concatenada de registros de dados [presume-se que um código que saiba quando parar de ler registros inteiros não compactados saiba exatamente quando parar lendo todo comprimido].
fonte