Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adiciona resumos de TC #193

Merged
merged 8 commits into from
Jun 23, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions tc/resumos/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Resumos

- [Autômatos Finitos](automatosFinitos.md)
- [Autômatos de Pilha](automatosDePilha.md)
- [Máquinas de Turing](maquinasDeTuring.md)
47 changes: 47 additions & 0 deletions tc/resumos/automatosDePilha.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# Autômatos de Pilha

Os **autômatos de pilha** são semelhantes aos autômatos finitos, porém, contam com um componente extra que provê memória: a **pilha**. Essa pilha é infinita e seu uso é motivado pela forma simples de armazenamento, não envolvendo endereçamento do conteúdo. Assim, o grande diferencial dos autômatos de pilha é a capacidade de armazenar símbolos nessa pilha à medida que realizam transições.

De maneira análoga aos autômatos finitos, existem autômatos de pilha determinísticos e não-determinísticos, porém, esses dois tipos não possuem as mesmas capacidades e tem objetivos distintos.

A definição formal de um **autômato de pilha (AP)** é uma 6-tupla **<Q, Σ, Γ, δ, q0, F>**, tal que:

- **Q** é o conjunto de estados.
- **Σ** é o alfabeto da entrada.
- **Γ** é o alfabeto da pilha.
- **δ: Q × Σ × Γε → P(Q × Γε)** é a função de transição do autômato.
- **q0** ∈ Q é o estado inicial do autômato.
- **F** ∈ Q é o conjunto de estados finais do autômato.

No **diagrama de estados**, utiliza-se a notação **a, b → c** para as transições, indicando que o autômato lê um símbolo *a* da entrada e substitui o símbolo *b* do topo da pilha por um símbolo *c*. A seguir, algumas notações importantes:

- Se **a = λ** (ou ε), tem-se que a transição é realizada sem consumir símbolos da entrada.
- Se **b = λ** (ou ε), tem-se que o símbolo *c* é empilhado sem remover o topo da pilha.
- Se **c = λ** (ou ε), tem-se que o símbolo do topo da pilha é desempilhado sem ser substituído.
- O símbolo **$** é um marcador do início da pilha, de modo que se **b = $** na última transição, a pilha estará vazia.

## Linguagens Livres de Contexto

Os autômatos de pilha são capazes de reconhecer algumas linguagens não-regulares e equivalem às **gramáticas livres de contexto (GLC)**. Além disso, dada uma **linguagem livre de contexto (LLC)**, obrigatoriamente há um autômato de pilha que a reconheça. Assim, uma forma prática de provar que uma linguagem é livre de contexto é construir o autômato de pilha que a reconheça.

Para criar um autômato de pilha que reconheça uma gramática livre de contexto, se começa adicionando o símbolo **$** e a variável inicial à pilha. A seguir, inicia-se o seguinte *loop*:
alvesmatheus marked this conversation as resolved.
Show resolved Hide resolved

- Se o topo da pilha for uma variável, uma de suas regras é selecionada não-deterministicamente para substituí-la.
- Se o topo da pilha é um terminal e coincide com o símbolo atual da entrada, ele é desempilhado.
- Se o topo da pilha é o **$**, o estado de aceitação foi alcançado.

Nesse contexto, caso mais de um ramo não-determinístico alcance a aceitação, diz-se que há **ambiguidade**. Porém, é importante compreender que existem linguagens que só podem ser geradas por gramáticas ambíguas.

Assim como os autômatos de pilha reconhecem as linguagens livres de contexto, os **autômatos de pilha determinísticos (APD)** reconhecem as **linguagens livres de contexto determinísticas (LLCD)**. Eles podem ser identificados pela existência de uma única transição válida a cada instante do processamento. Ainda, o determinismo garante a não-ambiguidade.

A nível de comparação, as **linguagens sensíveis ao contexto (LSC)** são aquelas em que pode haver mais de um símbolo à esquerda de cada regra, de modo que certas substituição estão habilitadas apenas em certos contextos.

### Lema do Bombeamento para LLCs

Se uma linguagem A é livre de contexto, existe um número **p** e uma cadeia **s** tal que qualquer palavra dessa linguagem que seja maior que p possuirá uma árvore sintática com repetição, ou seja, é possível gerar variações dessa palavra que pertencem à linguagem. Assim, é possível dividir a cadeia em cinco pedaços **s = uvxyz**, tal que:

