A computação é uma tarefa que consome recursos.
Os recursos que mais usualmente são considerados são o tempo (a duração da computação) e o espaço (uma medida da informação que é armazenada/consumida durante a computação), mas também é possível considerar outras quantidades, como a energia (necessária para executar a computação).
A complexidade computacional consiste no estudo dos recursos necessários para resolver um problema.
Podemos calcular a eficiência de uma máquina de Turing (que seja um classificador) relativamente ao tempo e ao espaço de forma relativamente simples, se tomarmos o número de passos de cada computação como uma medida do tempo, e o número de células de memória lidas/escritas ao longo de cada computação como uma medida de espaço.
Definição
Para uma máquina classificadora M definimos as funções timeM,spaceM:N→N da seguinte forma:
timeM(n) é o comprimento máximo - ou seja, o número de passos máximo - de uma computaçao de M sobre um input ω com ∣ω∣≤n;
spaceM(n) é o número máximo de células de memória lidas/escritas durante uma computação de M sobre um input ω com ∣ω∣≤n.
Para cada n∈N, timeM(n) e spaceM(n) dão-nos uma avaliação do pior caso, em termos de duração da computação ou da quantidade de memória necessária, respetivamente, para processar inputs de tamanho limitado por n.
Mais do que a expressão exacta das funções timeM e spaceM associadas a um classificadora M, estamos interessados em avaliar o seu crescimento. Por essa razão é usual usar notação assintótica, nomeadamente a notação O (como visto em cadeiras anteriores como IAED ou ASA).
Classes de Complexidade
Agrupamos problemas, de acordo com a sua dificuldade relativa, em classes de complexidade.
Definição
Seja f:N→R0+ uma função. Definem-se as seguintes classes de linguagens:
TIME(f(n))={L: existe uma maˊquina M que decide L com timeM(n)=O(f(n))};
SPACE(f(n))={L: existe uma maˊquina M que decide L com spaceM(n)=O(f(n))};
Em certas áreas de estudo, são consideradas como eficientes as máquinas cujo comportamento é limitado por um polinómio.
Por outro lado, o protótipo das máquinas ineficientes é precisamente o crescimento exponencial.
Estas considerações levam à definição das seguintes classes de complexidade:
Definição
Definem-se as seguintes classes de linguagens, em relação ao tempo:
P=⋃k∈NTIME(nk);
EXPTIME=⋃k∈NTIME(2nk).
analogamente, para o espaço, definimos
PSPACE=⋃k∈NSPACE(nk);
EXPSPACE=⋃k∈NSPACE(2nk).
Relação entre função tempo e espaço
Para uma máquina classificadora M, tem-se que timeM e spaceM são funções monótonas e, para qualquer, n∈N:
spaceM(n)≤timeM(n)
timeM(n)≤2O(spaceM(n)).
Prova
O facto de as funções timeM e spaceM serem monótonas segue da definição.
(1) A primeira propriedade vem apenas do facto de que, para escrever numa célula de memória de memória, é necessário deslocarmo-nos para essa célula.
Desta forma, o número de passos de uma computação é pelo menos igual ao número de células escritas.
(2) Considere-se a computação da máquina de Turing M com alfabeto de trabalho Γ e conjunto de estados Q, sobre um input de comprimento menor ou igual a n.
Temos que M é classificadora pelo que a sua computação termina sempre.
Verificamos que a computação de M não pode passar duas vezes pela mesma configuração: se isto acontecesse, a máquina entraria em ciclo infinito uma vez que todas as transições são deterministas.
Sendo assim, o tempo que a máquina demora a fazer a sua computação está majorado pelo seu número de configurações.
Seja m=spaceM(n).
Temos então que o número de configurações é definido por:
o conteúdo na fita, que é no máximo ∣Γ∣m;
a posição da cabeça de leitura/escrita, que pode estar numa de m posições;
o estado em que a computação se encontra, que é um de ∣Q∣.
Desta forma, o número de estados é majorado por ∣Γ∣m×∣Q∣×m.
Então:
Toda a máquina de Turing M com transições-S é equivalente a uma máquina de Turing T sem transições-S tal que timeT(n)=O(timeM(n)) e spaceT(n)=O(spaceM(n))
Prova
Na prova da equivalência, simulamos todos os movimentos-S com um movimento à direita seguido de um movimento à esquerda.
Temos então que cada movimento em M corresponde no máximo a dois movimentos em T pelo que
timeT(n)≤2timeM(n)=O(timeM(n))
spaceT(n)≤spaceM(n)+1=O(spaceM(n))
Bidirecional
Proposição
Toda a máquina bidirecional M é equivalente a uma máquina unidirecional T tal que timeT(n)=O(n+timeM(n)2) e spaceT(n)=O(spaceM(n))
Prova
Vamos basear-nos na prova de equivalência apresentada no capítulo de Máquinas de Turing.
A computação de T começa por balizar o input com os símbolos I e F, fazendo 2n+3 passos.
O resto da computação é idêntica a M, exceto nos casos em que é necessário introduzir espaçamento.
Para introduzir espaço à direita precisamos apenas de 3 movimentos, enquanto que à esquerda precisamos de copiar a palavra toda, o que implica O(spaceM(n)) passos.
No final há que apagar o delimitador F, o que demora O(spaceM(n)).
Na pior das hipóteses, temos que é preciso abrir espaço à esquerda em cada passo, pelo que:
Quando ao espaço, T usa apenas mais duas células, as que usa para delimitar a palavra.
Então:
spaceT(n)≤2+spaceM(n)=O(spaceM(n))
Multifita
Proposição
Toda a máquina de Turing multifita M é equivalente a uma máquina com apenas uma fita T tal que timeT(n)=O(n+timeM(n)2) e spaceT(n)=O(spaceM(n))
Prova
Atente-se na máquina T construída a partir de M tal como no capítulo de Máquinas de Turing.
A computação de T começa por inicializar a fita de memória, balizando o input com os símbolos I e F, e demarcando o espaço de cada uma das k fitas da máquina T, num número de passos da ordem de O(n+k), onde n é o tamanho do input e k o número de fitas.
De seguida simula cada uma das transições de M, percorrendo a fita da esquerda para a direita de forma a ler os símbolos marcados, e depois da direita para a esquerda atualizando as marcações, visitando um número de células da ordem de O(spaceM(n)).
Pode ter de efetuar um máximo de k espaçamentos, 1 em cada fita, visitando assim um número máximo de células da ordem de k⋅O(spaceM(n)).
Finalmente, após a aceitação por M, os símbolos marcados são adequadamente substituídos, e o símbolo F é removido, o que de novo implica que um número de células da ordem de O(spaceM(n)) seja visitado.
Assim, temos:
A seguinte proposição também transita para máquinas não deterministas:
Proposição
Para uma máquina não-determinista classificadora M, tem-se que ntimeM e nspaceM são funções monótonas e, para qualquer, n∈N:
nspaceM(N)≤ntimeM(n)
ntimeM(n)≤2O(nspaceM(n)).
Prova
Idêntica à para máquinas deterministas, quando considerado um ramo específico da computação não determinista.
e consequentemente
Corolário
NP⊂NPSPACE⊂NEXPTIME⊂NEXPSPACE
Finalmente, é importante estabelecer a relação entre a eficiência de máquinas deterministas com máquinas não-deterministas.
Proposição
Toda a máquina de Turing não-determinista N é equivalente a uma máquina de Turing determinista T tal que timeT(n)=O(n+ntimeN(n))⋅2O(ntimeN(n)) e spaceT(n)=O(n+ntimeN(n))
Prova
Vamos considerar a máquina T construída a partir de N como no capítulo de Máquinas de Turing.
A computação de T começa por inicializar 3 fitas de memória, a segunda das quais com o comprimento máximo das computações possíveis, que pode ser calculado num número de passos da ordem de O(ntimeN(n)).
De seguida, copia o input da primeira para a terceira fita, balizando-o com os símbolos I e F, e executando um número de passos da ordem de O(n).
Na terceira fita é então simulado o caminho de computação de N descrito na fita 2, num número de passos inferior ou igual a ntimeN(n), após o que volta a limpar a fita 3, visitando um número de células da ordem de O(spaceN(n)).
Em caso de aceitação por N, há ainda que, na terceira fita, remover o símbolo F e colocar a cabeça de leitura/escrita no início da palavra, visitando um número de células da ordem de O(nspaceN(n)).
Se b for o número máximo de escolhas não-deterministas na máquina N, temos assim:
Quanto ao espaço, como vimos na secção de máquinas multifita, temos que o espaço numa máquina multifita tem a mesma complexidade que a máquina de Turing com uma fita correspondente, pelo que:
Note-se que isto implica que a existência de uma máquina não-determinista de tempo polinomial para resolver um problema parece não nos poder garantir mais do que uma máquina determinista de tempo exponencial para resolver o mesmo problema.
O problema P vs NP pode ser compreendido como perguntando se é possível fazer esta simulação de forma mais eficiente (polinomial).
Propriedades de Fecho e Redução Polinomial
Proposição
Seja C uma das classes de complexidade P, NP, PSPACE, NPSPACE, EXPTIME, NEXPTIME, EXPSPACE, NEXPSPACE, e sejam Σ um alfabeto, e L1,L2∈C linguagens sobre Σ.
Então:
∅∈C
Σ∗∈C
L1∪L2∈C
L1∩L2∈C
Se C=NP e C=NEXPTIME, então temos também que:
L1∖L2∈C
Prova
É evidente que ∅ e Σ∗ podem ser decididas em O(1), pelo que estão contidas nas classes enumeradas.
Quanto as proposições 3 e 4, usamos as máquinas M como definidas nas prova que L1∩L2 e L1∪L2 são decidíveis, para L1 e L2 decidíveis.
Usamos o caso da disjunção como exemplo, mas a conjunção é análoga.
Se M1 é computada em O(f(x)) e M2 é computada em O(g(x)), então a máquina M que decide L1∪L2 computa em O(f(x)+g(x)), o que é suficiente para provar ambas proposições (não em teste!).
A quinta proposição fica como exercício (agradecem-se contribuições).
Stephen Cook e Leonid Levin mostraram que existem algumas linguagens em NP às quais todas as outras linguagens dessa classe se reduzem.
Mais ainda, mostraram que essa redução pode ser feita em tempo polinomial de forma que se se encontrar uma solução eficiente para um desses problemas, também se consegue decidir eficientemente qualquer outro problema de NP.
Vamos então começar por definir o que é uma redução polinomial de uma linguagem a outra:
Definição
Dadas linguagens sobre L1 e L2 sobre alfabetos Σ1 e Σ2, respetivamente, dizemos que há uma redução polinomial de L1 para L2 ou que L1 reduz polinomialmente a L2, o que denotamos por L1≤PL2 se existe uma função total f:Σ1∗→Σ2∗, calculada por uma máquina determinista em tempo polinomial tal que, para cada ω∈Σ1∗
ω∈L1⇔f(ω)∈L2
Obviamente, se L1≤PL2, então L1≤L2.
Proposição
Sejam L1 e L2 linguagens sobre alfabetos Σ1 e Σ2, respetivamente.
Seja C uma das classes de complexidade P, NP, PSPACE, NPSPACE, EXPTIME, NEXPTIME, EXPSPACE, NEXPSPACE.
Se L1≤PL2 e L2∈C, então L1∈C.
Prova
As demonstrações são semelhantes para todas as classes.
Ilustra-se a demonstração para a classe NP.
Assuma-se então que L1≤PL2 e L2∈NP. Seja N uma máquina de Turing não-determinista que decide L2 e k≥1 tal que ntimeN(n)=O(nk).
Seja M uma máquina de Turing que calcula f e l≥1 tal que timeM(n)=O(nl).
Consideremos a máquina de Turing T que ao receber um input ω, calcula f(ω) em M e usa o resultado dessa computação em N, retornando no final o mesmo que N.
Ora, T aceita então uma palavra ω se e só se N aceitar f(ω).
Ora, temos que N aceita f(ω) se e só se f(ω)∈L2.
Por definição de redução polinomial, isto acontece se e só se ω∈L1.
Conclui-se então que T decide L1 (pois termina sempre, uma vez que tanto N como M terminam sempre).
Basta-nos então provar que ntimeT(n)∈O(nt) para algum x∈N.
Ora:
Uma função f:N→N diz-se construtível no espaço se log(n)=O(f(n)) e
se a função que mapeia palavras 1n para a representação binária de f(n) é
computável em espaço O(f(n)).
Todas as funções mais comuns que são pelo menos O(log(n)), como, por
exemplo, log(n), nlog(n), n, n2 e 2n, são construtíveis no espaço.
Definição
Uma função t:N→N diz-se construtível no tempo se nlog(n)=O(t(n))
e se a função que mapeia palavras 1n para a representação binária de t(n) é
computável em tempo O(t(n)).
Todas as funções mais comuns que são pelo menos O(nlog(n)), como, por
exemplo, nlog(n), n2 e 2n, são construtíveis no tempo.
Teorema da Hierarquia no Espaço
Seja f:N→N uma função construtível no espaço. Então existe uma linguagem
decidível em espaço O(f(n)) mas não em espaço o(f(n)).
Corolário
Sejam f1,f2:N→N tais que f2(n) é construtível no espaço e f1(n)=o(f2(n)).
Então
SPACE(f1(n))⊊SPACE(f2(n)).
Teorema da Hierarquia no Tempo
Seja t:N→N uma função construtível no tempo. Então existe uma linguagem
decidível em tempo O(t(n)) mas não em tempo o(t(n)log(t(n))).
Este resultado permite-nos separar classes de complexidade temporais.
Corolário
Sejam t1,t2:N→N tais que t2(n) é construtível no tempo e t1(n)=o(log(t2(n))t2(n)).
Então
TIME(t1(n))⊊TIME(t2(n)).
Dificuldade e Completude
Seja C uma classe de complexidade. Uma linguagem A diz-se: