17
TRABALHO 04 TEORIA DA COMPUTAÇÃO INTRODUÇÃO À CIÊNCIA DA COMPUTAÇÃO - COM06850- 2012-II CIÊNCIA DA COMPUTAÇÃO GRUPO 5 2012204302 Caíque de Oliveira de Souza 2012204291 - Heloiza Barros Del’Esposti 2012204278 - Maycown Douglas O. Miranda 2012204279 - Melissa Silva de Souza 2012204298 - Otto Freitas Quintanilha 2012204286 - Paloma Marques Nobre

Trabalho 04

Embed Size (px)

DESCRIPTION

Trabalho de ICC

Citation preview

Page 1: Trabalho 04

TRABALHO 04 – TEORIA DA COMPUTAÇÃO

INTRODUÇÃO À CIÊNCIA DA

COMPUTAÇÃO - COM06850- 2012-II

CIÊNCIA DA COMPUTAÇÃO

GRUPO 5

2012204302 – Caíque de Oliveira de Souza

2012204291 - Heloiza Barros Del’Esposti

2012204278 - Maycown Douglas O. Miranda

2012204279 - Melissa Silva de Souza

2012204298 - Otto Freitas Quintanilha

2012204286 - Paloma Marques Nobre

Page 2: Trabalho 04

Teoria da Computação

Primeiro, apresentaremos uma linguagem que chamamos linguagem

simples, a fim demostrar que o numero mínimo de instruções necessárias para

resolver qualquer problema solúvel por um computador é três. Segundo,

explicaremos que outra ferramenta, chamada maquina de Turing também pode

resolver um problema que pode ser resolvido por nossa linguagem simples.

Terceiro, provaremos que nenhum programa pode informar se o outro para ou não

(se o programa termina ou ira executar para sempre), e essa terceira prova, mostra

por si própria que existem problemas que não podem ser solucionado por um

computador.

- As linguagens simples:

Nessa linguagem o único tipo de dados utilizado são números inteiros não

negativos para poder demonstrar algumas ideias da teoria da computação.

Definimos linguagens do computador apenas com três instruções:

• Instrução de incremento: Aumentar de 1 o valor de certa variável.

Imagine que um programa trabalhe com uma variável denominada X e que se

deseje aumentar de 1 o valor dessa variável ou seja incr(x): X = X + 1;

• Instrução de decremento: Esta operação é o inverso daquela

denominada incremento. Trata-se de retirar 1 do valor de uma variável. Então, de

modo análogo à operação de incremento tem-se decr(x): X = X - 1

• Instrução de laço: Trata-se de uma técnica que permite repetir as

mesmas instruções várias vezes ate alcançar o valor desejado da variável.

- A importância da linguagem simples

Embora não seja tão eficiente quanto outras linguagens sofisticadas, é tão

importante quanto, pois a partir dela é possível simular instruções que são

encontradas em algumas linguagens populares com apenas as três instruções da

linguagem simples.

Page 3: Trabalho 04

- Macros em linguagem simples

Macroinstrução (macro), chamamos cada simulação de ―macro‖ e os

utilizamos como base para uma nova simulação. O uso de macros facilita a

especificação de trechos repetitivos de um código, que podem ser invocados pelo

programador como uma única linha no programa. Toda macro tem um nome

especificado como o rótulo da pseudo-instrução e que será utilizado pelo

programador para invocar a macro, e um corpo, que será usado pelo macro-

montador para substituir o nome usado pelo programador pela sequência de

instruções nele especificados. Na sua forma mais simples, uma macro é

simplesmente uma abreviatura para um grupo de instruções. A forma geral de

definição de uma macro é:

nome MACRO [argumentos]

corpo

- Entrada e saída

Na linguagem simples, meramente para provar alguns teoremas da

ciência da computação simulamos a saída assumindo que a ultima variável utilizada

é o que deveria ser impresso.

Page 4: Trabalho 04

Máquina de Turing

A Máquina de Turing(MT) pode ser descrita como um modelo matemático

do processo de computação. Sua estrutura simples é proposital, uma vez que Turing

