Die Konvertierung regulärer Ausdrücke in (minimale) NFA, die dieselbe Sprache akzeptieren, ist mit Standardalgorithmen, z . B. dem Thompson-Algorithmus, einfach . Die andere Richtung scheint jedoch langweiliger zu sein, und manchmal sind die resultierenden Ausdrücke chaotisch.
Welche Algorithmen gibt es, um NFA in gleichwertige reguläre Ausdrücke umzuwandeln? Gibt es Vorteile hinsichtlich Zeitaufwand oder Ergebnisgröße?
Dies soll eine Referenzfrage sein. Bitte fügen Sie eine allgemeine Beschreibung Ihrer Methode sowie ein nicht triviales Beispiel bei.
Antworten:
Es gibt verschiedene Methoden, um die Konvertierung von endlichen Automaten in reguläre Ausdrücke durchzuführen. Hier werde ich diejenige beschreiben, die normalerweise in der Schule unterrichtet wird und die sehr visuell ist. Ich glaube, es wird in der Praxis am häufigsten verwendet. Das Schreiben des Algorithmus ist jedoch keine so gute Idee.
Methode zum Entfernen des Zustands
Dieser Algorithmus behandelt den Graphen des Automaten und ist daher für Algorithmen nicht sehr geeignet, da er Graphprimitive wie ... state removal benötigt. Ich werde es mit übergeordneten Primitiven beschreiben.
Die Schlüsselidee
Die Idee ist, reguläre Ausdrücke an Kanten zu berücksichtigen und dann Zwischenzustände zu entfernen, während die Kantenbeschriftungen konsistent bleiben.
Das Hauptmuster lässt sich im Folgenden an Figuren ablesen. Die erste hat Bezeichnungen zwischen , die reguläre Ausdrücke e , f , g , h , i sind, und wir möchten q entfernen .p , q, r e , f, g, H , i q
Nach dem Entfernen setzen wir zusammen (wobei die anderen Kanten zwischen p und r erhalten bleiben , dies wird hier jedoch nicht angezeigt):e , f, g, H , i p r
Beispiel
Verwenden Sie dasselbe Beispiel wie in Raffaels Antwort :
wir entfernen nacheinander :q2
und dann :q3
dann müssen wir noch einen Stern auf den Ausdruck von bis q 1 anwenden . In diesem Fall ist der Endzustand ebenfalls initial, so dass wir wirklich nur einen Stern hinzufügen müssen:q1 q1
Algorithmus
L[i,j]
ist der Ausdruck der Sprache von bis q j . Zuerst entfernen wir alle Mehrkanten:Nun ist die staatliche Entfernung. Angenommen, wir möchten den Zustand entfernen :qk
star(ε)=ε
e.ε=e
∅+e=e
∅.e=∅
Nun, wie benutzt man
remove(k)
? Sie sollten End- oder Anfangszustände nicht leichtfertig entfernen, da Sie sonst Teile der Sprache vermissen.Wenn Sie nur einen Endzustand und einen Anfangszustand der :q sqf qs
Wenn Sie mehrere Endzustände (oder sogar Anfangszustände) haben, gibt es keine einfache Möglichkeit zum Zusammenführen dieser Zustände außer der Anwendung der transitiven Abschlussmethode. Normalerweise ist dies kein Problem von Hand, aber beim Schreiben des Algorithmus ist dies umständlich. Eine viel einfachere Problemumgehung besteht darin, alle Paare und den Algorithmus im (bereits vom Status entfernten) Diagramm auszuführen, um alle Ausdrücke abzurufen, wobei angenommen wird , dass der einzige Anfangszustand und der einzige Endzustand ist state, dann mache die Vereinigung aller .e s , f s f e s , f(s,f) es,f s f es,f
Dies und die Tatsache, dass dadurch Sprachen dynamischer geändert werden als bei der ersten Methode, machen sie beim Programmieren fehleranfälliger. Ich schlage vor, eine andere Methode zu verwenden.
Nachteile
In diesem Algorithmus gibt es viele Fälle, zum Beispiel, um auszuwählen, welchen Knoten wir entfernen möchten, wie viele Endzustände am Ende vorliegen, ob ein Endzustand auch anfänglich sein kann usw.
Beachten Sie, dass dieser Algorithmus jetzt, da er geschrieben wurde, der Methode der transitiven Schließung sehr ähnlich ist. Lediglich der Kontext der Nutzung ist unterschiedlich. Ich empfehle nicht, den Algorithmus zu implementieren, aber es ist eine gute Idee, die Methode manuell zu verwenden.
quelle
ab
Methode
Die schönste Methode, die ich gesehen habe, ist eine, die den Automaten als Gleichungssystem von (regulären) Sprachen ausdrückt, die gelöst werden können. Es ist besonders schön, da es prägnantere Ausdrücke liefert als andere Methoden.
Sei eine NFA ohne -Übergänge. Erstellen Sie für jeden Zustand die GleichungA=(Q,Σ,δ,q0,F) ε qi
wobei die Menge der Endzustände und bedeutet , es ist ein Übergang von mit markiertem . Wenn Sie als oder lesen (abhängig von der Definition Ihres regulären Ausdrucks), sehen Sie, dass dies eine Gleichung für reguläre Ausdrücke ist.F qi→aqj qi qj a ∪ + ∣
Zur Lösung des Systems benötigen Sie Assoziativität und Verteilungsfähigkeit von und (String-Verkettung), Kommutativität von und Ardens Lemma ¹:∪ ⋅ ∪
Die Lösung ist eine Menge von regulären Ausdrücken , einer für jeden Zustand . beschreibt genau die Wörter, die von akzeptiert werden können, wenn es in gestartet ; daher ist (wenn der Anfangszustand ist) der gewünschte Ausdruck.Qi qi Qi A qi Q0 q0
Beispiel
Der Übersichtlichkeit halber bezeichnen wir Singleton-Mengen nach ihrem Element, dh . Das Beispiel stammt von Georg Zetzsche.a={a}
Betrachten Sie diese NFA:
[ Quelle ]
Das entsprechende Gleichungssystem lautet:
Stecken Sie nun die dritte Gleichung in die zweite:
Für den letzten Schritt wenden wir Ardens Lemma mit , und . Beachten Sie, dass alle drei Sprachen regulär sind und , sodass wir das Lemma anwenden können. Nun stecken wir dieses Ergebnis in die erste Gleichung:L=Q1 U=ab V=(b∪aa)⋅Q0 ε∉U={ab}
Somit haben wir einen regulären Ausdruck für die Sprache gefunden, die vom obigen Automaten akzeptiert wird, nämlich
Beachten Sie, dass es ziemlich prägnant ist (vergleiche mit dem Ergebnis anderer Methoden), aber nicht eindeutig bestimmt wird. Lösen des Gleichungssystems mit einer anderen Reihenfolge von Manipulationen führt zu einem anderen Äquivalent! - Ausdrücke.
quelle
maybe_union/2
Prädikat könnte mehr Arbeit gebrauchen (insbesondere das Entfernen des gemeinsamen Präfixes), um reguläre Ausdrücke ordentlicher zu gestalten. Eine andere Möglichkeit, diese Methode zu verstehen, besteht darin, sie als Übersetzung von Regex in eine rechtslineare Grammatik zu verstehen, wobei Sprachen mit Prolog-ähnlicher Vereinheitlichung oder ML-ähnlicher Musterübereinstimmung für sehr gute Wandler sorgen und nicht nur Stift und Papier sind Algorithmus :)Brzozowski algebraische Methode
Dies ist die gleiche Methode wie die in Raphaels Antwort beschriebene , jedoch unter dem Gesichtspunkt eines systematischen Algorithmus und dann tatsächlich des Algorithmus. Die Implementierung gestaltet sich einfach und natürlich, sobald Sie wissen, wo Sie anfangen sollen. Es kann auch von Hand einfacher sein, wenn das Zeichnen aller Automaten aus irgendeinem Grund unpraktisch ist.
Wenn Sie einen Algorithmus schreiben, müssen Sie bedenken, dass die Gleichungen immer linear sein müssen, damit Sie eine gute abstrakte Darstellung der Gleichungen erhalten, was Sie beim Lösen von Hand vergessen können.
Die Idee des Algorithmus
Ich werde nicht beschreiben, wie es funktioniert, da es in Raphaels Antwort, die ich vorher lesen möchte, gut gemacht ist. Stattdessen konzentriere ich mich darauf, in welcher Reihenfolge Sie die Gleichungen lösen sollten, ohne zu viele zusätzliche Berechnungen oder zusätzliche Fälle durchzuführen.
Ausgehend von Ardens genialer Lösung zur wir den Automaten als eine Menge von Gleichungen der Form betrachten:X=A∗B X=AX∪B
Wir können dies durch Induktion auf lösen, indem wir die Arrays und entsprechend aktualisieren . Im Schritt haben wir:n Ai,j Bi,j n
und Ardens Regel gibt uns:
und durch Setzen von und wir:B′n=A∗n,nBn A′n,i=A∗n,nAn,i
und wir können dann alle Bedürfnisse von im System entfernen , indem wir für :Xn i,j<n
A ' i , j = A i , j + A i , n A ' n , j
Wenn wir mit gelöst haben , erhalten wir eine Gleichung wie folgt: n = 1Xn n=1
ohne . So haben wir unseren regulären Ausdruck bekommen.A′1,i
Der Algorithmus
Dank dessen können wir den Algorithmus erstellen. Um die gleiche Konvention wie in der obigen Induktion zu haben, werden wir sagen, dass der Anfangszustand und dass die Anzahl der . Zuerst die Initialisierung zum Füllen von : m Bq1 m B
und :A
und dann die Lösung:
Der endgültige Ausdruck lautet dann:
Implementierung
Auch wenn es ein Gleichungssystem zu sein scheint, das für einen Algorithmus zu symbolisch erscheint, eignet sich dieses System gut für eine Implementierung.
Hier ist eine Implementierung dieses Algorithmus in Ocaml(defekter Link) . Beachten Sie, dass bis auf die Funktionbrzozowski
alles gedruckt oder für Raffaels Beispiel verwendet werden soll. Beachten Sie, dass es eine überraschend effiziente Funktion zur Vereinfachung regulärer Ausdrücke gibtsimple_re
.quelle
Transitive Verschlussmethode
Diese Methode ist einfach in Form eines Algorithmus zu schreiben, generiert jedoch absurd große reguläre Ausdrücke und ist unpraktisch, wenn Sie sie von Hand ausführen, meistens, weil dies zu systematisch ist. Es ist jedoch eine gute und einfache Lösung für einen Algorithmus.
Die Schlüsselidee
Beispiel
Wir werden dasselbe Beispiel wie in Raphaels Antwort verwenden . Zunächst können Sie nur die direkten Übergänge verwenden.
Algorithmus
Initialisierung:
Transitive Schließung:
quelle