====== Regulární jazyky a jejich modely ====== [[wp>Regular language]] Jazyk je regulární tehdy, pokud existuje konečný automat, který akceptuje **právě** všechna slova z jazyka L. ===== Uzávěrové vlastnosti ===== **Množina uzavřená na operaci** -- Vezmu dva prvky z množiny (přirozená čísla), provedu s nimi operaci (sečtu je) a výsledek bude zase prvek z té samé množiny (zase přirozené číslo) Regulární jazyk je uzavřen na skoro všechny operace, ale musí být konečné. ===== Důkaz, že jazyk je regulární ===== * Pumping lemma -- používá se k dokazování, že daný jazyk NENÍ regulární. ===== Pojmy ===== * **Prázdné slovo** (ε) -- Prázdný řetězec, který ale vyhovuje jazyku (je možné jej vygenerovat/přijmout)! * **Řetězec** -- jakákoli posloupnost terminálních i netereminálních symbolů (znaků) * **Větná forma** -- řetězec, který lze odvodit z počátečního symbolu gramatiky * **Věta** -- větná forma pouze z terminálních symbolů * **Jazyk** -- podmnožina všech řetězců nad abecedou (L ⊆ Σ) ===== Regulární gramatika ===== Regulární jazyk je definován regulární gramatikou. Je to čtveřice:((Jako u každé gramatiky)) * Konečná množina terminálních symbolů (T, abeceda) * Konečná množina neterminálních symbolů (N) * Konečná množina pravidel (P) * Počáteční symbol (S) Příklad: G = ({a, b}, {A, B, C}, P, A)\\ P = { * A -> ε | aB * B -> bC * C -> a } Pravidla musí být ve tvaru "neterminál -> terminál a neterminál" nebo "neterminál -> terminál"! Vyjímkou je počáteční symbol gramatiky, který může být přepsán na prázdné slovo, ale pak se počáteční symbol nesmí vyskytovat na pravé straně pravidla. "Odvození" = použití pravidla (přímé -- jedno pravidlo, v //k// krocích -- //k// pravidel) ===== Konečné automaty ===== [[wp>Finite-state machine]] Je to pětice: * Neprázdná konečná množina stavů (Q) * Konečná vstupní abeceda (T) * Parciální přechodová funkce (δ: Q × T -> Q, je možné ji zadat grafem, tabulkou nebo výčtem) * Počáteční stav (s ∈ Q) * Množina akceptujících stavů (F ⊆ Q) Příklad: A = ({q0, q1, q2}, {a, b}, δ, q0, {q0, q2}) * δ(q0, a) = q2 * δ(q1, b) = q1 * δ(q2, a) = q0 * Deterministický -- nejvíce jeden přechod pod jedním znakem (u každého stavu) * Nedetrministický -- více přechodů pod jedním znakem * S ε-kroky -- je možné nenačítat další symbol, a přejít ze stavu do stavu pod znakem ε Automaty jsou **ekvivalentní** pokud přijímají i zamítají stejná slova. Může skončit třemi stavy: - Po přečtení slova skončíme v některém z koncových (akceptujících) stavů -- v takovém případě je slovo přijato. - Po přečtení slova skončíme v jiném než koncovém stavu -- slovo je zamítnuto. - Nedočteme slovo (někde uprostřed slova se dostaneme do stavu, kdy nejsme schopni zpracovat další znak protože neexistuje pro ten znak přechod) -- slovo je zamítnuto. ==== Determinizace ==== * Pokud má nedeterministický konečný automat //n// stavů, bude jeho deterministická varianta mít nejvíce 2//n// stavů. * Každý nedeterministický konečný automat má svoji deterministickou variantu. * Deterministický konečný automat nemusí být minimální (a většinou ani není). === Příklad === {{determinizace_in.png}} - Dostaneme zadaný graf, nebo rovnou tabulku. * Graf přepíšeme do tabulky. ^ ^ //a// ^ //b// ^ | →1 | ∅ | {2, 3} | | 2 | {1, 6} | {7} | | 3 | ∅ | {4, 5, 7} | | ←4 | {6} | {2, 8} | | 5 | {1} | ∅ | | 6 | {6} | ∅ | | 7 | ∅ | {8} | | ←8 | {1} | {4, 5} | Teď opíšeme první řadek. ^ ^ //a// ^ //b// ^ | →1 | ∅ | {2, 3} | V něm je stav {2, 3}, připíšeme ho tedy do tabulky. Pak se podíváme do první tabulky, do jakých stavů se můžeme ze stavů 2 a 3 dostat, pokud příjmeme //a// nebo //b//. ^ ^ //a// ^ //b// ^ | →1 | ∅ | {2, 3} | | {2, 3} | {1, 6} | {4, 5, 7} | Teď nám tu přibyly 2 nové stavy ({1, 6} a {4, 5, 7}), uděláme tedy opět to samé co v minulém kroku. Tohle budeme opakovat neustále dokola, dokud nebudeme mít všechny stavy. Pokud je v tom novém stavu nějký stav který byl koncovým (např. 4 v {4, 5, 7}), bude i ten nový stav koncovým. ^ ^ //a// ^ //b// ^ | →{1} | ∅ | {2, 3} | | {2, 3} | {1, 6} | {4, 5, 7} | | {1, 6} | {6} | {2, 3} | | ←{4, 5, 7} | {1, 6} | {2, 8} | | {6} | {6} | ∅ | | ←{2, 8} | {1, 6} | {4, 5, 7} | {{determinizace_out.png}} ===== Regulární výrazy ===== [[wp>Regular expression]] Některé symboly tu fungují jinak než POSIX regexpy! * **a . b** -- konkatenace / zřetězení (jako v PHP) * **a + b** -- nebo, OR * **a***, **a+** -- iterace (zřetězení) * L((L je jazyk))(ε) = {ε} * L(∅) = ∅ * L(a) = {a} * L(E . F) = L(E) . L(F) * L(E + F) = L(E) ∪ L(F) * L(E*) = L(E)* ==== Převod regulárního výrazu na konečný automat ==== Nejdřív uděláme počáteční a koncový stav a mezi ně na přechod napíšeme regexp. Ten pak postupně (směrem zvenku dovnitř) rozgenerováváme podle následujících pravidel dokud není na každé hraně právě jeden symbol. ^ Vstup ^ Výstup ^ | {{regexp_or_in.png|a + b}} | {{regexp_or_out.png|a + b}} | | {{regexp_cat_in.png|a . b}} | {{regexp_cat_out.png|a . b}} | | {{regexp_iter_in.png|a*}} | {{regexp_iter_out.png|a*}} | === Příklad === **b ((aab* + aaaa) b)* a** {{re2ko_1.png|Rozgenerujeme okrajové konkatenace}}\\ {{re2ko_2.png|Iterace závorky}}\\ {{re2ko_3.png|Konkatenace (je v iteraci!)}}\\ {{re2ko_4.png|OR}}\\ {{re2ko_5.png|Konkatenace áček}}\\ {{re2ko_6.png|Recyklujeme první dvě áčka a přidáme iteraci béčka}} ==== Převod konečného automatu na regulární výraz ==== - Automat "obalíme" novým počátečním a koncovým stavem na které přes ε přechody navážeme ty staré. - Pak postupně škrtáme uzly grafu a nahrazujeme je hranami, podle dříve uvedených pravidel, ale v opačném pořadí. - Opakujeme krok 2 dokud nedostaneme jen počáteční a koncový stav s jednou hranou která představuje regulární výraz. === Příklad === Převedeme minule vytvořený konečný automat zpět na regulární výraz. {{ko2re_1.png|Obalíme do nových počátečních a koncových stavů}}\\ {{ko2re_2.png|Sloučíme áčka a iteraci}}\\ {{ko2re_3.png|Odtraníme uzel 6 (OR)}}\\ {{ko2re_4.png|Odtraníme uzel 4 (zřetězení)}}\\ {{ko2re_5.png|Odtraníme uzel 3 (iterace)}}\\ {{ko2re_6.png|Odtraníme uzly 1 a 2 (zřetězení)}} Ještě bysme mohli odstranit ε přechody 8-) ===== Shrnutí ===== * regulární jazyk: formální jazyk, generován regulární gramatikou, existuje konečný automat, který přijme právě všechna slova z jazyka * dva modely: konečný automat, regulární výraz * jeden lze převést na druhý * regulární gramatika: čtveřice (viz výše), pravidla: neterminál -> terminál a neterminál, možno vypustit druhý neterminál, odvození * konečný automat: pětice (viz výše), determinismus, ekvivalence, umět nakreslit a převést na reg. výraz * regulární výraz: jiný model regulárního jazyka, lze převést na konečný automat, konkatenace ., zřetězení (+ vs *), "nebo" +, umět napsat a převést * lze použít pumping lemmu na dokázání, že jazyk není regulární