- Para *i ≥ 0*, **u (v^i) x (y^i) z** ∈ A
- **|vy| > 0**
- **|vxy| ≤ p**

O lema do bombeamento é geralmente utilizado para provar que uma linguagem não é livre de contexto através de suas implicações sobre a ordem e o balanceamento dos símbolos.
39 changes: 39 additions & 0 deletions tc/resumos/automatosFinitos.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# Autômatos Finitos

Enquanto as máquinas de estado são capazes apenas de acompanhar os estados do sistema, um **autômato finito (AF)** é uma máquina que resolve algum problema, aceitando ou recusando a cadeia utilizada como entrada. Assume-se que os autômatos finitos são compostos por uma unidade de controle e uma fita na qual realiza a leitura da cadeia de entrada, que será aceita ou rejeitada.

Para que possa alcançar a **aceitação** da cadeia de entrada, é necessário que o autômato possua pelo menos um **estado final**. Se, ao termino do processamento de uma certa cadeia, o autômato tiver um de seus estado finais como estado atual, diz-se que a cadeia foi aceita. Caso contrário, diz-se que a cadeia foi rejeitada (**rejeição**). Dessa forma, um autômato não precisa ter estados finais, porém, sem eles torna-se inútil.

Dá-se o nome de **classe de linguagem** a todas as linguagens que podem ser resolvidas por um mesmo tipo de máquina. A classe que contém todas as linguagens que podem ser resolvidas por autômatos finitos chama-se **classe das linguagens regulares**.

## Autômatos Finitos Determinísticos

A definição formal de um **autômato finito determinístico (AFD)** é uma 5-tupla **<Q, Σ, δ, q0, F>**, tal que:

- **Q** é um conjunto finito e não-vazio, chamado de conjunto de estados.
- **Σ** é um conjunto finito e não-vazio, chamado de alfabeto.
- **δ: Q × Σ → Q** é a função (total) de transição do autômato.
- **q0** ∈ Q é o estado inicial do autômato.
- **F** ∈ Q é o conjunto de estados finais do autômato.

A **função de transição** é responsável por descrever as mudanças de estados a partir do estado atual e do símbolo recebido na entrada. O **diagrama de estados** é a representação gráfica do autômato. É possível gerar o diagrama de estados a partir da definição formal do autômato finito e vice-versa.

Na Teoria da Computação, os objetos de estudo são as **linguagens** e as ferramentas são as operações exclusivas para manipulação de linguagens. As **operações regulares** são a união (∪), a concatenação (•) e a estrela (*), descritas por:

```
- A ∪ B = { x | x ∈ A ou x ∈ B }
- A • B = { xy | x ∈ A e y ∈ B }
- A* = { x1, x2, ..., xk | xi ∈ A e k ≥ 0 }
```

Porém existem outras operações abordadas durante a disciplina como o complemento, a intersecção, a subtração, etc. Se uma operação realizada sobre uma linguagem da classe C sempre gera uma linguagem da mesma classe, diz-se que a classe é **fechada** por esta operação.

O símbolo *lambda* (**λ**) representa a palavra vazia (ou nula), em alguns livros utiliza-se o épsilon (**ε**). Já **Σ*** denota o alfabeto binário.
alvesmatheus marked this conversation as resolved.
Show resolved Hide resolved

## Autômatos Finitos Não-Determinísticos

Enquanto nos AFDs os estados e as transições são bem determinadas, em um **autômato finito não-determinístico (AFND)** podem existir múltiplas possibilidades para o próximo estado dado um mesmo símbolo, assim, ele torna-se capaz de explorar diversas possibilidades simultaneamente. Formalmente, difere dos AFDs apenas por sua função da transição, que é da forma **δ: Q × Σε → Q**.
alvesmatheus marked this conversation as resolved.
Show resolved Hide resolved

Nos AFNDS, um estado pode ter zero ou mais transições para cada símbolo do alfabeto e zero ou mais transições para o símbolo **ε** (ou **λ** em outras notações). Os arcos rotulados com **ε** indicam que é possível realizar aquela transição sem consumir símbolos da cadeia de entrada.

