• Nenhum resultado encontrado

Ű InsertEndseq(L, s) Entrada: Lista L e sequência s

Algoritmos dos operadores StreamPref

Algoritmo 29 Ű InsertEndseq(L, s) Entrada: Lista L e sequência s

Atualização: Lista L

1: if s.inserted > 0 then //VeriĄca se s possui inserções 2: ns ← s[♣s♣ − s.inserted + 1, ♣s♣] //Obtém a sequência ns com as posições inseridas 3: forss ∈ L do //Para cada subsequência ss ∈ L 4: ss ← ss + ns //Concatena ss com ns 5: L ← L ∪ NewConseq(ns) //Adicionas as subsequências de ns em L

7.2.3 Análise de complexidade

A complexidade do algoritmo ingênuo NaiveSubseq é O(zn) para o operador

CONSEQ e O(zn2) para o operador ENDSEQ, onde z = ♣Z♣ é o número de sequências recebidas e n é o comprimento da maior sequência recebida. O custo do NaiveSubseq para o operador ENDSEQ é maior porque o algoritmo precisa processar uma sequência múltiplas vezes para obter todas as suas subsequências-up.

A complexidade do algoritmo IncConseq depende do custo das funções DeleteConseq, InsertConseq e NewConseq. As funções DeleteConseq e InsertConseq têm os custos O(d) e O(i), respectivamente, onde d é o maior número de remoções e i é o maior número de inserções. Já a função NewConseq tem o custo de O(i2). Desta maneira, a complexidade do algoritmo IncConseq é O(zd + zi + zi2). Como foi descrito no Capítulo 6, o operador

CONSEQ obtém subsequências a partir das sequências extraídas pelo operador SEQ.

Na prática, o número de inserções nunca é maior do que um porque a cada instante a operação de extração de sequências (operador SEQ) vai receber no máximo uma nova tupla. Isto faz com que a complexidade do algoritmo IncConseq seja reduzida para O(zd).

A complexidade do algoritmo IncEndseq está relacionada com o custo das funções DeleteEndseq, InsertEndseq e NewEndseq. Com a ordenação da lista L, o custo da função DeleteEndseq é O(d). A função InsertEndseq tem o custo de O(n − d) para atualizar as sequências existentes uma vez que o algoritmo DeleteConseq já removeu d das n subsequências existentes. Já a construção das novas subsequências pela função NewEndseq tem o custo de O(i2). Assim, o custo Ąnal da função InsertEndseq é de O(n − d + i2). Logo, a complexidade do algoritmo IncEndseq é O(z × (d + n − d + i2)) = O(zn + zi2). Considerando novamente que o número máximo de inserções é um, esta complexidade passa a ser O(zn).

7.3 Algoritmos dos operadores MINSEQ e MAXSEQ

O processamento dos operadores MINSEQ e MAXSEQ é feito conforme mostrado no algoritmo FilterByLength (Algoritmo 30). O algoritmo consiste em varrer todas as sequências recebidas e veriĄcar o comprimento das mesmas. As sequências que não possuem comprimento válido de acordo com os parâmetros α e β são descartadas. A implementação do algoritmo usa um atributo especial para armazenar o comprimento da sequência, evitando assim a varredura de todas as posições da sequência para obter seu comprimento. Portanto, a complexidade do algoritmo FilterByLength é O(z), onde z = ♣Z♣ é o número de sequências recebidas.

Algoritmo 30 Ű F ilterByLength(Z)

1: Z← ¶♢ //Cria o conjunto Zpara armazenar as sequências a serem retornadas

2: for all s ∈ Z do //Para cada sequência s ∈ Z

3: if ♣s♣ é válido then //VeriĄca se s possui um comprimento válido 4: Z← Z∪ ¶s♢ //Adiciona s em Z

5: return Z′ //Retorna as sequências com tamanho válido

7.4 Algoritmos

dos

operadores

BESTSEQ

e

TOPKSEQ

