[形式语言] 05 Pushdown Automaton

Posted by roife on Tue, Oct 17, 2023

PDA

定义

RL 可以用一个 DFA 识别,其中 DFA 的每个状态都对应了 RL 的右线性文法 \(A \rightarrow aB\) 表示中的一个语法变量,字母表示了 DFA 上的一条边(转移)。

从前面的讨论可知 CFG 可以转换成 GNF 表示,其形式为 \(A \rightarrow a B_1 B_2 \dots B_n\),与右线性文法的区别在于它的右侧有多个需要依次转移的变量。为了识别 CFL,下推自动机在 FA 的基础上增加了一个栈,用于存储需要派生的状态变量。

(Pushdown Automata)

定义下推自动机(Pushdown Automata,PDA)为一个七元组 \(P = (Q, \Sigma, \Gamma, \delta, q_0, Z_0, F)\) ,其中:

  • \(Q\) 是一个有限的状态的集合
  • \(\Sigma\) 是一个输入字母表
  • \(\Gamma\) 一个栈字母表(stack alphabet)
  • \(\delta\) 是一个状态转移函数(transition function)
    • \(\delta : Q \times (\Sigma \cup \{\varepsilon\}) \times \Gamma \rightarrow 2^{Q \times \Gamma^{*}}\)
    • \(\delta(q, a, Z) = \{(p_i, \alpha_i) | p_i \in Q, \alpha_i \in \Gamma^*\}\) 表示 PDA 在状态 \(q\) 下且栈顶符号为 \(Z\) 时,可以选择将状态变为 \(p_i\),将 \(Z\) 从栈顶弹出并将序列 \(\alpha\) 从右到左依次压入栈,然后将读头移动到下一个字符
  • \(q_0 \in Q\) 是起始状态
  • \(Z_0 \in \Gamma\) 是起始符号
  • \(F \subseteq Q\) 是接收状态的集合

如果 \(\delta(q, a, Z) = \{(p, \epsilon)\}\),相当于从栈中弹出一个元素。

设 PDA \(M = (Q, \Sigma, \Gamma, \delta, q_0, Z_0, F)\),\((q, w, \gamma) \in (Q, \Sigma^{*}, \Gamma^{*})\) 称为 \(M\) 的一个即时描述(instantaneous description, ID)。它表示 \(M\) 处于状态 \(q\);\(w\) 是未处理完的字符串,\(M\) 正注视着 \(w\) 的首字符;\(\gamma\) 从左到右是从栈顶到栈底的符号。

  • 如果 \((p, \gamma) \in \delta(q, a, Z)\),则 \((q, aw, Z\beta) \vdash_M (p, w, y \beta)\) 表示 \(M\) 做了一次非空移动
  • 如果 \((p, \gamma) \in \delta(q, \varepsilon, Z)\),则 \((q, w, Z\beta) \vdash_M (p, w, y \beta)\) 表示 \(M\) 做了一次空移动

同样可以定义 \(\vdash_M^n\),\(\vdash_M^+\) 和 \(\vdash_M^{*}\),没有歧义时可以省略 \(M\)。

接收

类似 FA,PDA 在接收状态下仍然可以继续工作,PDA 的接收可以有两种定义。

设有 PDA \(M = (Q, \Sigma, \Gamma, \delta, q_0, Z_0, F)\),则

  • \(M\) 用终态接收的语言为 \(L(M) = \{w | (q_0, w, Z_0) \vdash^* (p, \varepsilon, \beta) \wedge p \in F\}\)
  • \(M\) 用空栈接收的语言为 \(N(M) = \{w | (q_0, w, Z_0) \vdash^* (p, \varepsilon, \varepsilon)\}\)(不需要 \(p \in F\))

