UMA ABORDAGEM EM HARDWARE PARA ... - Bioserver
UMA ABORDAGEM EM HARDWARE PARA ... - Bioserver
UMA ABORDAGEM EM HARDWARE PARA ... - Bioserver
You also want an ePaper? Increase the reach of your titles
YUMPU automatically turns print PDFs into web optimized ePapers that Google loves.
<strong>UMA</strong> <strong>ABORDAG<strong>EM</strong></strong> <strong>EM</strong> <strong>HARDWARE</strong> <strong>PARA</strong><br />
ALGORITMOS DE COM<strong>PARA</strong>ÇÃO DE SEQÜÊNCIAS<br />
BASEADOS <strong>EM</strong> PROGRAMAÇÃO DINÂMICA<br />
LUÍS GUSTAVO DE AQUINO CARVALHO<br />
DISSERTAÇÃO DE MESTRADO <strong>EM</strong> CIÊNCIA DA COMPUTAÇÃO<br />
DEPARTAMENTO DE CIÊNCIA DA COMPUTAÇÃO
UNIVERSIDADE DE BRASÍLIA<br />
INSTITUTO DE CIÊNCIAS EXATAS<br />
DEPARTAMENTO DE CIÊNCIA DA COMPUTAÇÃO<br />
<strong>UMA</strong> <strong>ABORDAG<strong>EM</strong></strong> <strong>EM</strong> <strong>HARDWARE</strong> <strong>PARA</strong><br />
ALGORITMOS DE COM<strong>PARA</strong>ÇÃO DE SEQÜÊNCIAS<br />
BASEADOS <strong>EM</strong> PROGRAMAÇÃO DINÂMICA<br />
LUÍS GUSTAVO DE AQUINO CARVALHO<br />
ORIENTADOR: PROF. DR. RICARDO PEZZUOL JACOBI<br />
DISSERTAÇÃO DE MESTRADO <strong>EM</strong><br />
CIÊNCIA DA COMPUTAÇÃO<br />
PUBLICAÇÃO: XXX/2003<br />
BRASÍLIA/DF, DEZ<strong>EM</strong>BRO/2003.
UNIVERSIDADE DE BRASÍLIA<br />
INSTITUTO DE CIÊNCIAS EXATAS<br />
DEPARTAMENTO DE CIÊNCIA DA COMPUTAÇÃO<br />
<strong>UMA</strong> <strong>ABORDAG<strong>EM</strong></strong> <strong>EM</strong> <strong>HARDWARE</strong> <strong>PARA</strong><br />
ALGORITMOS DE COM<strong>PARA</strong>ÇÃO DE SEQÜÊNCIAS<br />
BASEADOS <strong>EM</strong> PROGRAMAÇÃO DINÂMICA<br />
LUÍS GUSTAVO DE AQUINO CARVALHO<br />
DISSERTAÇÃO DE MESTRADO SUBMETIDA AO DEPARTAMENTO DE CIÊNCIA<br />
DA COMPUTAÇÃO DO INSTITUTO DE CIÊNCIAS EXATAS DA UNIVERSIDADE<br />
DE BRASÍLIA, COMO PARTE DOS REQUISITOS NECESSÁRIOS <strong>PARA</strong> A OBTEN-<br />
ÇÃO DO GRAU DE MESTRE.<br />
APROVADA POR:<br />
PROF. DR. RICARDO PEZZUOL JACOBI (UnB)<br />
(ORIENTADOR)<br />
PROF a DR a MARIA <strong>EM</strong>ÍLIA MACHADO TELLES WALTER (UnB)<br />
(EXAMINADOR INTERNO)<br />
PROF. DR. JOSÉ CAMARGO DA COSTA (UnB)<br />
(EXAMINADOR EXTERNO)<br />
BRASÍLIA/DF, 17 DE DEZ<strong>EM</strong>BRO DE 2003.<br />
ii
FICHA CATALOGRÁFICA<br />
CARVALHO, LUÍS GUSTAVO DE AQUINO<br />
Uma Abordagem em Hardware para Algoritmos de Comparação de Seqüências<br />
Baseados em Programação Dinâmica [Distrito Federal] 2003.<br />
xiv, 100 p., 297mm (CIC/IE/UnB, Mestre, Ciência da Computação, 2003).<br />
Dissertação de Mestrado — Universidade de Brasília. Instituto de Ciências<br />
Exatas. Departamento de Ciência da Computação.<br />
1. Comparação de seqüências 2. Smith-Waterman<br />
3. Arquiteturas Reconfiguráveis 4. FPGA<br />
5. Arquiteturas Sistólicas<br />
I. CIC/IE/UnB II. Título (série)<br />
REFERÊNCIA BIBLIOGRÁFICA<br />
CARVALHO, L. G. A. (2003). Uma Abordagem em Hardware para Algoritmos de<br />
Comparação de Seqüências Baseados em Programação Dinâmica. Dissertação de Mestrado,<br />
Publicação XXX/2003, Departamento de Ciência da Computação, Universidade de<br />
Brasília, Brasília, DF, 100 p.<br />
CESSÃO DE DIREITOS<br />
NOME DO AUTOR: Luís Gustavo de Aquino Carvalho<br />
TÍTULO DA DISSERTAÇÃO DE MESTRADO: Uma Abordagem em Hardware para<br />
Algoritmos de Comparação de Seqüências Baseados em Programação Dinâmica.<br />
GRAU / ANO: Mestre / 2003<br />
É concedida à Universidade de Brasília permissão para reproduzir cópias desta dissertação<br />
de mestrado e para emprestar ou vender tais cópias somente para propósitos acadêmicos e<br />
científicos. O autor reserva outros direitos de publicação e nenhuma parte desta dissertação<br />
de mestrado pode ser reproduzida sem a autorização por escrito do autor.<br />
Luís Gustavo de Aquino Carvalho<br />
iii
iv<br />
A minha família.
Agradecimentos<br />
Aos meus pais, pela formação que me foi dada e por todo o amor recebido.<br />
Ao meu orientador, Prof. Ricardo Jacobi, por sua paciência, compreensão<br />
e excelência acadêmica.<br />
Aos meus amigos, em especial ao Antônio Marcelo que me apresentou ao<br />
meu orientador e me incentivou a trabalhar com arquiteturas reconfiguráveis;<br />
à Marie, pela grande ajuda durante a conclusão das disciplinas, além de grande<br />
companheira; à Márcia, pela sua prontidão em elucidar dúvidas; ao Hugo e<br />
Cristiano, pelas constantes trocas de idéias e pela valiosa ajuda na formatação<br />
em L A TEX desta dissertação.<br />
E principalmente à minha esposa e filhos, por todos os momentos que deixei<br />
de estar com eles para me dedicar à essa dissertação.<br />
v
<strong>UMA</strong> <strong>ABORDAG<strong>EM</strong></strong> <strong>EM</strong> <strong>HARDWARE</strong> <strong>PARA</strong><br />
ALGORITMOS DE COM<strong>PARA</strong>ÇÃO DE SEQÜÊNCIAS<br />
BASEADOS <strong>EM</strong> PROGRAMAÇÃO DINÂMICA<br />
Resumo<br />
Pesquisas em bancos de dados biológicos utilizam algoritmos de comparação<br />
de seqüências para busca de similaridades entre as seqüências armazenadas<br />
nestes bancos e a seqüência consultada. Embora os algoritmos de comparação<br />
baseados em programação dinâmica retornem uma resposta ótima, eles não<br />
são usados na prática dos laboratórios de Bioinformática, pois a complexidade<br />
quadrática de tempo é um fator limitante em virtude do considerável tamanho<br />
das seqüências biológicas.<br />
Métodos mais rápidos, baseados em probabilidades, mas sem garantia de<br />
exatidão, são preferidos por possuírem uma complexidade linear de tempo.<br />
Assim, a aplicação de técnicas que acelerem e viabilizem a utilização dos<br />
algoritmos baseados em programação dinâmica constitui uma importante contribuição<br />
para a qualidade da informação produzida.<br />
Dentre essas técnicas está a criação de um hardware dedicado para uma<br />
aplicação específica. Nesse escopo, os sistemas reconfiguráveis baseados em<br />
FPGA’s encontram grande aplicação, pois permitem a prototipação em hardware<br />
de algoritmos bastante complexos com baixos custos.<br />
Este trabalho propõe e implementa em FPGA um hardware baseado em<br />
uma arquitetura sistólica que lineariza o tempo de execução dos algoritmos<br />
baseados em programação dinâmica.<br />
A fim de validar os resultados obtidos foram realizadas comparações com<br />
outras implementações seqüenciais e paralelas desses algoritmos.<br />
vi
A <strong>HARDWARE</strong> APPROACH<br />
TO SEQUENCE COMPARISON ALGORITHMS<br />
BASED ON DYNAMIC PROGRAMMING<br />
Abstract<br />
Sequence comparison algorithms are used in biological database searches<br />
in order to find similarities between the database sequences and a query sequence.<br />
Although the comparison algorithms based on dynamic programming<br />
techniques produces an optimal result, they are not used by Bioinformatics<br />
laboratories, once its quadratic time complexity is prohibitive in view of the<br />
considerable size of the biological sequences.<br />
Faster methods, based on probabilities, but without precision guarantee,<br />
are preferred for its linear time complexity.<br />
Therefore, improving sequence comparison algorithms based on dynamic<br />
programming constitutes an important contribution to the quality of the information<br />
produced.<br />
A dedicated hardware for an specific application could be one of this solutions.<br />
In this scope, reconfigurable systems find enormous application because<br />
they provide rapid prototyping of complex algorithms with small costs.<br />
In this work, we propose and implement in FPGA a systolic architecture<br />
based hardware which turns to linear the time complexity of the comparison<br />
algorithms based on dynamic programming.<br />
In order to validate the results produced by our implementation, we compared<br />
our results with the ones produced by other sequential and parallel<br />
implementations of the same algorithm.<br />
vii
Sumário<br />
1 INTRODUÇÃO 1<br />
1.1 Escopo do Trabalho . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1<br />
1.1.1 Projeto Genoma Humano . . . . . . . . . . . . . . . . . . . . . . . 1<br />
1.1.2 Pesquisas no Brasil . . . . . . . . . . . . . . . . . . . . . . . . . . . 3<br />
1.1.3 Bioinformática e Biologia Computacional . . . . . . . . . . . . . . . 4<br />
1.1.4 Pesquisas em Bancos de Dados Biológicos . . . . . . . . . . . . . . 5<br />
1.1.5 Algoritmos para Comparação de Seqüências . . . . . . . . . . . . . 6<br />
1.2 Revisão Bibliográfica . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7<br />
1.3 Objetivos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9<br />
1.4 Organização da Dissertação . . . . . . . . . . . . . . . . . . . . . . . . . . 10<br />
2 FUNDAMENTAÇÃO TEÓRICA 11<br />
2.1 Biologia Molecular . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11<br />
2.1.1 Ácidos Nucléicos . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11<br />
2.1.1.1 DNA . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13<br />
2.1.1.2 RNA . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14<br />
2.1.2 Aminoácidos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15<br />
2.1.3 Proteínas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16<br />
2.1.4 Genes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18<br />
2.1.5 Genética Molecular . . . . . . . . . . . . . . . . . . . . . . . . . . . 19<br />
2.1.6 Síntese Protéica . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20<br />
2.2 Algoritmos para Comparação de Seqüências Baseados em Programação<br />
Dinâmica . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22<br />
viii
2.2.1 Alinhamento de seqüências . . . . . . . . . . . . . . . . . . . . . . . 22<br />
2.2.2 Algoritmos baseados em programação dinâmica . . . . . . . . . . . 24<br />
2.2.2.1 Comparação global . . . . . . . . . . . . . . . . . . . . . . 24<br />
2.2.2.2 Comparação local . . . . . . . . . . . . . . . . . . . . . . . 27<br />
3 <strong>HARDWARE</strong> 30<br />
3.1 Sistemas Dedicados . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30<br />
3.2 Arquiteturas Sistólicas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33<br />
3.3 Sistemas Reconfiguráveis . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35<br />
3.3.1 FPGA . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38<br />
3.3.2 Síntese de sistemas reconfiguráveis . . . . . . . . . . . . . . . . . . 39<br />
3.3.3 Linguagens de descrição de hardware e VHDL . . . . . . . . . . . . 41<br />
3.4 Somadores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44<br />
3.4.1 Meio-somador (half adder) . . . . . . . . . . . . . . . . . . . . . . . 44<br />
3.4.2 Somador completo (full adder) . . . . . . . . . . . . . . . . . . . . 45<br />
3.4.3 Somador ripple carry . . . . . . . . . . . . . . . . . . . . . . . . . . 45<br />
3.4.4 Somador com “vai-um” antecipado (carry look ahead) . . . . . . . . 46<br />
3.4.5 Subtrator . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48<br />
3.5 Matrizes esparsas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48<br />
3.5.1 Compressed Row Storage (CRS) . . . . . . . . . . . . . . . . . . . . 49<br />
3.5.2 Compressed Column Storage (CCS) . . . . . . . . . . . . . . . . . . 50<br />
3.5.3 Compressed Diagonal Storage (CDS) . . . . . . . . . . . . . . . . . 50<br />
3.5.4 Jagged Diagonal Storage (JDS) . . . . . . . . . . . . . . . . . . . . 51<br />
4 DESCRIÇÃO DA IMPL<strong>EM</strong>ENTAÇÃO 52<br />
4.1 Aplicação de Estruturas Paralelas na comparação de seqüências . . . . . . 52<br />
4.2 Dependência de Dados . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53<br />
4.3 Plataforma Utilizada . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53<br />
4.4 Descrição Geral . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53<br />
4.4.1 Estrutura sistólica . . . . . . . . . . . . . . . . . . . . . . . . . . . 54<br />
ix
4.4.2 Otimização de Utilização de Espaço e Armazenamento dos Alinhamentos<br />
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66<br />
4.4.3 Outras otimizações . . . . . . . . . . . . . . . . . . . . . . . . . . . 70<br />
5 RESULTADOS 72<br />
5.1 Validação . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72<br />
5.2 Desempenho . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77<br />
6 CONCLUSÕES 81<br />
x
Lista de Tabelas<br />
1.1 Projetos Regionais de Seqüenciamento no Brasil. . . . . . . . . . . . . . . . 4<br />
2.1 Principais diferenças entre o DNA e o RNA. . . . . . . . . . . . . . . . . . 15<br />
2.2 Os 20 diferentes tipos de aminoácidos encontrados na natureza. . . . . . . 17<br />
3.1 Tabela-verdade do meio-somador (half adder). . . . . . . . . . . . . . . . . 44<br />
3.2 Tabela-verdade do somador completo (full adder). . . . . . . . . . . . . . . 45<br />
5.1 Quantidade de elementos lógicos utilizados e freqüência máxima de operação<br />
para diferentes comprimentos do vetor sistólico. . . . . . . . . . . . . . . . 77<br />
5.2 Comparação de velocidade entre uma implementação seqüencial, diversas<br />
paralelas e em hardware do algoritmo baseado em programação dinâmica. . 80<br />
xi
Lista de Figuras<br />
1.1 Crescimento do GenBank. . . . . . . . . . . . . . . . . . . . . . . . . . . . 6<br />
1.2 Mapeamento do cálculo da matriz de similaridade em uma estrutura sistólica<br />
bidirecional. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7<br />
2.1 Bases Nitrogenadas. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12<br />
2.2 Tipos de Açúcares. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12<br />
2.3 A estrutura de uma molécula de DNA, formada por uma dupla fita. (a)<br />
Forma helicoidal da dupla cadeia. (b) Forma esquemática da dupla cadeia,<br />
onde podemos visualizar a ligação entre as moléculas de açúcar (S)<br />
e de fosfato (P), em cada uma das fitas, e o emparelhamento das bases<br />
Adenina/Timina e Citosina/Guanina, entre as duas fitas. . . . . . . . . . . 13<br />
2.4 Dupla fita de DNA, observando-se o pareamento das bases A-T e C-G. . . 14<br />
2.5 Exemplo de alguns grupos orgânicos. . . . . . . . . . . . . . . . . . . . . . 15<br />
2.6 Estrutura e exemplos de alguns aminoácidos. . . . . . . . . . . . . . . . . . 16<br />
2.7 União de dois aminoácidos por uma ligação peptídica. . . . . . . . . . . . . 16<br />
2.8 Visão esquemática dos genes, cromossomos e genoma. . . . . . . . . . . . . 19<br />
2.9 Código genético. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19<br />
2.10 Duplicação do DNA. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20<br />
2.11 Representação esquemática da transcrição e tradução. . . . . . . . . . . . . 21<br />
2.12 Detalhamento do processo de tradução. . . . . . . . . . . . . . . . . . . . . 21<br />
2.13 Pontuação de um possível alinhamento entre CCTAGA e CTATGCAC. . . 23<br />
2.14 Matriz de similaridades das seqüências x = AACGT e y = AGC. . . . . . 26<br />
2.15 Obtenção do melhor alinhamento global. . . . . . . . . . . . . . . . . . . . 27<br />
3.1 Aspecto geral de uma arquitetura sistólica. . . . . . . . . . . . . . . . . . . 33<br />
3.2 Alguns tipos de estruturas sistólicas. . . . . . . . . . . . . . . . . . . . . . 34<br />
3.3 Modelos segundo a classificação de Page. . . . . . . . . . . . . . . . . . . . 37<br />
xii
3.4 Estrutura interna de um FPGA. . . . . . . . . . . . . . . . . . . . . . . . . 39<br />
3.5 Fluxo de projeto utilizando FPGAs. . . . . . . . . . . . . . . . . . . . . . . 40<br />
3.6 Diagrama esquemático do meio-somador. . . . . . . . . . . . . . . . . . . . 45<br />
3.7 Diagrama esquemático do somador completo. . . . . . . . . . . . . . . . . 46<br />
3.8 Diagrama de um somador ripple carry de 4 bits. . . . . . . . . . . . . . . . 46<br />
3.9 Diagrama de um somador de 4 bits com “vai-um” antecipado. . . . . . . . 47<br />
3.10 Diagrama de um somador de 16 bits com “vai-um” antecipado. . . . . . . . 48<br />
3.11 Diagrama de um somador-subtrator de 4 bits. . . . . . . . . . . . . . . . . 48<br />
4.1 Paralelização do cálculo da matriz de similaridade. . . . . . . . . . . . . . . 53<br />
4.2 Matriz de similaridade para as seqüências ACATAGGCAT e CATAAGGCT. 54<br />
4.3 Tipos de emulação da matriz de similaridade. . . . . . . . . . . . . . . . . 55<br />
4.4 Estrutura linear sistólica uniderecional. . . . . . . . . . . . . . . . . . . . . 56<br />
4.5 Estrutura interna inicial do elemento de processamento. . . . . . . . . . . . 57<br />
4.6 Fluxo interno dos dados dentro do elemento de processamento. . . . . . . . 58<br />
4.7 Dinâmica do sistema para vários elementos de processamento. . . . . . . . 58<br />
4.8 Somador de 8 bits com a constante -2 embutida no mesmo. . . . . . . . . . 60<br />
4.9 Cálculo do valor da diagonal. . . . . . . . . . . . . . . . . . . . . . . . . . 61<br />
4.10 Cálculo do valor relativo à inserção do espaço. . . . . . . . . . . . . . . . . 61<br />
4.11 Codificação dos vetores da matriz de similaridade. . . . . . . . . . . . . . . 63<br />
4.12 Tipos de zeros existentes na matriz de similaridade. . . . . . . . . . . . . . 67<br />
4.13 Verificação antecipada para saber se o zero fará parte de uma seqüência. . 68<br />
4.14 Posição das bases para a verificação antecipada. . . . . . . . . . . . . . . . 69<br />
4.15 Novo formato do dado fornecido à memória externa. . . . . . . . . . . . . . 70<br />
5.1 Matrizes de similaridade para as seqüências CATAG e ATAGC e para CA-<br />
TAG e CATGA. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73<br />
5.2 Comparação entre as seqüências CATAG e ATAGC. . . . . . . . . . . . . . 73<br />
5.3 Comparação entre as seqüências CATAG e CATGA. . . . . . . . . . . . . . 75<br />
5.4 Comparação entre as seqüências ACATAGGCAT e CATAAGGCT. . . . . 76<br />
5.5 Freqüência máxima de operação x Quantidade de células do vetor. . . . . . 78<br />
xiii
5.6 Quantidade de elementos lógicos utilizados no FPGA x Quantidade de<br />
células do vetor. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79<br />
xiv
Capítulo 1<br />
INTRODUÇÃO<br />
1.1 Escopo do Trabalho<br />
Há 50 anos, no dia 7 de março de 1953, no laboratório Cavendish, na Inglaterra, Francis<br />
Crick e James Watson concluíram que a molécula do DNA tem a estrutura de uma dupla<br />
hélice, uma descoberta que daria novos rumos à ciência. No dia 25 de abril daquele<br />
ano, a revista Nature publicou o artigo Molecular Structure of Nucleic Acids (Estrutura<br />
Molecular dos Ácidos Nucleicos) [72], primeiro de uma série sobre o tema. Com menos de<br />
mil palavras e um gráfico simplificado, o trabalho descrevia a estrutura da molécula.<br />
A partir de então, a Biologia Molecular tornou-se, de fato, uma ciência. Incontáveis<br />
pesquisas começaram a serem feitas para melhor compreender a estrutura e o funcionamento<br />
da genética dos seres vivos. Essas pesquisas proporcionaram inúmeros avanços nas<br />
técnicas da Biologia Molecular que aceleraram o processo de descoberta e descrição da<br />
estrutura e funcionalidade dos genes. Entre os avanços, o aparecimento de seqüenciadores<br />
automáticos capazes de gerar dados genômicos em grande escala e de ferramentas<br />
de análise computacional comparativa entre seqüências trouxeram um grande progresso<br />
nessa nova área do conhecimento biológico.<br />
1.1.1 Projeto Genoma Humano<br />
Um importante marco para o atual desenvolvimento da Biologia Molecular foi o Projeto<br />
Genoma Humano, um empreendimento internacional iniciado formalmente em 1990 e<br />
projetado para durar 15 anos, com os seguintes objetivos:<br />
• Identificar e fazer o mapeamento dos 80 mil genes que se calculava existirem no<br />
DNA das células do corpo humano;<br />
• Determinar as seqüências dos 3 bilhões de bases químicas que compõem o DNA<br />
humano;<br />
• Armazenar essas informações em bancos de dados, desenvolver ferramentas eficientes<br />
para analisar esses dados e torná-los acessíveis para novas pesquisas biológicas.<br />
1
Como parte deste empreendimento, paralelamente foram desenvolvidos estudos com<br />
outros organismos selecionados, principalmente microorganismos considerados modelos<br />
biológicos, tais como Saccharomyces cerevisiae e Drosophila melanogaster, entre outros.<br />
O objetivo era desenvolver e aperfeiçoar novas técnicas de análise e também auxiliar o<br />
trabalho de interpretar a complexa função genética humana. Como existe uma ordem<br />
subjacente a toda a diversidade da vida e como todos os organismos se relacionam através<br />
de semelhanças em suas seqüências de DNA, o conhecimento adquirido a partir de genomas<br />
não-humanos levaria a novas descobertas na biologia humana.<br />
Em 1990, ao iniciar-se o PGH, apenas 4550 genes humanos haviam sido identificados;<br />
cerca de 1500 genes haviam sido associados a localizações específicas nos 46 cromossomos, e<br />
apenas algumas, dentre cerca de 4000 doenças genéticas existentes, haviam sido entendidas<br />
em um nível molecular.<br />
Em 12 de fevereiro de 2001, simultaneamente ao anúncio da empresa norte-americana<br />
Celera, o PGH anunciou as primeiras transcrições quase completas do código genético<br />
humano. O número de genes existentes, segundo os cálculos de ambas as equipes de<br />
pesquisadores, não chega a 40 mil. Os resultados foram publicados em duas revistas<br />
diferentes. A revista inglesa Nature [3] publicou o trabalho dos pesquisadores do PGH,<br />
liderados por Francis Collins, e a norte-americana Science, o dos pesquisadores da Celera,<br />
liderados pelo empresário-cientista Craig Venter.<br />
Em 14 de abril de 2003, o consórcio internacional que constituiu o Projeto Genoma<br />
Humano anunciou oficialmente a conclusão do seqüenciamento dos 3 bilhões de bases<br />
do DNA da espécie humana. Liderados pelo Instituto Nacional de Pesquisa do Genoma<br />
Humano (NHGRI), nos EUA e pelo Instituto Sanger, no Reino Unido, o projeto durou<br />
13 anos e, segundo se afirmou, consumiu 2,7 bilhões de dólares para se chegar à meta<br />
proposta em 1990, de decifrar a estrutura do DNA humano com 99,9% de precisão.<br />
Embora o resultado desse grandioso empreendimento mundial deva ser comemorado,<br />
ele é apenas a conclusão da etapa inicial das pesquisas sobre o assunto. A analogia que<br />
se faz é a seguinte: os bilhões de elementos que estão sendo decifrados nada mais são do<br />
que as “letras”. Depois será preciso entender as “palavras” (mapeamento dos genes) e a<br />
“linguagem”, que correspondem às funções que esses genes desempenham.<br />
Essa linguagem contida na molécula de DNA serve para ordenar a fabricação das<br />
proteínas, que são usadas pelos seres vivos - das bactérias aos humanos - para executar<br />
tarefas vitais como movimentar-se, respirar, pensar e gastar energia.<br />
O objetivo agora, depois de se conhecer o genoma humano completo, assim como o de<br />
outros organismos, é determinar a composição, estrutura, e funções de todas as proteínas<br />
do corpo para saber como elas interagem entre si. Ao conjunto de proteínas que intervêm<br />
nos processos biológicos de uma espécie é dado o nome de proteoma.<br />
Empresas e laboratórios públicos e privados já estão na corrida para entender o proteoma,<br />
embora este seja sem dúvida muito mais extenso e complicado que o genoma.<br />
2
Enquanto o DNA possui somente quatro bases nitrogenadas, as proteínas são compostas<br />
de aminoácidos, dos quais existem 20 tipos diferentes. Além disso, o DNA está localizado<br />
no núcleo de qualquer célula, o que facilita a sua obtenção e purificação, já muitas<br />
proteínas só estão presentes em alguns tipos de células, e somente em certas fases de seu<br />
desenvolvimento.<br />
Por último, não basta enumerar a seqüência de aminoácidos que forma a proteína,<br />
porque tão importante quanto a seqüência é a estrutura tridimensional que ela possui,<br />
interferindo decisivamente no papel que ela realiza.<br />
Conhecer como funciona o proteoma é um processo complexo, porque na maioria das<br />
vezes a proteína não age sozinha realizando determinada tarefa, mas sim é uma interação<br />
entre elas que vai condicionar o processo. Uma forma de conhecer as funções das proteínas,<br />
é compará-la a funções conhecidas, tanto na própria espécie, quanto em outras, já que a<br />
maior parte das proteínas se conservam em muitos organismos, mesmo que alguns se<br />
encontrem filogeneticamente distantes entre si.<br />
A corrida ao grande mapa das proteínas, ou proteoma, será um dos maiores desafios<br />
científicos da próxima década.<br />
1.1.2 Pesquisas no Brasil<br />
A participação do Brasil na área de pesquisas genômicas teve início em 1998 a partir<br />
do financiamento, pela FAPESP (Fundação de Amparo à Pesquisa do Estado de São<br />
Paulo), de um instituto virtual formado por um consórcio de laboratórios, responsável<br />
pelo seqüenciamento e análise de nucleotídeos, denominado ONSA (Organization for Nucleotide<br />
Sequencing and Analysis) [53]. O primeiro resultado importante desse instituto<br />
com reconhecimento internacional ocorreu em 2000 com a publicação do genoma do fitopatógeno<br />
Xylella fastidiosa [65], agente etiológico da Citrus Variegated Chlorosis (CVC),<br />
mais conhecida como praga do amarelinho. Essa doença destrói lavouras de laranja,<br />
principalmente no Estado de São Paulo, ocasionando prejuízos econômicos de grandes<br />
proporções.<br />
Motivada pelo sucesso alcançado, a FAPESP resolveu investir em projetos mais ambiciosos,<br />
como o do mapeamento do genoma da cana-de-açúcar, do câncer humano (em<br />
colaboração com o Instituto Ludwig para Pesquisa do Câncer), do café e também de vários<br />
organismos e pragas como o Xylella fastidiosa de videira, o Xanthomonas campestris, o<br />
Xanthomonas axonopodis e o Leifsonia xyli, além de subsidiar outros projetos como o<br />
do mapeamento do genoma funcional do Schistosoma mansoni. Outro ponto que merece<br />
destaque é a criação das redes de seqüenciamento, que ocorreu tanto no âmbito nacional<br />
como no regional. No âmbito nacional há dois projetos: o Projeto Genoma Brasileiro,<br />
que seqüenciou a bactéria Chromobacterium violaceum, cujos resultados podem ser potencialmente<br />
aplicados no controle da doença de chagas e da leishmaniose, e o Projeto<br />
Genolyptus, responsável pelo seqüenciamento do eucalipto (Fundo Verde-Amarelo/MCT).<br />
3
No âmbito regional surgiram várias redes com projetos de seqüenciamento de organismos<br />
importantes, especialmente para o controle de pragas e doenças, conforme indicado na<br />
tabela 1.1.<br />
Tabela 1.1: Projetos Regionais de Seqüenciamento no Brasil.<br />
Rede Regional<br />
Organismo Alvo<br />
Rede Genoma do Estado de Minas Gerais<br />
Schistosoma mansoni<br />
Rede Genoma Nordeste<br />
Leishmania chagasi<br />
Rede Genômica do Estado da Bahia e São Paulo Crinipellis perniciosa<br />
Rede Genoma do Consórcio<br />
do Instituto de Biologia Molecular do Paraná, Trypanossoma cruzi<br />
FIO-CRUZ e Universidade de Mogi das Cruzes<br />
Programa Genoma do Estado do Paraná<br />
Herbaspirillum seropedicae<br />
Rede Genoma do Rio de Janeiro<br />
Gluconacetobacter diazotrophicus<br />
Rede Sul de Análise de Genomas e Biologia Estrutural Mycoplasma hyopneumoniae<br />
Rede Genoma Centro-Oeste<br />
Paracoccidioides brasiliensis<br />
Esses projetos colocam o Brasil no grupo dos países com tecnologia e infra-estrutura<br />
suficientes para conduzirem pesquisas na área genômica. Isso é de importância estratégica<br />
vital, pois permite que problemas específicos do nosso país, que afetam nossa população<br />
e/ou produção agropecuária, sejam resolvidos sem depender dos laboratórios estrangeiros.<br />
Além disso, esses projetos estimulam o desenvolvimento de novas tecnologias e a capacitação<br />
e de profissionais especializados, o que contribui para colocar o Brasil em posição<br />
de igualdade perante a comunidade científica internacional nessa área.<br />
1.1.3 Bioinformática e Biologia Computacional<br />
O Projeto Genoma Humano e os crescentes avanços da tecnologia tem permitido aos<br />
laboratórios de Biologia Molecular fornecerem detalhes cada vez mais precisos sobre as<br />
estruturas estudadas. O enorme volume de informações acumulado desde então e a necessidade<br />
de trabalhar esses dados eficientemente criou uma série de problemas que são, por<br />
natureza, interdisciplinares. Em particular, as teorias da matemática e da computação<br />
tornaram-se fundamentais no processo de manipulação de dados científicos dentro da Biologia<br />
Molecular [64].<br />
Isso levou ao surgimento de duas áreas de pesquisa intimamente ligadas:<br />
• A Bioinformática, que tem como finalidade principal gerar novos conhecimentos a<br />
partir da grande quantidade de dados que vêm sendo obtidos sobre seqüências de<br />
DNA e proteínas e pode ser descrita como a aquisição, organização, armazenamento<br />
e análise dessas informações biológicas;<br />
• e a Biologia Computacional, que estuda o desenvolvimento de algoritmos e programas<br />
computacionais para auxiliar a Bioinformática.<br />
4
A Bioinformática, apesar de ser um campo relativamente novo, tem evoluído dramaticamente<br />
nos últimos anos e, hoje, é fundamental para as pesquisas realizadas em Biologia<br />
Molecular [21].<br />
Há três objetivos principais dentro da Bioinformática. O primeiro é prover um meio de<br />
organizar os dados biológicos de forma a tornar fácil o acesso às informações e a submissão<br />
de novos dados à medida que estes são gerados. Diversos bancos de dados biológicos foram<br />
e continuam sendo criados com esse objetivo. O segundo objetivo é o desenvolvimento<br />
de ferramentas para processar os dados armazenados e extrair diversas informações ali<br />
contidas. O terceiro objetivo é a análise dos resultados gerados por essas ferramentas<br />
para interpretar as informações de uma maneira que seja biologicamente consistente e<br />
relevante [44].<br />
1.1.4 Pesquisas em Bancos de Dados Biológicos<br />
Tradicionalmente, pesquisas em Biologia investigavam um sistema isoladamente e o<br />
comparavam com outros poucos sistemas relacionados. A Bioinformática permitiu conduzir<br />
análises globais envolvendo um volume muito maior de dados, de forma a descobrir<br />
princípios comuns e características importantes mais facilmente.<br />
Um dos problemas fundamentais nessa área é a comparação entre duas ou mais seqüências<br />
de DNA ou proteínas, servindo como base para a solução de uma grande variedade de<br />
problemas. A comparação entre seqüências é uma tarefa computacionalmente intensa e<br />
lenta. Primeiro, porque os algoritmos utilizados possuem uma complexidade de tempo significativa<br />
pois devem permitir mutações genéticas, ou seja, inserções, remoções ou substituições<br />
nas seqüências comparadas. Segundo, porque o tamanho dessas seqüências podem<br />
ser muito grande, da ordem de milhões de caracteres.<br />
Como os repositórios dessas informações vêm aumentando de tamanho a taxas elevadas,<br />
métodos cada vez mais rápidos e eficientes para a comparação de seqüências se<br />
tornam necessários para se manterem eficientes em relação ao crescente tamanho dos bancos<br />
de dados. Por exemplo, o GenBank, um dos principais bancos de dados públicos<br />
sobre informações genéticas, tem sido alimentado a uma taxa quase exponencial com o<br />
tempo (figura 1.1).<br />
A análise de uma seqüência obtida dentro de um projeto de seqüenciamento é iniciada<br />
comparando-a com as seqüências já descobertas e analisadas, armazenadas nesses bancos<br />
de dados, para que o relacionamento existente entre elas possa permitir estabelecer<br />
a determinação de sua função, estrutura, características evolucionárias e influência em<br />
doenças, entre outras.<br />
5
Figura 1.1: Crescimento do GenBank.<br />
1.1.5 Algoritmos para Comparação de Seqüências<br />
O algoritmo com melhores resultados teóricos foi proposto por Smith e Waterman [66],<br />
baseado em técnicas de programação dinâmica, com o intuito de mostrar as posições<br />
“similares” entre duas seqüências. No entanto, conforme já citado, devido ao considerável<br />
tamanho de algumas seqüências biológicas, a computação por programação dinâmica,<br />
que tem complexidade quadrática de tempo e espaço, torna-se inviável com os recursos<br />
computacionais existentes atualmente.<br />
Assim surgiram os métodos heurísticos de comparação de seqüências, baseados em probabilidades<br />
estatísticas acerca destas seqüências. Estes métodos possuem complexidade<br />
linear de tempo, o que torna as pesquisas mais rápidas, embora não garantam a produção<br />
de resultados ótimos. Apesar desta desvantagem, as ferramentas baseadas nestes métodos<br />
têm sido bem aceitas e amplamente utilizadas pelos laboratórios de seqüenciamento.<br />
Uma das ferramentas mais utilizadas para a comparação de seqüências de DNA com<br />
os bancos de dados genômicos é o BLAST (Basic Local Alignment Search Tool) [6]. O<br />
BLAST é na verdade uma família de ferramentas para análises de DNA e proteínas e não<br />
um único programa.<br />
Uma outra família de ferramentas bastante utilizada, que também utiliza heurísticas,<br />
é o FAST [59], para comparações globais.<br />
Se os algoritmos de comparação baseados em programação puderem ser acelerados de<br />
6
modo a se tornar viável sua utilização, respostas ótimas poderão ser obtidas, uma vez que<br />
as soluções baseadas em heurísticas podem ocultar importantes relacionamentos entre as<br />
seqüências comparadas.<br />
Dentre as alternativas que vêm sendo pesquisadas estão a utilização de técnicas de<br />
computação paralela, que se baseia na cooperação de um conjunto de processadores que<br />
dividem a carga computacional e a construção de hardware específico e dedicado, dessa<br />
forma, mais otimizado e veloz, para a solução desse problema.<br />
Muitos esforços nas áreas comercial e acadêmica já foram feitos para utilizarem hardware<br />
específico com o objetivo de acelerar as pesquisas nos bancos de dados.<br />
Nesta dissertação é proposto um sistema baseado em hardware, chamado de ASIC-<br />
GENE (Acelerador Sistólico para Comparações Genéticas), e que utiliza um dispositivo<br />
reconfigurável conhecido como FPGA. Uma estrutura sistólica linear unidirecional é apresentada<br />
para acelerar o processo da comparação entre seqüências. Essa estrutura possui<br />
inúmeros pequenos processadores dedicados (chamados de elementos de processamento)<br />
que efetuam operações em paralelo, obtendo um significativo ganho de performance em<br />
relação à computação seqüencial.<br />
1.2 Revisão Bibliográfica<br />
Em 1985, Lipton e Lopresti [43] mostraram que o paralelismo existente no algoritmo de<br />
Smith-Waterman poderia ser mapeado em uma estrutura linear sistólica bidirecional. Na<br />
estrutura obtida, cada elemento de processamento (PE) do vetor sistólico era responsável<br />
pelo cálculo de uma das diagonais da matriz de similaridade, com a diagonal principal<br />
sendo processada no centro desse vetor (figura 1.2).<br />
Figura 1.2: Mapeamento do cálculo da matriz de similaridade em uma estrutura sistólica<br />
bidirecional.<br />
As seqüências a serem comparadas entravam em lados opostos do vetor e eram deslocadas<br />
a cada ciclo de relógio de modo a atravessar a estrutura linear. Dessa forma, o<br />
primeiro elemento das duas seqüências se encontravam no centro do vetor, quando era calculado<br />
o primeiro valor da matriz de similaridade. A cada ciclo de relógio, as seqüências<br />
se deslocavam em sentidos opostos e mais valores iam sendo calculados.<br />
7
Se as duas seqüências a serem comparadas possuíssem comprimentos iguais a n e<br />
m, a estrutura linear proposta deveria ter um comprimento de n + m − 1 elementos de<br />
processamento. Entretanto, a complexidade de tempo do algoritmo caiu de O(n × m)<br />
para O(n + m), ou seja, uma complexidade linear.<br />
Para o cálculo de cada elemento da matriz de similaridade, foi sugerido um esquema<br />
de pontuação sem valores negativos e que penalizava mais o alinhamento de caracteres<br />
diferentes das duas seqüências do que o alinhamento de um caracter de uma das duas<br />
seqüências com um espaço (gap). A pontuação proposta seguia a seguinte regra:<br />
t j<br />
. . .<br />
a b<br />
s i . . . c d<br />
⎧<br />
⎪⎨<br />
d = min<br />
⎪⎩<br />
b + 1<br />
c + 1<br />
a se s i = t j<br />
a + 2 se s i ≠ t j<br />
Com esse esquema de pontuação, foi demonstrado que o valor calculado para d seria<br />
igual ao de a ou então igual a a + 2. Com isso, apenas um bit indicaria essa diferença.<br />
Por esse motivo, essa implementação não armazenava os valores calculados da matriz de<br />
similaridade e conforme os dados iam saindo em uma das pontas do vetor, um contador<br />
previamente carregado ia sendo incrementado ou decrementado de acordo com os bits<br />
gerados. No final do processo, o último valor do contador indicava quão próximas eram<br />
as seqüências comparadas. Se o valor fosse baixo, indicava que as seqüências eram bem<br />
parecidas, com um valor igual a zero no caso das seqüências serem idênticas. Valores altos<br />
no contador indicavam que as seqüências eram bem diferentes.<br />
Com essa implementação não era possível obter nenhum alinhamento entre as duas<br />
seqüências e o resultado obtido era meramente um indicador de proximidade entre elas.<br />
Foi observado que os diversos artigos definem dois conceitos: comparação de seqüências<br />
e alinhamento de seqüências. Na comparação, o resultado obtido é simplesmente um<br />
escore que indica se as seqüências comparadas são próximas ou não. No alinhamento é<br />
que se consegue obter quais trechos de uma seqüência são similares ao da outra seqüência<br />
comparada.<br />
Baseadas nessa abordagem, foram propostas várias implementações. Em 1992, Hoang<br />
[31] descreve uma solução bastante similar, utilizando a arquitetura SPLASH [22],<br />
uma matriz lógica linear programável desenvolvida pelo Supercomputer Researh Center<br />
(SRC), que utilizava 32 FPGAs XC3090 da Xilinx [75]. Nessa solução era possível recuperar<br />
pelo menos um alinhamento, embora o esquema de pontuação utilizado foi o proposto<br />
por Lipton e Lopresti.<br />
Em 1993, Hoang [52] sugere uma nova solução utilizando uma arquitetura sistólica<br />
unidirecional, agora baseada no SPLASH 2 [9], uma evolução do sistema anterior. As<br />
duas seqüências eram colocadas em um único vetor e deslocadas para dentro da estrutura<br />
sistólica. Uma marca em cada posição desse vetor indicava quais bases faziam parte da<br />
seqüência de consulta e quais bases eram do banco de dados. Nessa solução, não foram<br />
8
dados detalhes sobre a recuperação de alinhamentos e pela estrutura da célula, apenas o<br />
cálculo de um escore de similaridade (comparação de seqüências) era feito.<br />
Utilizando o acelerador SAMBA [38] (Systolic Accelerator for Molecular Biological<br />
Applications), Lavenier propõe, em 1998, uma nova abordagem para o problema, mas<br />
ainda utilizando uma arquitetura sistólica, pela própria estrutura do SAMBA.<br />
Uma nova implementação da solução de Hoang ocorreu em 2002, utilizando tecnologia<br />
mais moderna, como a família Virtex de FPGAs da Xilinx [25]. A solução de Hoang<br />
também deu origem ao HokieGene [60], um sistema reconfigurável em tempo de execução<br />
baseado na placa Osiris [36] desenvolvida pelo Information Sciences Institute.<br />
Uma solução bastante similar à proposta nessa dissertação foi apresentada por Yamaguchi,<br />
Maruyama e Konagaya [76] em 2002. Nela uma placa PCI contendo uma FPGA<br />
XCV2000E da Xilinx, que contém 43200 células lógicas, foi utilizada, sendo possível a<br />
implementação de 144 elementos de processamento. Cada elemento de processamento<br />
leva quatro ciclos de relógio para gerar seu resultado. Nessa solução não é dito nada sobre<br />
a utilização de uma arquitetura sistólica. A comparação é dividida em vários pedaços<br />
devido às limitações da memória interna da FPGA.<br />
Com algumas modificações, mas ainda baseada na solução de Hoang de 1993, uma nova<br />
proposta é feita por Yu, Kwong, Lee e Leong [78] em 2003. Essa implementação também<br />
utiliza FPGAs da família Virtex da Xilinx, mais especificamente XCV1000E, com 27648<br />
células lógicas.<br />
Algumas soluções utilizando VLSI também foram propostas, como BioScan [73] em<br />
1991, KESTREL [30] em 1996 e as Proclets de Yang [77] em 2002. Essa última utiliza uma<br />
unidade de processamento (chamada de Proclet) para cada célula da matriz de similaridade<br />
e, dessa forma, torna-se muito onerosa, dada as dimensões que a matriz pode atingir.<br />
Dentre as arquiteturas dedicadas, além das já citadas SPLASH, Osiris e SAMBA,<br />
destacam-se o GeneMatcher2 [57] da Paracel [56] que usa um processador ASIC otimizado<br />
para essa tarefa, e o DeCypher [68] da TimeLogic [67] que utiliza FPGAs.<br />
1.3 Objetivos<br />
As soluções analisadas com maior interesse foram as que utilizaram FPGAs. A grande<br />
maioria delas foi baseada nas propostas de Lipton e Lopresti e de Hoang. Nessas abordagens<br />
foi utilizado um esquema de pontuação que, embora simplifique o hardware, penaliza<br />
mais a substituição do que a inserção ou remoção de uma base em uma das seqüências<br />
(ocorrência de espaços). Outro fato observado é que o resultado é simplesmente um escore<br />
que indica a proximidade entre as seqüências comparadas. Quanto menor o escore, maior<br />
a similaridade entre elas.<br />
Nas soluções não baseadas nessas propostas, um hardware dedicado de maior envergadura<br />
foi utilizado como suporte. A exceção é a solução apresentada por Yamaguchi,<br />
9
Maruyama e Konagaya que utilizada placas PCIs de “prateleira”. Entretanto, não são<br />
fornecidos maiores detalhes sobre a implementação feita, de forma que ela pudesse ser<br />
reproduzida.<br />
Dessa forma, até onde se pôde perceber, o trabalho proposto nesta dissertação é inédito,<br />
pois detalha todo o fluxo dos dados dentro da arquitetura sistólica e utiliza um esquema de<br />
pontuação mais voltado para os aspectos biológicos do problema e não com simplificações<br />
do circuito. Além disso, a matriz de similaridade é armazenada e permite a recuperação<br />
de todos os alinhamentos entre as duas seqüências comparadas.<br />
Assim, os objetivos desta dissertação são:<br />
• Propor, implementar e validar uma solução paralela baseada em hardware para o<br />
problema de comparar seqüências utilizando o algoritmo de Smith-Waterman [66];<br />
• Realizar comparações de desempenho com outras implementações do algoritmo,<br />
seqüenciais e paralelas.<br />
1.4 Organização da Dissertação<br />
No capítulo 2 são apresentados os conceitos básicos em Biologia Molecular, sendo<br />
descritos os algoritmos de comparação de seqüências baseados em programação dinâmica.<br />
No capítulo 3, são revistas as arquiteturas sistólicas e as arquiteturas reconfiguráveis, além<br />
de outros conceitos a serem utilizados. A descrição da solução proposta é apresentada no<br />
capítulo 4. Os resultados dos experimentos realizados e análises desses resultados são<br />
apresentados no capítulo 5. Finalmente, no capítulo 6 são apresentadas as conclusões<br />
deste trabalho e propostas novas direções de pesquisa a partir dele.<br />
10
Capítulo 2<br />
FUNDAMENTAÇÃO TEÓRICA<br />
2.1 Biologia Molecular<br />
Um dos pontos fundamentais da Teoria Atômica proposta por John Dalton [15] era que<br />
a matéria é constituída por unidades indivisíveis, os átomos. Estes, unidos uns aos outros,<br />
compõem as moléculas, que juntas formam uma célula. Segundo a teoria celular [7][8],<br />
formulada em 1839, por Schleiden e Schwann, todo ser vivo é formado por células. De<br />
forma simplista, a vida resulta de um complexo conjunto de reações bioquímicas que ocorrem<br />
nas células. Duas estruturas se destacam nesta química da vida: os ácidos nucléicos<br />
e as proteínas.<br />
A Biologia Molecular é a ciência onde se visa compreender a estrutura e função<br />
dos ácidos nucléicos e proteínas, e como estes participam nos intrincados processos responsáveis<br />
pela origem e conservação da vida citeSetubal.<br />
2.1.1 Ácidos Nucléicos<br />
A história da descoberta dos ácidos nucléicos remonta aos fins do século XIX, quando F.<br />
Miescher (1868), em um importante trabalho de citoquímica, isolou e analisou o núcleo das<br />
células. No entanto, foi Richard Altmann que, em 1889, atribuiu a designação de ácidos<br />
nucléicos, uma vez que foram primeiramente identificados no núcleo e porque manifestam<br />
propriedades ácidas.<br />
Os ácidos nucléicos estão presentes em todos os seres vivos, sejam eles simples ou<br />
complexos, e contêm as informações necessárias para a síntese de todas as proteínas que<br />
cada organismo é capaz de produzir [59]. São moléculas orgânicas gigantes formadas por<br />
uma cadeia de unidades menores chamadas nucleotídeos. Existem dois tipos principais: o<br />
ácido ribonucléico (RNA) e o ácido desoxirribonucléico (DNA).<br />
Cada nucleotídeo do ácido nucléico consiste de três partes básicas: um grupo fosfato,<br />
um açúcar e uma base nitrogenada (anel heterocíclico de átomos de carbono e nitrogênio).<br />
A base nitrogenada, de acordo com sua estrutura química, pode ser púrica ou pirimídica.<br />
Adenina (A) e guanina (G) são bases púricas enquanto citosina (C), timina (T)<br />
e uracila (U) são bases pirimídicas.<br />
11
As purinas são constituídas de dois anéis fundidos de 5 e 6 átomos e as pirimidinas<br />
de um único anel de 6 átomos. Uracil e Timina são moléculas bastante relacionadas,<br />
diferindo apenas pelo grupo metila encontrado no átomo C5 do anel pirimídico da Timina<br />
(figura 2.1). É a presença do nitrogênio que dá a essas moléculas o seu caráter básico.<br />
Apenas quatro tipos diferentes de bases são encontrados em um dado polímero de<br />
ácido nucléico, sendo duas purinas e duas pirimidinas. No DNA as bases constituintes são<br />
A, G, C, e T, enquanto que no RNA as bases são A, G, C e U.<br />
Figura 2.1: Bases Nitrogenadas.<br />
A molécula de açúcar, também chamada de pentose por ser composta de 5 átomos<br />
de carbono, pode ser de dois tipos, desoxirribose e ribose. Diferem uma da outra pela<br />
presença ou ausência do grupo hidroxila no C2’ (figura 2.2). É baseado nessa característica<br />
que os ácidos nucléicos recebem o nome RNA (ribose) ou DNA (desoxirribose).<br />
Figura 2.2: Tipos de Açúcares.<br />
A pentose é o elo de ligação entre a base e o grupo fosfato. De um lado, o Nitrogênio<br />
9 das purinas ou o Nitrogênio 1 das pirimidinas liga-se ao C1’ da pentose e, de outro lado,<br />
o grupo carboxila do átomo de C5’ da pentose participa da ligação éster com o grupo<br />
fosfato.<br />
12
2.1.1.1 DNA<br />
Segundo o modelo descoberto por Watson-Crick [72], o DNA é uma longa molécula,<br />
constituída por duas cadeias de nucleotídeos (um grupo fosfato, um açúcar e uma base<br />
nitrogenada), chamadas fitas, enroladas em torno de seu próprio eixo, como se fosse uma<br />
escada do tipo caracol (figura 2.3). A ligação entre as fitas é feita por pontes de hidrogênio,<br />
que são ligações fracas, isto é, que se rompem com facilidade. As pontes de hidrogênio<br />
unem duas bases nitrogenadas e são decorrentes de propriedades químicas entre uma base<br />
púrica e uma pirimídica, formando os chamados pares de bases (bp).<br />
Figura 2.3: A estrutura de uma molécula de DNA, formada por uma dupla fita. (a) Forma<br />
helicoidal da dupla cadeia. (b) Forma esquemática da dupla cadeia, onde podemos visualizar a<br />
ligação entre as moléculas de açúcar (S) e de fosfato (P), em cada uma das fitas, e o emparelhamento<br />
das bases Adenina/Timina e Citosina/Guanina, entre as duas fitas.<br />
O pareamento das bases de cada fita se dá de maneira padronizada, sempre uma<br />
purina com uma pirimidina, especificamente: adenina (A) com timina (T) e citosina (C)<br />
com guanina (G).<br />
Como cada ligação ocorre entre o carbono 3’ de um composto, o fosfato e o carbono<br />
5’ do próximo composto, diz-se que o DNA possui uma orientação que, por convenção,<br />
inicia-se na extremidade 5’ e termina na 3’, denominada direção canônica [64]. Assim,<br />
uma seqüência de nucleotídeos em uma fita corresponde à seqüência dos nucleotídeos<br />
complementares da outra fita, por causa do emparelhamento das bases. Dizemos que as<br />
duas fitas são complementares.<br />
Além disso, deve-se notar que as duas fitas possuem sentidos opostos. Uma fita começa<br />
em 5’ e termina em 3’, que é emparelhada com a outra, que começa em 3’ e termina em 5’.<br />
13
Por convenção, a fita de sentido 5’ → 3’ é colocada acima, como mostrado na figura 2.4.<br />
Figura 2.4: Dupla fita de DNA, observando-se o pareamento das bases A-T e C-G.<br />
A seqüência do DNA é determinada pela ordem das bases nitrogenadas ao longo de<br />
cada uma das fitas, já que o fosfato (P) e o açúcar (S) são idênticos em todos os nucleotídeos.<br />
Daí os pares de bases (bp) serem usados como unidades de comprimento para<br />
uma molécula de DNA. O tamanho do DNA varia para cada organismo, podendo ser de<br />
alguns milhões de bases, como no caso de uma bactéria, até de alguns bilhões de bases,<br />
no caso dos mamíferos.<br />
O DNA codifica todas as proteínas que as células devem sintetizar, o que garante<br />
a sobrevivência da espécie. Portanto, a principal função do DNA é armazenar toda a<br />
informação genética de um organismo. A conservação e transmissão dessas informações<br />
são realizadas pelos processos de duplicação e transcrição, respectivamente.<br />
2.1.1.2 RNA<br />
As moléculas de RNA possuem composição química e estrutural bastante similares às<br />
de DNA. As diferenças químicas estão no fato de o nucleotídeo ser formado pelo açúcar<br />
ribose e pela substituição da timina (T) pela uracila (U). As outras bases nitrogenadas<br />
são todas as mesmas que compõem o DNA: citosina (C), guanina (G) e adenina (A).<br />
Estruturalmente, enquanto o DNA apresenta-se como uma longa hélice dupla com uma<br />
estrutura secundária regular e simples, os RNAs são, geralmente, moléculas de fita única<br />
bem menores que o DNA, apresentando uma enorme diversidade de estruturas secundárias,<br />
com certas regiões podendo formar até mesmo uma dupla hélice.<br />
A estabilidade e regularidade estrutural da molécula de DNA, deve-se principalmente<br />
ao fato dos anéis de desoxirribose não possuírem grupos hidroxila no C2’. Os grupos<br />
hidroxila tanto do C2’ como C3’ são muito reativos e podem participar de uma série de<br />
ligações pouco usuais, permitindo uma variedade enorme de conformações para a molécula<br />
de ácido nucléico. Tal variedade, não seria uma característica desejável para uma molécula<br />
que tem armazenado e transmitido a informação genética durante estes milhões de anos<br />
de evolução. O exercício de tal função exige estabilidade e regularidade.<br />
Já o RNA, constituído de riboses é, por isso mesmo, muito mais reativo e flexível.<br />
Além disto, o fato de ser fita simples permite um emparelhamento intramolecular de<br />
bases, gerando estruturas bastante complexas. Ao adquirir diferentes conformações numa<br />
estrutura tridimensional, as moléculas de RNA podem, inclusive, apresentar sítios ativos<br />
14
que catalisem reações químicas da mesma forma que as enzimas protéicas.<br />
É a grande flexibilidade dos RNAs que lhes permite executar uma atividade fundamental<br />
na célula, qual seja, a de interpretar o código contido na linguagem de nucleotídios<br />
e decodificá-lo para a linguagem de aminoácidos. A molécula de RNA é o intermediário<br />
no fluxo de informações dentro da célula, do DNA às proteínas. Assim, existem diferentes<br />
tipos de RNA, tais como o RNA mensageiro (RNAm), o RNA ribossômico (RNAr) e<br />
o RNA transportador (RNAt), responsáveis por diversas funções vitais na realização da<br />
síntese de proteínas.<br />
A tabela 2.1 apresenta as diferenças fundamentais entre o DNA e o RNA.<br />
2.1.2 Aminoácidos<br />
De um modo geral, cada composto orgânico pertence a um determinado grupo. Entretanto,<br />
existem compostos que pertencem simultaneamente a dois ou mais grupos, ou<br />
seja, são de função mista. A figura 2.5 mostra alguns desses grupos.<br />
Figura 2.5: Exemplo de alguns grupos orgânicos.<br />
Os aminoácidos são compostos orgânicos de função mista e que apresentam em suas<br />
moléculas um grupo ácido (-COOH) e um grupo amina (-NH2), além de um radical -R, que<br />
vai ser responsável pela diferenciação entre os diversos tipos existentes (figura 2.6). Graças<br />
à presença de grupamentos derivados de ácidos carboxílicos e de aminas, os aminoácidos<br />
são dotados de propriedades de ácidos e bases. Esse duplo caráter é de vital importância<br />
para a compreensão do comportamento e das funções das proteínas e, por conseguinte, da<br />
matéria viva.<br />
Todas as proteínas existentes nos seres vivos, desde os vírus até os seres humanos, são<br />
constituídas por combinações de apenas 20 aminoácidos. Esses blocos constituintes da<br />
Tabela 2.1: Principais diferenças entre o DNA e o RNA.<br />
DNA<br />
RNA<br />
Nucleotídeo fosfato, desoxirribose, fosfato, ribose,<br />
base nitrogenada base nitrogenada<br />
Bases Nitrogenadas A, T, C e G A, U, C e G<br />
Estrutura duas cadeias normalmente,<br />
em estrutura helicoidal cadeia simples<br />
Função única varia de acordo com o tipo<br />
15
Figura 2.6: Estrutura e exemplos de alguns aminoácidos.<br />
vida se unem entre si para formar longas cadeias e moléculas complexas que configuram a<br />
estrutura de todos os organismos vivos. A tabela 2.2 mostra os aminoácidos encontrados<br />
na natureza, bem como suas abreviações e códigos utilizados.<br />
Os aminoácidos são classificados em essenciais e não-essenciais. Os essenciais, ou<br />
indispensáveis, são aqueles que o organismo humano não consegue sintetizar. Desse modo,<br />
eles devem ser obrigatoriamente ingeridos através de alimentos. Os aminoácidos nãoessenciais,<br />
ou dispensáveis, são aqueles que o organismo humano consegue sintetizar a<br />
partir dos alimentos ingeridos.<br />
São 8 os aminoácidos essenciais, a saber: leucina, isoleucina, valina, triptofano, metionina,<br />
fenilalanina, treonina e lisina (a histidina é um aminoácido essencial na infância,<br />
mas não na idade adulta).<br />
2.1.3 Proteínas<br />
As proteínas são compostos orgânicos de estrutura complexa e massa molecular elevada<br />
(entre 15.000 e 20.000.000) e são sintetizadas pelos organismos vivos através da condensação<br />
de um número grande de moléculas de aminoácidos, por intermédio de ligações<br />
denominadas peptídicas, que derivam da reação do grupo amina de um dos aminoácidos<br />
com o grupo carboxila de outro (figura 2.7). Pelo fato de uma molécula de água ser liberada<br />
como resultado dessa reação, cada aminoácido, após a união, passa a ser um resíduo<br />
do aminoácido original.<br />
Figura 2.7: União de dois aminoácidos por uma ligação peptídica.<br />
Para que as células funcionem são necessárias a realização de uma enorme quantidade<br />
de reações químicas que se processam em seu interior. As enzimas, proteínas especiais,<br />
regulam a atividade celular controlando e catalisando essas reações químicas.<br />
Além disso, as proteínas participam nos processos de duplicação, transcrição e reparo.<br />
A vida e a reprodução dependem da manutenção desses processos e da disponibilidade de<br />
16
Tabela 2.2: Os 20 diferentes tipos de aminoácidos encontrados na natureza.<br />
Aminoácido Abreviação Código<br />
Alanina Ala A<br />
Asparagina ou Aspartato Asx B<br />
Cisteína Cis ou Cys B<br />
Aspartato (Ácido aspártico) Asp D<br />
Glutamato (Ácido glutâmico) Glu E<br />
Fenilalanina Fen ou Phe F<br />
Glicina Gli ou Gly G<br />
Histidina His H<br />
Isoleucina Ile I<br />
Lisina Lis ou Lys K<br />
Leucina Leu L<br />
Metionina Met M<br />
Asparagina Asn N<br />
Prolina Pro P<br />
Glutamina (Glutamida) Gln Q<br />
Arginina Arg R<br />
Serina Ser S<br />
Treonina Ter ou Thr T<br />
Valina Val V<br />
Triptofano (Triptofana) Trp W<br />
Tirosina Tir ou Tyr Y<br />
Glutamina ou Glutamato Glx Z<br />
17
energia e dos componentes necessários para isso. Dessa forma, a síntese das proteínas é<br />
fundamental para o crescimento, o desenvolvimento e a manutenção celular.<br />
Para a formação de uma proteína é preciso uma informação que irá ditar a seqüência<br />
em que os aminoácidos devem ser unidos. Essas informações estão inscritas nas moléculas<br />
do DNA.<br />
Embora a seqüência de aminoácidos determine a estrutura da proteína, conhecida<br />
como estrutura primária, não é possível predizer com precisão a conformação espacial<br />
adotada por uma determinada proteína, apenas por esta seqüência. As interações moleculares<br />
entre os aminoácidos fazem com que a cadeia protéica assuma uma estrutura<br />
secundária. Podemos ter ainda as estruturas terciárias, resultado da estrutura secundária<br />
empacotadas em um nível mais global, e as estruturas quaternárias, quando<br />
um grupo de proteínas diferentes são empacotadas juntas.<br />
É possível também classificar proteínas com base em sua função. Elas podem ser divididas<br />
em dois grupos: proteínas estruturais e proteínas biologicamente ativas. Algumas<br />
proteínas, entretanto, podem pertencer aos dois grupos. A maioria das proteínas estruturais<br />
é composta por cadeias alongadas e têm como função compor estruturas de órgãos,<br />
tecidos, etc. Dois bons exemplos, nos animais, são o colágeno (ossos, tendões, pele e<br />
ligamentos) e a queratina (unhas, cabelos, penas e bicos). A maioria das proteínas biologicamente<br />
ativas tem forma globular e são encarregadas de executar ou controlar a maior<br />
parte das atividades dentro do organismo. Exemplos são as enzimas que aceleram reações<br />
químicas, os hormônios protéicos (que atuam como mensageiros químicos), as proteínas de<br />
transporte (como as lipoproteínas, que podem carregar o colesterol) e as imunoglobulinas<br />
(ou anticorpos), que protegem o corpo de microorganismos invasores [64].<br />
2.1.4 Genes<br />
Nas células dos organismos, cada molécula de DNA forma um cromossomo. O<br />
número de cromossomos é característico da espécie. Por exemplo, nas células dos seres<br />
humanos existem 23 pares de cromossomos.<br />
Cada molécula de DNA contém diversos genes, que são as unidades físicas e funcionais<br />
básicas da hereditariedade [2]. Um gene é uma seqüência específica de bases de<br />
uma molécula de DNA que contém a informação necessária para sintetizar proteínas ou<br />
RNA [2].<br />
Todos os genes estão dispostos linearmente ao longo dos cromossomos na forma de trechos<br />
contíguos. Mas, entre os genes, existem trechos, chamados DNA não-codificante<br />
que não possuem função codificadora, pelo conhecimento atual da ciência. Nos procariontes,<br />
organismos que não possuem núcleo organizado, os cromossomos estão quase totalmente<br />
cobertos por genes, mas, nos eucariontes, organismos com núcleo bem definido,<br />
estima-se que cerca de 90% do cromossomo seja DNA não-codificante [64].<br />
O conjunto completo de cromossomos de um organismo compreende o seu genoma,<br />
18
que engloba todas as informações necessárias para originar e manter a vida. A figura 2.8<br />
mostra o esquema dos genes dentro dos cromossomos e destes dentro do genoma. Estimase<br />
que o genoma humano possua aproximadamente 30.000 genes [2].<br />
Figura 2.8: Visão esquemática dos genes, cromossomos e genoma.<br />
Geralmente, cada gene em uma molécula de DNA corresponde a um tipo diferente<br />
de proteína. A informação genética contida nos genes é transmitida por triplas de nucleotídeos,<br />
chamadas códons. Cada códon representa um aminoácido na proteína e essa<br />
correspondência é chamada de código genético (figura 2.9).<br />
Figura 2.9: Código genético.<br />
A combinação das quatro letras genéticas (A,T,C,G) três a três permite obter 64 trincas<br />
diferentes. Dessas 64 trincas possíveis, apenas 61 correspondem a aminoácidos; as três<br />
restantes são utilizadas para indicar onde termina um mensagem genética (STOP). Em<br />
geral, o início de um gene é indicado pelo códon AUG.<br />
Como existem apenas 20 tipos diferentes de aminoácidos nas proteínas do seres vivos,<br />
alguns aminoácidos são codificados por mais de uma trinca de nucleotídeos. Por isso,<br />
diz-se que o código genético é degenerado.<br />
2.1.5 Genética Molecular<br />
O material responsável pelo comando e coordenação de toda a atividade celular e<br />
pelas divisões celulares e transmissões das características hereditárias está representado<br />
19
Figura 2.10: Duplicação do DNA.<br />
nas células pelos cromossomos. A conservação e a transmissão da informação genética<br />
ocorrem devido ao processo de duplicação do DNA, que acontece durante a divisão de<br />
uma célula, produzindo duas células filhas exatamente iguais.<br />
Na duplicação, as fitas do DNA se separam e cada uma serve de molde para a formação<br />
de uma fita complementar através do pareamento de bases. No final do processo haverá<br />
duas moléculas de DNA, cada uma constituída por uma fita original e outra complementar<br />
recém-fabricada (figura 2.10). É geralmente durante este processo que ocorrem as variações<br />
genéticas decorrentes de mutações, por exemplo, substituições, remoções ou inserções de<br />
bases.<br />
2.1.6 Síntese Protéica<br />
A expressão da informação genética ocorre na forma de proteínas, segundo o Dogma<br />
Central da Biologia Molecular, que preconiza que os genes são perpetuados como<br />
seqüências de ácidos nucléicos e, a partir destes, expressos na forma de proteínas. Duas<br />
fases compõem o processo de síntese de proteínas: transcrição e tradução.<br />
Na primeira etapa da síntese, ocorre a transcrição da informação depositada no<br />
DNA para uma cópia feita a partir de ribonucleotídeo. Assim, obtém-se uma molécula<br />
alongada de RNA com a mesma seqüência de nucleotídeo observada no DNA, com exceção<br />
da base timina substituída pela uracila. Esta cópia de DNA recebe o nome de RNA<br />
mensageiro (RNAm). O RNAm carrega a informação codificada para os ribossomos,<br />
que são estruturas celulares responsáveis por processar o código genético e sintetizar as<br />
proteínas [2].<br />
Terminada a transcrição do DNA, o RNAm sai do núcleo para o citoplasma rumo ao<br />
ribossomo, levando a seqüência de nucleotídeos que permitirá a formação das proteínas.<br />
Para que isso ocorra é necessário a tradução da seqüência de nucleotídeos do RNAm em<br />
seqüência de aminoácidos (figura 2.11).<br />
20
Figura 2.11: Representação esquemática da transcrição e tradução.<br />
Todas as células contêm um conjunto de RNA, os RNA transportadores (RNAt), que<br />
através da ligação de uma de suas extremidades a um códon, permite o alinhamento dos<br />
aminoácidos de acordo com a seqüência de nucleotídeos do RNAm.<br />
Um RNAt é responsável pelo transporte de um dos vinte aminoácidos utilizados na<br />
síntese de proteínas. Cada um dos aminoácidos tem pelo menos um tipo de RNAt a<br />
ele designado. O aminoácido é ligado ao RNAt que possui um anticódon (seqüência<br />
de três nucleotídeos que é complementar aos três nucleotídeos do códon que especifica o<br />
aminoácido na molécula de RNAm) correto, gerando uma molécula de aminoacil-RNAt.<br />
Através do pareamento códon-anticódon, o aminoácido é inserido em uma cadeia crescente<br />
de proteína, de acordo com o que está determinado na seqüência de nucleotídeo do RNAm.<br />
Com uma extremidade ligada a um aminoácido e a outra pareada a um códon, o RNAt<br />
converte a seqüência de nucleotídeo na seqüência de aminoácidos (figura 2.12). Apenas a<br />
molécula de RNAt, e não os aminoácidos a ela ligados, determina onde o aminoácido é<br />
adicionado durante a síntese de proteína.<br />
Figura 2.12: Detalhamento do processo de tradução.<br />
21
2.2 Algoritmos para Comparação de Seqüências Baseados<br />
em Programação Dinâmica<br />
A comparação de seqüências é a operação primitiva mais importante em Bioinformática,<br />
servindo como base para muitas outras manipulações complexas e é vastamente utilizada<br />
nos projetos de seqüenciamento.<br />
A comparação de seqüências consiste em duas partes: encontrar uma medida que indique<br />
a similaridade entre as seqüências, e obter uma forma de visualizar esta similaridade.<br />
A similaridade é uma métrica que expressa quantitativamente quão parecidas são duas<br />
seqüências. Já a visualização é feita por um alinhamento, que é um método de escrever<br />
uma seqüência acima da outra para tornar explícitas as correspondências entre caracteres<br />
ou regiões de caracteres similares das duas seqüências.<br />
O melhor alinhamento, ou<br />
alinhamento ótimo, é aquele que apresenta o máximo de regiões de similaridade [64].<br />
2.2.1 Alinhamento de seqüências<br />
Quando seqüências são comparadas, diversos termos podem ser utilizados para expressar<br />
o resultado encontrado. Identidade, similaridade e homologia de seqüências são<br />
os mais importantes, e embora sejam freqüentemente utilizados de forma intercambiável,<br />
seus significados são diferentes.<br />
A identidade entre seqüências se refere à ocorrência exata dos mesmos resíduos nas<br />
mesmas posições das seqüências alinhadas. A similaridade considera a possibilidade de<br />
ocorrência de mutações, sendo significativa quando estas são pontuadas de acordo com<br />
a probabilidade que têm de ocorrerem, sob um ponto de vista biológico. A homologia<br />
indica a existência de um relacionamento evolucionário entre as seqüências. A diferença<br />
entre os dois últimos termos é que a similaridade se refere à presença de locais idênticos<br />
ou similares nas seqüências, enquanto a homologia reflete uma afirmação mais forte, a de<br />
que as seqüências possuem um ancestral comum.<br />
Comparar seqüências depende da computação de um alinhamento entre elas. Para<br />
isso, é utilizado um esquema de pontuação do alinhamento. Cada coluna do alinhamento<br />
recebe um certo valor dependendo do seu conteúdo. A soma desses valores consiste na<br />
pontuação do alinhamento.<br />
Assim, as seqüências a serem comparadas são emparelhadas, ou seja, posicionadas uma<br />
acima da outra, de modos arbitrários e para cada um desses emparelhamentos é calculado<br />
um valor de acordo com certos critérios. O melhor alinhamento dentre todos os possíveis<br />
será aquele que possuir a maior pontuação.<br />
máximo, ambos serão considerados ótimos.<br />
Se dois alinhamentos resultarem no valor<br />
Um alinhamento de seqüências deve permitir introdução de espaços (gaps) em locais arbitrários<br />
das seqüências para compensar inserções ou remoções de bases de uma seqüência<br />
em relação a outra. A inclusão de espaços mantém, em registro, seqüências obviamente<br />
22
similares, o que não seria possível com um alinhamento direto sem eles. Assim, os espaços<br />
nos permitem lidar com contingências tais como duplicações internas, repetições, crossingover<br />
desigual e outras delinqüências genéticas. Não é permitido que um espaço em uma<br />
seqüência seja alinhado com um espaço na outra seqüência.<br />
Cada coluna do alinhamento recebe um certo valor dependendo do seu conteúdo. A<br />
soma desses valores resulta na pontuação do alinhamento. Um esquema de pontuação<br />
muito utilizado define um valor igual a +1 para colunas com caracteres coincidentes (matches)<br />
e −1 para colunas com caracteres divergentes (mismatches). Para impedir o acúmulo<br />
de muitos espaços em um alinhamento, uma quantidade fixa deve ser deduzida do valor<br />
acumulado a cada espaço introduzido. Assim, os espaços possuem pontuação negativa.<br />
Esse esquema de pontuação sugere o valor −2 para cada espaço inserido. Pode ainda ser<br />
definida uma penalidade mais suave para a extensão do espaço (espaços sucessivos).<br />
Por exemplo, considerando duas seqüências x = CCT AGA e y = CT AT GCAC, um<br />
possível alinhamento entre elas é mostrado na figura 2.13 e resultaria em uma pontuação<br />
(escore) igual a −5.<br />
Figura 2.13: Pontuação de um possível alinhamento entre CCTAGA e CTATGCAC.<br />
Nas comparações de seqüências de DNA, utiliza-se uma matriz unitária onde somente<br />
caracteres idênticos recebem uma pontuação positiva. No caso de se comparar<br />
seqüências protéicas, utilizam-se matrizes de substituição. Aminoácidos relativamente<br />
semelhantes recebem pontuação positiva e não semelhantes recebem pontuação negativa.<br />
Uma matriz de comparação para proteínas, amplamente utilizada nos últimos anos, foi a<br />
matriz PAM ( Point Accepted Mutation), construída por Dayhoff [16].<br />
Para construí-la, ele observou todas as substituições de aminoácidos verificadas em<br />
alinhamentos de um amplo conjunto de proteínas intimamente relacionadas, as quais<br />
tinham sofrido uma certa divergência evolucionária. A cada substituição possível de um<br />
resíduo foi dada uma pontuação que reflete a probabilidade de estar relacionado ao resíduo<br />
correspondente da seqüência em consulta. A pontuação do alinhamento é a soma das<br />
pontuações individuais e mede a quantidade de alterações evolutivas numa seqüência. Em<br />
média, 1,0 unidade PAM corresponde a alterações em 1% dos aminoácidos numa seqüência<br />
protéica.<br />
Um método alternativo, baseado nas matrizes BLOSUM (Blocks Substitution Matrix)<br />
[27] tem se mostrado superior à matriz PAM para detectar os parentescos biológicos<br />
entre seqüências moderadamente divergentes. No caso da matriz BLOSUM62, por exem-<br />
23
plo, o máximo de identidade compartilhado por duas seqüências é 62% e os scores são<br />
derivados da comparação de blocos de alinhamentos localizados nas proteínas relacionadas.<br />
Dependendo do tamanho das seqüências que estão sendo comparadas, matrizes de<br />
um tipo ou de outro são mais apropriadas.<br />
2.2.2 Algoritmos baseados em programação dinâmica<br />
Waterman mostrou que encontrar alinhamentos é um problema difícil, já que o número<br />
de alinhamentos possíveis é exponencial, dado aproximadamente pela fórmula [71]<br />
onde n representa o tamanho das seqüências.<br />
A n = (1 + √ 2) 2n+1√ n, (2.1)<br />
2.2.2.1 Comparação global<br />
Em 1970, Needleman e Wunsch [51] apresentaram o primeiro algoritmo de comparação<br />
de seqüências capaz de determinar o melhor alinhamento entre duas seqüências sem enumerar<br />
todas as soluções possíveis. A solução foi baseada em técnicas de programação<br />
dinâmica [13], que se baseia no princípio de que uma instância de um problema é resolvida<br />
aproveitando as soluções já computadas para instâncias menores deste problema.<br />
Programação dinâmica é aplicada tipicamente em problemas de otimização, para os<br />
quais deve-se construir um conjunto de escolhas visando obter uma solução ótima. À<br />
medida que estas escolhas são feitas, formam-se sub-problemas similares ao problema original.<br />
A idéia básica desta técnica é calcular o valor de cada sub-problema uma única vez,<br />
armazenando-o em uma tabela, e usar este valor sempre que o sub-problema correspondente<br />
reaparecer durante a execução do algoritmo que soluciona o problema.<br />
Existem duas características básicas que um problema de otimização deve ter para<br />
que a programação dinâmica possa ser aplicada: sub-estrutura ótima e sub-problemas<br />
que se sobrepõem. Dizemos que um problema exibe sub-estrutura ótima quando uma<br />
solução ótima para o problema é calculada a partir de soluções ótimas para sub-problemas<br />
similares, mas menores que o problema original. Em relação à segunda característica,<br />
para que um problema possua sub-problemas que se sobrepõem, o espaço de subproblemas<br />
deve ser pequeno, no sentido de que um algoritmo recursivo para o problema<br />
resolve os mesmos sub-problemas várias vezes, em vez de gerar diferentes sub-problemas.<br />
Tipicamente, o número total de sub-problemas distintos deve ser polinomial em relação<br />
ao tamanho da entrada.<br />
Dadas duas seqüências x e y, em vez de determinar a similaridade entre x e y tomando<br />
as duas seqüências inteiras, a solução pode ser obtida determinando todas as similaridades<br />
entre prefixos arbitrários das duas seqüências, iniciando pelos prefixos menores e utilizando<br />
os resultados já processados para resolver o problema para prefixos maiores.<br />
24
Este algoritmo reduziu a complexidade de tempo do problema de exponencial para<br />
quadrática, implementando um método de alinhamento global, que busca a similaridade<br />
máxima, pois prioriza os pareamentos (coincidências e divergências) e penaliza<br />
inserções e remoções (espaços) de bases, considerando o tamanho total das seqüências<br />
sendo comparadas. Este tipo de alinhamento é apropriado quando se espera encontrar<br />
similaridades ao longo de toda ou na maior parte das seqüências.<br />
Seguindo a técnica de programação dinâmica, a idéia básica do algoritmo consiste em<br />
dividir o problema de encontrar o melhor alinhamento entre duas seqüências em subproblemas<br />
de alinhar pares de bases, uma de cada seqüência, para encontrar subalinhamentos<br />
ótimos.<br />
alinhamentos possíveis:<br />
A solução de cada subproblema é dada pela escolha de um dos três<br />
• Alinhar as bases das duas seqüências;<br />
• Alinhar um espaço na primeira seqüência com a base da segunda seqüência;<br />
• Alinhar a base da primeira seqüência com um espaço na segunda seqüência.<br />
Para comparar duas seqüências x = x 1 x 2 . . . x |x| e y = y 1 y 2 . . . y |x| , onde |x| representa<br />
o comprimento da seqüência x e |y| o comprimento da seqüência y, o algoritmo gera uma<br />
matriz S |x|+1,|y|+1 , chamada de matriz de similaridade. Para cada célula s i,j da matriz,<br />
o algoritmo calcula a pontuação resultante de cada um dos três alinhamentos possíveis,<br />
selecionando o de maior valor, conforme a equação de recorrência do algoritmo de<br />
comparação global (equação 2.2).<br />
⎧<br />
⎪⎨ s i−1,j + ins<br />
s i,j = max s i−1,j−1 + sub<br />
⎪⎩<br />
s i,j−1 + del<br />
s i,0 = i × ins,<br />
s 0,j = j × del,<br />
i = 0, 1, . . . , |x|<br />
j = 1, 2, . . . , |y|<br />
(2.2)<br />
Os valores ins, sub e del são pontuações referentes a inserções, substituições e remoções,<br />
respectivamente. Conforme já citado, um esquema de pontuação muito utilizado [64]<br />
sugere ins = del = −2 que é a penalidade para inserir um espaço em uma das duas<br />
seqüências (alinhamento de uma base com um espaço). Para a substituição, temos sub =<br />
+1 se as duas bases x i e y j comparadas forem iguais ou sub = −1, caso contrário.<br />
A figura 2.14 mostra a matriz de similaridade obtida com a aplicação da equação de<br />
recorrência (equação 2.2) nas seqüências x = AACGT e y = AGT .<br />
A seqüência x é<br />
posicionada ao longo das colunas e y ao longo das linhas da matriz. A primeira linha e a<br />
primeira coluna, conforme a equação 2.2, são inicializadas com múltiplos da penalidade do<br />
espaço (−2 com o esquema de pontuação utilizado). Isto se deve à existência de apenas um<br />
alinhamento possível se uma das seqüências está vazia: apenas adicionar tantos espaços<br />
quanto forem os caracteres da outra seqüência. O escore deste alinhamento é −2k, onde k<br />
é o tamanho da seqüência não vazia. Para calcular as demais entradas (i, j) da matriz, só é<br />
preciso obter os valores computados para as três entradas anteriores: (i−1, j), (i−1, j −1)<br />
25
e (i, j−1), em função de haverem apenas três formas de obter um alinhamento entre x [1..i]<br />
e y [1..j]. De fato, para obter um alinhamento entre x [1..i] e y [1..j], temos as seguintes<br />
escolhas:<br />
• Alinhar x [1..i] com y [1..j − 1] e combinar um espaço com y [j], ou<br />
• Alinhar x [1..i − 1] com y [1..j − 1] e combinar x [i] com y [j], ou<br />
• Alinhar x [1..i − 1] com y [1..j] e combinar x [i] com um espaço.<br />
Figura 2.14: Matriz de similaridades das seqüências x = AACGT e y = AGC.<br />
Os ponteiros nessa matriz indicam qual dos três valores da equação de recorrência foi<br />
a origem da maior pontuação para a célula em questão. O preenchimento da matriz de<br />
similaridade pode ser feito tanto linha a linha, da esquerda para a direita em cada linha,<br />
ou coluna a coluna, de cima para baixo, em cada coluna. Qualquer outra ordem que torne<br />
disponível s [i, j − 1], s [i − 1, j − 1], s [i − 1, j] quando o valor de s [i, j] for computado,<br />
também pode ser utilizada.<br />
Com a matriz preenchida, o segundo passo é identificar o melhor alinhamento global.<br />
Para isso, é utilizado um procedimento de rastreamento no sentido inverso pela<br />
matriz, chamado backtracking, iniciando pelo elemento s [|x| + 1, |y| + 1], seguindo o direcionamento<br />
indicado pelos ponteiros de cada célula visitada até chegar na entrada s [0, 0]<br />
(figura 2.15). Cada ponteiro usado fornecerá uma coluna do alinhamento. Para uma dada<br />
célula (i, j) da matriz, se o ponteiro for uma seta horizontal, ela corresponde a um espaço<br />
inserido em x combinando com y [j]; se for uma seta vertical, então corresponde a x [i]<br />
combinado com um espaço inserido em y; finalmente, se for uma seta diagonal corresponde<br />
a x [i] combinando com y [j]. Como a primeira seqüência, x, é sempre colocada ao<br />
longo das colunas, um alinhamento ótimo pode ser facilmente construído da direita para<br />
a esquerda se tivermos a matriz S já calculada.<br />
Note que existem valores que são origem de mais de um vetor. Se um desses valores<br />
fizer parte do percorrimento reverso, todas as possibilidades deverão ser exploradas, pois<br />
cada uma delas representa um alinhamento ótimo.<br />
26
Figura 2.15: Obtenção do melhor alinhamento global.<br />
Para o exemplo anterior, o seguintes alinhamento ótimos são obtidos pelo percorrimento<br />
reverso, com x sendo a linha superior e y a inferior:<br />
A A C G T<br />
A − − G T<br />
e<br />
A A C G T<br />
− A − G T<br />
Para determinar a complexidade do algoritmo descrito, notamos que o número de<br />
operações executadas depende, essencialmente, do número de células da matriz que devem<br />
ser computados, isto é, do seu tamanho. Assim, supondo duas seqüências com comprimentos<br />
m e n, será gasto um tempo O(mn) nesses cálculos e este é o termo dominante<br />
da complexidade de tempo. O espaço utilizado também é proporcional ao tamanho da<br />
matriz. Se as seqüências tiverem o mesmo ou aproximadamente o mesmo tamanho, n,<br />
teremos complexidade de espaço e tempo de O(n 2 ), ou seja, uma complexidade quadrática.<br />
2.2.2.2 Comparação local<br />
O algoritmo de Needleman-Wunsch atribui uma penalidade constante, w k = kw 1 ,<br />
onde w 1 é a penalidade de inserção de um espaço, para seqüências de espaços, em uma<br />
das seqüências alinhadas. No entanto, sob o ponto de vista biológico, quando ocorrem<br />
eventos mutacionais em uma seqüência, a ocorrência de k espaços juntos é mais provável<br />
do que a ocorrência de k espaços isolados. Em 1981, Smith e Waterman generalizaram<br />
o algoritmo proposto por Needleman e Wunsch incorporando este critério, que atribui<br />
penalidades para espaços juntos considerando os seus tamanhos (w k ≤ kw 1 ), e propuseram<br />
um método de alinhamento local que, diferentemente do método de alinhamento global,<br />
identifica sub-regiões de maior similaridade entre as seqüências comparadas [66].<br />
Um alinhamento local de duas seqüências é definido como um alinhamento entre uma<br />
subseqüência da primeira seqüência com uma subseqüência da segunda. A similaridade<br />
das duas seqüências é definida como o escore máximo sobre todos os possíveis alinhamentos<br />
locais.<br />
Em várias aplicações biológicas, a identificação de regiões locais de similaridade em<br />
27
seqüências longas é mais significativa do que a similaridade entre as seqüências inteiras,<br />
pois o baixo valor desta pode esconder importantes fatos biológicos, só observáveis quando<br />
se consideram as sub-regiões.<br />
O algoritmo de Smith-Waterman é baseado em duas modificações no algoritmo de<br />
Needleman e Wunsch:<br />
• Quando o escore de um subalinhamento entre duas subsequências resulta em um<br />
valor negativo, é atribuído escore zero, que indica que o subalinhamento não deve<br />
ser prolongado;<br />
• Não basta considerar três células da matriz, pois em função da penalidade não constante<br />
para espaços juntos, é preciso verificar todas as células na mesma linha e todas<br />
as células na mesma coluna. Conseqüentemente, a interpretação dos valores da matriz<br />
é diferente. Cada entrada (i, j) irá armazenar o maior valor de um alinhamento<br />
entre um sufixo de x [1..i] e um sufixo de x [1..j].<br />
Neste caso, para encontrar o melhor alinhamento local, basta localizar a entrada da<br />
matriz que possui o maior valor de escore e aplicar o procedimento de rastreamento no<br />
sentido inverso até encontrar uma entrada com escore zero.<br />
No entanto, em função do tratamento diferenciado para a atribuição de penalidades<br />
para espaços juntos, o algoritmo de Smith-Waterman apresenta uma complexidade de<br />
tempo de O(n 3 ).<br />
Gotoh [23], em 1982, propôs uma forma de reduzir essa complexidade de tempo, modificando<br />
o algoritmo de Smith-Waterman por meio de uma limitação na métrica utilizada<br />
para espaços juntos. Sem afetar o critério de computar espaços juntos de tamanhos variados,<br />
ele conseguiu reduzir a complexidade de tempo para O(n 2 ), utilizando uma forma<br />
especial de penalidade para estes espaços juntos, chamada função de espaços juntos<br />
afim, expressa pela fórmula w k = u +vk (u, v ≤ 0), onde u expressa a penalidade para inserir<br />
o primeiro espaço, v indica o custo para estendê-lo e k indica o tamanho do conjunto<br />
de espaços juntos. A equação 2.3 representa a proposta de Gotoh.<br />
⎧<br />
⎪⎨ p i,j<br />
s i,j = max s i−1,j−1 + sub<br />
⎪⎩<br />
q i,j<br />
{<br />
si−1,j + w<br />
p i,j = max<br />
1<br />
p i−1,j + v<br />
{<br />
si,j−1 + w<br />
q i,j = max<br />
1<br />
q i,j−1 + v<br />
s i,0 = p i,0 = q i,0 = 0,<br />
s 0,j = p 0,j = q 0,j = 0,<br />
i = 0, 1, . . . , |x|<br />
j = 1, 2, . . . , |y|<br />
(2.3)<br />
Se a penalidade do espaço for constante como no algoritmo de Needleman-Wunsch,<br />
a equação de recorrência do algoritmo de comparação local pode ser reduzida para a<br />
equação 2.4.<br />
28
⎧<br />
⎪⎨<br />
s i,j = max<br />
⎪⎩<br />
s i−1,j + w 1<br />
s i−1,j−1 + sub<br />
s i,j−1 + w 1<br />
0<br />
s i,0 = 0,<br />
s 0,j = 0,<br />
i = 0, 1, . . . , |x|<br />
j = 1, 2, . . . , |y|<br />
(2.4)<br />
Embora não seja a equação mais correta do ponto de vista biológico, essa equação foi<br />
a escolhida para a implementação feita nessa dissertação. A idéia é atacar o problema<br />
com uma abordagem mais simples, e uma vez conhecidas suas peculiaridades, estender a<br />
solução obtida para situações mais complexas.<br />
Espaço Linear<br />
A complexidade quadrática em espaço do algoritmo de Smith-Waterman, que reflete<br />
a quantidade de memória necessária, pode torná-lo inviável quando seqüências muito<br />
longas forem comparadas, já que manter a matriz de similaridades totalmente carregada<br />
em memória possui um custo muito alto. No entanto, para o cálculo da posição s i,j , são<br />
necessários apenas os valores s i−1,j , s i−1,j−1 e s i,j−1 . Logo, é preciso manter em memória<br />
apenas a linha atual que está sendo calculada e a linha anterior, para consulta. Com isto,<br />
a complexidade de espaço que era O(n 2 ) passa a ser O(2n). A complexidade de tempo<br />
permanece O(n 2 ).<br />
29
Capítulo 3<br />
<strong>HARDWARE</strong><br />
3.1 Sistemas Dedicados<br />
Arquiteturas tradicionais de computadores podem resolver uma diversidade muito<br />
grande de problemas de computação, desde que lhes sejam submetidos diferentes programas,<br />
cada qual com um propósito específico. Para a maioria das tarefas de computação,<br />
esta abordagem, centrada na utilização de processadores de propósito geral (GPP), é mais<br />
barata e rápida.<br />
O principal foco do projeto de GPPs reside, pois, no desempenho e na funcionalidade<br />
geral a ser proporcionada. Contudo, os custos de fabricação e projeto de arquiteturas<br />
baseadas em processadores de propósito geral estão aumentando com rapidez [5]. Tais<br />
custos compreendem três perceptíveis aspectos:<br />
• Custos de hardware: os processadores de propósito geral são maiores e mais complexos<br />
do que o necessário para resolver uma tarefa específica;<br />
• Custos de projeto: unidades funcionais, raramente usadas em determinadas aplicações,<br />
podem estar presentes em GPPs, tendendo a consumir uma parte considerável do<br />
esforço de projeto;<br />
• Custos de energia: muita energia é desperdiçada por unidades funcionais ou blocos<br />
que não são usados durante grande porção do tempo de processamento.<br />
Considerando-se aplicações específicas ou a exigência de requisitos em termos de consumo,<br />
velocidade, tamanho e custos, podem ser adotados tipos especiais de processadores,<br />
voltados para a aplicação em questão ou otimizados com vistas ao conjunto de requisitos<br />
especificados. Sob esta ótica, somente as unidades funcionais necessárias, altamente otimizadas<br />
para um conjunto de problemas do mesmo tipo, estão presentes, o que redunda<br />
em economia de área e energia para o algoritmo específico às aplicações.<br />
Dessa forma, sistemas computacionais dedicados são usados tipicamente em aplicações<br />
específicas onde os sistemas de propósito geral não conseguem obter o desempenho esperado.<br />
30
No desenvolvimento desses circuitos dedicados, o desempenho depende, na maioria das<br />
vezes, mais da arquitetura do circuito do que da tecnologia de fabricação [12]. Este conceito<br />
é largamente utilizado no projeto de sistemas de tratamento de sinais, por exemplo,<br />
onde um processador com baixo custo executa uma filtragem mais rapidamente que um<br />
poderoso Pentium®.<br />
Para decidir sobre a utilização de um sistema dedicado e a arquitetura mais adequada,<br />
diversos aspectos devem ser levados em conta.<br />
Unidades simples e regulares<br />
Como os sistemas dedicados possuem aplicação limitada, seu custo deve ser menor<br />
que o benefício da utilização de uma arquitetura de propósito específico. Além do mais,<br />
como os sistemas dedicados não são produzidos em larga escala, os custos de projeto<br />
são mais importantes que os custos da fabricação das peças. Dessa forma, os custos de<br />
projeto devem ser baixos de modo a tornar esses sistemas mais atrativos que os sistemas<br />
de propósito geral.<br />
Felizmente, a utilização de arquiteturas apropriadas pode reduzir significativamente<br />
os custos de sistemas de propósito específico. Se uma determinada estrutura puder ser<br />
decomposta em poucas unidades menores e mais simples, e essas serem utilizadas repetidamente,<br />
uma grande economia pode ser obtida. Isto é especialmente verdade em projetos<br />
de circuito integrados VLSI, onde um simples chip contém milhares de componentes. Em<br />
adição, sistemas baseados em unidades simples e regulares são modulares e podem se<br />
ajustar a diversos critérios de performance.<br />
Operações de entrada e saída<br />
Tipicamente, um sistema dedicado deve se comunicar com o mundo externo, recebendo<br />
dados e entregando resultados. Não adianta o sistema fornecer resultados em uma velocidade<br />
maior que o mundo externo é capaz de recebê-los. Assim, as operações de entrada e<br />
saída (E/S) afetam bastante o desempenho geral de sistemas com arquiteturas específicas.<br />
Outra dificuldade é quando cálculos extensos devem se feitos em sistemas de pequeno<br />
porte. Neste caso, a computação deve ser decomposta em partes menores e os dados temporários<br />
gerados armazenados para futuras referências. Isso aumenta muito a comunicação<br />
com o ambiente externo.<br />
Assim, várias considerações devem ser feitas sobre como minimizar o acesso externo,<br />
como os requisitos de E/S afetam o sistema e sua memória interna e como a largura de<br />
banda das operações de entrada e saída pode limitar o ganho de velocidade (speed-up).<br />
31
Concorrência<br />
O hardware é inerentemente paralelo. Ao se ligar um circuito eletrônico, todos os seus<br />
transistores estão aptos a realizar alguma função. A utilização conveniente do paralelismo<br />
encontra, basicamente, duas dificuldades: raciocínio serial e dependência de dados. O<br />
primeiro problema é inerente à nossa forma de raciocinar, o segundo, advém das aplicações,<br />
pois alguns resultados só podem ser processados após o término de outros.<br />
Em termos de paralelismo, deve-se distinguir o modelo de hardware que se está tratando,<br />
ou pelo menos, seu nível de abstração. Existe o paralelismo explícito de processos,<br />
formado por um conjunto de máquinas, como em uma rede de computadores, ou por um<br />
conjunto de processadores atuando em conjunto.<br />
Um outro nível de paralelismo é aquele de processos de hardware completamente distintos,<br />
executando funções complementares. Como exemplo, podemos ter um microprocessador<br />
operando em paralelo com um temporizador e uma interface serial.<br />
Finalmente, tem-se o paralelismo em nível de operações de hardware. Por exemplo,<br />
no cálculo da equação y = x 2 + 3x + 1, a exponenciação pode ser feita em paralelo com a<br />
multiplicação, pois não há dependência de dados para essas operações. Em geral, quanto<br />
mais paralelismo estiver presente, mais rapidamente um algoritmo pode ser computado.<br />
Contudo, maior será o preço do hardware final, seja na utilização de uma maior área de<br />
silício em um CI, seja na quantidade de células lógicas necessárias em um FPGA.<br />
Para limitar esse problema no paralelismo de operações, a questão a ser respondida é<br />
qual o número mínimo de passos de relógio e qual o mínimo de componentes necessários<br />
para executar o algoritmo na maior velocidade possível. As duas características combinadas<br />
tendem a ser conflitantes. Para maior velocidade, precisa-se de um mínimo de passos,<br />
mas para executar o algoritmo em um mínimo de passos, maior quantidade de hardware<br />
deve estar disponível.<br />
Existem algoritmos que permitem descobrir o menor número de passos necessários,<br />
dada uma restrição de recursos. Entre esses, podemos citar o ASAP (as soon as possible),<br />
ALAP (as late as possible) e ordenação de lista (list scheduling) [20][48][49]. Nesses<br />
algoritmos, as operações são distribuídas em diversos passos de relógio, com o ASAP priorizando<br />
as operações para o primeiro ciclo possível, o ALAP colocando as operações o<br />
mais próximo do último ciclo de controle possível e a ordenação por listas utilizando as<br />
tabelas do ASAP e ALAP para efetuar suas decisões.<br />
Controle e comunicação<br />
Quando um elevado número de processadores opera em paralelo, os custos de controle<br />
(sincronização) e comunicação começam a ser tornar significativos. Se a granularidade for<br />
fina, para facilitar o balanceamento de carga, podem ocorrer sobrecargas de comunicação<br />
32
e sincronização.<br />
Na análise do sistema, devemos verificar se o algoritmo a ser abordado com a arquitetura<br />
dedicada suporta um alto grau de paralelismo e ao mesmo tempo pode ser<br />
implementado com um controle e comunicação simples e regular.<br />
No paralelismo de operações, também pode-se ter um alto custo de comunicação e<br />
controle. Imagine que uma constante deva ser somada a 100 números, disponíveis em 100<br />
registradores diferentes. Um conjunto de 100 somadores permitiria a soma em apenas<br />
um ciclo de relógio. Se cada registrador pudesse ser carregado no mesmo ciclo, a cada<br />
ciclo ter-se-iam 100 somas. Contudo, o custo de tal arquitetura é muito alto, pois além<br />
dos 100 somadores e registradores, seriam necessários 100*n bits de entrada, onde n é<br />
o número de bits de cada registrador, e, provavelmente, muito mais bits de saída pois<br />
o resultado de cada soma será maior que os valores somados. Para piorar, se os dados<br />
para os registradores vierem de uma memória externa e também devam ser armazenados<br />
externamente, o problema adquire novas dimensões.<br />
A conclusão é que, embora o paralelismo efetivamente acelere computações, seu custo<br />
deve ser medido não somente em termos de operadores a mais, mas também no custo do<br />
controle e comunicação para manterem o circuito paralelo ativo e funcional.<br />
3.2 Arquiteturas Sistólicas<br />
Uma possível solução para o projeto de sistemas dedicados são as arquiteturas sistólicas.<br />
Esse conceito foi desenvolvido na universidade Carnegie-Mellon e originalmente proposto<br />
para a implementação em VLSI de algumas operações sobre matrizes.<br />
A origem desse nome vem da sístole, movimento de contração no qual o coração bombeia<br />
o sangue para as artérias, da mesma forma que a memória “bombeia” dados para<br />
dentro da estrutura sistólica e que depois retornam processados para essa memória (figura<br />
3.1).<br />
Figura 3.1: Aspecto geral de uma arquitetura sistólica.<br />
Um sistema sistólico consiste em um conjunto de células (chamadas de elementos<br />
de processamento) interconectadas, cada uma capaz de realizar alguma operação simples<br />
[37]. Além disso, o controle e a comunicação entre as células é simples e regular.<br />
Tipicamente, as células de uma estrutura sistólica estão organizadas na forma de matrizes<br />
33
(unidimensionais ou bidimensionais) ou em árvores (figura 3.2). A comunicação com o<br />
mundo externo ocorre apenas nas células das “bordas” do sistema.<br />
Figura 3.2: Alguns tipos de estruturas sistólicas.<br />
O princípio básico de um sistema sistólico é substituir um elemento de processamento<br />
complexo por uma matriz de elementos de processamento simples e, conseqüentemente,<br />
rápidos, todos capazes de manipular eficientemente um particular dado de entrada (que<br />
percorre a estrutura), atingindo altas taxas de processamento com modesta utilização de<br />
memória.<br />
Para se avaliar a possibilidade de utilização dessa arquitetura em um particular problema,<br />
as seguintes características do algoritmo ou sistema devem ser analisadas:<br />
1. múltiplos usos de um único dado de entrada: devido a essa propriedade, pode-se<br />
obter alta performance com poucas operações de entrada e saída;<br />
2. uso intensivo de concorrência: o poder elevado de processamento de uma arquitetura<br />
sistólica vem do uso de muitas células simples e rápidas atuando em paralelo no lugar<br />
de um poderoso e único processador (ou poucos processadores);<br />
3. pode-se decompor a solução em poucas estruturas simples: como uma grande quantidade<br />
de elementos de processamento é utilizada, não deve haver muita variedade<br />
desses elementos e eles devem ser o mais simples possível;<br />
4. controle do fluxo de dados simples e regular: em um sistema sistólico, o único sinal<br />
global deve ser o relógio do sistema. Os outros sinais de controle e comunicação<br />
devem ficar restritos às células adjacentes da estrutura.<br />
Resumindo, um sistema sistólico baseado nesses critérios será simples, modular e expansível,<br />
com alta performance e possuindo poucos acessos à memória externa.<br />
Devido a essas propriedades, as arquiteturas sitólicas são adequadas para tarefas computacionalmente<br />
intensas, mas com poucas operações de entrada e saída.<br />
34
Dentre as possíveis aplicações para esse tipo de arquitetura, destacam-se: DFT (Discrete<br />
Fourier Transform) e FFT (Fast Fourier Transform), convolução, interpolação, multiplicação<br />
de matrizes, triangularização de matrizes (solução de sistemas lineares), ordenamentos,<br />
reconhecimento de voz, programação dinâmica, etc.<br />
3.3 Sistemas Reconfiguráveis<br />
A evolução contínua dos algoritmos e a diversidade das aplicações têm levado à concepção<br />
de ambientes de hardware baseados em arquiteturas reconfiguráveis que possibilitem<br />
a implementação de diferentes algoritmos em um mesmo suporte físico.<br />
Muitas aplicações emergentes em telecomunicações e multimídia necessitam que suas<br />
funcionalidades permaneçam flexíveis mesmo depois do sistema ter sido manufaturado [26].<br />
Tal flexibilidade é fundamental, uma vez que requisitos dos usuários, características dos<br />
sistemas, padrões e protocolos podem mudar durante a vida do produto. Essa maleabilidade<br />
também pode prover novas abordagens de implementação voltadas para ganhos de<br />
desempenho, redução dos custos do sistema ou redução do consumo geral de energia.<br />
A flexibilidade funcional é comumente obtida através de atualizações de software, mas<br />
desta forma a mudança é limitada somente à parte programável dos sistemas. Desenvolvimentos<br />
recentes na tecnologia de matrizes de elementos lógicos programáveis no campo<br />
(Field-Programmable Gate Arrays, ou FPGAs) têm introduzido suporte para modificações<br />
rápidas e em tempo de execução do hardware do sistema.<br />
Essas modificações referem-se a mudanças em circuitos digitais via reconfiguração.<br />
A implementação de sistemas que exigem flexibilidade, alto desempenho, alta taxa de<br />
transferência de dados e eficiência no consumo de energia são possibilitadas por essas<br />
tecnologias. Isto inclui aplicações de televisão digital, sistemas de computação de alto desempenho,<br />
processamento de imagens em tempo real, produtos para consumo atualizáveis<br />
remotamente, entre outros.<br />
Além das características citadas acima, a reconfigurabilidade também contribui para<br />
a economia de recursos: quando uma dada tarefa pode ser realizada em várias fases, uma<br />
diferente configuração pode ser carregada para cada fase seqüencialmente [70]. Desta<br />
forma o tamanho do sistema pode ser menor, o que implica na redução de preço.<br />
Para finalizar, a reconfigurabilidade também faz do desenvolvimento e teste de hardware<br />
tarefas mais rápidas e mais baratas. Com o advento das FPGAs, a engenharia de<br />
hardware foi capacitada a implementar projetos em nível de chip sem ter que fabricá-lo.<br />
Segundo Page [54], há cinco estratégias de projeto pelas quais programas podem ser<br />
embutidos em arquiteturas reconfiguráveis, sendo cada modelo mais apropriado a um<br />
específico escopo de aplicações, apresentando diferentes compromissos entre custo e desempenho<br />
(figura 3.3):<br />
• Modelo de hardware puro: um dado algoritmo é convertido em uma única descri-<br />
35
ção de hardware a qual é carregada em um FPGA. A configuração dá-se em tempo<br />
de projeto e este modelo pode ser implementado a partir de linguagens de descrição<br />
de hardware convencionais e das ferramentas de síntese atualmente disponíveis. É<br />
interessante para o projeto e rápida prototipação de circuitos dedicados;<br />
• Modelo de processadores voltados para uma aplicação: neste caso, um algoritmo<br />
é compilado e obtêm-se dois resultados: um código de máquina abstrata e um<br />
processador abstrato. A seguir, as partes são otimizadas para produzir a descrição<br />
de um processador de aplicação específica e o código de máquina para ele;<br />
• Modelo de reutilização seqüencial: a principal utilidade desta estratégia é notada<br />
em situações nas quais determinado algoritmo é por demais extenso para ser<br />
implementado nos dispositivos disponíveis, ou ainda, quando o projeto apresenta<br />
restrições de área por razões econômicas ou de engenharia. Deste modo, o projeto<br />
é subdividido em várias partes, as quais são submetidas a diferentes dispositivos,<br />
redundando em um conjunto de passos de reconfiguração. Os ganhos relacionados<br />
com a reutilização do hardware devem ser balanceados com o tempo que é gasto<br />
com a reconfiguração;<br />
• Modelo de múltiplo uso simultâneo: se porventura houver uma ampla disponibilidade<br />
de dispositivos programáveis, vários algoritmos podem estar residentes e<br />
serem executados simultaneamente, interagindo em diferentes graus de acoplamento<br />
com o processador hospedeiro. É um modelo menos comum, requerendo mais área<br />
do que a estratégia de reutilização seqüencial, mas é um método interessante para<br />
a exploração da computação reconfigurável.<br />
• Modelo de uso sob demanda: é muito interessante para a computação reconfigurável.<br />
Pode ser adotado em uma ampla variedade de aplicações quando existe a<br />
possibilidade de sistemas computacionais serem construídos onde o hardware não<br />
existe todo ao mesmo tempo, mas cuja demanda de tempo-real do sistema dita qual<br />
parte do hardware deve ser construída e qual parte deve ser destruída. Há uma<br />
analogia razoável com sistemas de memória virtual, e por isto esse esquema pode<br />
ser chamado de “hardware virtual”. Sua utilização cabe perfeitamente em sistemas<br />
de tempo real e em sistemas que apresentam uma grande quantidade de funções e<br />
operações não-concorrentes.<br />
Sob a ótica da capacidade de reconfiguração proporcionada pelo projeto da arquitetura<br />
reconfigurável, Adário [5] apresenta uma generalização dos modelos de execução definidos<br />
por Page. Esta abordagem divide os modelos de projeto em três classes de capacidade<br />
de programação, considerando o número de configurações e o instante em que ocorre<br />
cada reconfiguração:<br />
36
Figura 3.3: Modelos segundo a classificação de Page.<br />
• Projeto Estático: o circuito possui uma única configuração que nunca é modificada.<br />
O dispositivo programável é totalmente programado para executar uma única<br />
função que permanece inalterada durante toda vida útil do sistema. Esta classe não<br />
explora a flexibilidade provida pela reconfiguração; a única vantagem aproveitada<br />
diz respeito às facilidades de projeto e prototipação conferidas pela reconfiguração;<br />
• Projeto Estaticamente Reconfigurável: o circuito apresenta várias configurações,<br />
e as reconfigurações acontecem apenas ao final de cada tarefa de processamento. Dependendo<br />
da granularidade das tarefas executadas entre sucessivas reconfigurações,<br />
pode-se dizer que este modelo efetua reconfiguração em tempo de execução. Neste<br />
modelo, os dispositivos programáveis são usados de forma mais proveitosa. Arquiteturas<br />
desta classe são chamadas de SRA – Statically Reconfigurable Architecture;<br />
• Projeto Dinamicamente Reconfigurável: o circuito também apresenta várias<br />
configurações e as reconfigurações acontecem, de fato, em tempo de execução. Este<br />
tipo de projeto utiliza eficientemente as arquiteturas reconfiguráveis. O overhead<br />
acarretado pela reconfiguração em tempo de execução precisa ser bem caracterizado<br />
no domínio do conjunto das possíveis configurações. As arquiteturas resultantes<br />
desta classe são denominadas DRA – Dynamically Reconfigurable Architecture.<br />
As vantagens que podem ser auferidas da reconfiguração em tempo de execução dependem<br />
muito do algoritmo em questão e da granularidade das tarefas que o compõem.<br />
Por sua vez, o overhead de reconfiguração está fortemente vinculado à microarquitetura<br />
das FPGAs utilizadas.<br />
37
Geralmente, as aplicações, cuja implementação em arquiteturas reconfiguráveis é desejável,<br />
apresentam três características básicas, a saber[4]:<br />
• Regularidade: implica na execução das mesmas operações básicas repetidamente;<br />
• Alta concorrência: refere-se à existência de um grande número de operações que<br />
são efetuadas concomitantemente;<br />
• Dados com granularidade fina: diz respeito ao pequeno tamanho dos operandos.<br />
Dadas tais características, podem ser arroladas aplicações passíveis de implementação<br />
profícua em arquiteturas reconfiguráveis. Segundo Adário[4], merecem especial atenção<br />
aplicações voltadas para: criptografia e compressão, casamento de padrões, ordenação,<br />
simulação de sistemas físicos, processamento de vídeo e de imagens, aritmética especializada.<br />
Para que se possa tirar proveito de uma implementação em arquitetura reconfigurável,<br />
dois passos devem ser seguidos:<br />
• Identificar, em um aplicação, a porção regular e a seção crítica ao desempenho;<br />
• Avaliar as opções para o mapeamento da aplicação em dispositivos programáveis.<br />
Esta consideração é deveras importante, pois a melhor implementação em uma arquitetura<br />
reconfigurável pode ser muito diferente, no que tange ao estilo de programação,<br />
de uma implementação baseada em GPP.<br />
3.3.1 FPGA<br />
Os FPGAs (Field-Programmable Gate Arrays) foram introduzidos no mercado em 1985<br />
pela Xilinx e foram responsáveis pela grande expansão dos sistemas reconfiguráveis. Esses<br />
dispositivos permitem a integração de lógica e memória em um único circuito, além de<br />
serem programáveis, permitindo a reconfiguração do hardware e rápida prototipação de<br />
sistemas digitais.<br />
A estrutura básica do FPGA (figura 3.4) pode variar segundo o fabricante do mesmo,<br />
mas são compostos, basicamente, dos seguintes recursos:<br />
1. Funções lógicas programáveis de n entradas (blocos lógicos), onde n varia com a<br />
família e fabricante do FPGA;<br />
2. Rede de conexão para interligar entre os diversos blocos lógicos existentes;<br />
3. Flip-flops ou registradores (blocos lógicos) para o armazenamento de informações;<br />
4. Amplificadores de corrente de entrada e saída;<br />
38
Figura 3.4: Estrutura interna de um FPGA.<br />
5. Memória RAM interna nos dispositivos mais modernos.<br />
FPGAs que possuem um pequeno número de poderosos blocos lógicos reconfiguráveis<br />
são classificados como FPGAs com granulações grandes, enquanto que os que possuem<br />
grande número de blocos lógicos simples, são classificados como FPGAs com granulações<br />
pequenas [70]. Um único bloco lógico em um FPGA com grande granulação é capaz de<br />
adicionar ou comparar dois números, enquanto que em um FPGA com granularidade fina<br />
são necessários mais de um bloco lógico para efetuar as mesmas operações.<br />
3.3.2 Síntese de sistemas reconfiguráveis<br />
Os FPGAs são componentes bastante versáteis, capazes de implementar uma infinidade<br />
de circuitos lógicos combinacionais e seqüenciais. Entretanto, a tarefa de transformar o<br />
projeto de um circuito digital em um circuito mapeado na tecnologia de FPGA é bastante<br />
complexa.<br />
Além disso, os FPGAs possuem uma arquitetura interna que, embora possua um núcleo<br />
comum, varia dentro de famílias de um mesmo fabricante e também entre fabricantes<br />
diferentes. Devido a essa diversidade, uma outra tarefa difícil para o projetista é conhecer<br />
todas essas arquiteturas internas e manipular seus elementos programáveis (EABs, CLBs<br />
e interconexões) da forma mais otimizada para a arquitetura em questão.<br />
Para automatizar os processos envolvidos nos projetos com esses dispositivos e abstrair<br />
as dependências tecnológicas, diversas ferramentas foram criadas, algumas de uso geral<br />
e outras dependentes da tecnologia de um particular fabricante. A grande utilização<br />
dos FPGAs é devida ao suporte dado por esses programas de automação de projetos<br />
eletrônicos.<br />
Fluxo de projeto<br />
O fluxo de projeto para FPGA pode ser dividido basicamente nas seguintes fases:<br />
especificação do circuito, síntese, simulação e configuração do FPGA, como pode ser visto<br />
39
na figura 3.5.<br />
O projeto começa com a descrição do circuito. Nesta etapa pode-se optar por duas<br />
metodologias de especificação, o desenho de um diagrama esquemático ou a utilização de<br />
uma linguagem de descrição de hardware. A primeira abordagem normalmente requer ferramentas<br />
proprietárias do fabricante do FPGA escolhida, prejudicando sua portabilidade.<br />
Além disso, as alterações no projeto são mais complexas que nas linguagens de descrição.<br />
Por esses motivos, deve ser evitada.<br />
Figura 3.5: Fluxo de projeto utilizando FPGAs.<br />
Para uma especificação baseada em linguagens de descrição de hardware, as linguagens<br />
Verilog [18] e VHDL [10] são as mais utilizadas. Verilog é utilizado basicamente no mercado<br />
americano, enquanto que a linguagem VHDL é um padrão mundial.<br />
A etapa de síntese, em geral, é executada por uma ferramenta do fabricante do FPGA<br />
escolhida, pois está intimamente ligada com sua arquitetura interna. Ela pode ser dividida<br />
nas seguintes partes:<br />
• otimização lógica: manipula as equações lógicas geradas na etapa inicial, visando<br />
otimizar o circuito final;<br />
• mapeamento tecnológico: consiste na transformação das equações lógicas otimizadas<br />
em um circuito que utiliza os blocos lógicos presentes no FPGA alvo. Nesta fase<br />
também são realizadas minimizações nas quantidades de blocos lógicos e caminho<br />
crítico (caminho com maior atraso combinacional) do circuito;<br />
• posicionamento: é definida a distribuição os blocos lógicos na matriz do FPGA. Para<br />
isso, o arranjo dos blocos tenta minimizar o comprimento total das interconexões;<br />
• roteamento: é quando ocorre a interligação dos blocos lógicos dispostos na matriz<br />
do FPGA por intermédio da rede de interconexões programável.<br />
40
A síntese, embora totalmente automatizada, permite a intervenção de projetistas experientes,<br />
principalmente na fase de posicionamento, que é bastante crítica para a performance<br />
geral do sistema.<br />
Na fase de simulação é efetuado um teste da lógica do circuito descrito. Vários<br />
estímulos são aplicados em suas entradas e depois é verificado o comportamento ou as<br />
respostas obtidas para esses estímulos. Além disso, é possível verificar os atrasos internos,<br />
ou seja, tempo que um sinal de saída leva para ser alterado após a transição de um sinal<br />
de entrada, determinar caminhos críticos e a velocidade máxima de operação.<br />
Já no processo de síntese, é gerado um arquivo de configuração do FPGA. Não sendo<br />
descoberto nenhum problema durante a simulação, esse arquivo pode ser enviado para o<br />
FPGA, de maneira que ele passe a operar de acordo com o circuito projetado. Como o<br />
FPGA é volátil, o arquivo gerado pode ser armazenado em uma EEPROM (electrically<br />
erasable programable read-only memory) permitindo que o FPGA se auto configure toda<br />
vez que o circuito é ligado.<br />
3.3.3 Linguagens de descrição de hardware e VHDL<br />
No início dos anos 80, o departamento de defesa americano (DoD) estava preocupado<br />
com a manutenção de seus equipamentos eletrônicos e em aumentar a produtividade dos<br />
projetistas, devido aos constantes avanços tecnológicos que ocorrem na área. Além disso,<br />
várias empresas forneciam equipamentos e desenvolviam projetos para governo.<br />
No programa VHSIC (very high speed integrated circuits) foi feito um esforço de padronização<br />
por uma linguagem que pudesse descrever a estrutura e funcionalidade dos<br />
circuitos integrados, que fosse de fácil entendimento por qualquer projetista e possibilitasse<br />
simulações dos circuitos nela descritos. Desse modo, projetos que utilizassem essa<br />
linguagem poderiam ser facilmente migrados de uma tecnologia para outra, acompanhando<br />
as evoluções do setor, e os projetos desenvolvidos para o DoD pelos diversos fornecedores<br />
seriam padronizados e sua manutenção facilitada.<br />
Esse esforço resultou na linguagem VHDL (VHSIC hardware description language) [42],<br />
que passou a ser um padrão aceito pelo IEEE [1]. Como todos os padrões do IEEE, a<br />
VHDL é revista a cada cinco anos, e em 1992, foi proposta uma versão revisada, adotada<br />
em 1993 com o nome de IEEE-1164.<br />
No início da década de 90, a VHDL foi usada primeiramente para projetos em ASIC<br />
e foram desenvolvidas ferramentas para automatizar o processo de criação e otimização<br />
das implementações. Na segunda metade da década, o uso de VHDL em síntese moveu-se<br />
para a área de dispositivos lógicos programáveis (CPLDs e FPGAs).<br />
VHDL possibilita descrições tanto em baixo nível (conexões entre componentes como<br />
portas E, OU, etc.) quanto em nível mais abstrato de comportamento. Assim, as construções<br />
em VHDL são divididas em três categorias, cada uma significando um nível diferente<br />
de abstração:<br />
41
• Comportamental: o circuito é definido na forma de um algoritmo, utilizando construções<br />
similares àquelas de linguagens de programação;<br />
• Fluxo de dados: tem-se a visão dos dados como um fluxo através do circuito, da<br />
entrada até a saída. Uma operação é definida em termos de uma coleção de dados,<br />
expressados como comandos concorrentes;<br />
• Estrutural: a visão mais próxima do hardware. Um modelo onde os componentes<br />
do circuito são instanciados e as ligações entre eles descritas.<br />
Contudo, a maioria das ferramentas de síntese ainda não aceita descrições puramente<br />
comportamentais, onde não se tem um relógio explícito, não se consegue inferir os registradores<br />
e o conjunto de comandos é seqüencial, quase como um programa em linguagem<br />
C. Assim, as descrições comportamentais, embora mais abstratas, devem levar em conta<br />
diversos aspectos de um projeto de hardware para poderem ser sintetizadas corretamente.<br />
A estrutura de um programa escrito em VHDL baseia-se em níveis hierárquicos. Resumidamente,<br />
podemos definir 4 desses níveis:<br />
• Pacotes: permite agregar em um projeto de vários componentes ou entidades previamente<br />
definidos. Pode ser visto como uma “biblioteca” de componentes dentro de<br />
um projeto. Aceita também definições de tipos e funções;<br />
• Entidades: uma entidade é qualquer componente VHDL que tenha um conjunto de<br />
portas de comunicação, com entradas e saídas. Uma entidade descreve um componente<br />
como uma “caixa-preta”, ou seja, apenas suas portas de entrada e saída são<br />
visíveis;<br />
• Arquitetura: é um conjunto de primitivas em VHDL que farão a efetiva descrição do<br />
hardware. É aqui que as abordagens comportamental, fluxo de dados ou estrutural<br />
são definidas;<br />
• Processos: é uma abstração de hardware que está sempre atuando. Um processo é<br />
basicamente o modelo de um componente físico, que possui uma lista de sinais dos<br />
quais depende (chamada de lista de sensitividade). Os processos podem ser síncronos<br />
ou assíncronos e diversos deles podem ser definidos dentro de um arquitetura. Os<br />
processos descritos em uma arquitetura são sempre concorrentes, mas o fluxo dentro<br />
de um processo é seqüencial.<br />
Outra característica importante da VHDL é que ela é uma linguagem fortemente tipada,<br />
aceitando poucas conversões entre os tipos de dados aceitos.<br />
Um programa escrito em VHDL possui o seguinte aspecto:<br />
42
-- Uso de bibliotecas. A terceira cláusula use faz refer^encia a um pacote<br />
-- chamado componentes<br />
library IEEE;<br />
use ieee.std_logic_1164.all;<br />
use ieee.std_logic_unsigned.all;<br />
use work.componentes.all;<br />
-- Definiç~ao da entidade<br />
entity MULT is<br />
generic (size : integer := 16);<br />
port (NUM1, NUM2 : in std_logic_vector(size-1 downto 0);<br />
CLK, RST : in std_logic;<br />
RES: out std_logic_vector(size*2-1 downto 0));<br />
End MULT;<br />
-- Definiç~ao da arquitetura<br />
architecture CALC of MULT is<br />
-- Definiç~ao de sinais internos<br />
signal X,X1 : std_logic_vector(size downto 0);<br />
begin<br />
-- Definiç~ao de um processo síncrono<br />
REG: process (CLK, RST)<br />
Begin<br />
if RST = ’1’ then<br />
ESTADO
• a descrição da especificação do circuito serve como documentação e explicita os<br />
objetivos do projeto;<br />
• o uso da síntese melhora a produtividade;<br />
• a padronização dessas linguagens resulta em portabilidade, tornando o código reutilizável<br />
em diferentes ambientes de desenvolvimento.<br />
Evidentemente, esse estilo de projeto não possui apenas vantagens. Alguns problemas<br />
permanecem ou são criados pela utilização dessas linguagens:<br />
• investimento inicial em educação e treinamento dos projetistas;<br />
• a síntese é limitada e muitos problemas devem ser particionados à mão (mas, nesse<br />
caso, seriam mais dificilmente resolvidos pelo projetista humano);<br />
• não é solução para todo tipo de projeto;<br />
• não atende a algumas restrições sérias, por exemplo, circuitos voltados ao baixo<br />
consumo, uso de pipeline, etc;<br />
• não existe (ainda) a síntese de circuitos analógicos e mistos.<br />
3.4 Somadores<br />
3.4.1 Meio-somador (half adder)<br />
Executa a soma entre dois bits, gerando uma saída S dada pela soma desses dois bits<br />
e uma saída V A que representa o “vai-um” dessa soma, segundo a tabela a seguir.<br />
Tabela 3.1: Tabela-verdade do meio-somador (half adder).<br />
A 0 B 0 V A0 S 0<br />
0 + 0 = 0 0<br />
0 + 1 = 0 1<br />
1 + 0 = 0 1<br />
1 + 1 = 1 0<br />
Da tabela 3.1, obtêm-se as seguintes equações que descrevem a relação entre as entradas<br />
e as saídas de um meio-somador:<br />
S 0 = A 0 ⊕ B 0 e (3.1)<br />
o que leva à implementação esquematizada na figura 3.6.<br />
V A0 = A 0 · B 0 , (3.2)<br />
44
Figura 3.6: Diagrama esquemático do meio-somador.<br />
3.4.2 Somador completo (full adder)<br />
Executa a soma entre três bits sendo um deles o “vem-um” recebido de um bit menos<br />
significativo. Gera uma saída S dada pela soma desses bits e uma saída V que representa<br />
o “vai-um” dessa soma.<br />
A seguir, é apresentada a tabela-verdade que descreve o somador completo. Desta<br />
tabela, são obtidas as equações 3.3 e 3.4 para as saídas do somador.<br />
Tabela 3.2: Tabela-verdade do somador completo (full adder).<br />
V E1 A 1 B 1 V A1 S 1<br />
0 + 0 + 0 = 0 0<br />
0 + 0 + 1 = 0 1<br />
0 + 1 + 0 = 0 1<br />
0 + 1 + 1 = 1 0<br />
1 + 0 + 0 = 0 1<br />
1 + 0 + 1 = 1 0<br />
1 + 1 + 0 = 1 0<br />
1 + 1 + 1 = 1 1<br />
S 1 = V E1 ⊕ (A 1 ⊕ B 1 ), (3.3)<br />
A equação 3.4 pode ainda ser reescrita como<br />
V A1 = A 1 · B 1 + V E1 · (A 1 + B 1 ). (3.4)<br />
o que conduz ao circuito esquematizado na figura 3.7.<br />
V A1 = A 1 · B 1 + V E1 · (A 1 ⊕ B 1 ), (3.5)<br />
3.4.3 Somador ripple carry<br />
Para somarmos números com dois ou mais bits podemos utilizar o somador completo<br />
obtido anteriormente e conectarmos os mesmos em cascata (um seguido do outro). Por<br />
45
Figura 3.7: Diagrama esquemático do somador completo.<br />
Figura 3.8: Diagrama de um somador ripple carry de 4 bits.<br />
exemplo, para somarmos dois números (A + B) de quatro bits, montamos a estrutura<br />
mostrada na figura 3.8.<br />
No primeiro somador (de ordem 0, bit menos significativo) temos que fazer V 0 = 0 pois<br />
não temos nenhum bit vindo de uma etapa anterior. Poderia também ter sido utilizado o<br />
meio-somador para essa primeira etapa, já que ele não possui essa entrada de “vem-um”.<br />
A saída “vai-um” de um somador de ordem n é conectada na entrada “vem-um” de<br />
um somador de ordem n+1. Daí a origem do nome ripple carry, o “vai-um” (carry) vai<br />
se propagando, a partir do primeiro somador (bit 0), até o último somador (bit mais<br />
significativo).<br />
Isso torna esse somador lento, já que o sinal V 4 (o “vai-um” do último somador) deve<br />
aguardar o sinal V 3 , que por sua vez tem que aguardar o sinal V 2 e assim por diante.<br />
Supondo que o atraso (tempo para que o sinal de saída se estabilize após uma variação<br />
no sinal de entrada) de cada etapa seja de t, o sinal V 4 só estará estável após um tempo<br />
de 4t. Para somadores de maior ordem (8, 16, 32 bits) esse atraso crescerá linearmente.<br />
3.4.4 Somador com “vai-um” antecipado (carry look ahead)<br />
Ao invés de esperar com que o sinal de “vai-um” (carry) se propague por todas as<br />
etapas até a última e dado que os bits dos dois números a serem somados já estão estáveis<br />
na entrada, pode-se estimar com antecedência o valor que a saída “vai-um” terá em cada<br />
etapa.<br />
Tomando por base a equação do sinal “vai-um” obtida no somador completo,<br />
podemos escrever: V i+1 = A i · B i + V i · (Ai ⊕ Bi) ⇒ V i+1 = G i + P i · V i , onde G i = A i · B i<br />
é designado generate carry e P i = (A i ⊕ B i ) é designado propagate carry. Assim, temos:<br />
46
⎧<br />
⎪⎨<br />
⎪⎩<br />
V 1 = G 0 + P 0 · V 0<br />
V 2 = G 1 + P 1 · V 1 = G 1 + P 1 · G 0 + P 1 · P 0 · V 0<br />
(3.6)<br />
V 3 = G 2 + P 2 · V 2 = G 2 + P 2 · G 1 + P 2 · P 1 · G 0 + P 2 · P 1 · P 0 · V 0<br />
V 4 = G 4 + P 3 · V 3 = G 3 + P 3 · G 2 + P 3 · P 2 · G 1 + P 3 · P 2 · P 1 · P 0 · V 0<br />
Os sinais S i ’s, por sua vez, podem ser obtidos a partir dos sinais P i ’s gerados:<br />
S i = V i ⊕ (A i ⊕ B i ) = V i ⊕ P i . (3.7)<br />
A figura 3.9 ilustra um somador de 4 bits com “vai-um” antecipado.<br />
Figura 3.9: Diagrama de um somador de 4 bits com “vai-um” antecipado.<br />
Note que o último sinal de “vai-um” (V 4 ) exigiria em seu cálculo um tempo dado pelo<br />
atraso da operação OU-Exclusivo (XOR) utilizada nos P i ’s (enquanto isso os Gi’s também<br />
estariam sendo calculados), mais o atraso da operação E (AND) entre os P i ’s calculados<br />
e finalmente o atraso da operação OU (OR). Esse tempo é praticamente igual ao tempo<br />
que o somador completo leva para gerar em sua saída os sinais de soma e “vai-um”. Dessa<br />
forma, o tempo de resposta desse somador é equivalente ao de apenas uma etapa do<br />
somador anterior (ripple carry).<br />
Note ainda que a adição de mais etapas não altera o tempo de resposta desse somador<br />
já que os sinais V i ’s levam o mesmo tempo para serem calculados.<br />
Entretanto, a adição de mais etapas torna a lógica combinacional desse somador extremamente<br />
complexa. Assim, os somadores que utilizam esse esquema fazem uso de<br />
“módulos” de 4 bits ligados em uma estrutura hierárquica. Cada módulo deve gerar os<br />
sinais G G e P G , generate group e propagate group, respectivamente. Esses dois sinais nada<br />
mais são do que o sinal V 4 desmembrado, sendo calculados como:<br />
G G = G 3 + P 3 · G 2 + P 3 · P 2 · G 1 + P 3 · P 2 · P 1 · G 0 , e (3.8)<br />
P G = P 3 · P 2 · P 1 · P 0 . (3.9)<br />
A seguinte figura ilustra o diagrama de blocos de um somador carry look ahead de 16<br />
bits:<br />
47
Figura 3.10: Diagrama de um somador de 16 bits com “vai-um” antecipado.<br />
A lógica combinacional utilizada nesse somador de 16 bits é a mesma utilizada em<br />
cada um dos somadores de 4 bits.<br />
3.4.5 Subtrator<br />
Para construirmos um subtrator podemos aproveitar uma das propriedades das portas<br />
XOR (OU-Exclusivo) de atuar como um inversor controlado e que uma subtração pode<br />
ser efetuada através de uma soma se o número a ser subtraído estiver representado em<br />
complemento de 2: A − B = A + (−B) = A + (B + 1) = A + B + 1.<br />
O circuito abaixo pode somar ou subtrair dois números de 4 bits de acordo com o sinal<br />
de controle C. Se C = 0, temos S = A + B e se C = 1, S = A − B (e despreza-se o<br />
“vai-um” final).<br />
Figura 3.11: Diagrama de um somador-subtrator de 4 bits.<br />
3.5 Matrizes esparsas<br />
Matrizes esparsas são aquelas que possuem uma grande quantidade de elementos iguais<br />
a zero. Esse tipo de matriz pode ser mais eficientemente armazenada se apenas os elementos<br />
diferentes de zero forem guardados.<br />
Existem diversos métodos para efetuar esse armazenamento [63][19]. Nesses esquemas,<br />
os elementos diferentes de zero são armazenados de forma contínua na memória e,<br />
48
dependendo do método adotado, também uma limitada quantidade de zeros. Isto, é claro,<br />
requer uma forma de saber como os elementos armazenados se encaixam na matriz completa.<br />
Essas diversas formas de armazenamento também permitem que operações sobre<br />
matrizes (soma, multiplicação) sejam efetuadas diretamente sobre a matriz reduzida, sem<br />
a necessidade de se restaurar a matriz completa.<br />
3.5.1 Compressed Row Storage (CRS)<br />
É o método mais geral de armazenamento junto com o CCS. Ele não efetua nenhuma<br />
suposição acerca da estrutura da matriz esparsa, mas também não armazena nenhum<br />
elemento desnecessário. Por outro lado, não é muito eficiente, precisando de passos adicionais<br />
(endereçamento indireto) quando se efetuam operações (multiplicação de matrizes,<br />
por exemplo) sobre a forma reduzida obtida.<br />
Dada uma matriz A i,j esparsa e assimétrica, definimos nnz como a quantidade de<br />
elementos diferentes de zero em A. Nesse método, são criados 3 vetores: val, col ind<br />
e lin ptr. O vetor val, com comprimento igual a nnz, contém os elementos diferentes<br />
de zero da matriz A, na seqüência em que aparecem em cada linha, linha por linha. O<br />
vetor col ind guarda um índice da coluna na qual se encontra cada elemento armazenado<br />
em val (se val(k) = A i,j , então col ind(k) = j). Dessa forma, col ind possui o mesmo<br />
comprimento que val. Finalmente, o vetor lin ptr armazena a posição dos elementos em<br />
val que iniciam uma nova linha e possui um comprimento igual ao número de linhas da<br />
matriz mais 1.<br />
A economia de espaço obtida por esse esquema é razoável se houver uma grande<br />
quantidade de zeros na matriz esparsa. Supondo uma matriz quadrada, ou seja, i = j = n,<br />
ao invés de serem armazenados n 2 elementos, são necessários 2nnz + n + 1 elementos.<br />
Como um exemplo, considere-se a matriz 5x5 dada por:<br />
nesse caso, tem-se:<br />
⎛<br />
A =<br />
⎜<br />
⎝<br />
10 0 0 −2 0<br />
3 9 0 0 3<br />
0 7 8 0 0<br />
4 0 0 8 0<br />
0 4 0 2 1<br />
⎞<br />
; (3.10)<br />
⎟<br />
⎠<br />
val = [ 10 −2 3 9 3 7 8 4 8 4 2 1 ] , (3.11)<br />
col ind = [ 1 4 1 2 5 2 3 1 4 2 4 5 ] e (3.12)<br />
lin ptr = [ 1 3 6 8 10 13 ] . (3.13)<br />
49
3.5.2 Compressed Column Storage (CCS)<br />
Esse método é idêntico ao CRS, exceto que as colunas de A são armazenadas ao invés<br />
das linhas. Em outras palavras, o formato CCS é igual ao CRS aplicado em A t .<br />
Similarmente ao CRS, são criados 3 vetores: val, lin ind e col ptr, onde val armazena<br />
os elementos diferentes de zero de A, lin ind é um índice das linhas na qual se encontram<br />
os valores guardados em val e col ptr indica qual elemento de val inicia uma nova coluna.<br />
Para a mesma matriz A exemplificada na descrição do método CRS, obtemos:<br />
val = [ 10 3 4 9 7 4 8 −2 8 2 3 1 ] , (3.14)<br />
lin ind = [ 1 2 4 2 3 5 3 1 4 5 2 5 ] e (3.15)<br />
col ptr = [ 1 4 7 8 11 13 ] . (3.16)<br />
3.5.3 Compressed Diagonal Storage (CDS)<br />
Se a matriz esparsa concentrar os valores diferentes de zero em uma faixa em torno de<br />
sua diagonal principal, então é mais interessante aproveitar essa estrutura no esquema de<br />
armazenagem.<br />
No CDS, as subdiagonais da matriz esparsa são armazenadas em posições consecutivas<br />
de memória, não sendo necessários os vetores de identificação de linha e coluna. A matriz<br />
reduzida obtida é também mais eficiente nas operações de multiplicação.<br />
Entretanto, nesse esquema podem ser armazenados alguns elementos iguais a zero da<br />
matriz original. Além disso, o formato CDS irá introduzir alguns zeros na matriz reduzida<br />
que nem fazem parte da matriz esparsa, mas necessários para identificar a posição original<br />
dos elementos armazenados.<br />
Aplicando o CDS na matriz assimétrica e esparsa dada por<br />
obtemos:<br />
⎛<br />
A =<br />
⎜<br />
⎝<br />
10 −3 0 0 0<br />
3 8 2 0 0<br />
0 4 9 7 0<br />
0 0 0 6 1<br />
0 0 0 5 2<br />
⎞<br />
, (3.17)<br />
⎟<br />
⎠<br />
val(−1) = [ 0 3 4 0 5 ] , (3.18)<br />
val(0) = [ 10 8 9 6 2 ] e (3.19)<br />
50
3.5.4 Jagged Diagonal Storage (JDS)<br />
val(1) = [ −3 2 7 1 0 ] . (3.20)<br />
Esse formato é bastante útil na implementação de métodos iterativos em processadores<br />
paralelos ou vetoriais. Similarmente ao CDS, os vetores obtidos possuem o mesmo comprimento<br />
da matriz esparsa. Se os valores diferentes de zero não estiverem bem concentrados<br />
em torno da diagonal principal, o JDS é mais espaço-eficiente do que o CDS.<br />
Para se obter a matriz reduzida, na forma simplificada do JDS, os elementos diferentes<br />
de zero são deslocados para a esquerda e depois as colunas são armazenadas de forma<br />
consecutiva na memória. Como as colunas podem não ter o mesmo tamanho, alguns zeros<br />
são inseridos para que todos os vetores resultantes possuam o mesmo comprimento. Após<br />
essas transformações na matriz original, são obtidos os vetores contendo os elementos<br />
diferentes de zero e os zeros inseridos (val) e os índices das colunas na qual os elementos<br />
pertenciam antes da transformação (col ind).<br />
Como um exemplo, temos:<br />
⎛<br />
A =<br />
⎜<br />
⎝<br />
10 0 −3 0 0<br />
3 0 8 2 0<br />
1 4 9 7 0<br />
0 0 0 6 1<br />
0 0 5 0 2<br />
⎞<br />
⎛<br />
→<br />
⎟ ⎜<br />
⎠ ⎝<br />
10 −3<br />
3 8 2<br />
1 4 9 7<br />
6 1<br />
5 2<br />
⎞<br />
⎛<br />
→<br />
⎟ ⎜<br />
⎠ ⎝<br />
10 −3 0 0<br />
3 8 2 0<br />
1 4 9 7<br />
6 1 0 0<br />
5 2 0 0<br />
⎞<br />
, (3.21)<br />
⎟<br />
⎠<br />
sendo obtidos:<br />
⎧<br />
⎪⎨<br />
⎪⎩<br />
⎧<br />
⎪⎨<br />
⎪⎩<br />
val(1) = [ 10 3 1 6 5 ]<br />
val(2) = [ −3 8 4 1 2 ]<br />
val(3) = [ 0 2 9 0 0 ] e (3.22)<br />
val(4) = [ 0 0 7 0 0 ]<br />
col ind(1) = [ 1 1 1 4 3 ]<br />
col ind(2) = [ 3 3 2 5 5 ]<br />
col ind(3) = [ 0 4 3 0 0 ] . (3.23)<br />
col ind(4) = [ 0 0 5 0 0 ]<br />
Fica claro que esse método não é muito eficiente se a quantidade de zeros não for<br />
grande ou se as linhas da matriz esparsa não possuírem praticamente a mesma quantidade<br />
de elementos diferentes de zero.<br />
51
Capítulo 4<br />
DESCRIÇÃO DA IMPL<strong>EM</strong>ENTAÇÃO<br />
4.1 Aplicação de Estruturas Paralelas na comparação<br />
de seqüências<br />
Para a comparação de seqüências baseadas no algoritmo de Needleman e Wunsch,<br />
as soluções computacionais seqüenciais não oferecem um bom desempenho, mesmo com<br />
processadores mais velozes, pois este algoritmo tem complexidade de tempo quadrática,<br />
conforme visto no capítulo 2. Portanto, a computação paralela tem sido empregada na<br />
tentativa de reduzir o tempo de execução desses algoritmos.<br />
Com n processadores paralelos, é possível aumentar a velocidade de processamento<br />
por um fator n, desde que o algoritmo estritamente seqüencial usado possa ser reescrito<br />
por operações paralelas simultâneas. Como a comparação de seqüências é baseada em<br />
computações análogas para cada posição de um vetor linear, pode-se conjecturar que<br />
algoritmos paralelos mais eficientes possam ser elaborados para problemas de comparação<br />
de seqüências.<br />
Existem basicamente duas formas de aplicar paralelismo ao problema de comparação<br />
de seqüências [34]:<br />
• Paralelizando a operação de comparação: neste caso, todos os processadores cooperam<br />
para determinar o escore de cada célula da matriz de similaridades. Como a<br />
granularidade é mais fina, o número de comunicações é maior;<br />
• Paralelizando o processo de comparação: neste caso, cada processador realiza um<br />
número de comparações de forma independente, ou seja, calcula o escore das células<br />
de porções menores das seqüências comparadas. Como a granularidade é mais grossa,<br />
as demandas de comunicação são reduzidas. No entanto, o desempenho dependerá<br />
de quão balanceada estiver a distribuição da carga de trabalho.<br />
O segundo método é o método mais utilizado, porém o primeiro método é mais apropriado<br />
para computadores SIMD onde todos os processadores executam a mesma instrução<br />
ao mesmo tempo, e a velocidade de comunicação é rápida quando comparada à de processamento.<br />
Sistemas SIMD geralmente possuem centenas de processadores lentos, mas<br />
52
com baixo custo de comunicação. Essa é um tipo de arquitetura na qual as estruturas<br />
sistólicas se encaixam totalmente.<br />
O segundo método é mais adequado para MIMD, onde cada processador é significativamente<br />
mais poderoso que um processador SIMD, e os processadores executam suas<br />
instruções de forma independente, em vez de cooperarem para comparar cada seqüência<br />
do banco de dados.<br />
4.2 Dependência de Dados<br />
Pela relação de recorrência do algoritmo de Smith-Waterman com penalidade constante<br />
para os espaços (equação 2.4), pode-se observar que podemos computar s i,j se s i,j−1 ,<br />
s i−1,j−1 e s i−1,j tiverem sido computados. Assim, o cálculo do valor de cada célula da<br />
matriz de similaridades depende apenas da célula da linha e coluna anteriores (mesma<br />
diagonal), da célula da mesma linha e coluna anterior (célula à esquerda) e da célula da<br />
linha anterior e mesma coluna (célula acima).<br />
Uma forma de paralelizar o cálculo da matriz respeitando-se essas dependências de<br />
dados é calcular antidiagonal por antidiagonal, uma vez que elementos em uma antidiagonal<br />
só dependem das antidiagonais previamente calculadas. A esse tipo de computação<br />
paralela dá-se o nome de computação em onda [69] (figura 4.1).<br />
Figura 4.1: Paralelização do cálculo da matriz de similaridade.<br />
4.3 Plataforma Utilizada<br />
Para o desenvolvimento do projeto foi utilizada a placa APEX PCI Development Board<br />
do fabricante Altera, contendo o FPGA APEX EP20K400EFC672. Essa placa está instalada<br />
em um computador da Dell com processador Pentium IV. A ferramenta de síntese<br />
adotada foi o Quartus II da própria Altera.<br />
4.4 Descrição Geral<br />
A implementação realizada neste trabalho foi baseada no algoritmo de comparação local<br />
de duas seqüências proposto por Smith-Waterman, utilizando a equação de recorrência<br />
com penalidade constante para os espaços (equação 2.4), conforme descrito no capítulo 2.<br />
53
Seja comparar e obter os melhores alinhamentos de duas seqüências: a seqüência de<br />
consulta sendo CATAAGGCT e a seqüência do banco de dados sendo ACATAGGCAT.<br />
Aplicando a equação de recorrência do algoritmo de Smith-Waterman (equação 2.4) a<br />
essas seqüências, obtém-se a seguinte matriz de similaridade (figura 4.2), com a origem de<br />
cada valor indicada por uma seta. Essas setas também indicam o caminho a ser percorrido<br />
para se obter os alinhamentos. Os valores assinalados com um círculo serão posteriormente<br />
explicados.<br />
Figura 4.2: Matriz de similaridade para as seqüências ACATAGGCAT e CATAAGGCT.<br />
4.4.1 Estrutura sistólica<br />
Nas diversas implementações analisadas na revisão bibliográfica do capítulo 1, ficou<br />
claro que a melhor abordagem para paralelizar em hardware o problema da comparação<br />
de seqüências utilizando programação dinâmica era a utilização de estruturas sistólicas.<br />
A utilização de um vetor sistólico permite dois tipos de mapemanto do problema: a<br />
emulação das diagonais e a emulação das colunas (figura 4.3). No primeiro tipo, cada<br />
célula do vetor é responsável pelo cálculo de uma das diagonais da matriz. Para duas<br />
seqüências com comprimentos n e m, a matriz de similaridade irá possuir n + m − 1<br />
diagonais. Dessa forma, essa é a quantidade de células necessárias para o vetor sistólico<br />
com essa abordagem. Além disso, o vetor deve ser bidirecional e as seqüências a serem<br />
comparadas devem ser deslocadas a partir de extremidades opostas em direção ao centro<br />
do vetor.<br />
Para o segundo tipo, cada célula do vetor é responsável pelo cálculo de uma coluna<br />
da matriz de similaridade. Nesse mapeamento, o vetor pode ter o comprimento da menor<br />
54
Figura 4.3: Tipos de emulação da matriz de similaridade.<br />
das seqüências e seu sentido é unidirecional.<br />
Pelos motivos expostos, a estratégia adotada foi a construção de uma estrutura<br />
sistólica linear unidirecional. Nessa abordagem, de acordo com o exposto, cada elemento<br />
de processamento do vetor sistólico é responsável pelo cálculo de uma das colunas<br />
da matriz de similaridade. A principal razão para a escolha feita é que o tamanho da<br />
estrutura (quantidade de elemento de processamento) depende apenas da seqüência de<br />
consulta, não dependendo da seqüência do banco de dados, podendo essa ter qualquer<br />
tamanho (na verdade, a memória do sistema é que irá limitar o tamanho da seqüência do<br />
banco de dados).<br />
Conforme já discutido no capítulo 1, o paralelismo obtido com a utilização de uma<br />
estrutura linear sistólica reduz a complexidade de tempo do algoritmo de Smith-Waterman<br />
de O(n × m) para O(n + m), ou seja, transforma-se um tempo quadrático em linear.<br />
Para implementar o vetor sistólico, a cada base da seqüência de consulta deve corresponder<br />
um elemento de processamento. Com isso, a seqüência de consulta pode ficar<br />
armazenada dentro do vetor. Já a seqüência proveniente do banco de dados é deslocada,<br />
da esquerda para a direita, para dentro da estrutura sistólica de forma a atravessá-la. A<br />
cada ciclo de relógio, as bases da seqüência do banco de dados deslocam uma posição e o<br />
cálculo de uma antidiagonal da matriz de similaridade é efetuado segundo o esquema da<br />
figura 4.4.<br />
Para o exemplo anterior, cuja seqüência de consulta é CATAAGGCT e a seqüência do<br />
banco de dados é ACATAGGCAT, a estrutura sistólica resultante seria:<br />
Note que a seqüência proveniente do banco de dados entra no vetor sistólico de maneira<br />
invertida, de modo que o primeiro elemento dessa seqüência possa ser comparado com o<br />
primeiro elemento da seqüência de consulta.<br />
Elemento de processamento do vetor sistólico<br />
Uma estrutura sistólica é composta por inúmeras instâncias de uma unidade menor<br />
55
Figura 4.4: Estrutura linear sistólica uniderecional.<br />
conhecida como elemento de processamento. Essas unidades são responsáveis por todo<br />
o processamento efetuado dentro do sistema sistólico. Assim, o correto planejamento<br />
dessas unidades é de vital importância para que a estrutura sistólica obtida possa ter o<br />
desempenho e a simplicidade esperada.<br />
Critérios utilizados<br />
Para o projeto dos elementos de processamento (células) da estrutura sistólica foram<br />
inicialmente estabelecidos os seguintes critérios que eles deveriam atender:<br />
i. conseguirem aplicar a equação de recorrência (equação 2.4) do algoritmo de Smith-<br />
Waterman;<br />
ii. serem o mais simples possível para que utilizem poucos recursos da FPGA e, com<br />
isso, caibam uma quantidade maior de células dentro do dispositivo. Assim, se<br />
houver duas ou mais possibilidades de implementar um mesmo circuito, o mais<br />
simples será o escolhido em relação ao mais rápido, desde que o impacto não seja<br />
grande na performance;<br />
iii. possuírem uma memória local para armazenar temporariamente os cálculos efetuados.<br />
Mais tarde, verificou-se que somente esses critérios não eram suficientes e um acréscimo<br />
foi feito a essa lista:<br />
i. conseguirem aplicar as estratégias para minimizar a utilização da memória interna<br />
(essas estratégias serão analisadas posteriormente);<br />
ii. prover mecanismos de entrega dos dados calculados e armazenados para uma memória<br />
externa.<br />
56
Foi feita uma descrição inicial em VHDL do elemento de processamento baseada nos<br />
critérios iniciais (i, ii e iii) com enfoque principal no critério ii. Posteriormente, adequou-se<br />
o elemento de processamento para que os critérios iv e v também pudessem ser atendidos.<br />
Estrutura interna<br />
De acordo com a equação 2.4, o cálculo do valor de cada célula da matriz de similaridades<br />
depende apenas da célula da linha e coluna anteriores (mesma diagonal), da célula<br />
da mesma linha e coluna anterior (célula à esquerda) e da célula da linha anterior e mesma<br />
coluna (célula acima). Dessa forma, para que essa equação possa ser aplicada dentro do<br />
elemento de processamento, esses três valores devem estar presentes dentro da célula no<br />
instante do cálculo.<br />
Foi notado que o elemento de processamento necessitava armazenar apenas o valor da<br />
diagonal e da linha superior. O valor da coluna à esquerda viria da célula adjacente como<br />
resultado do cálculo feito no ciclo de relógio anterior. A estrutura inicial do elemento de<br />
processamento pode ser vista na figura 4.5.<br />
Figura 4.5: Estrutura interna inicial do elemento de processamento.<br />
A seqüência de consulta está armazenada no vetor sistólico, com cada célula desse vetor<br />
correspondendo a uma base dessa seqüência (B C ). Em um dado momento, após um ciclo<br />
de relógio, uma nova base da seqüência do banco de dados (B BD ) entra no elemento de<br />
processamento, proveniente da célula adjacente à esquerda. Essa célula também fornece<br />
o valor da coluna à esquerda (c). Nesse mesmo instante, os valores da diagonal (a) e da<br />
linha superior (b) também estão armazenados no elemento de processamento, após terem<br />
sido gerados internamente e guardados no mesmo pulso de relógio que deslocou a base da<br />
seqüência do banco de dados para dentro da célula.<br />
Com isso, o elemento de processamento possui em seu interior todos os requisitos para<br />
aplicar a equação de recorrência do algoritmo. O novo valor calculado (d) da matriz de<br />
similaridade é fornecido para uma memória externa e ao mesmo tempo serve como base<br />
para um novo cálculo que será feito por sua célula vizinha à direita.<br />
Fluxo dos dados em seu interior<br />
57
A dinâmica de como esses dados são gerados pode ser melhor visualizada com o auxílio<br />
da figura 4.6. Para simplificar a análise, o valor fornecido pela célula adjacente à esquerda<br />
foi colocado dentro do elemento de processamento, ao lado da base da seqüência do banco<br />
de dados (G2).<br />
Figura 4.6: Fluxo interno dos dados dentro do elemento de processamento.<br />
No instante t, conforme descrito anteriormente, a célula de processamento possui todos<br />
os elementos necessários para o cálculo de um novo valor da matriz de similaridade (esse<br />
valor é calculado por intermédio de uma lógica combinacional a ser explicada). Após o<br />
pulso de relógio, instante t + 1, o dado recebido da célula adjacente à esquerda (2) passa<br />
a ser o novo valor diagonal do elemento de processamento. O valor calculado dentro do<br />
elemento de processamento (0) passa a ser o novo valor da linha superior e também segue<br />
junto com a base da seqüência do banco de dados (G) para a célula da direita. Ainda nesse<br />
instante, a base da seqüência do banco de dados que estava na célula adjacente à esquerda<br />
(A) é deslocada para o interior do elemento de processamento em questão, juntamente<br />
com o valor calculado nessa célula (1), que será o novo valor da coluna à direita.<br />
A figura 4.7 (baseada no trecho final da matriz de similaridade da figura 4.2) ilustra<br />
essa dinâmica para várias células de processamento, mostrando o fluxo dos dados dentro<br />
do vetor sistólico.<br />
Figura 4.7: Dinâmica do sistema para vários elementos de processamento.<br />
Note que a saída da última célula do vetor sistólico não é utilizada por nenhuma outra<br />
célula. Entretanto, essa saída contém uma base da seqüência do banco de dados e o último<br />
valor calculado para a linha dessa base. Assim, para o exemplo em questão, teríamos o<br />
seguinte resultado a cada pulso de relógio: C3, A4 e T4. Veremos posteriormente que essas<br />
saídas irão permitir ligar duas implementações em cascata (a saída de uma alimentando a<br />
entrada da outra) permitindo que seqüências de consulta maiores possam ser utilizadas.<br />
58
Lógica combinacional<br />
Para a lógica combinacional que calcula o novo valor da matriz de similaridade dentro<br />
do elemento de processamento, várias abordagens foram testadas para que ela ficasse o<br />
menor e mais simples possível.<br />
Na aplicação da equação de recorrência (equação 2.4), valores fixos (1, −1 e −2) são<br />
somados aos valores armazenados na célula. Como essas operações devem ser efetuadas<br />
em paralelo, mais de um somador é necessário, não sendo possível o reaproveitamento de<br />
um único somador.<br />
Além disso, os resultados parciais obtidos devem ser comparados para a obtenção de<br />
um novo valor para a matriz de similaridade. Assim, as principais operações feitas na<br />
aplicação da equação de recorrência são somas e comparações, devendo essas operações<br />
serem tratadas de forma mais minuciosa.<br />
Somadores e comparadores<br />
Um somador que “incorporasse” a constante a ser utilizada seria mais simples que<br />
um somador genérico. A desvantagem dessa estratégia é que o circuito gerado, embora<br />
mais simples, ficaria restrito. Para um outro esquema de pontuação para a equação de<br />
recorrência, uma nova descrição do somador teria que ser feita.<br />
Das abordagens clássicas de somadores vistas no capítulo 3, o somador carry look ahead<br />
foi descartado devido à sua complexidade combinacional. Assim, preferiu-se optar pelo<br />
somador ripple carry já que a quantidade de bits a serem somados não seria grande e,<br />
principalmente, pelo critério ii . O primeiro teste, somador com a constante embutida,<br />
foi feito utilizando a constante −2 em sua notação em complemento de 2 com 8 bits:<br />
111111110 (na ordem B 7 B 6 B 5 . . . B 0 ). Para o bit 0 do somador de 8 bits, pode ser utilizado<br />
o meio somador pois não temos o sinal de “vem-um”. Pela tabela-verdade do meio somador<br />
analisada no capítulo 3 (com o bit A n dessa tabela vindo do valor armazenado na célula<br />
de processamento e o bit B 0 da constante −2), sendo o bit B 0 sempre igual a zero, uma<br />
rápida observação nos leva ao seguinte resultado: S 0 = A 0 e V A0 = 0.<br />
Como V A0 = 0, a tabela-verdade do meio somador pode ser novamente utilizada para<br />
o segundo bit desse somador. Sendo o valor de B 1 = 1, temos a seguinte simplificação:<br />
S 1 = Ā1 e V A1 = A 1 .<br />
Para os demais bits do somador (S 2 a S 7 ), teremos o valor de B N sempre igual a 1.<br />
Assim, simplificando a tabela-verdade do somador completo para essa situação, obtemos:<br />
S N = ĀN · ¯V EN + A N · V EN (não-ou-exclusivo) e V AN = A N + V EN , com N variando de 2<br />
a 7.<br />
O circuito final do somador de 8 bits com a constante −2 embutida no mesmo pode ser<br />
visto na figura 4.8. Esse circuito é bem mais simples que o demonstrado no capítulo 3. O<br />
59
último sinal de “vai-um” foi mantido para indicar se o resultado da operação foi positivo<br />
ou negativo.<br />
Figura 4.8: Somador de 8 bits com a constante -2 embutida no mesmo.<br />
Para a implementação desse somador de 8 bits em VHDL foi utilizada uma descrição<br />
estrutural. Entretanto, após descrito o elemento de processamento utilizando essa simplificação<br />
e comparando com o resultado de uma descrição em um nível mais alto (simplesmente<br />
A − 2, sendo A um vetor lógico de 8 bits), verificou-se que não houve ganho<br />
algum. A quantidade de elementos lógicos utilizados da FPGA foi a mesma para as duas<br />
abordagens, como também o atraso necessário para efetuar essa operação.<br />
Testes com as constantes +1 e −1 levaram ao mesmo resultado, ou seja, sem diferença<br />
nos recursos utilizados na FPGA.<br />
Como a ferramenta de síntese também faz uma análise lógica do sistema que está sendo<br />
descrito, a explicação para tal fato é que a ferramenta efetuou as mesmas simplificações<br />
feitas manualmente no circuito.<br />
Com os comparadores, os testes feitos também tiveram o mesmo resultado. Os projetos<br />
em nível de portas lógicas resultaram na mesma utilização de recursos que circuitos<br />
descritos em níveis mais abstratos (A = B ou A > B). Dessa forma, optou-se por fazer<br />
as implementações dos somadores e comparadores em um nível mais alto, deixando a descrição<br />
em VHDL mais genérica e permitindo que outros esquemas de pontuação possam<br />
vir a ser implementados com a simples substituição das constantes utilizadas.<br />
Além da necessidade de se otimizar o circuito dos somadores e comparadores, era<br />
também preciso otimizar a quantidade utilizada desses elementos dentro da célula de<br />
processamento. O resultado dos testes anteriores mostrou também que os comparadores<br />
são menos onerosos (menor quantidade de recursos utilizados) que os somadores. Assim,<br />
quando possível, foi dada preferência para a utilização de um comparador no lugar de um<br />
somador.<br />
No cálculo de um novo valor da matriz de similaridade, o valor da diagonal é somado<br />
com 1 ou −1 se as bases comparadas das duas seqüências forem iguais ou diferentes,<br />
respectivamente. Essas operações podem ser implementadas de duas formas, de acordo<br />
com a figura 4.9.<br />
A implementação 1 utiliza dois somadores, um comparador e um multiplexador, en-<br />
60
Figura 4.9: Cálculo do valor da diagonal.<br />
quanto que a implementação 2 utiliza um somador, um comparador e um multiplexador.<br />
Independente da quantidade de recursos internos da FPGA requerida pelo somador e<br />
comparador, a implementação 2 é mais otimizada que a 1. Entretanto, a implementação<br />
1 é um pouco mais rápida que a 2, pois no circuito 1 as somas e a comparação estão<br />
sendo feitas simultaneamente, enquanto que na implementação 2 o multiplexador tem que<br />
aguardar o resultado da comparação antes de definir qual será o valor fornecido ao somador.<br />
Como a diferença de performance é baixa e o principal critério é o da economia, o<br />
circuito 2 foi o escolhido. A esse resultado parcial, foi dado um nome interno de RES1.<br />
Já os valores da coluna anterior e da linha superior são somados com -2 e esses dois<br />
resultados, juntamente com o resultado anterior (RES1) e o 0 são comparados para definir<br />
o novo valor da matriz de similaridade. Ao invés de comparar esses quatro valores simultaneamente<br />
para selecionar o maior de todos, podemos comparar os resultados parciais<br />
dois a dois e com uma nova comparação definir o resultado final.<br />
Uma dessas comparações parciais pode ser obtida de acordo com uma das implementações<br />
mostrada na figura 4.10. A esse novo resultado parcial foi dado o nome de<br />
RES2.<br />
Figura 4.10: Cálculo do valor relativo à inserção do espaço.<br />
Novamente, a implementação 2 se mostrou mais eficiente no aspecto de utilizar recursos<br />
da FPGA, embora a 1 seja um pouco mais rápida. Como as operações RES1 e RES2 são<br />
feitas em paralelo, os atrasos das duas implementações não são somados. Além disso, a<br />
lógica combinacional de uma célula não precisa aguardar o resultado da célula anterior<br />
para efetuar o seu processamento. A cada ciclo de relógio todos os valores necessários para<br />
a aplicação da equação de recorrência estão contidos na célula. Desse modo, as operações<br />
61
RES1 e RES2 além de serem feitas em paralelo dentro de uma mesma célula, são feitas em<br />
paralelo por todas as células. Pelo exposto, a escolha das implementações mais simples<br />
para esses cálculos parciais não irá acarretar em uma perda notável na velocidade de<br />
processamento da estrutura sistólica proposta.<br />
Finalmente, para se gerar o resultado final da equação, basta comparar RES1, RES2<br />
e 0, selecionando o maior dos três valores. Isso pode ser feito com um comparador e um<br />
multiplexador. Entretanto, objetivando otimizar a saída de dados para a memória, uma<br />
outra abordagem foi escolhida.<br />
Após toda essa análise, percebe-se que o elemento de processamento é essencialmente<br />
combinacional. Os flip-flops utilizados (onde são armazenados os valores na célula de<br />
processamento) servem apenas como uma barreira temporal para que as operações possam<br />
ser efetuadas sem interferência. Assim, não foi necessário descrever uma máquina de<br />
estados [28] para controlar o fluxo do processamento, tornando a estrutura sistólica ainda<br />
mais simples.<br />
Saída para a memória externa<br />
Conforme os valores da matriz de similaridade vão sendo calculados, nas regiões onde<br />
as duas seqüências são similares, esses valores vão aumentando gradativamente. Se as<br />
duas seqüências forem praticamente iguais e com a pontuação utilizada na equação 2.4, o<br />
valor final da matriz de similaridade será bem próximo do comprimento dessas seqüências.<br />
Como as seqüências são grandes, a quantidade de bits necessária para representar esses<br />
valores também será grande. Para seqüências relativamente pequenas, com 1.000 bases,<br />
já seriam necessários 10 bits para essa representação.<br />
Com a matriz de similaridade montada, ainda é necessário efetuar um percorrimento<br />
reverso (backtracking) para se obter os alinhamentos. Nesse percorrimento, é preciso<br />
descobrir quais dos três valores adjacentes originou o dado corrente. Conforme visto no<br />
capítulo 2, a origem de cada valor da matriz pode ser identificada por um vetor, permitindo<br />
que o percorrimento reverso possa ser feito baseado nesses vetores (ou ponteiros).<br />
Como os vetores podem ser representados em um comprimento fixo, optou-se por<br />
armazená-los na memória externa ao invés dos valores calculados para a matriz, que iriam<br />
exigir uma grande quantidade de bits e que dependeriam do comprimento das seqüências<br />
comparadas. Além disso, o armazenamento do vetor acelera o processo do percorrimento<br />
reverso.<br />
A princípio, dois bits poderiam representar os três vetores possíveis. No entanto, um<br />
valor gerado na matriz de similaridade pode ter mais de uma origem. Para esgotar todas<br />
as possibilidades, a representação desses vetores deve utilizar três bits. A figura 4.11<br />
mostra como pode ser feita essa codificação.<br />
Cada bit da representação indica um sentido. Assim, um valor da matriz cuja origem<br />
62
Figura 4.11: Codificação dos vetores da matriz de similaridade.<br />
foi o elemento da diagonal, seria representado por 010, ou seja, apenas com o bit V2<br />
setado. Um valor cuja origem foi a diagonal e a linha superior seria representado por 011.<br />
Para um vetor nulo, que indicaria o final de uma seqüência, todos os bits estariam em 0.<br />
O início de um alinhamento se dá quando o valor calculado para a matriz de similaridade<br />
ultrapassa um certo limite considerado como ótimo. Como o valor calculado não está<br />
sendo mais fornecido externamente, era necessário indicar quando esse limite havia sido<br />
alcançado e/ou ultrapassado. Assim, foi adicionado um bit na estrutura de representação<br />
do vetor para essa indicação. O valor limite utilizado para indicar se um alinhamento deve<br />
ser recuperado é passado ao vetor sistólico como um parâmetro na compilação do código.<br />
Com base nessa representação, o dado gerado para a memória externa possuía inicialmente<br />
4 bits, independente do tamanho das seqüências comparadas. Posteriormente, esse<br />
tamanho teve que ser aumentado para que algumas otimizações pudessem ser efetuadas.<br />
Geração dos vetores<br />
Para saber a origem de um novo valor calculado para a matriz de similaridade era<br />
preciso efetuar alguns testes com os resultados parciais obtidos anteriormente. Até esse<br />
ponto, dois resultados parciais estavam disponíveis, RES1, originado pela aplicação da<br />
equação de recorrência ao elemento da diagonal, e RES2, originado pela aplicação da<br />
equação de recorrência ao maior valor dentre os valores da coluna à esquerda e da linha<br />
superior.<br />
Para que os bits V3, V2 e V1, representando uma seta à esquerda, uma seta diagonal<br />
e uma seta para cima, respectivamente, indicassem corretamente a origem do valor calculado,<br />
levando-se em conta que ela pode não ser única, as seguintes funções lógicas foram<br />
estabelecidas:<br />
- V1: se os resultados RES1 e RES2 forem positivos e RES1 for menor ou igual a<br />
RES2 e o valor da linha superior for maior ou igual ao da coluna à esquerda ou se<br />
RES1 for negativo e RES2 positivo e o valor da linha superior for maior ou igual ao<br />
da coluna à esquerda;<br />
- V2: se os resultados RES1 e RES2 forem positivos e RES1 for maior ou igual a<br />
RES2 ou se o resultado RES1 for positivo e RES2 negativo;<br />
- V1: se os resultados RES1 e RES2 forem positivos e RES1 for menor ou igual a<br />
RES2 e o valor da linha superior for menor ou igual ao da coluna à esquerda ou se<br />
63
RES1 for negativo e RES2 positivo e o valor da linha superior for menor ou igual ao<br />
da coluna à esquerda.<br />
Com RES1 e RES2 negativos, os bits V1, V2 e V3 serão iguais a zero, indicando um<br />
vetor nulo. Para que essas funções lógicas pudessem ser mapeadas, vários sinais lógicos<br />
(flags) tiveram que ser definidos dentro do elemento de processamento:<br />
- SIN0: ativo em 1 quando o resultado parcial RES1 é maior ou igual a zero;<br />
- SIN1: ativo em 1 quando o resultado parcial RES2 é maior ou igual a zero;<br />
- FLGD: ativo em 1 quando RES1 é maior que RES2;<br />
- FLGH: ativo em 1 quando o valor da coluna à esquerda é maior que o da linha<br />
superior;<br />
- FLGI1: ativo em 1 quando o valor da coluna à esquerda é igual ao da linha superior;<br />
- FLGI2: ativo em 1 quando os resultados parciais RES1 e RES2 são iguais.<br />
Além disso, para cada um desses sinais, também foi definido o seu complementar:<br />
NSIN0, NSIN1, NFLGD, NFLGH, NFLGI1 e NFLGI2. Alguns testes mostraram que<br />
definir um sinal complementar consumia menos recursos do que ficar negando (invertendo)<br />
o sinal original.<br />
Com a definição desses sinais, as funções lógicas dos bits V1, V2 e V3 foram mapeadas<br />
da seguinte forma:<br />
- V1: SIN0·SIN1·NFLGD·NFLGH + NSIN0·SIN1· NFLGH;<br />
- V2: SIN0 ·SIN1·FLGD + SIN0·SIN1·FLGI2 + SIN0 · NSIN1;<br />
- V3: SIN0·SIN1·NFLGD·FLGH + SIN0·SIN1· NFLGD·FLGI1 + NSIN0·SIN1· FLGH<br />
+ NSIN0 ·SIN1·FLGI1.<br />
Na definição dessas funções lógicas tomou-se o cuidado de não utilizar os sinais FLGD e<br />
NFLGD quando um dos resultados parciais RES1 e RES2 fosse negativo. Na representação<br />
em complemento de 2, um número negativo possui seu bit mais significativo em 1. Assim,<br />
um comparador binário gera resultados incorretos quando dois números de sinais opostos<br />
são comparados.<br />
Aplicando as técnicas de simplificação da álgebra de Boole [28], podemos reduzir essas<br />
funções lógicas para:<br />
- V1: SIN1 · NFLGH · (NSIN0 + NFLGD);<br />
- V2: SIN0 · (NSIN1 + FLGD + FLGI2);<br />
64
- V3: SIN1 · (NSIN0 + NFLGH) · (FLGH + FLGI1).<br />
Seleção do valor final da matriz de similaridade<br />
Quando os resultados parciais RES1 e RES2 foram obtidos, foi visto que o novo valor<br />
calculado da matriz de similaridade seria o maior dentre esses dois valores e o 0. Para<br />
essa seleção, poderia ser utilizado um comparador e um multiplexador.<br />
Acontece que um dos valores a serem selecionados é o 0. Assim, podemos “fundir” o<br />
comparador e o multiplexador e criar uma função lógica que indique se o valor de RES1<br />
deve ser o escolhido ou então RES2. Se nenhum deles for selecionado, a função lógica<br />
automaticamente irá gerar o 0 como resultado final.<br />
Dois novos sinais foram criados, MUX0 e MUX1, para selecionar os resultados parciais<br />
RES1 e RES2, respectivamente. Dessa forma, o valor final gerado pode ser obtido pela<br />
seguinte função lógica: VF = MUX0 · RES1 + MUX1 · RES2.<br />
O sinal MUX0 deve ser ativado quando os resultados RES1 e RES2 forem positivos e<br />
RES1 for maior ou igual a RES2 ou se o resultado RES1 for positivo e RES2 negativo.<br />
Já o sinal MUX1 deve ser ativado quando os resultados RES1 e RES2 forem positivos e<br />
RES1 for menor ou igual a RES2 ou se o resultado RES1 for negativo e RES2 positivo.<br />
Aproveitando os sinais de geração dos vetores, podemos definir as seguintes funções<br />
lógicas, já simplificadas, para os sinais MUX0 e MUX1:<br />
- MUX0: SIN0 ”(NSIN1 + FLGD + FLGI2);<br />
- MUX1: SIN1 ”(NSIN0 + NFLGH).<br />
Note que o sinal V2 é idêntico ao sinal MUX0 e que MUX1 representa a parte comum<br />
dos sinais V1 e V3. Por essa razão, os sinais de geração dos vetores foram redefinidos<br />
para:<br />
- V1: MUX1 · NFLGH;<br />
- V2: MUX0;<br />
- V3: MUX1 · (FLGH + FLGI1).<br />
Com a utilização dos mesmos sinais para a geração dos vetores e seleção do valor final<br />
calculado, a lógica combinacional do elemento de processamento foi bastante simplificada.<br />
Terminado o projeto inicial do elemento de processamento, várias dessas unidades<br />
foram descritas de forma a constituir o vetor sistólico do sistema. Cada uma dessas<br />
unidades ocupou, em média, 30 elementos lógicos da FPGA.<br />
No entanto, após testes iniciais para validar a solução, um novo problema tinha que<br />
ser resolvido. O sistema em questão foge aos requisitos de entrada e saída discutidos no<br />
capítulo 3.<br />
65
As estruturas sistólicas são apropriadas para tarefas computacionalmente intensas mas<br />
que possuem poucas operações de entrada e saída. A comunicação com o ambiente externo<br />
ao sistema sistólico deveria ocorrer apenas nas células das bordas da estrutura.<br />
O vetor sistólico proposto foge a essa regra pois cada célula deve se comunicar com a<br />
memória externa para que o dado gerado em seu interior possa ser armazenado. Com o<br />
crescimento desse vetor, cresce também a quantidade de células que precisam acessar a<br />
memória externa.<br />
Para uma seqüência de consulta com 1.000 bases, só a quantidade de pinos da FPGA<br />
necessários para poder escrever os valores gerados na memória já inviabilizaria o processo,<br />
fora sinais de endereço e controle. Além disso, a memória possui acesso seqüencial, não<br />
aceitando escritas em paralelo.<br />
Uma alternativa seria enfileirar os dados gerados, serializando a escrita na memória.<br />
Porém, com essa abordagem, todo o ganho obtido com a computação paralela seria perdido.<br />
Dessa forma, era necessário descobrir uma forma de compactar os valores calculados<br />
ou uma maneira de diminuir sua quantidade.<br />
4.4.2 Otimização de Utilização de Espaço e Armazenamento dos<br />
Alinhamentos<br />
O tamanho considerável que as seqüências biológicas podem ter impossibilita o armazenamento<br />
da matriz de similaridades em memória. Hirschberg [29] propôs uma implementação<br />
do algoritmo de Smith-Waterman utilizando espaço linear, aproveitando-se da<br />
própria dependência de dados existente no cálculo da matriz de similaridades, uma vez<br />
que somente os valores da linha anterior e da própria linha são necessários para o cálculo<br />
de uma determinada linha da matriz.<br />
No entanto, com essa otimização, os alinhamentos não podem ser recuperados pelo<br />
procedimento normal de backtracking, pois a matriz não é armazenada em memória. Assim,<br />
somente as coordenadas iniciais e finais de cada alinhamento são armazenadas. Dessa<br />
maneira, a adoção de outras estratégias se fez necessário.<br />
Estratégias Adotadas<br />
Conforme já discutido, pelo enorme montante de dados gerados simultaneamente, era<br />
inviável que esses dados fossem escritos diretamente na memória externa. Assim, estava<br />
claro que seria necessário descrever alguma memória interna ao vetor sistólico para armazenar<br />
temporariamente os valores calculados. Isso permitiria aplicar alguma heurística<br />
que pudesse minimizar esse armazenamento e, posteriormente, entregar a matriz reduzida<br />
para a memória externa.<br />
A primeira particularidade observada na matriz de similaridade foi a grande quantidade<br />
66
de elementos iguais a zero existentes. Devido a essa quantidade, podemos considerá-la uma<br />
matriz esparsa e aplicar uma das técnicas de armazenamento vistas no capítulo 3 para<br />
esse tipo de matriz.<br />
Entretanto, nem todos os zeros da matriz podem ser descartados. Existem dois “tipos”<br />
de zeros na matriz de similaridade: aqueles no qual os resultados parciais da equação de<br />
recorrência foram todos negativos e a constante 0 foi escolhida como o valor máximo e<br />
aqueles no qual um dos resultados parciais foi igual a zero e esse resultado tem prioridade<br />
sobre a constante 0 da equação.<br />
A figura 4.12 exemplifica esses dois tipos:<br />
Figura 4.12: Tipos de zeros existentes na matriz de similaridade.<br />
No tipo 1, a origem do valor zero calculado não foi nenhum dos três valores adjacentes<br />
(diagonal, coluna à esquerda e linha superior). Já o zero do tipo 2 teve múltiplas origens.<br />
Pela equação de recorrência, deve ser subtraído 1 do valor da diagonal caso as bases<br />
comparadas sejam diferentes. Do valor da linha superior é sempre subtraído 2. Essas<br />
duas operações resultam em zero e indicam a origem do novo valor calculado da matriz.<br />
Assim, não existe nenhum vetor saindo de um zero do tipo 1, mas podem existir um<br />
ou mais vetores saindo do zero do tipo 2. Esses zeros (tipo 2) não podem ser eliminados<br />
pois eles podem fazer parte de uma seqüência considerada boa e que resultará em um<br />
alinhamento a ser obtido.<br />
A princípio, pode parecer não muito simples diferenciar um zero do tipo 1 de um zero<br />
do tipo 2. Entretanto, os zeros do tipo 1 são os únicos elementos da matriz de similaridade<br />
que não possuem vetores saindo deles. Como a célula de processamento descrita gera o<br />
vetor indicando a origem do valor calculado, se o vetor produzido for nulo, ou seja, com<br />
os três bits V1, V2 e V3 iguais a zero, significa que o dado gerado para aquela célula foi<br />
um zero do tipo 1 e pode ser eliminado.<br />
O início de qualquer seqüência dentro da matriz ocorre quando todos os valores adjacentes<br />
(diagonal, linha superior e coluna à esquerda) ao valor a ser gerado são zeros do<br />
tipo 1 e as duas bases comparadas são iguais. Assim, todas as seqüências têm como valor<br />
inicial um 1 gerado a partir de um zero do tipo 1. Isso faz com que em um percorrimento<br />
reverso de uma seqüência considerada boa, o último elemento seja sempre um zero do tipo<br />
1. A função desse zero é servir como um marca para finalizar o percorrimento reverso.<br />
Essa função que alguns zeros do tipo 1 podem ter poderia impedir que eles fossem<br />
desprezados. Mas como toda seqüência possui o mesmo comportamento inicial, uma<br />
67
marca (flag) colocada no dado gerado para a memória externa já implicaria que duas<br />
bases iguais foram comparadas e que o valor 1 foi calculado a partir de um zero do tipo<br />
1 dando início a uma nova seqüência. A estrutura do dado fornecido à memória externa<br />
foi então modificada para que essa indicação fosse possível.<br />
Esse resultado permitiu, além de descartar os zeros do tipo 1, armazenar o primeiro<br />
dado de uma seqüência juntamente com o segundo valor dessa mesma seqüência. Como só<br />
era necessário uma marca, o primeiro valor da seqüência não precisava mais ser guardado<br />
explicitamente e poderia também ser desprezado.<br />
Ainda mais, a aplicação da equação de recorrência na primeira coluna da matriz de<br />
similaridade só resulta em zeros do tipo 1 e em valores iniciais de uma seqüência. Como<br />
esses dois valores não precisam mais serem armazenados, conclui-se que todos os dados<br />
da primeira coluna da matriz podem ser descartados.<br />
A próxima observação feita é que os elementos iguais a zero da matriz (sejam eles<br />
do tipo 1 ou 2) só podem ter setas diagonais apontando para eles. Para que essa seta<br />
exista, ou seja, o zero faça parte de uma seqüência, as duas bases da diagonal seguinte<br />
ao zero devem ser iguais. Esse fato não faz a menor diferença para zeros do tipo 1 pois<br />
eles são eliminados de qualquer forma. Entretanto, isso permite que alguns zeros do tipo<br />
2 também possam ser descartados.<br />
Quando um zero desse tipo for gerado, faz-se uma “verificação antecipada” para saber<br />
se esse zero fará parte de uma seqüência ou não. Isso é possível testando as duas bases que<br />
serão utilizadas na geração do próximo valor da matriz de similaridade que se localiza na<br />
diagonal seguinte a esse zero. Se elas forem iguais (situação 1), o zero fará parte de uma<br />
seqüência e deve ser guardado. Se elas forem diferentes (situação 2), o zero calculado,<br />
mesmo sendo do tipo 2, pode ser eliminado.<br />
A figura 4.13 exemplifica o que foi dito acima.<br />
Figura 4.13: Verificação antecipada para saber se o zero fará parte de uma seqüência.<br />
Essa verificação antecipada é facilmente implementada. As duas bases que precisam<br />
ser testadas para decidir se o zero calculado na célula corrente deve ser descartado ou<br />
não estão presentes nas células vizinhas à esquerda e à direita. Como o elemento de<br />
processamento em questão já se comunica com essas duas células, essas duas bases podem<br />
ser fornecidas para a célula em questão e comparadas.<br />
A figura 4.14 ilustra a posição das duas bases que precisam ser comparadas no instante<br />
em que o zero é calculado.<br />
68
Figura 4.14: Posição das bases para a verificação antecipada.<br />
Com as otimizações feitas até aqui, um nova economia foi possível. No preenchimento<br />
da matriz de similaridade, é muito comum que duas bases comparadas sejam iguais e<br />
dêem início a uma nova seqüência. Na maioria dos casos, as bases comparadas da diagonal<br />
seguinte são diferentes e, assim, a seqüência “morre” prematuramente. Essas seqüências<br />
possuem o seguinte formato: 0 ← 1 ← 0, com o primeiro 0 sendo do tipo 1 e o segundo 0<br />
sendo do tipo 2, mas sem nenhuma seta chegando nele.<br />
Como o valor inicial da seqüência não é armazenado e o zero do tipo 2 sem setas<br />
chegando nele é descartado, esse tipo de seqüência é automaticamente eliminado. Essa<br />
situação pode ser observada na matriz de similaridade da figura 4.2, com as seqüências<br />
citadas em uma tonalidade mais clara.<br />
Finalmente, os valores gerados na última linha e na última coluna da matriz só precisam<br />
ser guardados se forem maiores ou iguais ao valor considerado como ótimo para uma<br />
seqüência. Como mais nenhum valor será calculado a partir desses dados, se uma seqüência<br />
não atingiu o valor ótimo, ela não precisará ser recuperada.<br />
Resumindo, as estratégias adotadas para reduzir a quantidade de dados armazenados<br />
da matriz de similaridade foram:<br />
- Zeros que não possuem setas saindo deles (tipo 1) podem ser descartados;<br />
- Zeros que possuem setas saindo deles (tipo 2) só são armazenados se sua diagonal<br />
seguinte possuir duas bases iguais;<br />
- A seqüência 0 ← 1 ← 0 não é armazenada se o último zero obedecer a regra anterior;<br />
- Não é necessário armazenar nenhum valor da primeira coluna da matriz de similaridade;<br />
- A última coluna só armazena valores iguais ou maiores que o valor ótimo.<br />
Vale ressaltar que a aplicação dessas regras não acarreta em nenhuma perda de informação,<br />
ou seja, os alinhamentos que podiam ser obtidos antes de sua aplicação continuam<br />
a ser recuperados após o uso dessas regras.<br />
A utilização dessas simplificações na matriz de similaridade da figura 4.2 faz com que<br />
apenas os elementos marcados com um círculo precisem ser armazenados. Essa matriz<br />
possui 110 elementos e apenas 28 tiveram que ser guardados.<br />
69
Vários exercícios feitos com matrizes que variaram de 4 × 4 (16 elementos) a 15 × 15<br />
(225 elementos) mostraram que a redução obtida com essa heurística ficou entre 75 e<br />
80%, ou seja, seria necessário armazenar apenas entre 20 e 25% dos valores gerados para<br />
a matriz de similaridade.<br />
Embora a redução tenha sido significativa, a quantidade de memória necessária ainda<br />
é considerável. Para uma comparação de seqüências relativamente pequenas, em torno de<br />
1.000 bases, a aplicação dessas regras reduziria a memória de 1MB para 200KB. Levandose<br />
em conta que as seqüências podem atingir centenas de milhares de bases, essa redução<br />
ainda não seria suficiente. Só para se ter uma idéia, uma comparação com seqüências de<br />
400K bases necessitaria de uma memória inicial de 160GB e que poderia ser reduzida para<br />
32 GB.<br />
Para que todas essas otimizações pudessem ser implementadas, a estrutura do dado<br />
gerado para a memória externa teve que ser bastante alterada. Três novos tipos de dados<br />
foram definidos: um que indica o início de um alinhamento (final de um percorrimento<br />
reverso) e contém duas bases alinhadas, um que indica um dado interno a um alinhamento<br />
e um último que indica que o valor ótimo foi alcançado e um percorrimento reverso poderia<br />
ser iniciado nesse ponto. A figura 4.15 ilustra o novo formato do dado a ser fornecido para<br />
a memória externa.<br />
Nessa nova estrutura, para simplificar a obtenção dos alinhamentos locais das duas<br />
seqüências, a base da seqüência do banco de dados também foi incorporada ao dado<br />
fornecido à memória externa. Com isso, os alinhamentos podem ser obtidos apenas com os<br />
dados fornecidos, sem a necessidade de se ter em memória as duas seqüências comparadas.<br />
Figura 4.15: Novo formato do dado fornecido à memória externa.<br />
4.4.3 Outras otimizações<br />
Além de todas as considerações feitas até aqui, no desenvolvimento do projeto foram<br />
notadas algumas outras particularidades do sistema.<br />
70
A célula inicial do vetor sistólico tem sempre os valores da diagonal e da coluna à<br />
esquerda iguais a 0 e o valor da linha superior será no máximo igual a 1. Aplicando a<br />
equação de recorrência com esses valores, percebe-se que o resultado parcial RES2 será<br />
sempre negativo, ou seja, nunca será o escolhido como resultado final. Dessa forma, a<br />
equação de recorrência só precisa ser aplicada ao elemento da diagonal. Como o valor da<br />
diagonal é sempre zero, só existirão dois resultados finais possíveis para essa célula: 1 se<br />
as duas bases comparadas forem iguais ou 0 caso contrário.<br />
Por ter uma lógica combinacional bastante simplificada, a célula inicial do vetor<br />
sistólico recebeu um tratamento diferenciado e foi descrita à parte.<br />
Outra observação feita é que, com os valores utilizados na pontuação da equação de<br />
recorrência, o valor máximo gerado pela célula inicial é igual a 1 (de acordo com o exposto<br />
acima), igual a 2 para a segunda célula da estrutura, igual a 3 para a terceira, assim<br />
sucessivamente, até a n-ésima célula da estrutura que terá um valor máximo calculado<br />
igual a n.<br />
Se todos os elementos de processamento fossem iguais, a sua lógica combinacional<br />
interna teria que ser prevista para o pior caso. Supondo novamente um vetor com 1.000<br />
células, o valor máximo gerado pela última célula seria igual a 1.000. Isso resultaria em<br />
somadores, comparadores e multiplexadores de 10 bits (2 1 0 = 1.024). Essa quantidade<br />
de bits para a segunda célula do vetor representaria um desperdício enorme já que ela<br />
necessitaria de apenas 2 bits.<br />
Dessa forma, o elemento de processamento foi descrito com um tamanho interno configurável.<br />
A quantidade necessária de bits para cada célula é passada como um parâmetro<br />
quando o elemento de processamento é instanciado na descrição em VHDL do vetor<br />
sistólico.<br />
71
Capítulo 5<br />
RESULTADOS<br />
Neste capítulo são apresentados os resultados obtidos a partir da implementação descrita<br />
no capítulo 4. Como essa implementação se deu apenas em nível de síntese, os<br />
resultados apresentados foram obtidos a partir de simulações feitas na ferramenta de desenvolvimento<br />
do fabricante. Entretanto, essas ferramentas fornecem resultados bastante<br />
precisos, não só em termos de funcionalidade do sistema, como também em termos de<br />
velocidade final do sistema, indicando caminhos críticos e atrasos dos sinais. Além disso,<br />
a comunicação com o ambiente externo não é crítica como em um sistema de tempo real,<br />
o que poderia prejudicar os resultados da simulação.<br />
Para a validação da arquitetura sistólica projetada não bastava apenas conhecer os<br />
alinhamentos obtidos na comparação entre duas seqüências, mas também conhecer toda<br />
a matriz de similaridade para verificar se as diversas otimizações sugeridas no capítulo 4<br />
estavam sendo feitas corretamente. Assim, os testes foram todos feitos com seqüências<br />
fictícias cuja matriz de similaridade era conhecida ou poderia ser construída facilmente.<br />
Para o teste de desempenho, vetores de diferentes tamanhos foram sintetizados e suas<br />
freqüências máximas de operação foram obtidas a partir de informações fornecidas pela<br />
ferramenta de síntese.<br />
5.1 Validação<br />
Diversos arquivos de estímulo foram criados contendo seqüências de tamanhos variados.<br />
Nas simulações feitas para a validação, limitou-se o tamanho das seqüências em 20 bases já<br />
que o tamanho da matriz de similaridade se torna considerável para comprimentos acima<br />
desse valor, dificultando bastante a análise e verificação.<br />
Como primeiro exemplo, a comparação de duas seqüências pequenas, com apenas 5<br />
bases cada, é apresentada. Nesse exemplo a base de consulta é CATAG e a base do banco<br />
de dados ATAGC. Depois, é feita uma pequena modificação na seqüência da base de<br />
dados, sendo alterada para CATGA. As matrizes de similaridade dessas duas seqüências<br />
pode ser vista na figura 5.1.<br />
Aplicando as otimizações em relação ao armazenamento da matriz vistas no capítulo 4,<br />
72
Figura 5.1: Matrizes de similaridade para as seqüências CATAG e ATAGC e para CATAG e<br />
CATGA.<br />
apenas os valores circulados devem ser guardados. Note que, no primeiro caso, a matriz<br />
possui 36 elementos mas somente 4 precisam ser salvos, ou seja, apenas 11<br />
A simulação da primeira comparação pode ser vista na figura 5.2.<br />
Figura 5.2: Comparação entre as seqüências CATAG e ATAGC.<br />
A seqüência do banco de dados, que é a entrada principal da simulação, está delimitada<br />
pelo sinal FLAG IN, lembrando que as bases foram codificadas internamente como A =<br />
00, T = 01, C = 10 e G = 11. O valor ótimo fornecido ao sistema está armazenado em um<br />
sinal interno VAL que, nesse caso, foi igual a 4. Os sinais M<strong>EM</strong>2, M<strong>EM</strong>3, M<strong>EM</strong>4 e M<strong>EM</strong>5<br />
são os valores fornecidos para a memória externa pelas colunas 2, 3, 4 e 5, respectivamente<br />
(a coluna inicial, do espaço, foi considerada como coluna 0). Conforme foi discutido no<br />
capítulo 4, a primeira coluna (primeiro caracter da seqüência) não precisa fornecer dados<br />
73
externamente.<br />
Como saída do sistema, além dos dados para a memória externa, temos ainda os sinais<br />
BASE OUT, DATA OUT, FLAG OUT (não colocado na figura) e CONTA. O sinal<br />
BASE OUT é simplesmente a base do banco de dados após atravessar o vetor sistólico.<br />
Já o sinal DATA OUT contém os valores calculados na última coluna da matriz de similaridade.<br />
Note que os valores de DATA OUT estão associados com as bases do banco de<br />
dados que estão na mesma linha. Dessa forma, para essa comparação (comparação 1 da<br />
figura 5.1), temos a seguinte seqüência de saída nos sinais BASE OUT e DATA OUT: A0,<br />
T0, A1, G4 e C2.<br />
Esse formato de saída permite dividir uma seqüência de consulta que não caiba no<br />
tamanho máximo do vetor em duas ou mais partes, ou seja, em dois ou mais vetores<br />
sistólicos. A saída do primeiro vetor seria a entrada do segundo e assim, sucessivamente.<br />
O último sinal, CONTA, é o valor de um contador interno e serve para que um programa<br />
externo que esteja recebendo os dados gerados consiga remontar a matriz de similaridade.<br />
Pela teoria de matrizes esparsas vista no capítulo 3, como a maior parte da<br />
matriz original é desprezada, é necessário fornecer mecanismos para recuperar a posição<br />
original na matriz completa de um valor armazenado na matriz reduzida. No nosso caso,<br />
a coluna pode ser obtida pelo próprio elemento que gerou o dado externo, assim, um dado<br />
lido de M<strong>EM</strong>2 é da segunda coluna e um dado lido de M<strong>EM</strong>5 pertence à quinta coluna.<br />
Para a informação da linha, utiliza-se o sinal CONTA que indica o instante no qual o dado<br />
foi gerado. No primeiro ciclo de relógio, só o valor da primeira coluna e primeira linha da<br />
matriz é calculado. No segundo ciclo de relógio, são calculados o valor da primeira coluna<br />
e da segunda linha e o valor da segunda coluna e primeira linha. No terceiro ciclo, os<br />
valores da primeira coluna e terceira linha, segunda coluna e segunda linha e da terceira<br />
coluna e primeira linha são gerados. Dessa forma, o valor lido do sinal CONTA menos a<br />
coluna indica a linha do valor lido. Por exemplo, um dado lido de M<strong>EM</strong>2 com um valor<br />
5 em CONTA indica que esse dado pertence à segunda coluna e terceira linha da matriz<br />
original. Para a numeração de linha utilizada foi desconsiderada a linha inicial de zeros da<br />
matriz, ou seja, a primeira linha é a primeira linha que contenha uma base da seqüência.<br />
Analisando os dados gerados para a memória externa pela simulação, verifica-se que<br />
M<strong>EM</strong>2 não forneceu nenhum valor, M<strong>EM</strong>3 forneceu apenas o valor 8AH, M<strong>EM</strong>4 forneceu<br />
dois valores (22H e 39H) e M<strong>EM</strong>5 apenas 5AH. A quantidade de valores gerados para a<br />
memória externa confere com os valores circulados na figura 5.1.<br />
M<strong>EM</strong>3 forneceu o resultado 8AH quando o valor de CONTA era igual a 5, ou seja,<br />
esse resultado pertence à terceira coluna e segunda linha da matriz original. Já M<strong>EM</strong>5<br />
forneceu 5AH quando CONTA continha 9, ou seja, esse elemento está localizado na quinta<br />
coluna e quarta linha da matriz original. Essas posições também conferem com o indicado<br />
na figura 5.1.<br />
Finalmente, em relação ao significado dos valores gerados, deve-se recorrer à estrutura<br />
74
apresentada na figura 4.15. Com aquela estrutura, temos o seguinte resultado:<br />
• M<strong>EM</strong>3: 8AH = 10001010B = 1 00 01 010 o percorrimento reverso deve ser feito<br />
na diagonal e foi resultado da comparação de duas bases T, além disso, duas bases<br />
A foram comparadas e são o final do percorrimento reverso (ou o início do alinhamento);<br />
• M<strong>EM</strong>4: 22H = 00100010B = 0 0x 00 010 o percorrimento reverso deve ser feito na<br />
diagonal e foi resultado da comparação de duas bases A;<br />
• M<strong>EM</strong>4: 39H = 00111001B = 0 0x 11 001 o percorrimento reverso deve ser para a<br />
linha superior e mesma coluna e a base G da seqüência do banco de dados deve ser<br />
alinhada com um espaço;<br />
• M<strong>EM</strong>5: 5AH = 01011010B = 0 1x 11 010 esse valor pode ser o ponto inicial de um<br />
percorrimento reverso, que deve ser feito na diagonal e foi resultado da comparação<br />
de duas bases G.<br />
Novamente, os resultados estão coerentes com a matriz de similaridade obtida para<br />
essa comparação.<br />
A simulação da segunda comparação da figura 5.1, agora com um valor ótimo igual a<br />
2, pode ser vista na figura 5.3.<br />
Figura 5.3: Comparação entre as seqüências CATAG e CATGA.<br />
Uma análise similar à que foi feita anteriormente mostra que os resultados gerados nesta<br />
simulação estão corretos e são compatíveis com a matriz de similaridade da comparação<br />
2 da figura 5.1.<br />
75
Conforme previsto, apenas 7 valores são gerados para a memória externa (1 de M<strong>EM</strong>2,<br />
2 de M<strong>EM</strong>3, 3 de M<strong>EM</strong>4 e 1 de M<strong>EM</strong>5). Como análise da informação fornecida por<br />
esses dados, por exemplo, o valor 5AH fornecido por M<strong>EM</strong>5 indica um possível início<br />
de percorrimento reverso (um valor maior ou igual ao valor ótimo), que o percorrimento<br />
reverso deve ser feito na diagonal e que as duas bases comparadas foram G.<br />
Como um último resultado de simulação, os valores gerados pela estrutura sistólica<br />
para a matriz de similaridade obtida pela comparação das seqüências ACATAGGCAT e<br />
CATAAGGCT (figura 4.2) são apresentados na figura 5.4. A seqüência CATAAGGCT<br />
por ser menor, foi colocada dentro do vetor sistólico e a outra seqüência (considerada como<br />
a seqüência proveniente do banco de dados) é que atravessou o vetor. Nessa simulação<br />
é possível ver o sinal FLAG OUT e como ele acompanha as bases do banco de dados na<br />
saída do vetor.<br />
Em uma rápida inspeção, verifica-se que a seqüência de saída vinda de BASE OUT e<br />
DATA OUT é igual à gerada na última coluna da matriz, ou seja, A0, C0, A0, T1, A0, G0,<br />
G0, C3, A4 e T4. Já a quantidade de valores gerados para memória externa foi 28 (2 de<br />
M<strong>EM</strong>2, 4 de M<strong>EM</strong>3, 5 de M<strong>EM</strong>4, 3 de M<strong>EM</strong>5, 4 de M<strong>EM</strong>6, 4 de M<strong>EM</strong>7, 4 de M<strong>EM</strong>8 e 2<br />
de M<strong>EM</strong>9), o mesmo valor que resultaria na contagem dos valores circulados na figura 4.2.<br />
Aparentemente M<strong>EM</strong>2 só gera um valor de saída, mas é que eles são iguais e o sinal que<br />
indica um dado válido externo e permitiria essa diferenciação não foi mostrado.<br />
Figura 5.4: Comparação entre as seqüências ACATAGGCAT e CATAAGGCT.<br />
76
5.2 Desempenho<br />
Para os testes de desempenho, vetores com diversos tamanhos foram sintetizados. Em<br />
cada uma dessas sínteses, a ferramenta de desenvolvimento analisou os caminhos críticos e<br />
os diversos atrasos (tempo que a mudança em sinal leva para gerar outros sinais estáveis)<br />
e determinou a freqüência máxima de operação do circuito. Além disso, a quantidade de<br />
elementos lógicos do FPGA utilizados por vetores de comprimentos diversos também foi<br />
obtida (tabela 5.1).<br />
Tabela 5.1: Quantidade de elementos lógicos utilizados e freqüência máxima de operação para<br />
diferentes comprimentos do vetor sistólico.<br />
Quantidade de Quantidade de Freqüência Média de elementos<br />
células no vetor elementos lógicos máxima de utilizados por célula<br />
do vetor<br />
5 146 122,49 MHz 29,2<br />
10 507 77,54 MHz 50,7<br />
15 900 70,35 MHz 60<br />
20 1292 64,94 MHz 64,6<br />
25 1758 62,63 MHz 70,32<br />
30 2222 56,45 MHz 74,06<br />
40 3204 56,27 MHz 80,1<br />
50 4403 56,1 MHz 88,06<br />
Pode-se perceber que quanto maior a quantidade de células do vetor, menor sua<br />
freqüência máxima de operação. Aparentemente, o aumento do número de células não<br />
deveria afetar a freqüência de operação do circuito. As células possuem a mesma estrutura<br />
interna e, assim, o atraso resultante da lógica combinacional contida em seu interior será<br />
o mesmo. Esses atrasos de cada célula não são somados, pois as operações internas em<br />
cada célula são executadas em paralelo dentro da estrutura. Dessa forma, o tempo que a<br />
lógica combinacional precisaria para ter um sinal estável na saída indicaria a freqüência<br />
máxima de operação do circuito. A adição de uma nova célula não alteraria esse tempo.<br />
A explicação para tal fato é que com poucas células na estrutura, elas podem ser alocadas<br />
em blocos contíguos no FPGA. Isso reduz bastante a necessidade de um roteamento<br />
interno dos sinais, reduzindo os atrasos de comunicação entre as células. Com o aumento<br />
do vetor sistólico, as células têm que ser espalhadas pelo FPGA e uma maior quantidade<br />
de estruturas de roteamento precisam ser utilizadas, aumentando o tempo de comunicação<br />
entre as células. Entretanto, esse atraso de comunicação também não é somado, e o maior<br />
atraso de roteamento (caminho crítico), juntamente com a lógica combinacional da célula<br />
é que irá definir a nova freqüência de operação do circuito. Assim, a partir de um determinado<br />
ponto, a dispersão das células no FPGA já não irá afetar a freqüência de operação<br />
pois o tempo de roteamento irá se estabilizar.<br />
77
A figura 5.5 ilustra esse comportamento assintótico da freqüência máxima de operação.<br />
Com poucas células, a freqüência de operação é fortemente afetada pelos atrasos de roteamento.<br />
Com o aumento da estrutura e o espalhamento das células no FPGA, os atrasos de<br />
roteamento passam a ser praticamente constantes (já se atingiu uma determinada distância<br />
limite entre os blocos), praticamente não afetando mais a freqüência de operação. O valor<br />
limite teórico obtido foi em torno de 56MHz.<br />
Figura 5.5: Freqüência máxima de operação x Quantidade de células do vetor.<br />
Em termos de quantidade de elementos lógicos do FPGA necessários para sintetizar<br />
vetores de diferentes comprimentos, percebe-se uma relação linear entre essas quantidades<br />
(figura 5.6), facilitando bastante estimativas de quantas células poderiam ser alocadas em<br />
um determinado FPGA.<br />
Por exemplo, para o FPGA da família APEX EP20K400EFC672 com 16.640 elementos<br />
lógicos existente na placa PCI de testes, estima-se que possam ser alocadas 180 células de<br />
um vetor sistólico em seu interior.<br />
Comparação<br />
O tempo de execução (comparação) do sistema projetado é dado pelo tempo que<br />
a seqüência do banco de dados leva para atravessar a estrutura sistólica. Assim, se a<br />
seqüência de consulta possuir n elementos e a seqüência do banco de dados possuir m<br />
elementos, a seqüência do banco de dados atravessará o vetor em m + n ciclos de relógio.<br />
78
Figura 5.6: Quantidade de elementos lógicos utilizados no FPGA x Quantidade de células do<br />
vetor.<br />
Dessa forma, podemos deduzir um fórmula que calcula o tempo de comparação entre duas<br />
seqüências:<br />
Texec = m + n<br />
f clock<br />
(5.1)<br />
Apenas para se ter uma idéia do desempenho que essa implementação em hardware<br />
poderia proporcionar, supondo que fosse possível criar um vetor sistólico sem limite de<br />
comprimento, com uma freqüência de operação de 50 MHz, teríamos os seguintes tempos<br />
(em segundos), comparados com uma implementação seqüencial e paralela desenvolvidas<br />
em [47]:<br />
79
Tabela 5.2: Comparação de velocidade entre uma implementação seqüencial, diversas paralelas<br />
e em hardware do algoritmo baseado em programação dinâmica.<br />
Tamanho das 2 4 8 Vetor<br />
Seqüências Seqüencial Processadores Processadores Processadores Sistólico<br />
15kB X 15kB 296s 283,18s 202,18s 181,29s 0,000614s<br />
50kB X 50kB 3461s 2884,15s 1669,53s 1107,02s 0,002048s<br />
80kB X 80kB 7967s 6094,19s 3370,40s 2162,82s 0,003277s<br />
150kB X 150kB 24107s 19522,95s 10377,89s 5991,79s 0,006144s<br />
400kB X 400kB 175295s 141840,98s 72770,99s 38206,84s 0,016384s<br />
Embora o desempenho exibido na tabela 5.2 ainda não possa ser alcançado, por não ser<br />
possível colocar essa quantidade de células em um FPGA considerando o atual estágio de<br />
integração, ela demonstra o enorme ganho de velocidade que uma abordagem em hardware<br />
pode proporcionar. Dessa forma, mesmo que as seqüências tenham que ser divididas em<br />
pedaços menores, de forma que cada pedaço possa ser calculado dentro do FPGA, e depois<br />
os resultados parciais reunidos de modo a produzir a solução completa, pela diferença de<br />
velocidade apresentada, essa abordagem merece ser estudada.<br />
80
Capítulo 6<br />
CONCLUSÕES<br />
O volume de informações geradas para os bancos de dados biológicos tem sido maior<br />
que o crescimento do poder de processamento das máquinas utilizadas para processar essas<br />
informações. Dessa forma, encontrar mecanismos eficientes para tratar esses dados é um<br />
desafio constante da Bioinformática.<br />
Dentre as operações necessárias para esse tratamento, uma das mais utilizadas é a<br />
comparação de seqüências. O algoritmo de Smith-Waterman, baseado em programação<br />
dinâmica, é o que produz os melhores resultados, mas apresenta complexidades quadráticas<br />
de tempo e espaço, não sendo utilizado amplamente em projetos de seqüenciamento de<br />
genomas. Os programas mais utilizados são baseados em probabilidades e heurísticas que,<br />
apesar de serem consideravelmente mais rápidos, podem omitir resultados importantes.<br />
Para tentar melhorar o desempenho dos algoritmos baseados em programação dinâmica,<br />
soluções utilizando paralelismo vêm sendo desenvolvidas, tanto em hardware quanto em<br />
software.<br />
Este trabalho mostrou como um hardware dedicado, baseado em uma estrutura sistólica,<br />
é capaz de linearizar a complexidade temporal e reduzir bastante o tempo de processamento<br />
desses algoritmos.<br />
Embora o dispositivo gerado tenha sido apenas em nível de síntese, os resultados<br />
obtidos podem ser considerados bastante confiáveis, dada a precisão que a ferramenta de<br />
síntese possui para simulações funcionais e temporais.<br />
Para que a implementação proposta se torne funcional é necessário o desenvolvimento<br />
de um programa que converta as seqüências para a codificação interna utilizada no vetor,<br />
que forneça esses dados ao vetor pelo barramento PCI e que leia os dados gerados, montando<br />
a matriz de similaridade completa ou trabalhando com a matriz reduzida para o<br />
obtenção dos alinhamentos. Dada a velocidade na qual os resultados são produzidos pelo<br />
vetor, o programa deverá possuir mecanismos de sincronização para não haver perda de<br />
dados.<br />
Esse mesmo programa poderia dividir as seqüências em vários pedaços menores e<br />
efetuar a comparação desses pedaços menores, armazenando os resultados temporários e<br />
depois montando uma solução final. Como a velocidade do hardware projetado é muito<br />
81
grande, mesmo com uma granularidade pequena, que aumenta os custos de comunicação,<br />
o desempenho final do sistema ainda deverá ser bastante satisfatório.<br />
Outra possível implementação seria utilizar as soluções propostas em [50] e [47], baseadas<br />
em [14]. Em cada um desses trabalhos foi desenvolvido um programa para paralelizar o<br />
algoritmo de Smith-Waterman e, com isso, obter um ganho de performance. O problema<br />
do cálculo da matriz de similaridade foi dividido em blocos e cada um desses blocos é<br />
enviado para um processador do cluster. O hardware aqui proposto poderia ser utilizado<br />
para o cálculo de cada um desses blocos menores. Uma placa PCI similar à utilizada nessa<br />
dissertação poderia ser colocada em cada computador do cluster que, ao receber o bloco a<br />
ser calculado, repassaria esse bloco para o vetor sistólico e armazenaria os valores gerados.<br />
Dessa forma, teríamos dois níveis de paralelismo atuando, em software e em hardware, o<br />
que poderia acelerar bastante o tempo de processamento dessas comparações.<br />
Embora nesse trabalho tenha se conseguido simplificar bastante a quantidade de dados<br />
que devem ser guardados da matriz de similaridade, o resultado obtido ainda está longe de<br />
uma condição ideal. Pela revisão bibliográfica vista no capítulo 1, pode-se notar que o alvo<br />
principal das pesquisas é proporcionar um ganho de velocidade ao algoritmo, com poucos<br />
estudos sobre otimizações de espaço. Essa otimização é extremamente importante, dada<br />
a enorme quantidade de elementos que a matriz de similaridade pode possuir. Já notando<br />
esse problema, Cuvillo [14] sugere uma heurística para guardar apenas os alinhamentos<br />
que poderiam ser considerados bons, ignorando os demais. A união das otimizações aqui<br />
propostas com as utilizadas por Cuvillo poderiam ser avaliadas, bem como a aplicação de<br />
outras técnicas que pudessem reduzir ainda mais a quantidade de dados armazenados.<br />
Outro problema também não resolvido completamente foi o fornecimento dos valores<br />
gerados pelo vetor para uma memória externa. Como vários valores podem ser gerados<br />
simultaneamente, para que eles pudessem ser escritos em uma única memória, uma serialização<br />
desses dados seria necessária. Isso acarretaria uma perda da performance obtida<br />
nos cálculos em paralelo. Entre as possíveis soluções poderia se avaliar a utilização de<br />
memórias entrelaçadas [35] e a divisão da memória em blocos. Além disso, a família<br />
APEX de FPGAs da Altera, possui facilidades para implementar memórias de conteúdo<br />
(CAM), que também poderiam ser avaliadas.<br />
Finalmente, nas simplificações manuais feitas nos somadores e comparadores percebeuse<br />
que a ferramenta de síntese gerou os mesmos resultados automaticamente. Entretanto,<br />
na definição dos sinais internos para a geração dos vetores e escolha do melhor valor para a<br />
célula, algumas simplificações manuais e algumas outras observações descritas no capítulo<br />
4 resultaram em sínteses mais otimizadas que as obtidas automaticamente. Uma análise<br />
mais aprofundada desses resultados fugia ao escopo desta pesquisa. Assim, poderia ser alvo<br />
de estudo uma metodologia que forneça mecanismos ou aponte caminhos ao projetista para<br />
que ele possa decidir que parte da descrição deve ser simplificada automaticamente e que<br />
parte requer uma análise manual mais detalhada. A possível criação de uma biblioteca de<br />
82
componentes ou unidades funcionais otimizadas que pudessem ser utilizadas em projetos<br />
de maior porte também poderia fazer parte desse estudo.<br />
83
REFERÊNCIAS BIBLIOGRÁFICAS<br />
[1] IEE standard VHDL language reference manual, IEEE std. Relatório técnico, The<br />
Institute of Electrical and Electronics Engineers, 1988.<br />
[2] Primer on Molecular Genetics. U.S. DOE — Department of Energy., 1991.<br />
[3] Initial sequencing and analysis of the human genome. Relatório técnico, The Genome<br />
International Sequencing Consortium, Fevereiro de 2001.<br />
[4] Adário, A. M. S., Bampi, S., e Jacobi, R. P. Reconfigurable architectures. volume 12,<br />
páginas 133–136, Porto Alegre: PPGC da UFRGS, 1997.<br />
[5] Adário, A. M. S., Roehe, E. L., e Bampi, S. Dynamically reconfigurable achitecture<br />
for image processor applications. Em Design Automation Conference, páginas 623–<br />
628. ACM, 1999.<br />
[6] Altschul, S. F., Gish, W., Miller, W., Myers, E. W., e Lipman, D. J. Basic local<br />
alignment search tool. Journal of Molecular Biology, 215:403–410, 1990.<br />
[7] Amabis, J. M. e Martho, G. R. Curso Básico de Biologia, volume 1. Editora Moderna,<br />
1988.<br />
[8] Amabis, J. M. e Martho, G. R. Curso Básico de Biologia, volume 2. Editora Moderna,<br />
1988.<br />
[9] Arnold, J. M., Buell, D. A., e Davis, E. G. Splash 2. ACM Symposium on Parallel<br />
Algorithms and Architectures, 1992, Junho.<br />
[10] Aschenden, P. J. The Designer´s Guide to VHDL. Morgan Kaufmann Publishers,<br />
Inc., San Francisco, CA, 1996.<br />
[11] Brutlag, D. L., Dautricourt, J. P., Maulik, S., e Relph, J. Improved sensitivity of<br />
searches of biological sequence databases. CABIOS, 6 (3):237–245, 1990.<br />
[12] Carro, L. Projeto e Prototipação de Sistemas Digitais. Editora Universidade/UFRGS,<br />
Porto Alegre, RS, 2001.<br />
[13] Cormen, T. H., Leiserson, C. E., e Rivest, R. L. Introduction to Algorithms. MIT<br />
Press: McGraw Hill, 1990.<br />
[14] Cuvillo, J. Whole genome comparison using a multithreaded parallel implementation.<br />
Dissertação de Mestrado, Universidade de Delaware, 2001.<br />
[15] Dalton, J. Absorption of gases by water and other liquids. 1803.<br />
[16] Dayhoff, M. O., Scwartz, R. M., e Orcutt, B. C. A model of evolucionary change<br />
in proteins. volume 5, páginas 345–352, Washington, DC, 1978. Natl. Biomed. Res.<br />
Foundation.<br />
[17] Cuvillo, J. B.del , Martins, W. S., Gao, G. R., Cui, W., e Kim, S. ATGC: Another<br />
tool for genome comparison. Relatório técnico.<br />
84
[18] E., M. P. R. T. D. The Verilog Hardware Description Language. Kluwer Academics<br />
Publishers, 1991.<br />
[19] Eijikhout,. Lapack working note 50: Distributed sparse data structures for linear<br />
algebra operations. Relatório técnico, Computer Science Department, University of<br />
Tennessee, Knoxville, TN, 1992.<br />
[20] Gajski, D., Dutt, N., Wu, A., e Lin, S. Sigh Level Systems – Introduction to Chip and<br />
System Design. Kluwer Academic Publishers, Massachusets, Estados Unidos, 1992.<br />
[21] Gibas, C. e Jambeck, P. Developing Bioinformatics Computer Skills. O’Reilly, 2001.<br />
[22] Gokhale, M. Splash: A reconfigurable linear logic array. Procedings of 1990 International<br />
Conference on Parallel Processing, páginas 526–532, 1990.<br />
[23] Gotoh,. An improved algorithm for matching biological sequences. J. Mol. Biol.,<br />
162:705–708, 1982.<br />
[24] Grice, J. A., Hughey, R., e Speck, D. Parallel sequence alignment in limited space.<br />
Em Proc. Int. Conf. Intelligent Systems for Molecular, páginas 145–153. AAAI/MIT<br />
Press, 16-19 de Julho de 1995.<br />
[25] Guccione, S. A. e Keller, E. Gene matching using jbits. Xilinx, Inc., 2002.<br />
[26] Hadley, J. D. e Hutchings, B. L. Design methodologies for partially reconfigured<br />
systems. páginas 78–84, Califórnia, Estados Unidos, 1995.<br />
[27] Henikoff, S. e Henikoff, J. G. Aminoacid substitution matrices from proteins blocks.<br />
volume 89, páginas 10915–19, 1992.<br />
[28] Hill, F. J. e Peterson, G. R. Computer Aided Logical Design with Emphasis on VLSI.<br />
John Wiley & Sons, Inc, 4 edição, 1993.<br />
[29] Hirschberg, D. A linear space algorithm for computing maximal common subsequences.<br />
Communications of the ACM, 18:341–343, 1975.<br />
[30] Hirschberg, J. D., Hughey, R., e Karplus, K. Krestel: A programmable array for<br />
sequence analysis. Em Proc. Int. Conf. Application-Specific Systems, Architectures<br />
and Processors, páginas 25–34. IEEE CS, 19-21 de Agosto de 1996.<br />
[31] Hoang, D. T. A systolic array for the sequence alignment problem. Relatório Técnico<br />
CS-92-22, Brown University, Providence, RI, 1992.<br />
[32] Hoang, D. T. e Lopresti, D. P. FPGA implementation of systolic sequence alignment.<br />
1992.<br />
[33] Hughes, N. Implementing sequence matching algorithms with hardware compilation.<br />
Relatório técnico, St. Hugh’s College.<br />
[34] Hughey, R. Parallel hardware for sequence comparison and alignment. CABIOS,<br />
12(6):473–479, Dezembro de 1996.<br />
[35] Hwang, K. Advanced Computer Architecture. McGraw-Hill International Editions,<br />
Nova Iorque, 1993.<br />
[36] Information Sciences Institute - East, http:// www.east.isi.edu/projects/SLAAC/.<br />
Slaac project. World Wide Web site.<br />
[37] Kung, H. T. Why systolic architectures? IEEE Computer, 15 (1):37–46, Janeiro de<br />
1982.<br />
[38] Lavenier, D. Dedicated hardware for biological sequence comparison. 1996.<br />
85
[39] Lavenier, D. SAMBA - Systolic Accelerators for Molecular Biological Applications.<br />
Relatório Técnico 988, IRISA, Março de 1996.<br />
[40] Lavenier, D. Speeding up genome computations with a systolic accelerator. SIAM<br />
News, 31(8):1–7, Outubro de 1998.<br />
[41] Lewin, B. Genes VII. Artmed, Porto Alegre, RS, Brasil, 2001.<br />
[42] Lipsett, R., Schaefer, C., e Ussery, C. VHDL: Hardware Description and Design.<br />
Kluwer Academic Press, 1989.<br />
[43] Lipton, R. J. e Lopresti, D. A systolic array for rapid string comparison. Em Chapel<br />
Hill Conference on VLSI, páginas 363–376, 1985.<br />
[44] Luscombe, N. M., Greenbaum, D., e Gerstein, M. Yearbook Of Medical Informatics<br />
2001, chapter What is bioinformatics? An introduction and overview, páginas 83–<br />
100. International Medical Informatics Association, 2001.<br />
[45] Martins, W. S., Cuvillo, J. B.del , Useche, F. J., Theobald, K. B., e Gao, G. R.<br />
A multithreaded parallel implementation of a dynamic programming algorith for<br />
sequence comparison. Relatório técnico.<br />
[46] Martins, W. S., Cuvillo, J.del , Cui, W., e Gao, G. R. Whole genome alignment using<br />
a multithreaded parallel implementation. Relatório técnico.<br />
[47] Melo, R. C. F. Comparação de seqüências biológicas utilizando dsm. Dissertação<br />
de Mestrado, Departamento de Ciência da Computação, Universidade de Brasília,<br />
Brasília, DF, Janeiro de 2003.<br />
[48] Michel, P., Lauther, U., e Duzy, P. The Synthesis Approach to Digital Systems Design.<br />
Kluwer Academic Publishers, Massachusets, Estados Unidos, 1992.<br />
[49] Michele, G. D. Synthesis and Optimization of Digital Circuits. McGraw-Hill, 1994.<br />
[50] Murakami, M. M. Uma nova abordagem para pesquisa paralela em bancos de dados<br />
biológicos utilizando algoritmos de comparação de seqüências baseados em programação<br />
dinâmica. Dissertação de Mestrado, Departamento de Ciência da Computação,<br />
Universidade de Brasília, Brasília, DF, Março de 2003.<br />
[51] Needleman, S. B. e Wunsch, C. D. A general method applicable to the search for<br />
similarities in the amino acid sequence of two proteins. volume 48, páginas 443–453,<br />
1970.<br />
[52] Splash 2, S. G. D.on . Dzung t. hoang. páginas 185–191, Los Alamitos, CA, 1993.<br />
IEEE Computer Society Press.<br />
[53] ONSA - Organization for Nucleotide Sequencing and Analysis,<br />
http://watson.fapesp.br/onsa/Genoma3.htm. Genoma3.<br />
[54] Page, I. Reconfigurable processor architectures. Microprocessors and Microsystems<br />
(Special Issue on Codesign), 20:185–196, 1996.<br />
[55] Pappas, N. P. Searching biological sequence databases using distributed adaptive<br />
computing. Dissertação de Mestrado, Virginia Polytechnic Institute and State University,<br />
Blacksburg, Virginia, Janeiro de 2003.<br />
[56] Paracel, Inc, http://www.paracel.com/. 2001.<br />
[57] Paracel Inc, http://www.paracel.com/products/pdfs/gm2 datasheet.pdf. The Genematcher2<br />
System Datasheet, 2002.<br />
[58] Patzer, A. Highly parallel DNA sequence matching and alignment processor.<br />
86
[59] Pearson, W. R. e Lipman, D. L. Improved tools for biological sequence comparison.<br />
Proceedings Of The National Academy Of Science USA, 85:2444–2448, Abril de 1988.<br />
[60] Puttegowda, K., Worek, W., Pappas, N., Dandapani, A., e Athanas, P. A run-time<br />
reconfigurable system for gene-sequence searching. Proceedings of the International<br />
VLSI Design Conference, Janeiro de 2003.<br />
[61] Rognes, T. ParAlign: a parallel sequence alignment algorithm for rapid and sensitive<br />
database searches. Nucleic Acids Research, 29(7):1647–1652, 2001.<br />
[62] Rognes, T. e Seeberg, E. Six-fold speed-up of Smith-Waterman sequence database<br />
searches using parallel processing on common microprocessors. Bioinformatics,<br />
16(8):699–706, 2000.<br />
[63] Saad,. Sparskit: A basic tool kit for sparse matrix computation. Relatório Técnico<br />
CSRD TR 1029, University of Illinois, Urbana, IL, 1990.<br />
[64] Setubal, J. C. e Meidanis, J. Computational Molecular Biology. PWS, 1997.<br />
[65] Simpson, A. J. G. The genome sequence of the plant pathogen xylella. Nature,<br />
406:151–157, Julho de 2000.<br />
[66] Smith, T. e Waterman, M. Identification of common molecular subsequences. Journal<br />
of Molecular Biology, 147:195–197, 1981.<br />
[67] TimeLogic Corp, http://www.timelogic.com. 2002.<br />
[68] TimeLogic Corp, http://www.timelogic.com/ decypher intro.html. DeCypher, 2002.<br />
[69] Trelles, O. On the parallelization of bioinformatic applications. volume 2, 2001.<br />
[70] Villasenor, J. e Amgione-Smith, W. Configurable computing. Scientific American,<br />
19:54–58, 1997.<br />
[71] Waterman, M. S. Sequence alignments. páginas 53–92. CRC Press, 1989.<br />
[72] Watson, J. D. e Crick, F. H. Molecular structure of nucleic acids: A structure for<br />
deoxyribose nucleic acid. Nature, 171:737–738, Abril de 1953.<br />
[73] White, C. T., Singh, R. K., Reintjes, P. B., Lampe, J., Erickson, B. W., Dettloff,<br />
W. D., Chi, V. L., e Altschul, S. F. Bioscan: A vlsi system based for biosequence<br />
analysis. páginas 504–509. IEEE Computer Society Press, 1991.<br />
[74] Worek, W. J. Matching genetic sequences in distributed adaptive computing systems.<br />
Dissertação de Mestrado, Virginia Polytechnic Institute and State University,<br />
Blacksburg, Virginia, Julho de 2002.<br />
[75] Xilinx, Inc., http://www.xilinx.com.<br />
[76] Yamaguchi, Y., Maruyama, T., e Konagaya, A. High speed homology search with<br />
FPGAs. Pacific Symposion on Biocomputing, páginas 271–282, 2002.<br />
[77] Yang, B. H. W. A parallel implementation of Smith-Waterman sequence comparison<br />
algorithm. Relatório Técnico ID: 4469409, Instituição, 2002.<br />
[78] Yu, C. W., Kwong, K. H., Lee, K. H., e Leong, P. H. W. A smith-waterman systolic<br />
cell. The Chinese University of Hong Kong, 2003.<br />
87