É importante compreender que todo autômato determinístico é um autômato não-determinístico e, portanto, o não-determinismo não representa um aumento de capacidade dos autômatos.
17 changes: 17 additions & 0 deletions tc/resumos/introducao.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Introdução

O estudo da **Teoria da Computação** preocupa-se com a capacidade do computador independente dos fatores técnicos, como a linguagem de programação e o *hardware* utilizados, portanto, analisa a solubilidade de problemas. Ainda, na impossibilidade de encontrar soluções, procura por respostas sub-ótimas para estes problemas.

Embora o grande objetivo seja compreender os limites da computação, existem muitas aplicações de conceitos de Teoria da Computação como modelar um pedaço de hardware, modelar uma comunicação, descrever padrões, descrever o que é válido em uma linguagem, etc.

Nesse contexto, determinar a **complexidade** e a **solubilidade** de problemas é vital para empregar os recursos necessários para resolvê-los, se for possível.

Um **autômato** é uma máquina (ou modelo computacional) projetada para seguir automaticamente uma sequência predeterminada de operações ou para responder a instruções codificadas. Enquanto um **computador** é uma máquina real que realiza computações, um **modelo computacional** é uma máquina abstrata, simplificada e sob controle.

As **máquinas de estados** são modelos simples de computadores utilizados em muitas aplicações (como sistemas embarcados simples) que reagem às entradas conhecidas, que conhecem sua especificação (ou seja, como funcionam) e que conhecem seu estado atual nesta especificação. Para compreendê-las, é importante entender os seguintes conceitos:

- **Alfabeto:** Conjunto de símbolos que podem ser utilizados como entrada da máquina abstrata.
- **Cadeia:** Também chamada de palavra, é uma concatenação finita de símbolos do alfabeto em uso.
- **Linguagem:** Conjunto de todas as cadeias do alfabeto em uso que levam à aceitação de um autômato.
- **Processar:** Tratar os símbolos que compõem a cadeia de entrada, um a um e conforme a sequência em que estão escritos.
- **Estado:** Representa a situação atual da máquina de estados, sendo a única porção importante de sua "história". O estado inicial é aquele em que a máquina começa o processamento da cadeia.
70 changes: 70 additions & 0 deletions tc/resumos/maquinasDeTuring.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# Máquinas de Turing

