Pointer Jumping = (V,E) : árvore direcionada odg(v) e idg(v): graus de saída e entrada do vértice v ∈ V ∃ um vértice r tal que T ∀ v ∈ V-{r}, odg(v) = 1, odg(r)=0 ∀ v ∈ V-{r}, ∃ um caminho de v a r O vértice r é dita raíz de T Pointer Jumping é uma técnica usada para processamento de dados armazenados em forma de um conjunto de árvores direcionadas enraizadas Pointer Jumping - árvore direcionada Problema F : floresta de árvores direcionadas enraizadas especificação: através de um vetor F de n elementos onde – F(i) = j se (i,j) ∈ E (é um arco) ⇒ j é o pai ou predecessor imediato de i – F(i) = i se i é a raiz Problema: determinar a raiz S(j) da árvore contendo o vértice j Solução Seqüencial - resolve o problema em tempo linear: identificação das raízes: achar todos os vértices v tal que F(v) = v em O(n) reversão dos arcos: pois estamos considerando que se (i,j) ∈ E então j é pai de i em O(n) execução de uma busca em profundidade ou largura: nesta busca, podemos saber a partir da raiz r quem são seus descendentes Solução Paralela Um algoritmo eficiente foi proposto, sendo um esquema totalmente diferente do esquema seqüencial inicialmente: ∀ i ∈ V, S(i) é o pai de i a técnica pointer jumping consiste em atualizar o sucessor de cada vértice pelo sucessor do sucessor – percorrendo desta maneira, corresponde a cada iteração chegar mais e mais próximo doa raiz da árvore – a cada iteração, a distância entre o vértice i e seu sucessor S(i) dobra – o ponto de parada: quando S(i) é a raiz procurada; Pointer Jumping 1 2 3 4 5 R Pointer Jumping início : S[1] = 2 S[2] = 3 S[3] = 4 S[4] = 5 S[5] = 5 1o passo: S[1] = 3 S[2] = 4 S[3] = 5 S[4] = 5 S[5] = 5 2o passo: S[1] = 4 S[2] = 5 S[3] = 5 S[4] = 5 S[5] = 5 3o passo: S[1] = 5 S[2] = 5 S[3] = 5 S[4] = 5 S[5] = 5 …….. k-ésimo passo: S[1] = raiz ⇒ d(1, S[1]) = 2k (término do Algoritmo) Pointer Jumping PointerJumping_Pp (){ S[p] = F[p]; While (S[p] != S[S[p]]{ S[p] := S[S[p]]; } } ler S[p], S[S[p]] ! em variáveis locais pai e avô Comparar as duas informações; Escrever avô em S[p]; Complexidade e Corretude do Algoritmo como podemos provar que o algoritmo está correto? simplesmente definimos um algoritmo e o executamos? – seja h a altura máxima de uma árvore qualquer na floresta de árvores enraizadas direcionadas – por indução em h Temos que analisar tal algoritmo, considerando a altura da maior árvore dentre as da floresta: domina o tempo de execução do algoritmo – cada passo j, definição de distância entre i e S[i] dj(i,S[j]) = 2dj-1(i,S[i]) – por indução em k: supondo verdade que dk-1(i,S[i]) = 2k-1 Complexidade e Corretude do Algoritmo – assim, no passo k dk(i,S[j]) = 2 dk -1(i,S[i]) = 2* 2k-1 – logo, por definição da distância máxima, tem-se h = 2k e assim, o número máximo de iterações é k = O(log h) em cada iteração, o tempo paralelo é O(1). Temos um total de O(log h) iterações. Ainda, o número de processadores é n o algoritmo paralelo não tem custo ótimo. Por que? é um algoritmo CREW PRAM Soma de Prefixos si = x1 ⊗ x2 ⊗ …. ⊗ xi saída: n elementos : s1, s2, …., sn Aplicações: concatenação de strings, soma, multiplicação, etc Algoritmo Seqüencial Soma_Prefixos_Sequencial( x){ s1 := x1 ; Para i = 2, …., n si = si-1 ⊗ xi ; } Complexidade: O(n) Soma de Prefixos Definição Seja X = { x1, x2, …., xn } e uma operação ⊗ binária e a operação ⊗ é fechada sobre X ou seja, se xi e xj são elementos de X então xi ⊗ xj também é a operação ⊗ é associativa Soma de Prefixos - pointer jumping representação dos elementos é feita através de uma árvore direcionada enraizada – cada vértice i da árvore tem um peso associado xi – pointer jumping é usado, armazenando as somas intermediárias a cada iteração – como várias árvores podem ser percorridas ao mesmo tempo, várias seqüências podem ser resolvidas ao mesmo tempo algoritmo para soma de prefixos: temos a informação de quem é pai do vértice i, ou seja, F[i] – em seqüência de n elementos F[i] = i+ 1, i = 1,…., n-1 – a árvore seria uma lista linear Soma de Prefixos - pointer jumping 5 4 3 5+4 4+3 3+2 5+4+3+2 4+3+2+1 3+2+1 5+4+3+2+1 2 2+1 1 0 Soma de Prefixos - pointer jumping Soma_Prefixo_PJ_Pp (){ S[p] = F[p]; sp[i] = x[i]; While (S[p] != S[S[p]]{ sp[p] = sp[p] + sp[S[p]]; S[p] := S[S[p]]; } } Implementação II – pointer junping através de threads, implementar a soma de prefixos de n números através da técnica do pointer jumping - em um número qualquer de processadores algum cuidado especial a ser tomado? Soma de Prefixo – outro paradigma si = x1 ⊗ x2 ⊗ …. ⊗ xi saída: n elementos : s1, s2, …., sn Paradigma: árvores binárias A[i] = xi B[h,j] e C[h,j] onde 1 ≤ j ≤ n/2h (1 ≤ h ≤ log n especifica o nível) ao final: sj = C[0,j] P1 B[0,1]=X1 P2 B[0,2]=X2 P3 P4 P5 B[0,3]=X3 B[0,4]=X4 B[0,5]=X5 P6 B[0,6]=X6 P7 P8 B[0,7]=X7 B[0,8]=X8 B[1,1]=B[0,1]+B[0,2] B[1,2]=B[0,3]+B[0,4] B[1,3]=B[0,5]+B[0,6] B[1,4]=B[0,7]+B[0,8] X1+X2 X3+X4 X5+X6 X7+X8 B[2,1]=B[1,1]+B[1,2] B[2,2]=B[1,3]+B[1,4] X1+X2+x3+x4 X5+X6+x7+x8 B[3,1]=B[2,1]+B[2,2] X1+X2+...+x7+x8 C[3,1]=B[3,1] X1+X2+...+x7+x8 C[2,1]=B[2,1] C[2,2]=C[3,1] X1+X2+x3+x4 X1+X2+...+x7+x8 C[1,1]=B[1,1] C[1,2]=C[2,1] C[1,3]=C[2,1]+B[1,3] C[1,4]=C[2,2] X1+X2 X1+X2+X3+X4 X1+X2+...+X5+X6 X1+X2+...+X7+X8 C[0,1]=B[0,1] C[0,2]=C[1,1] C[0,3]=C[1,1]+B[0,3] C[0,4]=C[1,2] C[0,5]=C[1,2]+B[0,5] C[0,6]=C[1,3] C[0,7]=C[1,3]+B[0,7] C[0,8]=C[1,4] X1 X1+X2 X1+X2+X3 X1+X2+X3+X4 X1+X2+X3+X4+X5 X1+X2...X5+X6 X1+X2+...+X6+X7 X1+X2...X7+X8 Soma de Prefixos Não Recursivo Algoritmo Paralelo não Recursivo Soma_Prefixos_Paralela_nRecursivo( A ){ 1. Para 1 ≤ i ≤ n faça em // : B[0,j] := A[j]; 2. Para 1 ≤ h ≤ log n faça 2.1 2.1.1 Para 1 ≤ j ≤ n/2h faça em // B[h,j] := B[h - 1, 2j-1] * B[h - 1, 2j]; 3. Para h = log n … 0 faça 3.1 Para 1 ≤ j ≤ n/2h faça em // 3.1.1 3.1.2 se j é par, então C[h,j] := C[h + 1,j/2]; se j == 1, então C[h,1] := B[h,1]; 3.1.3 se j é ímpar, então C[h,j] := C[h + 1,(j-1)/2] * B[h,j]; } Princípio de Brent tempo de execução do algoritmo // A para P(n) processadores: T(n) w operações do algoritmo A tempo paralelo do algoritmo considerando p processadores de acordo com o princípio de Brent: Tp(n) = w/p + T Aplicação do Princípio necessário saber quantas operações são executadas a cada passo algoritmo de soma de prefixos com n = 2k - número de passos: 2log n + 2 ⇒ 2k+2 – qual o número de operações? – qual o custo? Princípio de Brent w1,1 : número de operações no passo 1 considerando o único loop w2,m : número de operações executadas no passo 2 na m-ésima iteração w3,m : número de operações executadas no passo 3 na m-ésima iteração Então: w1,1 = n w2,m = n/2m = 2k /2m para 1 ≤ m ≤ k w3,m = 2m para 0 ≤ m ≤ k Assim: w = w1,1 + ∑ w2,m + ∑ w3,m w = n + ∑ n/2m + ∑ 2m w = n + n(1-1/n) + 2n-1 = 4n-2 w = O(n) Divisão e Conquista usada quando identificamos problemas que podem ser particionados em subproblemas menores, que são mais simples de serem resolvidos – divisão da entrada em partições menores de mesmo tamanho (ou quase) – resolução recursiva de cada subproblema definido por cada partição – combinação das soluções de cada subproblema, produzindo a solução do problema como um todo tende a ser eficiente se a decisão e resolução podem ser feitas recursivamente eficiente no mundo seqüencial natural na exploração de paralelismo Divisão e Conquista Problema da Envoltória Convexa Seja S = { p1 , p2 , …. , pn } um conjunto de n pontos em um plano, cada um representado por suas coordenadas (xi, yi). A envoltória convexa planar de S é o menor polígono convexo que contém todos os pontos de S observação: um polígono é convexo quando, para qualquer dois pontos, (xi, yi) ≤ (xj, yj), a reta [(xi, yi),(xj, yj)] está dentro do polígono. o problema: determinar a lista ordenada de pontos S que formam o polígono convexo. Essa lista será denotada por CH(S) (convex hull). Divisão e Conquista Problema da Envoltória Convexa é um problema muito importante em geometria planar: – estatística – processamento de imagem – reconhecimento de padrões – computação gráfica – problemas geométricos resolvido sequencialmente através de divisão e conquista O(n log n) – o algoritmo de ordenação de pontos resolve esse problema mais eficientemente Divisão e Conquista Paralelo Dado um conjunto S de n pontos, sejam: p ∈ S o ponto com o menor xi q ∈ S o ponto com o maior xj ordenação paralela: em O(log n) em uma PRAM EREW com O(n log n ) operações particionam CH(S) em: envoltório superior UH(S) = < todos os pontos de p a q pertencentes a CH(S) seguindo o sentido horário > envoltório inferior LH(S) = < todos os pontos de q a p pertencentes a CH(S) seguindo o sentido horário > O Problema da Envoltória Convexa CH(S) envoltória superior UH(S) S p q envoltória inferior LH(S) Divisão e Conquista Paralelo p q Merging de duas envoltórias superiores p q Merging de duas envoltórias superiores Tangente Comum Superior • sequencial – O(log n) • busca binária p q Algoritmo Entrada: n pontos ordenados tais que x(p1) < x(p2) < .... < x(pn) Saída: UH(S) 1) 2) 3) 4) 5) 6) Se n <= 4 então ache UH(S) por força bruta e retorne S1 = (p1, ..., pn/2) e S2 = (pn/2+1, pn). Compute UH(S1) e UH(S2) em paralelo, recursivamente Ache a tangente comum superior entre UH(S1) e UH(S2) e defina UH(S) O(1) T(n/2) TCS(UH(S1), UH(S2)) em O (log n) Combinar as duas curvas dada a tangente produzindo S – em O(1) com n processadores ! leituras concorrentes serão realizadas. Implementação III – divisão e conquinta implementar o problema da envoltória convexa (coletar na internet um algorithmo da tangente comum superior Explicar: – ComplexidadeT(n) = O(log2 n) com O(n) processadores Qual o número de operações? Lista de Exercícios (1) Compare as diferenças entre o seguinte código executado numa máquina SIMD versus executado num sistema SPMD. gcd (x,y): {Calcula o maior divisor comum entre x e y} enquanto (x != y) faça se x>y então x:= x-y ; senão y := y-x; Suponha que diferentes valores de X e Y sejam difundidos para 100 processadores e o resultado deste cálculo seja os 100 maiores divisores comuns de (X,Y). Tente para dois processadores com os seguintes valores: X = (52,24) e Y = (12,64). Lista de Exercícios Exercícios do Capítulo 1, livro do Jájá Exercícios 1.5, 1.6, 1.7, 1.12 Exercícios do Capítulo 2 Exercícios 2.3, 2.6, 2.7, 2.12, 2.13, 2.14, 2.17 - discutir o algoritmo do convex hull problem, qual seriam os detalhes de implementação 2.21 - sobre partitioning 2.38- sobre symetry breaking