Você está na página 1de 13

Computação Paralela e a Classe N C

Daniel Saad Nogueira Nunes 06/81792


29 de novembro de 2009

Resumo
Esse documento visa apresentar aspectos introdutórios da teoria de
complexidade da computação paralela bem como modelos computacionais
razoáveis e uma discussão acerca da questão da P-Completude e a classe
de complexidade N C

1
Sumário
1 Introdução 3
1.1 Multiplicação de Matrizes Quadradas . . . . . . . . . . . . . . . . 3
1.2 Menor Caminho Entre Qualquer Par de Vértices . . . . . . . . . 4
1.3 Princı́pio de Brent . . . . . . . . . . . . . . . . . . . . . . . . . . 6

2 Modelos Computacionais 7
2.1 Modelo PRAM . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
2.2 Modelo de Circuitos Booleanos . . . . . . . . . . . . . . . . . . . 8

3 Complexidade Computacional 10
3.1 Classe N C . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
3.2 Redução . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
3.2.1 Redução Many-One . . . . . . . . . . . . . . . . . . . . . 10
3.2.2 Redução do tipo Turing . . . . . . . . . . . . . . . . . . . 11
3.2.3 P-Completude . . . . . . . . . . . . . . . . . . . . . . . . 11
3.3 Relação Tempo-Espaço . . . . . . . . . . . . . . . . . . . . . . . . 11
3.3.1 Parallel Computation Thesis (PCT) . . . . . . . . . . . . 12
3.4 Problemas Inerentemente Sequenciais . . . . . . . . . . . . . . . . 12
3.4.1 Problema P-Completo Genérico . . . . . . . . . . . . . . . 12
3.4.2 Circuit Value Problem (CVP) . . . . . . . . . . . . . . . . 12

2
1 Introdução
A essência da computação paralela está na busca de se obter um menor tempo
entre o começo e o fim da computação de algum problema. Comparado com
algum modelo sequencial de computação isso parece o tanto quanto óbvio, mas
a computação paralela é bem mais do que tentar obter uma simples diminuição
do tempo necessário para resolver algum problema sequencial, o grande in-
teresse do estudo da complexidade computacional paralela, está em obter uma
diminuição exponencial do tempo necessário para resolver esse mesmo problema
e reconhecer os limites da mesma.
Por exemplo, seja A1 um algoritmo que resolve um problema sequencial
em O(n), suponha que um algoritmo A2 foi projetado para resolver o mesmo
problema, só que esse algoritmo foi projetado para um modelo de computação
paralelo, e resolve esse problema em O(n) também, possı́velmente o algoritmo
A2 será mais rápido que o algoritmo A1 quanto ao tempo de execução, no en-
tando não será assintoticamente mais rápido, o tempo para resolver o problema
continua linear na ordem de entrada.
Um resultado mais interessante seria o projeto de um terceiro algoritmo A3
que resolve o mesmo problema também em algum modelo computacional par-
alelo, mas que leva da ordem de O((log(n))O(1) ) no tamanho n da entrada, isso
iria refletir numa diminuição exponencial na quantidade de passos necessários,
em termos assintoticos, para resolver o mesmo problema. Esse é o tipo de
resultado em que o estudo da computação paralela almeja alcançar.

1.1 Multiplicação de Matrizes Quadradas


Para ilustrar o projeto de algoritmos paralelos tome o problema da multiplicação
de matrizes quadradas .Esse problema consiste em multiplicar uma matriz A ∈
Rnxn por uma matriz B ∈ Rnxn resultando em uma matriz C ∈ Rnxn .
Um algoritmo sequencial conhecido resolve esse problema em Θ(n3 ), para
isso ele toma cada elemento ci,j da matriz C e o coloca dependente do seguinte
produto escalar.
n
X
ci,j = ai,k · bj,k (1)
k=1

Esse algoritmo é claramente da ordem de Θ(n3 ) visto que existem n2 pro-


