• Nenhum resultado encontrado

Algoritmo de Programação Dinâmica

No documento Alinhamento de Seqüências Biológicas (páginas 31-35)

1.5 Algoritmos Fundamentais

1.5.4 Algoritmo de Programação Dinâmica

Dada uma entrada para um problema que satisfaça as duas propriedades acima, um algoritmo baseado no paradigma de programação dinâmica opera resolvendo progressiva-mente subproblemas do problema original (geralprogressiva-mente, em ordem crescente de tamanho dos subproblemas) e armazenando as soluções de cada subproblema em uma tabela para um possível uso posterior. A idéia é evitar que algum subproblema seja resolvido (desnecessari-amente) mais de uma vez. Uma interpretação alternativa de um algoritmo de programação dinâmica pode ser como uma maneira de executar os passos de um algoritmo recursivo em uma ordem conveniente, usando uma tabela para manter as soluções dos subproblemas já resolvidos por chamadas recursivas do algoritmo.

Por exemplo, no caso do Problema APS, um algoritmo de programação dinâmica pode ser interpretado como uma ordenação adequada dos passos do Algoritmo Alinha-Rec de forma que os alinhamentos obtidos por cada chamada recursiva (como, por exemplo, Alinha-Rec(s[1 . . 3], t[1 . . 4])) sejam armazenados em uma tabela.

Ao longo de um algoritmo de programação dinâmica, tentam-se estender soluções ótimas de subproblemas a uma solução ótima de um subproblema maior, fazendo uso da Propri-edade das Subsoluções Ótimas, e prosseguindo até que uma solução ótima do problema original seja encontrada.

Um algoritmo de programação dinâmica para o Problema APS foi publicado em 1970 por Needleman e Wunsch [NW70], embora haja relatos de que suas idéias principais fizessem parte do folclore dos pesquisadores da época. O algoritmo, muito modificado desde então por vários pesquisadores, foi melhorado em relação à complexidade de tempo e de espaço [Hir75]

e também adaptado para outros problemas, sendo que uma das adaptações mais importantes e populares é a desenvolvida por Smith e Waterman em 1981, para computar alinhamentos locais [SW81]. O algoritmo que veremos possui sua origem incerta e foi provavelmente descoberto independentemente por diversos pesquisadores [SM97].

1.5.4.1 Etapas do Algoritmo

Bem como vários algoritmos de programação dinâmica, o algoritmo de programação dinâmica para o Problema APS opera em duas etapas. Na primeira etapa, a distância entre as seqüências de entrada é calculada e, na segunda, um alinhamento ótimo (i.e., de pontuação igual à distância entre as seqüências) é determinado. Vamos à descrição de cada etapa. Para nossas considerações, supomos que o alfabeto Σ e que a matriz de pontuação c estejam fixados, como no enunciado do Problema APS.

1.5.4.1.1 Etapa 1: Cálculo da Distância Na primeira etapa, para seqüências s e t de comprimentos|s|=me |t|=n, uma matrizade dimensões (m+ 1)×(n+ 1), indexada por {0, . . . , m} e {0, . . . , n}, é preenchida com as pontuações de alinhamentos ótimos de prefixos descom prefixos det, de forma que a posição (i, j) deacontenha a pontuação de um alinhamento ótimo des[1 . .i] et[1 . .j], isto é, de modo quea[i, j] =d(s[1 . .i], t[1 . .j]), para 0≤im e 0≤jn. É claro que a distância d(s, t) =d(s[1 . .m], t[1 . .n]) está na posição a[m, n].

Conforme mencionamos, o algoritmo tenta “estender” soluções já calculadas para pro-blemas de maior tamanho (ele opera “de baixo para cima”).

Pela definição da matriz a, a linha i = 0 é tal que a[0, j] = d(s[1 . . 0], t[1 . .j]) = d(ε, t[1 . .j]), para 0jn. Como os alinhamentos que consideramos são livres de colunas em branco, a única possibilidade de um alinhamento entre a seqüência vazia e t[1 . .j] é o alinhamento em que cada caractere de t[1 . .j] fica alinhado a um espaço. Naturalmente, como este alinhamento é único, ele é trivialmente um alinhamento ótimo e seu custo é a[0, j] =Pjk=1c(␣, t[k]). Em outras palavras, temos quea[0, j] =a[0, j−1] +c(␣, t[j]), para todo j= 1, . . . , n e a[0,0] = 0. Essa é a forma de preenchimento da linhai= 0 da matriz.

O mesmo argumento vale para ver que a coluna j = 0 deve ser preenchida de acordo com a relação de recorrência a[i,0] =a[i−1,0] +c(s[i],␣), para todo i= 1, . . . , m.

