Existem vários métodos para fazer a conversão de autômatos finitos em expressões regulares. Aqui vou descrever o que normalmente é ensinado na escola, que é muito visual. Eu acredito que é o mais usado na prática. No entanto, escrever o algoritmo não é uma boa idéia.
Método de remoção de estado
Esse algoritmo trata do manuseio do gráfico do autômato e, portanto, não é muito adequado para algoritmos, pois ele precisa de primitivas do gráfico, como ... remoção de estado. Vou descrevê-lo usando primitivas de nível superior.
A ideia chave
A idéia é considerar expressões regulares nas arestas e remover estados intermediários, mantendo os rótulos das arestas consistentes.
O padrão principal pode ser visto a seguir nas figuras. O primeiro possui rótulos entre que são expressões regulares queremos remover .e , f , g , h , i qp , q, re , f, g, H , iq
Uma vez removidos, compomos juntos (enquanto preservamos as outras arestas entre e mas isso não é exibido aqui):p re , f, g, H , ipr
Exemplo
Usando o mesmo exemplo da resposta de Raphael :
removemos sucessivamente :q2
e depois :q3
ainda precisamos aplicar uma estrela na expressão de a . Nesse caso, o estado final também é inicial; portanto, precisamos apenas adicionar uma estrela:q 1q1q1
( a b + ( b + a a ) ( b a )∗( a + b b ) )∗
Algoritmo
L[i,j]
é a regexp do idioma de a . Primeiro, removemos todas as arestas múltiplas:q jqEuqj
for i = 1 to n:
for j = 1 to n:
if i == j then:
L[i,j] := ε
else:
L[i,j] := ∅
for a in Σ:
if trans(i, a, j):
L[i,j] := L[i,j] + a
Agora, a remoção do estado. Suponha que desejemos remover o estado :qk
remove(k):
for i = 1 to n:
for j = 1 to n:
L[i,i] += L[i,k] . star(L[k,k]) . L[k,i]
L[j,j] += L[j,k] . star(L[k,k]) . L[k,j]
L[i,j] += L[i,k] . star(L[k,k]) . L[k,j]
L[j,i] += L[j,k] . star(L[k,k]) . L[k,i]
Note-se que ambos com um lápis de papel e com um algoritmo que você deve simplificar expressões como star(ε)=ε
, e.ε=e
, ∅+e=e
, ∅.e=∅
(por mão você simplesmente não escrever a borda quando não está , ou mesmo para uma auto-loop e você ignorar quando há nenhuma transição entre e ou e )∅q i q k q j q kεqEuqkqjqk
Agora, como usar remove(k)
? Você não deve remover os estados finais ou iniciais de ânimo leve, caso contrário, perderá partes do idioma.
for i = 1 to n:
if not(final(i)) and not(initial(i)):
remove(i)
Se você tiver apenas um estado final e um estado inicial , a expressão final será:q sqfqs
e := star(L[s,s]) . L[s,f] . star(L[f,s] . star(L[s,s]) . L[s,f] + L[f,f])
Se você possui vários estados finais (ou mesmo estados iniciais), não há uma maneira simples de mesclar esses, além de aplicar o método de fechamento transitivo. Normalmente, este não é um problema manual, mas é complicado ao escrever o algoritmo. Uma solução muito mais simples é enumerar todos os pares e executar o algoritmo no gráfico (já removido pelo estado) para obter todas as expressões supondo que é o único estado inicial é o único final estado, fazendo a união de todos os .e s , f s f e s , f( s , f)es , fsfes , f
Isso e o fato de modificar linguagens de maneira mais dinâmica que o primeiro método tornam mais propenso a erros na programação. Eu sugiro usar qualquer outro método.
Contras
Existem muitos casos nesse algoritmo, por exemplo, para escolher qual nó devemos remover, o número de estados finais no final, o fato de que um estado final também pode ser inicial etc.
Observe que agora que o algoritmo está escrito, é muito parecido com o método de fechamento transitivo. Somente o contexto do uso é diferente. Não recomendo implementar o algoritmo, mas usar o método para fazer isso manualmente é uma boa idéia.