dutos escalares, e cada produto escalar leva da ordem de Θ(n) para realizar o
seu trabalho. Assintoticamente existem algoritmos melhores como o algoritmo
de Strassen O(nlog2 7 ), mas o exemplo será dado no algoritmo inicialmente ap-
resentado.
O possı́vel projeto de um algoritmo paralelo para resolver o mesmo problema
[4], é tomar n3 processadores, cada processador fica responsável por produzir
o resultado de um produto ai,k · bj,k . Nesse ponto todos os produtos foram
resolvidos em O(1). Mas ainda é necessário fazer o somatório dos produtos
para cada elemento ci,j . Um algoritmo ingênuo para fazer isso é tomar n2 dos
processadores e alocar um para cada somatório.
n
X
Pi,j,1 = ai,k · bj,k (2)
k=1

3
Dessa forma esse algoritmo de multiplicação de matrizes leva Θ(n) passos
paralelos, usando de Θ(n3 ) processadores. É um resultado bom se comparado
com o algoritmo sequencial que levava Θ(n3 ), mas não é uma redução expo-
nencial do tempo no tamanho da entrada. Para obter tal redução é necessário
somar os produtos de uma maneira esperta.
Tal maneira esperta pode ser feita usando uma árvore de adições, desse
modo a soma levará log n + 1 passos paralelos para a execução. Deixando assim
o algoritmo de multiplicação de matrizes levando Θ(log n) passos paralelos para
computar o problema da multiplicação de matrizes quadradas, um decaimento
exponencial se compararmos com a cota antiga de Θ(n).

P0

P1 P2

+
..
.
P3 P4 ...

..
.

Figura 1: Árvore de adições entre os processadores

1.2 Menor Caminho Entre Qualquer Par de Vértices


O problema de encontrar o menor caminho entre quaisquer par de vértices de
um grafo, G = (V, E) tal que |V | = n, está em P, o algoritmo de Floyd-Warshall
resolve o problema em O(|V |3 ) usando de programação dinâmica.
Uma outra abordagem pode ser feita para resolver o mesmo problema de
maneira eficiente em paralelo a partir de uma idéia sequencial de uma maneira
indutiva [9].
(m)
Definição 1.2.1 Seja li,j o custo do caminho de menor peso que leva o vértice
i ao vértice j, m representa que esse caminho contém no máximo m elos.
O caso base é quando m = 0, o custo de um vértice i para ele mesmo é 0,
já o custo de um vértice i para um vértice j, com i 6= j é infinito, visto que o
caminho tem que ter zero arestas.

(0) 0, i = j
li,j = (3)
∞, i 6= j

4
(m)
O passo de indução consiste que li,j , isto é, o caminho de menor custo de i
m−1
a j pode ser obtido em função de li,j , pois um sub-caminho de um caminho
ótimo tem que ser ótimo também, e do peso da aresta dos nós adjacentes a j
que estão no sub-caminho ótimo. Então temos o seguinte resultado
 
(m−1)
li,j = min li,k + wk,j (4)
1≤k≤n

Ou seja, o caminho de menor custo de i à j é aquele que minimiza os sub-


caminhos com m − 1 elos e o peso dos predecessores de i.
Representando li,j por uma matriz de adjancências, teremos que o resultado
(n−1)
de todos os menores caminhos estarão em li,j , visto que um caminho que
contém v vértices tem que ter v − 1 arestas.
Mas a substituição dos seguintes termos da equação 4 da seguinte maneira

l(m−1) → a
w→b
l(m) → c
min → +
+→·

Chegaremos na equação 1, de multiplicação de matrizes, logo o problema do


menor caminho para os pares, pode ser resolvido por sucessivas “multiplicações”
de matrizes, onde a operação de soma corresponde a operação min da seguinte
maneira:
Seja Wi,j a matriz de adjacencias representando o valor da aresta e = {i, j},
ou seja 
 0, i = j
W = f (e), e = {i, j} , ou seja, o custo da aresta (5)
∞, e = {i, j} ∈ /E

E substituindo 0 (identidade da soma),por ∞ (identidade da operação min)


temos:
(x) (x−1)
li,j = li,j · W, x ∈ {1, . . . , n − 1} (6)
4
O que leva um tempo total de Θ(|V | ).
(v−1)
Mas é fácil ver que o resultado se encontra apenas em li,j , portanto
podemos fazer a “multiplicação” de uma maneira mais rápida, basta ver que
(1) (1) (n−1) d(log(n−1))e−1
Li,j = W , Li,j = W 2 = W · W , . . . , Li,j = W2 . Ou seja,
as matrizes são obtidas elevando o resultado anterior ao quadrado. Portanto,
para obter o resultado, precisamos de apenas dlog(n − 1)e multiplicações de
matrizes, fazendo com que o custo para resolver o problema seja reduzido para
Θ(n3 log n).
Em paralelo, temos que o custo de multiplicar matrizes pode ser obtido com
Θ(log n) passos paralelos, portanto, o algoritmo de menores caminhos entre qual-
quer par de vértices leva Θ(log2 n) passos paralelos, usando n3 processadores.
O fechamento transitivo de um grafo também é obtido de forma semelhante,
apenas por uma troca de operações também na multiplicação de matrizes [4].

5
1.3 Princı́pio de Brent
Definição 1.3.1 A quantidade de trabalho W (n) feita por um algoritmo par-
alelo é definido como a soma da quantidade de operações feitas por todos os
processadores durante a computação.

Como um algoritmo paralelo pode ser simulado com uma máquina com p
processadores, temos que o tempo necessário para execução do algoritmo em
paralelo é dada pela seguinte relação:

W (n)
T (n) ≤ b c + S(n) (7)
p(n)
Onde p(n) descreve o número de processadores em função da entrada, e
S(n) descreve a quantidade de passos paralelos necessários para a execução do
algoritmo e T descreve o tempo necessário para a execução do algoritmo.
Portanto é possı́vel estabelecer uma cota inferior de processadores à serem
usados em determinado , por exemplo, no algoritmo de multiplicações de ma-
trizes o custo total de trabalho foi de Θ(n3 ) visto que temos n2 produtos es-
calares. Logo para T = O(log n), a cota antiga e analisando 7, precisarı́amos de
n3
no mı́nimo Ω( log n ) processadores, visto que S(n) = O(log n).
Além disso, pelo mesmo motivo, dizemos que uma máquina sequencial pode
emular o algoritmo paralelo, portanto:

T (n)sequencial ≤ T (n)paralelo × p(n) (8)

Portanto , se o tempo sequencial for super-polinomial, só conseguiremos


um tempo paralelo poli-logaritmo se o número de processadores for super-
polinomial, e isso não corresponde a um modelo razoável de computação par-
alela.

6
2 Modelos Computacionais
Para falar de computação paralela e classes computacionais que abrangem os
problemas solúveis em paralelo de uma maneira eficiente, é necessário se basear
em algum modelo razoável de computação.
Os modelos, em geral, se diferenciam por dois grandes fatores. O nı́vel
de tratamento de operações, isto é, um modelo que trate operações bit a bit
como unidade básica de operação é mais rigoroso do que um modelo que trata
operações de mais alto nı́vel como exponenciação por exemplo como unidade
básica de operação.
O outro fator é como os recursos do modelo computacional paralelo se co-
municam, se permitirmos uma comunicação muito poderosa, modelos de com-
putação mais relaxados no aspecto comunicação poderão não conseguir simular
o modelo mais poderoso por um fator polinomial.

2.1 Modelo PRAM


O modelo PRAM1 é a versão paralela do modelo RAM, este modelo abstrai
o custo de comunicação entre os processadores, ou seja, não se considera uma
possı́vel topologia em que os processadores se organizam, além disso abstrai
alguns outros fatores como sincronização entre os processadores. Tal modelo
fornece uma visão de alto nı́vel, o que facilita a análise de algoritmos, o modelo
é bastante intuitivo e foi usado implicitamente nos algoritmos da multiplicação
de matrizes e menor caminho entre quaisquer par de vértices, descritos anteri-
ormente.

