Apostila LFA.pdf
-
Upload
vladimirpi -
Category
Documents
-
view
35 -
download
2
Transcript of Apostila LFA.pdf
UNIVERSIDADE ESTADUAL DO MATO GROSSO DO SUL
CURSO DE CIÊNCIA DA COMPUTAÇÃO
APOSTILA DE AULA
DISCIPLINA DE LINGUAGENS FORMAIS E AUTÔMATOS
Professora Viviane Duarte Bonfim
Lages, Agosto de 2009.
UEMS - Professora Viviane Duarte Bonfim
2
SUMÁRIO
1. SISTEMAS FORMAIS, GRAMÁTICAS E MODELOS ABSTRATOS DO COMPUTADOR ........... 5
1.1 Sistemas Formais ................................................................................................................................ 5
1.2 Origem Sistemas Formais ................................................................................................................... 5
1.3 Métodos Formais ................................................................................................................................. 6
1.4 Linguagens Formais ........................................................................................................................... 6
1.5 Gramáticas ......................................................................................................................................... 10
1.5.1 Definição Formal de Gramática .................................................................................................. 11
1.5.2 Derivação e Redução .................................................................................................................... 12
1.5.3 Notação ......................................................................................................................................... 13
1.5.4 Linguagens Definidas por Gramáticas ........................................................................................ 13
1.5.5 Sentença, Forma Sentencial e Linguagem .................................................................................. 14
1.6 Tipos deLinguagens/ Gramáticas ..................................................................................................... 14
1.7 Tipos de Linguagens – Representação gráfica ................................................................................. 15
2. LINGUAGENS REGULARES ................................................................................................................. 16
2.1 Operações de Concatenação e Fechamento ..................................................................................... 16
2.1.1. Definição de Expressões Regulares ............................................................................................. 17
2.2. AUTÔMATOS FINITOS ........................................................................................................................ 18 2.2.1. Autômatos Finitos Determinísticos .............................................................................................. 18
2.2.2. Autômatos Finitos Não-Determínisticos ...................................................................................... 20
2.2.3. Transformação de A.F.N.D. para A.F.D. .................................................................................... 21
2.2.4. Relação entre G.R. e A.F. ............................................................................................................. 22
2.2.5. Minimização de Autômatos Finitos: ............................................................................................ 25
2.2.6. Aplicações de A.F. e E.R. ............................................................................................................. 27
3. GRAMÁTICAS L IVRES DE CONTEXTO .................................................................................................... 29
3.1. SIMPLIFICAÇÕES DE GRAMÁTICAS L IVRES DE CONTEXTO ............................................................. 29 3.1.1. Símbolos Inúteis ........................................................................................................................... 29
3.1.2. Eliminação de εεεε-produções .......................................................................................................... 30
3.1.3. Produções Unitárias ..................................................................................................................... 30
3.1.4. Eliminação de Recursão à Esquerda ........................................................................................... 31
3.1.5. Fatoração à Esquerda .................................................................................................................. 31
3.2. CONJUNTOS FIRST E FOLLOW .......................................................................................................... 32 3.2.1. Conjunto First ............................................................................................................................... 32
3.2.2. Conjunto Follow ........................................................................................................................... 33
3.3. AUTÔMATOS COM PILHA .................................................................................................................. 33 3.3.1. Modelagem de MEF’s como SD’s ................................................................................................ 35
4. TEORIA DA COMPUTAÇÃO - TEORIA DE PROBLEMAS: DECIDIB ILIDADE, COMPUTABILIDADE E COMPLEXIDADE .................... ............................................................................. 37
4.1. INTRODUÇÃO ..................................................................................................................................... 37
4.1.1. Conceitos e Propósitos Fundamentais da Teoria da Computação .............................................. 38
4.2. TEORIA DE PROBLEMAS .................................................................................................................... 41 4.2.1. Solucionabilidade de Problemas .................................................................................................. 41
4.2.2. Decidibilidade ............................................................................................................................... 41
4.2.3. Princípio da Resolução de Problemas .......................................................................................... 42
4.2.4. Classes de Solucionabilidade de Problemas ................................................................................ 42
4.2.5. Definição Formal de Problema .................................................................................................... 43
4.2.6. Modos de Definir uma Função .................................................................................................... 45
4.3. COMPUTABILIDADE ........................................................................................................................... 46 4.3.1. Origem da Computabilidade ......................................................................................................... 46
4.3.2. Computabilidade de Funções ....................................................................................................... 49
4.3.3. Problema da Parada ..................................................................................................................... 50
4.3.4. Exemplo Problemas Não Computáveis ........................................................................................ 54
4.3.5. Computabilidade Parcial .............................................................................................................. 55
4.3.6. Complexidade ................................................................................................................................ 56
4.3.7. Recursos Computacionais ............................................................................................................ 56
4.3.8. Problemas Tratáveis e Intratáveis ................................................................................................ 58
UEMS - Professora Viviane Duarte Bonfim
3
4.3.9. Modelo Formal de Algoritmo: Máquina de Turing .................................................................... 59
REFERÊNCIAS BIBLIOGRÁFICAS............................................................................................................... 60
UEMS - Professora Viviane Duarte Bonfim
4
INTRODUÇÃO
Teoria de Linguagens Formais e Teoria de Máquina são práticas abrangentes que se inserem
no estudo da Teoria da Computação em geral. A teoria da Computação é uma ciência que procura
organizar o conhecimento formal relativo aos processos de computação, como complexidade de
algoritmos, linguagens formais, problemas intratáveis.
Atualmente, o termo “computar” está associado ao conceito de fazer cálculos ou aritmética,
usando para isso máquinas computadoras. Entretanto, a noção de computabilidade pode ser
dissociada da implementação física da máquina. Originalmente a palavra latina putare significa
“pensar”, mas no caso da teoria da computação o sentido mais adequado seria algo como
“manipulação de símbolos”, o que não é necessariamente, pensamento. Essa manipulação de
símbolos envolvendo, principalmente letras, números e proposições algébricas permitiriam às
máquinas computadoras, segundo Alan Turing (1939) realizar qualquer operação formal de que o ser
humano seria capaz.
Mesmo assim, alguns filósofos sustentavam que os computadores não poderiam computar
(fazer aritmética), porque não compreende a noção de número (apenas manipulam sinais elétricos).
Todavia, pode-se falar, sem entrar no mérito da questão, que os computadores realizam uma
“computação perceptível”, já que transforma uma entrada em saída como se estivessem realmente
computando. Neste caso, o que importa é o efeito final do processo e não a maneira como ele é
realizado.
UEMS - Professora Viviane Duarte Bonfim
5
1. Sistemas Formais, Gramáticas e Modelos Abstratos do Computador
1.1 Sistemas Formais
São Sistemas de manipulação de formas, sem preocupação de que estas formas significam no
mundo real.
A essência de um Sistema Formal é a Sintaxe.
Semântica – escrever de maneira correta – lexicograficamente.
Sintaxe: escrita na ordem correta. Manipula símbolos.
Ex. 15::=Resultado+10 (erro) – passaria pelo bloco léxico pois os tokens estão escritos de
maneira correta. Mas não passaria no bloco sintático.
1.2 Origem Sistemas Formais
A primeira notícia de que se tem de um sistema formal são os trabalhos de Euclides (300A.C.).
Estes trabalhos organizam e sistematizam todo o conhecimento da época com relação à Geometria e
são conhecidos sob nome de Elementos. Pela primeira vez, a apresentação é feita através de axiomas,
definições, postulados, teoremas e demonstrações.
O arcabouço básico dos Sistemas Formais é devido a René Descartes (1596-1650) e de
Leibniz (1646-1716) sobre linguagens e alfabetos. Frege (1848-1925), Peano (1858-1932), Whitehead
(1861-1947), Bertran Russel (1872-1970) e Wittgenstein (1889-1951) criaram a formalização como se
costuma apresentar.
Na construção de um Sistema Formal deve-se concentrar atenção na forma com que se
trabalha. As Linguagens Naturais, aquelas usadas entre seus seres humanos para se comunicarem
possuem ambigüidades que impedem seu uso para este propósito. Portanto, torna-se necessário, dar
um passo na direção de evitar estas ambigüidades o que é feito usando uma linguagem constituída por
um conjunto bem definido de símbolos e de regras de derivação, permitindo construir novos objetos a
partir daqueles disponíveis.
UEMS - Professora Viviane Duarte Bonfim
6
1.3 Métodos Formais
Podem ser aplicados em diversos domínios, dependendo do contexto. São técnicas com
fundamentos matemáticos usados para descrever e analisar propriedades de Sistemas. Um dos
motivos de usar métodos formais é avaliar ou eliminar as ambigüidades e inconsistências na
especificação. Normalmente cada método formal está associado a uma linguagem formal. A
Linguagem formal possui sua sintaxe e sua semântica bem definidas.
É possível provar que um programa, ou parte dele, sempre termina em um tempo finito.
1.4 Linguagens Formais
O que é a Teoria das Linguagens Formais?
Para responder esta questão precisa-se primeiro responder o que é Linguagem Formal, e para
isto precisamos antes responder o que é Linguagem.
Inicialmente, de maneira bastante informal, podemos definir uma linguagem como sendo uma
forma de comunicação. Elaborando um pouco mais esta definição, podemos definir uma linguagem
como sendo “um conjunto de elementos (símbolos) e um conjunto de métodos (regras) para combinar
estes elementos, usado e entendido por uma determinada comunidade”.
Exemplos: 1 - Linguagens Naturais (ou idiomáticas)
2 - Linguagens de Programação, de Controle, de Consulta
3 – Protocolos de Comunicação
Contudo, apesar de intuitiva, esta definição não nos permite responder satisfatoriamente as
duas primeiras questões; precisamos antes dar um sentido formal para a definição de linguagem.
Faremos isto nas duas próximas seções.
O estudo dos diversos tipos de linguagens aplica-se a diversas áreas de informática, sempre
que for necessário analisar o formato e o significado de uma seqüência de entrada.
O estudo das linguagens formais, sob a forma de gramáticas é a base da teoria da
interpretação e compilação. A decisão de uma seqüência constitui uma unidade válida para a
linguagem é baseada em regras definidas.
O nome Teoria de Linguagens Formais é devido a que regras para uma linguagem devem ser
explicitamente definidas em termos de quais seqüências ou cadeias (“strings”) podem ocorrer. O
estudo de linguagens formais objetiva como “especificar” um conjunto de cadeias para uma
determinada linguagem.
UEMS - Professora Viviane Duarte Bonfim
7
Conceitos Básicos:
Linguagem Formal: é o conjunto de palavras sobre um alfabeto.
� Um Alfabeto é definido simplesmente como um conjunto finito de símbolos. Por exemplo,
o alfabeto da língua portuguesa é V = {a, b, c, d..., z}. O alfabeto utilizado para expressar
os números naturais é V = {1, 2, 3, 4, 5, 6, 7, 8, 9, 0}.
� Um Símbolo é uma entidade abstrata que não precisa ser definida formalmente, assim
como “ponto” e “linha” não são definidos na geometria. Letras e dígitos são exemplos de
símbolos freqüentemente usados.
Símbolos são ordenáveis lexicograficamente e, portanto, podem ser comparados quanto à
sua igualdade. Por exemplo, tomando as letras do alfabeto, pode-se Ter a ordenação a < b
< c < ...< z. A utilidade dos símbolos está na possibilidade de usá-los como elementos
atômicos em definições de linguagens.
� Uma sentença sobre um alfabeto V, é uma seqüência (ou cadeia) finita de símbolos do
alfabeto.
Exemplo de sentenças sobre V = { a , b }: a, b, aa, ab, bb, aaa, aab, aba, baa, ...
� Tamanho de uma sentença: Seja w uma sentença ∀.
O tamanho da sentença w, denotado por |w|, é definido pelo número de símbolos
(elementos do alfabeto) que compõem w.
Exemplos: Seja V = { a , b , c }
se x = aba, então |x| = 3
se x = c, então |x| = 1
� Sentença vazia é uma sentença constituída de nenhum símbolo; isto é, uma sentença de
tamanho 0 (zero).
Observações: Representa-se a sentença vazia por ε (épsolon).
- Por definição, |ε| = 0
UEMS - Professora Viviane Duarte Bonfim
8
� Uma Cadeia é uma seqüência finita de símbolos justapostos (sem vírgula separando os
caracteres). Por exemplo, se a, b e c são símbolos, então abcb é um exemplo de cadeia
utilizando estes símbolos.
O tamanho de uma cadeia é o comprimento da seqüência se símbolos que a forma. O
tamanho de uma cadeia w é denotado por |w|. Por exemplo, |abcb| = 4. A cadeia vazia é
denotada por ε., e tem tamanho igual a 0; assim |ε| = 0.
Um prefixo de uma cadeia é um número qualquer de símbolos tomados de seu início, e um
sufixo é um número qualquer de símbolos tomados de seu fim. Por exemplo, a cadeia abc
tem prefixo ε a, ab e abc. Seus sufixos próprios são ε, c, bd, abc. Um prefixo ou sufixo que
não são a própria cadeia são chamados de prefixo próprio e sufixo próprio. No exemplo
anterior, os prefixos próprios são ε, a e ab; e os sufixos próprios são ε, c e bc.
� Potência de uma sentença: Seja w uma sentença ∀. A n-ésima potência de w,
representada por wn, significa w repetido n vezes.
Exemplos: se x = ab, então x3 = ababab
Para ∀ x, x0 = ε
� A Concatenação de duas cadeias é a cadeia formada pela escrita da primeira cadeia
seguida da Segunda, sem nenhum espaço no meio. Por exemplo, a concatenação de
compila e dores é compiladores. O operador de concatenação é a justaposição. Isto é, se
w e x são variáveis que denotam cadeias, então wx é a cadeia formada pela concatenação
de w e x. No exemplo acima, se tornarmos w=compila e x=dores, tem-se compiladores.
� O Fechamento de um Alfabeto V, representado por V*, é o conjunto de todas as cadeias
que podem ser formadas com símbolos de V, inclusive a cadeia vazia. O Fechamento
Positivo de V, denotado por V+ é definido como V* - {ε}. Ou seja, todas as cadeias
formadas com os símbolos de V, exceto a cadeia vazia.
Linguagens e suas representações:
� Uma Linguagem (formal) é um conjunto de cadeias de símbolos tomados de algum
alfabeto. Isto é, uma linguagem sobre o alfabeto V é um subconjunto de V*. Esta definição
não considera-se mecanismos formadores da linguagem, mas apenas a sua extensão.
UEMS - Professora Viviane Duarte Bonfim
9
Assim, por exemplo, o conjunto de sentenças válidas da língua portuguesa poderia ser
definido como um subconjunto de {a, b, c,.., z}+.
� Representações de Linguagens: O estudo de linguagens está intimamente relacionado
ao estudo das formas de representação dessas linguagens. O problema de representação
de uma linguagem, por sua vez, está relacionado com o fato dela ser finita ou infinita:
Linguagem Finita: É uma Linguagem que pode ser representada por enumeração.
Exemplo: A linguagem definida como sendo o conjunto dos inteiros positivos pares
maiores que 0 e menores que 20, pode ser representado por: L = {2, 4, 6, 8, 10, 12, 14, 16, 18}.
Linguagem Infinita: Neste caso, na impossibilidade de usarmos enumeração,
precisamos encontrar uma representação finita para estas linguagens.
Exemplo: A linguagem definida como sendo o conjunto dos inteiros pares poderia ser
representada por V ={2, 4, 6, 8, 10,...} que, que apesar de intuitiva, não é finita e nem precisa.
As representações finitas de linguagens classificam-se em Reconhecedores e Sistemas
Geradores:
� Um Reconhecedor para uma linguagem é um dispositivo formal usado para verificar se
uma determinada sentença pertence ou não a uma determinada linguagem. São exemplos
de reconheceres de linguagens, as Máquinas de Turing, o Autômato de pilha e o
Autômato Finito. Cada um destes mecanismos reconhece um conjunto bastante particular
de linguagens. Entretanto, os modelos são inclusivos: todas as linguagens reconhecíveis
por um Autômato Finito podem ser reconhecidas por um Autômato de Pilha e todas as
linguagens reconhecíveis por um autômato de pilha são reconhecíveis por Máquinas de
Turing.
� Um Sistema Gerador é um dispositivo formal através do qual sentenças de uma
linguagem podem ser sistematicamente geradas. Exemplos de sistemas geradores são as
gramáticas gerativas, definidas pela primeira vez por Noam Chomsky, em seus estudos
para sistematizar a gramática da língua inglesa.
Todo Reconhecedor e todo sistema gerador pode ser representado por algoritmos e/ou
procedimentos. Pode-se garantir que linguagens reconhecidas por autômatos são reconhecidas
algoritmicamente. Já o conjunto das linguagens reconhecidas por Máquinas de Turing, que é mais
UEMS - Professora Viviane Duarte Bonfim
10
abrangente, inclui linguagens reconhecíveis algoritmicamente e linguagens indecidíveis, que não
possuem algoritmos para reconhecimento.
� Linguagens Formais: São linguagens que podem ser representadas de maneira finita e
precisa através de sistemas com sustentação matemática (dispositivos formais ou modelos
matemáticos).
Obs: Entende-se por Teoria das Linguagens Formais e dos Autômatos o estudo de modelos
matemáticos que possibilitam a especificação e o reconhecimento de linguagens (no sentido amplo da
palavra), suas classificações, estruturas, propriedades, características e inter-relacionamentos.
A importância desta Teoria na Ciência da Computação é dupla: Ela tanto apóia outros aspectos
teóricos da Ciência da Computação (decidibilidade, computabilidade, complexidade computacional, por
exemplo), como fundamenta diversas aplicações computacionais tais como processamento de
linguagens, reconhecimento de padrões, modelagem de sistemas.
1.5 Gramáticas
Sabe-se que uma linguagem é qualquer conjunto ou subconjunto de sentenças sobre um
alfabeto, ou seja: dado um alfabeto V, uma linguagem L sobre esse alfabeto, é um subconjunto de V*∴
L ⊆ V*.
Assim sendo, devemos nos preocupar em definir que subconjunto é esse.
A finalidade de uma gramática é definir o subconjunto de V* que forma (define) uma
determinada linguagem. Uma gramática define uma estrutura sobre um alfabeto de forma a permitir
que apenas determinadas combinações sejam válidas, isto é, sejam consideradas sentenças (definindo
assim a linguagem que ela representa).
O que é Gramática?
Uma gramática, de maneira informal, pode ser definida como sendo:
a) Um sistema gerador de linguagens;
b) Um sistema de reescrita;
c) Uma maneira finita de descrever (representar) uma linguagem;
d) Um dispositivo formal usado para especificar de maneira finita e precisa uma linguagem
potencialmente infinita.
UEMS - Professora Viviane Duarte Bonfim
11
Uma gramática gerativa é um instrumento formal capaz de construir (gerar) conjuntos de
cadeias de uma determinada linguagem. As gramáticas são instrumentos que facilitam muito a
definição das características sintáticas das linguagens. São instrumentos que permitem definir, de
forma formal e sistemática, uma representação finita para linguagens infinitas.
Exemplo intuitivo de uma Gramática:
(um subconjunto da gramática da língua portuguesa)
<sentença> :: = <sujeito> <predicado>
<sujeito> :: = <substantivo>
| <artigo> <substantivo>
| <artigo> <adjetivo> <substantivo>
<predicado> :: = <verbo> <objeto>
<substantivo> :: = joão | Maria | cachorro | livro | pão
<artigo> :: = o | a
<adjetivo> :: = pequeno | bom | bela
<verbo> :: = morde | le | olha
<objeto> :: = <substantivo>
| <artigo> <substantivo>
| <artigo> <adjetivo> <substantivo>
Notação utilizada:
< ......... > : categoria sintática ou gramatical;
::= : definido por
| : ou (alternativa)
α ::= β : regra de sintaxe (ou regra gramatical ou regra de produção)
1.5.1 Definição Formal de Gramática
Uma gramática possui um conjunto finito de variáveis (não-terminais). A linguagem gerada por
uma gramática é definida recursivamente em termos de variáveis e de símbolos primitivos chamados
terminais, que pertencem ao alfabeto da linguagem.
UEMS - Professora Viviane Duarte Bonfim
12
As regras que relacionam variáveis e terminais são chamados de produções, que sempre
iniciam num ponto, o símbolo inicial. Uma regra de produção típica estabelece como uma determinada
configuração de variáveis e terminais pode ser reescrita, gerando uma nova configuração.
Uma Gramática é especificada por uma quádrupla (N,T,P,S), onde:
� N é o conjunto de não-terminais, ou variáveis.
� T é o conjunto de terminais, ou alfabeto, sendo que N e T são conjuntos disjuntos (não se
misturam)
� P é um conjunto finito de produções, ou regras, sendo que P⊆(N∪T)+ X (N∪T)*
� S é o símbolo não terminal inicial, sendo S∈N. a partir dele são geradas todas as
sentenças da linguagem.
Uma produção (n,p) pode ser escrita n::=p, para facilitar a leitura. No caso de existir mais de
uma alternativa para uma mesma configuração e símbolos do lado esquerdo da regra, como exemplo:
<substantivo> ::= coisa
<substantivo> ::= cão
<substantivo> ::= pedra
pode-se escrever as opções em uma única produção, separada por |. O mesmo ex. ficaria:
<substantivo> ::= coisa | cão | pedra
O símbolo ::= pode ser lido como “ é definido por” e o símbolo | pode ser lido como “ou”.
1.5.2 Derivação e Redução
São operações de substituição que formalizam a utilização de gramáticas, sendo que:
Derivação: É a operação que consiste em substituir em string (ou parte dele) por outro, de acordo com
as produções das gramáticas em questão, no sentido símbolo inicial → sentença;
Uma gramática pode ser usada para gerar um linguagem através de reescrita ou derivação.
Ex. dada uma sentença aba; se existir uma regra da forma b::=c, então a sentença inicial pode
ser reescrita como acd. Denotada por:
abd -> acd
Na sentença aaaDbbB e existe a produção D ::= ab na gramática. Então a derivação aaaDbbb
-> aaaabbbb
Redução: É a operação que consiste na substituição de um string (ou parte dele) por outro, de acordo
com as produções da gramática, no sentido sentença → símbolo inicial.
UEMS - Professora Viviane Duarte Bonfim
13
Observação: derivação é a operação adequada para geração de sentenças; enquanto que a operação
de redução é adequada ao reconhecimento de sentenças.
1.5.3 Notação
Como conversão notacional, pode-se admitir que símbolos não-terminais serão sempre
representados por letras maiúsculas, e terminais por letras minúsculas. Assim, uma regra como <a> ::=
<a>b | b poderia ser escrita como A::= Ab | b. Além disso, os conjuntos T e N podem ficar
subentendidos e não precisam ser expressos sempre.
Pode-se ainda arbitrar que o símbolo inicial S será o não-terminal que aparecer primeiro do
lado esquerdo da primeira produção da gramática. Assim, bastaria listar as regras de produção para se
Ter a definição completa da gramática. Por exemplo, a gramática:
S ::= ABSc | ε
BA ::= AB
Bc ::= bc
Ab ::= ab
Bb ::= bb
Aa ::= aa
Tem como símbolo inicial S, o conjunto de terminais é {a, b, c} e o conjunto dos não-terminais
(variáveis) é {A, B, C}. As produções estão detalhadas. Tem-se assim a definição completa da
gramática.
1.5.4 Linguagens Definidas por Gramáticas
A linguagem definida por uma gramática consiste no conjunto de cadeias de terminais que esta
gramática pode gerar. Este conjunto será denotado por L(G). A linguagem definida por uma gramática
G=(N,T,P,S) é dada por:
L(G) = { α| α ∈ T* ∧ S → * α }
Uma cadeia pertence a L(G) se e somente se ela consiste somente de terminais (pode ser a
cadeia vazia ε), e pode ser produzida a partir de S em 0 ou mais derivações.
Forma sentencial se ela pode ser reproduzida a partir de S mas ainda contém não terminais, aaaBbbC.
Já aabb já é uma sentença pois possui apenas terminais.
UEMS - Professora Viviane Duarte Bonfim
14
1.5.5 Sentença, Forma Sentencial e Linguagem
Sentença – É uma seqüência só de terminais produzida (gerada) a partir do símbolo inicial de
uma gramática; isto é, se G = (Vn, Vt, P, S) ∧∧∧∧ S x, então x é uma sentença pertencente à linguagem
representada por G.
Forma Sentencial – É uma seqüência qualquer (composta por terminais e não-terminais)
produzida (gerada) a partir do símbolo inicial de uma gramática; isto é,
se G = (Vn, Vt, P, S) ∧∧∧∧ S ⇒⇒⇒⇒ αααα ⇒⇒⇒⇒ ββββ ⇒⇒⇒⇒ ………… ⇒⇒⇒⇒ γγγγ ⇒⇒⇒⇒ ………… então αααα, ββββ, …………,γγγγ, …………são formas sentenciais de
G.
Linguagem – Formalmente definimos a linguagem gerada por G = (Vn, Vt, P, S), denotada por
L(G), como sendo: L(G) = {x | x ∈∈∈∈ Vt* ∧∧∧∧ S x}; ou seja, uma linguagem é definida pelo conjunto de
sentenças que podem ser derivadas a partir do símbolo inicial da gramática que a representa.
Gramáticas Equivalentes – Duas gramáticas G1 e G2 são equivalentes entre si, se e somente
se L(G1) = L(G2).
Formalmente: G1 ≡≡≡≡ G2 ⇔⇔⇔⇔ L(G1) = L(G2).
Exemplos:
1.6 Tipos deLinguagens/ Gramáticas
Impondo restrições na forma das produções, pode-se identificar quatro tipos diferentes de
gramáticas. Essa classificação foi feita por Chomsky e é conhecida como hierarquia de Chomsky. Os
tipos de gramáticas definidos nesta hierarquia são:
a) Tipo 0: Não há restrição na forma de das produções. É o tipo mais geral. Exemplo:
S ::= ABS | ab Ba ::= aB | a Aa ::= aa | a | ε
b) Tipo 1: Seja G=(N,T,P,S). Se:
� O símbolo Inicial S não aparece no lado direito de nenhuma produção, e
� Para cada produção σ1 ::= σ2
( o nº de símbolos da direita tem que ser igual ou maior o da esquerda)
então se diz que G é uma gramática do tipo 1, ou Gramática Sensível ao Contexto. Exemplo:
S ::= aBC | aABC A ::= AABC | aBC CB ::= BC
aB ::= ab bB ::= bb bC ::= bc cC ::= cc
⇒+
⇒+
UEMS - Professora Viviane Duarte Bonfim
15
c) Tipo 2: Uma Gramática G=(N,T,P,S) é do tipo 2, ou Gramática Livre de Contexto, se cada
produção é livre de contexto, ou seja, cada produção da forma: (No lado esquerdo tem apenas um
símbolo não-terminal.
A ::= σ com A ∈ N e σ ∈ (T ∪ N)*
Exemplo:
S ::= aSb | A A ::= cAd | e
O Tipo 2 não é definido como restrição do tipo 1, porque se permite produções da forma A ::= ε ;
também se permite que o símbolo S apareça no lado direito das produções.
d) Tipo 3: Uma gramática G é do tipo 3, ou regular, se cada produção é da forma A::= aB, A ::= a, A
::= ε, onde A e B são não-terminais e a é um terminal.
(Do lado esquerdo apenas um não terminal, e do lado direito, pode ter o epson, um terminal e um
não-terminal).
Exemplo:
S ::= aS | bB B ::= bB | bC C ::= cC | ε
1.7 Tipos de Linguagens – Representação gráfica
Uma Linguagem L é do tipo i se existe uma gramática G de tipi i tal que L = L(G), para i igual 0,
1, 2, 3.
Pode-se relacionar cada tipo de gramática com uma máquina reconhecedora da seguinte
maneira: a gramática do tipo 0 e 1 gera linguagens reconhecíveis por Máquinas de Turing; a gramática
do tipo 2 gera linguagens reconhecíveis por autômatos de pilha; a gramática do tipo 3 gera linguagens
reconhecíveis por autômatos finitos.
Representação:
Figura 1: Tipos de Linguagens.
UEMS - Professora Viviane Duarte Bonfim
16
2. Linguagens Regulares
As Linguagens Regulares constituem um conjunto de linguagens decidíeis bastante simples e
com propriedades bem definidas e compreendidas. Essas linguagens podem ser reconhecidas por
autômatos finitos e são facilmente descritas por expressões simples, chamadas expressões regulares
(E.). Antes de introduzir o mecanismo das E.R.s, será feito uma revisão sobre operações de
concatenação e fechamento de conjuntos, operações básicas para E.R.s.
2.1 Operações de Concatenação e Fechamento
Seja C um conjunto finito de símbolos (alfabeto), e sejam L, L1 e L2 subconjuntos de C*
(linguagens sobre o alfabeto C). A concatenação de L1 e L2, denotada por L1L2 é o conjunto { xy | x ∈
L1 e y ∈ L2}. Em outras palavras, as cadeias da linguagem L1L2 são formadas por uma cadeia de L1
concatenada a uma cadeia de L2, nesta ordem, incluindo aí todas as combinações possíveis.
Defini-se L0 = {ε} e Ln = LL n-1 para n ≥ 1. O fecho de Kleene ( ou simplesmente fecho) de uma
linguagem L, denotado por L*, é o conjunto:
L* = U Li
e o fecho positivo da linguagem L, denotado por L+, é o conjunto:
L+ = U Li
Em outras palavras, L* denota as cadeias construídas pela concatenação de qualquer número
de cadeias tomadas de L. O conjunto L+ é semelhante, mas neste caso, as cadeias de zero palavras,
cuja concatenação é definida como ε, são excluídas. Nota-se, porém, que L+ contém ε se e somente
se L contém. Esta definição difere da definição do fechamento de alfabetos, onde A+ era definido como
A* - {ε}. No caso da linguagem, pode ocorrer dois casos:
� Se ε ∈ L, então L+ = L*;
� Se ε ∉ L, então L+ = L* - {ε}.
Exemplo:
∞
i = 0
∞
i = 1
UEMS - Professora Viviane Duarte Bonfim
17
1. Seja L1 = {10, 1} e L2 = {0011, 11}. Então L1L2 = {100011, 1011, 10011, 111}
2. {10, 11}* = {ε, 10, 11, 1010, 1011, 1110, 1111,...}
2.1.1. Definição de Expressões Regulares
Seja A um alfabeto. As expressões regulares sobre o alfabeto A e os conjuntos (linguagens)
que elas denotam são definidas indutivamente como segue:
� ∅ é uma expressão que denota o conjunto vazio;
� ε é uma expressão regular que denota o conjunto {ε};
� Para cada símbolo em a em A, a é uma expressão regular que denota o conjunto {a};
� Se r e s são expressões regulares que denotam os conjuntos R e S, respectivamente,
então (r+s), (rs), e (r*) são expressões regulares que denotam os conjuntos R∪S, RS e R*,
respectivamente.
Quando se escreve E.R.s, pode-se omitir muitos parênteses se for assumido que o símbolo *
tem precedência maior que a concatenação e +, e que a concatenação tem precedência maior
que +. Por exemplo: ((0(1*))+0) pode ser escrita como )!* + ). Além disso, pode-se aplicar
simplificações abreviando expressões como rr* para r+.
As E.R.s possuem as seguintes propriedades algébricas:
AXIOMA DESCRIÇÃO
r + s = s + r + é comutativo
r + (s + t) = (r + s) + t + é associativo
(rs)t = r(st) a concatenação é associativa
r(s + t) = rs + RT
(s + t)r = sr + tr
a concatenação é distributiva sobre +
εr = r
rε = r
ε é o elemento neutro (identidade) da
concatenação
r* = (r + ε) relação entre ε e *
Exemplo;
Exercícios;
Tabela 1: Propriedades Algébricas.
UEMS - Professora Viviane Duarte Bonfim
18
2.2. Autômatos Finitos Autômato Finito é um reconhecedor de Linguagens Regulares. Estende-se por reconhecedor
de uma Linguagem L um dispositivo que tomado uma seqüência w como entrada, responde “sim” se w
∈ L e “não” caso contrário.
Os autômatos Finitos classificam-se em:
• Autômatos Finitos Determinísticos (A.F.D)
• Autômatos Finitos Não-Determinísticos (A.F.N.D)
2.2.1. Autômatos Finitos Determinísticos
Formalmente defini-se um A.F.D como sendo um sistema formal M = (Κ, Σ, δ, q0, F), onde:
Κ → É o conjunto finito não-vazio de ESTADOS;
Σ → É um ALFABETO, finto, de entrada;
δ → FUNÇÃO DE MAPEAMENTO ( ou função de transição), definida em Κ x Σ → Κ;
q0 → ∈ Κ, é o ESTADO INICIAL;
F → ⊆ Κ, é o conjunto de ESTADOS FINAIS;
2.2.1.1. Interpretação de δ
A interpretação de δ (q, a) = p, onde {q, p} ∈ K e a ∈ Σ, é de que se o “controle de M” está no
estado “q” e o próximo símbolo de entrada é ä”. Então "a" deve ser reconhecido e o “controle” passa
para o próximo estado (no caso “p”). Nota-se que a função de mapeamento é definida por Κ x Σ → Κ,
ou seja, de um estado, através do reconhecimento de um símbolo, o controle passa para UM ÚNICO
outro estado. Por esse motivo, este autômato é chamado de DETERMINÍSTICO.
Logicamente um estado é uma situação particular no processo de reconhecimento de uma
sentença.
Uma sentença x é aceita (reconhecida) por um A.F.M. = (Κ, Σ, δ, q0, F) se, e somente se, δ (q0, x) = p
∧ p ∈ F.
Uma Linguagem Aceita por Mapeamento é um conjunto de todas as sentenças aceitas por M.
Formalmente, defini-se por:
L(M) = {x | δ (q0, x) = p ∧ p ∈ F}
UEMS - Professora Viviane Duarte Bonfim
19
2.2.1.2. Diagrama de Transição
Um Diagrama de Transição para um A.F.M. é um grafo direcionado e rotulado. Os vértices
representam os estados e fisicamente são representados por círculos, sendo que o estado inicial é
diferenciado por uma seta com rótulo “inicio” e os estados finais são representados por círculos duplos.
As arestas representam as transições, sendo que entre dois estados “p” e “q” existirá uma aresta
direcionada de “p” para “q” com rótulo “a”( a ∈ Σ) ↔ ∃ δ (p, a) = q em M.
2.2.1.3. Tabela de Transição
É uma representação tabular de um A.F.
Nesta tabela as linhas representam os estados (o inicial por uma seta e os finais por
asteriscos). As colunas representam os símbolos de entrada e o conteúdo da posição (q, a) será igual a
“p” se existir δ(q, a) = p, senão será indefinida.
Exemplos:
Abaixo são apresentados dois exemplos de A.F.D nas formas gráficas e tabulares:
Exemplo1: A.F.D que reconheça as sentenças da linguagem L = { (a, b)+, onde o número de a’s é
impar}.
Forma Gráfica:
Início a
b
Forma Tabular:
δ a b
q0 q1 q0
q1 q0 q1
Exemplo2: A.F.D. que reconheça as sentenças da Linguagem l = { (0,1)*, onde todos os 1,s apareçam
consecutivos}.
Forma Gráfica:
Início 1 0
q0 q1
b b
**
q0 q1 q2
0 0 1
UEMS - Professora Viviane Duarte Bonfim
20
Forma Tabular:
δ 0 1
q0 q0 q1
q1 q2 q1
q2 q2 ___
2.2.2. Autômatos Finitos Não-Determínisticos
Um A.F.N.D. é um sistema formal M = (Κ, Σ, δ, q0, F), onde:
Κ, Σ, q0, F → possuem a mesma definição de A.F.D.
δ → é uma função de mapeamento, definida em K x Σ = ρ(K) (um conjunto de estados), sendo que
ρρ(K) é um subconjunto de K. Isto equivale dizer que δ(p, a) = p1, p2,..., pn. A interpretação de δ é que
M no estado “q”, com símbolo “a” na entrada pode ir tanto para o estado p1, como para o estado p2,...,
como para o estado pn.
Exemplo: Seja a Linguagem L = { (a, b)* abb} O A.F.N.D. seria:
Forma Gráfica:
a b b
a, b
Forma Tabular:
δ 0 1
q0 q0, q1 q0
q1 ___ q2
q2 ___ q3
q3 ___ ___
*
***
**
q0 q1 q2 q3
*
UEMS - Professora Viviane Duarte Bonfim
21
2.2.2.1. Comparação entre A.F.D. e A.F.N.D
A tabela abaixo mostra as principais diferenças entre A.F.D e A.F.N.D. :
Vantagens Desvantagens
A.F.D. Implementação Trivial Não apresenta adequadamente
algumas L. R.
A.F.N.D. Representa mais
adequadamente as L. R.
Implementação Complexa
2.2.3. Transformação de A.F.N.D. para A.F.D.
Teorema 4.1: “Seja L um conjunto aceito por um A.F.N.D. , então ∃ um A.F.D. que aceita L”.
Prova: Seja M = (Κ, Σ, δ, q0, F) um A.F.N.D. Construa um A.F.N.M.’ = (K’, Σ’, δ’, q0’, F’) como segue:
� K’ = {ρ(K)} → isto é, cada estado M’ é formado por um conjunto de estados de M.
� q0’ = [q0] → obs: representa-se um estado q ∈ K’ por [q].
� F’ = {ρ(K) | ρ(K) ∩ F ≠ ∅.
� Σ’ = Σ.
� Para cada ρ(K) ⊂ K’, δ’ (ρ(K), a) = ρ’(K) = {p | para algum q ∈ ρ(K), δ(q, a) = p}, ou seja:
SE ρ(K) = [q1, q2,..., qr ∈ K’ e
Se δ( q1, a) = p1, p2, ..., pj
δ( q2, a) = pj+1, pj+2, ..., pK
...
δ( qr, a) = pi, pi+1, ..., pn são as transições de M,
então ρ’(K) = [p1, p2, ..., pj,..., pj, pj+1, , ..., pK, pi, pi+1, pn] será um estado de M’ e M’ conterá a
transição: δ’(ρ(K), a) = ρ’(K).
Para concluir a prova do teorema acima, basta provar que a Linguagem M’ é igual a
Linguagem M(L(M) = L(M’)). Esta prova não será apresentada nesta seção.
Exemplo: Tendo por exemplo o A.F.N.D. já apresentado anteriormente:
δ 0 1
q0 q0, q1 q0
UEMS - Professora Viviane Duarte Bonfim
22
q1 ___ q2
q2 ___ q3
q3 ___ ___
Define M’ = (K’, Σ’, δ’, q0’, F’), onde
δ 0 1
[q0] [q0, q1] [q0]
[q0, q1] [q0, q1] [q0, q2]
[q0, q2] [q0, q1] [q0, q3]
[q0, q3] [q0, q1] [q0]
K’ = {[q0], [q0, q1], [q0, q2], [q0, q3]}
Σ’ = {a, b} q0 = [q0] F’ = [q0, q3]
2.2.4. Relação entre G.R. e A.F.
Teorema 4.2: “Seja G = (N, T, P, S) uma Gramática Regular, então ∃ um A.F.M. = ((K, Σ, δ, q0,
F) | L(M) = L(G)”.
Prova: a) Mostrar que M existe;
b) Mostrar que L(M) = L(G).
a) Define-se M como segue:
1. K = N ∪ {A}, onde A é um novo símbolo não-terminal;
2. Σ = T;
3. q0 = S;
4. F = {B | B → ε P} ∪ {A}, ou seja, todos os estados que produzem ε, juntamente com o novo
estado.
5. Construa δ de acordo com as regras a, b, c:
a) Para cada produção da forma B → a ∈ P, cria-se a transição δ(B, a) = A;
b) Para cada produção da forma B → aC ∈ P, cria-se a transição δ(B, a) = C;
c) Para produções B → ε, não é criada nenhuma transição;
d) Para todo a∈ T, δ(A, a) = -(indefinida)
*
UEMS - Professora Viviane Duarte Bonfim
23
b) Para mostrar que L(M) = L(G), deve-se mostrar que (1) L(G) ⊆ L(M) e (2) L(M) ⊆ L(G). esta
demonstração é fácil, considerando-se as produções as produções da G.R. e a definição das
transições de M, sendo omitida neste texto.
Exemplo:
Dada a gramática regular abaixo, que gera as sentenças da linguagem {(anbm), com n par e m
> 0}, iremos definir um A.F. que reconheça as sentenças desta linguagem.
Gramática: S ::= aA | bB
A ::= aS
B ::= bB | ε
Autômato:
Primeiramente deve-se definir os estados do autômato, com um estado novo, denominado aqui
C. assim, tem-se que K = {S, A, B, C}. O alfabeto é o mesmo, assim Σ = {a, b}, o estado inicial é S, e F
= {B, C}, pela definição acima. Na forma tabular o autômato fica o seguinte:
δ a b
S A B
A S ___
B ___ B
C ___ ___
Nota-se que pode ser gerado um estado inalcançável (o novo estado, quando não houverem
produções da forma B → a, B ∈ N e a ∈ T). Na forma gráfica o autômato fica:
Início
*
*
S
A
B
C
a
b
b
b
UEMS - Professora Viviane Duarte Bonfim
24
Teorema 4.3: “Seja um A.F.M. = (K, Σ, δ, q0, F). Então ∃ uma G.R. G = (N, T, P, S) | L(G) =
L(M)”.
Prova: a) Mostrar que G existe;
b) Mostrar que L(G) = L(M).
a) Seja M = (K, Σ, δ, q0, F) um A.F. Construir uma G.R. G = (N, T, P, S), como segue:
1. N = K;
2. T = Σ;
3. S = q0;
4. Define-se P como segue:
� Se δ(B, a) = C, então adiciona-se B ::= aC em P;
� Se δ(B, a) = C e C ∈ F, então adiciona-se B ::= a em P;
� Se q0 ∈ F, então ε ∈ L(M). Assim a gramática deve ser transformada, encontrando uma outra
G.R., G1, tal que L(G1) = L(G) ∪ {ε}, e L(G1) = L(M). Senão ε ∉ L(M).
b) Para mostrar que L(G) = L(M), deve-se mostrar que (1) L(M) ⊆ L(G) e (2) L(G) ⊆ L(M). Esta prova
também não será expressa aqui neste texto.
Exemplo: Tem-se o seguinte A.F.:
Início
Na forma tabular:
δ a b
S A B
A S C
B C S
C B A
S
A
B
C
a
a
b
b
a
a
b b
*
UEMS - Professora Viviane Duarte Bonfim
25
A G.R. definida pelo exemplo (algoritmo) acima resulta em:
S ::= aA | bB | a
A ::= aS | bC
B :: aC | bS
C ::= aB | bA | b
2.2.5. Minimização de Autômatos Finitos:
Definição: Um A.F.N.D. = (Κ, Σ, δ, q0, F) é MÍNIMO se:
1. Não possuir estados INACESSÍVEIS;
2. Não possui estados MORTOS;
3. Não possui estados EQUIVALENTES;
� Estados Inacessíveis:
Um estado q ∈ K é inacessível quando não existe w tal que a partir de q0, seja alcançado, ou seja,
~∃ w | δ(q0, w) = q, onde w é uma sentença ou parte dela.
� Estados Mortos:
Um estado q ∈ K é morto se ele ∉ F e ~∃ w | δ(q, w) = p, onde p ∈ F e w é uma sentença ou parte
dela. Ou seja, q é morto se ele não é final. E, a partir dele nenhum estado final é alcançado.
� Estados Equivalentes:
Um conjunto de estados q1, q2,..., qj são equivalentes entre sí, se eles pertencem a uma mesma
CLASSE DE EQUIVALÊNCIA.
� Classe de Equivalência:
Um conjunto de estados q1, q2,..., qj estão em uma mesma C.E. se δ(q1, a), δ(q2, a),..., δ(qj, a),
para cada a ∈ Σ, resultam respectivamente nos estados qi, qi+1 ,..., qn e estes pertencem a uma
mesma C.E.
2.2.5.1. Método para Construção do Autômato Finito Mínimo
1. Eliminar os estados inacessíveis;
2. Eliminar os estados mortos;
3. Construir todas as classes de equivalência;
4. Construir M’ como segue:
UEMS - Professora Viviane Duarte Bonfim
26
a) K’ → é o conjunto de C.E. obtidas;
b) q0’ → será a C.E. que contiver q0;
c) F’ → será o conjunto das C.E. que contenham pelo menos um elemento ∈ F, isto é, {[q] |
∃ p ∈ [q] e p ∈ F, onde [q] é um C.E.};
d) δ’ → δ’([p], a) = [q] ↔ δ(p, a) = q é uma transição de M e p e q são elementos de [p] e [q],
respectivamente.
Exemplo: Minimizar o A.F.D. definido na seguinte tabela de transição:
δ’ a b
A G B
B F E
C C G
D A H
E E A
F B C
G G F
H H D
Tem-se que os estados acessíveis são: {A, G, B, F, E, C}. Portanto, pode-se eliminar os
estados D e H. Assim, o novo A.F.D. é:
δ’ a b
A G B
B F E
C C G
E E A
F B C
G G F
Nenhum dos estados do A.F.D. é morto. Assim, pode-se construir as classes de equivalência.
No primeiro passo, duas classes de equivalência são construídas: F e K-F. Cada passo do algoritmo é
representado numa linha da tabela abaixo:
*
*
*
*
UEMS - Professora Viviane Duarte Bonfim
27
F K-F
{A, G} {B, C, E, F}
{A, G} {B, F} {C, E}
{A, G} {B, F} {C, E}
Denominando {A, G} = q0, {B, F} = q1 e {C, E} = q2 , tem-se o seguinte A.F.D. Mínimo:
δ’ a b
q0 q0 q1
q1 q1 q2
q2 q2 q0
2.2.6. Aplicações de A.F. e E.R.
Apesar da simplicidade destas ferramentas, existe uma grande variedade de software cuja
especificação e/ou implementação pode ser bastante simplificada se realizada em termos de A.F. e
E.R., resultando em software´s mais eficientes. Dentre as diversas aplicações que fazem uso de A.F. e
E.R. podemos citar:
a) Analisador Léxico: Os tokens (símbolos básicos) de uma linguagem de programação
geralmente podem ser especificados eficientemente através de E.R., as quais podem ser
automaticamente convertidas para A.F.D. equivalentes, cuja implementação (o analisador léxico
propriamente dito) é trivial.
Isto permite inclusive, a geração automática de um analisador léxico a partir da especificação
formal dos “tokens” de uma linguagem de programação.
b) Editores de Texto: As operações de busca e substituição de cadeias de caracteres em um
texto, podem ser eficientemente realizadas, se a cadeia for expressa em termos de E.R. e a operação
realizada em termos de um A.F. usufruindo da possibilidade da conversão automática de E.R. para
A.F., de forma transparente ao usuário.
c) Além das aplicações acima (tidas como as principais) podemos também destacar o uso
destas ferramentas nas seguintes áreas:
*
UEMS - Professora Viviane Duarte Bonfim
28
c.1) Protocolos de comunicação
c.2) Projeto (modelagem) de sistemas operacionais
c.3) Path Expression
c.4) Problemas específico tais como: segurança de arquivos, desorientação em sistemas
de hipertexto, modelagem de redes neurais, compressão de dados, etc...
UEMS - Professora Viviane Duarte Bonfim
29
3. Gramáticas Livres de Contexto
Uma gramática livre de Contexto (GLC) é denotada por G = (N, T, P, S), onde N e T são
conjuntos disjuntos de varáveis e terminais, respectivamente. P é um conjunto finito de produções,
cada uma da forma A::= α onde A é uma variável do conjunto N e α é uma cadeia de símbolos (N ∪
T)*. S é uma variável especial pelo fato de ser o Símbolo Inicial.
3.1. Simplificações de Gramáticas Livres de Contexto
Existem várias maneiras de restringir as produções de uma gramática livre de contexto sem
reduzir seu poder expressivo. Se L é uma linguagem livre de contexto não-vazia, então L pode ser por
uma gramática livre de contexto G com as seguintes propriedades:
a) Cada variável e cada terminal de G aparecem na derivação de alguma palavra de L.
b) Não há produções da forma A::= B, onde A e B são variáveis.
Além disso, se ε ∉ L, então há necessidade de produções da forma A::= ε.
3.1.1. Símbolos Inúteis
Pode-se eliminar os símbolos inúteis de uma gramática sem prejudicar seu potencial
expressivo. Um símbolo X é útil se existe uma derivação S→* αXβ →* w, para algum w, α e β,
onde w é uma cadeia de T* e α e β são cadeias quaisquer de variáveis e terminais. Caso contrário, o
símbolo X é inútil. Tanto terminais quanto não-terminais podem ser úteis ou inúteis. Se o símbolo inicial
for inútil, então a linguagem definida pela gramática é vazia.
Há dois tipos de símbolos inúteis. Aqueles que não geram nenhuma cadeia de terminais e
aqueles que jamais são gerados a partir de S. O primeiro caso corresponde aos símbolos improdutivos
(ou mortos), e o segundo caso corresponde aos símbolos inalcançáveis. Um terminal sempre é
produtivo, mas pode ser inalcançável. Já o não-terminal pode ser tanto improdutivo como inalcançável.
O algoritmo para eliminação dos símbolos improdutivos é baseado na idéia de que se um não-
terminal A tem uma produção consistindo apenas de símbolos produtivos, então o próprio A é
produtivo.
Exemplo;
Exercícios;
UEMS - Professora Viviane Duarte Bonfim
30
3.1.2. Eliminação de εεεε-produções
Conforme dito, uma GLC pode ter produções do tipo A::= ε. Mas toda GLC pode ser
transformada em uma GLC equivalente sem este tipo de produções (chamadas ε-produções), com
exceção da produção S::= ε, se esta existir (ou seja, a cadeia vazia pertence à linguagem). Assim,
procedendo, é possível mostrar que toda GLC pode obedecer à restrição das GSC (tipo 1). É o método
da eliminação de ε-produções, a qual se tratará.
O método consiste em determinar, para cada variável A em N, se A →* ε. Se isso for verdade,
se diz que a variável A é anulável. Pode-se assim substituir cada produção da forma B::= X1X2...Xn por
todas as produções formadas pela retirada de uma ou mais variáveis Xi anuláveis.
Exemplo;
Exercícios;
Os não-terminais que derivam a sentença ε são chamados de ε-não-terminais. Um não
terminal A é um ε-não-terminal se existir uma derivação A→* ε em G. Note que ε está em L(G) se e
somente se S é um ε-não-terminal. Se G não tem ε-não-terminais, ela é dita ε-livre.
Exemplo;
3.1.3. Produções Unitárias
Uma produção da forma A::= α em uma GLC = (N, T, P, S) é chamada de produção unitária se
α é um não terminal. Um caso especial de produção unitária é a produção A := A, também chamada
produção circular. Tal produção pode ser removida imediatamente sem afetar a capacidade da geração
da gramática. O algoritmo para eliminar produções unitárias assume que as produções circulares já
tenham sido eliminadas anteriormente.
Podem surgir símbolos inalcançáveis depois da aplicação do algoritmo. Isso se deve ao fato de
que o símbolo é substituído por suas produções, e se o mesmo aparecer somente em produções
unitárias, o mesmo irá desaparecer ao lado direito das produções. Para exemplificar, o algoritmo é
aplicado na seguinte gramática:
S ::= aB | aA | A B ::= aA | B | A
A ::= C | aaa C ::= ε | cBc
Primeiramente é necessário determinar o conjunto de Nk para cada não terminal K:
Ns = {S, A, B, C} Nb = {B, A, C} Na = {A, C} Nc = {C}
UEMS - Professora Viviane Duarte Bonfim
31
As produções de cada símbolo K são as produções R ::= α, onde R é um elemento de Nk e α é
uma produção não unitária. No exemplo, as produções de S são as produções unitárias de S, A, B e C.
Exemplo;
Exercícios;
3.1.4. Eliminação de Recursão à Esquerda
Um não-terminal A, em uma GLC G=(N, T, P, S) é recursivo se A → αAβ, para α e β ∈ (N ∪
T)*.
Se α = ε, então A =e recursivo à esquerda; se β = ε, então A é recursivo à direita. Esta
recursividade pode ser indireta ou direta.
Uma gramática com pelo menos um não-terminal recursivo à esquerda ou à direita é uma
gramática recursiva à esquerda ou a direita, respectivamente.
Uma GLC G=(N, T, P, S) possui recursão à esquerda direta se P contém pelo menos uma
produção da forma A :: = Aα.
Uma GLC G=(N, T, P, S) possui recursão à esquerda indireta se existe em G uma derivação da
forma A →n Aβ, para algum n≥2.
Para eliminar recursão diretas à esquerda nas produções:
A ::= Aα1 | Aα2 | ... | Aαn | ... | β1 | β2 | ... | βm
Onde nenhum βi começa com A, deve-se substituir estas produções pelas seguintes:
A ::= β1A’ | β2A’ | ... | βmA’
A’ ::= α1A’ | α2A’| ... | αnA’ | ε
Onde A’ é um novo não-terminal.
Exemplo;
Exercícios;
3.1.5. Fatoração à Esquerda
A fatoração à esquerda é uma transformação útil para a criação de uma gramática adequada à
analise sintática preditiva. A idéia básica está em, quando não estiver claro qual das duas produções
alternativas usar para expandir um não-termimal A, estamos capacitados a reescrever as produções- A
e adiar a decisão até que tenhamos visto o suficiente da entrada para realizarmos a escolha certa.
Por exemplo, se tivermos as duas produções ao enxergarmos o token de entrada if, podemos
imediatamente dizer qual produção escolher a fim de expandir cmd. Em geral, se A → αβ1, αβ2 São
duas produções -A, e a entrada começa por uma cadeia não vazia derivada a partir de α, não sabe-se
UEMS - Professora Viviane Duarte Bonfim
32
se vamos expandir A em αβ, ou αβ2. Entretanto, pode-se postergar a decisão expandido A para αA’.
Então, após enxergarmos a entrada derivada a partir de α, expandiremos A’ em β1 ou em β2. Isto é, as
produções originais, fatoradas à esquerda, tornam-se:
A → αA’
A’ → β1, β2
Entrada: Gramática G
Saída: Uma gramática equivalente fatorada à esquerda
Método: Para cada não-terminal A, encontrar o mais longo prefixo α comum a mais de duas ou mais
alternativas. Se α ≠ ∈, isto é, existe um prefixo comum não-trivial, substituir todas as produções de A,
A’ → αβ1 | αβ2 | ... | αβn | γ, onde γ representa todas as alternativas que não começam com α, por
A → αA’ | γ
A’ → β1 | β2 | ... | βn
Aqui, A’ é um novo não-terminal. Aplicar repetidamente esta transformação até que não haja
duas alternativas com um mesmo prefixo comum.
Exemplo;
Exercícios;
3.2. Conjuntos First e Follow
3.2.1. Conjunto First
Seja α uma forma sentencial qualquer gerada por G. FIRST(α) será o conjunto de símbolos
terminais que podem iniciar (que podem aparecer na posição mais à esquerda das sentenças
derivadas desta forma sentencial) α ou seqüências derivadas (direta ou indiretamente) de α. Além
disso, se α = ε ou α → ε então ε ∈ FIRST (α).
Para calcular FIRST(X) para todo X ∈ (N ∪ T)*, considera-se os seguintes aspectos especiais:
a) X = ε. Neste caso, FIRST(X) = {ε};
b) X ∈ T. Neste caso, FIRST(X) = {X};
c) X ∈ N. Neste caso, se X ::= α1 | α2 | ... | αn| são todas as produções com lado esquerdo X,
então FIRST(X) = FIRST(α1) ∪ FIRST(α2) ∪ ... ∪ FIRST(αn).
UEMS - Professora Viviane Duarte Bonfim
33
Para determinar o conjunto FIRST de cada um dos não-terminais de uma gramática, procede-
se como:
1. Cria-se uma tabela TABFIRST cujas linhas são rotuladas com os não-terminais da
gramática e com uma coluna rotulada como “FIRST”, que irá conter os símbolos
pertencentes ao FIRST de cada não-terminal. Inicializa-se cada uma das posições desta
tabela com ∅ (conjunto vazio);
2. Para cada um dos não-terminais, calcula-se o seu conjunto FIRST;
3. Repete-se o passo 2 até que não ocorra mais nenhuma modificação na tabela;
Exemplo;
Exercícios;
3.2.2. Conjunto Follow
FOLLOW(A) é definido para todo A ∈ N como sendo o conjunto de símbolos terminais que
podem aparecer imediatamente após A em alguma forma sentencial de G. É definido um algoritmo que
constrói o FOLLOW de todo os não-terminais simultaneamente.
Duas observações importantes:
a) A função FIRST é definida para as cadeias de símbolos, FOLLOW só é definida para
não-terminais;
b) Os elementos de um conjunto FIRST pertencem ao conjunto T ∪∪∪∪ {εεεε}; os elementos
de um conjunto FOLLOW pertencem ao conjunto T ∪∪∪∪ {$}.
Exemplo;
Exercícios;
3.3. Autômatos com Pilha
Assim como as expressões regulares possuem seu Autômato equivalente – o Autômato Finito,
as gramáticas livres de contexto também possuem sua máquina equivalente – o Autômato com Pilha (‘
pushdown automata”). A equivalência é algo satisfatório desde que o autômato com pilha seja não
determinístico, pois sua versão determinística aceita somente os subconjuntos das linguagens livres de
contexto. Ou seja, nem toda linguagem livre de contexto pode ser reconhecida por um autômato com
pilha. Sendo assim, é necessário adicionar um aspecto que permita que ele reconheça qualquer
linguagem livre de contexto. Neste caso, uma pilha adicionada ao Autômato lhe confere a facilidade de
não-determinismo.
UEMS - Professora Viviane Duarte Bonfim
34
O Autômato com Pilha é análogo ao Autômato Finito, incluindo uma pilha como memória
auxiliar. A pilha é independente da fita de entrada e não possui limite máximo de tamanho (memória
infinita). O A.P. é essencialmente um A.F. com controle da fita de entrada e da pilha.
Sua principal característica é que o último símbolo gravado é o primeiro a ser lido (“first in – last
out”), como mostra a figura abaixo:
Gravação Leitura
Topo
A base uma pilha é fixa e define o seu início.
O Autômato de Pilha é composta por quatro partes:
a) Fita: Análoga à do Autômato Finito;
b) Pilha: Memória auxiliar que pode ser usada livremente para leitura e gravação. É dividida
em células, armazenando cada uma,, um símbolo do alfabeto auxiliar (pode ser igual ao
alfabeto de entrada). Em uma estrutura do tipo pilha, a leitura ou gravação é sempre na
mesma extremidade denominada topo. O topo é variável e define a posição do último
símbolo gravado. Não possui tamanho fixo e nem máximo, sendo seu tamanho atual, igual
ao tamanho da palavra armazenada. Seu valor inicial é zero.
c) Unidade de Controle: Reflete o estado corrente da máquina. A unidade de controle possui
um número finito e pré-definido de estados. Possui uma cabeça de fita e uma cabeça de
pilha:
� Cabeça de Fita: unidade de leitura a qual acessa uma célula da fita de cada vez e
movimenta-se exclusivamente para a direita. É possível testar se a entrada foi
completamente lida.
� Cabeça da Pilha: unidade de leitura e gravação a qual move para a esquerda (ou “para
cima”) ao gravar e para direita (“ou para baixo”), ao ler um símbolo. Acessa um símbolo
Base
Sentido do Crescimento
Figura 2: Estrutura do Tipo Pilha.
UEMS - Professora Viviane Duarte Bonfim
35
de cada vez, estando sempre posicionada no topo. A leitura exclui o símbolo lido. É
possível testar se a pilha está vazia. Em uma operação de gravação, é possível
armazenar uma palavra composta por mais de um símbolo. Neste caso, o símbolo do
topo é o mais à esquerda da palavra gravada.
d) Programa ou Função de Transição: Comanda a leitura da fita, leitura de gravação da pilha
e define o estado da máquina. É uma função parcial que dependendo do estado atual,
símbolo lido na fita e símbolo lido na pilha, determina o novo estado e a palavra a ser
gravada na pilha. Pode mudar de estado sem ler a fita (movimento vazio).
Um Autômato com Pilha Não-Determinístico (A.P.N) ou simplesmente Autômato com Pilha
(A.P) M é uma 6-upla:
M = (Σ, Q, δ, q0, F, V) onde:
Σ → alfabeto de entrada;
Q → conjunto de estados possíveis do autômato o qual é finito;
δ → função programa ou função de transição: δ : Q x (Σ ∪ {ε, ?}) x (V ∪ {ε, ?}) → 2QxV
q0 → estado inicial do autômato, tal que q0 é elemento de Q;
F → conjunto de estados finais tal que F ⊆ Q;
V → alfabeto auxiliar ou alfabeto da pilha.
Algumas considerações devem ser feitas em relação a função programa:
� O símbolo ε na. Ieitura indica que o A.P. não lê e nem move a cabeça da fita ou da pilha
(movimento vazio) e ε na gravação indica que nenhuma gravação é realizada na pilha (e
não move a cabeça);
� “?” significa que a função pode não ser total, ou seja, indefinida para alguns argumentos do
conjunto da partida. A omissão do parâmetro de leitura é denotada por “?”. Isto indica que
toda palavra de entrada foi lida na fita e na leitura faz o teste de pilha vazia.
3.3.1. Modelagem de MEF’s como SD’s
A modelagem de sistemas como autômatos não se limita ao estudo de reconhecimento de
linguagens formais. Muitos modelos têm sido propostos para resolução de vários problemas. Os
autômatos podem ser utilizados nas mais diversas aplicações, como por exemplo, modelos de redes
neurais artificiais e modelos de agentes, modelos de sistemas hipermídia. Aqui será restrito ao estudo
das linguagens formais.
Uma Máquina de Estados Finitos é um Sistema Dinâmico, onde o conjunto dos tempos é o
conjunto dos inteiros, e a entrada, a saída e os estados são conjuntos finitos. Neste caso, os valores
UEMS - Professora Viviane Duarte Bonfim
36
possíveis de entrada e da saída são requeridos como alfabetos de entrada e saída. Sob estas
simplificações, basta declarar explicitamente um estado inicial correspondente ao tempo zero.
Um autômato (ou uma máquina) é descrito como uma 6-upla:
At = {U, Y, X, x0, λ, η}, onde:
U → é um conjunto finito de entradas;
Y → é um conjunto finito de saídas;
X → é um conjunto de estados ou espaço de estados;
x0 ∈ X é o estado inicial;
λ : U x X → é a função de próximo estado ou função de transição;
η : U x X → Y é a função de próxima saída.
Então um autômato é um sistema dinâmico invariante e discreto no tempo. Quando o espaço
de estado é um conjunto finito, o autômato é chamado de autômato finito.
Assim, esta sêxtupla formal pode ser interpretada como sendo uma descrição matemática de
uma máquina à qual, se no tempo t0, estiver no estado x0 e receber um segmento de entrada u do
tempo t0 ao tempo t estará no tempo t no estado λ(x, u) e emitirá a saída η(x, u).
UEMS - Professora Viviane Duarte Bonfim
37
4. Teoria da Computação - Teoria de Problemas: Decidibilidade,
Computabilidade e Complexidade
4.1. Introdução
A Teoria da Computação pode ser vista como um guia (um roteiro) que nos orienta no sentido
de informar o que pode e o que não pode ser efetivamente computável, explicando porque, de que
forma e com que complexidade. Neste sentido, a Teoria da Computação classifica os problemas
computacionais em três classes:
a) Problemas Indecidíveis (ou impossíveis de serem solucionados);
b) Problemas Intratáveis (possíveis com recursos ilimitados, porém impossíveis com recursos
limitados);
c) Problemas Tratáveis (possíveis de serem solucionadas com recursos limitados).
Esta classificação engloba problemas de toda a natureza, envolvendo desde problemas clássicos
que fundamentam a teoria da computação até problemas (ou instâncias de problemas) práticos da
ciência da computação, tais como:
1 – Existe programa para solucionar um determinado problema?
2 – Qual o poder de expressão de um determinado modelo de especificação?
3 – Dado um programa qualquer, ele sempre tem parada garantida?
4 – Dois programas P1 e P2 são equivalentes entre si?
5 – Uma determinada solução é a melhor solução para um dado problema?
6 – Qual o significado de um determinado programa?
7 – Dado um programa qualquer, este programa está correto?
Esta lista poderia ser expandida e detalhada, contudo, seu objetivo é enfatizar a abrangência
da teoria da computação. Dos tópicos aqui listados, complexidade (5), semântica (6) e
correção/construção (7), costumam ser tratados como disciplinas específicas e independentes,
enquanto que os demais se classificam como problemas básicos da teoria da computação. Todos os
problemas computacionais podem ser tratados (estudados) sob a ótica da Teoria das Linguagens
Formais e Autômatos.
UEMS - Professora Viviane Duarte Bonfim
38
Segundo esta ótica, a teoria da computação pode ser vista como um conjunto de modelos
formais (juntamente com suas propriedades) que fundamentam a ciência da computação. Tais modelos
incluem Autômatos (Finitos, de Pilha e Máquinas de Turing) e Gramáticas, enquanto que as
propriedades de interesse envolvem questões de decidibilidade, Inter-relacionamento entre modelos
(abrangência, equivalência, etc...) e complexidade computacional.
Nesta apostila, abordaremos a Teoria da Computação segundo a ótica da Teoria das
Linguagens Formais e Autômatos.
4.1.1. Conceitos e Propósitos Fundamentais da Teoria da Computação
Com o objetivo de melhor fundamentar as questões cobertas pela teoria da computação e de
identificar claramente a possibilidade de reduzir tais questões a problemas pertinentes a Teoria das
Linguagens Formais, apresentaremos nesta seção alguns conceitos fundamentais e comentamos
alguns dos principais propósitos que sustentam a teoria da computação.
Procedures e Algorítmos
O conceito de algoritmo é fundamental dentro da ciência da computação e pode ser definido
formalmente segundo vários propósitos da teoria da computação (como será visto no final desta seção)
ou informalmente em função da definição de procedure (como veremos a seguir).
Procedure: É m conjunto finito de passos (instruções), os quais podem ser executados mecanicamente
em uma quantidade fixa de tempo e com uma quantidade fixa de esforço. Um bom exemplo de uma
procedure é um programa de computador escrito em linguagem de máquina, pois tal programa possui
um número finito de passos, todos executáveis mecanicamente com uma quantidade fixa de recursos.
Algoritmo: É uma procedure que sempre pára; ou seja, uma procedure cuja execução chegará ao
final, independentemente de quais sejam suas entradas. Adicionalmente, dizemos que uma procedure
termina para uma determinada entrada, se existe um número finito t, tal que após a execução de t
instruções (não necessariamente distintas), ou não existem mais instruções a serem executadas, ou a
última instrução executada foi uma instrução “halt”.
Exemplos:
UEMS - Professora Viviane Duarte Bonfim
39
1 – Dado um número inteiro positivo I, determinar se I é ou não um número primo.
2 – Dado um inteiro I, determinar se existe um número perfeito maior que I (obs: um número é perfeito
se a soma de seus divisores (exceto ele mesmo) é igual ao próprio número).
3 – Dado um programa escrito em uma determinada linguagem de programação, determinar se esse
programa está sintaticamente correto. Este problema é uma instância do seguinte problema genérico:
dada uma cadeia de caracteres x determinar se essa cadeia é gerada por uma Gramática Livre de
Contexto (ou reconhecida por um Autômato de Pilha).
4 – Dado um programa qualquer, determinar se existe alguma entrada para a qual o programa entrará
em loop.
Os problemas enunciados nos exemplos 1 e 3 possuem representação algorítmica enquanto
que os problemas dos exemplos 2 e 4 só são representáveis via procedures.
Conjuntos Recursivos e Conjuntos Recursivamente Enumeráveis
Um conjunto é dito Recursivamente Enumerável se ele pode ser representado (solucionado)
por uma procedure, e Recursivo se ele pode ser representado (solucionado) por um algoritmo. Como
procedures e algoritmos podem ser definidos formalmente através de vários modelos (gramáticas e
autômatos, por exemplo), podemos também definir conjuntos recursivos e recursivamente enumeráveis
em função de tais modelos.
Problemas Decidíveis e Indecidíveis X Algoritmos e Procedures
Um problema é decidível (tratável ou não) se e somente se ele é resolvível por um algoritmo,
para qualquer entrada pertencente ao seu domínio; caso contrário ele é um problema indecidível.
A partir das definições acima, podemos notar claramente a relação entre problemas decidíveis
e indecidíveis com conjuntos recursivos e recursivamente enumeráveis; ou seja, um problema é
decidível se o conjunto de soluções das diversas instâncias deste problema é um conjunto recursivo, e
indecidível caso tal conjunto seja recursivamente enumerável. Assim sendo, torna-se evidente que a
questão da decidibilidade pode ser tratada formalmente através dos modelos que compõem a Teoria
das Linguagens e Autômatos.
UEMS - Professora Viviane Duarte Bonfim
40
A classe dos problemas indecidíveis é significativamente representada pelo “HALTING
PROBLEM” (problema da parada) que consiste em: “Dado uma procedure Z e uma entrada X, decidir
(determinar) se Z termina quando aplicado a X. A indecidibilidade deste problema é extremamente útil
para demonstrar a indecidibilidade de outros problemas através da redução destes para o ”halting
problem“.
Propósitos da Teoria da Computação
Até aqui definimos procedures e algoritmos de maneira intuitiva e informal. Contudo eles
podem ser definidos rigorosamente (precisamente) através de vários formalismos conhecidos como
propósitos (ou princípios) da Teoria da Computação. Tais formalismos tem sido explorados largamente
na Ciência da Computação, onde servem como modelos na solução de diversos problemas práticos.
Dentre os formalismos mais importantes, podemos citar:
a) Máquinas de Turing (Turing, 1936);
b) Gramáticas (Chomsky, 1959);
c) Algoritmos de Markov (Markov, 1951);
d) Lambda Calculus (Church, 1941);
e) Sistemas Post e Sistemas de Produção (Emil Post, 1936);
f) Funções Recursivas (Kleene, 1936).
Um ponto importante a ressaltar aqui, é que toda procedure (ou algoritmo) descrita por algum
destes formalismos, pode também ser descrita através de qualquer um dos demais; fato este que
sugere a equivalência entre os formalismos.
A aceitação destes formalismos dentro da teoria da computação é, em grande parte,
decorrente da hipótese (conhecida como Tese de Church) de que todo processo computável – passível
de ser descrito por uma procedure – pode ser realizado por uma Máquina de Turing. Esta tese, apesar
de não ter sido provada formalmente, também não foi contradita e continua sendo universalmente
aceita. Conseqüentemente podemos afirmar que Máquinas de Turing constituem o formalismo mais
genérico para a representação de procedure e que qualquer outro formalismo será significativo se for
considerado equivalente às máquinas de Turing. A demonstração formal da equivalência entre os
diversos formalismos citados e máquinas de Turing, reforça a tese de Church.
UEMS - Professora Viviane Duarte Bonfim
41
4.2. Teoria de Problemas
Pode-se dizer que computadores servem para resolver problemas. A resolução de um
problema envolve o conhecimento do domínio do problema e a técnica de busca da solução. Caso o
conhecimento a cerca do problema for total não é necessário a utilização de técnica de busca da
solução, mas se não existir nenhum conhecimento a cerca do problema, ele é insolúvel. Então para a
solução de um problema devem ser considerado os seguintes aspectos:
� Conhecimento sobre o problema;
� Métodos de busca da solução;
Há uma autora que sugere antes de tentar buscar a solução de um problema tente responder
primeiro as seguintes questões:
� Quais são os dados?
� Quais são as soluções possíveis?
� O que caracteriza uma solução satisfatória?
4.2.1. Solucionabilidade de Problemas
O objetivo do estudo de problemas é investigar a existência ou não de algoritmos que
solucionem determinada classe de problemas.
Em particular, este estudo evita a pesquisa de algoritmos inexistentes. Em 1901, Hilbert
formulou uma lista de problemas a serem resolvidos pelas futuras gerações de matemáticos. Contudo,
o décimo problema desta lista (o desenvolvimento de um algoritmo que determine se uma equação
polinomial qualquer, com coeficientes inteiros, possui solução neste mesmo conjunto) foi aprovado, por
Matijasevic, em 1970, ser insolúvel.
4.2.2. Decidibilidade
Neste estudo, concentra-se nos problemas com respostas binárias sendo sim ou não, os quais
serão referidos simplesmente como problemas sim/não ou problemas de decisão.
Na prática, qualquer problema pode ser tratado equivalentemente como um problema (ou
classe de problema) sim/ não.
Os problemas solucionáveis são chamados computáveis. Alguns problemas não-solucionáveis
são parcialmente solucionáveis, ou seja, existe um algoritmo capaz de responder sim, embora,
eventualmente possa ficar em laço infinito para uma resposta que deveria ser não. Neste caso, diz-se
que o problema é parcialmente solucionável.
UEMS - Professora Viviane Duarte Bonfim
42
4.2.3. Princípio da Resolução de Problemas
Pode-se afirmar que existem mais problemas não computáveis do que problemas computáveis.
O estudo da solucionabilidade de um problema é feito, em geral, usando o princípio da Redução. Este
princípio consiste em reduzir o problema que se está investigando a solucionabilidade em outro
problema que já se conheça que seja insolúvel. Desta forma implicaria em resolver o insolúvel. Sendo
assim, o princípio é resumido como segue:
a) Sendo A e B dois problemas de decisão. Suponha-se que seja possível modificar (reduzir)
o problema A de forma que ele se comporte como um caso do problema B.
b) Se A é insolúvel, não computável, e como A é um caso de B, conclui-se que B também é
não solucionável.
c) Se B é solucionável ( parcialmente computável), como A é um caso de B, conclui-se que A,
agora também seja solucionável.
4.2.4. Classes de Solucionabilidade de Problemas
De acordo com a possibilidade de estabelecimentos de algoritmos de solução, os problemas
podem ser agrupados nas seguintes classes:
� Problema Solucionável ou Totalmente Solucionável:
Um problema é tido como solucionável se existe algum algoritmo que resolva o problema,
sempre pára para qualquer que seja entrada, devolvendo uma resposta afirmativa (Aceita) ou
negativa(Rejeita).
� Problema Parcialmente Solucionável:
Um problema é Parcialmente Solucionável se existe um algoritmo que resolva o problema,
parando quando a resposta for afirmativa. No caso da resposta for negativa, o algoritmo pode parar ou
permanecer indefinidamente (LOOP). Ou seja, para qualquer algoritmo que processe esse problema,
existe pelo menos uma palavra de entrada que resulta em loop.
� Problema Não-Solucionável ou Insolúvel:
Quando não existe um algoritmo que resolva o problema tal que pára para qualquer entrada,
com uma resposta afirmativa ou negativa. Alguns problemas Não-Solucionáveis podem ser
Parcialmente Solucionáveis.
UEMS - Professora Viviane Duarte Bonfim
43
A união dos conjuntos de problemas solucionáveis e não-solucionáveis é o universo de todos
os problemas. Entretanto, existem problemas parcialmente solucionáveis.
O conjunto dos problemas parcialmente solucionáveis contém todos os problemas
solucionáveis e alguns não-solucionáveis. Com isso, pode-se afirmar três coisas:
a) Todo problema solucionável é parcialmente solucionável;
b) Existem problemas não-solucionáveis que possuem solução parcial;
c) Existem problemas sem solução total ou parcial tido como insolúveis.
4.2.5. Definição Formal de Problema
Um problema é o objeto matemático P = {D, R, q}, consistindo de dois conjuntos não vazios,
dados (D) e possíveis resultados (R) e uma relação binária q ⊂ D x R como uma condição que
caracteriza uma solução satisfatória, associando a cada elemento do conjunto de dados a única
solução desejada.
A solução do problema é uma relação (subconjunto de um conjunto cartesiano) ou uma função
ƒ ( caso considerar os subconjuntos de dados), ver figura 2.1. Com isso, resolver um problema é
implementar funções através de mecanismos de implementações de funções.
Funções (ƒ) : ƒ1, ƒ2, ƒ3, ..., ƒn
Mecanismos de implementações (M): M1, M2, M3, ..., Mn
Dados Resultados
X X
ƒ
Figura 2: Demonstração de um problema como uma função.
UEMS - Professora Viviane Duarte Bonfim
44
Denomina-se, então a solução de um problema como função.
ƒ : D → R ⇒ ∀d ∈ D
Tem-se: (d, ƒ(d)) ⊂ q
Sendo assim, um problema pode ser representado matematicamente por uma função.
Solucionar o problema, é encontrar uma maneira de implementar esta função ou de aproximá-la ao
conhecimento que dispõe.
Abaixo, apresenta-se um exemplo do autor Barreto.
- O conjunto de dados disponíveis d ∈ D, no qual d são dados (observação da amnese,
sintomas, resultados laboratoriais) que pertencem, ao conjunto D de dados disponíveis.
- R é o conjunto de doenças possíveis.
- A condição que caracteriza uma solução satisfatória consiste em encontrar o par (d, r),
onde r ∈ R é o diagnóstico desejado. Caso o diagnóstico for único, pode-se dizer que a
relação q torna-se uma função e, pode-se dizer que a solução do problema será poder
associar a cada elemento de D o elemento correspondente de R, de modo que (d, ƒ(d)) ∈
q (onde ƒ(d) = r) e ƒ é uma função.
Formular um problema é diferente de encontrar a solução. A definição de um problema
possibilita testar se um determinado elemento é ou não a solução, mas não auxilia na busca deste
elemento. Verificar se um elemento é a solução, verifica-se se o par (dado, elemento e candidato à
solução) satisfaz ou não a condição. Testar se um par (dado, elemento e candidato à solução) satisfaz
a solução de um problema, nem sempre é permitido. Isto depende do modo de definir a função
associada ao problema em questão.
X X
Dados Resultados
ƒ
f1 f2 f3 fn
ƒ
Figura 3: Resolução do problema: implementações de funções.
UEMS - Professora Viviane Duarte Bonfim
45
4.2.6. Modos de Definir uma Função
� Por enumeração exaustiva:
Neste método, fornece-se todos os conjuntos de pares, dados, resultado. Só é aplicado no
caso do conjunto de dados ser finito.
Exemplo: Numa agenda de telefones pode ser considerada como uma função que associa a
cada nome de pessoa seu telefone. Calcular o valor da função é simples e sempre possível, neste
caso, se o nome da pessoa pertencer ao conjunto de dados representado na agenda. Saber se um par
(nome, número de telefone) está na agenda também é fácil e sempre possível: basta olhar na agenda.
� Declarativa:
Definir um problema desta maneira é atribuir propriedades que devem ser satisfeitas pela
solução do problema. Da mesma forma que um conjunto pode ser definido por uma propriedade (ex:
conjunto dos objetos de madeira de uma sala), uma função pode ser definida por uma propriedade.
Exemplo: Seja a propriedade de pertencer a um conjunto. Neste caso, trata-se da definição da
função característica de um conjunto.
Normalmente costuma-se considerar o conceito de um elemento pertencer a um conjunto como
conceito primitivo, explicado, mas não definido. Entretanto, este, conceito pode ser substituído pelo de
uma função característica de um conjunto. Pertencer passará a ser um conceito definido e a função
característica do conjunto A será:
FA : U → Verdadeiro, Falso,
significa que se a imagem do elemento for Verdade, ele pertence ao conjunto e Falso se não pertencer.
� Por um Programa:
Um programa de computador define a correspondência entre dados e resultados sempre ele
conseguir chegar a uma solução. Portanto, um programa pode ser considerado como um modo de
definir um problema.
Exemplo: Neste modo, o problema não é completamente definido para todo valor de seus
dados. Conhece-se apenas a definição do problema para um subconjunto dos dados possíveis e este
conhecimento pode ser de qualquer uma das formas citadas: por enumeração, declarativamente ou
proceduralmente. Deseja-se conhecer os elementos do conjunto de respostas admissíveis para todos
os elementos do conjunto de dados, mesmo aquele que não estão incluídos na definição da função.
Pode-se reconhecer neste caso que a solução não é única: todas as funções que sejam iguais
dentro da região em que o problema é definido são válidas. Também, deve-se considerar que, neste
UEMS - Professora Viviane Duarte Bonfim
46
caso, muitas vezes, é melhor Ter uma solução aproximada quando dados são usados para definir a
função.
As maneiras de definir uma função levam ao conceito de computabilidade.
4.3. Computabilidade
Uma função é computável se for possível calcular seu valor para todos os elementos do seu
domínio de definição. Caso contrário é considerada não computável.
Uma função também pode ser considerada parcialmente computável se for possível calcular
seu valor para alguns elementos, pelo menos, de seu domínio de definição.
4.3.1. Origem da Computabilidade
A idéia de Ter um algoritmo, ou passos para desenvolver uma determinada tarefa, existe por
muitos anos.
Durante anos, acreditava-se que: se um determinado problema fosse precisamente declarado,
com esforço suficiente, uma solução poderia eventualmente ser encontrada ( ou senão, poderia ser
provado que não havia solução). Ou seja, acredita-se que nenhum problema era intrinsecamente difícil,
em princípio, que jamais poderia ser resolvido.
Um dos grandes percursores desta idéia foi o matemático David Hilbert (1862 – 1943). Hilbert
acreditava que todos os problemas poderiam ser precisamente formulados, num sistema formal, em
termos de declarações que poderiam ser falas ou verdadeiras. Sua idéia era encontrar um algoritmo
que, dado um sistema formal, poderia determinar se a declaração a cerca do problema era ou não
verdadeira. Se o objetivo de Hilbert fosse atingido, então qualquer problema bem definido (declarado
com precisão) poderia ser resolvido simplesmente pela execução de um algoritmo. A decisão da
verdade sobre uma determinada declaração em um sistema formal ficou conhecida como
Entscheidungsproblem. Este problema pode ser considerado o problema aberto fundamental da
matemática.
Mas, infelizmente, na década de 30, muitas pesquisas constataram que o
Entscheidungsproblem é não computável, não existia nenhum algoritmo do tipo sugerido por Hilbert.
� Teorema de Gödel
Uma das primeiras descobertas nesta linha, deve-se a Kurt Gödel, que em 1931 sugeriu um
Teorema da Não-Completude. (“Incopleteness Theorem”). Entre outras coisas, ele mostrou que não
UEMS - Professora Viviane Duarte Bonfim
47
existe algoritmo cujas entradas declaradas sejam números inteiros e cuja saída mostre se esta
declaração é verdadeira ou não.
No Teorema da Não-Completude (ou Incompleteza) de Gödel, um sistema de axiomas é dito
completo quando todo teorema é verdade ou mentira. Se existir um sistema de axiomas consistentes
(quando não existirem axiomas que entrem em contradição com outros axiomas) existirão sempre
teoremas que poderá provar que são mentiras e teoremas que poderão provar que são verdades.
Outros também que não podem provar nada, nem que sejam verdades, nem que sejam mentiras.
Neste caso, o sistema é dado como incompleto, no sentido de que existem coisas que não pode-se
provar, nem verdades, nem mentiras.
Este teorema parte da premissa de que existem verdades e mentiras levando a conclusão que
existem teoremas verdadeiros, falsos e outros que não sabem se são verdades ou mentiras.
Alguns outros matemáticos como Alonso Church, Stephen Kleene, Emil Post, Alan Turing
encontraram vários problemas que não possuem solução algorítmica.
� A Tese de Church – Turing
Um dos maiores obstáculos em saber se existe ou não algoritmo para resolver um determinado
problema é saber exatamente o significado de algoritmo.
Gödel definiu algoritmo como uma seqüência de regras para transformar funções matemáticas
complexas em funções matemáticas simples.
Church utilizou um formalismo chamado cálculo lambda.
Turing imaginou uma máquina hipotética (Máquina de Turing) definindo um algoritmo como
sendo qualquer conjunto de instruções para esta máquina.
Um algoritmo também pode ser definido como operações básicas em estruturas de dados
controladas por seqüência, seleção e iteração.
Uma conjectura, enunciada por Church, diz que todos os modelos razoáveis do processo de
computação, definidos e por definir, são equivalentes. Essa conjectura é conhecida como a Tese de
Church. A Tese de Church não admite nenhuma prova formal, mas até hoje todos os modelos
propostos se manteram equivalentes. Com conclusões:
� Todas estas definições de “algoritmo” são equivalentes;
� Qualquer definição razoável de algoritmo será equivalente a estas definições;
A tese de Church-Turing ( ou Tese de Church), define que se tem uma boa definição de algoritmo
se uma seqüência de passos possa ser executada de maneira rotineira (ou mecânica), de maneira
formal no desenvolvimento da mesma tarefa.
UEMS - Professora Viviane Duarte Bonfim
48
� Procedimento e Algoritmo
Um procedimento é definido como “uma seqüência finita de instruções, e define-se uma
instrução como uma operação claramente descrita, que pode ser executada mecanicamente, em tempo
finito”.
� “mecanicamente” significa que deve haver dúvidas sobre o que deve ser feito;
� “em tempo finito” significa que não há dúvidas de que a tarefa correspondente à
instrução pode, em qualquer caso, ser conduzida até sua conclusão.
Para se escrever um procedimento pode-se usar uma linguagem natural, uma linguagem de
programação, ou uma linguagem usada em matemática.
Na verdade, usa-se uma combinação de todas elas. Sobre a forma de escrever instruções e
procedimentos, supõe-se apenas que existe uma linguagem, comum a todos, em que instruções e
procedimentos podem ser escritos sem ambigüidade.
Exemplos:
� o algoritmo Euclides para cálculo máximo divisor comum de dois números naturais;
� um programa em PASCAL que calcula a soma de dois números;
� a fórmula de Bháscara que calcula as raízes da equação de segundo grau.
Por exemplo, um conjunto A é recursivamente enumerável se existe um procedimento que
enumera os elementos de A Existe então um procedimento que emite todos os elementos de A,
possivelmente com repetições.
Define-se então algoritmo como sendo um procedimento que sempre pára, quaisquer que
sejam os valores de suas entradas. Por exemplo, conjunto A é dito recursivo se existe um algoritmo
que determina para um valor arbitrário de sua entrada x, se x ∈ A ou se x A. Embora isso não seja
estritamente necessário, pode-se, para fixar as idéias, especificar que o algoritmo deve parar e dizer
“sim” ou “não”, respondendo a pergunte, se “x ∈ A”?.
No sentido moderno, pode-se definir um algoritmo como sendo qualquer coisa que possa ser
executada no computador. O computador particular escolhido é irrelevante para a definição, desde que
qualquer algoritmo que possa ser implementado em um computador possa ser implementado em outro.
Isto é real, porque todos os computadores podem simular um ao outro. Este programa é conhecido
como interpretador (ou simulador, ou programa universal).
A equivalência entre todos os computadores modernos, e sua equivalência às Máquinas de
Turing e outras definição de “algoritmo evidenciam a Tese de Church. A universalidade é uma
propriedade dos algoritmos, significando que qualquer computador é equivalente a todos os outros no
sentido de que todos eles podem desenvolver a mesma tarefa. Embora os computadores possam
UEMS - Professora Viviane Duarte Bonfim
49
desenvolver as mesmas tarefas, eles não necessariamente consomem os mesmos recursos
computacionais.
4.3.2. Computabilidade de Funções
� Funções Computáveis:
Um problema de Decisão é o processo de determinação, se um determinado elemento é ou
não membro de um conjunto. È altamente desejável saber antecipadamente se um determinado
problema de decisão pode ser ou não resolvido pelo computador (ser computável). De modo teórico,
pode-se dizer que um problema é computável se a função característica do conjunto for recursiva. De
modo prático, uma função é dita computável se para qualquer entrada de dados pode ser
implementada no computador em tempo finito, ou seja, o programa irá parar para qualquer entrada de
dados. A maioria das linguagens de programação oferecem algumas funções intrínsecas e também
permitem aos programadores definir novas funções.
Exemplo:
Se desejar usar uma função que computa a média entre valores de três números reais pode-se
utilizar o seguinte código em PASCAL. O qual permite definir tal função:
function media(x, y, z: real):real;
{encontra a média dos valores de três números reais}
begin (função média}
media := (x + y + z) / 3.0;
end;
O cabeçalho function dentro dos parênteses indica que a função consiste de todas 3-tuplas de
números reais. Para cada uma delas é esperado que a função produza um resultado único.
� Funções Parcialmente Computáveis:
Na computação, algumas funções não são definidas para algumas entradas. Teoricamente é
impossível, dado um programa sem conhecer sua estrutura interna garantir que ele termine com certo
tipo de entrada. Pode acontecer de escolher um conjunto de dados de entrada e se o programa tiver
laços pode entrar num loop infinito e nunca parar. Com isso, os programas podem gerar funções
parcialmente computáveis.
Exemplo:
UEMS - Professora Viviane Duarte Bonfim
50
function ƒ (x:integer): integer;
var
y:integer;
begin
y := 1;
while (x<>0) do
begin
x := x – 2;
y := y * 2;
end;
ƒ := y;
end;
Percebe-se que a chamada ƒ (2K), com K ≥ 0 retorna o número 2K. Para qualquer outra
entrada, o programa não pára. Portanto, este fragmento de programa computa a função F = {(2K, 2K ) |
K ∈ N}, a qual é uma função parcial de Z em Z.
� Funções Não Computáveis:
As funções não computáveis são aquelas que não podem ser implementadas no computador.
Pode-se considerar como funções não computáveis àquelas cujo tempo de execução do programa não
é hábil, quer dizer, o computador pode levar muito tempo para implementar tais funções.
Exemplo:
Dada uma equação arbitrária da forma (a + 1)2 + (b + 1)3 = (c + 1)4, o problema é determinar se
a equação é satisfeita por quaisquer números inteiros. Isto é chamado Problema da Equação
Diofantinas e sabe-se que não existe algoritmo de solução de equações Diofantinas Arbitrárias.
4.3.3. Problema da Parada
Vários problemas são conhecidos como não computáveis, ou seja, não são conhecidos
algoritmos para a resolução de tais problemas. Estes algoritmos não conhecidos porque simplesmente
não existem!
Um problema comum nos sistemas computacionais é a ocorrência de erros que impedem a
determinação normal do programa. Várias vezes, os problemas sem detectar a existência de laços
infinitos em seus programas antes de dispensar recursos computacionais na execução dos mesmos.
UEMS - Professora Viviane Duarte Bonfim
51
Portanto, o problema a ser resolvido é determinar se um programa arbitrário (qualquer) pára ou não
pára. Este é denominado “Problema de Parada”. Sua solução é um algoritmo, no qual, dado um
programa qualquer P e sua entrada de dados D, pode-se dizer ou não, se eventualmente P pára
quando executado com a entrada de dados D.
Muitas vezes a “solução” para o Problema da Parada, utilizado em muitos sistemas
computacionais, é forçar a parada do programa cada vez que sua execução ultrapasse o tempo
determinado (alocado) para isso. Mas esta solução não é adequada por duas razões:
� Os programas não terminantes pode alocar todo tempo dispensado na execução;
� Nem sempre o programa pode calcular o tempo necessário para a execução do programa,
e ele pode “terminar” de maneira precoce em um tempo inferior à sua parada com sucesso.
O Problema da Parada é não computável conforme a seguir:
Suponha que exista um algoritmo para resolver o Problema da Parada, testaparada. O
algoritmo testaparada possui duas entradas, P e D. Imprime a resposta “OK!” caso o programa P
termina quando é executada com uma entrada de dados D. E imprime “Não Pára!” caso contrário.
O testaparada testa a determinação do programa P para dados D conforme mostra a figura
abaixo:
P(D) pára?
Saída “OK!” Saída “Não Pára”
e pára e pára
Suponha-se que pode-se usá-la para construir um algoritmo mais limitado, o qual testa a
terminação de P quando os dados são o próprio P, o qual será chamado de novotestaparada.
Embora posa parecer estranho a entrada de dados com o próprio programa, sabe-se qualquer
seqüência de caracteres pode ser a entrada de um programa. Assim, existem programas de interesses
prático, cuja a entrada é uma seqüência de caracteres representando outro programa; exemplos são
compiladores e editores.
Figura 4: Ação Testaparada.
P D
UEMS - Professora Viviane Duarte Bonfim
52
Programa novotestaparada(P)
{ verifica se o programa P pára quando é executado com o dado sendo o próprio P }
testaparada(P,P)
A ação de novotestaparada é demonstrado na figura 2.4.
P
P(P) pára?
Saída “OK!” Saída “Não Pára”
e pára e pára
Supondo a existência do algoritmo testaparada estar-se-á supondo a existência também de
novotestaparada. Assim, pode-se construir o seguinte algoritmo, chamado parada, que possui apenas
uma entrada P.
Programa parada(P)
{para escrever esta rotina suponha-se que testaparada existe}
Se novotestaparada(P) sai “Não Pára!”
então pára
senão laço infinito
A demonstração do algoritmo parada está na figura 2.5.
Sim Não
Figura 5: Ação de novotestaparada.
UEMS - Professora Viviane Duarte Bonfim
53
P
P(P) Pára?
Pára
Laço Infinito
Finalmente, considerando o que ocorre durante a execução de parada(parada), ou seja,
durante a execução de parda com sua própria entrada de dados, um programa texto de P (P pode ser
qualquer seqüência de caracteres). A execução de parada(parada) é demonstrada na figura 2.6. Sendo
a mesma figura 2.5, mas a entrada P foi substituída pelo próprio parada.
parada
parada(parada) pára?
Sim Não
pára
laço infinito
A figura 2.6 mostra uma contradição, pois se a parada (parada) pára então ele entra em laço
infinito. Por outro lado, se parada(parada) entra em laço infinito então ele pára! Ou seja, a execução de
parada(parada) não pode parar nem entrar em laço infinito.
Esta contradição só pode ser resolvida admitindo-se que o algoritmo parada não existe. Porém,
a única suposição feita derivando parada, era que testaparada não existiria. Portanto, se parada não
Sim Não
Figura 6: Ação de parada(P).
Figura 2.6: Ação de parada(parada).
UEMS - Professora Viviane Duarte Bonfim
54
existe, então testaparada não existe. Concluindo com isso, que não existe algoritmo que solucione o
problema da parada (testaparada). Assim, o problema da Parada é não computável!
Resumindo:
1. Suponha-se que pode-se escrever o programa testaparada;
2. Usa-se este programa para construir outro programa (parada) através de um programa
intermediário (novotestaparada);
3. Mostra-se que parada tem algumas propriedades impossíveis (não pode parar e nem
entrar em laço infinito);
4. Conclui-se que a suposição no passo 1 está errada.
4.3.4. Exemplo Problemas Não Computáveis
É possível projetar um algoritmo o qual resolverá o problema da Parada em alguns casos. Mas
o algoritmo é limitado e pode falhar com outras entradas. Ë difícil determinar se um dado algoritmo
falha e quando (momento em que) ele falha.
Pode-se dizer que o Problema da Parada não pode ser resolvido por qualquer programa,
escrito em qualquer linguagem, para qualquer computador!
� Problema da Totalidade:
Sendo que o Problema da Parada é determinar se um programa arbitrário P pára ou não pára
quando executando com uma entrada de dados arbitrária D. A questão é saber se o programa arbitrário
P parará para todas as entradas. Este é denominado “Problema da Totalidade”. Assim, pode-se dizer
que P é total se P(D) pára para qualquer entrada de dados D.
É de se esperar que o Problema da Totalidade seja não computável. Ao contrário, dado
qualquer P e D, pode-se simplesmente construir um programa especial afim de que P e D ignorar sua
entrada e simular P(D). Este programa especial pode ser denominado paradapd.
Programa paradapd(E)
{é a entrada mas o programa não usará, ele apenas simula uma entrada de dados D}
simular o programa P com a entrada de dados D
Agora, perguntar se paradapd é total é o mesmo que perguntar se P(D) pára. Então, um
algoritmo para o Problema da Totalidade poderia também ser dado para o Problema da Parada:
UEMS - Professora Viviane Duarte Bonfim
55
Programa testaparada(P,D)
{para escrever este programa supõe-se que o algoritmo para o Problema da Totalidade
existe}
construir a entrada do programa paradapd
se paradapd é total
então imprimir “OK” e pára
senão imprimir “Não Pára” e pára
4.3.5. Computabilidade Parcial
Existem muitos problemas os quais não são computáveis. Todavia, alguns destes problemas
não computáveis são menos computáveis do que outro. Mas aqui terão mais atenção problemas que
requerem uma resposta “sim” ou “não”.
Considera-se novamente o Problema da Parada. Para um programa arbitrário P e sua entrada
de dados D, deseja-se saber se P(D) pára ou não. Se P(D) pára, não existe dificuldade porque pode-se
simplesmente executar este programa até que ele pare pois sabe-se que ele pára. A dificuldade
aparece no caso de P(D) não pára. Portanto, não existe um método geral (algoritmo) que possa
descobrir se P(D) não pára.
O Problema da Parada também é denominado “parcialmente computável” porque existe um
algoritmo que imprime sim”” se P(D) pára e outro que entram laço infinito se P(D) não pára. A diferença
entre a computabilidade e a computabilidade parcial é demonstrada na figura 2.7.
Entrada Entrada
Sim Não Sim Não
Algoritmo Algoritmo
Figura 7: Computabilidade Parcial.
UEMS - Professora Viviane Duarte Bonfim
56
Ao contrário do Problema da Parada, o Problema da Totalidade por exemplo, não são
parcialmente computáveis. Para este problema não existe algoritmo que imprima “Sim” se P pára para
todas entradas de dados e também permita entrar em laço infinito quando a resposta é “Não”.
4.3.6. Complexidade
O estudo da Computabilidade leva ao entendimento de quais problemas admitem solução
algorítmica ou não. Para aqueles problemas que existem algoritmos é válido saber quais os recursos
computacionais são necessários para a sua execução. Somente aqueles algoritmos que podem utilizar
uma quantia de recursos viáveis são de interesse prático. Isto é um campo da ciência da computação
denominado Teoria da Complexidade.
A figura 2.8 demonstra uma representação do universo de problemas. Aqueles que podem ser
computados algoritmicamente forma um pequeno subconjunto. Aqueles viavelmente computáveis, de
acordo com recursos que necessitam compreendem uma pequena porção deste subconjunto
infinitesimal.
4.3.7. Recursos Computacionais
Os maiores recursos computacionais de interesse são tempo, memória e hardware. O tempo é
o período necessário para o início e o término da execução de um algoritmo.
A memória é a quantia de armazenamento requerida pelo algoritmo. O hardware é a
quantidade de mecanismos físicos necessários para a execução de um algoritmo. Em uma máquina
Todos Problemas
Problemas Computáveis
Problemas viavelmente Computáveis
Figura 8: Universo de Problemas.
UEMS - Professora Viviane Duarte Bonfim
57
paralela, por exemplo, o hardware está intimamente ligado ao número de processadores necessários
pelo algoritmo.
Os algoritmos usualmente aceitam dados de entrada conforme seu processamento. Portanto, a
quantia de qualquer recurso usado pelo algoritmo pode variar de acordo com o tamanho dos dados.
Considera-se, por exemplo, um algoritmo que multiplica dois números. A figura 2.9 mostra um algoritmo
feito no “jardim de infância”. Se o algoritmo é apresentado com dois n-dígitos, necessita-se adicionar n
linhas, cada uma contendo n( ou n+1) dígitos. Cada linha pode ser computada com cerca de n passos,
ou n unidades de tempo, e existirá n linhas separadas. Adiciona as linhas é tomar n x n (ou n2)
unidades de tempo. Portanto, o tempo de execução deste algoritmo é proporcional a n2.
Existem outras formas de algoritmos de multiplicação, algumas bem mais rápidas que podem
ser feitas em computadores paralelos, mas problema é encontrar aqueles que têm a execução mais
rápida e demanda menos recursos computacionais.
A quantidade de recursos usados depende do tamanho dos dados de entrada. Assim, no caso
da multiplicação, quanto mais número a serem multiplicados mais tempo será necessário para
desenvolver esta multiplicação.
A teoria da Complexidade estuda vários recursos computacionais. A quantidade de recursos
usados por um algoritmo é expressa como uma função do tamanho dos dados de entrada.
Os algoritmos podem utilizar diferentes entrada de mesmo tamanho. É importante conhecer a
quantia de recursos usados pelo algoritmo para qualquer entrada de um dado tamanho. Por exemplo,
se o computador está controlando um reator nuclear ou lançando um foguete, é vital saber o tempo
mais longo necessário ao computador para responder a uma situação de emergência. Isto é
denominado complexidade no pior caso do algoritmo.
Alternativamente, conhecer a quantia média de recursos usados para todas as entradas de um
dado tamanho pode ser bastante útil. Isto é denominado complexidade média. Às vezes, é interessante
conhecer a chance do algoritmo permanecer perto de seu comportamento médio para um dado de
entrada. Neste caso, o desvio padrão do recurso utilizado, poderia ser calculado.
Várias vezes se conhecem os limites (inferior e superior) que se aproximam na solução de
determinado problema. A complexidade de algoritmos envolve a complexidade de problemas em
relação aos recursos necessários para resolver determinado problema. Isto é a complexidade de um
problema, é a complexidade do melhor algoritmo, o qual resolve este problema. A análise do algoritmo
fornece um limite superior (“upper bound”) para a quantidade de recursos que é suficiente para resolver
um problema. Para saber quanto pode-se melhorar este algoritmo, precisa-se estabelecer um limite
inferior (“lower bound”) na quantidade de recursos necessários, ou seja, qual a quantidade mínima
UEMS - Professora Viviane Duarte Bonfim
58
necessária de recursos para a solução do problema. Naturalmente, tem-se interesse em estabelecer o
mais limite e, analogamente, o menor limite superior possível.
Idealmente, os dois limites, inferior e superior, deveriam ser iguais, pois neste caso, saberia
exatamente a quantidade de recursos que é tanto necessária quanto suficiente para resolver um
problema.
Se utilizar um algoritmo que utilize exatamente esta quantidade de recursos, então, tem-se um
algoritmo ótimo para a tarefa.
A diferença entre limite inferior e superior demonstra uma medida de quanto o algoritmo pode
ser melhorado. Nem sempre é possível construir algoritmos ótimos.
A fim de capturar a noção de algoritmo praticamente viável, deve-se limitar os dispositivos
computacionais para somente executar um número de passos que é limitado por um polinômio no
comprimento da entrada. A esta classe de problemas denomina-se classe P. Existem problemas que
possuem verificação algorítmica em tempo não polinomial e formam a classe NP. Mas existem
problemas que não possuem uma fácil verificação algorítmica, os quais são denominados de
problemas “NP-Completos”. O tempo de execução destes algoritmos é não polinomial e de difícil
verificação. Os problemas de decisão na classe NP permitem que validem potenciais soluções em um
tempo polinomial. Isso quer dizer que para problemas NP utiliza-se uma redutibilidade polinomial.
4.3.8. Problemas Tratáveis e Intratáveis
Considerando a coleção de todos os algoritmos que resolvem certo problema P. Se existir um
algoritmo de complexidade polinomial, então P é denominado tratável; caso contrário é denominado
intratável. A idéia é que um problema tratável sempre pode ser resolvido por um processo automático
(computador, por ex.) em, tempo factível. Algoritmos não polinomiais, de problema intratável, podem
levar séculos, mesmo para entradas de tamanho reduzido.
Da Teoria da Complexidade pode-se considerar alguns critérios práticos para o julgamento de
um programa:
� Ele faz exatamente o que espera que faça?
� Ele o faz corretamente, de acordo com as especificações originais da tarefa?
� Há uma documentação que descreva como usá-lo e como ele trabalha?
� As sub-rotinas são criadas de tal modo que realizem sub-funções lógicas?
� O código é legível?
� Ele é executado em tempo ótimo de execução?
� Ele utiliza memória mínima necessária para sua execução?
UEMS - Professora Viviane Duarte Bonfim
59
Com essas considerações conclui-se que:
� Um algoritmo é eficiente precisamente quando sua complexidade for baixa;
� Um algoritmo é eficiente precisamente quando a sua complexidade for um polinômio nos
tamanhos de entrada e saída;
� Este critério não é absoluto, mas na maioria os casos é realmente aceitável.
4.3.9. Modelo Formal de Algoritmo: Máquina de Turing
Para se estudar os limites da computabilidade e da complexidade computacional, é necessário
escolher um modelo formal de algoritmo. O mais utilizado é o da Máquina de Turing, pois:
� É suficientemente simples, facilitando demonstrações, e,
� Ao mesmo tempo, é suficientemente poderoso para que os resultados se apliquem a
� Modelos aparentemente com mais recursos (na verdade, poderoso o suficiente para que
qualquer algoritmo possa ser nele representado).
Em 1936 o matemático britânico Alan Turing imaginou uma máquina abstrata denominada
Turing Machine. A Máquina de Turing será estudada melhor mais adiante.
UEMS - Professora Viviane Duarte Bonfim
60
REFERÊNCIAS BIBLIOGRÁFICAS
Apostila de Teoria dos Autômatos e da Computabilidade. Professora Maria Aparecida Fernandes de
Almeida. Agosto, 2001.
Apostila de Linguagens Formais e Compiladores. Professor Olinto José Varela Furtado, Universidade
Federal de Santa Catarina – UFSC, 2003.
Apostila de Compiladores. Professor Bráulio Adriano de Mello. Agosto, 2001.
ARBIB, M. A Theories of Abstract Automata. Prentice Hall in Automatic Computation, 1969.
DIVÉRIO, TIARAJU ASMUZ & MENEZES, Paulo F. Bath. Teoria da Computação, Série de Livros
Didáticos, Porto Alegre: Editora Sagra Luzzato.
DOMÊNICO, L. C. Matemática 3 em 1, Curso Completo de 2º Grau. São Paulo: Instituto Brasileiro de
Edições Pedagógicas.
GIOVANI, J. R. & BONJORNO, J. R. Matemática, 2º Grau, Vol. 1. São Paulo: Editora FTDS.A.
HOPCROFT, J. E., ULLMAN, J. D. Introduction to Automata Theory, Languages and Computation. New
York : Addison Wesley, 1979.
Material sobre Grafos. Disponível em http://www.ulbra.tche.br/~danielnm/ed/B/polB.html. Fevereiro,
2001.
MENEZES, P. F. B. Linguagens Formais e Autômatos. 4º ed. Série de Livros Didáticos. Porto Alegre :
Sagra Luzzato, 2001.