Esistono diversi metodi per eseguire la conversione da automi finiti a espressioni regolari. Qui descriverò quello che di solito viene insegnato a scuola, che è molto visivo. Credo che sia il più usato in pratica. Tuttavia, scrivere l'algoritmo non è una buona idea.
Metodo di rimozione dello stato
Questo algoritmo riguarda la gestione del grafico dell'automa e non è quindi molto adatto agli algoritmi poiché ha bisogno di primitive grafiche come ... rimozione dello stato. Lo descriverò usando primitivi di livello superiore.
L'idea chiave
L'idea è quella di considerare le espressioni regolari sui bordi e quindi rimuovere gli stati intermedi mantenendo coerenti le etichette dei bordi.
Lo schema principale può essere visto nelle figure seguenti. Il primo ha etichette tra che sono espressioni regolari e , f , g , h , i e vogliamo rimuovere q .p , q, re , f, g, h , ioq
Una volta rimosso, componiamo insieme (preservando gli altri bordi tra p e r ma questo non viene visualizzato su questo):e , f, g, h , iopr
Esempio
Usando lo stesso esempio della risposta di Raffaello :
rimuoviamo successivamente :q2
e quindi :q3
allora dobbiamo ancora applicare una stella sull'espressione da a q 1 . In questo caso, anche lo stato finale è iniziale, quindi è sufficiente aggiungere una stella:q1q1
(ab+(b+aa)(ba)∗(a+bb))∗
Algoritmo
L[i,j]
è la regexp della lingua da a q j . Innanzitutto, rimuoviamo tutti i bordi multipli:qiqj
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
Ora, la rimozione dello stato. Supponiamo di voler rimuovere lo stato :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]
star(ε)=ε
e.ε=e
∅+e=e
∅.e=∅
∅εq k q j q kqiqkqjqk
Ora, come si usa remove(k)
? Non dovresti rimuovere leggermente gli stati finali o iniziali, altrimenti perderai parti della lingua.
for i = 1 to n:
if not(final(i)) and not(initial(i)):
remove(i)
Se hai solo uno stato finale e uno stato iniziale l'espressione finale è: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 hai diversi stati finali (o addirittura stati iniziali), non esiste un modo semplice di unire questi, se non quello di applicare il metodo di chiusura transitiva. Di solito questo non è un problema a mano ma questo è imbarazzante quando si scrive l'algoritmo. Una soluzione molto più semplice consiste nell'enumerare tutte le coppie ed eseguire l'algoritmo sul grafico (già rimosso dallo stato) per ottenere tutte le espressioni supponendo che sia l'unico stato iniziale e sia l'unico finale stato, quindi facendo l'unione di tutti .e s , f s f e s , f(s,f)es,fsfes,f
Questo e il fatto che questo sta modificando i linguaggi in modo più dinamico rispetto al primo metodo lo rendono più soggetto a errori durante la programmazione. Suggerisco di usare qualsiasi altro metodo.
Contro
Ci sono molti casi in questo algoritmo, ad esempio per scegliere quale nodo dovremmo rimuovere, il numero di stati finali alla fine, il fatto che anche uno stato finale può essere iniziale, ecc.
Si noti che ora che l'algoritmo è stato scritto, è molto simile al metodo di chiusura transitiva. Solo il contesto dell'uso è diverso. Non consiglio di implementare l'algoritmo, ma usare il metodo per farlo manualmente è una buona idea.