pretendia, com sua definição, chegar a um modelo que fosse universalmente aceito.

Atualmente há diversos modelos na literatura, mas que seguem o mesmo princípio.

A MT é o principal modelo usado para o estudo do que é ou não é

computável. De acordo com a tese de Church, todos os modelos razoáveis de

procedimento são equivalentes, e a MT se revelou simples e flexível o suficiente

para permitir todas as demonstrações dos resultados principais. Pode-se usar uma

MT como aceitador ou reconhecedor, ou ainda como a implementação de um

procedimento mais geral, que transforma uma cadeia de entrada em uma cadeia de

saída.

Uma Máquina de Turing é feita de três componentes: fita, controlador

cabeçotes de leitura/gravação.

Uma definição para a Máquina de Turing pode ser: Uma máquina de

Turing M é uma tupla M = < K, Σ, Г, δ, i, F >, onde K é um conjunto (finito, não

vazio) de estados, Г é o alfabeto (finito) de símbolos da fita, Σ Г é o alfabeto de

símbolos de entrada, é a função de transição, i K é o estado inicial, e F K é o

conjunto de estados finais. A função de transição d é um mapeamento : K K

{L, R}. Quando tivermos (q, a) = (p, b, R), a MT M, quando está no estado q, e

lê o símbolo a na fita, escreve o símbolo b na mesma posição em que a estava

escrito, move-se para a direita uma célula, e passa para o estado p. (Idem, para a

esquerda no caso de (q, a) = (p, b, L) ). Por simplicidade, podemos deixar alguns

valores de indefinidos, de maneira que deve ser entendida como uma função

parcial. Atingida uma situação em que o estado é , o símbolo lido é a, e (q, a) é

indefinido, dizemos que a máquina para. Poderíamos, se desejado, definir máquinas

de Turing que sempre param quando atingem um estado final, e que nunca param

em um estado não final. Mas sempre que esta propriedade for desejada, podemos

alterar uma MT introduzindo um estado adicional, não final, do qual a máquina

nunca mais sai.

Page 5: Trabalho 04

Tese de Church-Turing

Já dizia a tese de Church-Turing: Se existe um algoritmo para fazer a

tarefa de manipulação de símbolos, existe uma máquina de Turing para realiza-la. A

tese consiste em tentar provar que qualquer tarefa de manipulação de símbolos,

pode ser executada em uma máquina de Turing, caso a tarefa não puder ser

calculada na máquina de Turing, a mesma não pode ser calculada. Essa tese pode

ser provada matematicamente, apesar de que nunca poderá ser provada, existem

fortes argumentos em seu favor. Como por exemplo, não foi encontrado nenhum

algoritmo que não possa ser simulado utilizando uma máquina de Turing, e foi

demonstrado que todos os modelos computacionais que têm sido comprovados são

equivalentes ao modelo dessa máquina.

Page 6: Trabalho 04

Numeros de Godel

Na ciência da computação, um numero sem sinal pode ser associado a cada

programa que poderá ser descrito em linguagem especifica, geralmente é chamado

de numero de Godel, em homenagem ao matemático austríaco Kurt Godel.

Vantagens de uso do numero de Godel: Os programas podem ser utilizados

como um único item de dados como entrada para outros programas. A Identificação

de um programa pode ser feita por apenas uma representação de um único numero

inteiro. O uso de numeração pode ser utilizado para provar que certos problemas

não podem ser solucionados pelo computador, mostrando que o número total de

problemas no mundo é maior do que problemas em programas.

Vários métodos foram criados para numeração de programas, um modo de

transformação simples para numerar programas escritos em linguagens simples na

tabela abaixo.

Símbolo Código

Hexadecimal

Símbolo Código

Hexadecimal

1 1 9 9

2 2 Incr A

3 3 Decr B

4 4 while C

5 5 { D

6 6 } E

7 7 X F

8 8

Page 7: Trabalho 04

Representação de um Programa

Ao utilizar a tabela, podemos representar qualquer programa escrito na

linguagem simples por um único numero inteiro positivo, basta seguir algumas