Naturalmente, como há apenas 3 possibilidades para a última coluna de um alinhamento e o Problema APS satisfaz à Propriedade das Subsoluções Ótimas, sabemos que um ali-nhamento ótimo entres[1 . .i] e t[1 . .j] pode ser obtido a partir de um alinhamento ótimo de s[1 . .i−1] e t[1 . .j] justaposto com s[i]

ou de um alinhamento ótimo des[1 . .i−1]

e t[1 . .j−1] justaposto com s[i]t[j] ou de um alinhamento ótimo de s[1 . .i] e t[1 . .j−1]

justaposto com ␣

t[j]

, dependendo de qual possuir a menor pontuação. Em termos da matriz a, isso fica:

a[i, j] = min

a[i−1, j] +c(s[i],␣), a[i−1, j−1] +c(s[i], t[j]),

a[i, j−1] +c(␣, t[j])

, (1.3)

parai >0 ej >0.

Para preenchermos a matrizacom o algoritmo, devemos escolher uma ordem conveniente para que o cálculo dea[i, j] seja feito apenas apósa[i−1, j],a[i−1, j−1] ea[i, j−1] estarem definidos. Uma possibilidade para isso é preencher a matrizalinha a linha, a partir da linha de índice 0 e, para cadai fixado, em ordem dej crescente4.

Um algoritmo que implementa as idéias acima é o Algoritmo Dist.

Como um comentário a parte, algumas implementações do Algoritmo Dist são feitas com a suposição de que existe uma constante g tal que c(␣, σ) =g para todo σ ∈ Σ. Em

4Outra possibilidade para preenchimento deaé fazer os cálculos coluna a coluna, a partir da coluna 0 e, parajfixado, fazer o preenchimento comivariando de 0 am.

1.5 Algoritmos Fundamentais 15

a[i−1, j−1] a[i−1, j]

a[i, j−1]oo a[i, j]

ggOOOOOOOOOOOO OO

Figura 1.4: Para preencher a entradaa[i, j], o AlgoritmoDistprecisa de 3 outras entradas:

a[i−1, j], a[i−1, j−1] e a[i, j−1].

Algoritmo 1.2 Dist(s, t)

Entrada: Duas seqüênciasse t, com|s|=m e|t|=n.

Saída: Uma matriza= (aij) coma[i, j] =d(s[1 . .i], t[1 . .j]).

1: m← |s|;n← |t|;a[0,0]←0;

2: para j= 1, . . . , nfaça

3: a[0, j]a[0, j−1] +c(␣, t[j]);

4: para i= 1, . . . , mfaça

5: a[i,0]←a[i−1,0] +c(s[i],␣);

6: para j = 1, . . . , n faça

7: a[i, j]a[i−1, j] +c(s[i],␣);

8: se a[i, j]> a[i−1, j−1] +c(s[i], t[j]) então

9: a[i, j]a[i−1, j−1] +c(s[i], t[j]);

10: se a[i, j]> a[i, j−1] +c(␣, t[j]) então

11: a[i, j]a[i, j−1] +c(␣, t[j]);

12: Devolvaa;

particular, nesse caso, a primeira linha de a pode ser preenchida com a[0, j] = g·j e, a primeira coluna, coma[i,0] =g·i. É comum referir-se a uma tal matriz de pontuação como matriz de custos lineares para lacunas.

1.5.4.1.2 Etapa 2: Cálculo de um Alinhamento Ótimo Até aqui, apenas o cálculo da pontuação de um alinhamento ótimo (distância entre seqüências) foi efetuado. Terminado esse pré-processamento, podemos usar a tabelaaresultante da primeira etapa para construir os alinhamentos ótimos.

A construção de um alinhamento ótimo é feita observando-se qual (ou quais, se es-tivermos interessados em vários alinhamentos ótimos) das pontuações dentre a[m−1, n], a[m−1, n−1] e a[m, n−1] produziu a pontuação a[m, n] (correspondente à pontuação ótima de todos os m caracteres de s alinhados a todos os n caracteres de t) e decidindo, portanto, qual é a última coluna de um alinhamento ótimo.

Desta forma, supondo-se quea[m0, n0] seja a posição dentre as três descritas que produziu a pontuaçãoa[m, n], podemos obter as demais colunas do alinhamento repetindo o processo, usando (m0, n0) no lugar de (m, n) e repetir o procedimento de procura de que posição deu origem a m0 e n0 até que a posição (0,0) de a seja atingida, momento em que todas as colunas do alinhamento estarão determinadas.

