Universidade Federal de Minas Gerais Instituto de Ciências Exatas Departamento de Ciência da Computação

Documentos relacionados
Processamento de Cadeias de Caracteres

Processamento de Cadeias de Caracteres

Casamento de Padrões

Strings (Casamento de padrões) Estrutura de Dados II Jairo Francisco de Souza

Casamento de Cadeias. Introdução. Introdução. Estrutura de Dados. Cadeia de caracteres: sequência de elementos denominados caracteres.

Estrutura de dados 1. Processamento de Cadeias de Caracteres

Algoritmos e Estruturas de Dados I (DCC/003) Estruturas Condicionais e de Repetição

Estruturas de Repetição

TÉCNICO DE INFORMÁTICA - SISTEMAS

Programação: Vetores

Compressão de Textos. Introdução. Introdução. Introdução. O volume de informação textual disponível on-line é imenso:

Aprendizado de Máquina

Tabelas de hash Acabamos de estudar como implementar uma tabela hashing aberta e estudaremos agora como implementar uma tabela hashing fechada ou

Introdução à Programação

Universidade Federal de Alfenas

Reconhecimento de Padrões. Prof. Flávio Humberto Cabral Nunes

Unidade VI. Técnicas de Teste de Software Teste Estrutural. Profa. Dra. Sandra Fabbri

Algoritmos em Strings

Capítulo 6: Linguagens de Programação

Universidade Federal de Campina Grande Unidade Acadêmica de Sistemas e Computação Curso de Bacharelado em Ciência da Computação.

Capítulo 9: Linguagens sensíveis ao contexto e autômatos linearmente limitados.

Métodos de Ordenação Parte I

I1, I2 e In são instruções simples ou estruturadas da linguagem Pascal.

Lista de Exercícios sobre Listas Implementadas por Encadeamento

Listas Lineares. Livro Projeto de Algoritmos Nívio Ziviani Capítulo 3 Seção 3.1

4. Algoritmos de Busca em Vetores

PROGRAMAÇÃO de COMPUTADORES: LINGUAGEM FORTRAN 90/95

Ordenação Externa. Ordenação Externa. Ordenação Externa. Ordenação Externa

Quinto Trabalho Prático. Este trabalho tem como objetivo indexar arquivos de dados usando um índice árvore-b.

Introdução à Programação em C Input / Output

MODOS DE ENDEREÇAMENTO E CONJUNTO DE INSTRUÇÕES

Listas Estáticas. SCC Algoritmos e Estruturas de Dados I. Prof. Fernando V. Paulovich. *Baseado no material do Prof.

Processamento de Cadeias de Caracteres

Capítulo 6: Arquivos

#include <stdio.h> Void main() { printf( Cheguei!\n"); } INTRODUÇÃO A LINGUAGEM C

Hashing (Tabela de Dispersão)

PROGRAMAÇÃO I E N T R A DA E S A Í DA D E DA D O S

4 Análise de Dados. 4.1.Procedimentos

Lista de Exercícios 04

MODOS DE ENDEREÇAMENTO E CONJUNTO DE INSTRUÇÕES

Linguagem C Princípios Básicos (parte 1)

Compressão Sem Perdas: Codificações Huffman e Aritmética. Adelar da Silva Queiróz Marcelo Teixeira Thiago da Silva Sodré

Conceitos Básicos de Programação

Algoritmos e Estruturas de Dados I (DCC/003) Estruturas Básicas. Aula Tópico 2

Programação Dinâmica. Prof. Anderson Almeida Ferreira. Adaptado do material elaborado por Andrea Iabrudi Tavares

Teoria da Computação. Computabilidade e complexidade computacional

C Operadores e Expressões

MATRIZES - PARTE Definição e Manipulação de Matrizes AULA 21

Análise e Síntese de Algoritmos. Emparelhamento de Cadeias de Caracteres CLRS, Cap. 32

Universidade de São Paulo

6 Aplicações Detalhes da Implementação

Tabelas Hash. Prof. Túlio Toffolo BCC202 Aulas 23 e 24 Algoritmos e Estruturas de Dados I

Organização de Arquivos. Leandro C. Cintra M.C.F. de Oliveira Thiago A. S. Pardo Cristina D. A. Ciferri

Aula 3: Algoritmos: Formalização e Construção

Alocação Dinâmica de Memória - Exercício

AULA 4 - FLUXOGRAMAS PARTE 1 Noções sobre a ferramenta Flowgorithm para construção de fluxogramas

Pesquisa em Árvores Digitais. Adaptado de David M.

Estruturas da linguagem C. 1. Identificadores, tipos primitivos, variáveis e constantes, operadores e expressões.

Organização e Arquitetura de Computadores I

VETORES Motivação AULA 19