下面是识别语言 \(L = \{w 2 w^T | w \in \{0, 1\}^{*}\}\) 的一个 PDA 设计:

  • 考虑对应的 CFG:\(G : S \rightarrow 2 | 0S0 | 1S1\),将其转化为 GNF \(G’ : S \rightarrow 2 | 0SA | 1SB; A \rightarrow 0; B \rightarrow 1\)
  • 将其转换为 PDA \(M = (\{q_0\}, \{0, 1, 2\}, \{S, A, B\}, \delta, q_0, S, \emptyset)\)
    • \(\delta(q_0, 0, S) = \{(q_0, SA)\}\),\(\delta(q_0, 1, S) = \{(q_0, SB)\}\),\(\delta(q_0, 2, S) = \{(q_0, \varepsilon)\}\)
    • \(\delta(q_0, 0, A) = \{(q_0, \varepsilon)\}\),\(\delta(q_0, 1, B) = \{(q_0, \varepsilon)\}\)
    • 此时是一个空栈接收的语言
  • 同时可以将其转换成一个终态接收的语言 \(M = (\{q_0, q_1\}, \{0, 1, 2\}, \{S, A, B, Z\}, \delta, q_0, Z, \{q_1\})\)
    • \(\delta(q_0, \varepsilon, Z) = \{(q_0, SZ), (q_1, \varepsilon)\}\)
    • \(\delta(q_0, 0, S) = \{(q_0, SA)\}\),\(\delta(q_0, 1, S) = \{(q_0, SB)\}\),\(\delta(q_0, 2, S) = \{(q_0, \varepsilon)\}\)
    • \(\delta(q_0, 0, A) = \{(q_0, \varepsilon)\}\),\(\delta(q_0, 1, B) = \{(q_0, \varepsilon)\}\),\(\delta(q_0, \varepsilon, Z_0) = \{(q_0, \varepsilon)\}\)

PDA 与图灵机

\(\{w2w^T | w \in \{0, 1\}^{*}\}\) 和 \(\{a^n b^n\}\) 可以用 PDA 模拟弹栈实现,但是 \(\{w2w | w \in \{0, 1\}^{*}\}\) 和 \(\{a^n b^n c^n\}\) 则不能用 PDA 构造。

从定义可以看出,一个 PDA 等价于一台拥有两根纸带的“受限图灵机”:在第一根纸带上,图灵机只能从左向右移动并且不能更改纸带;在第二根纸带上,图灵机只能删除纸带最左边的元素(弹出)或在纸带最左边添加元素(压入)。

从 PDA 的定义可以看出,与 FA 相比,PDA 多了存储数据的能力;但是与图灵机相比,它对数据的读取顺序有限制,而且只能读取一次。尽管可以设计 \(\delta\) 使得 PDA 在弹出符号后重新压回去,但是这会导致 PDA 无法解析底层的符号。

PDA 之所以比图灵机弱,是因为它弹出操作会删除数据,因此添加一根纸带用于存储删除值的 PDA 可以等价模拟图灵机。在这个模型下 PDA 相当于有三根纸带:一根只读的输入带和两个栈纸带。PDA 首先从输入带中读入元素并全部压入第一个栈中,然后就可以像图灵机一样进行操作:

  • 向左移动等价于弹出第一个栈的元素,并压入第二个栈;向右移动则相反
  • 写入操作对应弹出元素,并压入想要写入的元素

PDA 的变形

确定性 PDA

定义

上面描述的实际上是一个非确定性的 PDA,因为状态转移的结果是一个集合,下面定义了确定性的 PDA。

(Deterministic PDA, DPDA)

确定的 PDA \(M = (Q, \Sigma, \Gamma, \delta, q_0, Z_0, F)\) 是满足下面条件的 PDA:

\[\forall (q, a, Z) \in Q \times \Sigma \times \Gamma, |\delta(q, a, Z)| + |\delta(q, \varepsilon, Z)| \le 1\]

DPDA 的接收与 DCFL

在 DPDA 中,空栈接收和终态接收所描述的语言类并不等价(对 PDA 来说是等价的)。例如终态接收的 DPDA 可以描述 \(0^n\),但是空栈接收的 DPDA 无法描述。这是因为空栈接收的 DPDA 如果接受一门语言,那么对于这门语言中任意两个字符串 \(x, y\),满足 \(\forall z \in \Sigma^*. xz \ne y\),即任意一个字符串都不是另一个字符串的前缀(因为空栈接收的 DPDA 会提前终止)。所以终态接收的 DPDA 更加灵活,能够接收的语言更多。

通常使用终态接收的 PDA 定义确定性上下文无关语言(DCFL)。在编译器的设计中,识别的实际上也是 DCFL。当 DPDA 只有一个状态时,它描述的就是 \(LL(1)\) 语言。

DPDA 描述的 CFL 一定是无二义性的(但是无二义性的语言不一定可以用 DPDA 描述)。

DPDA 与 NPDA

虽然 DFA 可以用子集枚举的方式模拟 NFA,例如用 \(\{1, 2\}\) 来模拟同时走两个状态,但是在 DPDA 中走一步还伴随了对栈的操作,而对栈的操作无法利用子集枚举来同时模拟多个操作,即在 DPDA 中每一步对栈的操作都是确定且不可逆的。在利用子集枚举法模拟 NFA 时,NPDA 在多个状态下对栈的不同操作被收束到 DPDA 下对栈的唯一操作,这使得 DPDA 丧失了灵活性。