No processamento dos operadores de preferência BESTSEQ e TOPKSEQ, assim como no processamento dos operadores de subsequência, foram consideradas duas aborda- gens: ingênua e incremental. A Seção 7.4.1 descreve a algoritmo ingênuo. Em seguida, o algoritmo incremental é explicado na Seção 7.4.2. Depois, a Seção 7.4.3 apresenta a análise de complexidade dos algoritmos.

7.4.1 Algoritmo ingênuo

O processamento ingênuo do operador BESTSEQ é feita por meio do algoritmo GetBestSeq (Algoritmo 31). Primeiro, o algoritmo copia as sequências recebidas para o conjunto Z. Em seguida, para cada par de sequências s e sde Z, o algoritmo testa se

s ≻Φ sou s′ ≻Φ s usando a função Dominates (Algoritmo 32). Ao Ąnal, as sequências dominadas são descartadas e somente aquelas que são dominantes permanecem em Z. O Apêndice B apresenta um exemplo de execução completo do algoritmo GetBestSeq.

A função Dominates realiza o teste de dominância entre duas sequências s e s′ de acordo com uma teoria-pct Φ. Primeiro, o menor tamanho entre as duas sequências recebidas é calculado e armazenado em j. Em seguida, a função varre as posições de 1 a j das sequências em busca da primeira posição não correspondente. Quando a posição

7.4. Algoritmos dos operadores BESTSEQ e TOPKSEQ 139

Algoritmo 31 Ű GetBestSeq(Φ, Z)

Entrada: Conjunto de sequências Z e teoria-pct Φ Saída: Sequências dominantes de Z

1: Z← Z //Copia as sequências recebidas para Z

2: for all s, s∈ Zdo //Para cada par de sequências s, sem Z

3: if Dominates(Φ, s, s) then //Testa se s ≻Φs

4: Z← Z− ¶s //Remove a sequência dominada sde Z

5: else if Dominates(Φ, s, s) then //Testa se s

Φs

6: Z← Z− ¶s♢ //Remove a sequência dominada s de Z

7: return Z//Retorna somente as sequências dominantes

não corresponde i é encontrada, todas as regras-pct de Φ válidas em s[i] e s[i] são usadas para criar a teoria-pc Γ.

A obtenção de uma regra-pc a partir de uma regra-pct φ consiste em remover os componentes temporais de φ conforme explicado no Capítulo 5. A teoria-pc Γ construída é usada então para comparar as tuplas s[i] e s[i] usando o algoritmo SearchDom (Algoritmo 1). O algoritmo SearchDom, apresentado no Capítulo 3, usa a técnica de busca em profundidade para comparar duas tuplas de acordo com uma teoria-pc. Desta maneira, o resultado da comparação das sequências s e sé o resultado da comparação das tuplas

s[i] e s[i]. O algoritmo Dominates retorna false, quando a posição de comparação não é encontrada.

Algoritmo 32 Ű Dominates(Φ, s, s)

Entrada: Teoria-pct Φ e duas sequências s e sSaída: true, se s domina s. Caso contrário, false

1: j ← min¶♣s♣, ♣s♣♢ //Obtém o tamanho j da menor sequência 2: for all i ∈ ¶1, ..., j♢ do //Percorre as posições de 1 a j das sequências 3: if s[i] ̸= s[i] then //Testa se posição atual é diferente nas sequências 4: Γ ← ¶♢ //Cria uma teoria-pc Γ vazia

5: for all φ ∈ Φ do //Para cada regra-pct φ de Φ

6: if ((s, i) ♣= Cφ) and ((s, i) ♣= Cφ) then //Testa se a posição i de s e ssatisfaz Cϕ

7: Γ ← Γ ∪ ¶φ //Adiciona a regra-pc φem Γ

8: return SearchDom(Γ, s[i], s[i]) //Testa se s[i] ≻

Γ s[i]

9: return false

O algoritmo GetTopkSeq (Algoritmo 33) realiza a processamento ingênua do ope- rador TOPKSEQ. Inicialmente, todas as sequências são movidas para o conjunto Z+. A cada iteração do laço de repetição, as sequências são separadas em dominantes (Z+) e dominadas (Z) por meio da função SeparateSequences (Algoritmo 34). As sequências dominantes são inseridas no Ąnal da lista L e as sequências dominadas são movidas para Z+ para que possam ser separadas novamente na próxima iteração.

