Você está na página 1de 5

Teoria da Informação e Códigos

Irineu Antunes Júnior Mar. 2021

I.4 - Codificação Ótima de Fonte


Estude este capítulo da apostila e complete após as marcas de completar com texto b e de completar com
código b.
I.4.1 Introdução
Um código binário é emitido continuamente por uma fonte
Figura 1 - Fonte binária e decodificador de mensagens.

Considere o problema de decodificar o fluxo de dígitos para recuperar a mensagem.


Se tivéssemos apenas 1 tipo de mensagem, a decodificação seria certa e unívoca já que, neste caso, 0 ou 1
representariam a mesma mensagem.
Embora seja um caso trivial, cabe notar que esta codificação alcança máxima eficiência pois o comprimento
médio do código é igual à entropia da fonte, Lm = H = 1.
Continuando, se houver 2 tipos de mensagem, a codificação também será ótima.
Já com 3 tipos de mensagem, a representação com dígitos binários exige mais dígitos havendo vários códigos
possíveis conforme discutido a seguir.
Exemplo 1
Seja o código {1,01,001}. Este código é chamado de código de vírgula, em inglês, comma code.
Vamos decodificar o fluxo de bits:
00101101111000 ...
|
início
Há que se supor um sincronismo que estabeleça o início do fluxo, então, começamos a partir da esquerda com
dígito 0 seguido de outro dígito 0 e terminamos com dígito 1 que é usado como pontuação (vírgula).
Bem, necessitamos ainda um livro de código. Sejam
001 = mensagem C
01 = mensagem A
1 = mensagem D
Note que a mensagem, em si, é algo arbitrário e que não tem relação com o desempenho do sistema.
Já o código deve possibilitar decodificação unívoca, instantânea e com máxima eficiência.
O código aqui exemplificado é unívoco e instantâneo.
A prova é feita observando-se que se trata do que chamamos de código de árvore binária.
De fato, temos a representação na forma de árvore

1
Numa árvore, a codificação é feita partindo-se de folhas selecionadas (códigos válidos) e seguindo pelos ramos
até a raíz, sendo o código dado pelo caminho percorrido.
Já a decodificação é feita de forma inversa, partindo-se da raíz, lendo-se o código ao longo do percurso até uma
dada folha.
Como os caminhos são únicos, o código é unívoco.
E, como, ao chegar no destino (raíz ou folha), imediatamente tem-se o resultado, de certo, o código é instantâneo.
Na literatura, bons códigos de árvore binária são chamados de códigos de prefixo, sendo assim chamados pois
nenhuma palavra de código é prefixo de outra.
E como construir um código de prefixo que seja ótimo para uma dada DMS com probabilidades conhecidas?
Para responder, consideramos o caso de codificação de três mensagens do exemplo anterior.
Exemplo 2
Seja uma fonte ternária com probabilidades conhecidas.
Figura 2 - Obtenção do código de Huffman

A árvore completa da Figura 2a conta com várias podas de ramos possíveis com 3 folhas mas, de início, não
sabemos quais escolher ou, tão pouco, quais seriam ótimas para a fonte dada.
Huffman partiu das folhas, inicialmente desconhecidas (Figura 2b), e mostrou como chegar num código ótimo.
Como nada sabemos sobre a codificação dessa fonte, ordenamos as probabilidades e agrupamos as duas
mensagens menos frequentes. Com isto acabamos reduzindo o problema a uma fonte binária (Figura 2c).
Em seguida, desagrupamos os códigos com prefixo 1 e chegamos na árvore da Figura 2d cujo código é [0 10 11]
e que tem a palavra 0 atribuída à mensagem mais frequente.
O algoritmo de Huffman garante que o código obtido é de prefixo e que, ainda, alcança máxima eficiência.
De fato, na Figura 2, em (c) temos um código sabidamente ótimo com comprimento médio
L2 = 1p + 1q
que é igual a 1.
Antes disso, em (b), o comprimento médio era
L3 = 1p + 2r + 2s = 1p + 2(r + s) = 1p + 2q = L2 + 1q
Bem, se L2 é mínimo, então L3 também deve ser mínimo porque o termo 1q é constante.
Na apostila do curso, encontra-se detalhado o algoritmo para além de fontes ternárias.
E, por indução, demonstra-se que o código de Huffman é ótimo em todos os casos.
A seguir, apresentamos uma implementação computacional do algoritmo.
Exemplo 3
Seja uma fonte quaternária com probabilidades dadas.
O código a seguir mostra os passos do algoritmo de Huffman para 4 mensagens.
# Dados de entrada:
M={ '1' '2' '3' '4' }; # mensagens
P=[ .4 .3 .2 .1 ]; # probabilidades
sumP=sum(P) # verifica validade