Definição 2.1.1 Uma máquina PRAM é uma coleção de máquinas RAM, cada
RAM consiste de uma fita de entrada só de leitura, uma fita de saı́da, um número
infinito de células de memória. Um programa RAM é uma sequência finita de
instruções como LOAD, STORE, ADD, etc . . . A computação em uma RAM
acaba quando esta encontra a instrução HALT, uma definição mais completa do
modelo RAM se encontra em [4],[1],[9]. Como visto, uma PRAM consiste em p
processadores RAM. Além disso esse modelo possui um conjunto de células de
memória compartilhada.

Definição 2.1.2 A computação em uma PRAM é feita da seguinte maneira,


uma entrada w ∈ Σ? é colocada na memória compartilhada. Inicialmente so-
mente o processador P0 está ativo, e este pode ativar outros processadores. Mas
o modelo retringe a quantidade de processadores ativos, isto é, não podemos ter
uma ativação de um número super-polinomial de processadores em um tempo
polinomial. Quando o processador P0 encontra a instrução HALT a computação
em todos os processadores para,e o resultado da computação w0 se encontra
também na memória compartilhada.

Variações do modelo PRAM se distinguem quanto ao acesso à memória com-


partilhada, dentre elas podemos citar.

• CRCW-PRAM2 : Esse modelo permite escrita e leitura simultânea de uma


célula de memória por diversos processadores RAM.
1 Parallel Random Access Machine
2 Concurrent-read concurrent-write

7
• CREW-PRAM3 : Esse modelo permite leitura simultânea, mas apenas se
permite que um processador escreva na célula de memória compartilhada.

• CROW-PRAM4 : Esse modelo permite leituras simultâneas,no mais cada


célula de memória compartilhada tem um determinado processador como
dono, e só ele pode escrever na mesma.
• EREW-PRAM5 : Não se pode ter 2 ou mais processadores acessando (lendo
ou escrevendo) a mesma célula de memória compartilhada.

Todas essas variações são polinomialmente equivalentes, isto é, se o modelo


P1 computa em t(n) o modelo P2 computa em t(n)O(1) , ambos usando um
número polinomial de processadores.

2.2 Modelo de Circuitos Booleanos


O modelo PRAM é um bom modelo para analisar algoritmos, pois ele abstrai
muitos obstáculos como dito anteriormente. No entanto é necessário, para um
estudo mais aprofundado, um modelo um pouco mais próximo da realidade,
mais próximo da implementação.
A nı́vel de comparação, para combinar b bits em uma PRAM , é possı́vel
fazer em O(1), no entanto, no modelo de circuitos booleanos, se limitarmos o
número de entradas nas portas lógicas em dois, conseguiremos combinar b bits
em Ω(log b), temos uma visão em um nı́vel de abstração mais baixo do que o
modelo PRAM forneceu.

Definição 2.2.1 Um circuito booleano α é definido como um grafo rotulado,


direcionado e acı́clio. Cada vértice do grafo possui um determinado tipo τ ∈
{I, B0 , B1 , B2 }. Um vértice v, cujo τ (v) = I e tem grau de entrada ( in-degree)
0 é denominado de entrada ( input), um vértice cujo grau de saı́da é zero ( out-
degree) é chamado de saı́da ( output), um vértice cujo tipo τ (v) = Bi é chamado
de porta ( gate) e tem que ter grau de entrada igual a i. [1]

Definição 2.2.2 O conjunto de funções lógicas que atuam sobre o circuito é


definido como Bk = {f |f : {0, 1}k → {0, 1}}

Definição 2.2.3 A computação no modelo de circuitos booleanos segue da seguinte


maneira: É dado uma tupla Tin = (v1 , v2 , . . . , vn ) de entradas e uma tupla de
saı́da Tout = (v10 , v20 , . . . , vm
0
). Para cada vértice vi da tupla Tin é atribuı́do um
valor ν(vi ) = x ∈ {0, 1}. A computação é dada de tal forma que os valores dos
demais vértices são atribuı́dos olhando para a função lógica associada ao vértice
e pelos valores vindos vértices que aumentam o grau de entrada do mesmo. O
final da computação f {0, 1}n → f {0, 1}m se encontra nos valores obtidos nas
saı́das do circuito.

Definição 2.2.4 O tamanho do circuito α é definido pela cardinalidade de


vértices em α. Já a profundidade do circuito α é definido como sendo o maior
caminho de um vértice de entrada à um vértice de saı́da.
3 Concurrent Read Exclusive Write
4 Concurrent-read owner-write
5 Exclusive-read exclusive-write

8
Portanto um determinado circuito α faz uma computação de f {0, 1}n à
f {0, 1}m , no entanto isso não representa a noção de algoritmo, que têm que
aceitar um tamanho genérico da entrada. Então precisamos do conceito de
famı́lia de circuitos.

Definição 2.2.5 Uma famı́lia de circuitos {αn } é uma coleção de circuitos αi ,


cada um computando a função f i : {0, 1}i → {0, 1}m(i) .

Descrever uma função de circuitos requer uma atenção especial, pois se não
for colocada alguma restrição, tal coleção pode “computar” funções não com-
putáveis [1], então devemos restringir o poder de construção de circuitos, isto
é, a construção de um descrição de circuitos, feita por um determinado modelo,
não pode ter mais poder computacional do que esse mesmo modelo.
Por exemplo, se a descrição de uma famı́lia de circuitos for construı́do por
uma máquina de Turing Mt que se limita a usar O(log n) de espaço no tamanho
da entrada, a famı́lia descrita não terá mais poder computacional que a máquina
Mt . Informalmente isso corresponde ao conceito de uniformidade introduzido
por Allan Borodin [11].
Portanto ajustando diferentes construtores de poderes diferentes, poderemos
criar descrições das famı́lias com poder computacional diferente.

9
3 Complexidade Computacional
3.1 Classe N C
A classe dos problemas N C é a classe dos problemas que podem ser resolvidos em
tempo polilogaritmo (log n)O(1) usando um número polinomial de processadores
nO(1) no modelo PRAM.
A classe N C também pode ser definida como as linguagens decidı́veis por
um circuito booleano de profundidade (log n)O(1) e de tamanho nO(1) .

Definição 3.1.1 A classe N C é expressa como a união das classes N C k , k ∈ N,


ou seja [
NC = N Ck (9)
k∈N

O modelo de circuitos booleanos é mais robusto quanto às sub-classes N C k


do que o modelo PRAM, isto é, para determinado valor de k a subclasse N C k
pode ser diferente em variações do modelo PRAM.

Definição 3.1.2 As sub-classes de complexidade computacional N C k são definidas


como o conjunto de linguagens aceitas por uma famı́lia de circuitos booleano de
profundidade O(logk n) e tamanho nO(1) .

Informalmente N C é a classe dos problemas que possuem uma solução efi-


ciente (assintoticamente) em paralelo.

3.2 Redução
Definição 3.2.1 Uma redução é um meio de converter um determinado prob-
lema A à outro determinado problema B de forma que se a solução do problema
B for conhecida, podemos usá-la para resolver o problema A.

A redução entre problemas pode ser usada para explorar a complexidade


envolvendo os mesmos problemas e também explorar a diferença entre classes
de complexidade computacional.

3.2.1 Redução Many-One


A redução Many-One é uma forma de mapear um problema A em outro prob-
lema B de tal forma que ao resolver B conseguimos obter a resposta para A,
formalmente isso seria equivalente à seguinte definição.

Definição 3.2.2 Uma função f : Σ? → Σ? é uma função computável se existe


uma máquina de Turing Mt = (Q, Σ, Γ, δ, q0 , F ⊆ Q) que para cada entrada
w ∈ Σ? , a máquina pára com f (w) escrita na fita.

Definição 3.2.3 Dada duas linguagens A e B, dizemos que A se reduz a B


se existe uma função computável f : Σ? → Σ? de tal forma que, ∀w ∈ Σ? , w ∈
A ⇔ f (w) ∈ B [10].

Definição 3.2.4 Caso A se reduza à B pela redução Many-One, representamos


por A ≤m B.

10
f : Σ ? → Σ?
A B

Figura 2: Redução Many-One entre problemas

3.2.2 Redução do tipo Turing


3.2.3 P-Completude
Teorema 3.2.1 Tanto a redução do tipo Turing quando a redução many-one
são fechadas nas classes P e N C [1].
Definição 3.2.5 Seja C uma classe de complexidade. Dizemos que L é C-
completa se qualquer L0 ∈ C se reduz a L e L ∈ C [4].
Segundo a definição 3.2.5 é fácil ver que:
Definição 3.2.6 Seja L ∈ P, L é P-completa se, e somente se toda linguagem
L0 ∈ P se reduz à L.

3.3 Relação Tempo-Espaço


O primeiro problema P-completo, Path Systems, foi anunciado por Cook [8].
A motivação era responder se uma máquina de turing que decide em tempo
polinomial conseguiria decidir usando (log n)O(1) células de memória, ou seja,
a motivação para estudar os problemas P-completos surgiu muito antes com o
estudo do espaço polilogarı́timico do que com os conceitos de tempo paralelo.
Para tentar responder tal questão, se utilizava de uma técnica de redução
espacial, de tal forma que a função de redução não levava mais de SP ACE(log n)
para fazer a transformação.
Não se sabe dizer também se a classe dos problemas que estão em P podem
ser solúveis usando O(log n) células de espaço (classe L). Para ilustrar a situação
entre espaço e tempo temos o seguinte teorema.
Teorema 3.3.1 Reachability Method
Para uma função f(n) adequada:
I) SP ACE(f (n)) ⊆ N SP ACE(f (n))
II) T IM E(f (n)) ⊆ N T IM E(f (n))
III) N T IM E(f (n)) ⊆ SP ACE(f (n))
IV ) N SP ACE(f (n)) ⊆ T IM E(k log n+f (n) )

