Um algoritmo simples em Python
O número 29 é primo? True
O número 30 é primo? False
Computabilidade e Complexidade
Márcio Nicolau
25 de agosto de 2025
Nas aulas anteriores, fizemos uma descoberta chocante: existem infinitamente mais “problemas” (linguagens) do que “soluções” (programas). Isso implica que alguns problemas são fundamentalmente insolúveis. Mas essa conclusão nos deixa com uma pergunta central: o que, exatamente, significa que um problema é solucionável? O que é um “algoritmo”?
Nossa noção intuitiva de um algoritmo vem da nossa experiência com programação. Um algoritmo é uma sequência de passos bem definidos que resolve uma tarefa.
O número 29 é primo? True
O número 30 é primo? False
Este código Python é um algoritmo. Ele tem um conjunto finito de instruções, é preciso e sempre termina com uma resposta “sim” ou “não” (True/False). Mas para estudar os limites da computação de forma rigorosa, precisamos de um modelo matemático de um “algoritmo”, que seja independente de qualquer linguagem de programação específica.
É aqui que entra Alan Turing. Em 1936, ele propôs um dispositivo teórico, a Máquina de Turing, para formalizar a ideia de um “procedimento mecânico”. Este modelo simples, porém poderoso, tornou-se a base da teoria da computação.
O objetivo da aula de hoje é: > Definir funções computáveis e introduzir o modelo de Máquina de Turing como a formalização de um algoritmo.
Imagine o processo de computação mais simples possível. Você tem uma longa fita de papel, um lápis com borracha e um conjunto de regras. A Máquina de Turing é a formalização dessa ideia.
Ela consiste em três partes principais:
A “programação” de uma Máquina de Turing é sua função de transição, que é um conjunto de regras do tipo:
“Se você está no estado A e o símbolo sob o cabeçote é X, então:
- Escreva o símbolo Y.
- Mova o cabeçote para a Direita (R).
- Mude para o estado B.”
graph TD subgraph Fita Infinita direction LR c1[...] --> c2[ ] --> c3 --> c4 --> c5[...] end subgraph Unidade de Controle state("Estado Atual: q_i") end Cabeçote -- Lê/Escreve --> c4 Unidade_de_Controle -- "Controla" --> Cabeçote style c4 fill:#ffc,stroke:#333,stroke-width:2px
Formalmente, uma Máquina de Turing é uma 7-tupla \(M = (Q, \Sigma, \Gamma, \delta, q_0, q_{accept}, q_{reject})\), onde:
(Definição baseada em (Sipser, 2012, p. 168)).
Quando uma Máquina de Turing (TM) recebe uma string de entrada w
, ela a escreve no início da fita, posiciona o cabeçote no primeiro símbolo e inicia no estado \(q_0\). A partir daí, a função de transição \(\delta\) assume o controle. Existem três resultados possíveis para essa computação:
w
.w
.Essa distinção nos leva a duas definições cruciais de “solucionabilidade”:
Linguagem Turing-Reconhecível: Uma linguagem \(L\) é dita reconhecível se existe uma TM \(M\) tal que:
Um reconhecedor nos dá uma resposta “sim” garantida para strings na linguagem, mas pode não nos dar uma resposta definitiva para strings fora dela.
Linguagem Turing-Decidível: Uma linguagem \(L\) é dita decidível se existe uma TM \(M\) que para em todas as entradas:
Uma TM que decide uma linguagem é chamada de decisor. Ela sempre para e nos dá uma resposta clara de “sim” ou “não”.
flowchart TD classDef recon fill:#e3f2fd,stroke:#1976d2,stroke-width:2px,color:black classDef dec fill:#e8f5e9,stroke:#2e7d32,stroke-width:2px,color:black subgraph s1["Decidíveis"] Prop_Dec["<b>Propriedades:</b><br/>- TM sempre para<br/>- Resposta 'sim' ou 'não'<br/>- Ex: Paridade de 1s"] end subgraph subGraph1["Apenas Reconhecíveis (Não-Decidíveis)"] Prop_Recon["<b>Propriedades:</b><br/>- Para se 'sim'<br/>- Pode loop se 'não'<br/>- Ex: Problema da Parada"] end subgraph subGraph2["Ling. Turing-Reconhecíveis"] direction LR s1 subGraph1 end %% Apply styles Prop_Dec:::dec Prop_Recon:::recon %% Style subgraph titles style s1 color:#000,fill:none style subGraph1 color:#000,fill:none style subGraph2 color:#2962FF,fill:#FFE0B2
Problemas decidíveis são o que consideramos “efetivamente solucionáveis” por um computador.
Além de decidir linguagens (responder sim/não), as TMs podem calcular funções.
Uma função \(f: \Sigma^* \to \Gamma^*\) é uma função computável (ou Turing-computável) se existe uma Máquina de Turing \(M\) que, para toda entrada \(w \in \Sigma^*\), para com a string \(f(w)\) na fita e nada mais.
Por exemplo, vamos considerar uma função simples: \(f(w) = w\) concatenado com “01”. Se a entrada for “110”, a saída deve ser “11001”.
Uma TM para computar essa função faria o seguinte:
Isso demonstra que uma operação simples, que em Python seria w + "01"
, corresponde a um procedimento mecânico que pode ser executado por uma Máquina de Turing.
Isso nos leva a uma das hipóteses mais importantes da ciência da computação. A Tese de Church-Turing não é um teorema que pode ser provado, mas uma afirmação que tem resistido ao teste do tempo.
Tese de Church-Turing: A noção intuitiva de algoritmo é equivalente à noção de uma Máquina de Turing. ((Sipser, 2012, p. 182)).
Isso significa que qualquer coisa que possa ser “computada” por qualquer modelo de computação razoável (um programa Python, cálculo lambda, um computador quântico idealizado) pode também ser computada por uma Máquina de Turing.
Se quisermos provar que um problema é “insolúvel”, basta provar que nenhuma Máquina de Turing pode decidí-lo. A Tese de Church-Turing nos dá a confiança de que nenhum avanço em linguagens de programação ou arquitetura de computadores tornará esse problema solúvel.
Explique a diferença fundamental entre uma linguagem Turing-reconhecível e uma Turing-decidível. Por que, do ponto de vista prático de resolver um problema, a propriedade de ser “decidível” é muito mais forte e desejável?
Descreva em alto nível (sem a tupla formal, apenas a estratégia e os passos) como uma Máquina de Turing poderia decidir a linguagem \(L = \{w \mid w \text{ é uma string binária com um número par de 1s}\}\).
Pense em como você resolveria isso com “memória”. Como os estados da TM podem servir como essa memória?
Considere a seguinte função em Python que decide a linguagem da Questão 2.
Com base na Tese de Church-Turing, o que a existência deste programa Python nos permite concluir sobre a linguagem \(L\)? A linguagem \(L\) é decidível, reconhecível ou nenhuma das duas? Justifique sua resposta.