etapas.

1. Substituir a partir da tabela, cada símbolo hexadecimal correspondente.

2. Interpretar o número hexadecimal resultante como um número inteiro

sem sinal.

Ex:

Qual numero de Godel para o programa incr(X)?

A solução basta substituir cada símbolo pelo seu correspondente código

hexadecimal.

Incr X – (AF)16 ---- 175

A representação do programa em numero de Godel será 175.

Interpretação de um número de Godel

Para interpretar um numero de Godel em um programa, basta seguir as

seguintes instruções:

1. Converta o número para hexadecimal

2. Interprete cada dígito hexadecimal como um símbolo utilizando a

tabela.

Ex:

Interprete 3058 como um programa.

Basta modificar o numero para hexadecimal e substituir cada dígito pelo

correspondente símbolo.

3508 → (BF2)16 → decr X 2 → decr (X2)

Page 8: Trabalho 04

O Problema da Parada

Quase todo o programa escrito de em uma linguagem de programação

envolve alguma forma de repetição, laços ou funções recursivas. Uma construção

com base em repetição pode nunca parar; ou seja, é possível que um programa seja

executado para sempre se tiver um laço infinito. A existência desse programa

poderia economizar muito tempo dos programadores. Executar um programa sem

saber se ele irá ou não parar um trabalho muito difícil. Mas, agora já pode ser

comprovado que um tal programa não pode existir, o que é um grande

desapontamento para os programadores.

O Problema da Parada Não Pode Ser Resolvido

Em vez de afirmar que o programa de teste não existe, e nunca poderá

existir, o cientista da computação diz: ―o problema da parada não é solúvel‖.

Prova: Assumimos que o programa existe, e então, mostramos que essa

existência cria uma contradição; portanto ela não pode existir.

Etapa 1

Assumimos que um programa, chamado teste, existe.

Etapa 2

Criamos outro programa, chamado Estranho, que é composto de duas

partes: uma cópia de teste no início, e um laço vazio.

Etapa 3

Tendo escrito o programa Estranho, testamos consigo mesmo como

entrada.

Page 9: Trabalho 04

A Complexidade dos Problemas

A complexidade de um problema é o consumo de tempo do melhor

algoritmo possível para o problema. (O melhor algoritmo conhecido atualmente não

é, em geral, o melhor algoritmo possível.) É claro que estamos nos referindo ao

consumo de tempo no pior caso, ou seja, ao consumo de tempo para as instâncias

mais "difíceis" do problema.

Problemas computacionais

Precisamos de um repertório de exemplos. Seguem alguns:

Quadrado perfeito: Dado um número natural n, encontrar um número

natural x tal que x² = n ou constatar que tal x não existe.

Equação inteira do segundo grau: Dados números inteiros a, b e c,

encontrar um número inteiro x tal que ax² + bx + c = 0 ou constatar que tal xnão

existe.

Fatoração: Dado um número natural n, encontrar um número natural p,

maior que 1 e menor que n, que seja divisor n ou constatar que tal p não existe.

Máximo divisor comum: Encontrar o maior divisor comum de dois

números naturais m e n.

Divisor comum grande: Dados números naturais m, n e k, encontrar um

divisor comum de m e n que seja maior que k ou constatar que tal divisor não

existe.

Subsequência crescente máxima: Dada uma sequência s1,…,sn de

números naturais, encontrar uma subsequência crescente máxima de s1,…,sn.

Subsequência crescente longa: Dada uma sequência s1,…,sn de

números naturais e um número natural k, encontrar uma subsequência crescente de

s1,…,sn que tenha comprimento maior que k ou constatar que tal subsequência

não existe.

Page 10: Trabalho 04

Mochila: Dados números naturais p1,…,pn, v1,…,vn e c, encontrar um

subconjunto K de {1,…,n} tal que a soma dos pk para k em K não passe de c e a

soma dos vk para k em K seja máxima.

Caminho mínimo: Dados vértices r e s de um grafo, encontrar um

caminho de comprimento mínimo de r a s no grafo ou constatar que não há

