Fony ZH recp 2015 szivános typo lehet, ocs Regexől DFA-t. Erre direkt lgoritmust nem néztünk, olyt tudunk, hogy regexől NFA-t, ztán olyt, hogy NFA-t determinizálni. Nézzük ezeket lépésenként. Thompson lgoritmus: input egy regex, output egy -átmenetes NFA. A generált utomt mindig egy forrás kezdőállpottl és egy nyelő végállpottl fog rendelkezni, ezt rekurziónál felhsználjuk. A rekurzió: Regex -NFA (R 1 R 2 ) (R 1 + R 2 ) (R) Lássuk ezt futni mondjuk z ( + ) regexen: Fony ZH recp 1 2017/04/11/12:36:56
Regex + Thompson -NFA ( + ) ( + ) Az egész ( + ) -r kingyítom z eredményt és eindexelem z állpotokt, mert ezzel fogunk tová dolgozni: q 0 q 1 q 2 q 3 q 4 q 5 Egy X állpot(hlmz) -lezártj (jelen X) z összes olyn állpot hlmz, hov X-ől null, egy vgy tö -átmenettel el lehet jutni. (Mindig X X, mert null dr -lépés megengedett.) Ezt érdemes felírni: q 0 = {q 0, q 1, q 4 }, q 1 = {q 1 }, q 2 = {q 2 }, q 3 = {q 1, q 3, q 4 }, q 4 = {q 4 }, q 5 = {q 5 }. A Thompson-utomtát második lépésen determinisztikussá következőképp tesszük: DFA egy állpot Thompson-utomt állpotink egy hlmz lesz; kezdőállpot q 0 ; H-ól htásár q H q- lehet eljutni, zz vesszük z összes q H állpotot, és uniózzuk z összes olyn p hlmzt, hov q-ól -vl p-e lehet jutni; végállpot lesz minden olyn hlmz, mien vn eredeti végállpot. Pl. z első lépésen {q 0, q 1, q 4 } kezdőállpotól htásár el lehet jutni: q 0 -ól sehov, q 1 -ől q 2 -e és q 3 -, q 4 -ől pedig q 5 -e, z eredmény tehát q 2 q 3 q 5 = {q 2 } {q 1, q 3, q 4 } {q 5 } = {q 1, q 2, q 3, q 4, q 5 } hlmz lesz. H viszont ugynott -t kpunk, onnn se q 0 -ól, se q 1 -ől, se q 4 -ől nem lehet továmenni -vel, így z = hlmzt kpjuk. (Ami egyéként mindig cspdállpot.) A táláztot úgy készítjük, hogy először felvesszük sorfejlécnek z új kezdőállpotot, ztán kiszámoljuk sor celláit, és hányszor olyn hlmzt kpunk, ki nem szerepel még sorfejlécként, felvesszük sorfejlécnek zt is. Elő-utó elfogynk. Célszerű pl. rendezni mindig hlmz elemeit, hogy z ismétlést könnye legyen kiszúrni. Fony ZH recp 2 2017/04/11/12:36:56
A végeredmény most: {q 0, q 1, q 4 } {q 1, q 2, q 3, q 4, q 5 } {q 1, q 2, q 3, q 4, q 5 } {q 1, q 2, q 3, q 4, q 5 } {q 1, q 3, q 4 } {q 1, q 3, q 4 } {q 1, q 2, q 3, q 4, q 5 } és kész is, z egyetlen végállpot {q 1, q 2, q 3, q 4, q 5 } (mert z trtlmzz egyedül q 5 -öt). Aki krj, le is rjzolhtj ezt z utomtát: 014 12345 134, De nem muszáj. Pumpáló lemmás feldtok. A pumpáló lemm: kpunk egy input L nyelvet és egy prméter K-hoz kell djunk olyn w L, w K szót, mit árhogy is vágunk fel w = w 1 w 2 w 3 részre úgy, hogy w 1 w 2 K és w 2, mindig lesz olyn i 0, mire w 1 w i 2w 3 / L. H csk tehetjük, generáljunk olyn w szót, minek z első K etűje ugynz, mondjuk x, mert kkor csk zt kell megnézni, hogy w 2 = x t, 1 t K lkú lehet, kkor w 1 w i 2w 3 úgy néz ki, hogy w elé még ejön (i 1)t dr x, és így könnye sokszor i-t válsztni (áltlán elég z i = 0, i = 2 vlmelyikét megnézni és jó lesz). Gykon mit néztünk: Lássuk e, hogy L = {w {, } : w = w } nem reguláris! Tegyük fel, hogy L reguláris, legyen K lemm szerinti konstns. Legyen w = K K. Akkor w L, w = 2K K. H w = w 1 w 2 w 3 úgy, hogy w 1 w 2 K és w 2, kkor w 2 = t úgy, hogy 1 t K. Akkor i = 2-re w 1 w i 2w 3 = K+t K / L, mi ellentmondás, tehát L nem reguláris. Lássuk e, hogy L = { n2 : n 0} nem reguláris! Tegyük fel, hogy L reguláris, legyen K lemm szerinti konstns. Legyen w = K2. Akkor w L, w = K 2 K. H w = w 1 w 2 w 3 úgy, hogy w 1 w 2 K és w 2, kkor w 2 = t úgy, hogy 1 t K. Akkor i = 2-re w 1 w i 2w 3 = K2 +t, mi nem L-eli, mert K 2 < K 2 + t K 2 + K < K 2 + 2K + 1 = (K + 1) 2, így két szomszédos négyzetszám közé esik. Emitt L nem reguláris. Fony ZH recp 3 2017/04/11/12:36:56
Lássuk e, hogy L = {w {(, )} : w helyes zárójelezés} nem reguláris! Tegyük fel, hogy L reguláris, legyen K lemm szerinti konstns. Legyen w = ( K ) K. Akkor w L, w = 2K K. H w = w 1 w 2 w 3 úgy, hogy w 1 w 2 K és w 2, kkor w 2 = ( t úgy, hogy 1 t K. Akkor i = 2-re w 1 w i 2w 3 = ( K+t ) K / L. Emitt L nem reguláris. Lássuk e, hogy L = { p : p prímszám} nem reguláris! Tegyük fel, hogy L reguláris, legyen K lemm szerinti konstns. Legyen w = P, hol P > K prímszám (ilyen vn, mert végtelen sok prímszám vn). Akkor w L, w = P K. H w = w 1 w 2 w 3 úgy, hogy w 1 w 2 K és w 2, kkor w 2 = t úgy, hogy 1 t K. Akkor i = P + 1-re w 1 w2w i 3 = P +P t / L, mert P + P t = P (t + 1) összetett szám. Emitt L nem reguláris. A töi. Ezeket meg lehet így oldni: { n 2n : n 0} {w {, } : 2 w = w } {w {(, ), [, ]} : w helyes zárójelezés} { n3 : n 0} { 2n : n 0} {w {, } : w w } {w {, } : w < w } {w {, } : w plindrom} Nyelvhez CF nyelvtn készítése tippek. Amit tudunk: { t 1n+c 1 t 2n+c 2 : n 0}-hoz egy nyelvtn S t 1 S t 2 c 1 c 2. Pl. { n n : n 0}- hoz S S, { 2n+1 n : n 0}-hoz S S, st. A másik, mit tudunk, plindromák: S S S. H nyelvünk szvit két független részre tudjuk vágni, kkor tegyük meg, csináljuk meg hozzájuk külön-külön nyelvtnokt, mondjuk A és B nemterminálisól indítv, ztán vegyünk fel egy S AB szályt. Pl: { n m : n < m}-nél ez ugynz, mint { n n d : n 0, d > 0} (és kkor n < n + d = m), itt z n n és d részek közt semmi kpcsolt nincs, elsőhöz nyelvtn A A, másodikhoz B B, z egész meg S AB A A B B. Egy másik nyelvtn ugynerre: S S S. H szvk,,közepéől tudunk kivágni független dolgot, kkor zt vezessük le mondjuk A-ól, és z eredeti nyelvtnn kivágott rész helyére ezt z A-t vezessük le. Pl. { n m c m d n }-nél Fony ZH recp 4 2017/04/11/12:36:56
első m c m rész kiemelhető, A Ac, és ekkor z eredeti S-ől n Ad n lkú stringeket kell levezessünk, mit tudunk: S Sd A A Ac. H nyelvünket két nyelv uniójár tudjuk ontni, kkor csináljuk meg hozzájuk külön-külön nyelvtnokt, mondjuk A és B nemterminálisól indítv, ztán vegyünk fel egy S A B szályt. Pl: { n m : n m}-nél z n m z n < m vgy m < n és kkor S A B Chomsky-normálformár hozás. A A A B B B. Chomsky lk: minden szály A BC vgy A lkú. Kivéve z S szály, ez lehet, de h vn, kkor nem lehet S egy szály jo oldlán se. Minden CF nyelvtnt ilyen lkr lehet hozni. Algoritmus: i) Fke nemterminálisok evezetése: minden Σ-hoz evezetünk egy új X nemterminálist, és egy X szályt; z összes olyn jo oldlon, hol nem egyedül áll, kicseréljük X -r. ii) Hosszú jooldlk tördelése: kettőnél hossz jooldlk suffixei helyett új nemterminálisokt vezetünk e, kettő hosszú jooldlkt létrehozv. Példán keresztül: A X 1 X 2 X 3 X 4 -ől lesz A X 1 [X 2 X 3 X 4 ], [X 2 X 3 X 4 ] X 2 [X 3 X 4 ], [X 3 X 4 ] X 3 X 4. H n hosszú jooldl: A X 1 X 2... X n -ől A X 1 [X 2... X n ], [X i... X n ] X i [X i+1... X n ], [X n 1 X n ] X n 1 X n. iii) -mentesítés: először meghtározzuk z összes olyn nemterminális X hlmzát, kikől lehet -t levezetni. Inicilizálás: X := {A : vn A szály}. Iteráció: X := X {A : vn A α szály vlmilyen α X -r}. (H vlkinek vn csup nullázhtó jelől álló jooldl, kkor őt is evesszük.) H X már nem változik, kkor kész vgyunk. Ezek után,,töröljük z összes X -eli jelet, hányféleképp csk lehet, de jooldlt nem írunk fel, vgyis: z A BC szályok mellé felvesszük A B-t, h C nullázhtó és A C-t, h B nullázhtó; z A B és A szályok nem változnk; z A szályokt töröljük. Ezen kívül, h S nullázhtó, kkor felveszünk egy új S kezdőszimólumot és S S szályokt. iv) Láncszály-mentesítés: Először felírunk egy G gráfot. Csúcsi: nemterminálisok. Élek: A B él, h vn A B szály. Ezek után minden A nemterminális új jo oldl z összes, A-ól G-en elérhető nemterminális jo oldl lesz, kivéve láncszályokt. Fony ZH recp 5 2017/04/11/12:36:56
kész, kpott nyelvtn ekivlens, Chomsky lkú. Péld. Input: S ASA ACB A B BS B AA Akkor i) után: Tördelés: S ASAX ACB X X A X B BSX B AA X X S A[SAX ] A[CB] X X [SAX ] S[AX ] [AX ] AX [CB] CB A X B B[SX ] [SX ] SX B AA X X Nullázhtó: A (A mitt), B (B AA mitt) és h még lenne {A, B} szimólum, z is zzá váln, de nincs. Ezeket elhgyjuk: jooldlú S A[SAX ] [SAX ] A[CB] [CB] X X [SAX ] S[AX ] [AX ] AX X [CB] CB C A X B X B[SX ] [SX ] [SX ] SX B AA A X X Láncszályok: z éleket sorolv S [SAX ], [CB], [AX ] X, [CB] C, A X, [SX ], B A. Akkor S-ől elérhető S, [SAX ], [CB], C, [AX ]-ól [AX ], X, [CB]-ől [CB], C, A-ól A, X, [SX ], B-ől pedig B, A, X, [SX ]. A töi nemterminálisól csk önmguk. Fony ZH recp 6 2017/04/11/12:36:56
Mindenki mellé másoljuk előle elérhetőek nem-láncszály jooldlit: S A[SAX ] A[CB] X X S[AX ] CB [SAX ] S[AX ] [AX ] AX [CB] CB A X B B[SX ] SX [SX ] SX B AA X B B[SX ] SX X X és kész is. (Aki szemfüles, esetleg észreveheti, hogy C nem termináló, tehát törölhettük voln z elején kár.) Veremutomt építés Alpvetően veremutomt egy nemdeterminisztikus számológép, ellátv egy veremmel, minek szokásos pop/push műveleteit tudj lklmzni. A vermet két dologr lehet hsználni igzán: számlálónk (rel-life) eletenni egy szót és nnk megfordítottját ellenőrizni (somewht less rel-life) Vn hol w 1 és vn, hol w R jelzi z,,írd le w szót megfordítv műveletet, itt most w R lesz, tehát pl. c R = c. Kezdem számláló mngementtel. H veremutomtát krunk tervezni, kkor pl. kezdhetünk egy olyn lgoritmussl (nem rögtön veremutomtávl), mi lról jor olvss stringet egy egészértékű számlálót hsznál, más változó nincs, számláló nullár vn inicilizálv számláló lehet pozitív vgy negtív is számlálót lehet konstnssl növelni, csökkenteni vgy nullázni hogy mit csináljon z lgoritmus, z függhet z olvsott etűtől és ttól, hogy számláló értéke null, pozitív vgy negtív meg persze z ktuális progrmsortól, hov lehet gotozni is, kár nemdeterminisztikusn,,egyszer csk átugorv és z lgoritmus kimenete persze egy it lesz, hogy elfogdjuk-e szót (,,jó lkú-e ) vgy sem, elfogdni csk úgy szd, h végig is olvstuk Nézzünk egy példát: hogy z input stringünk n n lkú-e, rr egy számlálós lgoritmus ( számláló c): 1. H -t olvsunk, c:=c+1 és goto 1; nemdet átmehetünk 2-re is 2. H -t olvsunk, c:=c-1 és goto 2; nemdet átmehetünk 3-r is Fony ZH recp 7 2017/04/11/12:36:56
3. H elfogyott z input és c==0, elfogdjuk stringet. Pl. ez z lgoritmus z inputr először növeli számlálót eggyel, mjd még eggyel, hogy olvss e z -kt, ztán z utolsó után egyszer csk,,tudtállpotot vált (átmegy 2. pontr) és onnn kezdve hogy jönnek -k, csökkenti számlálót, és mikor elfogynk -k is, átugrik 3. pontr, ott ellenőrzi, 0-e számláló és mivel nnyi, elfogdj stringet. -re pl. 1 lenne számláló végén, zt nem fogdná el, z -t meg végig se tudj olvsni (mert 2. pontn tud csk -t olvsni, honnn nem tud visszjutni z 1-e, hol tudná z zt követő -t). H sorrend nem számít és z {w {, } : w = w } nyelvre írunk lgoritmust: 1. H -t olvsunk, növeljük c-t és goto 1; h -t, csökkentsük c-t és goto 1; nemdet mehetünk 2-re is 2. H elfogyott z input és c==0, elfogdjuk stringet. H nem egyenlőséget tesztelünk és z {w {, } : w < w } nyelvre írunk lgoritmust, kkor z utolsó lépésen c<0-r kell teszteljünk. H pl. helyes zárójelezéseket krunk felismerni, pl. (()), ()(), (())() jó, )( nem jó: 1. H (-t olvsunk, növeljük c-t és goto 1; h )-t és c>0, kkor csökkentsük c-t és goto 1; nemdet mehetünk 2-re is 2. H elfogyott z input és c==0, elfogdjuk stringet. (Ez mondjuk z üres stringet is elfogdj; h ezt nem krjuk, kkor pl. tehetjük goto 2 részt ) kezelés utánr is, helyes zárójelezések mindenképp csukójelre végződnek.) H pl. lineáris összehsonlítást krunk csinálni, pl. n 2n+1, kkor nem eggyel változttgtjuk számlálónkt: 1. H -t olvsunk, kkor c:=c+2 és goto 1; nemdet mehetünk 2-re is és kkor c:=c+1 2. H -t olvsunk, kkor c:=c-1 és goto 2; nemdet mehetünk 3-r is 3. H elfogyott z input és c==0, elfogdjuk stringet. Pl. z olvsáskor z első után 2, második után 4 lesz számláló értéke, ztán gotozunk 2-re, ekkor 5, és után minden egyes -re csökken számláló, végén épp 0 lesz és elfogdjuk. Persze lehet ezt még cizellálni, pl. { i j c k : i + k = j}-nél z -k és c-k növelik eggyel számlálót, -k meg csökkentik és végén 0-r tesztelünk, st. Hogy lesz eől veremutomt? A veremen trtjuk számlálót, háromféle jelet hsználunk: kezdeten is enne levő Z-t; pozitív értéket jelző +-t; negtív értéket jelző -t Fony ZH recp 8 2017/04/11/12:36:56
mégpedig úgy, hogy verem trtlm Z, h számláló értéke 0, +Z, h 1, + + Z, h 2 st, áltlán + n Z jelzi z n > 0 értéket és n Z n értéket. Nem keverjük +/ jeleket, mindig Z vn verem lján. Ekkor: Egy progrmsoról lesz (k) egy állpot; A számláló növelése eggyel: h verem tetején 0 vgy + vn, kkor tegyünk helyére +0-t vgy ++-t h pedig, kkor zt csk vegyük le. A számláló csökkentése eggyel: h verem tetején 0 vgy vn, kkor tegyünk helyére 0-t vgy -t h pedig +, kkor zt csk vegyük le. A számláló csökkentése konstnssl: tegyünk nnyi eggyel csökkentő állpotot e, mennyivel csökkenteni krunk. Növelésre ugynez. A számláló tesztelése: h Z vn verem tetején, kkor 0, h +, pozitív, h, negtív. Az,,elfogdjuk stringet rész egy végállpot ugrás lesz, nemdet gotozás pedig nem olvs e jelet z inputról. Nézzük meg z előző lgoritmusokt veremutomtár,,implementálv : n n :, Z / +Z, + / ++, /, Z / Z, + /, /, /, Z/ 1 2 3 Tehát: z első állpot míg -t olvsunk, növeli számlálót, mjd ugrik második, mi míg -t olvsunk csökkenti számlálót, ztán ugrunk 3-r és elfogdunk, feltéve, hogy számláló értéke épp 0. Ennél feldtnál persze észre lehet venni, hogy számláló értéke h mínusz csúszik, kkor úgyse fogjuk elfogdni z inputot, és ekkor negtív számokt kezelnünk se kell, h elpusztul menet közen z lgoritmus nem kezelt if mitt, kkor is elutsítj z inputot, olynkor nem j, h nem olvssuk végig:, Z / +Z, + / ++, + /, /, Z/ 1 2 3 Fony ZH recp 9 2017/04/11/12:36:56
és ez is ugynzt nyelvet ismeri fel. {w {, } : w > w }:, Z / +Z, + / ++, /, Z / Z, + /, /, +/ 1 2 Itt ugye z első sor mngeli számlálót, -r növel, -re csökkent, kell hogy legyen negtív is mngelve, és végén h pozitív lett számláló, kkor fogd el. { n 2n+1 : n 0}:, + / ++, Z / +Z, + / ++, / +, Z/ 1 2 3, + / Itt pedig l oldli két állpot együttesen mngeli kettővel növelést (tw mivel itt számláló csk pozitív lehet, egy + helyett + + + és egy Z helyett + + Z etétele is jó lenne, de áltlánosn, h nem tudod, hogy számlálód előjele mi lehet egy dott ponton, ezt külön kell mngelni). Arr kell odfigyelni, hogy ilyenkor csk z első nyíl (mi kifele megy z 1-ől) olvsson e etűt z inputról, töieknek z inputól -t olvsunk, így egy -r tö inc fut le mjd. Eztán 2-e ugráskor még teszünk egy +-t vereme, után minden -re csökkentünk és h végén 0 lesz, kkor jó. Annyit tennék még hozzá, hogy számtudól ez OK, fonyáól z, /X lkú átmenetek helyett, A/XA,, B/XB,... kell megdnunk, mert számtudól megengedett z, hogy verem tetejét meg se nézzük (ezt jelzi ugye vessző utáni ), fonyáól meg mindenképp popnunk kell egy jelet. Tehát mit JFLAP evesz ( verem tetején), zt fonyáól hogy vlid legyen, végig kell iterálnunk z összes lehetséges veremjelen, és mindre ugynúgy switchelni. Hát k így. lehet még egymás ágyzni számlálókt (pl. z n m c m d n nyelvnél), de ott már zt csinálnám, hogy CF nyelvtnt gyártok rá és zt konvertálom utomtár, hogy stringráló lgoritmusokól is (ww R meg ezek). Fony ZH recp 10 2017/04/11/12:36:56