A lista L armazena as sequências ordenadas de forma crescente pelo nível de preferência. Na primeira iteração, as sequências com nível zero são acrescentadas a lista, na segunda iteração, são acrescentadas as sequências com nível um e assim por diante.

Algoritmo 33 Ű GetTopkSeq(Φ, Z, k)

Entrada: Conjunto de sequências Z, teoria-pct Φ e inteiro k Saída: Top-k sequências de Z

1: Z+← Z //Copia as sequências recebidas para Z+

2: Z−← ¶♢ //Conjunto para armazenar as sequências dominadas

3: L ← NewList() //Lista para guardar as sequências ordenadas pelo nível 4: while (♣L♣ < k) and (♣Z+♣ > 0) do //Enquanto ♣L♣ < k e ♣Z+♣ > 0

5: Z+, Z← SeparateSequences(Z+, Φ) //Separa Z+ em dominantes e dominadas

6: L.append(Z+) //Acrescenta as sequências dominantes à lista L

7: Z+← Z//Move as sequências dominadas de Zpara Z+

8: return L.getFirst(k) //Retorna as primeiras k sequências de L

As iterações do laço terminam quando L possui, no mínimo, k sequências ou todas as sequências recebidas já se encontram em L. No Ąnal, o algoritmo retorna as primeiras k sequências de L.

A função SeparateSequences recebe os mesmos parâmetros e trabalha de forma semelhante ao algoritmo GetBestSeq. A diferença é que a função SeparateSequences retorna dois conjuntos disjuntos, um contendo as sequências dominantes e outro contendo as sequências dominadas.

Algoritmo 34 Ű SeparateSequences(Φ, Z) Entrada: Conjunto de sequências Z e teoria-pct Φ Saída: Sequências dominantes e dominadas de Z

1: Z+← Z //Copia as sequências recebidas para Z+

2: Z−← ¶♢ //Conjunto para armazenar as sequências dominadas

3: for all s, s∈ Z+ do //Para cada par de sequências s, sem Z+

4: if Dominates(Φ, s, s) then //Testa se s ≻

Φs

5: Z+← Z+− ¶s′♢ //Remove a sequência dominada sde Z+

6: Z← Z∪ ¶s′♢ //Adiciona sequência dominada sem Z

7: else if Dominates(Φ, s, s) then //Testa se s

Φs

8: Z+← Z+− ¶s♢ //Remove a sequência dominada s de Z+

9: Z← Z∪ ¶s♢ //Adiciona sequência dominada sem Z

10: return Z+, Z//Retorna sequências dominantes e dominadas

7.4.2 Algoritmo incremental

O processamento ingênuo dos operadores de preferência não usa qualquer informação do instante anterior. Isto pode causar a repetição desnecessária de testes de dominância. Por exemplo, em um instante, existem duas sequências s e stais que s ≻

Φ s′. Se, no instante seguinte, estas sequências não sofrerem qualquer alteração, a comparação já realizada prevalece a mesma. Os algoritmos incrementais foram criados para reduzir este tipo de problema.

O processamento incremental dos operadores de preferência utiliza uma estrutura de índice baseada em árvore chamada de árvore de sequências. Esta estrutura permite saber

7.4. Algoritmos dos operadores BESTSEQ e TOPKSEQ 141 onde duas sequências devem ser comparadas e também mantém hierarquias de preferências para as tuplas das sequências nas posições onde devem acontecer as comparações. A árvore de sequências possui uma raiz na profundidade zero. Começando na profundidade um, os nós da árvore passam a ser associados às tuplas das sequências. Seja s = ⟨t1, ..., tz⟩. Cada tupla ti de s é representada por um nó. A primeira tupla (t1) se torna um nó Ąlho da raiz. A partir de então, todo nó ti é pai do nó ti+1. A sequência s Ąca armazenada no último nó tn. O Exemplo 27 mostra como armazenar sequências em uma árvore de sequências.