caminho algum de r a s.

Caminho máximo: Dados vértices r e s de um grafo, encontrar um

caminho de r a s que tenha comprimento máximo ou constatar que não há caminho

algum de r a s.

Ciclo máximo: Encontrar um ciclo de comprimento máximo num grafo

dado ou constatar que o grafo não tem ciclo algum.

Ciclo hamiltoniano: Encontrar um ciclo hamiltoniano (ou seja, um ciclo

que passe por todos os vértices) num grafo dado ou constatar que tal ciclo não

existe.

Ciclo longo: Dado um grafo e um número k, encontrar um ciclo de

comprimento maior que k ou constatar que o grafo não tem tal ciclo.

Clique grande: Dado um grafo e um número k, encontrar uma clique com

k ou mais vértices ou constatar que tal clique não existe.

Cobertura pequena: Dado um grafo e um número k, encontrar uma

cobertura com menos que k vértices ou constatar que tal cobertura não existe.

(Observe que há uma relação íntima entre o problema do ciclo

hamiltoniano e o problema do ciclo longo. Há relações análogas entre vários outros

pares de problemas.)

Algoritmos Polinomiais

Dizemos que um algoritmo resolve um dado problema se, ao receber

qualquer instância do problema, devolve uma solução da instância ou diz que a

instância não tem solução.

Page 11: Trabalho 04

Um algoritmo que resolve um dado problema é polinomial se o seu

consumo de tempo no pior caso é limitado por uma função polinomial dos tamanhos

das instâncias do problema.

É polinomial, por exemplo, todo algoritmo que consome no máximo

100N4 + 300N2 + 5000 unidades de tempo, sendo N o tamanho da instância.

Também é polinomial todo algoritmo que consome no máximo 200N9 log N

unidades de tempo, por exemplo (pois 200N9 log N < 200N10).

Algoritmos polinomiais são considerados rápidos (ainda que seja difícil

aceitar como rápido um algoritmo que consome tempo proporcional a N500, por

exemplo). Algoritmos não polinomiais — como, por exemplo, os que consomem

tempo proporcional a 2N — são considerados inaceitavelmente lentos (ainda que

possam ser úteis para valores muito modestos de N).

Problemas Polinomiais e a Classe P

Um problema computacional é polinomial se existe um algoritmo

polinomial para o problema. Problemas desse tipo são considerados tratáveis do

ponto de vista computacional.

Exemplos de problemas polinomiais: o problema da equação do segundo

grau, o problema do máximo divisor comum, o problema do caminho mínimo,

oproblema da subsequência crescente máxima.

A classe P de problemas é o conjunto de todos os problemas polinomiais.

[A rigor, esta definição está incorreta, pois a classe P contém apenas os problemas

polinomiais de decisão.]

Um problema é não polinomial se nenhum algoritmo polinomial resolve o

problema. (Cuidado: não se trata de problemas para os quais algoritmos

polinomiais não são conhecidos atualmente, pois tais algoritmos podem vir a ser

descobertos no futuro.) Problemas desse tipo são considerados

computacionalmente intratáveis.

Page 12: Trabalho 04

A Classe NP de Problemas

O status de muitos problemas é desconhecido: não se sabe se o

problema é polinomial ou não. Diante disso, é uma boa ideia investigar a

complexidade relativa dos problemas. Trata-se de verificar se um dado problema Y é

computacionalmente mais fácil ou mais difícil que um outro problema X (talvez mais

bem-conhecido). Antes que isso possa ser feito, entretanto, é preciso restringir um

pouco o universo dos problemas sob estudo.

Quais problemas devemos considerar "razoáveis"? Diremos que um

problema é "razoável" se é fácil reconhecer uma solução do problema quando se

está diante de uma. Mais precisamente, um problema computacional X é "razoável"

se toda instância I de X satisfaz a seguinte condição:

é possível verificar, em tempo polinomial, se uma suposta solução da

instância I é, de fato, uma solução de I.

Muitos dos problemas mencionados acima são "razoáveis". Considere os

seguintes exemplos:

