# Theory of Computation Chapter 3, 4 - Regular Language (請搭配達叔的投影片一起服用) **正規語言 (Regular Language)**, 又稱**正則語言**,是滿足下述相互等價的一組條件的一類形式語言: * 可以被**確定有限狀態自動機 (DFA)** 辨識 * 可以被**非確定有限狀態自動機 (NFA)** 辨識 * 可以用**正規表示式 (Regular Expression)** 描述 * 可以用**正規文法 (Regular Grammar)** 生成 (以上摘自[正規語言 - 維基百科](https://zh.wikipedia.org/wiki/%E6%AD%A3%E5%88%99%E8%AF%AD%E8%A8%80)) ## Regular Expression ### 如何描述一個語言 * 如果是有限集的語言,可以用窮舉法,如 $L = \{a, aa, aba, aca\}$ * 無窮集的語言,則可以用描述法,如 $L = \{x \mid n_a(x) = n_b(x)\}$ * 由於語言是一個集合,因此將多個語言用集合運算子進行運算後的結果也是一個語言,如 $L = \{aa, ab\}^* \cup \{b\}\{bb\}^*$ ### 正規表達式 (Regular Expression) * 是一種基於集合運算子進行擴充的語言描述方法 * 基本定義如下,給定一個字母表 $\Sigma$ * $\emptyset$, $\lambda$, 和 $a \in \Sigma$ 皆為描述這個語言的**原生正規表達式 (primitive regular expressions)** * 如果 $r_1$ 和 $r_2$ 皆為正規表達式,則以下算式也都會是正規表達式 * $r_1 + r_2$ * $r_1 \cdot r_2$ ($\cdot$ 可省略) * $r_1^*$ * $(r_1)$ * 一串字串是一個正規表達式,若且唯若該字串可以由有限個原生表達式和上述的運算子組成 * 舉例 $r = (a + b \cdot c)^*$, 用來描述 $L = \{\{a\} \cup \{bc\}\}^*$ * 因此 $L(r) = \{\lambda , a, bc, aa, abc, bca, ...\}$ * 要注意的事 * 正規表達式並不是一種語言,而是一個描述語言的工具 * 對於一個語言 $L$, 我們不能說 $L = (a + b + c)^*$, 但可以說這個 $L$ 能夠用 $(a + b + c)^*$ 描述 ## Connection Between REs and Regular Languages ### 正規表達式描述的語言 * 對於所有的原生正規表達式,他們所接受的語言定義為 * $L(\emptyset) = \emptyset$ * $L(\lambda) = \{\lambda\}$ * $L(a) = \{a\}$ * 對於正規表達式 $r_1$ 和 $r_2$, 他們之間的運算子規則定義為 * $L(r_1 + r_2) = L(r_1) \cup L(r_2)$ * $L(r_1 \cdot r_2) = L(r_1)L(r_2)$ * $L(r_1^*) = (L(r_1))^*$ * $L((r_1)) = L(r_1)$ * 以上運算子之間的優先度, $()$ > $^*$ > $\cdot$ > $+$ * 給定兩個正規表達式 $r_1$ 和 $r_2$, 如果 $L(r_1) = L(r_2)$, 則我們說 $r_1$ 和 $r_2$ 是等價的 ### 克萊尼定理 (Kleene Theorem) * 正規表達式可以描述的語言集合,就是正規語言 * **克萊尼定理 (Kleene Theorem)**: 由於正規表達式和有限自動機所能夠描述 / 接受的語言集合是一樣的,因此可以說**正規表達式等價於有限自動機** * 對於每一個正規語言,都存在一條正規表達式可以描述他;對於每一個正規表達式,都存在其可以描述的一個正規語言 * 透過證明「正規表達式可描述的語言等同於正規語言」,可以證明克來尼定理 ![原生正規表達式可以很簡單的畫出對應的NFA](https://i.imgur.com/iiY6ydX.png) > Figure 1. 原生正規表達式可以很簡單的畫出對應的NFA > ![$+$ 運算子的NFA](https://i.imgur.com/8pLf8fM.png) > Figure 2. $+$ 運算子的 NFA > ![$\cdot$ 運算子的 NFA](https://i.imgur.com/AK7smMt.png) > Figure 3. $\cdot$ 運算子的 NFA > ![$^*$ 運算子的 NFA](https://i.imgur.com/4qiS7YK.png) > Figure 4. $^*$ 運算子的 NFA * 證明「正規表達式可描述的語言 $\subseteq$ 正規語言」 * 如果針對每一個正規表達式所描述的語言,我們都能夠建立一個可以接受該語言的有限自動機的話,就能證明正規表達式所描述的語言包含於正規語言 * 對於原生正規表達式,其描述的語言可以簡單的畫出 Fig. 1 中的 NFA * 對於正規表達式當中所有的運算子,他們的規則都可以用 Fig. 2-4 的 NFA 表達( $()$ 運算子不用 NFA 也可以得知) * 透過這些 NFA, 我們可以將正規表達式當中的每一個運算都畫出來,並且組合在一起,得到最後只有一個終止狀態的 NFA * 由於所有的正規表達式都可以做這樣的轉換(所有的正規表達式都有一個對應的 NFA),所以正規表達式可以描述的語言包含於正規語言 * 同時我們也得知,在這些運算子之下,正規語言會形成一個[閉包 (Closure)](https://zh.wikipedia.org/zh-tw/%E9%97%AD%E5%8C%85_(%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A7%91%E5%AD%A6)) ![這張圖的正規表達式為 $r = r1^*r2(r4 + r3r1^*r2)^*$](https://i.imgur.com/cnJm1IN.png) > Figure 5. 這張圖的正規表達式為 $r = r1^*r2(r4 + r3r1^*r2)^*$ * 證明「正規語言 $\subseteq$ 正規表達式可描述的語言」 * 泛化狀態轉移圖 (Generalized Transition Graphs, GTG), 是一個狀態轉移圖,其每一個有向邊都是一條正規表達式 * 每一個 NFA 都可以透過合併轉移函式和合併狀態的方式轉換成一個 GTG。 當一個 NFA 被化簡為只有起始狀態和終止狀態的 GTG 後,就可以簡單的得到與該 NFA 等價的正規表達式 * 值得注意的是,當我們要將 NFA 轉換成 Complete GTG (所有的邊都填上的 GTG) 時 * 由於 NFA 允許轉移函式的輸出為空集合,因此在轉換成 GTG 時需要補上一個 $\emptyset$ 的自環,而我們額外定義 $\emptyset^* = \lambda$ * 由於 NFA 原本的轉移函式中,可能會有一個狀態無法走到另一個狀態,在無法連通的狀態之間,也需要補上 $\emptyset$ 的路徑,而我們額外定義 $r + \emptyset = r$, $r \cdot \emptyset = \emptyset$ * 由於每一個 NFA 都可以透過 GTG 轉換得到一條對應的正規表達式,因此正規語言包含於正規表達式可以接受的語言 * 由於兩個集合互相包含對方,證明兩個集合相等,所以正規語言等於正規表達式可描述的語言 ## Regular Grammars ### 形式文法(Grammars) * 可以表示為一個四元組 $(V, T, S, P)$ * $V$ 是**非終結符號 / 變數 (variables)** 的有限集 * $T$ 是**終止符號 (terminals)** 的有限集 * $S$ 是**起始符號 (start variable)**, $S \in V$ * $P$ 是**產生式規則 (production rules)** 的有限集 * 給定一個形式文法 $G$, 根據以上定義,其可以產生的語言為 $L(G) = \{w \in T^* : S \Rightarrow w \}$ * 如果 $w \in L(G)$, 則序列 $S \Rightarrow w_1 \Rightarrow w_2 \Rightarrow ... \Rightarrow w_n \Rightarrow w$ 為 $w$ 的**推導 (derivation)** * 其中 $S, w_1, w_2, ... w_n$ (在代換的途中還有變數沒被換掉的狀態)稱為**句型 (sentential form)** * 線性文法 (Linear Grammar) 為形式文法的子集,其所有的產生是規則的右手邊最多只包含一個變數 * **右線性文法 (Right-Linear Grammar)**, 為線性文法當中,所有規則右手邊中唯一的變數都在最右邊的文法 * **左線性文法 (Left-Linear Grammar)**, 為線性文法當中,所有規則右手邊中唯一的變數都在最左邊的文法 * 左線性文法和右線性文法都屬於**正規文法 (Regular Grammar)** ### 正規文法與正規語言 * 正規文法產生的語言集合,就是正規語言 * 證明「正規文法可產生的語言 $\subseteq$ 正規語言」 * 如果是右線性文法,可以透過以下映射將文法轉換成有限自動機 * 將每一個變數都視為狀態,起始符號視為起始狀態,終止符號視為終止狀態 * 將每一條產生式規則都視為是一個轉移函式,如 $A \rightarrow aB$ 可以視為 $\delta (A, a) = B$ * 從起始符號開始,將所有的產生式規則都視為轉移函式畫為狀態機,直到連接終止符號為止 * 得到一個等價於該文法的 NFA * 如果是左線性文法,則透過以下映射 * 將每一個變數都視為狀態,起始符號視為終止狀態,終止符號視為起始狀態 * 將每一條產生式規則都視為是一個反向的轉移函式,如 $A \rightarrow Ba$ 可以視為 $\delta (B, a) = A$ * 從終止符號開始,將所有的產生式規則都視為轉移函式畫為狀態機,直到連起始符號為止 * 由於起始狀態只能有一個,所以在多個起始狀態前多加一個起始狀態,並且用空字串轉移連接到原本的多個起始狀態,得到一個等價於該文法的 NFA * 由於所有的正規文法都可以透過以上映射得到等價的 NFA,所以正規文法產生的語言包含於正規語言 * 證明「正規語言 $\subseteq$ 正規文法可產生的語言」 * 由於有限狀態機當中的每個元素都可以對應正規文法中的某些元素(如上方證明所述),所以可以透過反向映射的方式,用跟上方相似的步驟,將有限狀態機以一個正規文法描述(敘述略) * 由於所有的正規語言都對應到一個有限狀態機,而每一個有限狀態機都可以轉換為正規文法,所以正規語言包含於正規文法所產生的語言 * 兩個集合互相包含對方,證明兩個集合相等,所以正規語言等於正規文法可產生的語言 ## Closure Properties of Regular Languages 略。 ## Elementary Questions about Regular Languages * 目前為止我們已經學過了幾種正規語言的標準表達方式 (Standard Representation),包含: * 確定有限狀態自動機 (DFA) * 非確定有限狀態自動機 (NFA) * 正規表示式 (Regular Expression) * 正規文法 (Regular Grammar) * 當我們說有一個正規語言 $L$, 這表示 $L$ 一定是以上述幾個方法之一來描述的 ### Some Questions about Regular Language * 給定一個正規語言 $L$ 和一個字串 $w$, 我們怎麼確認 $w \in L$ ? (Membership Question) * 畫出一個可以接受 $L$ 的 DFA, 然後看看 $w$ 能不能被該 DFA 接受。若能,則 $w$ 屬於 $L$, 反之則否 * 給定一個正規語言 $L$, 我們怎麼確認 $L$ 是空集合 ($L = \emptyset$)? * 畫出一個可以接受 $L$ 的 DFA, 然後看看起始狀態是否有路徑可以走到終止狀態。若有,則 $L$ 非空集合,反之則是空集合 * 給定一個正規語言 $L$, 我們怎麼確認 $L$ 是有限集合 (finite set)? * 畫出一個可以接受 $L$ 的 DFA, 然後看看從起始狀態走到終點狀態的路徑中有沒有環的存在。若有,則 $L$ 不是有限集合,反之則是有限集合 * 給定兩個正規語言 $L_1$ 和 $L_2$, 我們怎麼確認 $L_1 = L_2$ ? * 確認是否 $(L_1 \cap L_2) \cup (L_1 \cap L_2) = \emptyset$ 。若是,則 $L_1 = L_2$, 反之則否 ## Identifying Nonregular Languages ![](https://i.imgur.com/lpkZje3.png) > Figure 6. 有限語言 $\subset$ 正規語言 $\subset$ 非正規語言 有些語言並不屬於正規語言的集合,我們該如何證明一個語言 $L$ 不是正規語言呢?我們或許可以證明沒有任何一個 DFA 可以接受這個語言,但是窮舉出所有的 DFA 並不是一件容易的事(是做不到的事),所以我們需要用到一個工具 —— **泵引理 (Pumping Lemma)**。 ### Pigeonhole Principle *參考離散數學。* 簡單來說,如果有 $m$ 隻鴿子要裝進 $n$ 個鴿籠,當 $m > n$ 時,必定會有某個籠子裡至少有兩隻鴿子。 ### Pigeonhole Principle and DFAs ![](https://i.imgur.com/0GmlkAB.png) > Figure 7. 鴿籠定理與 DFA 對於任意一個有 $n$ 個狀態的 DFA $M$, 如果有一個字串 $w$, 其中 $|w| \geq m$, 則 $w$ 在 $M$ 當中所經過的路徑,必定有其中一個狀態 $q$ 被重複走過了至少兩次,如 Fig. 7 所示。 ![](https://i.imgur.com/tb2R60Z.png) > Figure 8. 一個長度為 4 的 DFA * 例如: 對於 Fig. 8 中的 DFA 來說, $a$, $aa$, $aab$ 等字串因為長度小於該 DFA 的狀態數量,所以不一定有重複走過的狀態。但是像 $aabb$, $bbaa$, $bababb$ 這些字串,其長度已經大於或等於該 DFA 的狀態數量了,所以在 DFA 消化他的過程當中,必定會有至少一個狀態被走過了兩次 ### Pumping Lemma * 定義: 給定一個無限正規語言 $L$, 必定存在一個整數 $m$ (代表可以接受 $L$ 的 DFA 的狀態數量),對於任意字串 $w \in L$ 且 $|w| \geq m$, 可以表示為 $w = xyz$, 其中 $|xy| \leq m$ 且 $|y| \geq 1$, 使得 $xy^iz \in L , i = 0, 1, 2,...$ :::danger 很重要!! 上面要整段背起來!! ::: * 應用: 可以搭配反證法來證明某語言**不是**正規語言。證明過程如下: 1. 假設給定的語言為正規語言,故滿足 pumping lemma (需要完整寫出上面這一段) 2. 舉出任意一個字串 $w$, 此字串必須要滿足 $w \in L$ 且 $|w| \geq m$, 所以通常會將 $m$ 用在該字串的參數當中 3. 將 $w$ 拆解成 $xyz$ 三段,其中 $|xy| \leq m$ 且 $|y| \geq 1$, 注意 $xy$ 的選擇務必滿足這些條件 4. 證明至少有一個 $xy^iz$ 不屬於 $L$ 5. 由於 4. 違反了 pumping lemma, 跟「給定的語言是正規語言」的假設矛盾,故給定的語言並非正規語言 * Pumping lemma 常見的誤用 * 用 Pumping lemma 證明某語言是正規語言 * 就算一個語言符合 pumping lemma, 也不能保證他一定是正規語言。 符合 pumping lemma 是正規語言的充份條件,而不是必要條件 * 在 2. 時舉出了一個不在 $L$ 當中的字串 * 例: $L = \{a^n: \textrm{n is a prime number}\}$ * $w = a^m$ 並不是一個好的選項,因為 $m$ 不一定是質數 * $w = a^P$, 其中 $P$ 是一個比 $m$ 大的質數,才是正確的挑法 * 對於 $xyz$ 分解做出過度假設 * 例: $L = \{a^n: \textrm{n is a prime number}\}$ * 令 $y = ak$, 其中 $k$ 是一個奇數。這是一個不對的假設,因為這樣沒有考慮到 $k$ 是偶數時的狀況