Hogyan lehet a véges automatákat konvertálni reguláris kifejezésekké?
On február 16, 2021 by adminA reguláris kifejezések konvertálása (minimális) NFA-ba, amelyek elfogadják ugyanazt a nyelvet, egyszerű algoritmusokkal, pl. Thompson algoritmusa . A másik irány azonban unalmasabbnak tűnik, és néha a kapott kifejezések rendetlenek.
Milyen algoritmusok vannak van-e az NFA egyenértékű reguláris kifejezésekké konvertálása? Vannak-e előnyei az idő összetettségével vagy az eredmény nagyságával kapcsolatban?
Ez állítólag referencia kérdés. Kérjük, mellékeljen a módszer általános leírását, valamint egy nem triviális példa.
Megjegyzések
- Megjegyez egy hasonló kérdést itt: cstheory.SE , amely valószínűleg nem alkalmas közönségünk számára.
- minden válasz formális technikát használ a RE írásához a DFA-ból. Úgy gondolom, hogy technikám elemzéssel viszonylag könnyű és objektív, amit a válaszomban bemutatok : Mi a nyelve ezeknek a determinisztikus véges automatáknak? Úgy érzem, valamikor hasznos lenne. Igen, természetesen valamikor magam is formális módszert használok (Arden-tétel) írni RE az a kérdés összetett, mint ebben a példában: Hogyan írhatunk reguláris kifejezést egy DFA-hoz
Válasz
Számos módszer létezik a véges automatákból a reguláris kifejezésekké történő átalakításra. Itt leírom az iskolában általában tanítottakat, amelyek nagyon vizuálisak. Úgy gondolom, hogy a gyakorlatban használják a legjobban. Az algoritmus megírása azonban nem olyan jó ötlet.
Állapoteltávolítási módszer
Ez az algoritmus az automata grafikonjának kezeléséről szól, és ezért nem túl alkalmas algoritmusokhoz, mivel szüksége van rá grafikon primitívek, például … állapot eltávolítás. Magasabb szintű primitívekkel fogom leírni.
A legfontosabb ötlet
Az ötlet az, hogy fontolóra vegyük az éleken található szabályos kifejezéseket, majd eltávolítsuk a köztes állapotokat, miközben az élek címkéi konzisztensek maradnak.
A fő minta az alábbiakban látható az ábrákon. Az elsőnek vannak $ p, q, r $ közötti címkéi, amelyek reguláris kifejezések: $ e, f, g, h, i $, és el akarjuk távolítani a $ q $ -t.
Miután eltávolítottuk, összeállítjuk a $ e, f, g, h, i $ -t (miközben megőrzzük a többi élt a $ p $ és $ r $ között, de ez nem jelenik meg ezen):
Példa
Ugyanazzal a példával használja, mint a Raphael válasza :
egymás után eltávolítjuk a $ q_2 $ -t:
, majd $ q_3 $:
akkor még csillagot kell alkalmaznunk a $ q_1 $ és $ q_1 $ közötti kifejezésre. Ebben az esetben a végső állapot kezdőbetű is, szóval csak csillagot kell hozzáadnunk:
$$ (ab + (b + aa) (ba) ^ * (a + bb)) ^ * $$
Az algoritmus
L[i,j]
a nyelv regexp értéke $ q_i $ és $ q_j $ között. Először eltávolítjuk az összes ti-edge:
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
Most az állapot eltávolítása. Tegyük fel, hogy el akarjuk távolítani a $ q_k $ állapotot:
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]
Ne feledje, hogy mind ceruzával, mind algoritmussal egyszerűsítenie kell a star(ε)=ε
, e.ε=e
, ∅+e=e
, ∅.e=∅
(Írta: viszont csak nem írod az élt, ha ez nem $ ∅ $, vagy akár $ ε $ egy önhuroknál, és figyelmen kívül hagyod, ha nincs átmenet $ q_i $ és $ q_k $ vagy $ q_j $ és $ között q_k $)
Most hogyan kell használni a remove(k)
alkalmazást? Ne távolítsa el könnyedén a végső vagy a kezdeti állapotokat, különben hiányzik a nyelv egy része.
for i = 1 to n: if not(final(i)) and not(initial(i)): remove(i)
Ha csak egy végső állapota van $ q_f $ és egy kezdeti állapot: $ q_s $, akkor a végső kifejezés a következő:
e := star(L[s,s]) . L[s,f] . star(L[f,s] . star(L[s,s]) . L[s,f] + L[f,f])
Ha több végállapotod van (vagy akár kezdeti állapotod van), akkor az összevonásnak nincs egyszerű módja ezek, kivéve a tranzitív lezárási módszer alkalmazását. Általában ez nem okoz problémát kézzel, de ez kínos az algoritmus írásakor. Sokkal egyszerűbb megoldás az összes $ (s, f) $ pár felsorolása, és az algoritmus futtatása a (már állapotból eltávolított) grafikonon az összes kifejezés megszerzéséhez $ e_ {s, f} $ feltételezve, hogy $ s $ az egyetlen kezdeti állapot és a $ f $ az egyetlen végső állapot, amely az összes $ e_ {s, f} $ egyesítését végzi.
Ez és az a tény, hogy ez a nyelveket dinamikusabban módosítja, mint az első módszer programozáskor hajlamosabb a hibára. Javaslom bármilyen más módszer használatát.
Hátrányok
Nagyon sok eset van ebben az algoritmusban, például annak kiválasztására, hogy melyik csomópontot kell eltávolítanunk, a végső állapotok számát a végén , az a tény, hogy a végső állapot is lehet kezdeti, stb.Csak a használat összefüggései különböznek. Nem javaslom az algoritmus végrehajtását, de a módszer kézi használatára jó ötlet.
Megjegyzések
- A példában a 2. kép a csomópont eltávolítása után ” 2 ” hiányzik egy él – a hurok él (ab) az A csomópontban.
- @Kabamaru: Javítva. De most úgy gondolom, hogy a 3. képen szereplő $ \ varepsilon $ -nak is
ab
-nek kell lennie, és hasonlóan talán a végső reguláris kifejezésben is. dolgozzon tetszőleges számú kezdeti és végső állapotra úgy, hogy hozzáad egy új kezdeti $ q ^ + $ -t és egy új végső állapotot $ q ^ – $, és ezeket összekapcsolja az eredeti kezdeti és végső állapotokkal a $ \ varepsilon $ -élekkel. Most távolítsa el az összes eredeti állapotot az összes ből. A kifejezés ekkor megtalálható az egyetlen megmaradt élen, $ q ^ + $ és $ q _- $ között. A konstrukció nem ad ciklust $ q ^ + $ vagy $ q _- $ értéken, mivel ezeknek az állapotoknak nincs bejövő ill. kimenő élek. Vagy ha szigorú vagy, akkor az üres halmazot ábrázoló címkék lesznek. - A második példával még mindig probléma van: az egyszerűsítés előtt az automaták elfogadják a ” ba “, (1, 3, 1), de az egyszerűsítés után nem ‘ t.
Válasz
Módszer
A legszebb módszer, amelyet láttam, az, amely kifejezi az automatát (szabályos) nyelvek egyenletrendszere, amely képes meg kell oldani. Különösen szép, mivel úgy tűnik, hogy tömörebb kifejezéseket eredményez, mint más módszerek.
Engedje meg, hogy $ A = (Q, \ Sigma, \ delta, q_0, F) $ NFA nélkül $ \ varepsilon $ – átmenetek. Minden $ q_i $ államhoz hozza létre az egyenletet.
$ \ qquad \ displaystyle Q_i = \ bigcup \ limits_ {q_i \ overset {a} {\ to} q_j} aQ_j \ cup \ begin {cases} \ {\ varepsilon \} &, \ q_i \ az F-ben \\ \ tyhjyset &, \ text {else} \ end {esetben} $
ahol $ F $ a végállapotok halmaza és a $ q_i \ overset {a} {\ to} q_j $ azt jelenti, hogy átmenet történik $ q_i $ és $ q_j $ között $ a $ . Ha a $ \ cup $ értéket $ + $ vagy $ \ mid $ formátumban olvassa (a reguláris kifejezés definíciójától függően), akkor látja, hogy ez a reguláris kifejezések egyenlete.
A rendszer megoldásához asszociativitásra van szükség. és a $ \ cup $ és $ \ cdot $ (karakterlánc összefűzés), a $ \ cup $ és Arden s Lemma ¹ kommutativitása:
Hagyja, hogy a $ L, U, V \ subseteq \ Sigma ^ * $ reguláris nyelvek a $ \ varepsilon \ notin U $ értékkel. Ezután
$ \ qquad \ displaystyle L = UL \ cup V \ quad \ Longleftrightarrow \ quad L = U ^ * V $
A megoldás egy reguláris kifejezés halmaza $ Q_i $, minden államhoz egy, a $ q_i $. A $ Q_i $ pontosan azokat a szavakat írja le, amelyeket a $ A $ elfogadhat, amikor $ q_i $ -ban indul; ezért $ Q_0 $ (ha a $ q_0 $ a kezdeti állapot) a kívánt kifejezés.
Példa
Az egyértelműség kedvéért a szinglet halmazokat elemükkel jelöljük, azaz $ a = \ {a \} $. példa Georg Zetzschének köszönhető.
Fontolja meg t az NFA-ja:
[ forrás ]
A megfelelő egyenletrendszer a következő:
$ \ qquad \ begin {align} Q_0 & = aQ_1 \ cup bQ_2 \ cup \ varepsilon \\ Q_1 & = bQ_0 \ cup aQ_2 \\ Q_2 & = aQ_0 \ cup bQ_1 \ end {align} $
Most csatlakoztassa a harmadik egyenletet a másodikba:
$ \ qquad \ begin {align} Q_1 & = bQ_0 \ cup a (aQ_0 \ csésze bQ_1) \\ & = abQ_1 \ csésze (b \ csésze aa) Q_0 \\ & = (ab) ^ * ( b \ cup aa) Q_0 \ end {align} $
Az utolsó lépésben Arden Lemmáját alkalmazzuk $ L = Q_1 $, $ U = ab $ és $ V = (b \ cup aa) \ cdot Q_0 $. Ne feledje, hogy mindhárom nyelv szabályos, és a $ \ varepsilon \ notin U = \ {ab \} $, ami lehetővé teszi számunkra a lemma alkalmazását. Most ezt az eredményt bedugjuk az első egyenletbe:
$ \ qquad \ begin {align} Q_0 & = a (ab) ^ * (b \ cup aa ) Q_0 \ csésze baQ_0 \ csésze bb (ab) ^ * (b \ csésze aa) Q_0 \ csésze \ varepsilon \\ & = ((a \ csésze bb) (ab) ^ * (b \ csésze aa) \ csésze ba) Q_0 \ csésze \ varepsilon \\ & = ((a \ csésze bb) (ab) ^ * (b \ csésze aa) \ cup ba) ^ * \ qquad \ text {(írta: Arden “s Lemma)} \ end {align} $
Így találtunk egy szabályos kifejezést a fenti automata által elfogadott nyelvre:
$ \ qquad \ displaystyle ((a + bb) (ab) ^ * (b + aa) + ba) ^ *. $
Vegye figyelembe, hogy elég tömör (hasonlítsa össze a más módszerek eredményei), de nincsenek egyedileg meghatározva; az egyenletrendszer megoldása más manipulációs sorrenddel más – ekvivalens! – kifejezésekhez vezet.
- Arden igazolásához ” s Lemma, lásd itt .
Megjegyzések
- Mi az algoritmus időbeli összetettsége? Van-e korlátozás az előállított kifejezés méretére?
- @jmite: Fogalmam sincs. Nem gondolom, hogy ‘ ezt megpróbálnám megvalósítani (más módszerek ebben a tekintetben megvalósíthatóbbnak tűnnek), de toll-papír módszer.
- Itt ‘ sa ennek az algoritmusnak a Prolog-megvalósítása: github.com / wvxvw / intro-to-automata-theory / blob / master / automata / … , de
maybe_union/2
predikátuma használható több munka (pl. wrt kiküszöbölve a közös előtagot) a rendesebb szabályos kifejezések érdekében. A módszer meglátásának másik módja az, ha megértjük a regexből a jobb-lineáris nyelvtanba történő fordításként, ahol a Prolog-szerű unifikációval vagy ML-szerű mintaillesztéssel rendelkező nyelvek nagyon jó átalakítókat eredményeznek, ezért ‘ nemcsak toll és papír algoritmus 🙂 - Csak egy kérdés. Az első egyenletben szereplő ε azért van, mert a Qo kiinduló állapot, vagy azért, mert ‘ végső állapot? Ugyanúgy, ha két végállapotom van?
- @PAOK Ellenőrizze a $ Q_i $ definícióját a fenti sorban (a sor); azért ‘ s, mert a $ q_0 $ egy végső állapot.
Válasz
Brzozowski algebrai módszer
Ez ugyanaz a módszer, mint amelyet a Raphael válaszában leírtak, de egy nézet egy szisztematikus algoritmusról, majd valóban az algoritmus. Kiderül, hogy könnyen és természetes módon megvalósítható, ha tudod, hol kezdheted. Könnyebb lehet kézzel is, ha az összes automata rajzolása valamilyen okból nem praktikus.
Algoritmus írásakor emlékeznie kell arra, hogy az egyenleteknek mindig lineárisaknak kell lenniük, hogy az elvonások jó absztrakt ábrázolása legyen, amit elfelejthet, amikor kézzel oldja meg.
Az algoritmus ötlete
Nem fogom leírni a működését, mivel a Raphael válaszában jól megcsinálom. javasolom, hogy olvassa el korábban. Ehelyett arra koncentrálok, hogy melyik sorrendben kell megoldania az egyenleteket anélkül, hogy túl sok kiegészítőt tenne mputációk vagy extra esetek.
Arden szabályának ötletes megoldása a $ X = A ^ * B $ kezdettől a nyelvi egyenletig $ X = AX∪B $ tekinthetjük az automatát a következő egyenlethalmaznak:
$$ X_i = B_i + A_ {i, 1} X_1 +… + A_ {i, n} X_n $$
ezt meg tudjuk oldani a $ n $ indukciójával azáltal, hogy ennek megfelelően frissítjük a $ A_ {i, j} $ és $ B_ {i, j} $ tömböket. A $ n $ lépésnél:
$$ X_n = B_n + A_ {n, 1} X_1 +… + A_ {n, n} X_n $$
és Arden szabálya megadja:
$$ X_n = A_ {n, n} ^ * (B_n + A_ {n, 1} X_1 +… + A_ {n, n-1} X_ {n -1}) $$
és a $ B “_n = A_ {n, n} ^ * B_n $ és $ A” _ {n, i} = A_ {n, n} ^ * beállításával A_ {n, i} $ -ot kapunk:
$$ X_n = B “_n + A” _ {n, 1} X_1 +… + A “_ {n, n-1} X_ {n -1} $$
és ezután eltávolíthatjuk a $ X_n $ összes igényét a rendszerből azáltal, hogy beállítjuk a $ i értékre, j < n $:
$$ B “_i = B_i + A_ {i, n} B” _n $$ $$ A “_ {i, j} = A_ {i, j} + A_ {i, n} A “_ {n, j} $$
Amikor megoldottuk a $ X_n $ értéket, amikor $ n = 1 $, egy ilyen egyenletet kapunk:
$$ X_1 = B” _1 $$
nincs $ A “_ {1, i} $. Így megkaptuk a reguláris kifejezésünket.
Az algoritmus
Ennek köszönhetően felépíthetjük az algoritmust. Ahhoz, hogy a fenti indukcióval megegyező konvenció legyen, azt mondjuk, hogy a kezdeti állapot $ q_1 $, és az állapot száma $ m $. Először az inicializálás a $ B $ kitöltésére:
for i = 1 to m: if final(i): B[i] := ε else: B[i] := ∅
és $ A $:
for i = 1 to m: for j = 1 to m: for a in Σ: if trans(i, a, j): A[i,j] := a else: A[i,j] := ∅
majd a megoldás:
for n = m decreasing to 1: B[n] := star(A[n,n]) . B[n] for j = 1 to n: A[n,j] := star(A[n,n]) . A[n,j]; for i = 1 to n: B[i] += A[i,n] . B[n] for j = 1 to n: A[i,j] += A[i,n] . A[n,j]
a végső kifejezés ekkor:
e := B[1]
Megvalósítás
Még akkor is, ha ez olyan egyenletrendszernek tűnik, amely túl szimbolikusnak tűnik egy algoritmus számára, ez a megoldás alkalmas megvalósításra. Itt van ennek az algoritmusnak az implementációja az Ocaml ben (megszakadt hivatkozás) . Ne feledje, hogy a brzozowski
függvényen kívül minden nyomtatásra vagy Raphael példájára használható. Vegye figyelembe, hogy a reguláris kifejezések egyszerűsítésének meglepően hatékony funkciója van simple_re
.
Megjegyzések
- A link már nem működik …
- Megvalósítás Javascriptben: github.com/devongovett/regexgen/blob/master/src/regex.js
- köszönöm ezt a nagyszerű magyarázatot. Ha jól értem, az inicializálási álkódod feltételezi, hogy adott i és j esetén legfeljebb egy van, amely (i, a, j) átmenet. Ez akkor helyes, ha egyetértünk abban, hogy ezt az átmenetet a Σ amely a betűautomatában áttér az i-ről j-re, de akkor az a in jelölése kissé furcsa, mivel valójában nem betű. Ha betűről betűre haladunk, akkor több átmenet lehet i-ről j-re, és meg kell végezze el a címkék egyesítését a hurok testében.
Válasz
Transzitív lezárási módszer
Ezt a módszert könnyű formában írni algoritmus, de abszurdul nagy szabályos kifejezéseket generál, és nem praktikus, ha kézzel csinálod, főleg azért, mert ez túl szisztematikus. Jó és egyszerű megoldás egy algoritmushoz.
A legfontosabb ötlet
Jelölje $ R ^ k_ {i, j} $ a $ -tól kezdődő karakterláncok reguláris kifejezését q_i $ – $ q_j $ a $ \ {q_1,…, q_k \} $ állapotok használatával. Legyen $ n $ az automata állapotainak száma.
Tegyük fel, hogy már ismeri a $ R_ {i, j} $ reguláris kifejezést $ q_i $ és $ q_j $ között, a $ q_k köztes állapot nélkül. $ (a végtagok kivételével), az összes $ i, j $ esetében. Akkor kitalálhatja, hogy egy másik állapot hozzáadása milyen hatással lesz az új $ R “_ {i, j} $ reguláris kifejezésre: csak akkor változik, ha közvetlen átmenet van a $ q_k $ -ra, és így is kifejezhető:
$$ R “_ {i, j} = R_ {i, j} + R_ {i, k}. R_ {k, k} ^ *. R_ {k, j} $$
($ R $ = $ R ^ {k-1} $, a $ R “$ pedig $ R ^ k $.)
Példa
Ugyanazt a példát fogjuk használni, mint a Raphael válaszában . Eleinte csak a közvetlen átmeneteket használhatja.
Itt van az első lépés (vegye figyelembe, hogy egy $ a $ címkével rendelkező önhurok az első $ ε $ -t $ (ε + a) alakította volna $.
$$ R ^ 0 = \ begin {bmatrix} ε & a & b \\ b & ε & a \\ a & b & ε \ end {bmatrix} $$
A második lépésben használhatjuk a $ q_0 $ -ot (amelyet átnevezünk nekünk $ q_1 $ -ra, mert a $ R ^ 0 $ már használható megnézzük, hogy működik a $ R ^ 1 $.
$ q_2 $ és $ q_2 $ között: $ R ^ 1_ {2,2} = R ^ 0_ {2,2} + R ^ 0_ {2,1} {R ^ 0_ {1,1}} ^ * R ^ 0_ {1,2} = ε + b ε ^ * a = ε + ba $.
Miért van ez? Ez azért van, mert a $ q_2 $ és a $ q_2 $ közötti váltás csak $ q_1 $ használatával közbenső állapotként megtehető úgy, hogy itt marad ($ ε $), vagy megy a $ q_1 $ ($ a $), ott hurcolódik ($ ε ^ * $) és visszatérés ($ b $).
$$ R ^ 1 = \ begin {bmatrix} ε & a & b \\ b & ε + ba & a + bb \\ a & b + aa & ε + ab \ end {bmatrix} $$
Ilyen módon kiszámolhatja a $ R ^ 2 $ és $ R ^ 3 $, valamint a $ R ^ 3_ {1,1 } $ megadja a végső kifejezést, mert $ 1 $ egyszerre kezdő és végső. Megjegyezzük, hogy itt a kifejezések sok egyszerűsítése megtörtént. Ellenkező esetben a $ R ^ 0 $ első $ a $ értéke $ (∅ + a) $, a $ R ^ 1 $ első $ a $ értéke $ ((∅ + a) + ε (ε) ^ * a ) $.
Algoritmus
Inicializálás:
for i = 1 to n: for j = 1 to n: if i == j: R[i,j,0] := ε else: R[i,j,0] := ∅ for a in Σ: if trans(i, a, j): R[i,j,0] := R[i,j,0] + a
Transzitív lezárás:
for k = 1 to n: for i = 1 to n: for j = 1 to n: R[i,j,k] := R[i,j,k-1] + R[i,k,k-1] . star(R[k,k,k-1]) . R(k,j,k-1)
Ezután a végső kifejezés (tegyük fel, hogy a $ q_s $ a kezdeti állapot):
e := ∅ for i = 1 to n: if final(i): e := e + R[s,i,n]
De el lehet képzelni csúnya szabályos kifejezéseket generál. Valóban olyan dolgokra számíthat, mint a $ (∅) ^ * + (a + (∅) ^ *) (ε) ^ * (a + ∅) $, amelyek ugyanazt a nyelvet képviselik, mint a $ aa $. Ne feledje, hogy a reguláris kifejezés egyszerűsítése hasznos a gyakorlatban.
Vélemény, hozzászólás?