11
Do teorema 3.3.1 temos o seguinte resultado.

N C1 ⊆ L ⊆ N L ⊆ N C2 ⊆ N C ⊆ P
A demonstração da primeira e terceira inclusão se encontra em [4].
Portanto, de fato se tivermos que o resultado L = P, teremos também que
N C = P.

3.3.1 Parallel Computation Thesis (PCT)

3.4 Problemas Inerentemente Sequenciais


O termo inerentemente sequêncial surgiu do trabalho de John Reif [5], tal termo
remete aos problemas dı́ficeis de paralelizar eficientemente. Formalmente pode-
mos definir que um determinado problema é inerentemente sequencial caso não
se conheca uma solução para o mesmo que esteja em N C.
Os problemas P-completos capturam a dificuldade dos problemas da classe P
visto que, se algum problema P tenha solução em N C então todos os problemas
de P estão em N C. Ou então, se mostrarmos que um problema P-completo não
pode ser solucionado de uma maneira eficiente em paralelo, estaremos mostrando
que P 6= N C. Portanto analisar os problemas P-completos é um caminho para
?
responder a questão P = N C.

3.4.1 Problema P-Completo Genérico


3.4.2 Circuit Value Problem (CVP)

12
Referências
[1] Limits to Parallel Computation: P-Completeness Theory RAY-
MOND GREENWLAW, H. JAMES HOOVER, WALTER L. RUZZO
[2] Introduction to Automata Theory, Languages, and Computation
JOHN E. HOPCROFT, RAJEEV MOTWANI, JEFFREY D. ULLMAN
[3] Parallel Complexity Theory IAN PARBERRY
[4] Computacional Complexity CHRISTOS H. PAPADIMITRIOU

[5] Depth-First Search Is Inherently Sequential JOHN H. REIF


[6] Parallel Computing PRAM algorithms SIDDHARTHA CHATTER-
JEE, JAN PRINS
[7] Modelo Computacional e Redução Entre Problmas PEDRO J. DE
REZENDE

[8] An observation on time-storage trade off S. A. COOK


[9] Introduction to Algorithms THOMAS H. CORMEN, CHARLES E.
LEISERSON, RONALD L. RIVEST, CLIFFORD STEIN
[10] Introduction To The Theory Of Computation MICHAEL SIPSER

[11] On Relating Time And Space To Size and Depth ALLAN


BORODIN

13

Você também pode gostar