as tipologias adverbiais nas gramáticas normativas e na lingüística
emprego de gramáticas livres de contexto para a construção de um ...
Transcript of emprego de gramáticas livres de contexto para a construção de um ...
EMPREGO DE GRAMATICAS LIVRES DE CONTEXTO PARA
A CONSTRUCAO DE UM ALGORITMO CRIPTOGRAFICO
Joao Felipe Pontes Faria
Projeto de Graduacao apresentado ao Curso
de Engenharia Eletronica e de Computacao
da Escola Politecnica, Universidade Federal
do Rio de Janeiro, como parte dos requisitos
necessarios a obtencao do tıtulo de Enge-
nheiro.
Orientador: Flavio Luis de Mello
Rio de Janeiro
Abril de 2016
UNIVERSIDADE FEDERAL DO RIO DE JANEIRO
Escola Politecnica - Departamento de Eletronica e de Computacao
Centro de Tecnologia, bloco H, sala H-217, Cidade Universitaria
Rio de Janeiro - RJ CEP 21949-900
Este exemplar e de propriedade da Universidade Federal do Rio de Janeiro, que
podera incluı-lo em base de dados, armazenar em computador, microfilmar ou adotar
qualquer forma de arquivamento.
E permitida a mencao, reproducao parcial ou integral e a transmissao entre bibli-
otecas deste trabalho, sem modificacao de seu texto, em qualquer meio que esteja
ou venha a ser fixado, para pesquisa academica, comentarios e citacoes, desde que
sem finalidade comercial e que seja feita a referencia bibliografica completa.
Os conceitos expressos neste trabalho sao de responsabilidade do(s) autor(es).
iii
DEDICATORIA
A todos os gigantes, celebres ou anonimos, que humildemente oferecem seus om-
bros aos aprendizes.
iv
AGRADECIMENTO
Agradeco primeiramente ao povo brasileiro que contribuiu de forma significativa
a minha formacao e estada nesta Universidade. Este projeto e uma pequena forma
de retribuir o investimento e confianca em mim depositados.
Gostaria tambem de agradecer a Daniela, minha amada e minha musa, que me
apoiou e motivou na realizacao deste trabalho e na conclusao desta etapa academica;
meus pais Nelson e Andrea que tambem sempre estiveram ao meu lado e me apoiando
em minhas escolhas e conquistas; meus avos Rita e Ismael que sempre me incenti-
varam em todos os meus desafios; minha avo Nathalia que sempre me apoiou; meus
irmaos, todos os meus tios, primos e agregados, que sempre me proporcionaram
um ambiente familiar acolhedor, estimulante e incentivador, especialmente a Titita,
entre outros tantos que nao haveria espaco para citar um a um.
Meu muito obrigado ao professor Flavio Mello, que me apresentou este assunto
interessantıssimo e aceitou me orientar neste projeto, apesar do pouco tempo de que
eu dispunha para me dedicar a ele, e sempre me tratou com total atencao e respeito;
a todos os demais professores e orientadores (Case, Seixas, Mauros, Augusto, Jomar,
Henrik, Jose, Robert e muitos mais!), assim como os meus colegas, funcionarios e
amigos da UFRJ e da KTH, com quem estudei e trabalhei dentro ou fora de sala
de aula e que trouxeram, cada um, informacoes e experiencias fundamentais para a
minha formacao.
Sou grato tambem aos meus amigos, colegas e professores, do CAp-UFRJ que me
proporcionaram uma preparacao para os desafios academicos e de vida, especial-
mente ao Beto, cujos ensinamentos vao muito alem da Fısica.
v
RESUMO
Um algoritmo criptografico e construıdo empregando gramaticas livres de contexto
tal que a representacao criptografica dos dados seja uma gramatica que os representa.
Para dificultar o acesso indevido aos dados, trechos da gramatica codificada contendo
sımbolos terminais sao substituıdos por sımbolos fictıcios que nao fazem parte da
gramatica, e estes trechos substituıdos formam a chave criptografica do algoritmo.
Para descriptografar os dados, a chave e utilizada para reconstruir a gramatica que,
em seguida, e utilizada para gerar os dados originais.
Alem de criptografar os dados, o algoritmo proposto alcanca simultaneamente a
sua compressao, pois a abordagem utilizada em sua construcao e baseada no fato
de que gramaticas podem ser vistas como representacoes compactas dos dados que
elas geram, caracterıstica esta explorada por algoritmos de compressao de dados
tomados como ponto de partida neste estudo.
Uma avaliacao empırica mostra que, em media, a saıda do algoritmo criptografico
proposto e aprovada em 95 dentre 162 testes aplicados na bateria de testes es-
tatısticos para aplicacoes criptograficas do NIST.
Palavras-Chave: gramaticas livres de contexto, criptografia, teoria da informacao.
vi
ABSTRACT
A cryptographic algorithm is built employing context-free grammars such that
the cryptographic representation of the data is a grammar that represents it. To
make it hard to access the data without proper authorisation, segments of the coded
grammar containing terminal symbols are substituted by dummy symbols that are
not part of the grammar, and these substituted segments are used as the crypto-
graphic key of the algorithm. To decrypt the data, the key is used to reconstruct
the grammar so that it can be used to generate the original data.
Beyond encrypting the data, the proposed algorithm achieves simultaneously its
compression, as the approach used in its construction is based on the fact that gram-
mars can be seen as compact representations of the data it generates, a characteristic
exploited by compression algorithms used as a starting point for this study.
An empirical evaluation shows that, on average, the output of the proposed cryp-
tographic algorithm passes 95 out of 162 tests from NIST’s statistical test suite for
cryptography applications.
Key-words: context-free grammars, cryptography, information theory.
vii
SIGLAS
DAG - Direct acyclic graph
DSA - Digital Signature Algorithm
E/S - Entrada/saıda
FPGA - Field-programmable gate array
HEVC - High-Efficiency Video Coding
IED - Interactive Encoding and Decoding
LCA - Lowest common ancestor
LZ - Lempel-Ziv
LZMA - Lempel-Ziv-Markov chain algorithm
LZW - Lempel-Ziv-Welch
NIST - National Institute of Standards and Technology
NP - Non-deterministic polynomial
PPM - Prediction by partial matching
RGB - Red, green, and blue
RSA - Rivest-Shamir-Adleman
SLT - Static lookup table
STS - Statistical Test Suite
viii
XML - Extensible Markup Language
ix
Sumario
1 Introducao 1
1.1 Tema . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
1.2 Delimitacao . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
1.3 Justificativa . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.4 Objetivos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
1.5 Metodologia . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
1.6 Descricao . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
2 Gramaticas e Criptografia 6
2.1 Esteganografia . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
2.2 Autenticacao . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
3 Gramaticas e Compressao 11
3.1 Gramaticas admissıveis . . . . . . . . . . . . . . . . . . . . . . . . . . 13
3.2 Transformadas de gramatica . . . . . . . . . . . . . . . . . . . . . . . 16
3.2.1 Transformada gulosa . . . . . . . . . . . . . . . . . . . . . . . 23
3.2.2 Transformada condicional de casamento de padroes multinıvel 26
3.3 Trabalhos posteriores . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
3.3.1 Indiretamente ligados aos codigos baseados em gramaticas . . 30
3.3.2 Codigos baseados em gramaticas e suas aplicacoes diretas . . . 33
4 Um novo algoritmo criptografico 50
4.1 Sımbolo de partida . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50
4.2 Regras de Producao . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
4.3 Sımbolos terminais . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
4.4 Avaliacao empırica do algoritmo proposto . . . . . . . . . . . . . . . 55
x
5 Conclusoes 62
5.1 Consideracoes finais . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62
5.2 Trabalhos Futuros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64
Bibliografia 65
A Implementacao do algoritmo Crypto LCA 71
A.1 bits.c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72
A.2 bits.h . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76
A.3 cfg2enc.c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78
A.4 cfg2enc.h . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82
A.5 cfg2txt.c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84
A.6 enc2txt.c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86
A.7 enc2txt.h . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 90
A.8 lcacommon.h . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91
A.9 lcacomp.c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93
A.10 lcacrypt.c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95
A.11 txt2cfg online.c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98
A.12 txt2cfg online.h . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 107
xi
Lista de Figuras
4.1 Exemplo de arvore parcial de derivacao de uma gramatica . . . . . . 53
xii
Lista de Tabelas
4.1 Testes estatısticos nos arquivos originais do corpus Pizza&Chili . . . 59
4.2 Testes estatısticos nos arquivos comprimidos pelo Online LCA . . . . 60
4.3 Testes estatısticos nos arquivos criptografados pelo Crypto LCA . . . 60
4.4 Testes estatısticos nas chaves criptograficas geradas pelo Crypto LCA 61
xiii
Capıtulo 1
Introducao
1.1 Tema
A teoria da informacao e um campo do conhecimento interdisciplinar e de interesse
no ambito da engenharia eletronica, ciencia da computacao, telecomunicacoes, ma-
tematica aplicada, entre outros. Desde o inıcio da formalizacao das ideias centrais
deste campo de estudo com o trabalho seminal de Claude Shannon[1], os concei-
tos de quantidade de informacao, entropia e redundancia se mostraram poderosas
ferramentas no projeto e analise de todo tipo de sistema que tenha em seu cerne
a producao, transmissao ou consumo de dados (informacao), mesmo tomados em
sentido amplo.
Se pensarmos na modelagem de Shannon para os sistemas de comunicacao vere-
mos que partes fundamentais sao o transmissor e o receptor que, respectivamente,
codificam e decodificam a informacao em sinais transmitidos. A codificacao pode ser
projetada com (e analisada em relacao a) diversos objetivos e, enquanto Shannon
se debrucava sobre a transmissao eficiente da informacao por meio de sinais em um
canal, uma outra aplicacao da codificacao se encontra na area da criptografia. Nesta
ultima o foco nao e a eficiencia da transmissao mas sim a sua seguranca – busca-se
sinais que transmitam a informacao sem que terceiros possam compreende-la e nem
comprometer a sua integridade.
E interessante tambem notar que Shannon, no mesmo artigo, ao definir fontes de
informacao toma como exemplo a lıngua inglesa e mostra uma serie de aproximacoes
1
que a modelam[1, Parte 1, Secao 3], e pode-se fazer aqui a ponte a uma subarea da
teoria da informacao e da matematica –e tambem da linguıstica– que nos interessa:
o estudo das gramaticas livres de contexto. Gramaticas gerativas, entre as quais
as chamadas livres de contexto, passam a ser o foco de profundo estudo e amplas
aplicacoes a partir de outro trabalho seminal, este do linguista Noam Chomsky, que
busca modelar a estrutura da producao de sentencas na gramatica da lıngua inglesa
para gerar frases validas e ganhar um melhor entendimento sobre as gramaticas que
regem os idiomas[2].
Busca-se no presente trabalho investigar e experimentar o uso de gramaticas livres
de contexto na codificacao para criptografia.
1.2 Delimitacao
Na atualidade, comunicacoes e arquivos eletronicos sao extensivamente utilizados
em diversas aplicacoes que requerem seguranca e privacidade de dados, tais como
mensagens, aplicacoes bancarias e governamentais, entre outras, muitas das quais
implementadas em dispositivos moveis, sistemas embarcados e distribuıdos que tem
recursos restritos, e tambem em servidores de aplicacao centralizados que, apesar
de disporem de mais recursos, precisam responder a um alto numero de requisicoes
simultaneas.
Tais situacoes tornam imperativo o uso de algoritmos criptograficos simples e que
demandem poucos recursos computacionais e de memoria, e neste contexto se insere
a investigacao de algoritmos criptograficos obtidos a partir de codigos baseados em
gramaticas, originalmente desenvolvidos para compressao de dados e frequentemente
de implementados de maneira simples e com uso eficiente de recursos.
Adicionalmente, deseja-se que a saıda do algoritmo criptografico construıdo com
esta abordagem passe nos testes estatısticos para aplicacoes em criptografia do NIST
(National Institute of Standards and Technology).
2
1.3 Justificativa
A despeito da formalizacao do estudo das gramaticas livres de contexto no ambito
da teoria da informacao ter se iniciado nem uma decada apos a formalizacao desta
teoria, a area de codigos baseados em gramaticas e relativamente recente e foi for-
malizada do ponto de vista da compressao de dados por Yang e Kieffer praticamente
meio seculo depois[3].
As intencoes da compressao e da criptografia podem ser vistas, de certo modo,
como relacionadas. Algoritmos de compressao sem perdas buscam eliminar re-
dundancias e aproximar a taxa de bits da sequencia de saıda a taxa de entropia
da sequencia de entrada, ou seja, busca-se uma sequencia de saıda que se aproxime
de uma sequencia aleatoria do ponto de vista da teoria da informacao que conte-
nha toda a informacao da sequencia de entrada porem que seja mais curta que a
mesma –e este ponto fica absolutamente claro quando se observa que uma sequencia
aleatoria e incompressıvel por um algoritmo sem perdas. Algoritmos de criptogra-
fia, por sua vez, tambem buscam gerar uma sequencia de saıda que se aproxime de
uma sequencia aleatoria. O objetivo na criptografia nao e, contudo, representar a
informacao da sequencia de entrada com uma outra sequencia mais curta, mas sim
mascarar as correlacoes de modo a ocultar a informacao tal que somente da posse
de uma chave ou segredo alguem seja capaz de reconstruir a sequencia de entrada a
partir da sequencia de saıda.
Como se ve, uma das principais caracterısticas desejadas nas sequencias de saıda
tanto de algoritmos de compressao quanto de criptografia e a mesma, e daı pode-se
intuir que tecnicas de compressao podem ser adaptadas para o uso criptografico
e vice-versa. A ideia de se utilizar gramaticas livres de contexto no ambito da
criptografia ja foi levantada em aplicacoes de esteganografia[4, 5] e de producao de
tokens para autenticacao (numeros de cartao de credito descartaveis)[6].
As aplicacoes em esteganografia sao mais simples e diretas, e consistem na geracao
de textos gramaticais em que bits ou sequencias sao associados a cada uma das pos-
sibilidades distintas de escolha de palavras ou sintagmas terminais na geracao do
texto de modo que um subconjunto da linguagem gerada pela gramatica codifica
3
inequivocamente a sequencia de entrada em um texto gramaticalmente correto que
nao levante suspeitas. Ja na producao de numeros de cartao de credito descartaveis
(isto e, tokens de autenticacao para transacoes on-line) baseada em gramaticas li-
vres de contexto as regras das gramaticas sao parte do segredo compartilhado pelo
emissor e pelo titular do cartao, enquanto os tokens trocados sao derivados das lin-
guagens da gramatica. Essa abordagem se apoia na dificuldade de se reconstruir
uma gramatica a partir de exemplos de sequencias da linguagem gerada por ela.
Nas duas abordagens exemplificadas as gramaticas sao mantidas secretas e o que
se envia sao partes das linguagens geradas, em contraste com a abordagem da com-
pressao sem perdas baseada em gramaticas em que se constroi uma gramatica cuja
linguagem unitaria e a sequencia de entrada e cuja taxa de bits se aproxima da taxa
de entropia da sequencia de entrada, se aproximando tambem de uma sequencia
aleatoria. Nao ha, tanto quanto e do nosso conhecimento, aplicacoes de criptografia
utilizando gramaticas livres de contexto com uma abordagem similar a adotada nos
codigos de compressao sem perdas baseados em gramaticas e, dadas as ja aponta-
das similaridades entre os objetivos da criptografia e da compressao, ha razoes para
crer que a investigacao do uso de tal abordagem em criptografia pode resultar em
tecnicas simples, inovadoras e seguras.
1.4 Objetivos
Os principais objetivos perseguidos no desenvolvimento deste trabalho sao (i)
identificar de um algoritmo de compressao implementando um codigo baseado em
gramaticas que seja um bom candidato a ser utilizado como base para a obtencao de
um algoritmo criptografico simples e eficiente; (ii) propor e desenvolver um algoritmo
criptografico baseado em gramaticas a partir de modificacoes no algoritmo de com-
pressao candidato; (iii) avaliar o algoritmo proposto tanto do ponto de vista pratico
quanto teorico; e (iv) identificar direcoes promissoras para investigacoes futuras.
4
1.5 Metodologia
A presente investigacao se fundamenta em uma revisao bibliografica do uso de
gramaticas livres de contexto em criptografia, uma revisao bibliografica da producao
cientıfica sobre o uso de gramaticas livres de contexto na compressao de dados,
sistematica, partindo do trabalho seminal de Yang e Kieffer que formaliza o campo
de estudo dos codigos de compressao sem perdas baseados em gramaticas livres
de contexto[3], para a partir daı cumprir os objetivos elencados acima por meio
da formulacao de um algoritmo criptografico baseado em um codigo baseado em
gramaticas que represente o estado da arte e atenda aos requisitos de simplicidade
e uso eficiente de recursos, sua avaliacao teorica basica, implementacao e avaliacao
experimental de sua performance.
1.6 Descricao
No capıtulo 2 sera apresentada uma breve revisao bibliografica das abordagens
existentes com o emprego de gramaticas livres de contexto em criptografia e areas
correlatas.
O capıtulo 3 apresenta a classe dos codigos de compressao baseados em gramaticas
livres de contexto e uma revisao detalhada da bibliografia sobre o assunto a partir
dos artigos de Yang e Kieffer.
A construcao de um novo algoritmo criptografico baseado em gramaticas e apre-
sentada no capıtulo 4. Nele serao mostradas diferentes possibilidades avaliadas para
esta construcao e suas respectivas vantagens e desvantagens, assim como a aborda-
gem final adotada, suas caracterısticas basicas, sua implementacao e uma avaliacao
empırica apoiada em testes estatısticos.
As conclusoes e sugestoes para trabalhos futuros se encontram no capıtulo 5.
5
Capıtulo 2
Gramaticas e Criptografia
Para contextualizar a investigacao ora conduzida, apresentamos aqui um resumo
sobre as aplicacoes ja existentes de gramaticas livres de contexto na criptografia. A
bibliografia cientıfica sobre o assunto e limitada, indicando que este nao e um campo
que tem recebido muita atencao da comunidade de pesquisadores, mas ha literatura
com aplicacoes em autenticacao, esteganografia e em criptografia.
Todas as abordagens encontradas sao baseadas no fato de que e facil verificar se
um texto e gerado por uma gramatica quando da posse da ambos, mas difıcil obter
a gramatica da posse somente do texto[4, 6, 7, 8]; a consequencia disto e que a
chave do codigo e a propria gramatica, que deve ser conhecida por todas as partes
(mas nao por terceiros) e cuja linguagem forma o sinal transmitido, enquanto a
abordagem investigada neste trabalho e oposta e busca utilizar partes da propria
gramatica como sinal.
2.1 Esteganografia
A esteganografia e um campo correlato a criptografia mas com objetivos ligei-
ramente distintos; a ideia nao e somente evitar que terceiros possam compreender
a informacao enviada caso a mensagem seja interceptada mas buscam disfarcar a
mensagem, isto e, esconder o proprio fato de que alguma informacao sigilosa esteja
sendo enviada.
6
Ha muitas mencoes de usos bastante similares de gramaticas em esteganografia,
simples e diretas, e uma descricao bastante completa de tecnicas de esteganografia
pode ser encontrada no livro de Peter Wayner, “Disappearing Cryptography”[4],
que inclui um capıtulo dedicado a esteganografia com gramaticas livres de contexto.
A ideia basica consiste na formulacao de gramaticas livres de contexto nao de-
terminısticas com regras de producao cuidadosamente montadas de forma a possi-
bilitar a geracao de textos estruturados que codificam uma mensagem na selecao
das regras de producao aplicadas aos sımbolos nao-terminais. Assim, diferentes re-
gras de producao para um mesmo nao-terminal sao associadas a diferentes valores
(numeros, sequencias binarias, letras, palavras, etc) e o decodificador, conhecendo
a gramatica e os valores associados a cada regra de producao, pode analisar o texto
recebido e identificar as regras utilizadas e, por conseguinte, os valores codificados
que formam a mensagem oculta. Nao ha, contudo, um corpo significativo de resul-
tados teoricos em relacao a como de fato projetar codigos esteganograficos fortes
utilizando gramaticas livres de contexto[4].
Para exemplificar estas operacoes, considere a gramatica livre de contexto (porem
nao-determinıstica) abaixo, em que cada regra de producao e associada a uma
sequencia binaria, mostrada entre parenteses ao lado da respectiva regra:
S → αβγ
α → o flamengo (00)
α → o fluminense (01)
α → o botafogo (10)
α → o vasco (11)
β → ganhou (0)
β → perdeu (1)
γ → aquele jogo (0)
γ → aquela partida (1)
Esta gramatica pode ser utilizada para transmitir de maneira oculta a sequencia
0011 em uma mensagem aparentemente inocua: ”o flamengo perdeu aquela partida”.
7
Em abordagens hıbridas, a mensagem ocultada pode ser ja criptografada ou,
ainda, o texto pode codificar nao a mensagem diretamente, mas uma chave para
a obtencao da mensagem oculta por outra tecnica esteganografica, por exemplo en-
derecando uma sequencia de pixels de uma imagem em cujos bits menos significativos
se esconde a verdadeira mensagem[5].
A mesma gramatica do exemplo anterior poderia ser utilizada para exemplificar
(muito simplificadamente) como uma abordagem hıbrida poderia ser utilizada. Su-
ponha que quatro pixels de uma imagem RGB de quatro por quatro, com um byte
codificando cada componente de cor de cada pixel, sejam escolhidos para esconder
a sequencia 100111110100 no bit menos significativo de cada um dos componentes
dos pixels isto e, suponha que o primeiro pixel escolhido seja denotado pela tripla
RGB(0xFF, 0x45, 0x45), para esconder os tres primeiros bits da sequencia secreta
(100) podemos modificar a cor do pixel para RGB(0xFF, 0x44, 0x44). Como a
sequencia estara escondida em quatro pixels arbitrarios, podemos especificar quais os
pixels codificando de alguma maneira a sequencia em frases geradas pela gramatica.
Como neste exemplo usaremos a mesma gramatica do exemplo acima, podemos
simplesmente utilizar a sequencia binaria de uma frase, que tem quatro bits, para
especificar enumerativamente qual o pixel da imagem a ser utilizado, lendo os pixels
de cima para baixo e da esquerda para a direita. A sequencia de pixels indicada na
matriz abaixo poderia ser especificada, entao, pela sequencia de frases a sua direita:
3
1
4 2
o fluminense ganhou aquela partida (= 0b0101 = 5)
o vasco ganhou aquele jogo (= 0b1100 = 12)
o flamengo perdeu aquele jogo (= 0b0010 = 2)
o botafogo perdeu aquela partida (= 0b1011 = 11)
Wayner[4] observa ainda que do mesmo modo que os textos podem ser construıdos
como imitacoes de linguagens naturais, a mesma abordagem pode ser utilizada para
gerar sequencias binarias arbitrarias tendo como resultado entao um codigo crip-
tografico e nao mais esteganografia.
Um codigo deste tipo poderia ser construıdo, por exemplo, com uma gramatica
que tenha 256 regras de producao distintas para cada nao-terminal (sendo utilizado o
8
valor do proximo byte lido da entrada para decidir qual regra aplicar) cujos membros
direitos contenham cada um apenas um dos 256 terminais da gramatica (todos os
bytes possıveis) seguidos por zero ou mais nao-terminais, em combinacoes diferentes
para cada regra. A producao de frases se daria enquanto houvesse bytes a serem
codificados, e a producao da ultima frase pode ser interrompida quando atingido o
final da entrada. A decodificacao se daria pela identificacao, a cada byte lido dos
dados criptografados, de qual regra de producao foi utilizada e, por conseguinte, qual
o byte correspondente dos dados originais. Por exemplo, uma sequencia codificada
0x00FF... pode ser decodificada com o auxılio da gramatica abaixo para obter a
sequencia original 0x3037....
S → 0x00βγθ (0x30) β → 0x00θωγ (0xFE)
S → 0x01αω (0x4D) β → 0x01 (0x12)
... ... ...
S → 0xFF (0x02) β → 0xFFωαθγφ (0x37)
2.2 Autenticacao
Singh e dos Santos[6] desenvolveram um sistema de autenticacao para a auto-
rizacao de transacoes de cartao de credito atraves do uso de numeros de cartao de
credito descartaveis, isto e, tokens ou codigos de autenticacao de uso unico.
No esquema proposto, o titular do cartao de credito e a instituicao financeira
emissora do cartao compartilham um conjunto de gramaticas que o titular utiliza
para gerar novos numeros a cada transacao e o emissor utiliza para validar tais
numeros na autorizacao de transacoes. Um protocolo e seguido para definir qual a
ordem de utilizacao das gramaticas de modo que gramaticas distintas sejam utiliza-
das em sucessivas transacoes, o comprimento dos codigos e o historico dos codigos
ja autenticados para que um numero nao possa ser reutilizado para autenticar uma
segunda transacao fraudulenta[6].
A tecnica apresentada e de implementacao relativamente simples e nao requer
muitos recursos computacionais, e ao mesmo tempo que e segura, e e uma aborda-
gem similar a frequentemente utilizada em autenticacao de dois fatores com tokens
9
mas com a ideia original de aplicar gramaticas livres de contexto na producao dos
tokens. A principal motivacao apresentada por Singh e dos Santos[6] para a esco-
lha do uso de gramaticas livres de contexto ao inves de algoritmos criptograficos
usuais tais como RSA ou DSA e o fato de que a seguranca destes algoritmos de-
pende da dificuldade de fatoracao de grandes numeros, porem o avanco do poder
computacional significa que chaves de comprimentos considerados seguros tornam-se
em poucas decadas totalmente vulneraveis, e ha entao a necessidade de se atuali-
zar os algoritmos para que utilizem chaves cada vez maiores ao longo do tempo;
computar uma gramatica a partir de exemplos de sua linguagem, por sua vez, e
um problema computacionalmente intratavel e, portanto, a seguranca de algoritmos
baseados nesta caracterıstica estariam imunes aos avancos do poder computacional
ao longo do tempo.
Esquemas alternativos sao avaliados por Singh e dos Santos[6], porem eles apon-
tam que estes esquemas introduzem complexidade na operacao, requerendo por
exemplo autenticacao em tempo real diretamente entre o emissor e o titular e o
envio do codigo de uso unico do primeiro para o segundo, ou somente diminuem
as chances o o potencial de dano do roubo de numero de cartao de credito, mas
nao os eliminando, ao gerar numeros temporarios com limites de valor de transacao,
numero de usos ou tempo de validade mais curto que o usual.
Outros autores apontaram, entretanto, a falta de resultados teoricos que garantam
a seguranca deste esquema, dado que computar uma gramatica a partir de exemplos
de sua linguagem e um problema intratavel no pior caso mas nao se sabe a dificul-
dade de computacao no caso medio[9, 10] (e nem o esquema indica como construir
as gramaticas com a dificuldade desejavel[9, 11]) e que tambem nao se sabe o quao
difıcil e gerar novas frases validas a partir de exemplos da linguagem[9, 11, 12].
Estas questoes estao em linha com as colocadas por Wayner[4] acerca do uso de
gramaticas em esteganografia, ja comentados na secao anterior.
Trabalhos posteriores de Singh e dos Santos[12] trataram de uma destas crıticas
apresentando um algoritmo para a obtencao de gramaticas difıceis de se computar
a partir de exemplos, porem a avaliacao apresentada foi empırica.
10
Capıtulo 3
Gramaticas e Compressao
John C. Kieffer e En-hui Yang investigaram em uma serie de papers a classe de
codigos de compressao sem perdas batizada codigos baseados em gramaticas (no
original, grammar-based codes) e que “em resposta a qualquer sequencia x de dados
de entrada sobre um alfabeto, seleciona uma gramatica livre de contexto Gx que
represente x no sentido de que x e a unica sequencia que pertence a linguagem
gerada por Gx”[3]1.
O objetivo dos autores e desenvolver novos algoritmos de compressao de dados sem
perdas baseados em gramaticas que sejam eficientes, praticos e universais. Algorit-
mos de compressao existentes e largamente utilizados sao baseados ou em codificacao
aritmetica (tambem conhecidos como metodos estatısticos ou de aproximacao de en-
tropia) ou no algoritmo Lempel-Ziv (metodos baseados em dicionarios ou de reducao
de redundancia). A codificacao aritmetica utiliza modelos estatısticos para codifi-
car cada sımbolo com uma probabilidade condicional, enquanto no Lempel-Ziv a
sequencia de entrada e analisada e dividida em subsequencias utilizando casamento
de padroes, e as sequencias sao codificadas com suas posicoes em um dicionario[13].
Ate entao, algoritmos que nao se baseiam em nenhuma das duas tecnicas obtinham
taxas de compressao inferiores, nao tinham implementacao pratica, ou ambos[13],
mas os autores argumentam que a representacao de uma sequencia de dados por
1Traducao livre do original “in response to any input data x over a fixed alphabet, selects a
context-free grammar Gx representing x in the sense that x is the unique string belonging to the
language generated by Gx”
11
uma gramatica que a gera pode ser eficientemente utilizada para a compressao de
dados pois as regras de producao de tal gramatica podem ser vistas como uma
representacao compacta da sequencia que, em seguida, pode ser indiretamente com-
primida ao se aplicar tecnicas reconhecidas de codificacao aritmetica para comprimir
as regras de producao da gramatica[3]. Indo alem, construir uma gramatica a par-
tir de uma sequencia pode ser visto como um modo de analisar os dados e obter
subsequencias, tal qual o objetivo dos algoritmos Lempel-Ziv, e isto sugere que
codigos baseados em gramaticas podem ser uma combinacao elegante e eficiente de
casamento de padroes e codificacao aritmetica[13].
A principal proposicao do artigo seminal de Kieffer e Yang sobre o assunto de
codigos baseados em gramaticas[3] e que tais codigos (sujeitos a pequenas restricoes)
sao compressores sem perdas e universais que obtem boas taxas de compressao, al-
cancando resultados melhores que o algoritmo Lempel-Ziv para algumas sequencias
de dados se os codigos forem bem projetados. A estrutura geral de um codigo
baseado em gramatica consiste de duas partes, uma transformada de gramatica e
um codificador de gramatica. A transformada de gramatica recebe como entrada a
sequencia de dados x que se deseja comprimir e constroi uma gramatica livre de
contexto Gx que represente x (no sentido explicitado na citacao acima). O codifica-
dor de gramatica entao comprime as regras de producao de Gx em uma sequencia
binaria B(Gx). Para obter x, e necessario primeiro utilizar um decodificador que
reconstrua Gx a partir de B(Gx) para entao seguir aplicando as regras de producao
de Gx para, ao final, obter x.
Nas secoes que seguem serao apresentadas e discutidas as principais definicoes
e teoremas introduzidos por Kieffer, Yang e co-autores em tres de seus principais
artigos sobre os codigos baseados em gramaticas[3, 13, 14] em relacao a gramaticas
admissıveis, propriedades desejaveis de transformadas de gramaticas, analise de en-
tropia e metodos para a codificacao binaria nos codificadores de gramatica, assim
como algoritmos praticos para a implementacao dos codigos.
Serao tambem apresentados e discutidos, em seguida, alguns artigos e trabalhos
de diversos autores em uma revisao bibliografica sobre o desenvolvimento recente e
12
relevante dos codigos baseados em gramatica apos a sua definicao por Yang e Kief-
fer. Os trabalhos foram selecionados para a revisao seguindo os seguintes criterios:
trabalhos contendo citacoes a todos os tres artigos de Yang e Kieffer mencionados;
ou contendo citacoes a ao menos um dos artigos e tendo sido publicado nos ultimos
cinco anos (isto e, de 2011 a 2015 inclusive).
3.1 Gramaticas admissıveis
Gramaticas admissıveis sao a subclasse das gramaticas livres de contexto para as
quais se pode garantir que L(G) = x para alguma sequencia x, e a apresentacao
das mesmas neste trabalho segue a feita por Yang e Kieffer[3], que introduziram
notacoes uteis e definicoes e teoremas importantes que mostram que as propriedades
das gramaticas admissıveis sao consistentes e que nos dao ferramentas matematicas
para a utilizacao das gramaticas nos codigos de compressao.
Uma gramatica livre de contexto pode ser colocada na forma de uma quadrupla
G = (N, T,R, S) onde N e o conjunto de sımbolos nao-terminais ou variaveis da
gramatica, T e o conjunto de sımbolos terminais (disjunto de N), R e o conjunto de
regras de producao (como definidas acima) cujos membros esquerdos sao elementos
em N e cujos membros direitos sao elementos em (N ∪ T )∗, e cada variavel aparece
ao menos uma vez entre os membros esquerdos das regras em R e, finalmente, S
e uma variavel especial denominada sımbolo de partida. As regras de producao de
uma gramatica podem ser expressas na forma A → α, onde A ∈ Σ e α ∈ Σ∗ para
algum conjunto finito Σ.
Para definir a linguagem L(G) gerada por G, a seguinte notacao e utilizada:
αG→ β significando que uma regra de producao pode ser utilizada para substituir
uma variavel na sequencia α para obter a sequencia β, e de modo similar αG⇒ β
se uma sequencia de substituicoes utilizando regras de producao pode ser aplicada
para obter β a partir de α. Pode-se definir entao L(G) = u ∈ T ∗ : SG⇒ u.
Uma gramatica admissıvel pode ser, entao, definida como uma gramatica livre de
contexto G possui mais algumas propriedades:
13
1. G e determinıstica, isto e. para cada variavel ha exatamente uma regra de
producao em que ela e o membro esquerdo;
2. Nenhuma regra de producao tem o membro direito vazio;
3. L(G) nao e vazia; e
4. G nao contem sımbolos inuteis.
Nota-se que se uma gramatica e determinıstica entao sua linguagem e vazia ou
contem uma unica sequencia, portanto e claro que as propriedades 1 e 3 acima sao
suficientes para garantir que para cada gramatica admissıvel ha uma unica sequencia
x tal que L(G) = x, como desejado, e pode-se dizer que essa sequencia e represen-
tada por G. Adicionalmente, por conta destas propriedades exigidas das gramaticas
admissıveis, ve-se que somente a lista de regras de producao e suficiente para espe-
cificar completa e univocamente uma gramatica admissıvel G, pois N(G), T (G) e S
podem ser facilmente inferidas pela simples observacao de R(G).
Apresentamos ainda duas ultimas definicoes antes dos primeiros teoremas. Uma
e a de um endomorfismo fG sobre (N(G)∪T (G))∗, onde G e uma gramatica livre de
contexto determinıstica que nao contem nenhuma regra de producao com o membro
direito vazio (o que, como veremos, significa que ela e admissıvel), tal que fG(a) =
a, a ∈ T (G) e se A → α ∈ R(G) entao fG(A) = α. Essa definicao e, basicamente,
uma ferramenta pratica para denotar a aplicacao das regras de producao de uma
gramatica admissıvel e trabalhar matematicamente as suas propriedades. A outra
definicao e um mapeamento f∞G de (N(G)∪T (G))∗ em si mesmo, mapeando qualquer
sequencia u no domınio ao ponto fixo do L-sistema (ou sistema de Lindenmayer)
(N(G) ∪ T (G), fG, u).
Agora, apresentamos os teoremas como introduzidos em [3]:
Teorema 1. [3, Teo. 1] Seja G uma gramatica admissıvel. Entao a sequencia de
dados x representada por G pode ser caracterizada como o ponto fixo do L-systema
(N(G) ∪ T (G), fG, S).
14
Teorema 2. [3, Teo. 2] Seja G livre de contexto determinıstica tal que a sequencia
vazia nao seja o membro direito de nenhuma regra de producao de G. Entao as tres
afirmacoes a seguir sao equivalentes:
1. G e admissıvel;
2. O grafo de derivacao de G e acıclico e tem sua raiz no vertice S;
3. f|V (G)|G (S) ∈ T (G)+ e cada sımbolo em N(G) ∪ T (G) e uma entrada de ao
menos uma das sequencias f iG(S), i = 0, 1, . . . , |N(G)|.
Teorema 3. [3, Teo. 3] Seja G uma gramatica admissıvel. Entao a sequencia de
dados x representada por G e computada pelo calculo x = f|N(G)|G (S).
Teorema 4. [3, Teo. 4] Seja G uma gramatica admissıvel livre de contexto. Seja u
qualquer sequencia em (N(G) ∪ T (G))+. Entao o L-systema (N(G) ∪ T (G), fG, u)
tem um ponto fixo u∗, e u∗ ∈ T (G)+. O ponto fixo u∗ e computavel pela formula
u∗ = f|N(G)|G (u).
Teorema 5. [3, Teo. 5] Seja G uma gramatica admissıvel. Entao
1. f∞G e um endomorfismo em (N(G) ∪ T (G))∗;
2. f∞G (u) ∈ T (G)+ para cada u ∈ (N(G) ∪ T (G))+;
3. Para cada u ∈ (N(G) ∪ T (G))+, f∞G (u) = f
|N(G)|G (u);
4. Se A → α e uma regra de producao de G, entao f∞G (A) = f∞
G (α).
Estes teoremas garantem que qualquer gramatica livre de contexto determinıstica
tal que a sequencia vazia nao seja o membro direito de nenhuma de suas regras
de producao tera todas as propriedades das gramaticas admissıveis e provem um
arcabouco matematico para a analise da aplicacao das regras de producao atraves
do endomorfismo definido acima, que e uma representacao de operacoes de subs-
tituicao paralelas e que alcanca uma sequencia terminal em no maximo |N(G)|
iteracoes. Pode-se notar, por exemplo, que a terceira afirmacao do Teorema 2 equi-
vale a propriedade das gramaticas admissıveis de nao terem sımbolos inuteis; o
Teorema 3 segue diretamente do Teorema 2 e prove um algoritmo direto para com-
putar a sequencia de dados atraves de substituicoes paralelas, assim como um limite
15
superior para o numero de iteracoes necessarias para obter a sequencia representada
por uma gramatica admissıvel; Os teoremas 1, 4 e 3 tambem sao estreitamente re-
lacionados; e, finalmente, o Teorema 5 segue dos anteriores e introduz uma notacao
util.
O limite superior para o numero de iteracoes de substituicoes de sequencias ne-
cessarias para obter a sequencia representada a partir do sımbolo de partida (e simi-
larmente para o ponto fixo u∗ do sistema (N(G)∪ T (G), fG, u)) pode ser facilmente
deduzido se considerarmos que gramaticas admissıveis nao tem sımbolos inuteis e
que representam uma e somente uma sequencia composta somente por sımbolos
terminais. Qualquer sımbolo que nao o sımbolo de partida claramente deve estar
em um caminho que se inicia no sımbolo de partida, pois nao pode ser inutil, e
portanto o grafo tem sua raiz no sımbolo de partida. Como a sequencia produzida
contem apenas sımbolos terminais, ela e obrigatoriamente a sequencia representada
pela gramatica e mais nenhuma substituicao e possıvel e nao podem haver, entao,
ciclos no grafo de derivacao, caso contrario variaveis do ciclo iriam aparecer infi-
nitas vezes na sequencia produzida e haveriam infinitas iteracoes de substituicoes.
Sendo o grafo acıclico e com a raiz no sımbolo de partida, qualquer caminho entre o
sımbolo de partida e um sımbolo terminal pode passar por cada variavel no maximo
uma unica vez, e consequentemente o numero maximo de iteracoes necessarias para
produzir a sequencia terminal e o numero de variaveis da gramatica.
3.2 Transformadas de gramatica
Yang e Kieffer definem transformadas de gramatica mapeamentos um a um de
sequencias de dados a gramaticas (que representam as respectivas sequencias) e
focam em duas classes de transformadas, as assintoticamente compactas e as irre-
dutıveis. O conjunto G (Σ) e definido como o conjunto de todas as gramaticas G em
que i. G e admissıvel; ii. T (G) ⊂ Σ; iii. A0 e o sımbolo de partida de G; iv. N(G) =
A0, A1, A2, . . . , A|N(G)−1|; e v. a ordem da primeira aparicao (da esquerda para
a direita) das variaveis na sequencia f 0G(A0)f
1G(A0)f
2G(A0) . . . f
|N(G)|−1G (A0) segue a
ordem dos subscritos. Utilizando esta definicao, uma transformada de gramatica
pode ser representada como um mapeamento de Σ+ em G(Σ) tal que para x ∈ Σ+
16
e Gx ∈ G(Σ), a transformada de gramatica que assinala a gramatica Gx a sequencia
x que ela representa e denotada por x → Gx.[3]
Uma transformada de gramatica e dita assintoticamente compacta se para cada
sequencia x do alfabeto Σ a gramatica correspondenteGx ∈ G*(Σ) e, adicionalmente,
limn→∞maxx∈Σn|Gx||x| = 0, onde G*(Σ) e o subconjunto de gramaticas G ∈ G(Σ)
para as quais f∞G (A) 6= f∞
G (B) para todo A,B ∈ N(G) | A 6= B; e |G| e definido
como o comprimento total de todos os membros direitos das regras de producao de
G[3]. E evidente o porque de tal propriedade ser desejada em codigos baseados em
gramaticas para compressao de dados.
Por outro lado, uma transformada de gramatica e definida irredutıvel se cada
gramatica Gx produzida por si e irredutıvel, isto e, e uma gramatica admissıvel
em que f∞G (v1) 6= f∞
G (v2)∀v1, v2 ∈ N(G) | v1 6= v2, todas as variaveis (exceto o
sımbolo de partida) aparecem ao menos duas vezes entre os membros direitos das
regras de producao e nao ha subsequencias (nao-sobrepostas) repetidas de compri-
mento 2 ou mais nos membros direitos das regras de producao[3]. E novamente
evidente o porque destas propriedades serem desejadas, pois qualquer gramatica
que nao e irredutıvel pode ser manipulada e modificada por simples substituicoes de
subsequencias, variaveis e regras de producao para obter uma nova gramatica repre-
sentando a mesma sequencia de dados mas com um comprimento total menor dos
membros direitos das regras de producao e portanto obtendo melhor compressao.
Alias, Yang e Kieffer apontam em [3] que qualquer transformada de gramatica pode
ser tornada irredutıvel por meio da aplicacao sistematica de um numero finito de pas-
sos de reducao (basicamente casamento e substituicao de subsequencias) apos uma
gramatica representando a sequencia de dados ter sido obtida; os referidos autores
ainda definem um numero de regras de reducao e uma abordagem sistematica para
a sua aplicacao na forma de algoritmos para transformadas de gramatica que usam
as regras de reducao para alcancar a irredutibilidade, assim como teoremas relacio-
nados as propriedades de codificacao das gramaticas e transformadas de gramatica,
que sao os principais resultados do artigo.
17
Cinco regras de reducao sao apresentadas em Yang e Kieffer[3], todas bastante
simples e descritas a seguir:
1. Se A e uma variavel que aparece uma unica vez entre os membros direitos das
regras de producao de G, remova a regra de producao cujo membro esquerdo
e A e substitua por seu membro direito a variavel A no unico lugar em que ela
ocorre nos membros direitos do restante das regras de producao;
Exemplo 1. Suponha que S → aabaAbaaaba e A → bb sao as regras de
producao de uma gramatica. A regra de reducao 1 pode ser utilizada para
obter uma gramatica com o conjunto reduzido de regras de producao S →
aababbbaaaba.
2. Se β e uma sequencia de comprimento ao menos 2 que aparece duas vezes
no membro direito de uma regra de producao (em posicoes nao sobrepostas),
adicione um novo sımbolo de variavel a N(G), substitua β pela nova variavel
na regra de producao, e adicione uma nova regra de producao com o membro
direito sendo β e o membro esquerdo a nova variavel;
Exemplo 2. Suponha que S → aababbbaaaba e a unica regra de producao
de uma gramatica. A regra de reducao 2 pode ser aplicada para obter uma
gramatica com as regras de producao S → AbbbaA e A → aaba.
3. A Regra de Reducao 3 e similar a Regra de Reducao 2, mas neste caso a
sequencia β nao aparece duas vezes na mesma regra de producao, mas aparece
nos membros direitos de duas regras de producao distintas e e substituıda por
uma nova variavel nos dois lugares, ao passo que uma nova regra de producao
e adicionada;
Exemplo 3. Suponha que S → AbbbaA e A → aaba sao as regras de producao
de uma gramatica. Aplique a regra de reducao 3 para obter uma nova gramatica
com as regras de producao S → AbbBA, A → aaB e B → ba.
4. Se β e o membro direito de uma regra de producao mas tambem aparece como
uma subsequencia no membro direito de outra regra de producao, substitua β
no membro direito da segunda regra pelo membro esquerdo da primeira;
18
Exemplo 4. Suponha que S → AbbBA, A → aaba e B → ba sao as regras
de producao de uma gramatica. Aplicando a regra de reducao 4 as regras de
producao se tornam S → AbbBA, A → aaB e B → ba.
5. Se ∃A,B ∈ V (G) | A 6= B ∧ f∞G (A) = f∞
G (B), substitua B por A em todos
os membros direitos das regras de producao e remova as regras de producao
cujos membros esquerdos se tornem sımbolos inuteis.
Exemplo 5. Suponha que S → AbbBC, A → aaB, B → ba, e C → aaba
sao as regras de producao de uma gramatica. Utilizando a regra de reducao
5 obtem-se uma gramatica reduzida com as regras de producao S → AbbBA,
A → aaB e B → ba.
Pode-se ver facilmente que as regras de reducao 2, 3 e 4 sao as que trazem o po-
der de compressao do casamento de sequencias as transformadas de gramatica irre-
dutıveis, mas estas regras nao definem, por si, transformadas de gramatica, nem nos
instruem explicitamente no melhor caminho para projeta-las[13]. Yang e Kieffer[3]
discutem dois algoritmos iterativos que se utilizam destas regras na implementacao
de transformadas de gramatica, que resumimos a seguir:
• Algoritmo do Casamento Mais Longo de Subsequencia: Dada uma sequencia
de dados, se inicia com a gramatica trivial que possui uma unica regra de
producao com o sımbolo de partida como seu membro esquerdo e a sequencia
de dados completa como seu membro direito. O restante do procedimento
se resume a buscar iterativamente o casamento mais longo de subsequencias
nos membros direitos das regras de producao da gramatica, isto e, a mais
longa subsequencia que aparece duas vezes (em posicoes nao-sobrepostas, se
na mesma regra de producao), e, dependendo de onde a subsequencia e en-
contrada, aplicar a regra de reducao 2, 3 ou 4. Quando nao puderem mais
ser encontrados casamentos de subsequencias de comprimento 2 ou mais, a
gramatica obtida representa a sequencia de dados de entrada e irredutıvel.
• Algoritmo Sequitur Modificado: O procedimento comeca com uma gramatica
mınima cuja unica regra de producao possui o sımbolo de partida como seu
membro esquerdo e o primeiro sımbolo (da esquerda para a direita) da sequencia
19
de dados de entrada como seu membro direito. A cada iteracao, o proximo
sımbolo (lendo da esquerda para a direita) da sequencia de dados e adicionado
ao final da regra de producao atual para o sımbolo de partida e as regras de
reducao sao aplicadas de modo que ao fim de cada passo a gramatica obtida
seja sempre irredutıvel. Quando o ultimo sımbolo da sequencia de entrada e
adicionado e o ultimo passo de aplicacao das regras de reducao e executado, a
gramatica resultante representa a sequencia de dados de entrada e e irredutıvel.
O segundo algoritmo e denominado Sequitur Modificado pois ele e bastante pa-
recido com o algoritmo Sequitur proposto por Nevill-Manning e Witten, que e um
algoritmo em tempo linear para gerar recursivamente uma gramatica que represente
uma dada sequencia adicionando um sımbolo por vez e aplicando duas restricoes
a cada passo: todo digrama (par de sımbolos) deve ser unico e todas as regras de
producao devem ser utilizadas ao menos duas vezes[15].
Em [3] ha tambem varias definicoes, demonstracoes e teoremas sobre os codigos
baseados em gramaticas vistos pelo prisma da teoria da informacao, tais como resul-
tados referentes a entropia, metodos de codificacao em sequencias de codigo binario
com os limites para tais sequencias (Teorema 6), e resultados acerca do decaimento
assintotico de sua maxima redundancia pontual (Teoremas 7 e 8 – os principais
resultados de [3]). O conceito de maxima redundancia pontual exprime um limite
superior para a redundancia ponto a ponto, um conceito mais forte que o de um
limite para o valor esperado da redundancia, que e a diferenca entre o comprimento
da descricao de um codigo e o numero otimo teorico de bits de informacao[16].
Teorema 6. [3, Teo. 6] Ha um mapeamento um a um B : G(Σ) → 0, 1+ tal que:
1. Se G1 e G2 sao gramaticas distintas em G(Σ), entao o codigo binario B(G1)
nao e um prefixo do codigo binario B(G2); e
2. Para cada G ∈ G(Σ), o comprimento do codigo B(G) satisfaz |B(G)| ≤ |Σ|+
4 |G|+ dH(G)e.
A quantidade H(G) referida no Teorema 6 e a entropia da gramatica G, definida
em [3] como a entropia nao normalizada da sequencia ωG, que por sua vez e a
20
concatenacao dos membros direitos das regras de producao de G ρG com a primeira
ocorrencia (da esquerda para a direita) de cada variavel de G removida. A entropia
nao normalizada de uma sequencia e definida por H∗(u) ,∑n
i=1 log(
nm(ui|u)
), onde
m(s | u) = |1 ≤ i ≤ n : ui = s| e n = |u|; a entropia da gramatia e entao H(G) ,
H∗(ωG).
Teorema 7. [3, Teo. 7] Seja φ um codigo baseado em gramaticas da classe Cac(Σ)
[todos os codigos baseados em gramaticas com alfabeto Σ e utilizando uma trans-
formada de gramatica assintoticamente compacta], e seja x → Gx a transformada
de gramatica utilizada por φ. Seja νn uma sequencia de numeros positivos con-
vergindo a zero tal que maxx∈ΣnGx
x= O(νn). Entao, para cada inteiro positivo k,
Redn(φ,Λkfs(Σ)) = O(γ(νn)), onde γ , x log( 1
x), x > 0.
Teorema 8. [3, Teo. 8] A classe de codigos Cirr(Σ) [todos os codigos baseados em
gramaticas com alfabeto Σ e utilizando uma transformada de gramatica irredutıvel]
e um subconjunto da classe Cac(Σ). Adicionalmente, para cada inteiro positivo k,
maxφ∈Cirr(A)Redn(φ,Λkfs(Σ)) = O( log log n
log n).
Note que o Teorema 8 garante que todas as transformadas de gramatica irre-
dutıveis sao tambem assintoticamente compactas, o que e um resultado muito in-
teressante uma vez que as regras de reducao que podem ser utilizadas para obter
gramaticas irredutıveis sao relativamente simples de serem implementadas em al-
goritmos (como visto, porr exemplo, nos algoritmos de Casamento Mais Longo de
Subsequencia e Sequitur Modificado). Uma prova oferecida para o Teorema 6 e
um exemplo de algoritmo para o codificador de gramatica que satisfaz as condicoes
do teorema. Entretanto, uma observacao e feita em relacao a este algoritmo para
codificacao (e os Teoremas 7 e 8 que dependem dele) restringe os codigos baseados
em gramaticas a processamento em batelada somente, pois as gramaticas precisam
estar completas (e portanto a sequencia de dados de entrada deve ter sido comple-
tamente analisada) para ser codificada, o que impede a adocao de abordagens de
codificacao sequencial contınua. Esta questao e resolvida num outro artigo de Yang
e Kieffer[13]. O esquema do codificador de gramatica para uma gramatica G ∈ G(Σ)
introduzida na prova do Teorema 6 consiste em montar uma sequencia binaria B(G)
concatenando seis partes B1 a B6, cada uma computada como descrito a seguir[3]:
21
1. B1 tem comprimento |N(G)| e consiste de |N(G)| − 1 zeros seguidos por um
1. Isto indica o numero de variaveis da gramatica;
2. B2 tem comprimento |Σ| e consiste em uma sequencia de bits indicando quais
sımbolos do alfabeto sao incluıdos entre os sımbolos terminais da gramatica;
3. B3 tem comprimento |G| e consiste da representacao unaria (como em B1)
da frequencia absoluta de cada sımbolo da gramatica (variaveis e sımbolos
terminais) exceto o sımbolo de partida nos membros direitos das regras de
producao;
4. B4 tem comprimento |G| e consiste nos comprimentos dos membros direitos
das regras de producao (tambem em representacao unaria);
5. B5 tem comprimento |G| e consiste em uma sequencia de bits indicando em que
posicoes de ρG (a concatenacao dos membros direitos das regras de producao
de G) esta a primeira (da esquerda para a direita) ocorreencia de cada variavel
de G; e
6. B6 tem comprimento maximo de dH(G)e e consiste de ωG codificado utilizando
codificacao enumerativa (que faz uso das frequencias em B3).
A tecnica de codificacao enumerativa consiste na producao de um dicionario
ordenado (em ordem lexicografica) das sequencias com as mesmas frequencias de
sımbolos da sequencia a ser codificada e a transmissao do ındice desta naquele di-
cionario, assim como os proprios sımbolos e suas frequencias se estas informacoes ja
nao forem do conhecimento do decodificador[17].
As transformadas de gramatica e os algoritmos introduzidos em [3] se utilizam
tanto do casamento de padroes e codificacao aritmetica, porem nao e feita uma
tentativa explıcita de otimizar esta combinacao. Isto e feito em [13] com a introducao
de uma transformada de gramatica gulosa sequencial e tres algoritmos de compressao
baseados nela.
22
3.2.1 Transformada gulosa
A transformada de gramatica gulosa descrita em [13] e bastante similar ao algo-
ritmo Sequitur Modificado de [3], mas ao inves de simplesmente adicionar o proximo
sımbolo a cada passo, o algoritmo guloso adiciona a variavel da gramatica (exceto o
sımbolo de partida) que representa o prefixo mais longo do restante da sequencia de
dados, se houver tal variavel ou, se nao, adiciona o proximo sımbolo. Uma variante
ligeiramente mais gulosa e de implementacao mais complicada, permitindo o uso
do sımbolo de partida (e o redefinindo, se utilizado), tambem foi apresentada por
Kieffer e Yang [18], porem e pouco provavel que toda a sequencia ja processada se
repita inteiramente como prefixo da sequencia restante a nao ser bem no inıcio do
processo, e as propriedades da transformada sao identicas a da versao mais simples
[13].
Tres algoritmos de compressao desenvolvidos utilizando esta transformada gulosa
e apresentados em [13] se encontram resumidos a seguir. Em [13] Kieffer e Yang
tambem apresentam resultados de simulacoes mostrando que a performance de com-
pressao utilizando estes algoritmos foi ate 26% melhor em comparacao com o Unix
Compress (LZ78) e 37% em comparacao com o Gzip (LZ77). Mais resultados de
simulacoes e detalhes de implementacao seriam apresentados em [19] porem apesar
dos nossos melhores esforcos nao foi possıvel localizar uma versao publicada deste
artigo.
3.2.1.1 Algoritmo Hierarquico
Uma gramatica e obtida a partir da sequencia de dados de entrada com a aplicacao
da transformada gulosa, e em seguida a gramatica final obtida e codificada com um
codigo aritmetico de ordem zero e alfabeto dinamico.
Para codificar a gramatica, primeiro faz-se uma conversao para a sua forma
canonica (simplesmente renomear as variaveis para si, i = 0, 1, 2, . . ., onde s0 e o
sımbolo de partida e tal que se as regras de producao forem lidas da esquerda para
a direita e de cima para baixo, as variaveis aparecam em ordem, isto e, si aparece
antes de si+1 para todo i–para simplificar a notacao utilizamos S ao inves de N(G)
23
para denotar este novo conjunto de variaveis renomeadas) e se concatenam os mem-
bros direitos das regras de producao em uma sequencia, inserindo o sımbolo e apos
o membro direito da regra do sımbolo de partida, e apos inserindo b e e respectiva-
mente antes e depois de qualquer regra de producao cujo comprimento seja maior
que 2.
A partir desta sequencia, a primeira ocorrencia da esquerda para a direita de
cada variavel e substituıda por s, tirando vantagem do fato que a gramatica foi
reescrita em sua forma canonica, e finalmente e aplicado um codigo aritmetico de
ordem zero para codificar esta sequencia, utilizando um contador c(β), β ∈ S ∪Σ ∪
b, e, s, iniciando com c(β) = 1 para cada β ∈ Σ ∪ b, e, s e c(β) = 0 para os
outros. Cada sımbolo da sequencia, lido da esquerda para a direita, e codificado
pela probabilidade c(β)/∑
α∈S(i)∪Σ∪b,e,sc(α), onde S(i) = s1, s2, ..., si e o subconjunto
de S contendo somente as variaveis introduzidas ate aquele ponto na codificacao da
sequencia (exceto o sımbolo de partida s0); e conforme cada sımbolo e codificado, seu
contador e incrementado e, se o sımbolo for s, a proxima variavel si+1 e adicionada
ao alfabeto do codigo aritmetico e o contador c(si+1) tambem e incrementado.
3.2.1.2 Algoritmo Sequencial
Enquanto a transformada de gramatica gulosa analisa a sequencia de dados, a
sequencia de subsequencias analisadas e codificada utilizando um codigo aritmetico
de ordem zero.
Note que cada subsequencia analisada na entrada ou e um unico sımbolo do alfa-
beto ou e representada por uma unica variavel e, pela natureza sequencial do algo-
ritmo guloso, o decodificador pode decodificar cada subsequencia sequencialmente,
conforme bits suficientes sao recebidos, e utilizar as mesmas regras da transformada
gulosa para obter tanto a gramatica quanto a propria sequencia de dados original
tambem de modo sequencial. Cada sımbolo da sequencia de subsequencias analisa-
das pode ser codificada de modo similar ao visto acima no algoritmo hierarquico,
mas com o alfabeto do codigo aritmetico iniciando somente com Σ, e as variaveis
sao adicionadas ao passo em que sao adicionadas a propria gramatica.
24
Os contadores sao iniciados com c(β) = 1 para β ∈ Σ, e cada sımbolo lido e
codificado usando a probabilidade c(β)/ ∑α∈S(i)∪Σ
c(α) e tem seu contador incrementado.
Se uma variavel e introduzida a gramatica, um contador e criado com o valor c(si) =
1.
3.2.1.3 Algoritmo Sequencial Aprimorado
Enquanto a transformada de gramatica gulosa analisa a sequencia de dados, ao
inves de simplesmente codificar a sequencia de subsequencias, o algoritmo procura
operar na sequencia de particoes induzida pela gramatica, que e uma sequencia mais
curta.
A sequencia de particoes induzida pela gramatica e obtida substituindo a primeira
ocorrencia da esquerda para a direita de cada variavel regra de producao do sımbolo
de partida pelo membro direito da sua regra de producao correspondente, e uma
analise da sequencia de dados pode ser obtida substituindo cada variavel pela sub-
sequencia que ela representa. Como foi descrito, so se poderia obter a sequencia de
particoes induzida pela gramatica apos esta ter sido completamente formada, mas
pode-se tentar utilizar esta ideia se, no momento da codificacao de um sımbolo ana-
lisado pela transformada gulosa, se uma regra de reducao sera aplicada ou nao apos
a sua adicao, e se tambem se tem acesso ao estado atual da gramatica antes de ser
atualizada; o decodificador tem, na realidade, acesso ao estado atual da gramatica
pois ele a constrois sequencialmente durante a decodificacao, como visto no algo-
ritmo sequencial original acima, e e assim que o algoritmo sequencial aprimorado
busca operar na sequencia de particoes induzida.
Uma sequencia auxiliar I e produzida com um bit para cada sımbolo analisado da
sequencia de dados. Quando o i-esimo sımbolo e analisado, I(i) = 1 se ocorre uma
reducao apos sua adicao a gramatica e caso contrario I(i) = 0. Esta sequencia e
codificada com um codigo aritmetico de primeira ordem utilizando quatro contadores
c(0, 0), c(0, 1), c(1, 0) e c(1, 1), inicialmente com o valor 1. Se i sımbolos ja foram
analisados, o valor de I(i+1) e definido quando o (i+1)-esimo sımbolo β e analisado
e adicionado a gramatica. I(i+ 1) e entao codificado coma probabilidade dada por
c(I(i),I(i+1))/(c(I(i),0)+c(I(i),1)) e β e codificado com um codigo aritmetico de ordem zero
25
com dois contadores separados c(β) e c(β), usando a probabilidade c(β)/∑
c(γ)γ∈S(ji)∪Σ−L2(α)
se I(i+1) = 0, a probabilidade c(β)/∑c(γ)
γ∈L1(α)
se I(i) = 0 e I(i+1) = 1, e nao codificando
β se I(i) = 1 e I(i+1) = 1. L1(α) e L2(α) sao listas mantidas de todos os sımbolos
η ∈ S ∪ Σ tal que αη e um padrao que aparece no estado atual da gramatica
mas nao e os dois ultimos sımbolos da regra de producao do sımbolo de partida, e
L1(α) tem a restricao adicional que αη nao esteja no membro direito de nenhuma
regra de producao. Estas listas sao atualizadas tanto pelo codificador quanto pelo
decodificador e mantem informacoes sobre a estrutura da gramatica atual, que e
utilizada como contexto na codificacao dos sımbolos analisados, em conjunto com
I(i + 1) que e enviado ao decodificador como informacao lateral. A ideia e que se
o decodificador sabe que uma reducao acontecera, ao menos parte da informacao
contida no proximo sımbolo ja esta prasente na gramatica atual.
3.2.2 Transformada condicional de casamento de padroes
multinıvel
Uma transformada de gramatica condicional de casamento de padroes multinıvel
(conditional multilevel pattern matching grammar transform ou conditional MPM
(CMPM) grammar transform) e descrita em [14] e e baseada na transformada MPM
incondicional introduzida num artigo anterior dos mesmos autores[20]. A ideia
basica da transformada MPM e particionar a sequencia de dados em blocos e entao
em sub-blocos, de modo que repeticoes de subsequencias sao capturadas em varios
nıveis, e a versao condicional aumenta a capacidade de compressao se utilizando de
correlacoes entre a sequencia de dados e a informacao lateral.
3.2.2.1 A transformada incondicional
Uma transformada MPM tem dois parametros, I e r, e pode ser representada
por MPM(r, I), onde I define o numero de nıveis e r o tamanho dos blocos e sub-
blocos. Cada nıvel e uma particao diferente da sequencia de dados usando tamanhos
de blocos diferentes, o nıvel mais baixo e o nıvel 0 e contem os menores blocos,
compostos por um sımbolo cada; nos nıveis i = 1, . . . , I a sequencia e particionada
em blocos de ri sımbolos e se o comprimento da sequencia nao e um multiplo de ri,
o restante so ira ser processado a partir do (i− 1)-esimo nıvel, e assim por diante.
26
Em cada nıvel os blocos distintos sao etiquetados com numeros naturais denomi-
nados tokens, tal que blocos contendo a mesma subsequencia sao representados pelo
mesmo token, os numeros representam a ordem em que eles aparecem conforme a
sequencia de dados de entrada e lida da esquerda para a direita, e cada nıvel pode ser
descrito por sua sequencia de tokens, exceto o nıvel mais baixo, cujos tokens podem
ser os proprios sımbolos do alfabeto. Como para cada bloco representado por um
mesmo token em um nıvel i correspondem r sub-blocos iguais no nıvel i−1, somente
o primeiro conjunto de r sub-blocos (correspondendo a primeira ocorrencia do token)
precisa ser mantida e representada por tokens, enquanto as proximas ocorrencias dos
mesmos blocos no nıvel i − 1 sao redundantes sao descartadas. Adicionalmente, a
primeira ocorrencia da esquerda para a direita de cada token em cada sequencia de
tokens e substituıda por s, exceto no nıvel mais baixo.
O conjunto de sequencias de tokens e entao a representacao multinıvel da sequencia
de dados original e pode ser vista como um conjunto de regras de producao de uma
gramatica, de modo similar ao ja visto nas outras transformadas acima, e e uma
representacao compacta da sequencia de dados de entrada, formada explorando os
casamentos de padroes. Assim como com as regras de producao, as sequencias
de tokens podem ser comprimidas com codificacao aritmetica. Cada sequencia
e codificada de maneira independente e, exceto pela do nıvel mais baixo, todas
comecam com o sımbolo s, entao ele nao precisa ser codificado. Utiliza-se um con-
tador c(β), β ∈ s∪1, 2, 3, . . . , f si , iniciando com c(β) = 1 para cada β ∈ s, 1 e
c(β) = 0 caso contrario, e onde f si representa o numero de vezes que o sımbolo s apa-
rece na sequencia de tokens, isto e, o numero de blocos distintos naquele nıvel. Cada
sımbolo β e entao codificado com a probabilidade c(β)/∑
α∈s,1∪2,3,...,j+1c(α), onde j e o
numero de vezes que o codificador processou o sımbolo s ate entao, e, conforme cada
sımbolo e processado, seu contador e incrementado e, se o sımbolo for s, o proximo
token na ordem natural e adicionado ao alfabeto do codigo aritmetico e o contador
c(j + 2) tambem e incrementado. No nıvel mais baixo nao e preciso levar em conta
o sımbolo s e os sımbolos podem ser codificados diretamente utilizando-se contado-
res c(β), β ∈ Σ, todos iniciando em 1, e cada sımbolo β codificado utilizando-se a
probabilidade c(β)/∑
α∈Σc(α), e incrementando seu contador.
27
A sequencia binaria codificada pode ser construıda concatenando as sequencias de
tokens codificadas comecando (da esquerda para a direita) com a do nıvel mais alto,
seguida pelo nıvel imediatamente abaixo e assim sucessivamente ate o nıvel 0. Se o
comprimento total da sequencia de dados original e conhecido pelo decodificador, o
comprimento da sequencia de tokens do nıvel mais alto pode ser diretamente calcu-
lado e, uma vez que esta sequencia seja decodificada, pode-se calcular o comprimento
da sequencia seguinte e assim por diante. Entretanto, note que este codificador de
gramatica implica codificacao em batelada; um algoritmo de codificacao sequencial
para a transformada MPM e apresentada no artigo [21].
3.2.2.2 A transformada condicional
A versao condicional da transformada MPM (transformada CMPM) descrita em
[14] e uma adaptacao direta do esquema mostrado acima, em que, ao inves de a unica
entrada ser a sequencia de dados x, a transformada tambem recebe uma sequencia
y do mesmo comprimento de x como informacao lateral, e a entrada e tratada como
uma sequencia de pares (xi, yi) ao inves de uma sequencia simples de sımbolos. O
particionamento da entrada em blocos e sub-blocos e o mesmo, mas duas sequencias
de tokens sao geradas a cada nıvel, uma em relacao aos dados de y em que cada
bloco de y e etiquetado sequencialmente com um numero natural como token (1, 2,
3, ...) e blocos iguais recebem o mesmo token, enquanto a sequencia de tokens com
relacao a x e construıda condicionalmente a y: os blocos de x que correspondem
a blocos de y iguais sao etiquetados como uma subsequencia independente condi-
cional, tal que os numeros utilizados como tokens representam o numero de blocos
diferentes encontrados em cada subsequencia e nao na sequencia x completa como
no caso incondicional. Alem disso, a primeira vez que cada token aparece em cada
subsequencia de x e substituıda por s. Note que agora, como a etiquetagem dos blo-
cos de x e condicional a etiquetagem dos blocos de y e possıvel que blocos diferentes
de x sejam representados pelo mesmo token e tambem que s represente o mesmo
bloco de x mais de uma vez, diferentemente do caso incondicional. Note tambem
que nenhum dos tokens de y e s.
28
Presuma que x e ytenham sido apropriadamente etiquetados no nıvel i com o
metodo descrito acima, de modo similar ao caso incondicional, no nıvel i−1th nao e
necessario manter e etiquetar os sub-blocos correspondendo a combinacoes repetidas
de blocos de x e de y, de maneira que no nıvel i − 1 so e necessario processar sub-
blocos de blocos de x no nıvel i que sejam etiquetados com o token s e os blocos de
y correspondentes.
As sequencias de tokens a cada nıvel vem, como vimos, como um par de sequencias
ou, alternativamente, podem ser interpretadas como sequencias de pares de tokens.
Como no caso incondicional, estas sao comprimidas utilizando um codigo aritmetico,
e para cada primeira ocorrencia de um token de y, o token de x correspondente
sempre sera um s e portanto este par nao precisa ser codificado. Adicionalmente,
se nos lembrarmos que a sequencia y e informacao lateral disponıvel tanto para o
codificador quanto para o decodificador, nao e necessario codificar os tokens de y
mas somente os tokens de x. Para tirar proveito da informacao lateral no codificador
de gramatica, ela tambem e utilizada para codificar condicionalmente os tokens de x
associando-se diferentes contadores cγ(β) para cada par de sımbolos (β, γ), onde β e
um token de x e γ ´r um token de y, os contadores iniciando em 1 se β ∈ s, 1 e 0
caso contrario, e entao codificando cada sımbolo β de cada par lido da sequencia de
tokens com a probabilidade cγ(β)/∑
α∈s,1∪2,3,...,j+1cγ(α), onde j e onumero de vezes que
o codificador processou o par (β, γ) ate entao, e, conforme cada par e processado,
seu contador e incrementado e, se o sımbolo codificado for s, o proximo token na
ordem natural e adicionado ao alfabeto do codigo aritmetico e o contador cγ(j + 2)
tambem e incrementado. Para o nıvel mais baixo nao e necessario levar em conta
o sımbolo s e os sımbolos podem ser condicionalmente codificados utilizando-se os
contadores cγ(β), β ∈ Σ, todos iniciando em 1, e cada sımbolo β e codificado com a
probabilidade cγ(β)/∑α∈Σ
cγ(α) e tem seu contador incrementado.
Novamente, a sequencia do codigo binario pode ser construıda concatenando-se
as sequencias de tokens de x codificadas, comecando pela do nıvel mais alto seguida
pelo nıvel imediatamente abaixo e assim por diante ate o nıvel mais baixo. O
comprimento total da sequencia de dados original x e conhecida pelo decodificador
pois e o mesmo comprimento da sequencia de informacao lateral y, entao o com
29
primento da sequencia de tokens do nıvel mais alto pode ser facilmente calculada e,
uma vez que ela seja decodificada, o comprimento da sequencia seguinte pode ser
calculado e assim por diante.
3.3 Trabalhos posteriores
Agora partimos para uma revisao bibliografica sistematica de artigos de varios
autores que citam os artigos seminais de Yang e Kieffer ([3, 13, 14]) que foram
revisados acima. Artigos que citam todos os tres principais artigos de Yang e Kief-
fer sobre codigos baseados em gramaticas ([22, 23, 24, 25, 26]) e artigos que citam
ao menos um deles e foram publicados nos ultimos cinco anos, isto e, entre 2011
e 2015 ([27, 28, 29, 30, 31, 32, 33, 24, 25, 34, 35, 36, 37, 38, 39, 40]) foram se-
lecionados para esta revisao. Um artigo publicado em 2005 foi identificado como
uma referencia importante para varios dos artigos selecionados e traz resultados
interessantes em relacao a dificuldade de aproximar a solucao otima para o pro-
blema da menor gramatica[41] entao tambem foi incluıdo na revisao, assim como
tambem incluımos um artigo interessante reportando uma comparacao de perfor-
mance de compressao em ferramentas de compressao de documentos XML[42] que
compara abordagens baseadas em gramaticas especializadas em documentos XML
a outras ferramentas especializadas e compressores de uso geral, que aponta para a
falta de implementacoes solidas publicamente disponıveis para codigos baseados em
gramaticas.
3.3.1 Indiretamente ligados aos codigos baseados em gramaticas
Alguns dos trabalhos que citam os artigos de Yang e Kieffer nao tratam direta-
mente de codigos baseados em gramaticas ou suas aplicacoes, mas investigam areas
relacionadas, complementares, ou de algum modo similares. Fazemos uma breve re-
visao destes abaixo, antes de partir para uma revisao mais detalhada da bibliografia
que trata diretamente dos codigos baseados em gramaticas.
30
3.3.1.1 Codificacao e Decodificacao Interativa
A maioria dos artigos que citam todos os tres artigos de Yang e Kieffer sao tra-
balhos de Yang e co-autores apresentando o arcabouco teorico da Codificacao e
Decodificacao Interativa (Interactive Encoding and Decoding – IED) [22, 23, 24, 25].
A IED e uma proposta de um esquema para codigos de compressao quase sem
perdas com informacao lateral somente para o decodificador, que e conceitualmente
similar a codificacao Slepian-Wolf, exceto pelo fato de que a IED utiliza de um canal
de retorno entre o codificador e o decodificador e a codificacao e decodificacao da
sequencia de dados e feita diversas vezes, em iteracoes, em que o encoder utiliza
uma fluxo de bits realimentado do decodificador a partir do resultado da iteracao
anterior para produzir uma codificacao melhor na iteracao atual, e o decodificador
utiliza a informacao lateral para decodificar a sequencia codificada e produzir a
realimentacao para a proxima iteracao de tal modo que sucessivas estimativas ou
aproximacoes da sequencia de dados original sao obtidas pelo decodificador ate que
uma seja tida como suficientemente correta[23].
Os autores tambem demonstraram que qualquer codigo de compressao sem perdas
classico com informacao lateral disponıvel tanto para o codificador quanto para o
decodificador pode ser adaptado ao esquema IED[25], e as citacoes aos artigos de
Yang e Kieffer sao feitas muito rapidamente em relacao a certas propriedades que
estao neles demonstradas para codigos baseados em gramaticas e cuja existencia e
necessaria para analise teorica feita da IED.
3.3.1.2 Tecnicas de compressao relacionadas mas nao baseadas em gramaticas
Alguns artigos investigam outras tecnicas de compressao que sao de algum modo
relacionadas aos codigos baseados em gramaticas ou que usam esquemas similares
ou analogos em alguns pontos aos algoritmos propostos para codigos baseados em
gramaticas e citam os artigos de Yang e Kieffer neste contexto.
Doshi e Gandhi[30] demonstram uma combinacao de duas tecnicas (processamento
de multiplos bits simultaneos no ciclo de renormalizacao e escalamento da frequencia
31
total para uma potencia de 2) para reduzir bastante o tempo de execucao de im-
plementacoes de codigos aritmeticos tanto na codificacao quanto na decodificacao,
e notam que codigos baseados em gramaticas podem ter a execucao do codificador
de gramatica otimizada.
Zhang, Yang e Kieffer[33] codificam arvores binarias utilizando suas representacoes
por grafos acıclicos diretos (direct acyclic graph – DAG) mınimos. Os autores notam
que ha algoritmos em tempo linear para a obtencao do DAG mınimo de uma arvore
binaria, que pode ser codificado em uma sequencia binaria utilizando um esquema
similar ao utilizado para codificar as gramaticas com codificacao enumerativa como
mostrado na prova do Teorema 6.
Hu e Yang[37] desenvolvem um algoritmo para reduzir o tempo de codificacao
do HEVC (High Efficiency Video Coding/H.265) utilizando deteccao de amostras
atıpicas para acelerar a selecao do modo intra e um aprimoramento da codificacao
aritmetica que usa indicadores de amostras atıpicas numa imagem binıvel pois ela
e altamente relacionada as decisoes de divisao da unidade de codificacao e escolha
do modo intra que precisam ser codificadas juntamente com os dados da imagem
de vıdeo, e usam um esquema de arvore que se parece com um algoritmo MPM
bidimensional para codificar a imagem binıvel de amostras atıpicas.
3.3.1.3 Tecnicas de compressao nao relacionadas
Ha tambem artigos que nao se relacionam diretamente com codigos baseados em
gramaticas mas os citam como exemplos de esquemas de codificacao e compressao
existentes.
Debowski[28] conduz uma investigacao empırica sobra a conjectura de Hilberg so-
bre a linguagem natural, que afirma que a informacao mutua de dois blocos longos
adjacentes de texto natural cresce como uma potencia do comprimento do bloco.
Ele argumenta que utilizando um codigo de compressao universal pode-se obter
um limite superior para o expoente em nβ onde n e o comprimento do bloco e a in-
formacao mutua e conjecturada proporcional a nβ. Codigos baseados em gramaticas
sao citados como exemplos de codigos universais, entre outros, e o autor escolhe
32
introduzir um novo codigo de compressao baseado numa mistura de cadeias de Mar-
kov adaptativas, que ele compara empiricamente ao LZ77 e obtem melhores taxas
de compressao e portanto um limite mais justo para o valor de β.
Jain e Bansal[31] investigam certos cenarios para codigos LZ de janela deslizante
e incluem um dos artigos de Yang e Kieffer[3] na bibliografia, mas ele nao e citado
no texto do artigo.
Kuzuoka e Watanabe[34] estudam a codificacao de comprimento variavel na co-
dificacao Slepian-Wolf e citam brevemente o artigo de Yang e Kieffer que inclui
informacao lateral[14] para fazer a distincao de que a investigacao naquele artigo
e em outros se refere a codificacao sem perdas como codificacao de erro zero, en-
quanto neste artigo os codigos tratados sao fracamente sem perdas, isto e, que tem
a probabilidade de erro diferente de zero mas assintoticamente indo a zero.
O artigo de Zheng e Yang sobre codificacao causal de vıdeo[35] descreve um al-
goritmo para codificar quadros de vıdeo modelando cada quadro como uma fonte
de informacao estacionaria, utilizando todos os quadros anteriores na codificacao do
quadro atual (isto e, considerando multiplas fontes) e minimizando a distorcao total
para todas as fontes. O algoritmo gera para cada quadro codificado uma sequencia
de ındices utilizando todas as fontes de informacao disponıveis, e entao codifica essa
sequencia utilizando um codigo de comprimento fixo para a transmissao, mas menci-
ona que esquemas de codigos de comprimento variavel poderiam ser utilizados como
alternativas, e cita codigos baseados em gramaticas como um exemplo.
3.3.2 Codigos baseados em gramaticas e suas aplicacoes di-
retas
3.3.2.1 Avaliando aplicacoes diretas de compressao baseada em gramaticas
Revisamos um par de artigos que avaliam aplicacoes diretas de codigos de com-
pressao baseados em gramaticas e comparam a sua performance as de outras ferra-
mentas disponıveis.
33
Wang et al [38] descrevem em seu artigo uma aplicacao bastante direta de codigos
baseados em gramaticas em sistemas de detecao de intrusao. Eles empregam com-
pressao sem perdas para medir a quantidade de informacao (no mesmo espırito do
uso que Debowski faz da compressao sem perdas[28]) tal que se uma amostra adi-
cionada a um corpo de referencia representativo afeta significativamente o tamanho
total dos dados comprimidos (em relacao ao tamanho dos dados de referencia com-
primidos por si so), a amostra pode ser considerada anomala.
E requerido que o codigo de compressao nao utlize janelas deslizantes para que os
dados de todo o corpo de referencia seja de fato utilizado na compressao da amostra
adicionada, e tambem que nao possua alfabeto fixo de modo que o codigo se adapte
melhor a diferentes tipos de fontes de dados tais como registros de sistema e de
aplicacoes ou tracos de execucao, e nao deve haver nenhuma restricao quanto aos
dados. Codigos baseados em gramaticas sao considerados a escolha mais adequada,
dadas estas condicoes, para o codigo de compressao utilizado, e os autores adotam
a transformada gulosa de Yang e Kieffer[13] mas nao o codificam a gramatica, pois
a taxa de compressao nao e um objetivo direto nesta aplicacao e os autores desejam
que seja preservada a relacao entre a estrutura dos dados e a hierarquia, alem de
facilitar a analise manual de anomalias por ventura detectadas.
Os resultados alcancados com o uso do codigo baseado em gramaticas sao posi-
tivos e favoraveis na comparacao com metodos estatısticos tradicionais ou baseados
em cadeias de Markov; quatro diferentes cenarios foram testados (analise de tex-
tos, detecao de acesso por terceiros a linha de comando de um usuario, detecao de
intrusao utilizando sequencias de chamadas de sistema e detecao de erros usando
registros de depuracao de alta granularidade da execucao de saltos num programa)
e o algoritmo baseado em gramaticas obteve boa performance em todos os casos,
enquanto todos os metodos concorrentes falharam em ao menos alguns. Os au-
tores apontam como sugestoes para investigacao futura algumas modificacoes no
algoritmo que permitiriam nao so a detecao de anomalias como tambem a sua clas-
sificacao.
34
Sakr[42] fez um levantamento e testes comparativos das ferramentas disponıveis
para compressao sem perdas de documentos XML. Os testes incluıram tanto com-
pressores sem perdas de uso geral (gzip, bzip2 e PPM) quando ferramentas especi-
alizadas em compressao de XML que sejam livremente disponıveis e independentes
de esquema. No total foram comparados nove compressores, dos quais seis espe-
cializados em compressao de documentos XML –entre os quais dois sao codigos
baseados em gramaticas (Exalt e AXECHOP). Os testes avaliaram a estabilidade,
taxa de compressao e tempo de compressao e descompressao para um corpo grande
e diversificado de documentos XML.
O autor observou que ambos os compressores baseados em gramaticas tiveram
muito baixa estabilidade, e frequentemente falhavam para descomprimir correta-
mente os documentos, tanto que em muitos dos resultados compilados os dados
referentes a estes compressores tiveram de ser excluıdos por nao haver representa-
tividade para comparacao com as outras opcoes. Nos comentarios finais do artigo,
o autor nota que tanto quanto se foi possıvel saber nao ha implementacoes solidas
e confiaveis de compressores de documentos XML baseados em gramaticas, e esta
continua sendo uma area de pesquisa aberta.
3.3.2.2 Novos codigos baseados em gramaticas e extensoes para fins es-
pecıficos
A seguir discutimos artigos que descrevem novos codigos baseados em gramaticas
e extensoes de algoritmos anteriores para adaptacao de codigos a casos especıficos.
Kieffer e Yang[26] introduzem um codigo de compressao de refinamento sem per-
das baseado em gramaticas. Codigos de refinamento podem ser vistos como um
caso especial de codigos com informacao lateral em que a informacao lateral y e
uma aproximacao grosseira da sequencia de dados original x (isto e, uma versao em
baixa resolucao) que o decodificador utiliza em conjunto com o codigo binario rece-
bido para reconstruir a sequencia original; tambem podem ser vistos como codigos
de camadas diferenciais. De modo mais geral, varios passos de refinamento podem
ser empregados em uma codificacao progressiva sem perdas que produz no deco-
dificador uma sequencia de aproximacoes progressivas em que a cada passo uma
35
representacao cada vez mais proxima dos dados originais e obtida, ate que seja ob-
tida uma copia fiel. A abordagem baseada em gramaticas apresentada pelos autores
constroi uma sequencia binaria B(x|y) em duas partes, primeiro codificando uma
maneira de construir a gramatica Gy (que representa y) dado y em B(Gy|y) e entao
codifica uma sequencia B(Gx|Gy) instruindo como obter a gramatica Gx que re-
presenta x a partir de Gy, e Gx pode ser chamado um refinamento de Gy (ou, ao
contrario, Gy um engrossamento de Gx). A sequencia de dados original x pode entao
ser obtida realizando-se as substituicoes paralelas usando as regras de producao de
Gx.
Para tornar a operacao de refinamento de Gy para Gx algo direto, os autores
restringem a estrutura das gramaticas utilizadas criando conjuntos parametrizados
de gramaticas que impoe certas estruturas as arvores de derivacao das gramaticas de
modo que tanto Gy quanto Gx compartilham da mesma estrutura em suas arvores
de derivacao. Esta abordagem e emprestada dos codigos estruturados baseados em
gramaticas tambem introduzidos por Yang e Kieffer que codificam separadamente a
estrutura e os dados das gramaticas no que eles chamam de gramatica estrutural e
gramatica representativa, respectivamente[43]. Um conjunto de gramaticas Gn pode
ser composto fixando um parametro β ≥ 3 e incluindo todas as gramaticas livres
de contexto G tal que N(G) ⊂ 2, 3, . . . , n, n e o sımbolo de partida (a raiz da
arvore de derivacao), T (G) = 1 e para cada nao-terminal i ha uma unica regra
de producao i → (i1, i2, . . . , ik) tal que k ≥ 2, each ij > 1 e um nao-terminal de G,∑kj=1 ij = i e i/ij ≤ β, j = 1, 2, . . . , k.
Os conjuntos definidos acima podem ser vistos como conjuntos de gramaticas
G que servem como modelos que podem ser utilizados para construir gramaticas
Gu ou (G)u representando qualquer sequencia u de comprimento n. Em seguida,
os autores mostram passos para construir estas gramaticas; cada sımbolo de u e
utilizado para etiquetar as n folhas da arvore de derivacao de G, e seus vertices
internos sao etiquetados com subsequencias de u formadas pela concatenacao das
etiquetas de seus filhos. Pode-se entao tomar os sımbolos nas etiquetas das folhas
como terminais de Gu, e nao -terminais sao distribuıdos aos vertices internos tal que
aqueles etiquetados com a mesma subsequencia de u recebem o mesmo nao-terminal,
36
de modo que o numero de nao-terminais e o numero de diferentes subsequencias de
u nas etiquetas. Claramente a etiqueta da raiz da arvore de derivacao sera a propria
sequencia u, que e substituıda pelo sımbolo de partida. A ideia defendida pelos
autores e que pode-se codificar uma gramatica estrutural G∗ adequada que pode ser
transformada tanto na gramatica representativa Gy quanto na Gx; de modo que a
gramatica estrutural pode ser codificada e, com a versao em baixa resolucao (ou
informacao lateral) y, ela especifica univocamente Gy (B(Gy|y)) e, por sua vez, so
se necessita codificar um mapeamento dos nao-terminais de Gy aos de Gx –o que
sempre sera possıvel pois ambos compartilham o mesmo comprimento n e sempre
sera unico pois elas compartilham a mesma estrutura G∗– tal que utilizando Gx o
decodificador pode obter o refinamento, ou seja, a sequencia original x.
E demonstrado que num conjunto Gn(A) de gramaticas representando sequencias
do conjunto An (isto e, sequEncias de comprimento n cujas entradas vem do alfabeto
A) ha no maximo C√n log2 n gramaticas distintas representando cada sequencia, onde
C e uma constante. Isto segue do Lema 1, cuja prova se encontra em[43] e nao
estao incluıdos em [26] passos para codificar em uma sequencia binaria Bn(G) uma
gramatica estrutural G. Entretanto, podemos ligar a segunda assercao do Lema
1 ao [43, Th. 1], mas a primeira assercao nao se encontra naquele artigo. Na
realidade, este outro artigo[43] trata de um problema ligeiramente diferente pois nele
se pretende codificar uma gramatica representativa dada uma gramatica estrutural
como informacao lateral, enquanto na primeira parte da sequencia codificada binaria
em [26] o objetivo e codificar a gramatica estrutural dada uma sequencia como
informacao lateral, isto e, B(Gy|y). Pode ser que um caso seja facilmente convertido
para uso no outro, mas esta nao e uma analise que tentamos fazer neste momento.
Lema 1. [26, Lem. 1] Seja n qualquer inteiro ≥ 2. Entao
• para cada G ∈ Gn, ha uma sequencia binaria Bn(G) de comprimento |Bn(G)| =
4⌊β3/2
√n⌋(1 + dlog2 ne) tal que Bn(G1) 6= Bn(G2) sempre que G1, G2 sao
gramaticas distintas em Gn;
• para cada conjunto finito nao-vazio A e cada gramatica G ∈ Gn(A), |G| ≤
72β2(|A|+ 2)2 log2(|A|+ 2)(n/log2 n).
37
Um metodo para obter a sequencia binaria B(Gx|Gy) e entao mostrado pela
prova do Teorema 9, que e reproduzido a seguir:
Teorema 9. [26, Teo. 2] Seja n qualquer inteiro ≥ 2. Ha um mapeamento
(G1, G2) → B(G1|G2) de R(Gn(A1),Gn(A2)) ao conjunto de sequencias binarias
nao-vazias como segue: i) para cada (G1, G2) ∈ R(Gn(A1),Gn(A2)), B(G1|G2) ≤
H(G1|G2) + Jn; e ii) sempre que (G1, G2) e (G′1, G
′2) em R(Gn(A1),Gn(A2)) satis-
fazem G2 = G′2 e G1 6= G′
1, a sequencia B(G1|G2) nao e um prefixo da sequencia
B(G′1|G′
2), onde R(Gn(A1),Gn(A2)) e o conjunto de todos os pares (G1, G2) em que
G2 e um engrossamento de G1 e G1 ∈ Gn(A1), G2 ∈ Gn(A2), e Jn e definido como
Jn , 72β2(3 + dlog2 |A1|e)(|A1|+ 2)2 log2(|A1|+ 2)(n/log2 n).
Omitimos aqui a prova (que pode ser consultada em [26], assim como a derivacao
da entropia condicional H(G1|G2)) e descrevemos brevemente como e formada a
sequencia B(Gx|Gy) propsota pelos autores. Note que se presume que os alfabetos
das gramaticas Gy e Gx ou sao iguais ou que o de Gy e menor que o de Gx, o que
faz sentido se vemos y como uma versao em baixa resolucao de x. B(Gx|Gy) e uma
concateacao B1B2B3B(s(U1))B(s(U2)) . . . B(s(Uj)):
1. B1 de comprimento |Gx| instrui como construir, usando Gy, a estrutura da
sub-arvore T ∗ da arvore de derivacao T de Gx (T∗ e obtida percorrendo a
arvore de derivacao em largura e podando os vertices filhos e as folhas sempre
que um nao-terminal repetido e encontrado);
2. B2 de comprimento K dlog2 |Ax|e, K sendo o numero de folhas de T ∗ que
tambem sao folhas de T , especifica quais sımbolos terminais de Gx serao assi-
nalados a cada uma das K folhas;
3. B3 de comprimento |Gx| −K com as frequencias dos nao-terminais nos mem-
bros direitos das regras de producao de Gx;
4. cada B(s(U)) e uma codificacao enumerativa de s(U), onde cada s(U) e uma
sequencia de sımbolos de Gx obtida percorrendo as folhas de T ∗ em profun-
didade para a qual o nao-terminal U e assinalado no vertice correspondente
da arvore de derivacao de Gy. Note que todas as permutacoes de cada s(U)
podem ser computadas utilizando Gy, B1, B2 e B3.
38
Yang e Kieffer[26] nao especificam exatamente como podem ser codificados os
componentes B1, B2, . . . mas codificacoes apropriadas podem ser facilmente deduzi-
das, B1, por examplo pode ser codificado percorrendo em largura a sub-arvore T ∗,
ignorando a raiz, e codificando um bit 1 se o vertice atual e interno ou um bit 0
caso contrario. A sequencia binaria codificada completa transmitida para o refina-
mento e entao a concatenacao B(Gy|y)B(Gx|Gy), e os autores mostram que o limite
para a redundancia maxima para tal codigo de refinamento baseado em gramaticas
e O( 1log2 n
).
Debowski[27] escreve sobre uma explicacao para a distribuicao das palavras em
linguagens naturais, que e be descrita pela lei de Zipf-Mandelbrot (a frequencia das
palavras e uma lei de inverso de potencia do posto das palavras) e uma versao desta
lei chamada lei de Herdan, que afirma que o numero de palavras distintas e uma lei
de potencia do comprimento do texto. E esta segunda versao que Debowski busca
explicar, e para isso ele busca provar outra proposicao, que afirma que um texto
de comprimento n descrevendo nβ fatos independentes em uma maneira repetitiva
deve conter ao menos nβ/log n, presumindo β ∈ (0, 1).
Para atingir seu objetivo, Debowski escolhe utilizar um codigo baseado em gramaticas
pois sao eficientes na detecao de limites de palavras (tomando palavras nao em sen-
tido estrito, contando expressoes como palavras, como por exemplo New York) e o
numero de nao-terminais numa gramatica mınima pode ser tomado como um indi-
cador para o numero de palavras distintas no texto que ela representa. Ele define
uma classe de transformadas de gramatica codigos baseados em gramaticas que ele
chama admissivelmente mınimos. Transformadas de gramatica codigos baseados
em gramatica admissivelmente mınimos sao aqueles para os quais |B(Γ(W ))| ≤
|B(G)| para todas as gramaticas G que representam w, onde Γ e a transformada de
gramatica e B e o codificador de gramatica; alem disso, a estrutura do codificador
de gramatica e definida em uma forma especıfica. Classes de processos estocasticos
tambem sao definidos para modelar a producao de fatos e textos, e tres teoremas
sao provados utilizando as classes definidas para mostrar uma motivacao para a
conjectura de Hilberg (veja [28]), como esta conjectura implica a lei de Herdan e
explicacoes para essas leis a partir da proposicao introduzida por Debowski.
39
Analises interessantes de codigos baseados em gramaticas sao feitas no artigo,
entretanto, apesar de serem utilizadas propriedades de gramaticas mınimas, ele nao
introduz resultados que possam ser utilizados para o aprimoramento de algoritmos
praticos para a obtencao de transformadas de gramatica mınimas.
Dorier et al [29] introduzem uma abordagem duplamente original: uma nova mo-
delagem de comportamento de entrada/saıda baseado em gramaticas formais e uma
extensao inovadora de codigos baseados em gramaticas para uso como preditores. Os
autores buscam solucionar o problema de que em aplicacoes de computacao de alta
performance E/S e um gargalo, e propoe modelar tanto o acesso temporal quanto
espacial de E/S com uma abordagem contınua, rapidamente convergente, adapta-
tiva, de baixo nıvel (que nao requeira modificacoes no codigo de aplicacoes ou de
bibliotecas de alto nıvel) e agnostica em relacao a aplicacao. Outras tecnicas pre-
viamente empregadas consistem principalmente em metodos estatısticos tais como
modelos ocultos de Markov ou modelos auto-regressivos integrados de media movel
e, de acordo com os autores, abordagens baseadas nestes metodos nao foram, ate
o momento, capazes de preencher todos os requisitos dispostos acima. Os autores
tambem notam que metodos estatısticos sao mais adequados para modelar processos
estocasticos em que ha aleatoriedade, enquanto aplicacoes de computacao de alto
desempenho sao, por sua natureza, altamente determinısticas. Isto torna uma abor-
dagem baseada em gramaticas muito interessante, pois gramaticas podem capturar
a natureza determinıstica e hierarquica da execucao de programas e operacoes de
E/S.
Chamadas de funcoes de E/S de baixo nıvel sao empacotadas e instrumentadas
para registrar o traco das pilhas das chamadas, das quais e mantido um dicionario
em que diferentes pilhas sao assinaladas a sımbolos de contexto distintos, que podem
ser relacionados a tamanhos de acessos e cujas transicoes podem ser relacionadas
a evolucao da posicao de leitura ou escrita e o tempo entre chamadas de E/S. O
algoritmo proposto pelos autores utiliza uma abordagem escalonada em que uma
gramatica principal modela a sequencia de sımbolos de contexto e gramaticas locais
modelam sequencias de tamanhos e saltos nas posicoes de acessos. O tempo entre
acessos nao e modelado por uma gramatica, mas por algumas estatısticas basicas
40
que permitem um agendamento eficiente (tempos mınimo, maximo e medio entre
acessos); a mesma abordagem estatıstica e utilizada se o comprimento da gramatica
local se torna maior que 24 sımbolos. As aplicacoes consideradas nos testes nao
acessam mais de um arquivo simultaneamente, entao este caso nao foi modelado no
algoritmo.
A transformada de gramatica introduzida pelos autores para gerar as gramaticas
locais e a principal e uma extensao do algoritmo Sequitur (que e bastante simi-
lar ao Sequitur Modificado de Yang e Kieffer[3] e foi brevemente descrito na Secao
3.2) em que certos sımbolos terminais sao marcados como preditores de acordo com
operacoes de atualizacao e descoberta e duas novas restricoes relativas a marcacao
de preditores: nao-terminais so podem ser marcados como preditores se o membro
direito de sua regra de producao contem ao menos um preditor, e um sımbolo no
membro direito de uma regra de producao (exceto a do sımbolo de partida) so pode
ser um preditor se o seu membro esquerdo e um preditor no membro direito de
outra regra de producao. A operacao de atualizacao de preditores e feita sempre
que um novo sımbolo e lido da entrada; todos os sımbolos terminais marcados como
preditores sao desmarcados se nao coincidem com o novo sımbolo, as restricoes aos
preditores sao aplicadas, e entao os preditores que coincidem com o sımbolo lido sao
tambem desmarcados e sao agora marcados como preditores os sımbolos seguintes
na sequencia nos membros direitos, a nao ser que o preditor seja o ultimo sımbolo
de uma regra de producao, caso em que os sımbolos seguintes ao nao-terminal cor-
respondente em outras regras de producao serao marcados. Se nenhum sımbolo e
preditor (isto e, nenhum preditor coincidiu com o sımbolo lido e todos foram des-
marcados), e feita a operacao de descoberta em que todos os sımbolos iguais ao
lido sao marcados como preditores, e caso o sımbolo apensado tenha formado um
digrama que seja substituıdo por um nao-terminal na aplicacao das restricoes do
Sequitur, somente sımbolos na regra de producao correspondente serao marcados
como preditores.
Os resultados reportados no artigo sao muito bons, com acertos de predicoes
entre 79.5% e 100% nos cenarios de teste, e isto demonstra que gramaticas podem
codificar eficientemente padroes de sequencias, rapidamente convergindo o modelo
41
a um regime estacionario sem nenhum conhecimento previo da estrutura ou da
estatıstica dos dados, o que e por si so uma confirmacao empırica das qualidades
defendidas por Yang e Kieffer para codigos de compressao baseados em gramaticas.
Se tanto a extensao do Sequitur apresentada quanto a abordagem escalonada sao
bastante especıficas para esta aplicacao, nao deixam de ser excelentes exemplos de
usos possıveis para transformadas de gramatica.
Zhang, Yang e Kieffer[32] estudam o problema da compressao sem perdas de
arvores binarias utilizando codigos baseados em gramativas. A abordagem geral
adotada e muito similar ao caso generico: uma transformada de gramatica e aplicada
para obter uma representacao compacta da arvore binaria original, que em seguida
e comprimida e codificada numa sequencia binaria. A originalidade da abordagem
esta no fato de que o codigo baseado em gramaticas apresentado pretende comprimir
a informacao de uma estrutura e nao de um conteudo, propriamente. Isto e feito
construindo uma gramatica tal que sua arvore de derivacao, retiradas as etiquetas
dos nos, seja igual a arvore que se deseja comprimir. Esta ideia e de certo modo
relacionaa aos codigos estruturados baseados em gramaticas e abordagens similares
investigados Por Yang e Kieffer[43, 26], mas nestes o objetivo nao e comprimir uma
estrutura, as estruturas sao utilizadas como auxiliares na compressao dos dados.
Um algoritmo que codifica univocamente os isomorfismos de uma arvore binaria
nao-trivial e descrito pelos autores. Ele se inicia por uma etiquetagem dos vertices
da arvore t talque a raiz e etiquetada 0 e todas as folhas sao etiquetadas T , e entao
a arvore e percorrida em largura e os vertices restantes sao etiquetados de modo
que, se a sub-arvore com raiz no vertice atual e igual a sub-arvore com raiz em um
vertice que ja foi etiquetado, a mesma etiqueta e aplicada, caso contrario o proximo
numero natural nao utilizado e aplicado como a etiqueta. Os inteiros utilizados como
etiquetas podem ser vistos como o conjunto de nao-terminais de uma gramatica Gt,
e T como o conjunto de terminais. Se N e a cardinalidade do conjunto de todas as
sub-arvores distintas de t, havera N−1 sımbolos nao-terminais na gramatica e o seu
conjunto sera 0, 1, . . . , N − 2. Adicionalmente, a arvore etiquetada sera a arvore
de derivacao de Gt. O proximo passo e codificar Gt em uma sequencia binaria, e
aqui os autores se inspiram em abordagens anteriores e utilizam um procedimento
42
similar ao utilizado para codificar a gramatica no algoritmo hierarquico de Yang
e Kieffer[13], descrito na Secao 3.2.1, e ao utilizado em seu artigo seminal[3]. Os
membros direitos das regras de producao –todos com comprimento 2– sao listados
em uma sequencia S(t); as primeiras ocorrencias da esquerda para a direita dos
sımbolos nao-terminais sao removidas para obter uma nova lista S1(t); o numero de
nao-terminais e codificado em B1 na forma de N − 2 zeros seguidos de um bit 1,
B2 tem comprimento 2N − 2 (isto e, o comprimento de S(t)) e codifica as posicoes
da primeira ocorrencia de cada nao-terminal em S(t), B3 codifica as frequencias
dos nao terminais em N − 1 sequencias alternadas de zeros e uns, a ultima tendo
comprimento 1 (a frequencia de T pode ser computada usando a informacao de B1)
e B4 representa S1(t) utilizando uma codificacao enumerativa.
Uma extensa prova de que tal codigo e universal e otimo para certas classes de
arvores binarias e incluıda no artigo, mas a omitimos aqui nesta revisao
Maruyama et al [36] desenvolvem uma versao contınua de um algoritmo para um
codigo baseado em gramaticas e seu artigo e uma continuacao de trabalhos anteriores
do mesmo grupo. Sakamoto[44] introduziu o algoritmo Levelwise-RePair inspirado
no Re-Pair de Larsson and Moffat[45] (que e muito simples mas de difıcil analise[46])
com a intencao de igualar o melhor resultado conhecido para a taxa de aproximacao
as gramaticas mınimas –O(log2(n/g∗)), onde n e o comprimento da entrada e g∗
e o menor tamanho possıvel para uma gramatica que o representa– usando um
algoritmo simples que nao demande a construcao de arvores de sufixos (que nao
sao eficientes em uso de memoria) e com a mesma complexidade de espaco do Re-
Pair, que como outros algoritmos depende linearmente do comprimento da entrada.
Sakamoto et al [47] entao buscam desenvolver um algoritmo com execucao em tempo
linear e espaco sublinear baseado no menor ancestral comum em arvores binarias
balanceadas; este algoritmo foi posteriormente denominado LCA (de lowest common
ancestor) e e o algoritmo adaptado para o caso contınuo por Maruyama et al no
que foi batizado de algoritmo Online LCA no artigo que ora revisamos.
Os autores primeiro simplificam o algoritmo LCA e entao fazem a extensao para
o caso contınuo. Seu objetivo e minimizar o numero de nao -terminais na gramatica
43
final gerada pela substituicao de pares por nao-terminais. Nota-se tambem que os
autores restringem as gramaticas de modo que suas regras de producao sempre tem
comprimento 2. Sao introduzidas tres regras de decisao para a substituicao de pares:
1. Regra do par repetitivo: Se uma sequencia x contem uma subsequencia de
repeticao maxima x [i, j] = ak, isto e, uma subsequEncia de comprimento
k = j−i+1 emque o sımbolo a e repetido k vezes tal que x [i− 1] , x [j + 1] 6= a,
uma regra de producao A → aa e gerada e x [i, j] e substituıda por outra
repeticao Ak/2 para k par ou x [i, j − 1] e substituıda por A(k−1)/2 para k
ımpar.
2. Regra do par mınimo: Presuma que todos os sımbolos sao representados por
inteiros, se uma subsequencia aiajak e tal que j < i, k entao aj e chamado
mınimo e o par ajak e substituıdo por um nao-terminal.
3. Regra do par maximo: Novamente presuma que todos os sımbolos sao repre-
sentados por inteiros e, alem, que sao folhas ordenadas em uma arvore binaria
T ordenada, completa e com raiz, se uma subsequencia aiajakal e tal que
i < j < k < l or i > j > k > l, se a altura do menor ancestral comum do
par formado por aj e ak e maior que a altura do menor ancestral comum dos
outros pares possıveis, isto e, lca(j, k) > lca(i, j), lca(k, l), entao o par do meio
ajak e um maximo e substituiıdo por um nao-terminal.
Conforme os dados sao lidos para a compressao, o algoritmo sempre avalia as
regras para decidir se o par x[i, i + 1] ou o par x[i + 1, i + 2] sera substituıdo.
A prioridade das regras e a mesma da ordem que elas foram listadas, para evitar
ambiguidade na decisao; primeiro o algoritmo verifica se x[i, i+1] ou x[i+2, i+3] sao
pares repetitivos e, se algum deles for, o par x[i, i+ 1] e substituıdo; caso contrario
se x[i+1, i+2] for repetitivo ele e substituıdo. Se nenhum e repetitivo, verifica-se se
x[i, i+1] e um par mınimo ou maximo, e caso positivo ele e substituıdo, caso contrario
verifica-se o mesmo em relacao ao par x[i+1, i+2] que, caso positivo, e substituıdo.
Se nenhuma das regras e verificada positivamente, x[i, i + 1] e substituıdo. Sempre
que e feita uma substituicao uma nova regra de producao e adicionada a gramatica,
se necessario. Quando o final da sequencia de entrada e alcancado, o algoritmo
44
passa a ler a sequencia modificada pelas substituicoes novamente desde o inıcio e
continua avaliando os pares conforme as regras e fazendo novas substituicoes, ate
que o processo se completa quando a sequencia original se reduz a um unico sımbolo,
que e tomado como o sımbolo de partida da gramatica.
A versao contınua e entao apresentada pelos autores, introduzindo o uso de no
maximo h filas q1, q2, . . . , qh que contem segmentos da sequencia que corresponde a
cada uma das iteracoes do laco externo do algoritmo em batelada descrito acima. O
numero maximo de filas h e portanto limitado a O(log2 n), assim como o numero de
iteracoes do laco. No algoritmo contınuo, todas as filas quando sao criadas ja contem
um sımbolo fictıcio que nao faz parte do alfabeto e nem e admissıvel como sımbolo
nao-terminal; os sımbolos da sequencia a ser comprimida sao entao lidos sequenci-
almente e enfileirados em q1. Se, apos o enfileiramento de um sımbolo, len(q1) ≥ 5,
entao o mesmo procedimento do algoritmo em batelada e utilizado para decidir se
q1[1, 2] ou q1[2, 3] sera susbstituıdo por um nao-terminal. Com a decisao tomada,
q1[0] (isto e, o primeiro sımbolo de q1) e desenfileirado e descartado (na primeira vez
sera o sımbolo artificial, depois sera um sımbolo ja substituıdo) e entao, se q1[1, 2]
sera substituıdo, q1[1] e desenfileirado e um nao-terminal apropriado e enfileirado
em q2, enquanto se q1[2, 3] for substituıdo, q1[1] e q1[2] sao desenfileirados, e q1[1] e
enfileirado em q2 seguido por um nao-terminal apropriado. Note que no final desta
operacao ou o conteudo inicial de q1[2] ou de q1[3] estarao na frente da fila, em q1[0],
e podem ser utilizados na avaliacao das regras mas serao descartados pois ja sao re-
presentados por um nao-terminal em q2. Essas operacoes sao feitas recursivamente
de modo que quando len(q2) ≥ 5 um para sera substituıdo e um nao-terminal enfi-
leirado em q3, e assim por diante ate que todos os sımbolos da sequencia de dados
de entrada tenham sidos processados e todos os sımbolos restantes em filas sao pa-
reados e substituıdos por nao-terminais apropriados ate que um unico nao-terminal
ira resultar da ultima fila utilizada (que sera, no maximo, a fila qh).
Os autores entao propoe um esquema simples para codificar a gramatica obtida,
utilizando a ideia da arvore parcial de derivacao (utilizada por Rytter[48] e tambem
por Yang e Kieffer[26]r). Uma arvore parcial de derivacao e construıda de modo
similar a arvore completa de derivacao, com a diferenca que os nos representando
45
nao-terminais repetidos sao podados e deixados como folhas; deste modo, o numero
de nos internos e o numero de nao-terminais na gramatica e, como neste caso a arvore
e binaria, o numero de folhas e numero de nao-terminais mais um. Os autores propoe
entao codificar esta arvore parcial a percorrendo em pos-ordem e indicando com um
bit para cada no se ele e um no interno ou uma folha, e construindo uma sequencia
das etiquetas das folhas que pode ser codificada em (|N(G)|+1) dlog2(|N(G)|+ |Σ|)e
bits.
Os resultados de testes apresentados pelos autores mostram que para conjuntos
de dados repetitivos o Online LCA obtem melhor taxa de compressao e e uso de
memoria do que o LZW, gzip e bzip, enquanto tanto o Re-Pair e o LZMA obtem
melhores taxas de compressao mas com uso de memoria muito maior do que o do
Online LCA.
Yamagiwa e Sakamoto[39] fazem ainda uma extensao do algoritmo Online LCA
para uma implementacao em FPGA com regras de producao estaticas. Dados de
treino comprimidos pelo Online LCA geram uma gramatica cujas regras de producao
podem ser total ou parcialmente distribuıdas como tabelas estaticas utilizadas por
compressores e decompressores simples que nao atualizam as regras de producao e
nem as transmite. As tabelas podem ser atualizadas de tempos em tempos utli-
zando novos conjuntos de treino, representativos dos dados transmitidos em um
dado perıodo, de modo que as regras guardadas nas tabelas estaticas continuem
sendo capazes de prover uma boa taxa de compressao conforme os padroes dos da-
dos transmitidos mudam ao longo do tempo. O novo algoritmo e nomeado LCA-SLT
(onde SLT e acronimo para Static Lookup Table), e a implementacao em FPGA e
mostrada, mas omitimos aqui os seus detalhes.
3.3.2.3 Aspectos praticos e teoricos da busca por uma gramatica mınima
Revisamos tambem aqui um artigo importante acerca do desafio de se obter a
menor gramatica possıvel que represente uma dada sequencia de dados.
Charikar et al [41] apresentam em seu artigo uma revisao profunda e uma inves-
tigacao teorica dos limites das transformadas de gramatica e dos algoritmos exis-
46
tentes, assim como mostram algoritmos proprios para aproximar a menor gramatica
possıvel, obtendo, na epoca, a melhor taxa de aproximacao teorica conhecida de
O(log2(n/g∗)). Contudo, os autores nao abordam o problema da construcao pratica
de um codigo baseado em gramaticas para compressao de dados e nao se preocupam
com aspectos praticos dos algoritmos tais como compelxidade de tempo e espaco,
taxa de compressao final apos a codificacao da gramatica em uma sequencia binaria,
etc.
Inicialmente, e mostrado que a menor gramatica representando uma dada sequencia
de comprimento n tem tamanho Ω(log2 n) e tambem que sequencias altamente es-
truturadas,que contem muitas repeticoes, sao codificadas por gramaticas menores
que as nao estruturadas, pois se Gα gera α e Gβ gera β, ha uma gramatica de tama-
nho |Gα|+ |Gβ|+ 2 que gera αβ mas que uma de tamanho apenas |Gα|+O(log2 k)
gera αk. Entao os autores mostram de duas maneiras diferentes que a aproximacao
da menor gramatica por uma constante pequena e NP-difıcil, uma presumindo que
as entradas nao sao adequadas para a geracao de gramaticas pequenas e uma presu-
mindo entradas altamente estruturadas e adequadas para a obtencao de gramaticas
pequenas.
O artigo segue entao com a analise das taxas de aproximacao (a gramatica mınima)
de varios dos algoritmos existentes: LZ78 e LZW (O((n/ log2 n)2/3)); a transformada
de bisseccao de Yang e Kieffer[3] (O(√n/ log2 n)), as transformadas MPM de Yang
e Kieffer[20, 14] (O(√
n/ log2 n)), assim como a sua transformada gulosa[13] –que
os autores denominam Sequencial– (Ω(n1/3) e O((n/ log2 n)2/3)) e o algoritmo do
casamento mais longo[3] (Ω(log2 log2 n) e O((n/ log2 n)2/3g∗)); o algoritmo guloso de
Apostolico e Leonardi[49] que traz uma ideia similar a do Casamento mais Longo
mas escolhe subsequencias repetidas que tragam a maior reducao no tamanho da
gramatica ao inves de simplesmente a mais longa (ao menos (5 log 3)/(3 log 5) e
O((n/ log2 n)2/3g∗)); e finalmente o Re-Pair[45], para os quais foram encontrados li-
mites muito largos pois e um algoritmo de difıcil analise (Ω(√log2 n) eO((n/ log2 n)
2/3g∗)).
Os novos algoritmos introduzidos pelos autores tem taxa de aproximacaoO(log32 n)
e O(log2(n/g∗)). O primeiro e um algoritmo recursivo que comeca com a sequencia
47
de entrada completa de comprimento n e a corta ao meio, em duas partes; as partes
sao sobrepostas de modo a formar uma sequencia mais curta, que por sua vez e
cortada nos limites esquerdos de cada uma das partes originais que a constituem,
de modo a formar novas partes, e qualquer parte mais longa que n/2 e dividida pela
metade. Na proxima iteracao, estas partes sao sobrepostas de maneira gulosa para
formar uma nova sequencia ainda mais curta, que tambem sera cortada nos limites
esquerdos das partes que a constituem e cujos pedacos mais longos que n/4 serao
divididos ao meio, e assim por diante ate que na ultima iteracao as pecas sao de
comprimento 2 ou menos; assinalando nao-terminais para as partes em cada iteracao,
cada parte pode ser especificada por pares de terminais (as partes da ultima iteracao)
ou por nao-terminais correspondentes as partes das iteracoes seguintes. O segundo
algoritmo e baseado no LZ77; primeiramente e feita uma passada da esquerda para
a direita na sequencia de dados de entrada para gerar a menor sequencia LZ77, e
entao esta sequencia e analisada e transformada em uma gramatica pela introducao
de nao-terminais para os pares do LZ77.
Os autores reconhecem que os algoritmos apresentados tem como objetivo uma
melhor compreensao analıtica do problema de aproximacao da gramatica mınima
e podem nao ser adequados para a implementacao pratica e usos reais, pois varios
outros fatores estao envolvidos em compressores praticos e eles nao sao abordados
no artigo. Contudo, o artigo traz uma contribuicao muito interessante na forma da
analise dos principais algoritmos disponıveis a epoca, fazendo a primeira abordagem
analıtica do ponto de vista da aproximacao da gramatica mınima e mostrando um
examplo estabelecendo um novo valor para a melhor taxa de aproximacao conhecida.
Li e Chen[40] propoe uma abordagem nao-determinıstica para a construcao de
gramaticas a partir de sequencias com o uso de algoritmos geneticos. Eles buscam
obter gramaticas menores que as obtidas por algoritmos determinısticos baseados
em heurısticas gulosas conhecidos ate o momento e, alem disso, obter diferentes
gramaticas para uma mesma sequencia. O algoritmo genetico proposto pelos au-
tores toma o Sequitur como ponto de partida e referencia; a ideia de digramas
e extendida para trigramas que podem ser classificados em quatro tipos distintos
dependendo se os digramas esquerdo e direito que constituem o trigrama estao pre-
48
sentes ou nao na sequencia parcial ja lida da entrada, e o Sequitur pode ser visto
como um algoritmo de decisao determinıstico que sempre substitui o digrama es-
querdo por um nao-terminal caso ele seja repetido, mas nunca o direito. Contudo
os autores notam que pode ser benefico pular o primeiro sımbolo e substituir o di-
grama direito, e extendem aqui uma proposta anterior de um dos autores de decidir
aleatoriamente entre a substituicao do digrama esquerdo ou direito quando ambas
sao possıveis[50] e desenvolvem um algoritmo genetico em que os cromossomos sao
sequencias binarias do mesmo comprimento da entrada codificando uma sequencia
de decisoes de substituicao do digrama esquerdo ou direito.
Os resultados obtidos mostram que foi possıvel obter gramaticas mais curtas que
as obtidas com o Sequitur e a convergencia rapida do algoritmo. Nao ha, contudo,
comparacoes com outras transformadas de gramatica mais recentes que o Sequitur
e nao analisam a performance do algoritmo para entradas muito grandes.
49
Capıtulo 4
Um novo algoritmo criptografico
Feita uma revisao dos fundamentos teoricos dos codigos baseados em gramaticas
para compressao de dados e um levantamento dos mais recentes desenvolvimentos em
algoritmos para a area, nesta secao segue-se para o objetivo final deste trabalho, que
visa obter novos algoritmos criptografico a partir de codigos baseados em gramaticas
para compressao de dados.
Como ponto de partida para a formulacao de algoritmos criptograficos, foi es-
colhido o algoritmo Online LCA de Maruyama et al [36]. Ve-se como vantagens
do Online LCA a sua simplicidade, bom equilıbrio entre complexidade de tempo
e espaco do algoritmo, assim como seu desempenho de aproximacao da gramatica
mınima.
4.1 Sımbolo de partida
A ideia basica aplicada aqui e que, assim como no caso da compressao, pode-se
produzir uma gramatica a partir da sequencia de dados de entrada. Escondendo
alguma parte desta gramatica busca-se impedir a obtencao da sequencia de dados
original e ate mesmo de subsequencias dela a partir da parte restante que e gravada
ou transmitida.
Uma opcao obvia seria esconder a regra de producao do sımbolo de partida e
toma-la como chave; ela e parte necessaria para a obtencao da sequencia original
pois e justamente a peca utilizada para se dar o inıcio do processo de substituicoes
50
paralelas que produz a sequencia original e decodifica a gramatica. Entretanto,
no Online LCA todas as gramaticas produzidas tem regras de producao com ape-
nas dois sımbolos em seus membros direitos (de maneira similar a forma normal
de Chomsky), o que tornaria muito curta a chave e consequentemente facil a de-
criptacao por forca bruta. Mesmo que se aplicassem substituicoes, como por exemplo
aplicacoes seguidas das regras de reducao de Yang e Kieffer, poder-se-ia obter uma
chave mais longa, mas seria ainda possıvel somente com o restante da gramatica
obter trechos de texto pleno que comprometam a seguranca e a privacidade dos da-
dos, possibilitando ate, dependendo do contexto e do conhecimento de quem tenta
o ataque, a obtencao do entendimento dos dados originais ou uma boa aproximacao
destes.
Esta ideia e suas deficiencias podem ser mais claramente vistas com o auxılio de
um exemplo. Considere a gramatica a seguir, gerada pelo algoritmo Online LCA,
que teve a regra de seu sımbolo de partida omitida:
A1 → A3A2∗→ A rose is a rose is a
A2 → A6A5∗→ s a rose is a
A3 → A12A7∗→ A rose i
A4 → A9A8∗→ rose.
A5 → A11A10∗→ e is a
A6 → A10A9∗→ s a ros
A7 → A15A11∗→ ose i
A8 → e.
A9 → A16A15∗→ ros
A10 → sA13∗→ s a
A11 → eA14∗→ e i
A12 → AA16∗→ A r
A13 → a
A14 → i
A15 → os
A16 → r
51
E trivial verificar que a regra do sımbolo de partida e formada por A1 e A4, dado
que sao os unicos nao-terminais que nao aparecem em nenhuma regra, e a simples
inspecao das expansoes dos dois nao-terminais nos leva a provavel conclusao quanto
ao conteudo da regra do sımbolo de partida e, consequentemente, da sequencia de
entrada:
S → A1A4∗→ A rose is a rose is a rose.
Reduzindo a gramatica utilizando as regras de Yang e Kieffer, podemos obter:
A9 → ros
A18 → A9e is a∗→ rose is a
Com a gramatica irredutıvel obtida, mais informacao e escondida com a omissao
da regra do sımbolo de partida, porem ve-se que pode-se obter, por inspecao, tre-
chos da sequencia original, que podem se mostrar relevantes e comprometer a se-
guranca dos dados ou permitir que um palpite informado se aproxime ou revele a
provavel sequencia original; qualquer um que seja familiarizado com a famosa frase
de Gertrude Stein, sabendo que ” rose is a” e ” ros” sao elementos repetitivos na
sequencia original, poderia deduzir o conteudo como ”A rose is a rose is a rose.”
ou ”Rose is a rose is a rose is a rose.” ou algo similar.
Claramente o exemplo mostrado e demasiado simples e, na pratica, com entradas
mais longas e complexas, a gramatica reduzida dificultaria bastante a obtencao da
sequencia original completa (ou de um palpite razoavel). Contudo, a possibilidade da
obtencao de trechos continua presente, e o acesso a um trecho contendo informacao
sensıvel pode ser o suficiente para um ataque bem-sucedido.
4.2 Regras de Producao
Uma outra opcao, mais interessante, e olhar para o codificador de gramatica do
Online LCA para extrair a chave. O codificador primeiro computa a arvore parcial
de derivacao da gramatica construıda, e entao codifica a sequencia de nos desta
arvore, indicando o tipo de cada no, se interno (ate 2h−1 nos) ou folha (ate 2h nos).
Por ser uma arvore parcial de derivacao, aproximadamente metade dos nos serao
52
Figura 4.1: Exemplo de arvore parcial de derivacao de uma gramatica
S
A1
A3
A12
A A16
r
A7
A15
o s
A11
e A14
i
A2
A6
A10
s A13
a
A9
A16 A15
A5
A11 A10
A4
A9 A8
e .
folhas, e dentre eles pode haver tanto sımbolos do alfabeto da sequencia original
como sımbolos nao-terminais da gramatica.
Para codificar a sequencia dos nos, o algoritmo percorre a arvore pos-ordem e,
com a ordem fixa e sendo cada no interno etiquetado por nao-terminais distintos,
apenas indicar a existencia dos nos internos e o suficiente para especifica-los por
completo, enquanto os nos folha necessitam ser codificados nao so com a indicacao
de que sao nos folha como tambem com a etiqueta do no, seja ela um terminal ou
um nao-terminal.
Codificando-se separadamente os nos folha do restante da estrutura da arvore e
os tomando como chave, nao so sera difıcil obter a sequencia original sem a posse
da chave, como sera tambem difıcil recuperar ate parcialmente a sequencia. A
unica informacao a que se tem acesso parcial e a estrutura hierarquica da sequencia,
capturada pela gramatica e presente na arvore parcial de derivacao.
Pode-se ver na Figura 4.2, por exemplo, a arvore parcial de derivacao da gramatica
do exemplo da secao anterior. Seguindo o esquema do algoritmo Online LCA, esta
arvore pode ter sua estrutura representada pela sequencia de bits F que indica, para
cada no da arvore percorrida pos-ordem, se e folha (bit 1) ou nao (bit 0):
F = 11100110111000011100110011000111000
53
E os nos folha podem ser representados pela sequencia L de suas etiquetas,
tambem percorrida a arvore pos-ordem:
L = A rose is aA16A15A11A10A9e.
A implementacao de referencia do Online LCA codifica a arvore parcial escrevendo
uma sequencia entrelacando F e L, e o arquivo comprimido pode ser representado
por:
LCA = 1A1 1r001o1s01e1 1i00001s1 1a001A161A15001A111A100001A91e1.000
Simplesmente utilizar L como chave e F como a saıda criptografada seria, contudo,
tambem uma solucao ingenua – embora mais segura que a utilizacao da regra do
sımbolo de partida como chave – pois logo se ve que |L| >> |F |, ou seja, a chave
seria muito maior que o proprio arquivo criptografado.
4.3 Sımbolos terminais
No caso exemplo da secao anterior, como o texto e pequeno, o numero de terminais
na sequencia das folhas |T (L)| e mais que o dobro do numero de nao-terminais
|N(L)|, contudo para casos de sequencias mais longas, que sao os casos de uso
reais, tipicamente teremos que |N(L)| >> |T (L)|. Pode-se tirar proveito desta
observacao e, ao inves de tomar L como chave, tomar T (L). Observando-se que as
folhas etiquetadas por nao-terminais na realidade tambem representam a estrutura
hierarquica dos dados, posto que de maneira abreviada, ve-se que uma separacao
entre estrutura e conteudo se pode dar de maneira completa somente com esta
separacao entre as folhas terminais e nao-terminais.
Pode-se adotar um procedimento bastante simples para efetuar a extracao da
chave e criptografia da sequencia de entrada utilizando a ideia exposta acima ti-
rando proveito do sımbolo fictıcio utilizado para inicializar as filas no Online LCA,
cujo codigo nao e admissıvel nem como terminal nem como nao-terminal. No mo-
mento da codificacao da gramatica, caso a etiqueta da folha a ser gravado seja um
sımbolo terminal, basta substituı-lo pelo sımbolo fictıcio D0 e apensar o terminal
54
a chave. Para decodificar o arquivo, a unica mudanca necessaria no algoritmo de
descompressao e a detecao do sımbolo fictıcio e a leitura do sımbolo correto na chave.
Retomando o exemplo da sequencia de entrada ”A rose is a rose is a rose.”,
obterıamos entao duas sequencias de saıda, a sequencia comprimida criptografada
LCA′ e a chave T (L):
L′ = D0D0D0D0D0D0D0D0D0D0D0A16A15A11A10A9D0D0
LCA′ = interleave(F,L′) =
1D01D01D0001D01D001D01D01D000001D01D0...
...1D0001A161A15001A111A100001A91D01D0000
T (L) = A rose is ae.
O efeito desta operacao e, em suma, gerar uma sequencia com o mesmo tama-
nho da sequencia original, porem consistindo de repeticoes de um unico sımbolo
fictıcio, e comprimida utilizando a estrutura da sequencia original. De posse de uma
chave composta pela sequencia dos sımbolos terminais nas etiquetas das folhas da
arvore de derivacao parcial percorrida pos-ordem, pode-se regerar a sequencia ori-
ginal ao reintroduzir os terminais apropriados na gramatica e, em seguida, descom-
primindo a sequencia normalmente pelo processo gerativo de substituicoes paralelas
pela aplicacao das regras de producao da gramatica.
Esta ideia de separar conteudo e estrutura esta relacionada as ideias de Yang e
Kieffer quanto a gramaticas estruturais vs gramaticas representativas[43, 26, 32],
especialmente o codigo de refinamento em que sao enviadas uma gramatica estru-
turalmente identica a que gera a sequencia original e as transformacoes necessarias
para obter a gramatica que gera tal sequencia[26].
4.4 Avaliacao empırica do algoritmo proposto
Uma implementacao do algoritmo proposto, baseada na implementacao de re-
ferencia do algoritmo Online LCA, pode ser consultada no Apendice A. Esta imple-
mentacao foi utilizada para comprimir e criptografar arquivos do corpus Pizza&Chili [51]
em uma avaliacao empırica do algoritmo proposto, batizado Crypto LCA.
55
Como metricas para a avaliacao foram utilizados o numero de aprovacoes na
bateria de testes da versao 2.1.2 da STS (Statistical Test Suite), uma suıte de tes-
tes estatısticos de aleatoriedade para aplicacoes criptograficas disponibilizada pelo
NIST, instituto governamental dos Estados Unidos, assim como a medida de taxa
de entropia de Shannon em bits de informacao por byte.
Com a STS, pode-se aplicar uma bateria de 188 testes a amostras de fluxos de bits
para determinar se diferentes caracterısticas estatısticas das amostras se adequam
aos valores esperados de fluxos aleatorios de bits, e a suıte se destina a validacao
de geradores de numeros aleatorios e pseudo-aleatorios utilizados em algoritmos
criptograficos[52].
Para reproduzir os testes, sao necessarios os seguintes comandos, que presumem
que os arquivos a serem testados estao no diretorio test inputs, os resultados serao
guardados no diretorio test outputs e a STS esta instalada no diretorio sts-2.1.2,
todos os tres diretorios estando no mesmo nıvel:
1 cd sts-2.1.2
2
3 for file in $(ls ../test_inputs/*); do
4 echo "0
5 $file
6 1
7 0
8 100
9 1" | ./assess 10000
10
11 cp ./experiments/AlgorithmTesting/finalAnalysisReport.txt
../test_outputs/assess_10k_$(basename $file).txt
12 done
Foram amostrados 100 fluxos de 10000 bits cada de cada arquivo para os testes,
utilizando os parametros sugeridos por padrao onde necessario. Dos 188 testes
56
disponıveis, 26 nao obtiveram resultados definidos para a maioria das amostras (por
sua limitacao de tamanho) e foram excluıdos da avaliacao, restando 162 testes cujos
resultados foram levados em conta. Para que um arquivo seja considerado aprovado
num teste, foi seguida a recomendacao da STS de que ao menos 96 das 100 sequencias
amostradas do arquivo tenham sido aprovadas pelo teste.
O algoritmo proposto neste trabalho nao se utiliza de geradores de numeros
(pseudo-)aleatorios, contudo se espera que sequencias criptografadas tambem exi-
bam caracterısticas estatısticas de aleatoriedade e, portanto, as aprovacoes na suıte
de testes do NIST sao empregadas aqui como uma indicacao de quanto os arquivos
criptografados produzidos se aproximam da aleatoriedade estatıstica e, consequente-
mente, da dificuldade de predicao das sequencias produzidas. E neste mesmo sentido
que e interpretada a entropia das sequencias que, quanto mais proxima de 8 bits
por byte, mais a sequencia se aproxima da aleatoriedade. A entropia foi medida
utilizando o utilitario ent[53], e esta medicao pode ser reproduzida para todos os
arquivos de um diretorio atraves dos comandos abaixo:
1 for file in $(ls ./test_inputs/*); do
2 ent $file > ./test_outputs/ent_$(basename $file).txt
3 done
Os numeros de aprovacoes nos testes da STS, a entropia e o tamanho dos arqui-
vos do Pizza&Chili originais, comprimidos pelo Online LCA e criptografados pelo
Crypto LCA se encontram, respectivamente, nas Tabelas 4.1, 4.2 e 4.3. Na Tabela
4.4 estao listados o tamanho e a entropia das chaves geradas pelo Crypto LCA.
Como era esperado dada a natureza da operacao de compressao, ve-se que a
compressao pelo algoritmo Online LCA aumenta significativamente a entropia dos
arquivos, tendo sido aumentada em media em 141%, sendo o menor acrescimo, de
44%, para o arquivo coreutils, que e o que possui maior entropia original, e o maior
acrescimo, de 301%, para o arquivo influenza, que possui a menor entropia original.
A entropia dos arquivos comprimidos ficou, na media, aproximadamente 0.166 bits
abaixo dos 8 bits esperados para sequencias perfeitamente aleatorias.
57
Tambem de acordo com o esperado, pode-se observar que a aplicacao do algoritmo
criptografico proposto, Crypto LCA, diminui ligeiramente a entropia dos arquivos,
sendo o valor observado em media 0.009 bits menor em relacao a simples compressao.
Em termos percentuais, este valor representa uma diminuicao media 0.001% da
entropia em decorrencia da criptografia. Esta diminuicao e esperada pois a sequencia
produzida pelo algoritmo criptografico e muito similar a sequencia produzida pela
compressao, com a unica diferenca sendo a substituicao de todas as ocorrencias de
sımbolos terminais, que podem ser quaisquer sımbolos do alfabeto, pelo sımbolo
fictıcio, que sera sempre o mesmo.
Analisando o resultado pelo numero de aprovacoes na bateria de testes da STS,
vemos que este numero aumentou ou ao menos se manteve estavel se compararmos
os arquivos criptografados em relacao aos comprimidos. Isto indica que, mesmo
com a diminuicao da entropia em relacao a compressao, a criptografia ajudou a
mascarar certos tipos de padroes dos dados melhor do que a compressao pura e
simples, tambem de acordo com o efeito desejado.
Contudo, a mesma analise do resultado pela otica do numero de aprovacoes numa
comparacao entre os arquivos originais e os comprimidos ou criptografados mostra
que para 7 (dos 11) arquivos o numero de aprovacoes aumentou apos o processa-
mento, contudo para 4 arquivos este numero diminuiu. Estes arquivos sao coreutils,
einstein.de.txt, einstein.en.txt e influenza.
Os arquivos einstein.de.txt e einstein.en.txt consistem de varias repeticoes dos
artigos da Wikipedia sobre Albert Einstein em alemao e ingles, respectivamente,
coreutils e uma concatenacao de arquivos de codigo fonte, e influenza e o sequen-
ciamento genetico do vırus da gripe.
Todos os 4 tem, por sua natureza, conteudos altamente estruturados e repetiti-
vos, seja por serem repeticoes (einstein.de.txt, einstein.en.txt), textos sujeitos a
fortes restricoes sintaticas e vocabulares e de natureza hierarquica (coreutils) ou
uma sequencia com longas estruturas repetitivas e complementares (influenza)[54].
Como a compressao pelo Online LCA (e tambem, por extensao, a criptografia pelo
58
Tabela 4.1: Testes estatısticos nos arquivos originais do corpus Pizza&Chili
Arquivo Tamanho (bytes) Aprovacoes STS (/162) Entropia (bits/byte)
cere 461286644 67 2.191510
coreutils 205281778 75 5.465309
dblp.xml 296135874 78 5.262064
einstein.de.txt 92758441 94 5.038626
einstein.en.txt 467626544 95 4.962309
english 2210395553 79 4.525110
Escherichia Coli 112689515 87 2.000835
influenza 154808555 110 1.973055
kernel 257961616 90 5.379011
para 429265758 109 2.124905
world leaders 46968181 112 3.471487
Crypto LCA) busca representar justamente a estrutura dos dados, e de se espe-
rar que estas estruturas repetitivas gerem padroes no resultado final, o que pode
acarretar este efeito observado.
59
Tabela 4.2: Testes estatısticos nos arquivos comprimidos pelo Online LCA
Arquivo Tamanho (bytes) Aprovacoes STS (/162) Entropia (bits/byte)
cere.lca 14871788 101 7.807951
coreutils.lca 10688340 31 7.917588
dblp.xml.lca 68854732 97 7.818900
einstein.de.txt.lca 282488 73 7.924042
einstein.en.txt.lca 781380 61 7.902004
english.lca 759864780 104 7.652208
Escherichia Coli.lca 14003896 105 7.688689
influenza.lca 7030156 56 7.917138
kernel.lca 5605988 123 7.872786
para.lca 19119780 93 7.765356
world leaders.lca 1574904 128 7.905300
Tabela 4.3: Testes estatısticos nos arquivos criptografados pelo Crypto LCA
Arquivo Tamanho (bytes) Aprovacoes STS (/162) Entropia (bits/byte)
cere.clca 14871788 101 7.807703
coreutils.clca 10688340 37 7.908567
dblp.xml.clca 68854732 105 7.817553
einstein.de.txt.clca 282488 80 7.880171
einstein.en.txt.clca 781380 67 7.875517
english.clca 759864780 108 7.651920
Escherichia Coli.clca 14003896 105 7.688579
influenza.clca 7030156 93 7.917038
kernel.clca 5605988 124 7.861296
para.clca 19119780 93 7.765122
world leaders.clca 1574904 135 7.895641
60
Tabela 4.4: Testes estatısticos nas chaves criptograficas geradas pelo Crypto LCA
Arquivo Tamanho (bytes) Entropia (bits/byte)
cere.clca.key 5248 3.978653
coreutils.clca.key 179576 5.205402
dblp.xml.clca.key 150944 4.820551
einstein.de.txt.clca.key 13984 5.977262
einstein.en.txt.clca.key 25908 5.658158
english.clca.key 323300 4.244618
Escherichia Coli.clca.key 1852 4.491471
influenza.clca.key 1300 4.974419
kernel.clca.key 89400 5.219574
para.clca.key 6104 4.028607
world leaders.clca.key 21792 5.611751
61
Capıtulo 5
Conclusoes
Neste trabalho foi demonstrada viabilidade da construcao de um algoritmo crip-
tografico baseado em gramaticas livres de contexto em que a propria gramatica
representa o texto criptografado.
Tanto quanto se sabe, a abordagem aqui utilizada e original, e difere de outras
abordagens baseadas em gramaticas livres de contexto pois nao utiliza gramaticas
arbitrarias como chave ou segredo, mas infere uma gramatica a partir dos dados a
serem criptografados e extrai, desta gramatica inferida, elementos que impecam a
obtencao dos dados originais, de modo que a propria gramatica seja a representacao
criptografada e comprimida dos dados.
5.1 Consideracoes finais
Esta abordagem e inspirada nas aplicacoes de compressao de dados baseadas em
gramaticas livres de contexto e na observacao de que a gramatica livre de contexto
inferida e, sobretudo, uma representacao da estrutura dos dados, exprimida por
suas regras de producao e sımbolos nao-terminais, e o conteudo dos dados, que ori-
ginalmente consiste somente dos sımbolos terminais que neles aparecem, e destilado
de modo a que se reduza a um mınimo de sımbolos terminais e padroes curtos de
sımbolos terminais que precisam ser inseridos, reinseridos e repetidos na aplicacao
das regras de producao para que se gere os dados originais.
62
Sem este conjunto de sımbolos e padroes curtos de sımbolos, que representam
uma pequena parcela da gramatica, se torna impossıvel gerar os dados originais,
pois as regras de producao e os sımbolos nao-terminais perdem todas as referencias
que os ligam ao conteudo dos dados. Este conjunto de sımbolos e padroes terminais
se torna, entao, a chave do algoritmo criptografico aqui proposto.
Para atender aos objetivos iniciais de que o algoritmo criptografico seja simples,
de baixa complexidade computacional tanto temporal quanto espacial, foi escolhido
como base um algoritmo de compressao com estas caracterısticas. Adicionalmente,
pelo fato de o algoritmo criptografico proposto manter as caracterısticas de com-
pressao do algoritmo de compressao subjacente – o que e, por si so, bastante in-
teressante uma vez que, de modo geral, algoritmos criptograficos nao comprimem
os dados – foi levada em conta tambem a capacidade de compressao do algoritmo
escolhido.
Por apresentar um bom compromisso entre todas as caracterısticas desejaveis, foi
escolhido oOnline LCA como base para a construcao do algoritmo criptografico, e di-
ferentes maneiras de adaptar este algoritmo foram avaliadas do ponto de vista teorico
quanto as possibilidades de ataques e comparada a outras abordagens possıveis para
chegar ao algoritmo proposto Crypto LCA.
Uma implementacao do algoritmo foi desenvolvida e resultados de testes empıricos
demonstram que o conceito apresentado e viavel e sobre o qual maiores investigacoes
sao desejaveis, tanto teoricas quanto praticas.
Os casos de uso inicialmente vislumbrados para o algoritmo criptografico introdu-
zido neste trabalho sao os que envolvem a transmissao segura e eficiente de grandes
volumes de dados por um canal inseguro, tirando vantagem da compressao obtida
com a criptografia. A chave, relativamente pequena, pode transmitida fora de banda
ou por um canal seguro mas de baixa capacidade.
63
5.2 Trabalhos Futuros
Trabalhos futuros sugeridos abrangem: uma analise da robustez do algoritmo em
relacao a ataques diversos, tais como analisar quais informacoes se poderia extrair
da estrutura, precisar o nıvel de dificuldade para encontrar a chave ou uma chave
suficientemente proxima que permita uma aproximacao dos dados originais; a in-
vestigacao mais aprofundada das propriedades das gramaticas como representacoes
de estruturas (que muitas vezes apresentam fortes padroes) e sua relacao com os
resultados dos testes estatısticos de aleatoriedade e forca criptografica; adicionar a
chave permutacoes na ordem de codificacao dos nos para dificultar a obtencao da
estrutura correta e uma apoximacao dos dados originais por busca da chave, aumen-
tar a entropia e aumentar a taxa de aprovacao nos testes estatısticos do NIST; a
introducao de aleatoriedade na inferencia da gramatica, de modo que sejam produ-
zidas diferentes gramaticas para uma mesma sequencia de entrada, diminuindo as
chances de ataques em que candidatos sao criptografados e suas saıdas comparadas
ao alvo para determinar possıveis correspondencias; e pesquisar a possibilidade de
estender o algoritmo de modo a prover tambem garantias quanto a integridade dos
dados ou, ainda, tolerancia a erros de transmissao.
64
Referencias Bibliograficas
[1] SHANNON, C. E., “A mathematical theory of communication”, The Bell Sys-
tem Technical Journal, v. 27, n. 3, pp. 379–423, July 1948.
[2] CHOMSKY, N., “Three models for the description of language”, IRE Transac-
tions on Information Theory, v. 2, n. 3, pp. 113–124, September 1956.
[3] KIEFFER, J. C., YANG, E.-H., “Grammar-Based Codes: A New Class of Uni-
versal Lossless Source Codes”, IEEE Trans. Inform. Theory, v. 46, pp. 737–754,
May 2000.
[4] WAYNER, P., Disappearing Cryptography: Information Hiding: Steganography
& Watermarking, The Morgan Kaufmann Series in Software Engineering and
Programming. Elsevier Science, 2009.
[5] BASSIL, Y., “An Image Steganography Scheme using Randomized Algorithm
and Context-Free Grammar”, Journal of Advanced Computer Science & Tech-
nology, v. 1, n. 4, pp. 291–305, 2012.
[6] SINGH, A., DOS SANTOS, A. L. M., “Grammar Based off Line Generation
of Disposable Credit Card Numbers”. In: Proceedings of the 2002 ACM Sym-
posium on Applied Computing, SAC ’02, pp. 221–228, New York, NY, USA,
2002.
[7] ANGLUIN, D., KHARITONOV, M., “When Won’t Membership Queries
Help?”, Journal of Computer and System Sciences, v. 50, n. 2, pp. 336 – 355,
1995.
[8] GOLD, E. M., “Language identification in the limit”, Information and Control,
v. 10, n. 5, pp. 447 – 474, 1967.
65
[9] BUCCAFURRI, F., LAX, G., “A Light Number-Generation Scheme for Fea-
sible and Secure Credit-Card-Payment Solutions”. In: Psaila, G., Wagner, R.
(eds.), E-Commerce and Web Technologies: 9th International Conference, EC-
Web 2008 Turin, Italy, September 3-4, 2008 Proceedings, pp. 11–20, Berlin,
Heidelberg, 2008.
[10] MOLLOY, I., LI, J., LI, N., “Dynamic Virtual Credit Card Numbers”. In:
Dietrich, S., Dhamija, R. (eds.), Financial Cryptography and Data Security:
11th International Conference, FC 2007, and 1st International Workshop on
Usable Security, USEC 2007, Scarborough, Trinidad and Tobago, February 12-
16, 2007. Revised Selected Papers, pp. 208–223, Berlin, Heidelberg, 2007.
[11] BUCCAFURRI, F., LAX, G., “Implementing disposable credit card numbers
by mobile phones”, Electronic Commerce Research, v. 11, n. 3, pp. 271–296,
2011.
[12] SINGH, A., DOS SANTOS, A. L. M., “Context Free Grammar for the Ge-
neration of a One Time Authentication Identity”. In: Proceedings of the 17th
International FLAIRS Conference, 2004.
[13] YANG, E.-H., KIEFFER, J. C., “Efficient Universal Lossless Data Compresion
Algorithms Based on a Greedy Sequential Grammar Transform –Part One:
Without Context Models”, IEEE Trans. Inform. Theory, v. 46, pp. 755–777,
May 2000.
[14] YANG, E.-H., KALTCHENKO, A., KIEFFER, J. C., “Universal Lossless Data
Compression With Side information by Using a Conditional MPM Grammar
Transform”, IEEE Trans. Inform. Theory, v. 47, pp. 2130–2150, September
2001.
[15] NEVILL-MANNING, C., WITTEN, I., “Identifying hierarchical structure in
sequences: A linear-time algorithm”, J. Artificial Intell. Res., v. 7, pp. 67–82,
1997.
[16] KONTOYIANNIS, I., “Pointwise redundancy in lossy data compression and
universal lossy data compression”, IEEE Trans. Inform. Theory, v. 46,
pp. 136–152, 2000.
66
[17] COVER, T., “Enumerative source encoding”, IEEE Trans. Inform. Theory,
v. IT-19, pp. 73–77, January 1973.
[18] KIEFFER, J. C., YANG, E.-H., “Lossless data compression algorithms based
on substitution tables”. In: Proc. IEEE 1998 Canadian Conf. Electrical and
Computer Engineering, pp. 629–632, Waterloo, Ont., Canada, May 1998.
[19] YANG, E.-H., JIA, Y., “Efficient grammar-based data compression algorithms:
Complexity, implementation, and simulation results”. paper in preparation.
[20] KIEFFER, J. C., YANG, E.-H., NELSON, G., et al., “Lossless compres-
sion via multilevel pattern matching”, IEEE Trans. Inform. Theory, v. 46,
pp. 1227–1245, July 2000.
[21] YANG, E.-H., JIA, Y., “Universal lossless coding of sources with large or un-
bounded alphabets”. In: et al., I. A. (ed.), Numbers, Information and Comple-
xity, Norwell, MA, Kluwer, pp. 421–442, 2000.
[22] YANG, E.-H., HE, D.-K., “Interactive Encoding and Decoding for One Way Le-
arning: Near Lossless Recovery With Side Information at the Decoder”, IEEE
Transactions on Information Theory, v. 56, pp. 1808–1824, April 2010.
[23] YANG, E.-H., HE, D.-K., “Two results on interactive lossless source encoding
and decoding with side information at the decoder”. In: Third International
Conference on Communications and Networking in China. ChinaCom 2008,
pp. 90–94, Hangzhou, August 2008.
[24] MENG, J., YANG, E.-H., “Interactive Encoding and Decoding Based on Binary
LDPC Codes With Syndrome Accumulation”, IEEE Transactions on Informa-
tion Theory, v. 59, pp. 3068–3103, May 2013.
[25] MENG, J., YANG, E.-H., HE, D.-K., “Linear Interactive Encoding and Deco-
ding for Lossless Source Coding With Decoder Only Side Information”, IEEE
Transactions on Information Theory, v. 57, pp. 5281–5297, August 2011.
[26] KIEFFER, J. C., YANG, E.-H., “Grammar-Based Lossless Universal Refi-
nement Source Coding”, IEEE Transactions on Information Theory, v. 50,
pp. 1415–1424, July 2004.
67
[27] DEBOWSKI, L., “On the Vocabulary of Grammar-Based Codes and the Lo-
gical Consistency of Texts”, IEEE Transactions on Information Theory, v. 57,
pp. 4589–4599, July 2011.
[28] DEBOWSKI, L., “A Preadapted Universal Switch Distribution for Testing
Hilberg’s Conjecture”, IEEE Transactions on Information Theory, v. 61,
pp. 5708–5715, October 2015.
[29] DORIER, M., IBRAHIM, S., ANTONIU, G., et al., “Omnisc’IO: A Grammar-
Based Approach to Spatial and Temporal I/O Patterns Prediction”. In: Pro-
ceedings of the International Conference for High Performance Computing,
Networking, Storage and Analysis, pp. 623–634, Piscataway, NJ, 2014.
[30] DOSHI, J., GANDHI, S., “Enhanced arithmetic coding using total frequency in
power of 2 amp; processing multi-bits at a time”, Sixth International Conference
on Contemporary Computing (IC3), pp. 1–6, Aug 2013.
[31] JAIN, S., BANSAL, R. K., “On Match Lengths, Zero Entropy, and Large
Deviations–With Application to Sliding Window Lempel-Ziv Algorithm”, IEEE
Transactions on Information Theory, v. 61, pp. 120–132, January 2015.
[32] ZHANG, J., YANG, E.-H., KIEFFER, J. C., “A Universal Grammar-Based
Code for Lossless Compression of Binary Trees”, IEEE Transactions on Infor-
mation Theory, v. 60, pp. 1373–1386, March 2014.
[33] ZHANG, J., YANG, E.-H., KIEFFER, J. C., “Redundancy analysis in lossless
compression of a binary tree via its minimal DAG representation”. In: 2013
IEEE International Symposium on Information Theory Proceedings (ISIT), pp.
1914–1918, July 2013.
[34] KUZUOKA, S., WATANABE, S., “An Information-Spectrum Approach to
Weak Variable-Length Source Coding With Side-Information”, IEEE Transac-
tions on Information Theory, v. 61, pp. 3559–3573, June 2015.
[35] ZHENG, L., YANG, E.-H., “On optimum fixed-rate causal scalar quantization
design for causal video coding”. In: 12th Canadian Workshop on Information
Theory (CWIT), pp. 58–61, 2011.
68
[36] MARUYAMA, S., TAKEDA, M., NAKAHARA, M., et al., “An Online Algo-
rithm for Lightweight Grammar-Based Compression”. In: First International
Conference on Data Compression, Communications and Processing (CCP), pp.
19–28, June 2011.
[37] HU, N., YANG, E.-H., “Fast Mode Selection for HEVC Intra-Frame Coding
With Entropy Coding Refinement Based on a Transparent Composite Mo-
del”, IEEE Transactions on Circuits and Systems for Video Technology, v. 25,
pp. 1521–1532, September 2015.
[38] WANG, N., HAN, J., FANG, J., “An Anomaly Detection Algorithm Based
on Lossless Compression”. In: 7th International Conference on Networking,
Architecture and Storage (NAS), pp. 31–38, 2012.
[39] YAMAGIWA, S., SAKAMOTO, H., “A reconfigurable stream compression
hardware based on static symbol-lookup table”. In: 2013 IEEE International
Conference on Big Data, pp. 86–93, On page(s), 2013.
[40] LI, Y., CHEN, J. X., “A nondeterministic approach to infer context free gram-
mar from sequence”. In: 11th International Computer Conference on Wavelet
Active Media Technology and Information Processing (ICCWAMTIP), pp. 1–9,
2014.
[41] CHARIKAR, M., LEHMAN, E., LIU, D., et al., “The smallest grammar pro-
blem”, IEEE Transactions on Information Theory, v. 51, pp. 2554–2576, July
2005.
[42] SAKR, S., “XML Compression Techniques: A Survey and Comparison”, Jour-
nal of Computer and System Sciences (JCSS), v. 75, pp. 303–322, August 2009.
[43] KIEFFER, J. C., YANG, E.-H., “Structured grammar-based codes for universal
lossless data compression”, Commun. Inform. and Syst., v. 2, n. 1, pp. 29–52,
June 2002.
[44] SAKAMOTO, H., “A fully linear-time approximation algorithm for grammar-
based compression”, J. Discrete Algorithms, v. 3, pp. 416–430, June 2005.
69
[45] LARSSON, N. J., MOFFAT, A., “Offline dictionary-based compression”. In:
Proceedings of the IEEE, pp. 1722–1732, November 2000.
[46] NAVARRO, G., RUSSO, L., “Re-pair Achieves High-Order Entropy”. In: 2008
Data Compression Conference (DCC 2008), pp. 537–537, Snowbird, UT, 2008.
[47] SAKAMOTO, H., KIDA, T., SHIMOZONO, S., String Processing and Infor-
mation Retrieval: 11th International Conference, SPIRE 2004, Padova, Italy,
October 5-8, 2004. Proceedings, chapter A Space-Saving Linear-Time Algorithm
for Grammar-Based Compression, Berlin, Heidelberg, Springer Berlin Heidel-
berg, pp. 218–229, 2004.
[48] RYTTER, W., “Application of lempel-ziv factorization to the approximation of
grammar-based compression”, Theor. Comput. Sci., v. 302, pp. 211–222, June
2003.
[49] APOSTOLICO, A., LONARDI, S., “Off-line compression by greedy textual
substitution”, Proc. IEEE, v. 88, n. 11, pp. 1733–1744, November 2000.
[50] LI, Y., LIN, J., OATES, T., “Visualizing Variable-Length Time Series Motifs”.
In: Proceedings of the 2012 SIAM International Conference on Data Mining
(SDM 2012), pp. 895–906, April 2012.
[51] FERRAGINA, P., GONZaLEZ, R., NAVARRO, G., et al., “Compressed
Text Indexes: From Theory to Practice”, J. Exp. Algorithmics, v. 13,
pp. 12:1.12–12:1.31, Feb. 2009.
[52] RUKHIN, A., SOTO, J., NECHVATAL, J., et al., A Statistical Test Suite for
Random and Pseudorandom Number Generators for Cryptographic Applicati-
ons, Report, National Institute of Standards and Technology, Gaithersburg,
MD, 2010.
[53] WALKER, J., “Ent - A Pseudorandom Sequence Test”, http://www.fourmi-
lab.ch/random/, 2008, (Acesso em 29 de Marco de 2016).
[54] CHERNIAVSKY, N., LADNER, R., Grammar-based Compression of DNA Se-
quences, Report, University of Washington, 2004.
70
Apendice A
Implementacao do algoritmo
Crypto LCA
Neste apendice se encontra o codigo-fonte completo de uma implementacao do
algoritmo criptografico Crypto LCA, proposto neste trabalho. O algoritmo e baseado
no algoritmo de compressao Online LCA, cuja implementacao escrita e disponibili-
zada por Maruyama[36] no endereco eletronico http://code.google.com/p/lcacomp/
serviu de base para esta aqui apresentada.
71
A.1 bits.c
1 /*2 * Copyright (c) 2011-2012 Shirou Maruyama3 *4 * Redistribution and use in source and binary forms, with
or without5 * modification, are permitted provided that the following
conditions6 * are met:7 *8 * 1. Redistributions of source code must retain the above
Copyright9 * notice, this list of conditions and the following
disclaimer.10 *11 * 2. Redistributions in binary form must reproduce the
above Copyright12 * notice, this list of conditions and the following
disclaimer in the13 * documentation and/or other materials provided with the
distribution.14 *15 * 3. Neither the name of the authors nor the names of its
contributors16 * may be used to endorse or promote products derived from
this17 * software without specific prior written permission.18 */19
20
21 #include "bits.h"22
23 #define INLINE __inline24 //#define DEBUG25
26 #define W_BITS 3227 #define BITIN_BUF_LEN 32768 /* BITIN_BUF_LEN*sizeof(uint)
bytes */28 #define BITOUT_BUF_LEN 32768 /* BITOUT_BUF_LEN*sizeof(uint)
bytes */29
30 #ifdef DEBUG31 // function for debug32 static33 void printBinary(uint x) 34 int bit = 1, i;35 char c[W_BITS];36
37 for (i = 0; i < W_BITS; i++) 38 if (x & bit)39 c[i] = ’1’;40 else41 c[i] = ’0’;42 bit <<= 1;
72
43 44 for (i = W_BITS - 1; i >= 0; i--) 45 putchar(c[i]);46 47 printf("\n");48 49 #endif50
51 BITOUT *createBitout(FILE *output) 52 BITOUT *b = (BITOUT*)malloc(sizeof(BITOUT));53
54 b->output = output;55 b->emplen = W_BITS;56 b->bitbuf = 0;57 b->buftop = (uint*)calloc(BITOUT_BUF_LEN+1, sizeof(uint));58 b->bufpos = b->buftop;59 b->bufend = b->buftop + BITOUT_BUF_LEN;60 return b;61 62
63 INLINE64 void writeBits(BITOUT *b, uint x, uint wblen) 65 uint s;66
67 #ifdef DEBUG68 if (wblen > W_BITS) 69 fprintf(stderr, "Error: length of write bits (%d) is
longer than %d\n",70 wblen, W_BITS);71 exit (1);72 73 if (wblen == 0) 74 return;75 76 #endif77
78 if (wblen < b->emplen) 79 b->emplen -= wblen;80 b->bitbuf |= x << b->emplen;81 82 else 83 s = wblen - b->emplen;84 b->bitbuf |= x >> s;85 *(b->bufpos) = b->bitbuf;86 b->bufpos++;87 b->emplen = W_BITS - s;88 if (b->emplen != W_BITS) 89 b->bitbuf = x << b->emplen;90 91 else 92 b->bitbuf = 0;93 94
95 if (b->bufpos == b->bufend)
73
96 fwrite(b->buftop, sizeof(uint), BITOUT_BUF_LEN,b->output);
97 memset(b->buftop, 0, sizeof(uint)*BITOUT_BUF_LEN);98 b->bufpos = b->buftop;99
100 101 102
103 void flushBitout(BITOUT *b)104 105 uint n;106 if (b->emplen != W_BITS) 107 *(b->bufpos) = b->bitbuf;108 b->bufpos++;109 110 n = fwrite(b->buftop, sizeof(uint), b->bufpos -
b->buftop, b->output);111 memset(b->buftop, 0, sizeof(uint)*BITOUT_BUF_LEN);112 b->bufpos = b->buftop;113 b->bitbuf = 0;114 b->emplen = W_BITS;115 116
117 BITIN *createBitin(FILE *input) 118 BITIN *b = (BITIN*)malloc(sizeof(BITIN));119
120 b->input = input;121 b->bitlen = 0;122 b->bitbuf = 0;123 b->buftop = (uint*)calloc(BITIN_BUF_LEN, sizeof(uint));124 b->bufpos = b->bufend = b->buftop;125
126 return b;127 128
129 INLINE130 uint readBits(BITIN *b, uint rblen) 131 uint x;132 uint s, n;133
134 #ifndef DEBUG135 if (rblen > W_BITS) 136 fprintf(stderr, "Error: length of read bits (%d) is
longer than %d \n",137 rblen, W_BITS);138 exit (1);139 140 if (rblen == 0) 141 return 0;142 143 #endif144
145 if (rblen < b->bitlen) 146 x = b->bitbuf >> (W_BITS - rblen);147 b->bitbuf <<= rblen;
74
148 b->bitlen -= rblen;149 150 else 151 if (b->bufpos == b->bufend) 152 n = fread(b->buftop, sizeof(uint), BITIN_BUF_LEN,
b->input);153 b->bufpos = b->buftop;154 b->bufend = b->buftop + n;155 if (b->bufend < b->buftop) 156 fprintf(stderr, "Error: new bits buffer was not
loaded.\n");157 exit(1);158 159 160
161 s = rblen - b->bitlen;162 x = b->bitbuf >> (W_BITS - b->bitlen - s);163 b->bitbuf = *(b->bufpos);164 b->bufpos++;165 b->bitlen = W_BITS - s;166 if (s != 0) 167 x |= b->bitbuf >> b->bitlen;168 b->bitbuf <<= s;169 170 171
172 return x;173
75
A.2 bits.h
1 /*2 * Copyright (c) 2011-2012 Shirou Maruyama3 *4 * Redistribution and use in source and binary forms, with
or without5 * modification, are permitted provided that the following
conditions6 * are met:7 *8 * 1. Redistributions of source code must retain the above
Copyright9 * notice, this list of conditions and the following
disclaimer.10 *11 * 2. Redistributions in binary form must reproduce the
above Copyright12 * notice, this list of conditions and the following
disclaimer in the13 * documentation and/or other materials provided with the
distribution.14 *15 * 3. Neither the name of the authors nor the names of its
contributors16 * may be used to endorse or promote products derived from
this17 * software without specific prior written permission.18 */19
20 #ifndef BITS_H21 #define BITS_H22
23 #include <stdlib.h>24 #include <stdio.h>25 #include <string.h>26 #include <limits.h>27 #include "lcacommon.h"28
29 typedef struct bit_input 30 FILE *input;31 uint bitlen;32 uint bitbuf;33 uint *bufpos;34 uint *buftop;35 uint *bufend;36 BITIN;37
38 typedef struct bit_output 39 FILE *output;40 uint emplen;41 uint bitbuf;42 uint *bufpos;43 uint *buftop;44 uint *bufend;
76
45 BITOUT;46
47
48 BITIN *createBitin(FILE *input);49 uint readBits(BITIN *bitin, uint readBitLen);50
51 BITOUT *createBitout(FILE *output);52 void writeBits(BITOUT *bitout, uint symbol, uint
writeBitLen);53 void flushBitout(BITOUT *bitout);54
55
56 /*57 //upper bits mask for uint58 static const uint UBM[] = 59 0x00000000,60 0x00000001, 0x00000003, 0x00000007, 0x0000000F,61 0x0000001F, 0x0000003F, 0x0000007F, 0x000000FF,62 0x000001FF, 0x000003FF, 0x000007FF, 0x00000FFF,63 0x00001FFF, 0x00003FFF, 0x00007FFF, 0x0000FFFF,64 0x0001FFFF, 0x0003FFFF, 0x0007FFFF, 0x000FFFFF,65 0x001FFFFF, 0x003FFFFF, 0x007FFFFF, 0x00FFFFFF,66 0x01FFFFFF, 0x03FFFFFF, 0x07FFFFFF, 0x0FFFFFFF,67 0x1FFFFFFF, 0x3FFFFFFF, 0x7FFFFFFF, 0xFFFFFFFF68 ;69
70 //lower bits mask for uint71 static const uint LBM[] = 72 0x00000000,73 0x80000000, 0xC0000000, 0xE0000000, 0xF0000000,74 0xF8000000, 0xFC000000, 0xFE000000, 0xFF000000,75 0xFF800000, 0xFFC00000, 0xFFE00000, 0xFFF00000,76 0xFFF80000, 0xFFFC0000, 0xFFFE0000, 0xFFFF0000,77 0xFFFF8000, 0xFFFFC000, 0xFFFFE000, 0xFFFFF000,78 0xFFFFF800, 0xFFFFFC00, 0xFFFFFE00, 0xFFFFFF00,79 0xFFFFFF80, 0xFFFFFFC0, 0xFFFFFFE0, 0xFFFFFFF0,80 0xFFFFFFF8, 0xFFFFFFFC, 0xFFFFFFFE, 0xFFFFFFFF,81 ;82 */83
84
85 #endif /* BITS_H */
77
A.3 cfg2enc.c
1 /*2 * Copyright (c) 2016 Joao Faria3 * Copyright (c) 2011-2012 Shirou Maruyama4 *5 * Redistribution and use in source and binary forms, with
or without6 * modification, are permitted provided that the following
conditions7 * are met:8 *9 * 1. Redistributions of source code must retain the above
Copyright10 * notice, this list of conditions and the following
disclaimer.11 *12 * 2. Redistributions in binary form must reproduce the
above Copyright13 * notice, this list of conditions and the following
disclaimer in the14 * documentation and/or other materials provided with the
distribution.15 *16 * 3. Neither the name of the authors nor the names of its
contributors17 * may be used to endorse or promote products derived from
this18 * software without specific prior written permission.19 */20
21 #include "cfg2enc.h"22
23 #define INLINE __inline24
25 static void encodeCFG_rec (CODE code, EDICT *ed, BITOUT*output);
26 static void putLeaf (uint num_code, CODE lv_code, BITOUT*output);
27 static void putParen (uchar b, BITOUT *output);28
29 static INLINE30 uint bits (uint n)31 uint b = 0;32 while (n)33 b++; n >>= 1; 34 return b;35 36
37 static INLINE38 void putLeaf(uint num_code, uint lvcode, BITOUT *output) 39 uint bits_len = bits(num_code);40 writeBits(output, lvcode, bits_len);41 42
78
43 static INLINE44 void putParen(uchar b, BITOUT *output) 45 if (b == OP) 46 writeBits(output, OP, 1);47 48 else 49 writeBits(output, CP, 1);50 51 52
53 static54 void encodeCFG_rec(uint code, EDICT *ed, BITOUT *output) 55 if (ed->tcode[code] == DUMMY_CODE) 56 encodeCFG_rec(ed->rule[code].left, ed, output);57 encodeCFG_rec(ed->rule[code].right, ed, output);58 ed->tcode[code] = ++ed->newcode;59 putParen(CP, output);60 61 else 62 putParen(OP, output);63 if (code < CHAR_SIZE) 64 putLeaf(ed->newcode, code, output);65 66 else 67 putLeaf(ed->newcode, ed->tcode[code], output);68 69 70 71
72 static73 void encodeCFG_crypt_rec(uint code, EDICT *ed, BITOUT
*output, BITOUT *key) 74 if (ed->tcode[code] == DUMMY_CODE) 75 encodeCFG_crypt_rec(ed->rule[code].left, ed, output,
key);76 encodeCFG_crypt_rec(ed->rule[code].right, ed, output,
key);77 ed->tcode[code] = ++ed->newcode;78 putParen(CP, output);79 80 else 81 putParen(OP, output);82 if (code < CHAR_SIZE) 83 putLeaf(ed->newcode, code, key);84 putLeaf(ed->newcode, DUMMY_CODE, output);85 86 else 87 putLeaf(ed->newcode, ed->tcode[code], output);88 89 90 91
92 void EncodeCFG(EDICT *ed, FILE *output) 93 BITOUT *bitout;94 printf("Encoding CFG ... ");
79
95 fflush(stdout);96 ed->newcode = CHAR_SIZE;97 fwrite(&ed->txt_len, sizeof(uint), 1, output);98 fwrite(&ed->num_rules, sizeof(uint), 1, output);99 bitout = createBitout(output);
100 encodeCFG_rec(ed->start, ed, bitout);101 putParen(CP, bitout);102 flushBitout(bitout);103 printf("Done!\n");104 105
106 void EncodeCFG_crypt(EDICT *ed, FILE *output, FILE *key) 107 BITOUT *bitout, *bitkey;108 printf("Encoding and encrypting CFG ... ");109 fflush(stdout);110 ed->newcode = CHAR_SIZE;111 fwrite(&ed->txt_len, sizeof(uint), 1, output);112 fwrite(&ed->num_rules, sizeof(uint), 1, output);113 bitout = createBitout(output);114 bitkey = createBitout(key);115 encodeCFG_crypt_rec(ed->start, ed, bitout, bitkey);116 putParen(CP, bitout);117 flushBitout(bitout);118 flushBitout(bitkey);119 printf("Done!\n");120 121
122 EDICT *ReadCFG(FILE *input) 123 uint i;124 uint num_rules, txt_len;125 EDICT *ed;126 RULE *rule;127 CODE *tcode;128
129 fread(&txt_len, sizeof(uint), 1, input);130 fread(&num_rules, sizeof(uint), 1, input);131 rule = (RULE *)malloc(sizeof(RULE) * num_rules);132
133 printf("num_rules = %d\n", num_rules);134
135 for (i = 0; i <= CHAR_SIZE; i++) 136 rule[i].left = (CODE)i;137 rule[i].right = DUMMY_CODE;138 139
140 fread(rule+CHAR_SIZE+1, sizeof(RULE),num_rules-(CHAR_SIZE+1), input);
141
142 tcode = (CODE*)malloc(sizeof(CODE)*num_rules);143 for (i = 0; i <= CHAR_SIZE; i++) 144 tcode[i] = i;145 146 for (i = CHAR_SIZE+1; i < num_rules; i++) 147 tcode[i] = DUMMY_CODE;148
80
149
150 ed = (EDICT *)malloc(sizeof(EDICT));151 ed->txt_len = txt_len;152 ed->num_rules = num_rules;153 ed->start = num_rules-1;154 ed->rule = rule;155 ed->tcode = tcode;156 ed->newcode = CHAR_SIZE;157 return ed;158 159
160 void DestructEDict(EDICT *ed)161 162 if (ed == NULL) return;163 if (ed->rule != NULL) free(ed->rule);164 if (ed->tcode != NULL) free(ed->tcode);165 free(ed);166
81
A.4 cfg2enc.h
1 /*2 * Copyright (c) 2016 Joao Faria3 * Copyright (c) 2011-2012 Shirou Maruyama4 *5 * Redistribution and use in source and binary forms, with
or without6 * modification, are permitted provided that the following
conditions7 * are met:8 *9 * 1. Redistributions of source code must retain the above
Copyright10 * notice, this list of conditions and the following
disclaimer.11 *12 * 2. Redistributions in binary form must reproduce the
above Copyright13 * notice, this list of conditions and the following
disclaimer in the14 * documentation and/or other materials provided with the
distribution.15 *16 * 3. Neither the name of the authors nor the names of its
contributors17 * may be used to endorse or promote products derived from
this18 * software without specific prior written permission.19 */20
21 #ifndef CFG2ENC_H22 #define CFG2ENC_H23
24 #include<stdio.h>25 #include<stdlib.h>26 #include<string.h>27 #include<math.h>28 #include"bits.h"29 #include"lcacommon.h"30
31 typedef struct EncodeDictionary32 33 uint txt_len;34 uint num_rules;35 CODE start;36 RULE *rule;37 CODE *tcode;38 CODE newcode;39 EDICT;40
41 EDICT *ReadCFG(FILE *input);42 void EncodeCFG(EDICT *dict, FILE *output);43 void EncodeCFG_crypt(EDICT *dict, FILE *output, FILE *key);44 void DestructEDict(EDICT *dict);
82
45
46 #endif /* CFG2ENC_H */
83
A.5 cfg2txt.c
1 /*2 * Copyright (c) 2011-2012 Shirou Maruyama3 *4 * Redistribution and use in source and binary forms, with
or without5 * modification, are permitted provided that the following
conditions6 * are met:7 *8 * 1. Redistributions of source code must retain the above
Copyright9 * notice, this list of conditions and the following
disclaimer.10 *11 * 2. Redistributions in binary form must reproduce the
above Copyright12 * notice, this list of conditions and the following
disclaimer in the13 * documentation and/or other materials provided with the
distribution.14 *15 * 3. Neither the name of the authors nor the names of its
contributors16 * may be used to endorse or promote products derived from
this17 * software without specific prior written permission.18 */19
20 // Restore CFG_file to the TXT_file21
22 #include <stdio.h>23 #include <stdlib.h>24 #include <string.h>25 #include <math.h>26 #include "lcacommon.h"27
28 static29 void restoreString(RULE *rule, CODE code, FILE *output)30 31 CODE left, right;32
33 left = rule[code].left;34 right = rule[code].right;35 if (code == left && right == DUMMY_CODE) 36 fputc(code, output);37 else 38 restoreString(rule, left, output);39 restoreString(rule, right, output);40 41 42
43 int main(int argc, char *argv[])44
84
45 FILE *input, *output;46 CODE start;47 uint num_rules;48 uint txt_len;49 uint i;50 RULE *rule;51
52 if (argc != 3) 53 printf("usage: %s target_cfg_file output_txt_file\n",
argv[0]);54 exit(1);55 56
57 input = fopen(argv[1], "rb");58 output = fopen(argv[2], "w");59 if (input == NULL || output == NULL) 60 puts("File open error at the beginning.");61 exit(1);62 63
64 fread(&txt_len, sizeof(uint), 1, input);65 fread(&num_rules, sizeof(uint), 1, input);66 start = num_rules - 1;67
68 rule = (RULE*)malloc(sizeof(RULE)*num_rules);69 if (rule == NULL) 70 puts("Memory allocate error.");71 exit(1);72 73
74 for (i = 0; i <= CHAR_SIZE; i++) 75 rule[i].left = i;76 rule[i].right = DUMMY_CODE;77 78
79 fread(rule+CHAR_SIZE+1, sizeof(RULE),num_rules-(CHAR_SIZE+1), input);
80 printf("Expanding CFG...");81 fflush(stdout);82 restoreString(rule, start, output);83 printf("done!!\n");84
85 fclose(input);86 fclose(output);87 free(rule);88 return;89
85
A.6 enc2txt.c
1 /*2 * Copyright (c) 2016 Joao Faria3 * Copyright (c) 2011-2012 Shirou Maruyama4 *5 * Redistribution and use in source and binary forms, with
or without6 * modification, are permitted provided that the following
conditions7 * are met:8 *9 * 1. Redistributions of source code must retain the above
Copyright10 * notice, this list of conditions and the following
disclaimer.11 *12 * 2. Redistributions in binary form must reproduce the
above Copyright13 * notice, this list of conditions and the following
disclaimer in the14 * documentation and/or other materials provided with the
distribution.15 *16 * 3. Neither the name of the authors nor the names of its
contributors17 * may be used to endorse or promote products derived from
this18 * software without specific prior written permission.19 */20
21 #include"enc2txt.h"22
23 #define INLINE __inline24 #define OUTPUT_BUFF_SIZE 3276825
26 static char wbuffer[OUTPUT_BUFF_SIZE];27 static uint buf_pos = 0;28
29 static uint bits(uint n);30 static void expandLeaf(RULE *rule, CODE code, FILE *output);31
32 static INLINE33 uint bits (uint n)34 35 uint b = 0;36 while (n)37 b++; n >>= 1; 38 return b;39 40
41 static INLINE42 void expandLeaf(RULE *rule, CODE leaf, FILE *output) 43 if (leaf < CHAR_SIZE) 44 wbuffer[buf_pos++] = (char)leaf;
86
45 if (buf_pos == OUTPUT_BUFF_SIZE) 46 fwrite(wbuffer, 1, OUTPUT_BUFF_SIZE, output);47 buf_pos = 0;48 49 50 else 51 expandLeaf(rule, rule[leaf].left, output);52 expandLeaf(rule, rule[leaf].right, output);53 54 55
56 void DecodeCFG(FILE *input, FILE *output) 57 uint i;58 RULE *rule;59 uint num_rules, txt_len;60 BITIN *bitin;61 uint exc, sp;62 uint stack[256];63 CODE newcode, leaf;64 uint bit_len;65 uchar paren;66
67 fread(&txt_len, sizeof(uint), 1, input);68 fread(&num_rules, sizeof(uint), 1, input);69 printf("txt_len = %d, num_rules = %d\n", txt_len,
num_rules);70 rule = (RULE*)malloc(sizeof(RULE)*num_rules);71 for (i = 0; i <= CHAR_SIZE; i++) 72 rule[i].left = (CODE)i;73 rule[i].right = DUMMY_CODE;74 75
76 for (i = CHAR_SIZE+1; i < num_rules; i++) 77 rule[i].left = DUMMY_CODE;78 rule[i].right = DUMMY_CODE;79 80
81 printf("Decompressing ... ");82 fflush(stdout);83 bitin = createBitin(input);84 newcode = CHAR_SIZE;85 exc = 0; sp = 0;86 while (1) 87 paren = readBits(bitin, 1);88 if (paren == OP) 89 exc++;90 bit_len = bits(newcode);91 leaf = readBits(bitin, bit_len);92 expandLeaf(rule, leaf, output);93 stack[sp++] = leaf;94 95 else 96 if (--exc == 0) break;97 newcode++;98 rule[newcode].right = stack[--sp];
87
99 rule[newcode].left = stack[--sp];100 stack[sp++] = newcode;101 102 103 fwrite(wbuffer, 1, buf_pos, output);104 printf("Done!\n");105 free(rule);106 107
108 void DecodeCFG_crypt(FILE *input, FILE *output, FILE *key) 109 uint i;110 RULE *rule;111 uint num_rules, txt_len;112 BITIN *bitin, *bitkey;113 uint exc, sp;114 uint stack[256];115 CODE newcode, leaf;116 uint bit_len;117 uchar paren;118
119 fread(&txt_len, sizeof(uint), 1, input);120 fread(&num_rules, sizeof(uint), 1, input);121 printf("txt_len = %d, num_rules = %d\n", txt_len,
num_rules);122 rule = (RULE*)malloc(sizeof(RULE)*num_rules);123 for (i = 0; i <= CHAR_SIZE; i++) 124 rule[i].left = (CODE)i;125 rule[i].right = DUMMY_CODE;126 127
128 for (i = CHAR_SIZE+1; i < num_rules; i++) 129 rule[i].left = DUMMY_CODE;130 rule[i].right = DUMMY_CODE;131 132
133 printf("Decompressing ... ");134 fflush(stdout);135 bitin = createBitin(input);136 bitkey = createBitin(key);137 newcode = CHAR_SIZE;138 exc = 0; sp = 0;139 while (1) 140 paren = readBits(bitin, 1);141 if (paren == OP) 142 exc++;143 bit_len = bits(newcode);144 leaf = readBits(bitin, bit_len);145 if(leaf == DUMMY_CODE) 146 leaf = readBits(bitkey, bit_len);147 148 expandLeaf(rule, leaf, output);149 stack[sp++] = leaf;150 151 else 152 if (--exc == 0) break;
88
153 newcode++;154 rule[newcode].right = stack[--sp];155 rule[newcode].left = stack[--sp];156 stack[sp++] = newcode;157 158 159 fwrite(wbuffer, 1, buf_pos, output);160 printf("Done!\n");161 free(rule);162
89
A.7 enc2txt.h
1 /*2 * Copyright (c) 2016 Joao Faria3 * Copyright (c) 2011-2012 Shirou Maruyama4 *5 * Redistribution and use in source and binary forms, with
or without6 * modification, are permitted provided that the following
conditions7 * are met:8 *9 * 1. Redistributions of source code must retain the above
Copyright10 * notice, this list of conditions and the following
disclaimer.11 *12 * 2. Redistributions in binary form must reproduce the
above Copyright13 * notice, this list of conditions and the following
disclaimer in the14 * documentation and/or other materials provided with the
distribution.15 *16 * 3. Neither the name of the authors nor the names of its
contributors17 * may be used to endorse or promote products derived from
this18 * software without specific prior written permission.19 */20
21
22 #ifndef ENCODE2CFG_H23 #define ENCODE2CFG_H24
25 #include<stdio.h>26 #include<stdlib.h>27 #include<string.h>28 #include<math.h>29 #include"bits.h"30 #include"lcacommon.h"31
32 void DecodeCFG(FILE *input, FILE *output);33 void DecodeCFG_crypt(FILE *input, FILE *output, FILE *key);34
35 #endif /* ENCODE2CFG_H */
90
A.8 lcacommon.h
1 /*2 * Copyright (c) 2011-2012 Shirou Maruyama3 *4 * Redistribution and use in source and binary forms, with
or without5 * modification, are permitted provided that the following
conditions6 * are met:7 *8 * 1. Redistributions of source code must retain the above
Copyright9 * notice, this list of conditions and the following
disclaimer.10 *11 * 2. Redistributions in binary form must reproduce the
above Copyright12 * notice, this list of conditions and the following
disclaimer in the13 * documentation and/or other materials provided with the
distribution.14 *15 * 3. Neither the name of the authors nor the names of its
contributors16 * may be used to endorse or promote products derived from
this17 * software without specific prior written permission.18 */19
20 #include <stdbool.h>21
22 #ifndef LCACOMMON_H23 #define LCACOMMON_H24
25 #ifndef LOG226 # define LOG2(X) (log((double)(X))/log((double)2))27 #endif28
29 #ifndef uchar30 typedef unsigned char uchar;31 #endif32 #ifndef uint33 typedef unsigned int uint;34 #endif35 #ifndef ulong36 typedef unsigned long ulong;37 #endif38
39 #ifndef __bool_true_false_are_defined40 #define __bool_true_false_are_defined41 typedef _Bool bool;42 #define false 043 #define true 144 #endif
91
45
46 #ifndef CODE47 typedef unsigned int CODE;48 #endif49
50 typedef struct Rule 51 CODE left;52 CODE right;53 RULE;54
55 #define CHAR_SIZE 25656 #define DUMMY_CODE (CODE)25657
58 #define OP 159 #define CP 060
61 static const uint primes[] = 62 /* 0*/ 8 + 3,63 /* 1*/ 16 + 3,64 /* 2*/ 32 + 5,65 /* 3*/ 64 + 3,66 /* 4*/ 128 + 3,67 /* 5*/ 256 + 27,68 /* 6*/ 512 + 9,69 /* 7*/ 1024 + 9,70 /* 8*/ 2048 + 5,71 /* 9*/ 4096 + 3,72 /*10*/ 8192 + 27,73 /*11*/ 16384 + 43,74 /*12*/ 32768 + 3,75 /*13*/ 65536 + 45,76 /*14*/ 131072 + 29,77 /*15*/ 262144 + 3,78 /*16*/ 524288 + 21,79 /*17*/ 1048576 + 7,80 /*18*/ 2097152 + 17,81 /*19*/ 4194304 + 15,82 /*20*/ 8388608 + 9,83 /*21*/ 16777216 + 43,84 /*22*/ 33554432 + 35,85 /*23*/ 67108864 + 15,86 /*24*/ 134217728 + 29,87 /*25*/ 268435456 + 3,88 /*26*/ 536870912 + 11,89 /*27*/ 1073741824 + 85,90 091 ;92
93 #endif /* LCACOMMON_H */
92
A.9 lcacomp.c
1 #include <stdio.h>2 #include <stdlib.h>3 #include <string.h>4 #include "txt2cfg_online.h"5 #include "cfg2enc.h"6 #include "enc2txt.h"7
8 EDICT *convertDict(DICT *dict)9
10 EDICT *edict = (EDICT*)malloc(sizeof(EDICT));11 uint i;12 edict->txt_len = dict->txt_len;13 edict->start = dict->num_rules-1;14 edict->rule = dict->rule;15 edict->num_rules = dict->num_rules;16 edict->tcode = dict->h_list;17 edict->newcode = CHAR_SIZE;18
19 for (i = 0; i <= CHAR_SIZE; i++) 20 edict->tcode[i] = i;21 22 for (i = CHAR_SIZE+1; i < dict->num_rules; i++) 23 edict->tcode[i] = DUMMY_CODE;24 25
26 free(dict->h_entry);27 free(dict);28 return edict;29 30
31 int decompression(char *input_filename, char*output_filename)
32 33 FILE *input, *output;34
35 input = fopen(input_filename, "rb");36 output = fopen(output_filename, "w");37 if (input == NULL || output == NULL) 38 printf("File open error.\n");39 return 0;40 41 DecodeCFG(input, output);42 fclose(input); fclose(output);43 return 1;44 45
46 int compression(char *input_filename, char *output_filename)47 48 FILE *input, *output;49 DICT *dict;50 EDICT *edict;51
52 input = fopen(input_filename, "r");
93
53 output = fopen(output_filename, "wb");54 if (input == NULL || output == NULL) 55 puts("File open error at the beginning.");56 return 0;57 58
59 dict = GrammarTrans_LCA(input);60 edict = convertDict(dict);61
62 EncodeCFG(edict, output);63 DestructEDict(edict);64 fclose(input);65 fclose(output);66 return 1;67 68
69 void printUsage(char *program_name)70 71 printf("\n");72 printf("---Usage-------------------------------------------------------------\n");73 printf("%s (c|d) <input_file> <output_file>\n",
program_name);74 printf("c = Compresses <input_file> with LCA-online and
creates <output_file>.\n");75 printf("d = Decompresses <input_file> and creates
<output_file>.\n");76 printf("---------------------------------------------------------------------\n");77 printf("\n");78 79
80 int main(int argc, char *argv[])81 82
83 if (argc != 4) 84 printUsage(argv[0]);85 exit(0);86 87
88 if (!strcmp(argv[1], "c")) 89 compression(argv[2], argv[3]);90 91 else if (!strcmp(argv[1], "d")) 92 decompression(argv[2], argv[3]);93 94 else 95 printf("Unexpected argment!\n");96 printUsage(argv[0]);97 exit(1);98 99
100 exit(0);101
94
A.10 lcacrypt.c
1 #include <stdio.h>2 #include <stdlib.h>3 #include <string.h>4 #include "txt2cfg_online.h"5 #include "cfg2enc.h"6 #include "enc2txt.h"7
8 EDICT *convertDict(DICT *dict)9
10 EDICT *edict = (EDICT*)malloc(sizeof(EDICT));11 uint i;12 edict->txt_len = dict->txt_len;13 edict->start = dict->num_rules-1;14 edict->rule = dict->rule;15 edict->num_rules = dict->num_rules;16 edict->tcode = dict->h_list;17 edict->newcode = CHAR_SIZE;18
19 for (i = 0; i <= CHAR_SIZE; i++) 20 edict->tcode[i] = i;21 22 for (i = CHAR_SIZE+1; i < dict->num_rules; i++) 23 edict->tcode[i] = DUMMY_CODE;24 25
26 free(dict->h_entry);27 free(dict);28 return edict;29 30
31 int decompression(char *input_filename, char*output_filename, char *key_filename)
32 33 FILE *input, *output, *key;34
35 input = fopen(input_filename, "rb");36 key = fopen(key_filename, "rb");37 output = fopen(output_filename, "w");38 if (input == NULL || output == NULL || key == NULL) 39 printf("File open error.\n");40 return 0;41 42 DecodeCFG_crypt(input, output, key);43 fclose(input); fclose(output); fclose(key);44 return 1;45 46
47 int compression(char *input_filename, char*output_filename, char *key_filename)
48 49 FILE *input, *output, *key;50 DICT *dict;51 EDICT *edict;
95
52
53 input = fopen(input_filename, "r");54 output = fopen(output_filename, "wb");55 key = fopen(key_filename, "wb");56 if (input == NULL || output == NULL || key == NULL) 57 puts("File open error at the beginning.");58 return 0;59 60
61 dict = GrammarTrans_LCA(input);62 edict = convertDict(dict);63
64 EncodeCFG_crypt(edict, output, key);65 DestructEDict(edict);66 fclose(input);67 fclose(output);68 fclose(key);69 return 1;70 71
72 void printUsage(char *program_name)73 74 printf("\n");75 printf("---Usage--------------------------------------------------------------------------------------\n");76 printf("%s (c|d) <input_file> <output_file>
<key_file>\n", program_name);77 printf("c = Compresses/encrypts <input_file> with
LCA-online and creates <output_file> and<key_file>.\n");
78 printf("d = Decompresses/decrypts <input_file> with<key_file> and creates <output_file>.\n");
79 printf("----------------------------------------------------------------------------------------------\n");80 printf("\n");81 82
83 int main(int argc, char *argv[])84 85
86 if (argc != 5) 87 printUsage(argv[0]);88 exit(0);89 90
91 if (!strcmp(argv[1], "c")) 92 compression(argv[2], argv[3], argv[4]);93 94 else if (!strcmp(argv[1], "d")) 95 decompression(argv[2], argv[3], argv[4]);96 97 else 98 printf("Unexpected argment!\n");99 printUsage(argv[0]);
100 exit(1);101 102
96
103 exit(0);104
97
A.11 txt2cfg online.c
1 /*2 * Copyright (c) 2011-2012 Shirou Maruyama3 *4 * Redistribution and use in source and binary forms, with
or without5 * modification, are permitted provided that the following
conditions6 * are met:7 *8 * 1. Redistributions of source code must retain the above
Copyright9 * notice, this list of conditions and the following
disclaimer.10 *11 * 2. Redistributions in binary form must reproduce the
above Copyright12 * notice, this list of conditions and the following
disclaimer in the13 * documentation and/or other materials provided with the
distribution.14 *15 * 3. Neither the name of the authors nor the names of its
contributors16 * may be used to endorse or promote products derived from
this17 * software without specific prior written permission.18 */19
20 #include "txt2cfg_online.h"21
22 //#define DEBUG23 #define INLINE __inline24
25 #define INIT_RLBUF_LEN (256*1024) //initial size of bufferfor rule[]
26 #define RLBUF_RESIZE_FACTOR (1.5) //resize factor of bufferfor rule[].
27 #define INIT_PRIMES_INDEX (13) //initial value of primes[].28 #define HASH_LOAD_FACTOR (1.0) //load factor of hash entry.29 #define INPUT_BUFFER_SIZE (32*1024) // size of input buffer.30 #define MAX_LEN_QUE (8) // maximum length of queue.31 #define MOD(X) ((X) % MAX_LEN_QUE) //compute index of que[].32 #define hash_val(BUF_LEN, A, B) (((A)*(B))%BUF_LEN)33 //#define hash_val(BUF_LEN, A, B)
((((A)<<16)|(B)>>16)%BUF_LEN)34 //#define hash_val(BUF_LEN, A, B) ((A+(A<<16)^B)%BUF_LEN)35
36 typedef struct Queue 37 CODE w[MAX_LEN_QUE];38 uint bpos;39 uint epos;40 uint num;41 struct Queue *next;
98
42 QU;43
44 //Inner function declaration.45 static QU *createQueue ();46 static void destructQueues (QU *q);47 static void enQueue (QU *q, CODE c);48 static CODE deQueue (QU *q);49 static CODE refQueue (QU *q, uint i);50 static bool isRepetition (QU *q, uint i);51 static bool isMinimal (QU *q, uint i);52 static uint computeLCAd (CODE i, CODE j);53 static bool isMaximal (QU *q, uint i);54 static bool isPair (QU *q);55 static void resizeDict (DICT *d);56 static void rehash (DICT *d);57 static CODE addRule2Dictionary (DICT *d, CODE left, CODE
right);58 static CODE searchRule (DICT *d, CODE left, CODE right);59 static CODE reverseAccess (DICT *d, CODE left, CODE right);60 static DICT *createDictionary ();61 static void grammarTrans_rec (DICT *d, QU *q, CODE c);62
63 static64 QU *createQueue() 65 uint i;66 QU *q = (QU*)malloc(sizeof(QU));67
68 for (i = 0; i < MAX_LEN_QUE; i++) 69 q->w[i] = DUMMY_CODE;70 71 q->bpos = 0;72 q->epos = 0;73 q->num = 1;74 q->next = NULL;75
76 return q;77 78
79 static INLINE80 void enQueue(QU *q, CODE c)81 82 q->epos = MOD(q->epos+1);83 q->w[q->epos] = c;84 q->num++;85 86
87 static INLINE88 CODE deQueue(QU *q)89 90 register CODE x = q->w[q->bpos];91
92 q->bpos = MOD(q->bpos+1);93 q->num--;94 return x;95
99
96
97 static INLINE98 CODE refQueue(QU *q, uint i)99
100 return q->w[MOD(q->bpos+i)];101 102
103 static104 void destructQueues(QU *q)105 106 if (q == NULL) 107 return;108 109 destructQueues(q->next);110 free(q);111 112
113 static INLINE114 bool isRepetition(QU *q, uint i)115 116 register CODE w1 = refQueue(q, i);117 register CODE w2 = refQueue(q, i+1);118
119 if (w1 == w2) 120 return true;121 122 return false;123 124
125 static INLINE126 bool isMinimal(QU *q, uint i)127 128 register CODE w0 = refQueue(q, i-1);129 register CODE w1 = refQueue(q, i);130 register CODE w2 = refQueue(q, i+1);131
132 if ((w0 > w1) && (w1 < w2)) 133 return true;134 else 135 return false;136 137 138
139 static INLINE140 uint computeLCAd(CODE i, CODE j)141 142 register uint Ni, Nj;143 register uint x;144
145 Ni = 2*i - 1;146 Nj = 2*j - 1;147 x = Ni ^ Nj;148 x = (uint)floor(LOG2(x));149 return x;150
100
151
152 static INLINE153 bool isMaximal(QU *q, uint i)154 155 register CODE w0 = refQueue(q, i-1);156 register CODE w1 = refQueue(q, i);157 register CODE w2 = refQueue(q, i+1);158 register CODE w3 = refQueue(q, i+2);159
160 if (!(w0 < w1 && w1 < w2 && w2 < w3) &&161 !(w0 > w1 && w1 > w2 && w2 > w3))162 163 return false;164 165
166 if (computeLCAd(w1,w2) > computeLCAd(w0,w1) &&167 computeLCAd(w1,w2) > computeLCAd(w2,w3))168 169 return true;170 171 else172 173 return false;174 175 176
177 static INLINE178 bool isPair(QU *q) 179 if (isRepetition(q, 1)) 180 return true;181 182 else if (isRepetition(q, 2)) 183 return false;184 185 else if (isRepetition(q, 3)) 186 return true;187 188 else if (isMinimal(q, 1) || isMaximal(q, 1)) 189 return true;190 191 else if (isMinimal(q, 2) || isMaximal(q, 2)) 192 return false;193 194 return true;195 196
197 static INLINE198 void rehash(DICT *d)199 200 uint i;201 uint h;202 CODE temp;203
204 if ((d->hebuf_len = primes[++d->p_idx]) == 0) 205 puts("size of hash table is overflow.");
101
206 exit(1);207 208 d->h_entry = (CODE*)realloc(d->h_entry,
d->hebuf_len*sizeof(CODE));209 if (d->h_entry == NULL) 210 puts("Memory reallocate error (h_entry) at rehash.");211 exit(1);212 213 for (i = 0; i < d->hebuf_len; i++) 214 d->h_entry[i] = (uint)DUMMY_CODE;215 216 for (i = CHAR_SIZE+1; i < d->num_rules; i++) 217 d->h_list[i] = DUMMY_CODE;218 219 for (i = d->num_rules-1; i > CHAR_SIZE; i--) 220 h = hash_val(d->hebuf_len, d->rule[i].left,
d->rule[i].right);221 temp = d->h_entry[h];222 d->h_entry[h] = i;223 if (temp != DUMMY_CODE) 224 d->h_list[i] = temp;225 226 227 228
229 static INLINE230 void resizeDict(DICT *d)231 232 d->rlbuf_len *= RLBUF_RESIZE_FACTOR;233 d->rule = (RULE*)realloc(d->rule,
d->rlbuf_len*sizeof(RULE));234 if (d->rule == NULL) 235 puts("Memory reallocate error (rule) at resizeDict.");236 exit(1);237 238 d->h_list = (CODE*)realloc(d->h_list,
d->rlbuf_len*sizeof(CODE));239 if (d->h_list == NULL) 240 puts("Memory reallocate error (h_list) at resizeDict.");241 exit(1);242 243 244
245 static INLINE246 CODE addRule2Dictionary(DICT *d, CODE left, CODE right)247 248 CODE new_key = d->num_rules++;249 CODE temp;250 uint h;251
252 if (d->num_rules > d->rlbuf_len) 253 resizeDict(d);254 255 if (d->num_rules > (uint)(d->hebuf_len*HASH_LOAD_FACTOR))
102
256 rehash(d);257 258
259 d->rule[new_key].left = left;260 d->rule[new_key].right = right;261
262 if (new_key > DUMMY_CODE) 263 h = hash_val(d->hebuf_len, left, right);264 temp = d->h_entry[h];265 d->h_entry[h] = new_key;266 if (temp != DUMMY_CODE) 267 d->h_list[new_key] = temp;268 269 else 270 d->h_list[new_key] = DUMMY_CODE;271 272 273 return new_key;274 275
276 static INLINE277 CODE searchRule(DICT *d, CODE left, CODE right)278 279 register CODE key;280 register uint h;281
282 h = hash_val(d->hebuf_len, left, right);283 key = d->h_entry[h];284 while (key != DUMMY_CODE) 285 if (d->rule[key].left == left && d->rule[key].right ==
right) 286 return key;287 else 288 key = d->h_list[key];289 290 291 return DUMMY_CODE;292 293
294 static INLINE295 CODE reverseAccess(DICT *d, CODE left, CODE right)296 297 register CODE R;298
299 if ((R = searchRule(d, left, right)) == DUMMY_CODE) 300 R = addRule2Dictionary(d, left, right);301 302 return R;303 304
305 static306 DICT *createDictionary()307 308 uint i;309 DICT *d;
103
310
311 d = (DICT*)malloc(sizeof(DICT));312 d->rlbuf_len = INIT_RLBUF_LEN;313 d->p_idx = INIT_PRIMES_INDEX;314 d->hebuf_len = primes[d->p_idx];315
316 d->rule = (RULE*)malloc(d->rlbuf_len*sizeof(RULE));317 if (d->rule == NULL) 318 puts("Memory allocate error (rule) at
createDictionary.");319 exit(1);320 321 d->h_entry = (CODE*)malloc(d->hebuf_len*sizeof(CODE));322 if (d->h_entry == NULL) 323 puts("Memory allocate error (h_entry) at
createDictionary.");324 exit(1);325 326 for (i = 0; i < d->hebuf_len; i++) 327 d->h_entry[i] = DUMMY_CODE;328 329
330 d->h_list = (CODE*)malloc(d->rlbuf_len*sizeof(CODE));331 if (d->h_list == NULL) 332 puts("Memory allocate error (h_list) at
createDictionary.");333 exit(1);334 335 for (i = 0; i < d->rlbuf_len; i++) 336 d->h_list[i] = DUMMY_CODE;337 338 for (i = 0; i < CHAR_SIZE; i++) 339 addRule2Dictionary(d, i, DUMMY_CODE);340 341 addRule2Dictionary(d, DUMMY_CODE, DUMMY_CODE);342 return d;343 344
345 static INLINE346 void grammarTrans_rec(DICT *d, QU *p, CODE c)347 348 QU *q;349 CODE v, x1, x2, x3;350
351 if (p->next == NULL) 352 q = p->next = createQueue();353 354 else 355 q = p->next;356 357
358 enQueue(q, c);359 if (q->num == MAX_LEN_QUE) 360 if (isPair(q) == true) 361 deQueue(q);
104
362 x1 = deQueue(q); x2 = refQueue(q, 0);363 v = reverseAccess(d, x1, x2);364 grammarTrans_rec(d, q, v);365 366 else 367 deQueue(q);368 x1 = deQueue(q);369 grammarTrans_rec(d, q, x1);370 x2 = deQueue(q); x3 = refQueue(q, 0);371 v = reverseAccess(d, x2, x3);372 grammarTrans_rec(d, q, v);373 374 375 376
377 DICT *GrammarTrans_LCA(FILE *input)378 379 uchar *w, *w_top;380 uint lg;381 QU *dummy_que, *que;382 CODE v, x1, x2;383 DICT *d;384 long cnt = 0;385
386 dummy_que = createQueue();387 d = createDictionary();388
389 printf("Grammar Transforming ...\n");390 w_top = (uchar*)malloc(sizeof(uchar)*INPUT_BUFFER_SIZE);391 while ((lg = fread(w_top, sizeof(uchar),
INPUT_BUFFER_SIZE, input)) > 0) 392 cnt += lg;393 w = w_top;394 do 395 grammarTrans_rec(d, dummy_que, *w++);396 while (--lg > 0);397 printf("\r");398 printf("[ %12ld ] bytes -> [ %10d ] rules.", cnt,
d->num_rules);399 fflush(stdout);400 401 d->txt_len = cnt;402
403 que = dummy_que->next;404 while (que->next != NULL || que->num > 2) 405 deQueue(que);406 while (que->num > 1) 407 x1 = deQueue(que); x2 = deQueue(que);408 v = reverseAccess(d, x1, x2);409 grammarTrans_rec(d, que, v);410 411 if (que->num == 1) 412 x1 = deQueue(que);413 grammarTrans_rec(d, que, x1);414
105
415 que = que->next;416 417
418 printf("\r");419 printf("[ %12ld ] bytes -> [ %10d ] rules.\n", cnt,
d->num_rules);420 free(w_top);421 destructQueues(dummy_que);422 return d;423 424
425 void OutputGeneratedCFG(DICT *d, FILE *output)426 427 fwrite(&d->txt_len, sizeof(uint), 1, output);428 fwrite(&d->num_rules, sizeof(uint), 1, output);429 fwrite(d->rule+CHAR_SIZE+1, sizeof(RULE),430 d->num_rules-(CHAR_SIZE+1), output);431 432
433 void DestructDict(DICT *d)434 435 if (d == NULL) return;436 if (d->rule != NULL) free(d->rule);437 if (d->h_entry != NULL) free(d->h_entry);438 if (d->h_list != NULL) free(d->h_list);439 free(d);440
106
A.12 txt2cfg online.h
1 /*2 * Copyright (c) 2011-2012 Shirou Maruyama3 *4 * Redistribution and use in source and binary forms, with
or without5 * modification, are permitted provided that the following
conditions6 * are met:7 *8 * 1. Redistributions of source code must retain the above
Copyright9 * notice, this list of conditions and the following
disclaimer.10 *11 * 2. Redistributions in binary form must reproduce the
above Copyright12 * notice, this list of conditions and the following
disclaimer in the13 * documentation and/or other materials provided with the
distribution.14 *15 * 3. Neither the name of the authors nor the names of its
contributors16 * may be used to endorse or promote products derived from
this17 * software without specific prior written permission.18 */19
20 #ifndef TXT2CFG_ONLINE_H21 #define TXT2CFG_ONLINE_H22
23 #include <stdio.h>24 #include <stdlib.h>25 #include <string.h>26 #include <math.h>27 #include "lcacommon.h"28
29 typedef struct Dictionary 30 uint txt_len;31 uint num_rules;32 RULE *rule;33 CODE *h_entry;34 CODE *h_list;35 uint rlbuf_len;36 uint p_idx;37 uint hebuf_len;38 DICT;39
40 // function prototype declarations41 DICT *GrammarTrans_LCA (FILE *input);42 void OutputGeneratedCFG (DICT *d, FILE *output);43 void DestructDict (DICT *d);44
107
45 #endif /* TXT2CFG_ONLINE_H */
108