%%{init: {"flowchart": {"useMaxWidth": false, "rankSpacing": 30, "nodeSpacing": 30}, "sequence": {"useMaxWidth": false}, "class": {"useMaxWidth": false}, "state": {"useMaxWidth": false}, "er": {"useMaxWidth": false}}}%%
flowchart TD
E["desenho com setas faltando: acrescente<br/>o estado de erro, fora da aceitação"]
T["escreva a tabela inteira: uma linha por estado,<br/>inclusive o de erro, e uma coluna por símbolo;<br/>todo par sem seta recebe o erro como destino"]
Q1{"(1) cada célula que aponta<br/>para o erro devia mesmo ir para lá?"}
X["a máquina desenhada é outra:<br/>corrija a seta daquele par"]
Q2{"(2) a linha do erro aponta,<br/>inteira, para o próprio erro?"}
Y["uma saída do erro faria aceitar<br/>cadeia que o desenho recusava"]
OK["a tabela descreve a máquina que você tinha em mente,<br/>e ela reconhece a mesma linguagem do desenho"]
E --> T --> Q1
Q1 -->|"não"| X --> T
Q1 -->|"sim"| Q2
Q2 -->|"não"| Y --> T
Q2 -->|"sim"| OK
Autômatos finitos determinísticos — Atlas
O módulo inteiro em oito peças visuais. Cada uma olha o mesmo conteúdo por um lado: o resumo desenhado, os procedimentos passo a passo, os cartões para treinar de memória, o módulo contado em quadros, o mapa dos tópicos, o painel que junta tudo, a rede de conceitos e a folha para consultar na hora.
Resumo ilustrado
Fluxogramas
Cinco procedimentos do módulo. Siga cada um com o lápis, sobre uma máquina ou uma especificação sua.
Completar o desenho e conferir a tabela
Deixar setas de fora de um desenho é declarar que todos aqueles pares vão para o erro. A conferência mostra se era isso mesmo.
Executar a máquina sobre uma cadeia
Um símbolo por passo, até o fim da cadeia, mesmo depois de uma queda no erro. A aceitação se testa uma vez só, com a cadeia acabada.
%%{init: {"flowchart": {"useMaxWidth": false, "rankSpacing": 30, "nodeSpacing": 30}, "sequence": {"useMaxWidth": false}, "class": {"useMaxWidth": false}, "state": {"useMaxWidth": false}, "er": {"useMaxWidth": false}}}%%
flowchart TD
I["o peão no estado inicial;<br/>a cadeia inteira por ler"]
S{"sobra símbolo<br/>por ler?"}
C{"o símbolo<br/>tem coluna?"}
FA["fora do alfabeto declarado:<br/>anote a posição, se é a primeira<br/>queda; o peão vai ao erro"]
Q{"a célula leva<br/>ao erro pela<br/>primeira vez?"}
QA["anote a posição da queda"]
N["o peão vai ao destino;<br/>avance uma posição"]
FIM["lida a cadeia inteira:<br/>o veredito"]
I --> S
S -->|"sim"| C
C -->|"não"| FA --> S
C -->|"sim"| Q
Q -->|"sim"| QA --> N
Q -->|"não"| N
N --> S
S -->|"não"| FIM
%%{init: {"flowchart": {"useMaxWidth": false, "rankSpacing": 30, "nodeSpacing": 30}, "sequence": {"useMaxWidth": false}, "class": {"useMaxWidth": false}, "state": {"useMaxWidth": false}, "er": {"useMaxWidth": false}}}%%
flowchart TD
L["a cadeia inteira lida"]
F{"o estado<br/>alcançado<br/>está em F?"}
A["aceita"]
H{"houve queda<br/>anotada?"}
R1["recusa com culpado:<br/>mostre a posição; diga se<br/>o símbolo é do alfabeto ou não"]
R3["recusa sem queda:<br/>a cadeia parou cedo;<br/>diga o que se esperava"]
L --> F
F -->|"sim"| A
F -->|"não"| H
H -->|"sim"| R1
H -->|"não"| R3
Projetar a máquina a partir da especificação
A pergunta de fundo é uma só: que informações do passado a máquina tem de carregar adiante?
%%{init: {"flowchart": {"useMaxWidth": false, "rankSpacing": 30, "nodeSpacing": 30}, "sequence": {"useMaxWidth": false}, "class": {"useMaxWidth": false}, "state": {"useMaxWidth": false}, "er": {"useMaxWidth": false}}}%%
flowchart TD
E["especificação em português"]
FIN{"é finito?"}
NAO["nenhuma máquina<br/>finita serve: mostre<br/>uma família infinita<br/>de prefixos"]
S1["(1) liste as situações<br/>que a especificação<br/>obriga a distinguir"]
S2["(2) nomeie cada uma<br/>pelo que ela lembra:<br/>«abri aspas e<br/>ainda não fechei»"]
PAR{"respostas<br/>diferentes?"}
DOIS["ficam dois estados"]
UM["cabem num estado só"]
S3["(3) decida a situação<br/>seguinte para cada<br/>situação e cada símbolo,<br/>sem par em branco"]
S4["(4) marque as situações<br/>em que parar quer dizer<br/>sim; o que sobra sem<br/>nome é o erro"]
E -->|"o que a máquina<br/>precisa lembrar"| FIN
FIN -->|"não"| NAO
FIN -->|"sim"| S1 --> S2 -->|"duas situações,<br/>a mesma continuação"| PAR
PAR -->|"sim"| DOIS --> S3
PAR -->|"não"| UM --> S3
S3 --> S4
%%{init: {"flowchart": {"useMaxWidth": false, "rankSpacing": 30, "nodeSpacing": 30}, "sequence": {"useMaxWidth": false}, "class": {"useMaxWidth": false}, "state": {"useMaxWidth": false}, "er": {"useMaxWidth": false}}}%%
flowchart TD
M["a máquina das etapas (1) a (4)"]
FECHA{"a máquina não fecha,<br/>ou falha num teste?"}
PEAO{"passe o peão por duas cadeias que deviam<br/>ter tratamento diferente: chegam ao mesmo estado?"}
FALTA["falta uma distinção: ela é o nome<br/>do estado novo; volte à etapa (2)"]
SETA["o problema está nas setas:<br/>volte à etapa (3)"]
OK["máquina projetada"]
M --> FECHA
FECHA -->|"não"| OK
FECHA -->|"sim"| PEAO
PEAO -->|"sim"| FALTA
PEAO -->|"não"| SETA
Achar o piso de estados com testemunhas
%%{init: {"flowchart": {"useMaxWidth": false, "rankSpacing": 30, "nodeSpacing": 30}, "sequence": {"useMaxWidth": false}, "class": {"useMaxWidth": false}, "state": {"useMaxWidth": false}, "er": {"useMaxWidth": false}}}%%
flowchart TD
P["para a linguagem L,<br/>escolha prefixos de Σ*,<br/>inclusive os que<br/>levam ao erro"]
PAR["tome um par u, v<br/>ainda não separado"]
Z{"alguma z separa?<br/>comece pela vazia"}
TROCA["tentativa que falha<br/>não prova nada: tente<br/>outra z, ou troque<br/>um dos prefixos"]
TODOS{"todos os pares<br/>separados?"}
K["k prefixos separados<br/>dois a dois: toda<br/>máquina para L tem<br/>pelo menos k estados"]
INF{"a família pode<br/>crescer sem fim?"}
NR["como nos parênteses<br/>balanceados: nenhuma<br/>máquina finita serve,<br/>L não é regular"]
SUF["o piso mostra que<br/>nenhum estado sobra;<br/>que nenhum falta se<br/>prova na máquina"]
P --> PAR --> Z
Z -->|"sim: só uma de<br/>uz e vz está em L"| TODOS
Z -->|"não achei"| TROCA --> PAR
TODOS -->|"não"| PAR
TODOS -->|"sim"| K --> INF
INF -->|"sim"| NR
INF -->|"não"| SUF
Calcular o tamanho da tabela e decidir
%%{init: {"flowchart": {"useMaxWidth": false, "rankSpacing": 30, "nodeSpacing": 30}, "sequence": {"useMaxWidth": false}, "class": {"useMaxWidth": false}, "state": {"useMaxWidth": false}, "er": {"useMaxWidth": false}}}%%
flowchart TD
F["B = n · k · b<br/>n: os estados, com o de erro<br/>k: as colunas do alfabeto declarado<br/>b: os bytes de um destino; o número de estados tem de caber nele"]
V["some o vetor de colunas:<br/>256 entradas por autômato"]
D["conte as células que vão para o erro,<br/>e a fração da tabela que elas ocupam"]
A["anote o tamanho em que a decisão se refaz"]
Q{"fração alta?"}
E{"a escala cresce?"}
OK["aceite a tabela"]
R["refaça a decisão: primeiro as alternativas<br/>que recuperam memória sem perder<br/>a consulta em tempo constante"]
F --> V --> D --> A --> Q
Q -->|"não"| OK
Q -->|"sim"| E
E -->|"não"| OK
E -->|"sim"| R
Cartões de memória
Leia a frente, diga a resposta em voz alta ou escreva no papel, e só então vire o cartão.
História em quadros
O módulo contado do começo ao fim, um quadro por passo, na ordem em que o livro avança.
Mapa mental
Os tópicos do módulo, do centro para fora, na ordem do livro.
Painel do conhecimento
Conceitos
- Autômato finito determinístico: a quíntupla M = (Q, \Sigma, \delta, q_0, F), com a função de transição \delta : Q \times \Sigma \to Q total.
- Estado de erro: o estado absorvente fora de F; o completamento o acrescenta sem mudar a linguagem.
- Configuração: o par (q, w), o estado e o que falta ler.
- Linguagem reconhecida, L(M): as cadeias que, lidas inteiras, levam o peão a F; é regular por definição.
- Prefixos distinguíveis: separados por uma testemunha; k deles, dois a dois, dão o piso de k estados.
- Tabela de transição: a função total guardada em memória, que custa B(n,k,b) = n \cdot k \cdot b bytes na matriz densa.
Exemplos
valor_2: aceita, em oito configurações.2valor: recusa, com queda no erro na posição 0.42.: recusa sem cair no erro, parada emapos_ponto.++5: recusa na posição 1; o segundo+encontra o peão emsinal.- Identificador: dois estados úteis; número com sinal: cinco; comentário de linha: três.
Diagrama
%%{init: {"flowchart": {"useMaxWidth": false, "rankSpacing": 30, "nodeSpacing": 30}, "sequence": {"useMaxWidth": false}, "class": {"useMaxWidth": false}, "state": {"useMaxWidth": false}, "er": {"useMaxWidth": false}}}%%
flowchart TD
I["inicio<br/>não aceita"] -->|"+ -"| S["sinal<br/>não aceita"]
I -->|"dígito"| N["inteiro<br/>aceita"]
S -->|"dígito"| N
N -->|"dígito"| N
N -->|"ponto (.)"| P["apos_ponto<br/>não aceita"]
P -->|"dígito"| FR["fracao<br/>aceita"]
FR -->|"dígito"| FR
Evidências
- 1943: McCulloch e Pitts publicam, no The Bulletin of Mathematical Biophysics, um modelo do sistema nervoso com estados em número finito.
- Dezembro de 1951: Kleene escreve o memorando RM-704, da RAND, com a notação das expressões regulares; o texto sai em livro em 1956.
- 1957 e 1958: Myhill e Nerode chegam ao resultado completo sobre o número de estados, cada um em separado; a contribuição de Myhill está num relatório técnico de circulação restrita.
- As contagens das três máquinas (células, bytes, transições que não vão ao erro) são as que o programa do projeto de referência calcula e imprime.
Referências
- McCulloch e Pitts, A logical calculus of the ideas immanent in nervous activity, The Bulletin of Mathematical Biophysics, v. 5, n. 4, p. 115–133, 1943.
- Kleene, Representation of events in nerve nets and finite automata, em Automata Studies, Princeton University Press, 1956, p. 3–41.
- Nerode, Linear automaton transformations, Proceedings of the American Mathematical Society, v. 9, n. 4, p. 541–544, 1958.
- Rabin e Scott, Finite automata and their decision problems, IBM Journal of Research and Development, v. 3, n. 2, p. 114–125, 1959.
- Leitura complementar: Hopcroft, Motwani e Ullman; Menezes (Grupo A, 2011).
Aplicações
- Um reconhecedor chamado sobre texto qualquer: recusar é o funcionamento normal, e num sistema que testa vários padrões na mesma posição o padrão que falha cede a vez.
- No projeto de referência, cada tabela se calcula antes de se escrever: 888, 624 e 896 bytes.
- As tarefas do módulo: decidir a representação da função de transição, com a conta, e executar uma máquina descrita à mão.
- Adiante: a máquina construída a partir da expressão (04), a determinização e a redução de estados (05), a segunda rota para provar que uma linguagem não é regular (06).
Mapa conceitual
Escreva num papel: autômato finito determinístico, função de transição, estados, completamento, estado de erro, estados de aceitação, configuração, passo de computação, linguagem reconhecida, linguagem regular, recusa, prefixos distinguíveis, testemunha, limite inferior, tabela de transição, matriz densa, vetor de colunas, B(n,k,b). Ligue os conceitos com setas, e escreva em cada seta um verbo que diga qual é a relação. Depois compare com o mapa.
Folha de consulta
A quíntupla
- M = (Q, \Sigma, \delta, q_0, F): estados, alfabeto, transição, estado inicial, estados de aceitação
- \delta : Q \times \Sigma \to Q é total: n \cdot k valores, para n estados e k símbolos
- um estado inicial só; F = \emptyset e F = Q são legítimos
- completar: um estado de erro a mais, com as suas \lvert\Sigma\rvert setas, e destino para cada par sem seta
- absorvente fora de F: estado de erro; em F: aceitação irreversível
Executar e aceitar
- configuração: (q, w); a inicial é (q_0, w)
- passo: (q, aw) \vdash_M (\delta(q,a), w)
- \hat{\delta}(q, \varepsilon) = q; \hat{\delta}(q, wa) = \delta(\hat{\delta}(q, w), a)
- w \in L(M) quando \hat{\delta}(q_0, w) \in F
- \varepsilon \in L(M) se e somente se q_0 \in F
- n símbolos: exatamente n passos, aceita ou recusada
Projetar
- liste as situações; (2) nomeie cada uma pelo que ela lembra; (3) dê destino a cada par; (4) marque as de aceitação
- símbolo que exige o que só vem depois: um estado intermediário que nunca é de aceitação
- viradas mais a situação inicial: identificador 1 + 1 = 2, comentário de linha 2 + 1 = 3, número com sinal 4 + 1 = 5 estados úteis
- a soma confere uma máquina projetada; ela não é fórmula geral
O piso
- u e v distinguíveis: existe z com exatamente uma de uz e vz em L
- a testemunha z pode ser \varepsilon
- k prefixos distinguíveis dois a dois: todo autômato para L tem pelo menos k estados, contado o de erro se algum prefixo levar a ele
- número com sinal: \varepsilon,
+,4,4.,4.5; testemunhas+5,5.5,.5e \varepsilon - família infinita de prefixos dois a dois distinguíveis: a linguagem não é regular
Contas da tabela
| Máquina | n | k | Células | Bytes | Não-erro |
|---|---|---|---|---|---|
| identificador | 3 | 37 | 111 | 888 | 63 |
| número com sinal | 6 | 13 | 78 | 624 | 53 |
| comentário de linha | 4 | 28 | 112 | 896 | 30 |
- B(n,k,b) = n \cdot k \cdot b, com n contando o estado de erro e b = 8 bytes por destino
- a outra escrita: (n+1) \times m, com n estados úteis e m símbolos
- índice da célula: q \cdot k + c
- vetor de colunas: 256 entradas por autômato, 256 \times 8 = 2.048 bytes
- destinos de 2 bytes: no máximo 65.536 estados
Três recusas
- símbolo do alfabeto cuja transição leva ao erro:
2valor, posição 0;/x, posição 1 - símbolo fora do alfabeto declarado:
//OK, posição 2 - cadeia inteira lida, parada fora de F:
42., sem queda - a mensagem útil diz o que se esperava: «esperava-se um dígito após o ponto decimal»
Erros previsíveis
- «a função de transição pode ser parcial»: a definição a exige total; o desenho com setas faltando é abreviação, e o completamento a legitima
- «todo estado absorvente é estado de erro»: o absorvente em F é aceitação irreversível
- «aceita se passar por um estado de aceitação»: vale o estado depois da cadeia inteira, e
42.é recusada - «recusa implica cair no erro»:
42.é recusada sem cair - «a testemunha tem de ser não vazia»: \varepsilon separa sempre que só um dos dois prefixos está em L
- «a distinguibilidade é transitiva»: exija a separação dois a dois
- «k prefixos distinguíveis provam que k estados bastam»: provam só que nenhum sobra
- «ler o sinal não cria estado»:
+5separa o início do estadosinal - «a matriz densa economiza memória»: ela perde em memória para o mapa esparso e ganha no custo por símbolo consumido