可以将 PDA 的栈看作是“全局状态”的一部分(当然这样的“全局状态”的数量是无限的),这样就会发现 DPDA 无法实现 NPDA 的模拟。

而 NFA 由于状态机有多个方向可以选择,每个方向对栈可以有不同的操作,因此能力更强。所以 DPDA 接收的语言集合是 NPDA 的子集。例如偶数长度的回文串 \(S \rightarrow 0S0 | 1S1 | \varepsilon\) 无法被 DPDA 接接收,下面是一个简单的证明:

  • 假设 DPDA 能够接收 \(S \rightarrow 0S0 | 1S1 | \varepsilon\),那么它就能接收 \(s_1 = 0^{n}110^{n}\) 和 \(s_2 = 0^n110^n0^n110^n\)
  • 经过上面的讨论得知终态接收的 DPDA 描述能力更强,因此不妨使用终态接收的 DPDA 构造
  • DPDA 在接收 \(s_1\) 时,由于状态机的状态数量和栈符号字母表数量是有限的,因此它必须通过压栈的方式记录 \(n\) 的数量,并且在遇到第二个 \(0^n\) 时弹出栈中的符号来验证是否接收 \(s_1\)
  • 由于 DPDA 每一步都是确定的,因此在经过 \(s_2\) 的前半部分时,其经过的全局状态一定与 \(s_1\) 的接收过程相同
  • 但是由之前的讨论知,此时 DPDA 已经弹出了栈中的所有符号,因此它无法判定 \(s_2\) 的前半部分与后半部分是否回文

在下一章讨论 DCFL 的性质还有一个严格的证明。

在这个例子中,NPDA 可以在每一步选择两个方向:开始弹栈,或继续压栈。但是 DPDA 在每一步只能做一个抉择,而它并不能判断在哪一步开始弹栈。而对于普通的 \(0^n10^n\),DPDA 可以在识别到 \(1\) 的时候判断跨过了中点时就开始弹栈。

Generalized PDA

广义下推自动机(generalized PDA, GPDA)定义为一个七元组 \(M = (Q, \Sigma, \Gamma, \delta, Z_0, q_0, F)\),其中 \(\delta : Q \times (\Sigma \cup \{\varepsilon\}) \times \Gamma^{*} \rightarrow 2^{Q \times \Gamma^{*}}\)

GPDA 的特殊之处在于每次可以向栈中压入一系列字符或弹出一系列字符。

不难证明 GPDA 与 PDA 等价:

  • PDA 显然是 GPDA

  • 对于 PDA 中的特殊操作 \(\delta(q, w, x_1 x_2 \dots x_n) = (p, y_1 y_2 \dots y_m)\),定义

    \[\delta’(q, w, x_1) = (p_1, \varepsilon)\] \[\delta’(p_1, \varepsilon, x_2) = (p_2, \varepsilon)\] \[\dots\] \[\delta’(p_{m-1}, \varepsilon, x_m) = (p_m, \varepsilon)\] \[\delta’(p_{m}, \varepsilon, \varepsilon) = (p_{m+1}, y_n)\] \[\delta’(p_{m+1}, \varepsilon, \varepsilon) = (p_{m+1}, y_{n-1})\] \[\dots\] \[\delta’(p_{m+n-1}, \varepsilon, \varepsilon) = (p, y_1)\]

Counter Automaton

Counter automaton 是一类受限的 PDA,其中它只能向纸带上打印唯一的一种符号,即 \(|\Gamma| = 1\)。

Counter automaton 等价于带了一个额外的计数器(只能记录非负数)的 FA,这使其能够识别类似于 \(0^n 0^n\) 这样的语言,但是由于计数器只能记录一个非负数,因此无法识别 \(0^n1^m1^m0^n\) 这样的语言。

Queue Automaton

Queue automaton 又称 pullup automaton(PUA)。相比 PDA,QA 能够

一个 queue automaton 可以用一个六元组 \(M = (Q, \Sigma, \Gamma, \$, S, \delta)\) 描述:

  • \(Q, S\) 的定义同 PDA
  • \(\Sigma \subset \Gamma\) 是有限的输入字母表
  • \(\Gamma\) 是有限的队列字母表
  • \(\$ \in \Gamma \backslash \Sigma\) 是队列的起始标记
  • \(\delta : Q \times \Gamma \rightarrow Q \times \Gamma^{*}\) 是状态转移函数
    • 队列的状态可以用 \((p, \alpha)\) 表示,前者是当前的状态,后者是当前的队列
    • \(\delta(p, A\alpha) = (q, \alpha \gamma)\) 表示在状态 \(p\) 下;队列为 \(A\alpha\),头部为 \(A\);然后取出字符 \(A\),转移到状态 \(q\),并在队尾压入 \(\gamma\)
  • 接收状态定义为队列为空

