Istnieje kilka metod konwersji z automatów skończonych na wyrażenia regularne. Tutaj opiszę ten, którego zwykle uczy się w szkole, który jest bardzo wizualny. Uważam, że jest najczęściej używany w praktyce. Jednak napisanie algorytmu nie jest tak dobrym pomysłem.
Metoda usuwania stanu
Algorytm ten dotyczy obsługi wykresu automatu i dlatego nie jest zbyt odpowiedni dla algorytmów, ponieważ wymaga prymitywów grafowych, takich jak ... usunięcie stanu. Opiszę to za pomocą prymitywów wyższego poziomu.
Kluczowy pomysł
Chodzi o rozważenie wyrażeń regularnych na krawędziach, a następnie usunięcie stanów pośrednich przy zachowaniu spójności etykiet krawędzi.
Główny wzór można zobaczyć poniżej na rysunkach. Pierwszy ma etykiety między które są wyrażeniami regularnymi e , f , g , h , i, i chcemy usunąć q .p,q,re,f,g,h,iq
Po usunięciu składamy razem (zachowując pozostałe krawędzie między p i r, ale nie jest to wyświetlane na tym):e,f,g,h,ipr
Przykład
Korzystając z tego samego przykładu, co w odpowiedzi Raphaela :
sukcesywnie usuwamy :q2
a następnie :q3
wtedy nadal musimy zastosować gwiazdkę do wyrażenia od do q 1 . W tym przypadku stan końcowy jest również początkowy, więc naprawdę wystarczy dodać gwiazdkę:q1q1
(ab+(b+aa)(ba)∗(a+bb))∗
Algorytm
L[i,j]
to wyrażenie regularne języka od do q j . Najpierw usuwamy wszystkie krawędzie: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
Teraz usunięcie stanu. Załóżmy, że chcemy usunąć stan :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]
Należy zauważyć, że zarówno z ołówkiem papieru i algorytmu należy uprościć wyrażenia jak star(ε)=ε
, e.ε=e
, ∅+e=e
, ∅.e=∅
(ręcznie po prostu nie pisać krawędź gdy nie lub nawet ε dla siebie pętli i zignorować, gdy istnieje brak przejścia między q i a q k lub q j i q k )∅εqiqkqjqk
Teraz, jak korzystać remove(k)
? Nie powinieneś lekko usuwać stanów końcowych ani początkowych, w przeciwnym razie ominiesz część języka.
for i = 1 to n:
if not(final(i)) and not(initial(i)):
remove(i)
Jeśli masz tylko jeden ostateczny stan i jeden stan początkowy q s następnie ostateczne wyrażenie jest:qfqs
e := star(L[s,s]) . L[s,f] . star(L[f,s] . star(L[s,s]) . L[s,f] + L[f,f])
Jeśli masz kilka stanów końcowych (lub nawet stanów początkowych), nie ma prostego sposobu połączenia tych stanów, oprócz zastosowania metody zamykania przechodniego. Zwykle nie jest to problem ręcznie, ale jest to niewygodne podczas pisania algorytmu. Znacznie prostszym obejściem jest wyliczenie wszystkich par i uruchomienie algorytmu na wykresie (już usuniętym przez stan), aby uzyskać wszystkie wyrażenia e s , f zakładając , że s jest jedynym stanem początkowym if jest jedynym stanem końcowym, następnie robi unii wszystkich e s , f .(s,f)es,fsfes,f
To oraz fakt, że modyfikuje języki bardziej dynamicznie niż pierwsza metoda, czyni go bardziej podatnym na błędy podczas programowania. Sugeruję użycie innej metody.
Cons
Algorytm zawiera wiele przypadków, na przykład wybór węzła, który należy usunąć, liczbę stanów końcowych na końcu, fakt, że stan końcowy może być również początkowy itp.
Zauważ, że teraz, gdy algorytm jest zapisany, przypomina to metodę zamykania przechodniego. Jedynie kontekst użytkowania jest inny. Nie polecam implementacji algorytmu, ale dobrym pomysłem jest użycie metody ręcznej.