O Algoritmo Alinha contém um resumo dessa discussão.

Algoritmo 1.3 Alinha(a, s, t)

Entrada: Duas seqüênciasse te a matrizadevolvida por Dist(s, t).

Saída: Um alinhamento entre se tde pontuação mínima.

1: m← |s|;n← |t|;

2: sem= 0 então

3: Devolva os caracteres de talinhados a espaços ems;

4: sen= 0 então

5: Devolva os caracteres de salinhados a espaços emt;

6: sea[m, n] =a[m−1, n] +c(s[m],␣) então

7: DevolvaAlinha(a, s[1 . .m−1], t) : s[m] 8: sea[m, n] =a[m−1, n−1] +c(s[m], t[n]) então

9: DevolvaAlinha(a, s[1 . .m−1], t[1 . .n−1]) : s[m]t[n]

10: sea[m, n] =a[m, n−1] +c(␣, t[n])então

11: DevolvaAlinha(a, s, t[1 . .n−1]) : ␣

t[n]

1.5.4.2 Análise de Complexidade

Vamos analisar a complexidade de tempo e de espaço dos algoritmos vistos. Para evitar ambigüidade, convencionamos que, nesta seção, a palavra espaço será utilizada para nos referirmos à quantidade de memória requerida para os algoritmos em vez de designar o caractere espaço (␣) como nas demais seções.

O AlgoritmoDistinicializa a primeira linha da matrizaem tempoO(n) (linhas 2 e 3).

A linha 1 é executada em tempoO(1). Após a inicialização, os laços encaixados em ie em j (linhas 4–11) são executados. A parte mais interna desses laços (i.e., cada execução das linhas 7–11) leva tempo constante e são realizadas um total de O(mn) iterações. Ao longo do algoritmo, a linha 5 é executada um total dem vezes e, como cada execução dela toma tempo constante, a parcela de tempo total do algoritmo referente a sua execução éO(m).

Disso podemos concluir que o algoritmo leva tempoO(1)+O(n)+O(m)+O(mn) =O(mn).

O espaço usado pelo algoritmo5éO(1), uma vez que os recursos de memória empregados são, basicamente, as variáveis de controle do algoritmo (que são i,j,m en) e que ocupam espaçoO(1), a matriz de pontuaçãoc, que tem também tamanhoO(1) (pois o alfabeto está fixado) e a matriza, de tamanho (m+ 1)×(n+ 1), que faz parte da resposta devolvida por Dist.

O outro algoritmo, Alinha, opera em tempo e espaço lineares no tamanho das seqüên-cias s e t. Para nos convencermos da complexidade de tempo, basta ver que cada coluna do alinhamento construído como solução requer que, no máximo, 3 posições da matriz a sejam analisadas (vide linhas 6–11). Como cada um dos testes é feito em tempo constante, a determinação de uma coluna qualquer do alinhamento final toma tempo O(1). Ademais, todos os alinhamentos que consideramos (i.e., livres de colunas em branco) possuem com-primento máximo dem+ncolunas. Daí, concluímos que o AlgoritmoAlinhaleva tempo O(m+n).

Para o espaço usado pelo Algoritmo Alinha, observemos que, excetuando-se a matriza

5Para a análise de espaço de nossos algoritmos, usamos a prática comum [Pap94] de não considerar na complexidade o espaço usado para resposta dos algoritmos (i.e., os algoritmos são modelados comomáquinas de Turing de Entrada e Saída).

1.5 Algoritmos Fundamentais 17

e o alinhamento produzido como resposta (que usa espaçoO(m+n)), tudo o que é necessário é armazenar as variáveis de controle do algoritmo que totalizam espaço O(1) e a pilha de recursão do algoritmo, que tem tamanhoO(m+n) (porque uma chamada recursiva é feita para determinar cada coluna do alinhamento). Isso justifica a afirmação de o Algoritmo Alinhausar espaço O(m+n).

É importante ver que, apesar de ambos os Algoritmos Dist e Alinha terem comple-xidades individuais de espaço de O(1) e O(m+n), respectivamente, uma implementação natural para encontrar um alinhamento ótimo desetopera primeiro fazendo uma chamada a Dist, depois armazenandoa e, por fim, fazendo uma chamada aAlinha, de forma que este método usa espaço O(mn) como um todo.

Como um comentário adicional, embora tenhamos descrito algoritmos para o Problema APS usando espaço (total) quadrático, é possível realizar todo o procedimento em espaço O(m +n), mantendo ainda a complexidade de tempo assintótica de O(mn), conforme veremos na Seção 1.6.

No documento Alinhamento de Seqüências Biológicas (páginas 31-35)