可以证明 QA 等价于图灵机。显然图灵机可以模拟 QA,因此只需要用 QA 模拟图灵机即可:

  • 首先将图灵机的纸带复制到 QA 的队列内,并且在首尾添加两个符号:图灵机读头符号 \(\$\) 和纸带分隔符 \(\#\)
  • 对于图灵机的每一次状态转移,QA 都会遍历两趟纸带(从开头到第一次遇到 \(\#\))
  • 状态用 \((q, 0/1, x, L/R, z)\) 表示,一开始状态是 \((q_0, 0, \bot, ?, \bot)\) ,其中 \(\bot \notin \Sigma\)
    • 第一个 \(q\) 表示图灵机的状态
    • 第二个 \(0\) 表示这是第一趟,\(1\) 表示这是第二趟
    • 第三个 \(x\) 在第一趟遇到读头前存储的是上一个字符,遇到读头后存储读头前一个位置的字符,可以是 \(\bot\)
    • 第四个 \(L/R\) 表示读头在第二趟时是左移还是右移,\(?\) 表示还没遇到第一趟的读头,\(!\) 表示刚经过第一趟的读头
    • 第五个 \(z\) 用于记录第二趟遇到读头前的上一个字符,可以是 \(\bot\)
    • 第二个和第四个位置决定了当下的操作,第一个和第三个和第五个位置用于记录
  • 第一趟遍历处理转移(下面所说的读取指取出队首并转移;打印指把字符放到队尾,\(\bot\) 不打印)
    • 开始的状态是 \((q, 0, x / \bot, ?, \bot)\)
      • 如果当前字符 \(y \in \Sigma\),转移到 \((q, 0, y, ?, \bot)\),并打印 \(x\)
      • 遇到读头时,状态是 \((q, 0, x, ?, \bot)\),当前状态中的第三个位置 \(x\) 是读头前的一个字符。此时不放字符,转移到 \((q, 0, x, !, \bot)\),读取下一个字符
      • 由于还没遇到读头,当前字符不可能是 \(\#\)
    • 此时状态形如 \((q, 0, x, !, \bot)\),检测到读头,模拟图灵机的一次操作,设状态转移到 \(p\),打印 \(y\),读头移动为 \(L/R\)
      • 将 \(xy\) 放到队列中,状态转移到 \((p, 0, x, L/R, \bot)\),并继续读入字符
    • 经过读头后,状态形如 \((q, 0, x, L/R, \bot)\),此时如果当前位置的字符 \(y \in \Sigma\),则打印,且状态不转移
      • 如果当前字符是 \(\#\),状态转移到 \((q, 1, x, L/R, \bot)\),并打印 \(\#\)
  • 第二趟遍历打印读头
    • 开始状态是 \((q, 1, x, L/R, z/\bot)\)
      • 如果当前位置的字符 \(y \in \Sigma\),则状态转移到 \((q, 1, x, L/R, y)\),并打印 \(z\)
      • 直到遇到读头
        • 如果状态是 \((q, 1, x, L, z)\) 则打印 \(\$x\),状态转移到 \((q, 1, x, L, \bot)\)
        • 如果状态是 \((q, 1, x, R, z)\) 则,则打印 \(x\) 并转移到 \((q, 1, x, ?, \bot)\)
    • 此时状态可能是 \((q, 1, x, ?, \bot)\),表示恰好在读头右一个位置,设当前字符为 \(y\),打印 \(y\$\),并转移到 \((q, 1, x, R, \bot)\)
    • 最后遇到 \(\#\),状态是 \((q, 1, x, L/R, z)\),打印 \(z\#\),状态转移到 \((q, 0, x, ?, \bot)\)
  • 如果到了图灵机的接收状态,则后面的指令就是一直读取直到清空队列

PDA 的性质

预先放置

给定 PDA \(P\),如果 \((q, x, \alpha) \vdash^{*} (p, y, \beta)\),则 \(\forall w \in \Sigma^{*}, \gamma \in \Gamma^{*}. (q, xw, \alpha \gamma) \vdash^{*} (p, yw, \beta \gamma)\)。

给定 PDA \(P\),如果 \((q, xw, \alpha) \vdash^{*} (p, yw, \beta)\),则 \((q, x, \alpha) \vdash^{*} (p, y, \beta)\)。

注意删除相同的部分栈底元素可能会对自动机造成影响。

空栈接收与终态接收等价

首先证明任意终态接收的 PDA 可以转换为空栈接收的 PDA。

对于任意 PDA \(M_1\),存在 PDA \(M_2\) 使得 \(L(M_1) = N(M_2)\)

下面使用构造证明。

这个证明的核心在于两点

  1. \(M_1\) 进入终止状态后,要清空栈来接收(下面用 \(q_{\varepsilon}\) 来解决)
    • 如果 \(M_2\) 进入了 \(q_\varepsilon\),则用空移动可以清栈,根据 NFA 的性质,此时输入也被读完才能接收
  2. \(M_1\) 没到终止状态,\(M_2\) 栈空时不能误接收(下面用 \(q_{02}, Z_{02}\) 来解决)

设 PDA \(M_1 = (Q, \Sigma, \Gamma, \delta_1, q_{01}, Z_{01}, F)\),下面构造 \(M_2 = (Q \cup \{q_{02}, q_{\varepsilon}\}, \Sigma, \Gamma \cup \{Z_{02}\}, \delta_2, q_{02}, Z_{02}, F)\)。并根据下面规则构建 \(\delta_{2}\)。

  • \(M_2\) 启动后,立即进入 \(M_1\) 的初始 ID \(\delta_2(q_{02}, \varepsilon, Z_{02}) = \{(q_{01}, Z_{01}Z_{02})\}\)
  • 在 \(M_1\) 的非空移动,\(M_2\) 直接模拟 \(\forall (q, a, Z) \in Q \times \Sigma \times \Gamma. \delta_2(q, a, Z) = \delta_1(q, a, Z)\)
  • 在 \(M_1\) 非终态时的空移动也可以直接模拟 \(\forall(q, Z) \in (Q - F) \times \Gamma. \delta_2(q, \varepsilon, Z) = \delta_2(q, \varepsilon, Z)\)
  • 当 \(M_1\) 进入终态时进行空移动,\(M_2\) 要额外模拟清栈 \(\forall(q, Z) \in F \times \Gamma. \delta_2(q, \varepsilon, Z) = \delta_1(q, \varepsilon, Z) \cup (q_\varepsilon, \varepsilon)\)
  • \(M_1\) 栈空并且进入终态,\(M_2\) 也一定终止 \(\delta_2(q, \varepsilon, Z_{02}) = \{(q_\varepsilon, \varepsilon)\}\)
  • \(M_2\) 清栈后可以接收 \(\forall Z \in \Gamma \cup \{Z_{02}\}. \delta_2(q_{\varepsilon}, \varepsilon, Z) = \{(q_{\varepsilon}, \varepsilon)\}\)

下面证明 \(L(M_1) = N(M_2)\)。

  • 首先证明 \(L(M_1) \subseteq N(M_2)\)

    • 设 \(x \in L(M_1)\),则 \((q_{01}, x, Z_{01}) \vdash_{M_1}^* (q, \varepsilon, \gamma)\)。由于 \(Z_{02}\) 与 \(M_1\) 无关,因此有

      \[(q_{01}, x, Z_{01}Z_{02}) \vdash_{M_1}^{*} (q, \varepsilon, \gamma Z_{02})\ (q \in F)\]

    • 根据定义,\(M_2\) 能模拟 \(M_1\) 的所有移动,并且在 \(M_{01}\) 的终态清栈,有

      \[(q_{01}, x, Z_{01}Z_{02}) \vdash_{M_2}^{*} (q, \varepsilon, \gamma Z_{02}) \vdash_{M_2}^{*} (q_{\varepsilon}, \varepsilon, \varepsilon) \ (q \in F)\]

    • 又因为 \((q_{02}, x, Z_{02}) \vdash_{M_2} (q_{01}, x, Z_{01}Z_{02})\),则

      \[(q_{02}, x, Z_{02}) \vdash_{M_2} (q_{01}, x, Z_{01}Z_{02}) \vdash_{M_2}^{*} (q, \varepsilon, \gamma Z_{02}) \vdash_{M_2}^{*} (q_{\varepsilon}, \varepsilon, \varepsilon) \ (q \in F)\]

    • 即 \(x \in N(M_2)\)

  • 然后证明 \(N(M_2) \subseteq L(M_1)\)

    • 设 \(x \in N(M_2)\),将上面的过程反推即可:此时 \(M_2\) 最后必须进入清栈的状态且读完 \(x\),因此 \(M_1\) 必然进入终态且读完 \(x\),即 \(M_1\) 也接收 \(x\)

下面证明反方向:

对于任意 PDA \(M_1\),存在 PDA \(M_2\) 使得 \(N(M_1) = L(M_2)\)

类似的,需要通过构造并证明等价性。

这个证明的核心在于提前放一个哨兵 \(Z_{02}\) 在 \(M_2\) 的栈中。在接收过程中发现栈顶是 \(Z_{02}\),则说明栈空了,那么 \(M_2\) 应当立即进入终态。

设 PDA \(M_1 = (Q, \Sigma, \Gamma, \delta_1, q_{01}, Z_{01}, F)\),下面构造 \(M_2 = (Q \cup \{q_{02}, q_{f}\}, \Sigma, \Gamma \cup \{Z_{02}\}, \delta_2, q_{02}, Z_{02}, \{q_f\})\)。并根据下面规则构建 \(\delta_{2}\)。

  • \(M_2\) 启动后,开始模拟 \(M_1\) 的栈 \(\delta_2(q_{02}, \varepsilon, Z_{02}) = \{(q_{01}, Z_{01}Z_{02})\}\)
  • 在 \(M_1\) 的非空移动,\(M_2\) 直接模拟 \(\forall (q, a, Z) \in Q \times \Sigma \times \Gamma. \delta_2(q, a, Z) = \delta_1(q, a, Z)\)
  • 如果 \(M_1\) 的栈空时,立即进入终态 \(\delta_2(q, \varepsilon, Z_{02}) = \{(q_f, \varepsilon)\}\)

PDA 与 CFG 等价

从 CFL 转换到 PDA 比较简单,只需要考虑 CFG 的 GNF 即可。

对于任意 CFL \(L\),存在 PDA \(M\),使得 \(N(M) = L\)。

设 CFL 对应 GNF \(G(V, T, P, S)\),使得 \(L(G) = L\)。

下面构造一个空栈接收的 PDA \(M = (\{q\}, T, V, \delta, q, S, \emptyset)\),其中

\[\forall A \in V, a \in T. \delta(q, a, A) = \{(q, \gamma) | A \rightarrow a \gamma \in P\}\]

下面证明 \(L(M) = L(G) = L\),设 \(w \in L\),只要证明

\[(q, w, S) \vdash_M^n (q, \varepsilon, \alpha) \Leftrightarrow S \xRightarrow{n} wa \in P\]

  • 首先证明充分性,对 \(|w|\) 进行归纳

    • 当 \(n = 1\) 时,\((q, a, S) \vdash_M^n (q, \varepsilon, \alpha)\),此处 \(a \in T\),则 \((q, \alpha) \in \delta(q, a, S)\)。根据定义,有 \(S \rightarrow a \alpha \in P\),因此 \(S \Rightarrow a \alpha\)。

    • 设 \(n = k\) 时成立,当 \(n = k + 1\) 时,有 \(w = xa, |x| = k, a \in T\) 使得

      \[(q, w, S) = (q, xa, S) \vdash_M^n (q, a, A \beta_1) \vdash_M (q, \varepsilon, \beta_2 \beta_1) = (q, \varepsilon, \alpha)\]

      因此 \((q, \beta_2) \in \delta(q, a, A)\),根据定义有 \(A \rightarrow a \beta_2 \in P\)。又根据归纳假设有 \((q, xa, S) \vdash_M^n (q, a, A \beta_1) \Rightarrow S \xRightarrow{n} x A \beta_1 \in P\)。因此有

      \[S \xRightarrow{n} x A \beta_1 \Rightarrow xa \beta_2 \beta_1 = xa \alpha = w\alpha \]

      假设成立。

  • 然后证明必要性,同样用归纳的方法

    • 当 \(n = 1\) 时,\(S \Rightarrow w \alpha\),其中 \(w \in T \wedge S \rightarrow w \alpha \in P\),根据定义有 \((q, \alpha) \in \delta(q, w, S)\),因此 \((q, w, S) \vdash_M (q, \varepsilon, \alpha)\),成立

    • 设 \(n = k\) 时成立,当 \(n = k + 1\) 时,设 \(S \xRightarrow{k} xA\beta_1 \Rightarrow xa \alpha = xa\beta_2\beta_1\),从中可知 \[A \rightarrow \alpha \beta_2 \in P\]

      因此根据定义有 \((q, \beta_2) \in \delta(q, a, A)\),即

      \[(q, a, A) \vdash_M (q, \varepsilon, \beta_2)\]

      又根据归纳假设及 \(S \xRightarrow{k} xA\beta_1\) 有

      \[(q, xa, S) \vdash_M^k (q, a, A\beta_1)\]

      因此有

      \[(q, xa, S) \vdash_M^k (q, a, A\beta_1) \vdash_M (q, \varepsilon, \beta_2 \beta_1) = (q, \varepsilon, \alpha)\] 成立

综上所述,下面的结论成立

\[(q, w, S) \vdash_M^n (q, \varepsilon, \alpha) \Leftrightarrow S \xRightarrow{n} wa \in P\]

注意到 \(\alpha\) 的任意性,因此

\[(q, w, S) \vdash_M^n (q, \varepsilon, \varepsilon) \Leftrightarrow S \xRightarrow{n} w \in P\]

即 \(N(M) = L(G)\)

值得注意的是,这里最后还要考虑 \(\varepsilon \in L\) 的情况。首先构造 \(M = (Q, \Sigma, \Gamma, \delta, q_0, Z_0, \emptyset)\) 使得 \(N(M) = L - \{\varepsilon\}\),然后令

\[M’ = (Q \cup \{q_\varepsilon\}, \Sigma, \Gamma \cup \{Z_\varepsilon\}, \delta’, q_\varepsilon, Z_\varepsilon)\]

\[\delta(q, a, Z) = \begin{cases} \{(q_\varepsilon, \varepsilon), (q_0, Z_0)\}, & a = \varepsilon \\ \delta(q, a, Z), & a \ne \varepsilon \end{cases}\]

则 \(N(M’) = N(M) \cup \{\varepsilon\}\)

从 PDA 转换到 CFL 要复杂一些。考虑 PDA 的一次移动 \(\delta(q, a, A) \ni (q_1, A_1 A_2 \dots A_n)\) 中表示 \(M\) 在状态 \(q\) 下,栈顶字符为 \(A\),读入一个字符 \(a\) 可以转移到 \(q_1\),并压入 \(A_1 A_2 \dots A_n\)。类似 GNF 的想法,应该设计为 \([q, a] \rightarrow a [q_1, A_1 A_2 \dots A_n]\)。

但是这样设计的问题在于无法给出 \([q, A_1 A_2 \dots A_n] \rightarrow \dots\)。注意到这里的 \(A_1 A_2 \dots A_n\) 压入栈后,下一次转移 PDA 只能看到栈顶的 \(A_1\),因此在设计状态时,可以将其拆分开来,一个状态只包含一个符号(每次只压入一个符号),形如 \([q,A] \rightarrow a[q_1, A_1][q_2, A_2] \dots [q_n, A_n]\)。这里的 \([q_k, A_k]\) 表示当 \(1 \le i \le k\) 解析完成后,栈顶是 \(A_i\),状态是 \(q_i\)。

这样设计带来了新的问题:在 PDA 工作时,弹出一个符号后可能压入新的一系列符号,并进行状态转移,而 \([q_i, A_i] [q_{i+1}, A_{i+1}]\) 表示弹出 \(A_i\) 压入新符号前的状态是 \(q_i\),处理新符号后的状态是 \(q_{i+1}\)。但是实际过程中并不能保证这一点,有可能中间转移到其他状态了。为了保证在 \(q_i\) 处理 \(A_i \xRightarrow{k} w\) 完成后,转移到 \(q_{i+1}\) 再对 \(A_{i+1}\) 进行处理,这里考虑将非终结符表示成:

\[[q_i, A_i, q_{i+1}]\]

这表示当前状态 \(q_i\),栈顶为 \(A_i\),当前的栈顶和压入的新符号完全弹出(即栈顶变成 \(A_{i+1}\) 时)时状态为 \(q_{i+1}\)。即利用 \(q_i \rightarrow q_{i+1}\) 之间产生的序列来弹出 \(A_i\)。

对于任意 PDA \(M\),存在 CFG \(G\) 使得 \(L(G) = N(M)\)。

设 \(M = (Q, \Sigma, \Gamma, \delta, q_0, Z_0, \emptyset)\),取 CFG \(G = (V, \Sigma, P, S)\),其中

\begin{aligned} V = \{& S\} \cup Q \cup \Gamma \cup Q \\ P = \{& S \rightarrow [q_0, Z_0, q] | q \in Q \} \\ \cup \{& [q, A, q_{n+1}] \rightarrow a[q_1, A_1, q_2][q_2, A_2, q_3] \dots [q_n, A_n, q_{n+1}] \\ & \quad | (q_1, A_1 A_2 \dots A_n) \in \delta(q, a, A) \wedge a \in \Sigma \cup \{\varepsilon\}, q_i \in Q]\} \\ \cup \{& [q, A, q_1] \rightarrow a | (q_1, \varepsilon) \in \delta(q, a, A)\} \end{aligned}

下面证明 \(L(G) = N(M)\),即证明

\[[q, A, p] \xRightarrow{*} x \Leftrightarrow (q, x, A) \vdash^* (p, \varepsilon, \varepsilon)\]

  • 首先证明充分性。设 \([q, A, p] \xRightarrow{n} x\),对 \(n\) 进行归纳
    • 当 \(n = 1\) 时,必有 \(x \in \Sigma \cup \{\varepsilon\}\),因此 \([q, A, p] \rightarrow x \in P\),根据定义有 \((p, \varepsilon) \in \delta(q, a, A)\),即 \((q, a, A) \vdash (p, \varepsilon, \varepsilon)\),成立

    • 设 \(n \le k\) 时结论成立,即 \(([q, A, p] \xRightarrow{i} x) \Leftrightarrow ((q, x, A) \vdash^* (p, \varepsilon, \varepsilon))\ (1 \le i \le n)\)

    • 则当 \(n = k + 1\) 时,有

      \[[q, A, p] \Rightarrow a[q_1, A_1, q_2][q_2, A_2, q_3] \dots [q_n, A_n, q_{n+1}] \xRightarrow{k} a x_1 x_2 \dots x_n\]

      根据定义有 \((q_1, A_1 A_2 \dots A_n) \in \delta(q, a, A)\)。

      设 \([q_i, A, q_{i+1}] \xRightarrow{k_i} x_i\ (1 \le i \le n)\) 且 \(\Sigma k_i = k\)。由归纳假设有 \((q_i, x_i, A_i) \vdash^* (q_{i+1}, \varepsilon, \varepsilon)\)。

      因此

      \begin{aligned} (q, a x_1 x_2 \dots x_n, A) & \vdash (q_1, x_1 x_2 \dots x_n, A_1 A_2 \dots A_n) \\ & \vdash^* (q_2, x_2 \dots x_n, A_2 \dots A_n) \\ & \vdash^* \dots \\ & \vdash^* (q_n, x_n, A_n) \\ & \vdash^* (q_{n+1}, \varepsilon, \varepsilon) \end{aligned}

      成立

  • 下面证明必要性。设 \((q, x, A) \vdash^n (p, \varepsilon, \varepsilon)\),对 \(n\) 进行归纳
    • 当 \(n = 1\) 时,\((q, a, A) \vdash (p, \varepsilon, \varepsilon)\),即 \(\delta(q, a, A) \ni (p, \varepsilon)\),根据定义 \([q, A, p] \rightarrow a \in P\),成立

    • 设当 \(n = k\) 时成立,即 \((q, x, A) \vdash^k (p, \varepsilon, \varepsilon) \Rightarrow [q, A, p] \xRightarrow{k} x\)

    • 则当 \(n = k + 1\) 时,设 \(x = a x_1 x_2 \dots x_n\),则

      \[(q, x, A) = (q, a x_1 x_2 \dots x_n, A) \vdash (q, x_1 x_2 \dots x_n, A_1 A_2 \dots A_n)\]

      其中 \((q_i, x_i, A_i) \vdash^{k_i} (p, \varepsilon, \varepsilon)\),则 \([q_i, A_i, q_{i+1}] \xRightarrow{k_i} x_i\)

      由于 \((q, x, A) \vdash (q, \varepsilon, A_1 A_2 \dots A_n)\),因此有 \(\delta(q, x, A) \ni (q_1, A_1 A_2 \dots A_n)\),根据定义有

      \[[q, A, q_{n+1}] \rightarrow a[q_1, A_1, q_2][q_2, A_2, q_3] \dots [q_n, A_n, q_{n+1}] \in P\]

      综上,有

      \begin{aligned} [q, A, q_{n+1}] & \xRightarrow a[q_1, A_1, q_2][q_2, A_2, q_3] \dots [q_n, A_n, q_{n+1}] \\ & \xRightarrow{*} a x_1 [q_2, A_2, q_3] \dots [q_n, A_n, q_{n+1}] \\ & \dots \\ & \xRightarrow{*} a x_1 x_2 \dots x_n = x \end{aligned}

      成立。

综上,原命题成立