É fácil verificar se um dado inteiro x satisfaz a equação ax² + bx + c = 0.

Essa verificação consome tempo limitado por um polinômio no tamanhosda instância

(a,b,c) pois o valor absoluto de qualquer solução x da equação não é maior que o

produto (|a|+1)(|b|+1)(|c|+1). Portanto, oproblema da equação do segundo grau é

"razoável".

É fácil verificar se um dado número natural p divide n. Ademais, a

verificação consome tempo polinomial no tamanho da instância pois todo divisor de

n é menor que n. Portanto, o problema da fatoração é "razoável".

O problema do ciclo longo é "razoável" pois é fácil verificar, em tempo

polinomial, se um dado objeto é um ciclo no grafo e tem comprimento maior que k.

O problema do ciclo hamiltoniano é "razoável" pois é fácil verificar, em

tempo polinomial, se um dado objeto é um ciclo no grafo e passa por todos os

vértices do grafo.

Page 13: Trabalho 04

O conjunto de todos os problemas "razoáveis" é (essencialmente) igual à

classe NP de problemas. [Cuidado: "NP" não é abreviatura de "não polinomial" mas

sim de "nondeterministic polynomial".]

(A rigor, não é correto confundir o conjunto dos problemas "razoáveis"

com classe NP. A questão é que o conceito de solução — que serve de base para a

ideia de problema "razoável" — não é suficientemente preciso. Considere, por

exemplo, o problema do ciclo máximo. Por um lado, parece que deveríamos aceitar

o problema como "razoável" uma vez que o problema do ciclo longo é "razoável".

Por outro lado, o problema não parece "razoável" pois não está claro como verificar

se um dado ciclo é máximo, ou seja, se não existe ciclo mais longo. Para contornar

essas dificuldades, é preciso restringir nossa atenção a problemas "de decisão" e

trocar o conceito de "solução" pelo de "certificado".)

A Questão "P = NP?"

Não é difícil entender que a classe NP inclui a classe P, ou seja, que todo

problema polinomial é "razoável". O bom senso sugere que P é apenas uma

pequena parte de NP. Surpreendentemente, ninguém conseguiu ainda encontrar

um problema de NP que comprovadamente não esteja em P, isto é, um problema

"razoável" para o qual comprovadamente não existe algoritmo polinomial.

Esta situação abre caminho para a suspeita de que talvez P seja igual a

NP . A maioria dos especialistas não acredita nessa possibilidade, entretanto. [O

Instituto Clay de Matemática oferece um prêmio de um milhão de dólares pela

solução da questão "P=NP?".]

A pergunta "P = NP?" por ser reformulada assim: "É verdade que todo

problema cujas soluções podem ser conferidas por um algoritmo polinomial pode

também ser resolvido por um algoritmo polinomial?"

Complexidade Relativa de Problemas

Podemos agora dizer algo sobre a complexidade relativa de problemas

em NP. Um problema Y não é mais difícil que um outro problema X se Y for um

"subproblema", ou "caso particular", de X. Exemplos:

Page 14: Trabalho 04

O problema do quadrado perfeito não é mais difícil que o problema da

equação do segundo grau.

O problema do ciclo hamiltoniano não é mais difícil que o problema do

ciclo longo.

O problema da cobertura pequena de um grafo não é mais difícil que o

problema da clique grande. (Por que?)

Para explicar um pouco melhor o conceito, diremos que um problema Y

não é mais difícil que um problema X se qualquer algoritmo polinomial para X pode

ser transformado num algoritmo polinomial para Y. O algoritmo para Y tem três

etapas: primeiro, qualquer instância J de Y é transformada, em tempo polinomial,

numa instância "equivalente" I de X; depois, a instância I é submetida ao algoritmo

polinomial para X, que produz uma solução S; finalmente, S é transformada, em

tempo polinomial, numa solução T de J. Assim, se X está em P e Y não é mais

difícil que X então Y também está em P.

Problemas Completos em Np

Um problema X é completo em NP, ou NP-completo, se X está em NP e

todos os demais problemas em NP não são mais difíceis que X.