heapsort (int *x, int n) { int i, e, s, f, aux; /*fase de pré-processamento - cria heap inicial*/ for (i=1; i<n; i++) { e = x[i]; s = i; f = (s-1)/2;

MC102 Aula 26. Instituto de Computação Unicamp. 17 de Novembro de 2016

Linguagem e Técnicas em Programação. Gilson de Souza Carvalho

Cursos: Análise, Ciência da Computação e Sistemas de Informação Laboratório I - Prof. Aníbal Notas de aula 2 SISTEMAS NUMÉRICOS

Organização e Arquitetura de Computadores I

Universidade Federal de Uberlândia Faculdade de Computação. Linguagem C: ponteiros e alocação dinâmica

Universidade Estadual de Mato Grosso do Sul Bacharelado em Ciência da Computação Algoritmos e Estruturas de Dados II Prof. Fabrício Sérgio de Paula

ACH2043 INTRODUÇÃO À TEORIA DA COMPUTAÇÃO

UNIVERSIDADE FEDERAL RURAL DO SEMI-ÁRIDO CURSO: CIÊNCIA DA COMPUTAÇÃO 9º PERÍODO. Profª Danielle Casillo

ÁRVORE BINÁRIA DE BUSCA TDA-ABB

Programação I A Linguagem C. Prof. Carlos Alberto

Aula 3 Listas Lineares Sequenciais Ordenadas. prof Leticia Winkler

Nível da Arquitetura do Conjunto das Instruções

Listas Estáticas. Prof. Fernando V. Paulovich *Baseado no material do Prof. Gustavo Batista

Organização Básica de Computadores. Organização Básica de Computadores. Organização Básica de Computadores. Organização Básica de Computadores

Disciplina: Arquitetura de Computadores

2. A influência do tamanho da palavra

Programação de Redes de Computadores

Algoritmos e Estruturas de Dados I (DCC/003) 2013/1. Estruturas Básicas. Aula Tópico 4

Máquinas de Turing - Computabilidade

PROGRAMAÇÃO A. Matrizes

Pesquisa em Memória Primária Hashing

Análise de complexidade

Árvores. Prof. César Melo DCC/ICE/UFAM

Programação Dinâmica. Prof. Anderson Almeida Ferreira

Estrutura de um Algoritmo, Variáveis, Comandos de Entrada e Saída e Expressões Aritméticas

Tabelas de dispersão/hash

Algoritmos e Estrutura de Dados II. Árvore. Prof a Karina Oliveira.

Introdução Métodos de Busca Parte 1

Introdução à Linguagem C Variáveis e Expressões

ANÁLISE DE ALGORITMOS: PARTE 1. Prof. André Backes. Como resolver um problema no computador? Precisamos descrevê-lo de uma forma clara e precisa

a) Calcule o valor médio de CPI apresentado na execução deste programa P, utilizando-se C1 sem e com otimização.

Edital de Seleção 024/2017 PROPESP/UFAM. Prova de Conhecimento. Caderno de Questões

Tabelas Hash. informação, a partir do conhecimento de sua chave. Hashing é uma maneira de organizar dados que:

CONJUNTO DE INSTRUÇÕES

Arquitetura Von Neumann Dados e instruções são obtidos da mesma forma, simplificando o desenho do microprocessador;

Árvores. Thiago Martins, Fabio Gagliardi Cozman. PMR2300 / PMR3201 Escola Politécnica da Universidade de São Paulo

ANÁLISE DE COMPLEXIDADE DOS ALGORITMOS

Descrição do Algoritmo LZ77

Transcrição:

Universidade Federal de Minas Gerais Instituto de Ciências Exatas Departamento de Ciência da Computação PROJETO E ANÁLISE DE ALGORITMOS Casamento Exato e Aproximado de Cadeias de Caracteres Terceiro Trabalho Prático - disponível em: http://www.dcc.ufmg.br/ menoti/paa/tp3/ David Menoti Gomes Professor - Nivio Ziviani Belo Horizonte 31 de maio de 2004

Sumário 1 Introdução 1 2 Estruturas de Dados e Interface do Programa 2 3 Instâncias 4 4 Abordagem 5 4.1 Casamento Exato............................. 5 4.1.1 Algoritmo de Boyer-Moore-Horspool (BMH).......... 5 4.1.2 Algoritmo de Boyer-Moore-Horspool-Sunday (BMHS)..... 7 4.1.3 Algoritmo Shift-And Exato (SAE)................ 9 4.2 Casamento Aproximado......................... 12 4.2.1 Algoritmo Shift-And Aproximado (SAA)............ 13 4.2.2 Algoritmo usando Programação Dinâmica........... 16 5 Experimentos 21 5.1 Casamento de Cadeias Exato - Tempo................. 22 5.2 Casamento de Cadeias Exato - Número de Comparações....... 24 5.3 Casamento de Cadeias Aproximado - Tempo.............. 26 6 Conclusões 29 7 Anexos 31 2

1 Introdução Uma cadeia de caracteres é uma seqüência qualquer de elementos. As cadeias aparecem no processamento de textos em linguagem natural, códigos, dicionários, seqüenciamento de DNA em biologia computacional, representação de imagens por meio de bitmaps, dentre outros [9]. Neste trabalho são apresentados algoritmos de uma classe de problemas que envolvem a manipulação de cadeias. Esses algoritmos estão relacionados com pesquisa exata e pesquisa aproximada. Uma cadeia corresponde a uma seqüência de elemtnos denomiados caracteres. Os caractes são escolhdios de um conjunto denominado alfabeto. Por exemplo em uma cadeia de bits o alfabeto é 0, 1. A pesquisa em cadeias de caracteres é um componente importante em diversos problemas computacionais, tais como edição de texto, recuperação de informação e estudo de seqüências de DNA em biologia computacional. No caso de programas editores de texto, o usuário pode estar interessado em buscar todas as ocorrências de um padrão (uma palavra particular) no texto que está sendo editado. Este problema é conhecimento como casamento de cadeias de caracteres ou casamento de padrão (do inglês pattern matching). O problema de casamento de cadeias ou casamento de padrão pode ser formalizado como da seguinte forma. O texto é um arranjo T [1..n] de tamanho n e o padrão é um arranjo P [1..m] de tamanho m n. Os elementos P e T são escolhidos de um alfabeto finito Σ de tamanho c. Por exemplo, podemos ter Σ = 0, 1 ou Σ = a, b,..., z. Dadas duas cadeias P (padrão) de comprimento P = m e T (texto) de comprimento T = n, em que n >> m, deseja-se saber as ocorrências de P em T. Os algoritmos para casamento de cadeias podem ser classificados em três categorias maiores: Padrão e texto não pré-processados; Padrão pré-processado; Padrão e texto pré-processados. No entanto, o trabalho concentra-se na segunda categoria, ou seja, algoritmos de casamento de padrão com padrão pré-processado. Esses algoritmos são do tipo seqüêncial e o padrão é conhecido anteriormente, o que permite o seu préprocessamento. Os algoritmos têm complexidade de tempo O(n) e complexidade de espaço O(m + c), no pior caso. Os algoritmos nesta categoria são usados em diversas aplicações como, por exemplo, em programas para edição de textos. O trabalho está organizado da seguinte forma. Na Seção 2 são apresentadas as estruturas de dados utilizadas para os algoritmos. Na Seção 3 são apresentadas as instâncias utilizadas para os experimentos, ou seja, os arquivos de teste. Os algoritmos implementados são descritos na Seção 4 e na Seção 5 os experimentos realizados são apresentados. E, finalmente, na Seção 6 conclusões são apontadas. 1

2 Estruturas de Dados e Interface do Programa Nesta seção são apresentadas as estruturas de dados, bem como uma leve explicação sobre a interface do programa constrúido. No Programa 1 são apresentadas as estruturas de dados básicas utilizadas no trabalho. TipoTexto é um tipo de dado para armazenar um texto de no máximo BUFSIZ bytes. Na maioria das versões do arquivo de cabeçalho stdio.h essa macro é definida como sendo 8k, ou 8192 bytes. TipoPadrao é um tipo de dado para armazenar um padrão de no máximo BUFSIZ bytes. Já TipoTextoT é um ponteiro/apontador para o tipo de dado char, ou seja, ele serve para apontar para um texto de tamanho desconhecido. typedef char TipoTextoT; typedef char TipoTexto [BUFSIZ] ; typedef char TipoPadrao[BUFSIZ] ; Programa 1: Estruturas de dados básicas usadas no trabalho. Dois outros artifícios foram utilizados nesse trabalho. Uma macro chamada VERBOSE foi utilizada para ajustar o grau de verbalização do programa. Em situações iniciais, de construção do programa, era desejável apresentar as ocorrências de casamento. Já na fase de testes, essa informação era desnecessária. O interessante era somente o tempo de processamento, o número de ocorrências e o número de comparações. Para o número de comparações foi utilizada outra macro, COMP, essa definia seções do programa que deveriam ser compiladas caso o número de comparações fosse desejado. Caso esse número não fosse desejado e essa macro não fosse definida, o código necessário para o cálculo do número de comparações era removido, automaticamente. Isso fazia com que a comparação do tempo de relógio fosse mais fiel, pois incrementos indesejáveis do número de comparações não eram computados. Todos os algoritmos foram implementados sobre um único programa. Para tanto, desenvolveu-se uma interface para manusear todos os algoritmos. O programa tem a seguinte sintaxe: matching -[algoritmo] -[f l] padrão arquivo-texto k onde algoritmo era um dos seguintes: bmh - Algoritmo BMH bmhs - Algoritmo BMHS sae - Algoritmo Shift-And Exato saa - Algoritmo Shift-And Aproximado pd - Algoritmo de Programação Dinâmica os três primeiros não havendo a necessidade do parâmetro k, pois estavam envolvidos com casamento exato. Já os dois últimos necessitavam do parâmetro k para informar a quantidade de erros toleráveis. e f ou l indicavam se o programa deveria ler todo texto inicialmente, ou ler o texto linha por linha, respectivamente. padrão e arquivo-texto indicavam o padrão a ser casado e o caminho do arquivo onde o texto 2

estava armazenado, respectivamente, e finalmente o parâmetro k, com 0 < k < m, onde m é o tamanho do padrão. Caso o programa seja executado com os parâmetros fora de ordem, ou insuficientes, a seguinte mensagem era dada: tigre:~/paa/tp3/src->./matching use:./matching -bmh -[f l] pattern filename use:./matching -bmhs -[f l] pattern filename use:./matching -sae -[f l] pattern filename use:./matching -saa -[f l] pattern filename k use:./matching -pd -[f l] pattern filename k fornecendo ao usuário a forma correta de informar os dados para execução do programa. 3

3 Instâncias Para os experimentos realizados no trabalho, foram utilizadas as coleções de documentos TREC disponível em /export/texto/wsj na máquina leão. Essa coleção tem características conforme descrito pela Tabela 1. Tabela 1: Características dos Documentos utilizados nos experimentos. Coleção Tamanho (MB) wsj88 109 wsj88_10 10 wsj88_20 20 wsj89 2.8 Um documento exemplo extraído de uma das coleções é mostrado na Figura 1. <DOC> <DOCNO> WSJ890802-0123 </DOCNO> <DD> = 890802 </DD> <AN> 890802-0123. </AN> <HL> Settsu Corp. Proposes @ To Pay $53.3 Million @ To Buy R.L. Crain </HL> <DD> 08/02/89 </DD> <SO> WALL STREET JOURNAL (J) </SO> <CO> T.CRL BOW </CO> <IN> TENDER OFFERS, MERGERS, ACQUISITIONS (TNM) </IN> <DATELINE> OTTAWA </DATELINE> <TEXT> Settsu Corp. of Japan proposed to acquire R.L. Crain Inc. for 63 million Canadian dollars (US$53.3 million). The purchase of the business-form producer would be the latest in a series of acquisitions in the U.S. and Canada by Settsu, a paperboard-products company. In October, Settsu bought Uarco Inc., a Barrington, Ill., business-form producer. </TEXT> </DOC> Figura 1: Exemplo de um documento extraído da coleção wsj89. 4

4 Abordagem Nessa seção serão apresentados 5 algoritmos de casamento de cadeias de caracteres, sendo três algoritmos referentes a casamento exato, extraídos de [9], e mais dois referentes a casamento aproximado, extraídos de [9] e [6], ou seja: Casamento Exato Algoritmo de Boyer-Moore-Horspool (BMH); Algoritmo de Boyer-Moore-Horspool-Sunday (BMHS); Algoritmo Shift-And Exato (SAE); Casamento Aproximado Algoritmo Shift-And Aproximado (SAA); Algoritmo usando Programação Dinâmica exposto em [6]. 4.1 Casamento Exato No casamento exato de padrão, o problema básico consiste em obter todas as ocorrências exatas do padrão no texto. A Figura 2 mostra uma ocorrência exata do padrão teste em um texto exemplo. teste os testes testam estes alunos... Figura 2: Exemplo de Casamento exato. Nas próximas subseções desta seção serão apresentados três algoritmos de casamento exato de cadeias. 4.1.1 Algoritmo de Boyer-Moore-Horspool (BMH) Inicialmente, Boyer e Moore, em [3], publicaram um algoritmo clássico para casamento de cadeias de caracteres, ficando conhecido como Boyer-Moore (BM). A idéia básica era a de pesquisar um padrão no sentido da direta para a esquerda, o que tornava o algoritmo muito rápido. Já em [4], Horspool apresentou uma simplificação importante no algoritmo BM, tão eficiente quanto o algoritmo original. Essa simplificação, nova versão, no algoritmo BM proposta por Horspool ficou conhecida como BMH. Em ambos algoritmos, BM e BMH a pesquisa consiste em pesquisar o padrão P em uma janela que desliza ao longo do texto T. Horspool, observou que qualquer caractere já lido do texto a partir do último deslocamente pode ser usado para endereçar a tabela de deslocamentos. Baseado nesse fato, Hospool propôs endereçar a tabela com o caractere no texto correspondente ao último caractere do padrão. Para pré-computar o padrão (pré-processamento do padrão), o valor inicial de todas as entradas na tabela de deslocamentos é feito igual a m. A seguir, apenas os m 1 primeiros caractres do padrão são usados para obter os outros valores da tabela, Formalmente, pode-se escrever: 5

d[x] = minj tal quej = m (1 j < m P [m j] = x). Para o padrão P = teste, os valores de d são d[t] = 1, d[e] = 3, d[s] = 2, e todos os outros valores são iguais ao valor de P, nesse caso m = 5. Um exemplo da execução do algorimto BMH pode ser visto na Figura 3. O texto a ser procurado é apresentado na primeira linha e o padrão é deslocado nas linhas seguintes. 123456789012 aabcaccacbac cacbac cacbac cacbac Figura 3: Exemplo de execução do algoritmo BMH, em que o padrão P = cacbac, com d[a] = 1, d[b] = 2 e d[c] = 3, é procurado no texto T = aabcaccacbac. long BMH(TipoTextoT T, TipoPadrao P) long i, j, k, l, o; long m, n; long d[maxchar + 1]; #ifdef COMP long c ; #endif / m tamanho do padrao / m = strlen(p); / n tamanho do texto / n = strlen(t); / pre processamento / for ( j = 0; j <=MAXCHAR ; j++) d[ j ] = m; for ( j = 1; j < m; j++) d[(int)p[ j 1]] = m j ; #ifdef COMP c = 0; #endif o = 0; i = m; while ( i <= n) / Pesquisa / k = i ; j = m; #ifdef COMP while (++c &&T[k 1] == P[ j 1] && j > 0) #else while (T[k 1] == P[ j 1] && j > 0) #endif k ; j ; 6

if ( j == 0) o++; i f (VERBOSE>=2) fprintf (stdout,"%05ld %05ld %s\n", l, k+1,t); i += d[(int)t[ i 1]]; #ifdef COMP fprintf(stdout,"bmh: number of comparisions: %ld\n", c); #endif return o; Programa 2: Implementação do Algoritmo Boyer-Moore-Horspool A listagem da implementação em C desse algoritmo pode ser vista no Programa 2. O pré-processamento do padrão para obter a tabela de deslocamentos d ocorre nos dois primeiros loops (for s). A fase de pesquisa é consituída pelo anel mais interno do código em que i varia de m até n, com incrementos de d[t [i]], onde T [i] retorna o código ASCII do caractere em questão e d[t [i]] é o incremento pré-cálculado para o caractere na i-ésima posição no texto, a qual corresponde à posição do último caractere em P. Análise. O deslocamento ocorrência pode ser pré-computado com base apenas no padrão e no alfabeto, e a complexidade de tempo e de espaço para essa fase é O(m + c). Para a fase de pesquisa, o pior caso do algoritmo é O(nm), o melhor caso é O(n/m) e o caso esperado é O(n/m), se c (alfabeto) não é pequeno e m (padrão) não é muito grande. 4.1.2 Algoritmo de Boyer-Moore-Horspool-Sunday (BMHS) Em [7], Sunday fez outra simplificação importante no algoritmo BM, e este ficou conhecido como BMHS. Este algoritmo é uma variante do BMH. Sunday propos endereçar a tabela com o caractere no texto correspondente ao próximo caractere após o úiltimo caractere do padrão, em vez de deslocar o padrão usando o último caractere como no algoritmo BMH. O passo de pré-processamento para o algoritmo BMHS é diferente do BMH. Para pré-computar o padrão, o valor inicial de todas as entradas na tabela de deslocamentos é feito igual; a m + 1. A seguir,,os m primeiros caracteres do padrão são usadis para obter os outros valores da tabela. Formalmente pode escrever d[x] = minj tal quej = m (1 j m P [m + 1 j] = x). Para o padrão P = teste, os valores de d são d[t] = 2, d[e] = 1, d[s] = 3, e todos os outros valores são iguais ao valor de m + 1 = P + 1, nesse caso m = 5. Um exemplo da execução do algorimto BMHS pode ser visto na Figura 4. O texto a ser procurado é apresentado na primeira linha e o padrão é deslocado nas linhas seguintes. A listagem da implementação em C desse algoritmo pode ser vista no Programa 3. O pré-processamento do padrão para obter a tabela de deslocamentos d ocorre nos dois primeiros loops (for s). A fase de pesquisa é consituída pelo anel mais 7

123456789012 aabcaccacbac cacbac cacbac cacbac cacbac Figura 4: Exemplo de execução do algoritmo BMHS, em que o padrão P = cacbac, com d[a] = 2, d[b] = 3 e d[c] = 1, é procurado no texto T = aabcaccacbac. interno do código em que i varia de m até n, com incrementos de d[t [i + 1]], onde T [i + 1] retorna o código ASCII do caractere em questão e d[t [i + 1]] é o incremento pré-cálculado para o caractere na i + 1-ésima posição no texto, a qual corresponde à posição do último caractere em P. O funcionamento do algoritmo é semelhante ao BMH, a diferença reside na fase de pré-processamento, que acarreta deslocamento diferentes para o padrão P ao longo do texto T e também no deslocamento que é baseado no próximo caractere no texto T [i + 1]. long BMHS(TipoTextoT T, TipoPadrao P) long i, j, k, o; long n, m; long d[maxchar + 1]; #ifdef COMP long c ; #endif / n tamanho do texto / n = strlen(t); / m tamanho do padrao / m = strlen(p); / pre processamento / for ( j = 0; j <=MAXCHAR; j++) d[ j ] = m + 1; for ( j = 1; j <=m; j++) d[(int)p[ j 1]] = m j + 1; #ifdef COMP c = 0; #endif o = 0; / occurence counter / i = m; while ( i <= n) / Pesquisa / k = i ; j = m; #ifdef COMP while (++c &&T[k 1] == P[ j 1] && j > 0) #else while (T[k 1] == P[ j 1] && j > 0) #endif k ; j ; if ( j == 0) 8

o++; i f (VERBOSE>=2) fprintf (stdout,"%05ld %s\n",k+1,t); i += d[(int)t[ i ] ] ; #ifdef COMP fprintf(stdout,"bmhs: number of comparisions: %ld\n", c); #endif return o; Programa 3: Implementação do Algoritmo Boyer-Moore-Horspool-Sunday Análise. O algoritmo BMHS tem comportamento assintótico igual ao algoritmo BMH. No entanto, os deslocamentos são mais longos (podendo ser iguais a m + 1 - todo o padrão mais um caractere), levando a saltos relativamente maiores para padrões curtos. Por exemplo, para um padrão de tamanho m = 1, o deslocamento é igual a 2m quando não há casamento com o próximo caractere do texto, pois todos os d s. são iguais a m + 1 (2m = m + 1, quando m = 1) executando-se o único caractere que contém o padrão. Nessa situação o deslocamento é 1. 4.1.3 Algoritmo Shift-And Exato (SAE) O algoritmo Shift-And foi proposto por Baeza-Yates e Gonnet [1]. Além disso, na Seção 4.2.1 apresentar-se-á uma extensão para esse algoritmo permitindo o casamento aproximado de cadeias de caracteres. O algoritmo usa o conceito de paralelismo de bit (do inglês bit parallelism), uma técnica que tira proveito do paralelismo intrínseco das operações sobre bits dentro de uma palavra de computador. Neste caso, é possível empacotar muitos valores em uma única palavra e atualizar todos eles em um única operação. Pelo fato de tirar proveito do paralelismo de bit, o número de operações que um algoritmo realiza pode ser reduzido por um fator de até w, em que w é o número de bits da palavra do computador. Considerando que nas arquiteturas atuais w é 32 ou 64, o ganho na prática pode ser muito grande. Agora, apresenta-se a notação que será utilizada para descrever as operações usando paralelismo de bit. Para denotar repetição de bit é usada exponenciação: 01 3 = 0111. Uma seqüência de bits b 1... b c é chamada de máscara de bits de comprimento c, a qual é armazenada em alguma posição de uma palavra w do computador. Para as operações sobre os bits da palavra do computador, " " é a operação or, " & " é a operação and, " " complementa todos os bits, e " >> " move os bits para a direita e entra com zeros à esquerda (por exemplo, b 1 b 2... b c 1 b c >> 2 = 00b 1... b c 2. Da mesma maneira " << " move os bits para a esquerda e entra com zeros à direita. O algoritmo mantém um conjunto de todos os prefixos de P que casam com o texto já lido e utiliza o paralelismo de bit para atualizar o conjunto a cada caractere lido do texto. Este conjunto é representado por uma máscara de emphbits R = (b 1, b 2,..., b m ). Assim, o algoritmo Shift-And pode ser visto como a simulação de um autômato que pesquisa o padrão no texto. O algoritmo Shift-And usa um algoritmo não determinista para simular o paralelismo de bit. 9

Figura 5: Autômato não-determinista que reconhece todos os prefixo de P = teste. A Figura 5 mostra um autômato não-determinista capaz de reconhecer todos os prefixos do padrão P = teste. O self-loop no vértice 0 significa que o estado permaece ativo durante todo o processamento, permitindo que um casamento possa ser iniciado na posição corrente do texto. Neste caso, mais de um estado pode estar ativo em um determinado instante. Um breve relato sobre o funcionamento do algoritmo Shift-And é dado a seguir. O valor de 1 é colocado na j-ésima posição de R = (b 1, b 2,..., b m ) se e somente se p 1... p j é um sufixo de t 1... t j, em que i corresponde à posição corrente no texto. A j-ésima posição de R é dita estar ativa. Um casamento é relatado sempre que b m fica ativo. Na leitura do próximo caractere t i+1, o novo valor do conjunto R é calculado, o qual denomina-se de R. A posição j + 1 no conjunto R ficará ativa se e somente se a posição j estava ativa em R. Em outras palavras, p 1... p j era um sufixo de t 1... t i e t i+1 casa com p j+1. Com o uso de paralelismo de bit, é possível computar o novo conjunto com custo O(1) em uma linguagem de programação que realize com eficiência as operações and, or, deslocamento à direita e complemento, como no caso da linguagem C. Além disso, se o tamanho do padrão m for menor do que a palavra w do computador, então o conjunto R pode ser implementado em um arranjo de bits que cabe em um registrador do computador. O primeiro passo do algoritmo é a construção de uma tabela M para armazenar uma máscara de bits b 1... b m para cada caractere. A Tabela 2 apresenta as máscaras de bits para os caracteres presente em P = cacbac. A máscara em M[a] é 010010, pois o caractere a aparece nas posições 2 e 5 de P. Tabela 2: Máscara relativa a P = cacbac. 1 2 3 4 5 6 M[a] 0 1 0 0 1 0 M[b] 0 0 0 1 0 0 M[c] 1 0 1 0 0 1 Na fase de pesquisa de P e T, o valor do conjunto é inicializado como R = 0 m (0 m significa 0 repetidos m vezes). Para cada novo caractre t i+1 lido do texto, o valor do conjunto R é atualizado de acordo com a seguinte fórmula: R = ((R >> 1) 10 m 1 ) & M[T [i]] (1) Intuitivamente, a operação " >> " desloca todas as posições para a direita no passo i + 1 para marcar quais posições de P eram suficos no passo i. A cadeia vazia ɛ também é marcada como um sufixo por meio da operação or entre o conjunto 10

obtido após a operação " >> " e 10 m 1. Essa operação permite que um casamento possa iniciar na posição corrente do texto, o que corresponde ao self-loop no início do autômato da Figura 5. No entanto aquela figura faz referência ao padrão P = teste. Do conjunto objtido até o momento são mantidas apenas as posições em que t i+1 casa com p j+1, o que é alcançado por meio da operação and desse conjunto de posições com o conjunto M[t i+1 ] de posições de t i+1 em P. A Tabela 3 mostra o funcionamento do algoritmo Shift-And para pesquisar o padrão P = cacbac no texto T = aabcaccacbac. Tabela 3: Exemplo de funcionamento do algoritmo Shift-And. O 1 na última coluna significa que o estado final está ativo, indicando casamento de P = cacbac no texto. Texto (R >> 1) 10 m 1 R a 1 0 0 0 0 0 0 0 0 0 0 0 a 1 0 0 0 0 0 0 0 0 0 0 0 b 1 0 0 0 0 0 0 0 0 0 0 0 c 1 0 0 0 0 0 1 0 0 0 0 0 a 1 1 0 0 0 0 0 1 0 0 0 0 c 1 0 1 0 0 0 1 0 1 0 0 0 c 1 1 0 1 0 0 1 0 0 0 0 0 a 1 1 0 0 0 0 0 1 0 0 0 0 c 1 0 1 0 0 0 1 0 1 0 0 0 b 1 1 0 1 0 0 0 0 0 1 0 0 a 1 0 0 0 1 0 0 0 0 0 1 0 c 1 0 0 0 0 1 1 0 0 0 0 1 A listagem da implementação em C desse algoritmo pode ser vista no Programa 4. O pré-processamento do padrão para obter a tabela de máscara M é realizado pelos dois primeiros loops (for s). Pode ser visto nesse código em C, o uso efetivo dos operadores de deslocamento de bits. long ShiftAndExato(TipoTextoT T, TipoPadrao P) long Masc[MAXCHAR] ; long i, o; long n, m; long R; / n tamanho do texto / n = strlen(t); / m tamanho do padrao / m = strlen(p); / pre processamento / for ( i = 0; i <MAXCHAR ; i++) Masc[ i ] = 0; for ( i = 1; i <=m; i++) Masc[P[ i 1] + 127] = 1 << (m i ); o = 0; / occurence counter / R = 0; for ( i = 0; i < n; i++) 11

R = ((((unsigned long)r) >> 1) (1 << (m 1))) & Masc[T[ i ] + 127]; if ((R & 1)!= 0) o++; if (VERBOSE>=2) fprintf (stdout,"%05ld %s\n", i+1,t); return o; Programa 4: Implementação do Algoritmo Shift-And Exato Análise. O custo do algoritmo Shift-And é O(n), desde que as operações na Equação 1 possam ser realizadas em O(1) e o padrão caiba em umas poucas palavras do computador. 4.2 Casamento Aproximado Existem variações com relação ao casamento exato de cadeias, sendo a mais importante aquela que permite operações de inserção, de substituição e de retirada de caracteres do padrão. A Figura 6 mostra três ocorrências do padrão teste em que os casos de inserção, de substituição e de retirada de caracteres no padrão acontecem, a saber: no primeiro, um espaço é inserido entre o terceiro e quarto caracteres do padrão; no segundo, o último caractere do padrão é substituído pelo caractere a; e no terceiro, o primeiro caractere do padrão é retirado. tes te testa este os testes testam estes alunos... Figura 6: Exemplo de Casamento aproximado do padrão teste. O número k de operações de inserção, de substituição e de retirada de caracteres necessário para transformar uma cadeia x em outra cadeia y é conhecido na literatura como distância de edição [5]. Assim, a distância de edição entre duas cadeias x e y, ed(x, y) é o menor número de operações necessárias para converter x em y, ou vice-versa. Por exemplo, ed(teste, estende) = 4, valor obtido por meio de uma retirada do primeiro t de P e a inserção dos três caracteres nde ao final de P. O problema do casamento aproximado de cadeias é o de encontrar todas as ocorrências em T de cada P que satisfaz ed(p, P ) k. O problema da busca aproximada somente faz sentido para 0 < k < m, porque no caso de k = m, toda subcadeia de comprimento m pode ser convertida em P por meio da substituição de m caracteres. O caso em que k = 0 corresponde ao casamento exato de cadeias. O nível de erro α = k/m fornece uma medida da fração do padrão que pode ser alterada. Em geral, α < 1/2 para a maioria dos casos de interesse. O casamento aproximado de cadeias, também conhecido como casamento de cadeias permitidno erro, é o problema de encontrar um padrão P em um texto 12

T quando um número limitado k de operações (erros) de inserção, de substituição e de retirada é permitido entre P e suas ocorrências T. 4.2.1 Algoritmo Shift-And Aproximado (SAA) Nesta seção é apresentado uma forma de lidar com o problema de casamento aproximado de cadeias por meio de um autômato não-determinista. Conforme mostrado em [8], uma maneira de tratar o problema do casamento aproximado de cadeias é modelar a pesquisa por um autômato não-determinista. Assim como o algoritmo Shift-And para casamento exato de cadeias apresentado na Seção 4.1.3, o algoritmo que será apresentado também usa o paralelismo de bit, o qual simula o funcionamento de um autômato não-determinista. A Figura 7 apresenta três autômatos não-deterministas para casamento aproximado do padrão P = teste. A primeira linha de cada autômato representa casamento exato e a segunda linha representa casamento aproximado com um erro. A 7(a) mostra o autômato que permite a inserção de um caractere em qualquer posição de P, a Figura 7(b) mostra o autômato que permite a substituição de um caractere em qualuqer posição de P, e a Figura 7(c) mostra o autômato que permite a retirada de um caractere de qualuqer posição de P. Em qualuqer dos três autômatos da Figura 7, uma aresta horizontal representa o casamento de um caractere, isto é, se os caracteres do padrão e do texto casam, então avançamos em P e T. Uma aresta vertical na 7(a) insere um caractere no padrão, o que significa que avançamos em T mas não em P. Uma aresta diagonal sólida na Figura 7(b) substitui um caractere, oque significa que avançamos em T e P. Uma aresta diagnonal tracejada na Figura 7(c) retira um caractere de P, o que significa que avançamos em P, mas não em T, o que equivae a uma transição-ɛ. O self-loop inicial em cada autômato permite que uma ocorrência se inicie emqualquer posição em T. Cada autômato sinaliza uma ocorrência que o estado final mais à direita se torna ativo. A Figura 8 apresenta um autômato que permite casamento aproximado com k = 1 erro para P = teste. Nesse caso, as três operações de distância de edição estão juntas em um único autômato. A liinha 1 representa casamento exato (k = 0), a linha 2 representa casamento aproximado permitindo um erro (k = 1). Uma vez que um estado no autômato está ativo, todos os estados nas linhas seguintes na mesma coluna também estão ativos. O algoritmo Shift-And para casamento aproximado de cadeias, como dito anteriormente, também simula um autômato não-determinista através do paralelismo de bit, como o autômato mostrado na Figura 8. O algoritmo que vamos estudar a seguir é uma extensão do algoritmo Shift-And para casamento exato de cadeias apresetnado na Seção 4.1.3. O algoritmo Shift-And para casamento aproximado de cadeias foi proposto por Wu e Manber em [8]. O algoritmo empacota cada linha j (0 < j k) do autômato não-determinista em uma palavra R j diferente do computador. A cada novo caractere lido do texto, todas as transições do autômato são simuladas usando operações entre as k + 1 máscaras de bits. Todas as k + 1 máscaras de bits têm a mesma estrutura e assim o mesmo bit é alinhado com a mesma posição no texto. Na posição i to texto, os novos valores R j, 0 < j k, são obtidos a partir dos valores correntes R j, a saber: 13

(a) (b) (c) Figura 7: Autômatos para casamento aproximado permitindo um erro. (a) Erro de inserção de caractere. (b) Erro de substituição de um caractere. (c) Erro de retirada de um caractere. Figura 8: Autômato para casamento aproximado permitindo um erro, podendo ser de inserção, de substituição, ou de retirada de um caractere. R 0 = ((R 0 >> 1) (10 m 1 & M[T [i]] R j = ((R j >> 1) & M[T [i]]) R j 1 (R j 1 >> 1) (R j 1 >> 1) 14

onde M é a tabela do algoritmo Shift-And para casamento exato de Seção 4.1.3. A pesquisa inicia com R j = 1 j 0 m j. Conforme esperado, R 0 equivale ao algoritmo Shift-And para casamento exato, e as outras linhas R j recebem 1 s (estados ativos) também de linhas nateriores. Considerando a Figura 8, a fórmula para R expressa arestas horizontais, indicando casamento de um caractere; arestas verticais, indiciando inserção (Rj 1); arestas diagonais cheias, indicando substituição (R j 1 >> 1); e arestas diagonais tracejadas, indicando retirada (R j 1 >> 1). A implementação em C deste algoritmo pode ser vista no Programa 5. long ShiftAndAproximado(TipoTexto T, TipoPadrao P,long k) long Masc[MAXCHAR] ; long i, j, o; long Ri, Rant, Rnovo; long n, m; long R[NUMMAXERROS + 1]; / n tamanho do texto / n = strlen(t); / m tamanho do padrao / m = strlen(p); / pre processamento / for ( i = 0; i <MAXCHAR; i++) Masc[ i ] = 0; for ( i = 1; i <=m; i++) Masc[P[ i 1] + 127] = 1 << (m i ); o = 0; / occurence counter / R[0] = 0; Ri = 1 << (m 1); for ( j = 1; j <= k; j++) R[ j] = (1 << (m j )) R[ j 1]; for ( i = 0; i < n; i++) Rant = R[0]; Rnovo = ((((unsigned long)rant) >> 1) Ri) & Masc[T[ i ] + 127]; R[0] = Rnovo; for ( j = 1; j <= k; j++) Rnovo = ((((unsigned long)r[ j]) >> 1) & Masc[T[ i ] + 127]) Rant (((unsigned long)(rant Rnovo)) >> 1); Rant = R[ j ] ; R[ j ] = Rnovo Ri; if ((Rnovo & 1)!= 0) o++; if (VERBOSE>=2) fprintf (stdout,"%05ld %s\n", i+1,t); return o; Programa 5: Implementação do Algoritmo Shift-And para casamento aproximado de cadeias. 15

Análise. O custo da simulação do autômato é O(k m/w n) no pior caso e no caso médio, o que equivale a O(kn) para padrões típicos na pesquisa em textos (isto é, m w). Em [2] é apresentado um fórmula para o paralelismo de bits que realiza a paralelização pro intermédio da diagonal do autômato, obtendo um algoritmo cujo pior caso é O(n). Uma explicação didática sobre esse algoritmo pode ser obtida em [6]. 4.2.2 Algoritmo usando Programação Dinâmica A solução mais antiga para o problema de casamento de cadeias de caracteres é atribuída a Programação Dinâmica. Descoberta e redescoberta várias vezes desde os anos 60, o algoritmo final é atribuído a Sellers. Embora esse algoritmo não seja muito eficiente, tendo complexidade de tempo O(mn), ele está entre os mais adaptáveis para funções de distâncias mais complexas. Nesta Seção será apresentado o algoritmo de Programação Dinâmica apresentado em [6]. A princípio será mostrado como calcular a distância de edição entre duas cadeias. Depois, o algoritmo será estendido para procurar um padrão em um texto permitindo erros. Então, será mostrado como fazer este algoritmo rápido na média. Computando a distância de Edição É necessário calcular ed(x, y). Uma matriz M 0... P, 0... T é preenchida, onde seus valores M i, j representam o menor número de operações de edição necessárias para emparelhar (match) x 1...i com y 1...j, isto é, M i, j = ed(x 1...i, y 1...j ). Essa matriz é calculado da seguinte maneira: M 0,0 0 M i,j min(m i 1, j 1 +σ(x i, y j ), M i 1, j +1, M i, j 1 +1 onde σ(a, b) = 0 se a = b e 1 caso contrário, e o valor de M é assumido como quando tentativas de acesso fora de seus limites são feitas. No final, M x, y = ed(x, y). A razão dessa forma é a seguinte: M 0,0 é a distância de edição entre duas cadeias vazias. Para duas cadeias de comprimento i e j, assume-se indutivamente que para todas as distâncias de edição entre a menores cadeias já foram calculadas, e tenta-se converter x 1...i em y 1...j. Considere os últimos caracteres x i e y i. Se eles são iguais, então não é necessário considerá-los, somente converter x 1...i 1 em y 1...j 1 à um custo de M i 1, j 1. Por outro lado, se eles não são iguais, deve-se lidar com isso. Seguindo as três operações permitidas, pode-se substituir x i por y i e converter x 1...i 1 em y 1...j 1 à um Custo de M i 1, j 1 +1, remover x i e converter x 1...i 1 em y 1...j à um Custo de M i 1, j +1 ou inserir y j no final de x 1..i e converter x 1...i em y 1...j 1 à um Custo de M i, j 1 +1. Obserque que a inserção em uma cadeia é equivalente a deleção na outra. Portanto, a complexidade de tempo do algoritmo é O( x y ) no caso médio e no pior caso. Uma formulação alternativa que produz uma rápida codificação é a seguinte: M i,0 i, M 0,j j M i 1, j 1 se x i = y j, M i,j 1 + min(m i 1, j 1, M i 1, j, M i, j 1 ) caso contrário (2) 16

que é equivalente ao apresentado anteriormente devido aos elementos vizinhos de M diferirem em no máximo 1. Portanto, quando σ(x i, y i ) = 0, tem-se que M i 1, j 1 não pode ser maior que M i 1, j +1 ou M i, j 1 +1. Através da matriz é possível determinar um caminho ótimo, isto é, uma seqüência de custo mínimo dos elementos da matriz que vão do elemento M 0, 0 até M x, y. Vários caminhos podem existir. Cada caminho é relacionado à um alinhamento, que é um mapeamente entre os caracteres de x e y que mostram como os caracteres foram emparelhados, substituídos, e removidos para fazer x e y iguais. A Tabela 4 ilusta o funcionamento do algoritmo para computador ed(teste, testando). Tabela 4: Um exemplo de algoritmo de Programação Dinâmica para calcular a distância de edição entre "teste" e "testando". O caminho em negrito produz o único alinhamento ótimo. t e s t a n d o 0 1 2 3 4 5 6 7 8 t 1 0 1 2 3 4 5 6 7 e 2 1 0 1 2 3 4 5 6 s 3 2 1 0 1 2 3 4 5 t 4 3 2 1 0 1 2 3 4 e 5 4 3 2 1 1 2 3 4 Busca em Textos Procurar um padrão P em um texto T é basicamente similar à calcular a distância de edição com x = P e y = T. A única diferença é que deve-se permitir uma ocorrência do começo à qualquer posição no texto. Isto é alcançado através do ajuste de M 0, j = 0 para todos os j 0...n. Isto é, o padrão vazio ocorre com erro zero em qualuqer posição porque ele emparelha com uma subcadeia de texto de comprimento zero. O algorimto resultante tem complexidade de tempo O(mn). Se uma matriz M é usada, ela também precisa de espaço O(mn). Entretanto, pode-se trabalhar somente com O(m) em espaço. A observação chave é que para calcular M, j precisa-se somente dos valores de M, j 1. Logo, em vez de construir toda a matriz M, processa-se os caracteres de T um a um e mantém-se uma única coluna de M, que é atualizada depois da leitura de cada nova posição do texto j para manter invariante C i = M i, j. O algorimto inicializa sua coluna C 0...m com os valores C i i e processa o texto caractere por caractere. A cada novo caractere do texto t j, seu vetor coluna é atualizado para C 0..m. A fórmula de atualização é C i C i 1 se p i = t j, 1 + min(c i 1, C i 1, C i ) caso contrário e as posições do texto onde C m k são ditas como posições finais de ocorrências. Observe que se C = M, j 1 é a coluna antiga e C = M, j é a coluna nova, então C i 1 corresponde a M i 1, j 1, C i 1 a M i 1, j e C i a M i, j 1 na Equação 2. 17

A Tabela 5 apresenta o resulatdo deste algoritmo para procurar o padrão P = teste no texto T = testanto com no máximo k = 2 erros. Neste caso existem quatro ocorrências. Tabela 5: Um exemplo de algoritmo de Programaçao Dinâmica para procurar o padrão P = teste no texto T = testanto com dois erros. Cada coluna dessa matriz é um valor da coluna C em algum ponto do tempo. Elementos em negrito indicam posições de casamento de cadeias. t e s t a n d o 0 0 0 0 0 0 0 0 0 t 1 0 1 1 1 1 1 1 1 e 2 1 0 1 2 2 2 2 2 s 3 2 1 0 1 2 3 3 3 t 4 3 2 1 0 1 2 3 4 e 5 4 3 2 1 1 2 3 4 Melhorando o caso médio Uma simples mistura para o algoritmo de Programação Dinâmica, que mantém a flexibilidade tem complexidade de tempo O(kn). A idéia é que, desde que um padrão não emparelha normalmente em um texto, os valores lidos em cada coluna do topo até o fundo rapidamente alcançam k + 1 (i.e. desemparelhamento), e que se um elemento tem um valor maior que k + 1, o resultado da procura não depende do seu valor exato. Um elemento é chamado ativo se seu valor é no máximo k. O algoritmo mantém um contador do último elemento ativo e evita o trabalho nos elementos subsequentes. O último elemento ativo é recalculado para cada nova coluna. Quando o movimento é feito de uma posição do texto para a próxima, o último elemento ativo pode ser incrementado por no máximo um desde que a vizinhança em M difere por no máximo um, então verifica-se em tempo constante se o próximo elemento ficará ativo. Embora, também seja possível que o último elemento anteriormente ativo torne-se inativo agora. Neste caso deve-se procurar subindo a coluna pelo novo último elemento ativo. Embora pode-se trabalhar com O(m) operações em uma dada coluna, não se pode trabalhar com mais de O(n) operações no total, pois existe no máximo n incrementos deste valor em todo o processo, e portanto não existe mais do que n decrementos. Então, o último elemento ativo é mantido em O(1) no pior caso amortizado de custo por coluna. O resultado desse processo é ilustrado no Algoritmo 1 através de um pseudocódigo. A idéia básica é evitar o calculo de alguns elementos inativos quem têm sido usados extensivamente em outros algoritmos. Uma implementação do Algoritmo 1 pode ser vista em 6 long PD(TipoTextoT T, TipoPadrao P,long k) long i, pos, o; long n, m; long lact,nc,pc; 18

Algorítmo 1 Um algoritmo de Programação Dinâmica com tempo esperado de O(kn). Observe que ele trabalha somente com um vetor coluna (O(m) de espaço). procedure DP (P = p 1 p 2...p m, T = t 1 t 2...t n, k) Preprocessing for i 0...m do C i i end for lact k + 1 last active cell Searching for pos 1...n do pc 0, nc 0 for i 1...lact do if p i = t pos then nc pc else if pc < nc then nc pc end if if C i < nc then nc C i end if nc nc + 1 end if pc C i, C i nc end for while C lact > k do lact lact 1 end while if lact = m then report an occurence at pos else lact lact + 1 end if end for end 19

long C; / n tamanho do texto / n = strlen(t); / m tamanho do padrao / m = strlen(p); / xxx / C = (long )malloc( sizeof(long) (m+1)); / preprocessing / for( i=0;i<=m; i++) C[ i ] = i ; o = 0; / occurence counter / lact = k + 1; / searching / for(pos=1;pos<=n; pos++) pc = 0; nc = 0; for( i=1;i<=lact ; i++) if (P[ i 1] == T[pos 1]) nc = pc; else if (pc < nc) nc = pc; if (C[ i ] < nc) nc = C[ i ] ; nc++; pc = C[ i ] ; C[ i ] = nc; / seach upwards in the column for the new last active c e l l / while(c[ lact] > k) lact ; if ( lact ==m) o++; if (VERBOSE>=2) fprintf (stdout,"%05ld %s\n", i+1,t); else lact++; free (C); return o; Programa 6: Implementação do Algoritmo de Programação Dinâmica. 20

5 Experimentos Os experimentos realizados neste trabalho tomam os padrões apresentados na Tabela 6 com os textos/arquivos apresentados na Tabela 1. Para os experimentos de casamento de cadeias exato foram escolhidos dez padrões. Para o casamento de cadeias aproximado também foram escolhidos 10 padrões. Esse número e a distribuição escolhida é suficiente para plotar curvas que dão interpretação ao desenvolvimento dos algoritmos a serem comparados. Para os experimentos de casamento de cadeias aproximado foram escolhidos somente palavras/padrões com menos de 32 caracteres, pois a implementação é limitada ao tamanho da palavra da arquitetura Intel de 32 bits. Tabela 6: Padrões utilizados nos experimentos. A primeira coluna mostra os padrões, a segunda o número de caracteres do padrão. A terceira e quarta coluna mostram em qual experimentos o padrão será utilizado. Padrão Tamanho Exato Aproximado DCC 3 x x That 4 x Stock 5 x x Uberaba 7 x x Exchange 8 x Price Index 11 x x DCC UFMG dollar 15 x Brazilian coffee 16 x x New York Stock Exchange 23 x x The agency sees widespread 30 x x use many investors now riding 49 x the Tokyo rocket are so Low wages and a large work 93 x force attract the investors, while suprisingly robust agricultural Mr. Jordan said the provision 119 x allowing non-lawyers to be partners reflects shifts in providing legal services that have Para tornar mais justa a comparação com o programa agrep, os algoritmos foram adaptados a pararem de processar uma linha caso uma ocorrência de casamento aconteça. Isto porque o programa agrep comporta-se desta maneira. Nos experimentos também foram omitidos a impressão dos casamentos. Somente foram impressos o número de ocorrências de casamentos, o que permitia verificar a integridade dos resultados apresentados pelos algoritmos implementados com o programa agrep. 21

Para estes testes foram implementados duas versões para cada algoritmo. Na primeira o programa carregava todo arquivo em memória e na segunda o programa carregava um única linha por vez. A primeira implementação foi a mais rápida em tempo de relógio, isto porque o tempo de I/O e CPU foi otimizado, ou seja, todo o arquivo era carregado em memória (operação de I/O) e depois era processado (operação de CPU ). Isto evita que a CPU fique ociosa aguardando a leitura de blocos menores. As duas implementações estão anexadas ao final do trabalho. No entanto, somente os resultados relativos a primeira implementação foram reportados. 5.1 Casamento de Cadeias Exato - Tempo Foram executados 160 testes sobre os quatro arquivos base. Sendo que em cada um deles foram testados 10 padrões diferentes, conforme indicado pela Tabela 6. Esse conjunto de 10 padrões foram submetidos a quatro algoritmos diferentes: BMH, BMHS, Shift-And Exato e o agrep - um software livre com implementação rápida disponível na rede do DCC/ICEx/UFMG. Então, dado quatro algoritmos, quatro arquivos/base e 10 padrões a serem testados, isso perfaz o total de 160 testes realizados. Os experimentos realizados sobre a menor base, wsj89, são apresentados na Figura 9. Apesar do baixo suporte estatístico apresentado por este gráfico, visto o pequeno tempo de execução dos algoritmos comparado com a resolução (10 milisegundos) do programa de captura de tempo de processo (comando time do Sistema Operacional Linux), pode-se tecer as seguintes conclusões. O algoritmo agrep foi o mais rápido para essa base, tendo tempo de processamento zero (resolução do time - 10 milisegundos). O algoritmo BMH foi superior, ou seja mais rápido que o BMHS para grandes valores. O pior de todos foi o algoritmo Shift-And Exato, conforme esperado pela sua complexidade de tempo O(mn). Isto já era sabido, pois o programa agrep é uma implementação rápida e usual na prática. Análises similares podem ser feitas sobre os gráficos das Figuras 10 e 11. Nestas duas figuras fica mais evidente que o programa agrep não apresenta resultados para padrões maiores que 50 caracteres. Empiricamente verificou-se que ele tem alguma restrição ao tamanho do conjunto de caracteres que é utilizado em relação ao alfabeto. No entanto, essa restrição não está muito clara. Novamente, o pior desempenho ficou com o algoritmo Shift-And Exato e o melhor com o programa agrep. Para os algoritmos BMH e BMHS não ficou claro qual tem o melhor desempenho. Melhores análises são obtidas através do gráfico da Figura 12. As curvas deste gráfico são mais suavizadas devido a uma melhor resolução (relação entre tempo do algoritmo e resolução de tempo do sistema). Realmente, o programa agrep é o mais rápido de todos, e o algoritmo Shift-And é o mais lento. O algoritmo BMHS é ligeiramente mais rápido que o algoritmo BMH para padrões de pequeno tamanho, já para tamanhos médios e grandes (maior que 20 caracteres) de padrões o desempenho de ambos é bem aproximado. Uma conclusão importante após observar o gráfico dessa figura é que o tamanho do padrão é pouco sensitivo ao tempo de processamento dos algoritmos. Uma leve relação pode ser estabelecida. O tempo de processamento diminui a medida que o tamanho do padrão cresce e esse tempo se estabiliza após um certo tamanho de padrão. Esse raciocínio pode ser aplicado aos algoritmos BMH, BMHS e ao programa agrep. 22

Figura 9: Experimentos para casamento exato de cadeias com o arquivo wsj89. O tempo é dado em segundos e o eixo x apresenta o tamanho dos caracteres. 0.045 0.04 0.035 0.03 tempo em segundos 0.025 0.02 0.015 0.01 0.005 agrep BMH BMHS SAE 0 0 20 40 60 80 100 120 tamanho do padrão Figura 10: Experimentos para casamento exato de cadeias com o arquivo wsj88_10. O tempo é dado em segundos e o eixo x apresenta o tamanho dos caracteres. 0.11 0.1 0.09 0.08 tempo em segundos 0.07 0.06 0.05 0.04 0.03 agrep 0.02 BMH BMHS SAE 0.01 0 20 40 60 80 100 120 tamanho do padrão Analisando-se os gráficos das Figuras 9, 10, 11 e 12 verifica-se que para o algoritmo Shift-And Exato o tempo de processamento é proporcional/sensitivo somente ao tamanho do arquivo (texto). 23

Figura 11: Experimentos para casamento exato de cadeias com o arquivo wsj88_20. O tempo é dado em segundos e o eixo x apresenta o tamanho dos caracteres. 0.25 0.2 tempo em segundos 0.15 0.1 0.05 agrep BMH BMHS SAE 0 0 20 40 60 80 100 120 tamanho do padrão Figura 12: Experimentos para casamento exato de cadeias com o arquivo wsj88. O tempo é dado em segundos e o eixo x apresenta o tamanho dos caracteres. 1.2 1 0.8 tempo em segundos 0.6 0.4 0.2 agrep BMH BMHS SAE 0 0 20 40 60 80 100 120 tamanho do padrão 5.2 Casamento de Cadeias Exato - Número de Comparações Uma análise mais refinada pode ser feita para comparar o desempenho dos algoritmos BMH e BMHS, através do número de comparações realizadas entre o padrão e o texto. Analisando-se os gráficos das Figuras 13, 14, 15 e 16 pode chegar a seguinte conclusão. O algorimto BMHS apresentou desempenho ligeiramente superior, ou seja menos comparações, que o algoritmo BMH para padrões pequenos 24

Figura 13: Experimentos para casamento exato de cadeias com o arquivo wsj89 relativo ao número de comparações efetuado pelos algoritmos BMH e BMHS. 1e+06 900000 800000 número de comparações 700000 600000 500000 400000 300000 200000 BMH BMHS 100000 0 20 40 60 80 100 120 tamanho do padrão Figura 14: Experimentos para casamento exato de cadeias com o arquivo wsj88_10 relativo ao número de comparações efetuado pelos algoritmos BMH e BMHS. 3.5e+06 3e+06 2.5e+06 número de comparações 2e+06 1.5e+06 1e+06 500000 BMH BMHS 0 0 20 40 60 80 100 120 tamanho do padrão (menores que 16 caracteres). Para padrões com tamanho mediano (entre 16 e 49 caracteres), o algoritmo BMH foi ligeiramente superior que o BMHS. Para padrões de grande tamanho os algoritmos apresentam desempenho similar. Vale ressaltar que estes dois algoritmos trabalham com deslocamentos baseado nos padrões (fase de pré-processamento) e essas conclusões são extraídas com base em um número de padrões muito baixo, o que implica dizer que as conclusões não são fortes, ou seja, 25

Figura 15: Experimentos para casamento exato de cadeias com o arquivo wsj88_20 relativo ao número de comparações efetuado pelos algoritmos BMH e BMHS. 7e+06 6e+06 5e+06 número de comparações 4e+06 3e+06 2e+06 1e+06 BMH BMHS 0 0 20 40 60 80 100 120 tamanho do padrão Figura 16: Experimentos para casamento exato de cadeias com o arquivo wsj88 relativo ao número de comparações efetuado pelos algoritmos BMH e BMHS. 4e+07 3.5e+07 3e+07 número de comparações 2.5e+07 2e+07 1.5e+07 1e+07 5e+06 BMH BMHS 0 0 20 40 60 80 100 120 tamanho do padrão limitadas a esses experimentos. 5.3 Casamento de Cadeias Aproximado - Tempo Para os experimentos realizados nessa seção foram levados em conta dez padrões com tamanho menor que 32 caracteres. Restrição essa imposta pelo algoritmo Shift-And 26

Aproximado, relativo ao tamanho da palavra da arquitetura Intel (32 bits). Para o algoritmo de Programação Dinâmica implementado, não existe restrição relativa ao tamanho da palavra, e esse tem complexidade de espaço de O(m). Os padrões selecionados são os apontados pela Tabela 6, quarta coluna. Para as próximas quatro figuras foi utilizado somente o arquivo/base wsj88, por motivos de espaço e coesão. Figura 17: Experimentos para casamento aproximado de cadeias com o arquivo wsj88 para o programa agrep. 3.5 3 k=1 k=2 k=3 2.5 tempo em segundos 2 1.5 1 0.5 0 0 5 10 15 20 25 30 tamanho do padrão Figura 18: Experimentos para casamento aproximado de cadeias com o arquivo wsj88 para o algoritmo Shift-And Aproximado. 3.8 3.6 k=1 k=2 k=3 3.4 3.2 tempo em segundos 3 2.8 2.6 2.4 2.2 2 1.8 0 5 10 15 20 25 30 tamanho do padrão 27

Figura 19: Experimentos para casamento aproximado de cadeias com o arquivo wsj88 para o algoritmo Programação Dinâmica. 6.5 6 k=1 k=2 k=3 5.5 tempo em segundos 5 4.5 4 3.5 3 2.5 0 5 10 15 20 25 30 tamanho do padrão Com um pouco de boa vontade, pode-se afirmar através dos resultados apresentados nos gráficos das Figuras 17, 18 e 19 que o tempo de processamento dos algoritmos aproximados são independentes do tamanho do padrão e linearmente dependentes do número de erros tolerados (k). No entanto, o programa agrep (Figura 17) apresenta alta sensitividade para padrões pequenos (menos de 10 caracteres), enquanto que o algoritmo de Programação Dinâmica implementado (Figura 19) se mantém relativamente estável até um tamanho médio atingindo estabilidade para padrões maiores. Seguramente, o algoritmo Shift-And Aproximado (Figura 18) foi o que apresentou desempenho mais estável. Quanto ao tempo de execução: O programa agrep foi o mais rápido na maioria das situações, sendo seguido pelo algoritmo Shift-And Aproximado. Por último, apresenta-se a implementação do Algoritmo de Programação Dinâmica. Segundo [6] existem algoritmos de Programação Dinâmica com ordem de complexidade melhor que a apresentada por esta implementação, O(kn). Talvez uma dessas implementações seja a do programa agrep. Essa comparação entre os três algoritmos implementados, fica mais evidente quando os três são plotados em um único gráfico com um mesmo número de erro k. Essa situação (k = 3) é apresentada no gráfico da Figura 20. Para mostrar que os algoritmos são sensitivos também ao tamanho do arquivo, plotou-se o gráfico da Figura 21. No eixo x está o tamanho dos arquivos base utilizados de acordo com a Tabela 1. Cada curva representa o desenvolvimento do tempo de processo de cada algoritmo ou programa executado, mostrando que os algoritmos e programa são dependentes do tamanho do arquivo/texto a ser processado. 28

Figura 20: Experimentos para casamento aproximado de cadeias com o arquivo wsj88 e k = 3. agrep - o programa, SAA - Shift-And Aproximado e PD - Programação Dinâmica. 7 6 agrep SAA PD 5 tempo em segundos 4 3 2 1 0 0 5 10 15 20 25 30 tamanho do padrão Figura 21: Experimentos para casamento aproximado de cadeias com o padrão DCC UFMG dollar para os quatro arquivos. agrep - o programa, SAA - Shift-And Aproximado e PD - Programação Dinâmica. 3.5 3 agrep SAA PD 2.5 tempo em segundos 2 1.5 1 0.5 0 0 20 40 60 80 100 120 tamanho do padrão 6 Conclusões Após a confecção deste trabalho, chega-se as seguintes conclusões: O programa agrep foi superior a todos os algoritmos implementados neste 29