> Conheça mais sobre Alan Turing [aqui](https://pt.wikipedia.org/wiki/Alan_Turing).

Os autômatos (finitos ou de pilha) são bons modelos para alguns dispositivos, mas muito restritos para modelar computadores reais. Para este objetivo, utiliza-se as **máquinas de Turing**, capazes de resolver todos os problemas que os computadores conseguem resolver. Consequentemente, os problemas que não podem ser resolvidos por máquinas de Turing estão além dos limites teóricos da computação.

Ainda que possuam diversas semelhanças com os autômatos, as máquinas de Turing possuem memória infinita (e irrestrita) através de uma fita infinita. Além dessa, as principais diferenças entre esses dois tipos de máquina são:

- A capacidade de ler e escrever na fita infinita.
- Os estados de aceitação e rejeição têm efeito imediato.
- O cabeçote da máquina pode se mover em ambas as direções.
- É possível que o processamento não se encerre nunca (*loop*).

A definição formal de uma **máquina de Turing (MT)** é uma 7-tupla **<Q, Σ, Γ, δ, q0, qA, qR>**, tal que:

- **Q** é o conjunto de estados.
- **Σ** é o alfabeto da entrada (não contém B).
- **Γ** é o alfabeto da fita, onde B ∈ Γ e Σ ⊂ Γ.
- **δ: Q × Γ → Q × Γ × {E, D}** é a função de transição da máquina de Turing.
- **q0** ∈ Q é o estado inicial da máquina de Turing.
- **qA** ∈ Q é o estado de aceitação da máquina de Turing.
- **qR** ∈ Q é o estado de rejeição da máquina de Turing.

Uma maneira informal de descrever o **funcionamento** de uma máquina de Turing é imaginar que, inicialmente, a fita infinita contém apenas a cadeia de entrada e os demais espaços são "branco" (denotado por **B** ou **ν**). A medida que o processo ocorre, a máquina poderá não só reagir aos símbolos lidos, mas também escrever símbolos na fita caso necessite armazenar informações.

Dá-se o nome de **configuração** ao conjunto de três informações que representam o *status* atual de uma máquina de Turing: o estado atual, o conteúdo da fita e a posição atual do cabeçote. Ainda, diz-se que uma configuração C1 **produz** uma configuração C2 se a máquina de Turing for capaz alcançar C2 a partir de C1 em um único passo.

A coleção de cadeias que uma máquina de Turing M aceita é chamada de **linguagem de M** e denotada por **L(M)**.

Uma linguagem pode ser **Turing-reconhecível** ou **Turing-decidível** se existir uma máquina de Turing que a reconheça ou a decida, respectivamente. A distinção entre essas características se dá pelo fato de um decisor garantir que haverá fim no processamento (aceitação/rejeição), enquanto o reconhecedor pode entrar em *loop*. Portanto, uma linguagem decidível é reconhecível, mas o inverso não é garantido.

## Variações

As **variações** de máquinas de Turing são ambundantes, mas todas reconhecem a mesma classe de linguagens, diz-se então que possuem a mesma **robustez**. Um exemplo simples que permite a percepção dessa característica é garantir ao cabeçote a capacidade de permanecer parado durante uma transição. Ainda que seja uma nova capacidade, ela não adiciona poder à máquina de Turing, dado que seria possível realizar as mesmas tarefas com duas transições distintas.

### Calculadora de Função

É o tipo de variação em que a máquina de Turing não se limita a responder *"sim"* (aceitação) ou *"não"* (rejeição), mas realiza algo a mais. Geralmente a cadeia escrita na fita ao final do processamento é de mais interesse do que a própria aceitação.

### Multifitas

É o tipo de variação em que a máquina de Turing não possui apenas uma fita infinita, mas várias delas (que são utilizadas simultaneamente). É importante compreender que, para toda MT multifita, existe uma máquina MT de fita única equivalente. Na máquina de Turing de fita única, a fita será a concatenação das fitas originais com um símbolo (geralmente **#**) que identifica a divisão entre elas. Ainda, para monitorar a posição do cabeçote em cada fita, é adicionada uma marca ao símbolo atual de cada uma delas.

### Não-Determinística

Assim como nos autômatos finitos, a adição do não-determinismo não representa aumento de poder. É importante compreender que, para toda MT não-determinística, existe uma máquina MT multifita equivalente. Na máquina de Turing equivalente haverão 3 fitas:

- A primeira fita armazena a cadeia de entrada original, que será copiada para a segunda fita a cada execução.
- A segunda fita é a memória de trabalho. É nela que serão realizadas as operações referentes à execução em curso.
- A terceira fita atua como registro dos caminhos não-determinísticos que já foram tomados e de qual será seguido na execução em curso.

### Enumerador

Informalmente, um enumerador é uma máquina de Turing com um *"impressora"* acoplada, através da qual são impressas as cadeias que são aceitas. O enumerador irá imprimir a lista de todas as cadeias que compõem sua linguagem, porém, essa listagem não segue nenhuma ordem específica e não está livre de repetições, o que pode levar a um tempo de processamento infinito.

Sua característica mais importante é que uma linguaguem é Turing-reconhecível se, e somente se, existir um enumerador que a enumere.

## Algoritmos

A **Tese de Church-Turing** é uma hipótese sobre a natureza de computadores e sobre que tipo de **algoritmos** eles podem executar. Ela descreve algoritmos através das seguintes características:

- Um algoritmo é um conjunto finito de instruções simples e precisas, que são descritas com um número finito de símbolos.
- A execução do algoritmo não requer inteligência além da necessária para entender e executar as instruções.
- Um algoritmo sempre produz resultado em um número finito de passos.

A partir da tese acima, é possível mostrar que todo algoritmo pode ser representado por uma máquina de Turing. Além disso, tanto as máquinas de Turing quanto os algoritmos podem ser descritos em três níveis:

- **Baixo:** Utiliza a descrição formal e/ou o diagrama de estados.
- **Médio:** Utiliza a descrição de implementação, apresentando o movimento do cabeçote, os símbolos, a gerência da fita e a codificação da entrada.
- **Alto:** Ignora o cabeçote e os símbolos, além de assumir que a entrada pode ser codificada. Dessa forma, apresenta uma ideia mais geral de como funciona a máquina de Turing.