A existência de problemas completos em NP é um fato surpreendente e

fundamental. O fato foi demonstrado, por volta de 1970, por S. Cook e L. Levin

(independentemente).

Para mostrar que P = NP basta encontrar um algoritmo polinomial para

um único problema NP-completo. Portanto, os problemas NP-completos são os

mais "difíceis" de NP.

Por exemplo, são NP-completos os problemas (de decisão derivados dos)

seguintes: ciclo hamiltoniano, ciclo longo, clique grande, cobertura

pequena,mochila. Uma lista com centenas de outros problemas NP-completos

pode ser encontrada no livro de Garey e Johnson.

Page 15: Trabalho 04

Apêndice: Certificados de Inexistência de Solução

Nossa tentativa grosseira de definir a classe NP de problemas, trouxe à

baila uma questão importante. Muitos problemas têm instâncias que não admitem

solução. Como é possível "provar" ou "certificar" que uma dada instância de um

problema não admite solução? Não estamos tratando aqui de como descobrirque

uma dada instância não tem solução, mas apenas de, uma vez descoberta a

inexistência de solução, como tornar este fato "evidente".

Para muitos problemas, existem certificados naturais e elegantes para a

inexistência de solução. (Todos consistem em trocar um "não existe x" por um

"existe y" apropriado.) Eis alguns exemplos:

Problema do quadrado perfeito: Para mostrar que um número natural n

não é um quadrado perfeito, basta exibir um número natural k tal quek² < n < (k+1)².

Um tal k é um certificado de inexistência de solução.

Problema da equação do segundo grau: Para mostrar que não existe um

inteiro x tal que ax² + bx + c = 0, basta verificar que (1) b²−4ac não é um quadrado

perfeito, ou (2) b²−4ac é um quadrado perfeito mas nem (b²−4ac)½ + b nem

(b²−4ac)½ − b são divisíveis por 2a. Assim, um certificado de inexistência de

solução consiste em certificados para as condições (1) ou (2).

Problema do divisor comum grande: Para mostrar que não existe divisor

comum de m e n que seja maior que k é suficiente exibir números inteiros (não

necessariamente positivos) x e y tais que 0 < xm+yn ≤ k. Como qualquer divisor

comum de m e n é também divisor de xm+yn, concluímos que todo divisor comum

de m e n é menor ou igual a k. Assim, o par x,y é um certificado da inexistência de

divisor comum grande. Todas as instâncias sem solução têm um tal certificado. (O

algoritmo de Euclides calcula o certificado ao mesmo tempo que calcula um máximo

divisor comum.)

Problema da fatoração: Existe um certificado muito interessante para as

instância do problema que não têm solução, mas não tenho condições descrever o

certificado aqui.

Page 16: Trabalho 04

Problema da subsequência crescente longa: Suponha dada uma

cobertura por subsequências estritamente decrescentes de uma sequência

s1,…,snde números naturais. Se a cobertura consiste em k sequências então é claro

que nenhuma subsequência crescente de s1,…,sn pode ter comprimento maior que

k. Assim, uma cobertura pequena por subsequências estritamente decrescentes é

um certificado de inexistência de subsequência crescente longa. Todas as

instâncias sem solução têm uma tal cobertura. (O algoritmo que calcula uma

subsequência crescente máxima pode ser adaptado para determinar também um

cobertura mínima.)

Problema do caminho mínimo: Seja R um conjunto de vértices que

contém o vértice r mas não contém o vértice s. Suponha ainda que nenhuma aresta

liga um vértice de R a um vértice fora de R. Se um tal R existe, é claro que não

existe caminho de r a s. Assim, um tal R é um certificado de inexistência de solução

para a instância em discussão. (Toda instância sem solução tem um tal certificado.)

Cada um desses exemplos mostra que o correspondente problema está

na classe coNP.

Page 17: Trabalho 04

Referências Bibliográficas

[1] FOROUZAN, Behrouz; MOSHARRAF, Firouz. Fundamentos da Ciência da

Computação, tradução da 2ª edição internacional.

[2] http://www.ime.usp.br