2
# ESaída:
sumP = 1.00000

# a) Início:
P4=P # probabilidades
M4=M
# ESaída:
P4 =
0.40000 0.30000 0.20000 0.10000

M4 =
1 2 3 4

# b) Ordenação: (4 mensagens)
[P,ind]=sort(P)
# mensagem ordenada:
M4o=M4(ind)
# ESaída:
P =
0.10000 0.20000 0.30000 0.40000

ind =
4 3 2 1

M4o =
4 3 2 1

# c) Redução: (4 -> 3)
M3=M4o(2:end); # Copia
M3(1)={[M4o{1} M4o{2}]}
# ESaída:
P=[ P(1)+P(2) P(3:end) ] # Soma prob. 1 e 2
M3 =
43 2 1
P =
0.30000 0.30000 0.40000

# d) Ordenação: (3)
[P,ind]=sort(P)
M3o=M3(ind)
# ESaída:
P =
0.30000 0.30000 0.40000

ind =
2 1 3

M3o =
2 43 1

# e) Redução: (3 -> 2)
M2=M3o(2:end); # Copia
M2(1)={[M3o{1} M3o{2}]}
P=[ P(1)+P(2) P(3:end) ] # Soma prob. 1 e 2
# ESaída:
M2 =
243 1
P =
0.60000 0.40000

3
# f) Ordenação: (2)
[P,ind]=sort(P)
M2o=M2(ind)
# ESaída:
P =
0.40000 0.60000

ind =
2 1

M3o =
1 243

# g) Codificação: (2)
C2={}; # início da codificação
C2{1}='0'; # prefixo '0' para agrupamento 1
C2{2}='1'; # prefixo '1' para agrupamento 2
# Exibe M e C
disp('b
# ESaída:

M2 =
243 1
C2 =
0 1

# h) Codificação: (3)
C3={}; im=1; suf='0'
for m=M3 # mensagem
ig=1;
for g=M2 # grupo
if ! isempty(strfind(g{1},m{1})) # se grupo contém mensagem
if ! isempty(strfind(M2{1},m{1})) # se veio de desagrupamento
C3{im}=[C2{ig} suf]; # acrescenta prefixo e sufixo
suf='1';
else
C3{im}=[C2{ig}]; # senão, só acrescenta prefixo
endif
endif
ig=ig+1; # indice de grupo
endfor
im=im+1; # indice de mensagem
endfor
# Exibe M e C
disp('b
# ESaída:
suf = 0

M3 =
43 2 1
C3 =
00 01 1

# i) Codificação: (4)
C4={}; im=1; suf='0';
for m=M4 # mensagem
ig=1;
for g=M3 # grupo
if ! isempty(strfind(g{1},m{1})) # se grupo contém mensagem
if ! isempty(strfind(M3{1},m{1})) # se veio de desagrupamento

4
C4{im}=[C3{ig} suf]; # acrescenta prefixo e sufixo
suf='1';
else
C4{im}=[C3{ig}]; # senão, só acrescenta prefixo
endif
endif
ig=ig+1; # indice de grupo
endfor
im=im+1; # indice de mensagem
endfor
# Exibe M e C
disp('b
# ESaída:

M4 =
1 2 3 4
C4 =
1 01 000 001

# j) Fim

v Exercícios
1. Seja uma fonte ternária, DMS, com probabilidades 0.5, 0.25 e 0.25. Pede-se:
a) A entropia da fonte.
b) O comprimento médio do código de vírgula visto no Exemplo 1.
c) O código pré-vírgula {100,10,1} conta com mesma eficiência?
d) O código pré-virgula seria melhor? Teria alguma desvantagem na prática? É de prefixo? É de árvore
binária?
e) (opcional) G Faça os cálculos e análises para responder os itens anteriores usando ferramenta computa-
cional (Octave, Python etc.)
2. Seja o algoritmo de Huffman para 4 mensagens do Exemplo 3. Usando ferramenta computacional (Octave,
Python etc.) de sua preferência, pede-se:
a) Execute o algoritmo para uma DMS com probabilidades 0.4, 0.3, 0.2 e 0.1.
b) Verifique o resultado anterior manualmente.
c) O comprimento médio do código obtido nos itens anteriores. Compare-os.
d) Modifique o algoritmo para aceitar entrada com maior número de mensagens.
e) Repita a, b e c para uma DMS com probabilidades 0.45, 0.31, 0.14, 0.08 e 0.02. Use o seu algoritmo
modificado.
f) (opcional) G Aperfeiçoe o seu algoritmo para que sempre atribua sufixo 0 ao maior desagrupamento em
caso de empate de probabilidades. O algoritmo do Exemplo 3 garante isto?

Você também pode gostar