diff --git a/01-regular/regular.tex b/01-regular/regular.tex index 867155f2420eb306e54eac44891ceeb4d653ae52..3e76794285b025c521182f8b2dc3064b8143d85e 100644 --- a/01-regular/regular.tex +++ b/01-regular/regular.tex @@ -250,6 +250,30 @@ jak automatem~$A_1$, tak~$A_2$. Proto $L(A) = L(A_1) \cap L(A_2)$. Průnik dvou regulárních jazyků je zase regulární jazyk. } +\subsectionstar{Automaty s~výstupem} + +Automat může místo rozpoznávání jazyka produkovat výstup. +To můžeme definovat například následovně: + +\defn{\em{Mooreův stroj} +je uspořádaná pětice $(Q,\Sigma,\Delta,\delta,q_0,G)$, kde: +\list{o} +\:$Q$ je konečná neprázdná \em{množina stavů,} +\:$\Sigma$ je konečná neprázdná \em{vstupní abeceda,} +\:$\Delta$ je konečná neprázdná \em{výstupní abeceda,} +\:$\delta: Q\times \Sigma \rightarrow Q$ je \em{přechodová funkce,} +\:$q_0\in Q$ je \em{počáteční stav,} +\:$G: Q\rightarrow \Delta$ je \em{výstupní funkce.} +\endlist +} + +\defn{ +Výpočet stroje nad vstupem $\alpha\in\Sigma^*$ délky~$n$ definujeme opět jako +posloupnost stavů $s_0,s_1,\ldots,s_n$, kde $s_i = \delta^*(q_0,\alpha[{}:i]$). +\em{Výstup stroje} je pak řetězec $G(s_1)\ldots G(s_n)$. +Stroj tedy počítá nějakou funkci ze~$\Sigma^n$ do~$\Delta^n$. +} + \exercises \excmt{ @@ -314,6 +338,23 @@ kde~$S$ je počet stavů KMP.} \ex{Dokažte, že iterační lemma není ekvivalence: najděte neregulární jazyk~$L$, který \uv{jde pumpovat}.} +\exx{Sestrojte Mooreův stroj na sčítání binárních čísel $x_n\ldots x_0$ +a $y_n\ldots y_0$. Stroj na vstupu dostane posloupnost dvojic bitů $(x_0,y_0) +\ldots (x_n,y_n)$ od nejnižšího řádu k~nejvyššímu, na výstupu vydá bity součtu +v~tomtéž pořadí.} + +\exx{Jiný způsob, jak automatem produkovat výstup, dává \em{Mealyho stroj.} +Ten tvoří výstup přechodovou funkcí $\delta: Q\times\Sigma \rightarrow Q\times\Delta$, +která každé dvojici stavu a znaku se vstupu přiřadí nový stav a znak k~vypsání +na výstup. Ukažte, že Mealyho stroje umí počítat tytéž funkce jako Mooreovy stroje. +} + +\exx{Podobně jako u~\cc{NP}-úplnosti můžeme i zde jazyky porovnávat vhodnými redukcemi. +Jazyk $K$ se dá regulárně převést na jazyk~$L$ ($K\rightarrow_R L$), pokud existuje funkce~$f$ spočítatelná +Mooreovým strojem taková, že platí $\alpha\in K$ právě tehdy, když $f(\alpha)\in L$. +Dokažte, že pokud $K\rightarrow_R L$ a $L$ je regulární, pak $K$ je regulární. +} + \endexercises \section{Nedeterministické automaty} @@ -1024,6 +1065,9 @@ Algoritmus tedy doběhne v~čase $\Theta(S^2A)$. \ex{Funguje myšlenka ekvivalence stavů a faktorizace automatu i pro nedeterministické automaty?} +\exx{Rozšiřte ekvivalenci stavů a faktorizaci automatů na automaty s~výstupem +(Mooreovy stroje).} + \endexercises \sectionstar{Kanonické automaty} diff --git a/03-recursive/recursive.tex b/03-recursive/recursive.tex index fc94970d9d00035083413e57c782fbef3a2e8f26..d3dd2f7a5b8eaad5101a2eb6bd9b47f2ab3e5728 100644 --- a/03-recursive/recursive.tex +++ b/03-recursive/recursive.tex @@ -176,9 +176,12 @@ Na rozdíl od konečných automatů mohou být různé TM pro tentýž vstup roz \em{Prostor výpočtu} je počet políček pásky, která během výpočtu navštívila hlava stroje. } -\defn{\em{Časová složitost} stroje je funkce, která každé délce vstupu~$n$ přiřadí -maximální čas výpočtu pro vstupy z~$\Sigma^n$. Podobně prostorová složitost -přiřadí délce vstupu maximální prostor výpočtu. Pokud se některý výpočet +\defn{\em{Časová složitost} stroje je funkce, která každému přirozenému čísl~$u$ +přiřadí maximální čas výpočtu pro vstupy délky nejvýše~$n$.\foot{Často se složitost +definuje přes vstupy délky \em{právě~$n$.} Naše definice má tu výhodu, že vždy dává +neklesající funkce, se kterými se zachází snáz.} +Podobně prostorová složitost přiřadí délce vstupu maximální prostor výpočtu. +Pokud se některý výpočet nezastaví, časová složitost bude nekonečná a prostorová možná také.} \examplen{proměnné ve stavu}{Často se hodí, aby si stroj pamatoval několik @@ -867,10 +870,11 @@ Turingova stroje, který je rozhoduje: \defn{Nechť $f$ je funkce z~$\N$ do~$\N$. Potom: \list{o} \:$L\in\cc{TIME}(f)$ právě tehdy, když je rozhodován Turingovým strojem, který se pro -vstup délky~$n$ zastaví za $\O(f(n))$ kroků. +vstup délky nejvýše~$n$ zastaví za $\O(f(n))$ kroků. \:$L\in\cc{SPACE}(f)$ právě tehdy, když je rozhodován Turingovým strojem, který pro -vstup délky~$n$ spotřebuje prostor $\O(f(n))$. -\:$\cc{NTIME}(f)$ a $\cc{NSPACE}(f)$ jsou definovány analogicky přes nedeterministické stroje. +vstup délky nejvýše~$n$ spotřebuje prostor $\O(f(n))$. +\:$\cc{NTIME}(f)$ a $\cc{NSPACE}(f)$ jsou definovány analogicky přes nedeterministické stroje.\foot{Někdy se používá \cc{DTIME} a \cc{DSPACE} místo \cc{TIME} a \cc{SPACE}, +abychom zdůraznili determinismus.} \:$\cc{P}$ je sjednocení tříd $\cc{TIME}(n^k)$ přes všechna $k\ge 0$. \:$\cc{NP}$ je sjednocení tříd $\cc{NTIME}(n^k)$ přes všechna $k\ge 0$. \endlist @@ -904,89 +908,90 @@ Nyní dokážeme, že to vyjde nastejno -- každý jazyk přijímaný obousměrn \theorem{Obousměrné konečné automaty přijímají právě regulární jazyky.} \proof -Připomeňme definici TFA: je to Turingův stroj, který dostane vstup $\|<|\alpha\|>|$ +Připomeňme definici TFA: je to jednopáskový Turingův stroj, který dostane vstup $\|<|\alpha\|>|$ a nemá ho povoleno měnit. Navíc na levé zarážce~$\|<|$ nesmí vykonat pohyb doleva -a na pravé zarážce~$\|>|$ nesmí jít doprava. Aby byl TFA podobnější konečným automatům, -výpočet začíná s~hlavou na prvním znaku slova~$\alpha$. To je ale detail: TFA můžeme snadno upravit, -aby výpočet začínal na~$\|<|$ -- stačí přidat nový počáteční stav, v~němž provedeme jeden pohyb -hlavou doprava a přejdeme do původního počátečního stavu. +a na pravé zarážce~$\|>|$ nesmí jít doprava. Každý regulární jazyk je určitě přijímán nějakým TFA, který vznikne přímočarým překladem příslušného DFA. Opačná implikace je méně triviální. Uvažme TFA rozpoznávající nějaký jazyk~$L$ a jeho výpočet nad nějakým vstupem~$\alpha$ délky~$n$. Do vstupu ještě doplníme zarážky $\alpha[-1] = \|<|$ a $\alpha[n] = \|>|$. -Potřebujeme se nějak vyrovnat s~tím, že automat se může během výpočtu na jedno -políčko vracet opakovaně. Představme si, že se díváme dovnitř výpočtu, hlava zrovna stojí -na $i$-tém políčku slova~$\alpha$, stroj se právě přepíná ze stavu~$s$ do~$s'$ a chystá se -odejít doprava do nějakého suffixu $\alpha[i+1:{}]$. -Jak bude výpočet pokračovat? Jedna možnost je, že se stroj po čase vrátí zprava na $i$-té políčko v~nějakém novém stavu, -přičemž nic kromě stavu stroje se nezměnilo (na pásku nemůžeme zapisovat). -Nebo se předtím stroj stihl zastavit a přijmout/odmítnout. -Případně se stroj zacyklil v~nekonečné smyčce, což rovněž odpovídá odmítnutí vstupu. - -Z~této úvahy plyne, že kdybychom znali chování stroje na suffixu $\alpha[i+1:{}]$ -(jakému vstupnímu stavu odpovídá jaký výstupní), mohli bychom pomocí něj určit, -co bude stroj dělat na políčku~$\alpha[i]$, aniž bychom se dívali na následující -znaky. Z~toho bychom mohli určit chování na suffixu $\alpha[i:{}]$ a tak dále. -Zkusme to provést. - -Chování stroje na suffixu vstupu $\alpha[i:{}]$ popíšeme nějakou funkcí~$f_i(s)$. -Ta dostane počáteční stav~$s\in Q\setminus\{q_+, q_-\}$, v~němž stroj vstoupí -na $\alpha[i]$. Výsledkem funkce je koncový stav~$s'\in Q$, v~němž stroj odchází -ze suffixu doleva. Pokud je $s'=q_+$, stroj se místo odejití doleva zastavil a přijal. -Pokud $s'=q_-$, stroj odmítl zastavením nebo zacyklením se. - -Ukážeme, jak sestrojit funkci~$f_i$, pokud už známe~$f_{i+1}$. -Chceme-li stanovit $f(s)$, budeme konstruovat posloupnost stavů $s_0$, $s_1$, $s_2$, \dots{} +Představme si výpočet obousměrného automatu, který právě navštívil znak~$\alpha[i]$. +Pokud se automat pohne doprava, můžeme tento krok provést i~konečným automatem. +Pokud vyčkává na místě, jenom mění stavy, takže DFA může celou posloupnost změn provést +najednou. + +Problém nastane, pokud se TFA pohybem doleva vrátí do prefixu $\alpha[{}:i]$, +který už jednou zpracoval. Uvnitř prefixu se může libovolně dlouho toulat, než nastane +jedna ze tří možností: buď prefix opustí doprava v~nějakém novém stavu a~je opět +na znaku~$\alpha[i]$. Anebo se zastaví ve stavu $q_+$ či~$q_-$, případně se zacyklí +(tím také odmítne vstup, takže je to ekvivalentní se zastavením v~$q_-$). + +Jelikož TFA nemůže měnit obsah pásky, můžeme jeho chování v~prefixu $\alpha[{}:i]$ +jednoznačně popsat nějakou funkcí $f_i: Q\setminus\{q_+, q_-\} \rightarrow Q$. +Ta jako argument dostane stav~$s$, ve kterém stroj začíná na posledním znaku prefixu, tedy +$\alpha[i-1]$. Výsledkem funkce je stav~$s'$, v~němž stroj prefix opustí pohybem vpravo. +Pokud je $s'=q_+$, stroj z~prefixu neodešel, nýbrž se zastavil a přijal. +Je-li $s'=q_-$, stroj odmítl zastavením nebo zacyklením se. + +Budeme se snažit sestrojit DFA, který si bude ve stavu udržovat chování prefixu~$f_i$ +nalevo od aktuální pozice. + +Začněme tou nejzajímavější částí: konstrukcí~$f_{i+1}$ z~$f_i$. +Nechť chceme spočítat $f_{i+1}(s)$. TFA tedy stojí na políčku $\alpha[i]$ ve stavu~$s$. +Jelikož se na toto políčko může vracet, budeme konstruovat posloupnost stavů $s_0$, $s_1$, $s_2$, \dots{} při jednotlivých návštěvách políčka $\alpha[i]$. Na počátku položíme $s_0=s$. Nyní budeme z~libovolného~$s_j$ počítat $s_{j+1}$. Podíváme se, co stroj provede, přečte-li ve stavu~$s_j$ znak~$\alpha[i]$. -Vyhodnotíme tedy přechodovou funkci $\delta(s_j, \alpha[i])$, čímž získáme instrukci, která +Vyhodnocením přechodové funkce $\delta(s_j, \alpha[i])$ získáme instrukci, která přechází do nějakého stavu~$s'_j$, zapisuje nezměněný znak~$\alpha[i]$ a možná pohybuje hlavou: \list{o} -\:Pokud hlava odchází doleva, položíme $f_i(s) = s'_j$ a jsme hotovi. +\:Pokud hlava odchází doprava, položíme $f_{i+1}(s) = s'_j$ a jsme hotovi. \:Pokud hlava zůstává na místě, položíme $s_{j+1} = s'_j$ a pokračujeme ve vytváření posloupnosti -s~několika výjimkami: Je-li $s'_j$ rovno $q_+$ nebo~$q_-$, položíme $f_i(s) = s'_j$ a skončíme. +s~několika výjimkami: Je-li $s'_j$ rovno $q_+$ nebo~$q_-$, položíme $f_{i+1}(s) = s'_j$ a skončíme. Je-li $s'_j$ rovno některému z~předešlých~$s_k$ pro $k\le j$, stroj se zacyklil, takže položíme -$f_i(s) = q_-$ a skončíme. -\:Pokud hlava odchází doprava, využijeme známou funkci $f_{i+1}$ popisující chování na suffixu -$\alpha[i+1:{}]$, takže položíme $s_{j+1} = f_{i+1}(s'_j)$. Opět ošetříme případy, kdy je tento +$f_{i+1}(s) = q_-$ a skončíme. +\:Pokud hlava odchází doleva, využijeme známou funkci $f_i$ popisující chování na prefixu +$\alpha[{}:i-1]$. Stačí položit $s_{j+1} = f_i(s'_j)$. Opět ošetříme případy, kdy je tento stav roven $q_+$, $q_-$, případně některému z~předchozích stavů v~posloupnosti. \endlist -Všimněte si, že funkce~$f_i$ je jednoznačně určena funkcí~$f_{i+1}$ a znakem $\alpha[i]$. -To nám dává návod na sestrojení konečného automatu, který bude procházet vstupem zprava doleva -a postupně přepočítávat funkci~$f_i$. Stavy automatu odpovídají všem funkcím z~$Q\setminus\{q_+,q_-\}$ do~$Q$, -takže jich je konečně mnoho. +Všimněme si, že funkce~$f_{i+1}$ je jednoznačně určena funkcí~$f_i$ a znakem $\alpha[i]$. +Můžeme tedy sestrojit konečný automat, který bude procházet vstupem zleva doprava +a postupně přepočítávat funkci~$f_i$. Stavy automatu odpovídají všem funkcím z~$Q\setminus\{q_+,q_-\}$ do~$Q$ +a~těch je konečně mnoho. Přechody jsou dány konstrukcí~$f_{i+1}$ z~$f_i$. +Po zpracování znaku $\alpha[i]$ se tedy automat nachází ve stavu~$f_{i+1}$. -Zbývá dořešit, jak automat začne a jak skončí. +Ještě je potřeba domyslet, jak automat začne. +Zkusme použít naši konstrukci pro funkci~$f_0$ -- chování TFA na prázdném prefixu. +Hlava TFA tedy stojí na levé zarážce~$\|<|$, odkud se nesmí pohnout doleva. +Konstrukce se proto nikdy nezeptá na neexistující~$f_{-1}$. +Funkce~$f_0$ je tudíž nezávislá na vstupu a může posloužit jako počáteční stav automatu. -Použijeme-li naši konstrukci pro funkci~$f_n$, tedy chování výpočtu na pravé zarážce~\|>|, -nikdy se nezeptá na neexistující~$f_{n+1}$. To proto, že stroj se na pravé zarážce nemůže -pohybovat doprava. Funkce~$f_n$ je tedy nezávislá na vstupu, takže může posloužit jako -počáteční stav automatu. +Máme tedy automat, který po přečtení vstupu $\alpha\|>|$ zná funkci~$f_{n+1}$ -- +chování na celém vstupu, stojíme-li na pravé zarážce~$\|>|$. -Až automat přečte levou zarážku~$\|<|$, bude jeho stav roven funkci~$f_{-1}$. -Ta popisuje chování na celém vstupu. Takže do ní chceme dosadit počáteční stav~$q_0$ -původního TFA. -Je-li $f_{-1}(q_0)$ rovno~$q_+$, vstup přijmeme. -Pokud je rovno~$q_-$, tak odmítneme. -Nic jiného nemůže funkce vrátit, protože by to znamenalo, že automat z~\|<| odešel doleva, a~to nesmí. -Přijímací stavy tedy odpovídají těm funkcím~$f$, pro něž je $f(q_0)=q_+$. +Teď se nabízí do této funkce dosadit počáteční stav TFA~$q_0$, a~tím zjistit, +jaký výsledek TFA vydá. To ale nemůžeme provést: hlava TFA začíná na levém +okraji vstupu, nikoliv na~$\|>|$. Pomoc je naštěstí snadná: TFA upravíme, aby +začínal na~$\|>|$ v~nějakém novém stavu~$q'_0$. V~něm půjde doleva, dokud nenarazí +na~$\|<|$, načež udělá krok doprava a přepne se do původního počátečního stavu~$q_0$. -Tím jsme sestrojili automat dosvědčující regularitu. Ovšem ne původního jazyka~$L$, -nýbrž jazyka $L' = L\rev\cdot\{\|<|\}$, v~němž jsou slova pozpátku a ukončená zarážkou. +Je-li tedy $f_{n+1}(q'_0)$ rovno~$q_+$, TFA vstup přijal, takže DFA přijme také. +Podobně je-li rovno~$q_-$, tak odmítne. +Nic jiného nemůže funkce vrátit, protože by to znamenalo, že automat z~\|>| odešel doprava, a~to nesmí. +Přijímací stavy tedy odpovídají těm funkcím~$f$, pro něž je $f(q'_0)=q_+$. -Teď si stačí uvědomit, že z~regularity~$L'$ plyne regularita~$L\rev$ a z~ní zase regularita~$L$. -Regularitu $L\rev$ můžeme zdůvodnit cvičením \exref{quotex}, protože $L\rev$ je kvocient $L' / \{\|<|\}$. +Tím jsme sestrojili automat dosvědčující regularitu. Ovšem ne původního jazyka~$L$, +nýbrž jazyka $L' = L\cdot\{\|>|\}$, v~němž jsou slova ukončená zarážkou. +Uvědomíme si, že z~regularity~$L'$ plyne regularita~$L$. +To můžeme zdůvodnit cvičením \exref{quotex}, protože $L$ je kvocient $L' / \{\|>|\}$. Nebo to lze provést přímo úpravou koncových stavů: za koncové prohlásíme ty stavy, z~nichž vede přechod -před znak~$\|<|$ do některého z~původních koncových stavů. -Regularitu~$L$ dostaneme z~uzavřenosti regulárních jazyků na otočení (cvičení \exref{regrev}). - +přes znak~$\|>|$ do některého z~původních koncových stavů. \qed \exercises @@ -997,6 +1002,11 @@ jazykům rozpoznatelným TFA, tedy regulárním. Nezapomeňte na pracovní pásk \ex{Rozšiřte definici TFA o~nedeterminismus. Dokažte, že nedeterministické TFA také rozpoznávají pouze regulární jazyky. Z~toho plyne, že $\cc{NSPACE}(c) = \cc{SPACE}(c) = \Ell_3$.} +\ex{Pokud jednopáskovému Turingovu stroji omezíme pracovní prostor zarážkami kolem +vstupu, ale nezakážeme mu vstup přepisovat, získáme tzv. \em{lineárně omezený automat.} +Dokažte, že jazyky rozpoznávané lineárně omezenými automaty tvoří třídu +$\cc{SPACE}(n)$. Nezapomeňte na $\O$ v~definici složitostních tříd.} + \endexercises \endchapter diff --git a/TODO b/TODO index f7f1bd417aead046a9295745c8035d9c980257ef..a5dfb9285070a25eda3bf725710a1b3583f90d2c 100644 --- a/TODO +++ b/TODO @@ -1,7 +1,5 @@ Regulární: -- Automaty s výstupem -> cvičení - ... pak by se dala definovat regulární redukce mezi jazyky - obrázek ke kongruencím: automat, automatová kongruence, syntaktická kongruence - cvičení na redukci automatů @@ -9,9 +7,7 @@ Bezkontextové: Rekurzivní: -- TIME se také někdy značí DTIME -- uvážit definici složitosti pro vstupy délky _nejvýše_ n -- cvičení na kompresi pásky => SPACE(n) je totéž jako in-place stroj +- nerozhodnutelnost generování všech slov pomocí CFG (cvičení?) Rozšíření: