[学习笔记] - 计算理论

复杂性理论:发现了一个按照计算难度给问题分类的完美体系
可计算性理论:把问题分成可解和不可解
自动机理论:论述计算的数学模型和定义和性质

集合

集合:是一组对象,把它作为一个整体。
集合中的对象称为:元素或成员

  • 子集ABA \subseteq B
  • 真子集ABA \nsubseteq B
  • 多重集合:考虑元素出现的次数
  • 空集\varnothing

其他:

  • 交集\cap
  • 并集\cup
  • 补集A\overline{A}

序列和多元组

  • 序列:把一些对象按照某种顺序排列成一列
  • 又穷序列多元组
  • kk个元素的序列k元组
  • 2元组:有序对

笛卡尔积丨叉积

A, BA,\ B是两个集合,A, BA,\ B笛卡尔积丨叉积是第一个元素位AA的成员,第二个元素位B的程用的所有有序对组成的集合,记作A×BA \times B

  • kk个集合A1,A2,A3,,AkA_1, A_2, A_3, \cdots, A_k的笛卡尔积,记作A1×A2×A3××AkA_1 \times A_2 \times A_3 \times \cdots \times A_k,它是由所有k元组(a1,a2,,ak)(a_1, a_2, \cdots, a_k)组成的集合,其中aiAia_i \in A_i
  • 集合自身的笛卡尔积记作:A×A××A=AkA \times A \times \cdots \times A = A^k

函数丨关系

函数建立一个输入-输出的关系,记作

f(a)=bf(a) = b

函数又称作映射,并且若f(a)=bf(a) =b,则说ffaa映射到bb

  • 定义域:函数所有可能的输入组成的集合
  • 值域:函数的输出

f:DRf: D \rightarrow R

  • kk元函数kk个自变量的函数
  • 元数kk
  • 一元函数k=1k=1的时候
  • 二元函数k=2k=2的时候

谓词丨性质

谓词或性质是值域伪True,False的函数。
例:当even是谓词时,输入是偶数为True,奇数时为False

等价关系

一种特殊的二元关系

  • RR自反的,集对每一个xxxRyxRy
  • RR对称的,集对每一个xxyyxRyxRy当且仅当yRxyRx
  • RR传递的的,集对每一个x,yx, yzzxRyxRyyRzyRz可推出xRzxRz

无向图又简称为:是一个点的集合和连接其中的某些点的线段

  • 顶点:图中的点
  • :图中的边
  • 顶点的度数:以这个顶点为端点的边的数目

概念:

  • 子图:如果图GG的顶点集是图HH的顶点集,则GGHH的子图
  • 路径:由边连接的顶点序列
  • 简单路径:没有顶点重复的路径
  • 简单圈:只有最后一个点和第一个的重复的圈

有向图

用箭头代替线段

概念:

  • 出度:一个顶点引出的箭头数
  • 入度:指向一个顶点的箭头数
  • 有向路径:所有箭头的方向都与其前进的方向一致的路径
  • 强连通:每一个顶点到另一个顶点都有一条有向路径

字符串数语言

  • 字母表:任意一个又穷集合
  • 字母表的成员:是该字母表的符号,记作Σ\SigmaΓ\Gamma

例:

Σ1=0,1\Sigma_1 = \begin{vmatrix} 0, & 1 \end{vmatrix}

Σ1=a,b,c,,z\Sigma_1 = \begin{vmatrix} a, & b, & c, & \cdots, & z \end{vmatrix}

Σ1=0,1\Sigma_1 = \begin{vmatrix}0, & 1\end{vmatrix},则01001Σ1\Sigma_1上的一个字符串

  • 长度:字符串包含的符号数
  • 空串:长度为0的字符串
  • 反转:按照相反的顺序写源字符串所得到的字符串,记作wRw^R
  • 子串:如果字符串zz连续出现在ww中,则zzww的子串
  • 连结:设xxyy为字符串,把yy附加在xx后面为连结,记作xyxy
  • 自身连结:记作xkx^k,记为自身连结kk
  • 字符串的字典序:同字母表顺序

布尔逻辑

布尔逻辑是建立在两个值TrueFalse的数学体系,TrueFalse称为布尔值

运算:

  • 或非NOT运算
    • ¬1=0\neg 1 = 0
    • ¬0=1\neg 0 = 1
  • 合并或AND运算\wedge
  • 析取或OR运算\vee

其他布尔运算:

  • 异或或者XOR运算\oplus
  • 等值运算\leftrightarrow
  • 蕴涵运算\rightarrow

AND,OR分配律:

  • P(QR)==(PQ)(PR)P \wedge (Q \vee R) == (P \wedge Q) \vee (P \wedge R)
  • P(QR)==(PQ)(PR)P \vee (Q \wedge R) == (P \vee Q) \wedge (P \vee R)

定理、定理和证明

  • 定义:描述我们使用的对象和概念
  • 数学命题:表述某一个对象具有某种心智
  • 证明:一种逻辑
  • 定理:被证明为帧的数学命题
  • 引理:帮助我们证明其他更有意义命题的命题
  • 推论:一个定理或它的证明可以使我们容易得出另外一些有关命题为真的结论

寻找证明

  • PP仅当QQ:若PP为真,则QQ为真,写作PQP \Rightarrow Q
  • PPQQ:若QQ为真,则PP为真,写作PQP \Leftarrow Q
  • PP当且仅当QQ:写作PQP \Leftrightarrow Q

证明的类型

  • 构造性证明
    • 证明方法:说明如何构造这样的对象
  • 反证法
    • 证明方法:假设这个定理为假,然后证明这个假设导致的一个明显错误的结论
  • 归纳法:证明无穷集合的所有元素都有一种特定性质的高级方法
    • 归纳步骤:归纳假设
    • 归纳基础

自动机与语言

确定型有穷自动机

有穷自动机是关于储存量极其有限的计算机的很好的模型。

上图为M1M_1状态图

  • 状态q1,q2,q3q_1, q_2, q_3
  • 起始状态q1q_1
  • 接受状态q2q_2
  • 转移:一个状态指向另外一个状态的箭头
  1. 自动机从左至右一个接一个接受输入串的所有符号
  2. 读取到符号后,M1M_1沿着标有符号的转移从一个状态移动到另一个状态
  3. 读取到最后一个符号后,M1M_1产生它的输出
    • 接受状态:接受
    • 其他状态:拒绝

确定型有穷自动机的形式定义

有穷自动机是一个5元组(Q,Σ,δ,q0,FQ, \Sigma, \delta, q_0, F

  • QQ是一个有穷集合,叫做状态集
  • Σ\Sigma是一个有穷集合,叫做字母集
  • δ\deltaQ×ΣQQ \times \Sigma \rightarrow Q转移函数
  • q0Qq_0 \in Q起始状态
  • FQF \subset Q接受状态集

AA是机器M接受的全部字符串集,称AA是机器MM的语言,记作L(M)=AL(M) = A,称MM识别AAMM接受AA

L(M)=AL(M) = A

  • 一台机器可能接受若干字符串,但是只能识别一个语言
  • 如果机器不接受任何字符串,但它仍然识别一个语言:\varnothing

确定型有穷自动机的数学形式定义

M=(Q,Σ,δ,q0,F)M = (Q, \Sigma, \delta, q_0, F)是一台有穷自动机,w=w1w2wnw=w_1w_2\cdots{}w_n是字母集Σ\Sigma上的一个字符串,如果存在QQ中的状态序列r0,r2,,rnr_0, r_2, \cdots, r_n满足以下条件:

  • r0=q0r_0 = q_0
  • δ(ri,wi+1)=rr+i,i=0,1,,n1\delta(r_i, w_{i+1}) = r_{r+i}, \quad i=0,1,\cdots,n-1
  • rnFr_n \in F

MM接受ww

如果A={wM接受w}A = \lbrace w | M\text{接受}w \rbrace,则称MM识别语言AA
正则语言:如果一个语言被一台有穷自动机识别,则称他是正则语言

非确定性有穷自动机

  • 确定型有穷自动机(DFA):下一个状态是确定的
  • 非确定型有穷自动机(NFA):下一个状态是不确定的
  • 一个状态对于字母表中的每一个符号可能有0个,1个或多个射出的箭头
  • 箭头可以标记字母表中的符号或ε\varepsilon空字符串
  • 遇到多种选择,机器将分裂(出一个备份),形成类似多线程
  • 如果下一个输入符号不出现在她所处的状态射出的任何箭头上,此分支废弃
  • 如果机器的某一个备份(分支)处于接受状态,则NFA接受输入串
  • 如果遇到射出箭头有ε\varepsilon,机器不读取输入,分裂为多个备份
    • 每一个标记ε\varepsilon的射出箭头有一个备份跟踪(ε\varepsilon指向的状态)
    • 有一个备份停留在当前状态
    • 然后和之前一样的多线程的方式继续执行

每一台NFA能够转换成一台等价的DFA

非确定型有穷自动机的形式定义

  • 在NFA在,转移函数取一个状态和一个输入符号,产生下一个状态的集合
    • 引入形式符号P(Q)P(Q)QQ的所有子集组成的集合,称P(Q)P(Q)是Q的幂集
  • 对于任意字母表Σ\Sigma,把Σ{ε}\Sigma \cup \lbrace \varepsilon \rbrace,记作Σε\Sigma_\varepsilon
  • 转移函数:δ:Q×ΣεP(Q)\delta: Q \times \Sigma_\varepsilon \rightarrow P(Q)

非确定型有穷自动机是一个5元组(Q,Σ,δ,q0,FQ, \Sigma, \delta, q_0, F

  • QQ是一个有穷集合,叫做状态集
  • Σ\Sigma是一个有穷集合,叫做字母集
  • δ\deltaQ×ΣεP(Q)Q \times \Sigma_\varepsilon \rightarrow P(Q)转移函数
  • q0Qq_0 \in Q起始状态
  • FQF \subset Q接受状态集

非确定型有穷自动机的数学形式定义

N=(Q,Σ,δ,q0,F)N = (Q, \Sigma, \delta, q_0, F)是一台NFA,w=y1y2ynw=y_1y_2\cdots{}y_n是字母集Σε\Sigma_\varepsilon上的一个字符串,如果存在QQ中的状态序列r0,r2,,rmr_0, r_2, \cdots, r_m满足以下条件:

  • r0=q0r_0 = q_0
  • ri+1δ(ri,yi+1)=rr+i,i=0,1,,m1r_{i+1} \in \delta(r_i, y_{i+1}) = r_{r+i}, \quad i=0,1,\cdots,m-1
  • rmFr_m \in F

NN接受ww

NFA与DFA的等价性

定理:确定型和非确定型有穷自动机识别相同的语言类,如果两台机器识别相同的语言,则称他们是等价

  • 每一台非确定型有穷自动机都有一台等价的确定型有穷自动机
  • kk是NFA的状态数,它有2k2^k个状态子集,所以DFA也有2k2^k个状态子集

N=(Q,Σ,δ,q0,F)N = (Q, \Sigma, \delta, q_0, F)是识别语言A的NFA,假设NN没有ε\varepsilon箭头

  • 构造M=(Q,Σ,δ,q0,F)M = (Q, \Sigma, \delta, q_0, F)
    • Q=P(Q)Q' = P(Q)
  • MM的每一个状态是NN的一个状态子集,P(Q)P(Q)QQ的所有子集组成的集合
    • 对于RQR \in Q'aΣa \in \Sigma,令δ(R,a)={qQ}\delta'(R, a) = \lbrace q \in Q \rbrace存在rRr \in R,使得qδ(r,a)q \in \delta(r, a)
    • 如果RRMM的一个状态,则他是NN的一个状态子集,也可以写成

δ(R,a)=rRδ(r,a)\delta'(R, a) = \bigcup_{r \in R} \delta(r, a)

  • q0={q0}q'_0 = \lbrace q_0 \rbrace
    • MM开始时所在的状态对应于只含NN的起始状态的集合
  • F={RQR包含N的一个接受状态}F' = \lbrace R \in Q' | R \text{包含N的一个接受状态} \rbrace

考虑ε\varepsilon的情况
引入一个记号,对于MM的任意一个状态RR,定义E(R)E(R)为从RR出发只沿着ε\varepsilon箭头可以到达的状态集合,包括RR本身。对于RQR \subseteq Q,令

E(R)={qR出发的沿着0个或多个ε箭头可以达到q}E(R) = \lbrace q | \text{从}R\text{出发的沿着}0\text{个或多个}\varepsilon\text{箭头可以达到}q \rbrace

为了达到沿着ε\varepsilon箭头的所有状态,用E(δ(r,a))E(\delta(r,a))代替δ(r,a)\delta(r,a)

δ(R,a)={qQrRQE(δ(r,a))}\delta'(R, a) = \lbrace q \in Q | \exists r \in R \rightarrow Q \in E(\delta(r, a)) \rbrace

同时,对于起始状态,把q0q_0'改为E({q0})E(\lbrace q_0 \rbrace)符合要求。


定理:一个语言时正则的,当且仅当有一台非确定型有穷自动机识别它

NFA转换DFA给过程

  • kk是NFA的状态数,它有2k2^k个状态子集,所以DFA也有2k2^k个状态子集

{,{1},{2},{3},{1,2},}\lbrace \varnothing, \lbrace 1 \rbrace, \lbrace 2 \rbrace, \lbrace 3 \rbrace, \lbrace 1,2 \rbrace, \cdots \rbrace

  • 接受状态集是DFA的所有包含接收状态的状态子集
  • 确定DFA的转移函数
    • 对于每一个字符串,遍历所有状态的输入和输出
      • 状态xx遇到aayy,则xa{y}x \xrightarrow{\quad a \quad} \lbrace y \rbrace
      • 状态xx遇到aay,zy, z,则xa{y,z}x \xrightarrow{\quad a \quad} \lbrace y, z \rbrace
      • 状态xx遇到aa没有输出,则xax \xrightarrow{\quad a \quad} \varnothing
      • 状态xx遇到aayy,状态yy遇到aazz,则{x,y}a{y,z}\lbrace x, y \rbrace \xrightarrow{\quad a \quad} \lbrace y, z \rbrace
    • DFA中对于没有射入状态,可以删除进行简化

正则语言

AABB是两个语言,定义正则运算

  • AB={x  xAxB}A \cup B = \lbrace x\ |\ x \in A \text{或} x \in B \rbrace
  • 连结AB={xy  xAxB}A \circ B = \lbrace xy\ |\ x \in A \text{且} x \in B \rbrace
  • 星号A={x1x2xk  k0且每一个xiA}A^* = \lbrace x_1x_2\cdots x_k\ |\ k \geq 0\text{且每一个}x_i \in A \rbrace

正则语言的并运算

定理:正则语言类在并运算下封闭

N1N_1识别A1A_1N2N_2识别A2A_2,其中

N1={Q1,Σ,δ1,q1,F1}N2={Q2,Σ,δ2,q2,F2}\begin{aligned} N_1 &= \{Q_1, \Sigma, \delta_1, q_1, F_1\} \\ N_2 &= \{Q_2, \Sigma, \delta_2, q_2, F_2\} \end{aligned}

构造识别A1A2A_1 \cup A_2NN

N=(Q,Σ,δ,q0,F)N = (Q, \Sigma, \delta, q_0, F)

  • QQN1N_1N2N_2的所有状态Q1Q2{q0}Q_1 \cup Q_2 \cup \lbrace q_0 \rbrace
    • q0q_0N1N_1N2N_2的开始状态
  • qqq0q_0
  • FFF1F2F_1 \cup F_2
  • 定义δ\delta如下,对每一个qQq \in Q和每一个aΣεa \in \Sigma_\varepsilon,令

δ(q,a)={δ1(q,a),qQ1δ2(q,a),qQ2{q1,q2},q=q0,a=ε,q=q0,aε\delta(q, a) = \begin{cases} \delta_1(q,a), &\text{若}q \in Q_1 \\ \delta_2(q,a), &\text{若}q \in Q_2 \\ \lbrace q_1, q_2 \rbrace, &\text{若}q = q_0, \text{且} a = \varepsilon \\ \varnothing, &\text{若}q = q_0, \text{且} a \neq \varepsilon \end{cases}

正则语言的连结运算

定理:正则语言类在连结运算下封闭

设两台NFA,N1N_1识别A1A_1N2N_2识别A2A_2,其中

N1={Q1,Σ,δ1,q1,F1}N2={Q2,Σ,δ2,q2,F2}\begin{aligned} N_1 &= \{Q_1, \Sigma, \delta_1, q_1, F_1\} \\ N_2 &= \{Q_2, \Sigma, \delta_2, q_2, F_2\} \end{aligned}

构造识别ABA \circ BNN

N={Q,Σ,δ,q,F}N = \{Q, \Sigma, \delta, q, F\}

  • QQN1N_1N2N_2的所有状态Q1Q2Q_1 \cup Q_2
  • qqN1N_1的起始状态q1q_1
  • FFN2N_2的接受状态集F2F_2
  • 定义δ\delta如下,对每一个qQq \in Q和每一个aΣεa \in \Sigma_\varepsilon,令

δ(q,a)={δ1(q,a),qQ1,qF1δ1(q,a),qF1,aεδ1(q,a){q2},qF1,a=εδ2(q,a),qQ2\delta(q, a) = \begin{cases} \delta_1(q,a), &\text{若}q \in Q_1, \text{且}q \notin F_1 \\ \delta_1(q,a), &\text{若}q \in F_1, \text{且}a \neq \varepsilon \\ \delta_1(q,a) \cup \lbrace q_2 \rbrace, &\text{若}q \in F_1, \text{且}a = \varepsilon \\ \delta_2(q,a), &\text{若}q \in Q_2 \end{cases}

正则语言的星号运算

定理:正则语言类在星号运算下封闭

N1=(Q1,Σ,δ1,q1,F1)N_1 = (Q_1, \Sigma, \delta_1, q_1, F_1)识别A1A_1,构造识别AA^*N=(Q,Σ,δ,q0,F)N=(Q, \Sigma, \delta, q_0, F)

  • QQQ1{q0}Q_1 \cup \lbrace q_0 \rbrace
    • q0q_0:新的起始状态
  • qqq0q_0
  • FF{q0}F1\lbrace q_0 \rbrace \cup F_1
  • 定义δ\delta如下,对每一个qQq \in Q和每一个aΣεa \in \Sigma_\varepsilon,令

δ(q,a)={δ1(q,a),qQ1,qF1δ1(q,a),qF1,aεδ1(q,a){q1},qF1,a=ε{q1},q=q0,a=ε,q=q0,aε\delta(q, a) = \begin{cases} \delta_1(q,a), &\text{若}q \in Q_1, \text{且}q \notin F_1 \\ \delta_1(q,a), &\text{若}q \in F_1, \text{且}a \neq \varepsilon \\ \delta_1(q,a) \cup \lbrace q_1 \rbrace, &\text{若}q \in F_1, \text{且}a = \varepsilon \\ \lbrace q_1 \rbrace, &\text{若}q = q_0, \text{且}a = \varepsilon \\ \varnothing, &\text{若}q = q_0, \text{且}a \neq \varepsilon \end{cases}

正则表达式

利用正则运算符构造描述语言的表达式,称作正则表达式,例如

(01)0=(01)0\begin{aligned} (0 \cup 1)& 0^* \\ = (0 \cup 1)& \circ 0^* \end{aligned}

这里的正则表达式可以理解为匹配的正则表达式

  • Σ\Sigma:描述该字母表上所有长度为1的字符串组成的语言
  • Σ\Sigma^*:描述该字母表上所有字符串组成的语言
  • Σ1\Sigma^*1:包含所有以11结尾的字符串的语言
  • (0Σ)(Σ1)(0 \Sigma^*)\cup(\Sigma^*1):包含所有以00开始或者以11结尾的字符串的语言

正则表达式运算

  • aa=aa \cup a = a
  • ab=baa \cup b = b \cup a
  • a=aa=(a)=aaa^* = a^*a^* = (a^*)^* = a \cup a^*
  • a=εa=εaa=(εa)a^* = \varepsilon \cup a^* = \varepsilon \cup aa^* = (\varepsilon \cup a)^*
  • (ab)=(ba)(a \cup b)^* = (b \cup a)^*
  • (ab)=(ab)=(ab)(a \cup b)^* = (a^* \cup b^*)^* = (a^*b^*)^*
  • (ab)=(ab)a=a(ba)(a \cup b)^* =(a^*b^*)^*a^* = a^*(ba^*)^*
  • (ab)=(ab)a(a \cup b)^* = (a \cup b)^* \cup a

  • (ab)ab(a \cup b)^* \neq a^* \cup b^*
  • (ab)ab(a \cup b)^* \neq a^*b^*

正则表达式的形式定义

RR是一个正则表达式,如果RR

  • aa,这里aa是字母表Σ\Sigma中的一个元素
  • ε\varepsilon{ε}\lbrace \varepsilon \rbrace,空串
  • \varnothing:空语言
  • (R1R2)(R_1 \cup R_2),这里R1R_1R2R_2是正则表达式
  • (R1R2)(R_1 \circ R_2),这里R1R_1R2R_2是正则表达式
  • (R1)(R_1^*),这里R1R_1是正则表达式

这里使用R1R_1R2R_2定义RR,其中R1R_1R2R_2总是比RR要小,类似一种递归,这样的叫做归纳定义
表达式可以省去括号,计算顺序:

  1. 星号
  2. 连结

一些较为特殊的正则表达式

  • (ΣΣ)(\Sigma\Sigma)*{ww是偶长度的字符串}\lbrace w|w\text{是偶长度的字符串}\rbrace
  • 11*\varnothing\varnothing
  • \varnothing^*{}\lbrace \varnothing \rbrace
  • R=RR \cup \varnothing = R
  • Rε=RR \circ \varepsilon = R
  • RεR \cup \varepsilon不一定等于RR
  • RR \circ \varnothing不一定等于RR

程序设计语言中基本对象叫做单字,如变量名和长了,他们可以用正则表达式描述

  • 只要程序设计语言中单字的语法用正则表达式描述出来,自动系统能够生成词法分析程序
  • 这个是编译程序的一部分,用在开始阶段处理输入程序

正则表达式与有穷自动机的等价性

正则表达式和有穷自动机的描述能力是等价的

  • 定理:一个语言是正则的,当且仅当可以用正则表达式描述它
  • 引理:如果一个语言可以用正则表达式描述,则它是正则的

RR转换成一台NFANN,需要考虑6种情况

  • R=aR = a,这里aΣa \in \Sigma,那么L(R)={a}L(R) = \lbrace a \rbrace
            graph LR
            id1(( )) --a--> id2((接受));
          
  • R=εR = \varepsilon,那么L(R)={ε}L(R) = \lbrace \varepsilon \rbrace
            graph LR
            id1((接受));
          
  • R=R = \varnothing,那么L(R)={}L(R) = \lbrace \varnothing \rbrace
            graph LR
            id1((接受));
          
  • R=R1R2R = R_1 \cup R_2
  • R=R1R2R = R_1 \circ R_2
  • R=R1R = R_1^*

证明:

广义非确定型有穷自动机:记作GNFA,即非确定型有穷自动机,但是转移箭头上可以使用任何正则表达式

  • 起始状态有射到其他每一个状态的箭头,但是没有从任何其他状态射入的箭头
  • 唯一的一个接受状态,并且它有从其他每一个状态射入的箭头,但是没有射到任何其他状态的箭头
  • 接受状态与起始状态不同
  • 初起始状态和接收状态之外,每一个状态到自身和其他每一个状态都有一个箭头

为了把DFA转化为GNFA,添加一个新的起始状态和一个新的接受状态

            graph LR
            3状态DFA --> 5状态GNFA;
5状态GNFA --> 4状态GNFA;
4状态GNFA --> 3状态GNFA;
3状态GNFA --> 2状态GNFA;
2状态GNFA --> 正则表达式;
          
  • 当状态数k>2k>2时,构造等价的少一个状态的GNFA
    • 挑选一个状态(非起始和接受),把它(qripq_{rip})从机器上删掉
    • 修改留下来的部分使其仍然识别相同的语言
            graph LR
            id1((q_i)) --R4--> id2((q_j));
id1((q_i)) --R1--> id3((q_rip));
id3((q_rip)) --R3--> id2((q_j));
id3((q_rip)) --R2-->id3((q_rip));
          

可以转化为

qi(R1)(R2)(R3)(R4)qjq_i \xrightarrow[(R_1)(R_2)*(R_3)\cup(R_4)]{} q_j

广义非确定型有穷自动机

(Q,Σ,δ,qstart,qaccept)(Q, \Sigma, \delta, q_{start}, q_{accept})是一个5元组,其中

  • QQ是一个有穷集合
  • Σ\Sigma是输入字母表
  • δ\delta(Q{qaccept})×(Q{qstart})R(Q - \lbrace q_{accept} \rbrace) \times (Q - \lbrace q_{start} \rbrace) \rightarrow R是转移函数
  • qstartq_{start}是起始状态
  • qacceptq_{accept}是接受状态

如果字符串ww可以写成w=w1w2w3wk,wiΣw = w_1w_2w_3\cdots w_k, w_i \in \Sigma^*,且存在状态序列q0,q1,,qkq_0,q_1,\cdots,q_k,使得

  • q0=qstartq_0 = q_{start}是起始状态
  • qk=qacceptq_k = q_{accept}是接受状态
  • i,wiL(Ri)\forall i, w_i \in L(R_i),其中Ri=δ(qi1,qi)R_i = \delta(q_{i-1}, q_i),换句话说,RR是从qi1q_{i-1}qiq_i的箭头上的表达式

则称这台GNFA接受字符串ww

DFA转换GNFA算法

GNFAGNFA \rightarrow正则表达式,这个递归算法CONVERT(G)可以表示为

  1. kkGG的状态数
  2. 如果k=2k = 2,则GG一定是由一个起始状态,一个接受状态及连接这两个状态的箭头组成,返回这个箭头上的表达式
  3. 否则添加一个新的起始状态和接受状态
  4. 如果k>2k > 2,则任取一个状态qripQ{qstart,qaccept}q_{rip} \in Q - \lbrace q_{start}, q_{accept} \rbrace
  • GG'GNFA(Q,Σ,δ,qstart,qaccept)GNFA(Q', \Sigma, \delta', q_{start}, q_{accept})
  • Q=Q{qrip}Q' = Q - \lbrace q_{rip} \rbrace

且对每一个qiQ{qaccept}q_i \in Q' -\lbrace q_{accept} \rbrace和每一个qjQ{qaccept}q_j \in Q' -\lbrace q_{accept} \rbrace,令

δ(qi,qj)=(R1)(R2)(R3)(R4)\delta'(q_i, q_j) = (R_1)(R_2)*(R_3)\cup (R_4)

其中

  • R1=δ(qi,qrip)R_1 = \delta(q_i, q_{rip})
  • R2=δ(qrip,qrip)R_2 = \delta(q_{rip}, q_{rip})
  • R3=δ(qrip,qj)R_3 = \delta(q_{rip}, q_j)
  • R4=δ(qi,qj)R_4 = \delta(q_i, q_j)

计算CONVERT(G)CONVERT(G'),并且返回这个值

非正则语言

泵引理

语言种的所有字符串只要它的长度不小于某一个特定的值 - 泵长度,就可以被抽取

意思是:每一个这样的字符串都包括一段字串,把这段字串重复任意次,得到的字符串仍在这个语言种


AA是一个正则语言,则存在一个数pp(泵长度)使得,如果ssAA中任一长度不小于p的字符串,那么ss可以被分为33段,s=xyzs = xyz,且满足下述条件

  • 对每一个i0,xyizAi \geq 0, xy^iz \in A
  • y>0|y| > 0yεy \neq \varepsilon
  • xyq|xy| \leq qxxyy两段在一起的长度不超过pp

s|s|表示字符串的长度,yiy^iiiyy连接在一起,y0y^0等于ε\varepsilon,当ss被划分为xyzxyz时,z,xz,x可以是ε\varepsilon

上下文无关语言

这是一种能力更强的描述语言的方法,这种文法能够描述某些具有递归结构的特征

上下文无关语法

A0A1ABB#\begin{aligned} A \rightarrow 0A1 \\ A \rightarrow B \\ B \rightarrow \# \end{aligned}

  • 一个文法由一组替换规则组成
  • 替换规则也叫做产生式
    • 每一个规则占一行
    • 一个符号一个字符串构成
    • 符号和字符串之间用一个箭头隔开:符号字符串\text{符号} \rightarrow \text{字符串}
    • 变元:即符号,常用大学字母表示
    • 字符串:由变元和终结符组成
    • 起始变元:通常出现在第一条规则的左边

如果用语法生成每一个字符串

  • 写下起始变元,一般来说是第一条规则左边的变元
  • 去一个写下的变元,找到以该变元开始的规则,把这个变元替换成这条规则右边的字符串
  • 重复上步骤,直到没有变元

A0A100A11000A111000B111000#111A \Rightarrow 0A1 \Rightarrow 00A11 \Rightarrow 000A111 \Rightarrow 000B111 \Rightarrow 000\#111

上下文无关语言:能够用上下文无关文法生成的语言(CFL),用L(G1)L(G_1)表示文法G1G_1的语言
对几个左边变元相同的规则采用缩写的形式,比如

{A0A1ABA0A1B\begin{cases} A \rightarrow 0A1 \\ A \rightarrow B \end{cases} \Rightarrow A \rightarrow 0A1|B

符号"|“表示"或”

上下文无关文法的形式定义

上下文无关文法是一个4元组(V,Σ,R,S)(V, \Sigma, R, S),这里

  • VV:一个有穷集合,称作变元集
  • Σ\Sigma:一个与VV不相交的有穷集合,称作终结符集
  • RR:一个有穷的规则集,每一条规则是一个变元一个由变元和终结符组成的字符串
  • SVS \in V:起始变元

AwA \rightarrow w是文法的一条规则,称uAvuAv生成uwvuwv,记作uAvuwvuAv \Rightarrow uwv
如果u=vu = v,或者存在序列u1,u2,,uku_1, u_2, \cdots, u_k,使得

uu1u2ukvu \Rightarrow u_1 \Rightarrow u_2 \Rightarrow \cdots \Rightarrow u_k \Rightarrow v

其中k0k \geq 0,则记作uvu \overset{*}{\Rightarrow} v,该文法的语言是{wΣSw}\lbrace w \in \Sigma^* | S \overset{*}{\Rightarrow} w \rbrace

设计上下文无关文法

  • 许多CFG是由几个较简单的CFG合并成的
    • CFG是由几个较简单的部分,可以把它拆分成几部分,再分别构成每一部分
    • 只需要把他们的规则都放在一起,再加入新的规则SS1S2SkS \rightarrow S_1 | S_2 | \cdots | S_k,其中SiS_i是起始变元

例如:{0n1nb0}{1n0nn0}\lbrace 0^n1^n | b \geq 0 \rbrace \cup \lbrace 1^n0^n | n \geq 0 \rbrace

SS1S2S10S11εS21S20ε\begin{aligned} S &\rightarrow S_1|S_2 \\ S_1 &\rightarrow 0S_11|\varepsilon \\ S_2 &\rightarrow 1S_20|\varepsilon \end{aligned}

如果这个语言是正则的

  • 先构造DFA,再构造CFG
    • 对于DFA的每一个状态qiq_i,设一个变元RiR_i
    • 如果δ(qi,a)=qj\delta(q_i, a) = q_j是DFA中的一个转移,则把规则RiaRjR_i \rightarrow aR_j加入CFG
    • 如果qiq_i是DFA的接收状态,则把规则RiεR_i \rightarrow \varepsilon加入CFG
    • q0q_0是DFA的起始状态,则取R0R_0作为CFG的起始变元。

歧义性

有时候一个文法能够用几种不同的方式产生同一个字符串,这样的结构可能是某些情况下不希望看到的,例如:程序设计语言希望给定程序应该有唯一的解释

如果字符串ww在上下文无关文法GG中有两个或两个以上不同的最左派生,则称在GG歧义地生产字符串ww,如果一个文法GG歧义地产生某一个字符串,则称这个文法是歧义的

  • 某些时候能够找到一个产生相同语言的非歧义文法
  • 某些只能使用歧义文法产生,称作固有歧义

乔姆斯基范式

最简单,最有用的形式叫做乔姆斯基范式
一个上下文无关语法为乔姆斯基范式,如果它的每一个规则具有如下形式:

ABCAa\begin{aligned} A &\rightarrow BC \\ A &\rightarrow a \end{aligned}

  • aa:任意的终结符
  • A,B,CA,B,C:任意的变元,但是B,CB,C不能是起始变元
  • 允许规则SεS \rightarrow \varepsilon,其中SS是起始变元

任一上下文无关语言都可以用乔姆斯基范式的上下文无关文法产生

转换乔姆斯基范式算法

  • 添加一个新的起始变元S0S_0和规则S0SS_0 \rightarrow SSS是原来的起始变元
  • 考虑所有的ε\varepsilon的规则
    • 删除一条ε\varepsilon规则AεA \rightarrow \varepsilonAA不是起始变元
    • 然后对规则右边出现的每一个AA,删除这个A然后得到一条新规则(原规则不删去)
      • RuAR \rightarrow uA,则添加规则RuR \rightarrow u
      • RAvR \rightarrow Av,则添加规则RvR \rightarrow v
      • RuAvR \rightarrow uAv,则添加规则RuvR \rightarrow uv
      • RuAvAwR \rightarrow uAvAw,则添加规则RuvAwR \rightarrow uvAwRuAvwR \rightarrow uAvwRuvwR \rightarrow uvw
      • 如果有规则RAR \rightarrow A,则添加RεR \rightarrow \varepsilon
        • 除非前面已经删除过规则RεR \rightarrow \varepsilon
        • 即使这个RR是起始变元,也照样添加S0εS_0 \rightarrow \varepsilon
    • 重复进行上述步骤,直到删除所有不包括起始变元的ε\varepsilon规则
  • 处理所有单一规则
    • 删除一条单一规则ABA \rightarrow BAA可以是起始变元
    • 然后对规则左边出现的每一个BB
      • 只要有一条规则BuB \rightarrow u,就要添加规则AuA \rightarrow u,且不删除BuB \rightarrow u
      • 除非AuA \rightarrow u是在前面被删除的单一规则
      • uu是变元和终结符的字符串
    • 重复进行上述步骤,直到删除所有单一规则
  • 把所有留下的规则转换成适当的形式
    • 对每一个长度k3k \geq 3的字符串u1u2uku_1u_2\cdots u_k,进行以下操作
      • 把每一条规则Au1u2ukA \rightarrow u_1u_2\cdots u_k替换成规则Au1A1, A1u2A2, A2u3A3, ,Ak2uk1ukA \rightarrow u_1A_1,\ A_1 \rightarrow u_2A_2,\ A_2 \rightarrow u_3A_3,\ \cdots, A_{k-2} \rightarrow u_{k-1}u_k
      • 例如:S0ASAS_0 \rightarrow ASA,变为S0AA1S_0 \rightarrow AA_1A1SAA_1 \rightarrow SA
      • 每一个uiu_i是一个变元或终结符,AiA_i是新的变元
    • 重复上步骤,直到没有长度k3k \geq 3的字符串

至此,所有规则只能是以下几种形式

  • S0εS_0 \rightarrow \varepsilon
  • AaiA \rightarrow a_i
  • ABCA \rightarrow BC
  • AaiBA \rightarrow a_iB
  • ABaiA \rightarrow Ba_i
  • AaiajA \rightarrow a_ia_j

其中ai,aja_i,a_j是终结符,A,B,CA, B, C是变元,S0S_0是开始阶段引入的新起始变元
为了把后三种转换成符合要求的规则

  • 对每一个终结符aia_i引入一个新变元UiU_i和规则UiaiU_i \rightarrow a_i
  • 如果aia_i不出现在规则的右边,则不需要引入
  • 把后3种规则分别替换成

AaiBABaiAaiajAUiBABUiAUiUj\begin{aligned} A &\rightarrow a_iB \\ A &\rightarrow Ba_i \\ A &\rightarrow a_ia_j \end{aligned} \Rightarrow \begin{aligned} A &\rightarrow U_iB \\ A &\rightarrow BU_i \\ A &\rightarrow U_iU_j \end{aligned}

至此,所有的式子都应该只是以下形式

S0εAaiABC\begin{aligned} S_0 &\rightarrow \varepsilon \\ A &\rightarrow a_i \\ A &\rightarrow BC \end{aligned}

下推自动机

这种机器(PDA)非常像非确定型有穷自动机,但是有,使之能够识别一些非正则语言

  • 下推自动机在能力上与上下文无关文法等价
  • 下推自动机能够把符合写到栈上,然后再读取它
    • 写一个符合,把栈种其他的所有符合"下推"
    • 在任何时候,可以读和删去栈顶的符号,其余符号向上移动
    • 在栈上写一个符号,叫做"推入"这个符号
    • 删去一个符号叫做弹出
    • 无论是读,写,都只能在栈顶进行,遵循”先进后出

下推自动机的形式定义

下推自动机(PDA)是一个6元组(Q,Σ,Γ,δ,q0,F)(Q, \Sigma, \Gamma, \delta, q_0, F),这里QQΣ\SigmaΓ\GammaFF都是有穷集合

  • QQ:状态集
  • Σ\Sigma:输入字母表
  • Γ\Gamma:栈字母表
  • δ\deltaQ×Σε×ΓεP(Q×Γε)Q \times \Sigma_\varepsilon \times \Gamma_\varepsilon \rightarrow \mathcal{P}(Q \times \Gamma_\varepsilon)
  • q0Qq_0 \in Q:起始状态
  • FQF \subset Q:接受状态集

一台下推自动机M=(Q,Σ,Γ,δ,q0,F)M=(Q, \Sigma, \Gamma, \delta, q_0, F)的计算如下

  • 接受输入ww
  • 如果能够把ww写成w=w1,w2,,wm,(wiΣε)w=w_1, w_2, \cdots, w_m,(w_i \in \Sigma_\varepsilon)
  • 并且存在状态序列r0,r1,,rmQr_0, r_1, \cdots, r_m \in Q和字符串序列s0,s1,,smΔs_0, s_1, \cdots, s_m \in \Delta^*满足下述3个条件,则字符串s0,s1,,sms_0, s_1, \cdots, s_mMM在计算的接受分支中的栈内容序列
    • r0=q0r_0 = q_0s0=εs_0 = \varepsilon,表示MM从起始状态和空栈开始
    • 对于i=0,,m1,(ri+1,b)δ(ri,wi+1,a)i = 0, \cdots, m - 1, (r_{i+1}, b) \in \delta(r_i, w_{i+1}, a),其中si=at,si+1=bt,(a,bΣε)s_i = at, s_{i+ 1}= bt, (a, b \in \Sigma_\varepsilon)tΣt \in \Sigma^*,该条表示MM在每一步都完全按照当时的状态,栈顶符号和下一个输入符号动作
    • rmFr_m \in F,该条说明在输入结束时出现一个接受状态

下推自动机运作

  • a,bca, b \rightarrow c表示当机器从输入中读到aa时可以用cc替换栈顶的符号bb
    • a,b,ca, b, c中任何一个都可以是ε\varepsilon
    • 如果aaε\varepsilon,则机器做这个转移,而不读输入中的任何符号
    • 如果bbε\varepsilon,则机器做这个转移,而不读栈中的任何符号
    • 如果ccε\varepsilon,则机器做这个转移,而不在栈中写任何符号

检测空栈的方法:
PDA的形式定义没有提供检验空栈的直接手段,但是如果在PDA一开始把一个特殊符号放入栈中,每当机器看见@时,就知道栈实际上是空了

q1ε,ε$q2\color{blue}q_1\color{black} \xrightarrow{\varepsilon, \varepsilon \rightarrow \$} q_2

检测输入达到末端:
PDA不能直接检测到达输入的末端,但是可以使PDA当只有它位于输入的末端时,接受状态才起作用,这样就可以实现同样的效果。

q1ε,$εq2q_1 \xrightarrow{\varepsilon, \$ \rightarrow \varepsilon} \color{green}q_2

  • c,εcc, \varepsilon \rightarrow c:读取到cc,则在栈中写入cc
  • c,cεc, c \rightarrow \varepsilon:读取到cc,则在栈中弹出cc

a,bca,b \rightarrow c能被执行的条件为:当读取到aa,且栈顶是bb的时候才能执行

下推自动机与上下文无关文法的等价性

它们都能够描述上下文无关语言类

定理:一个语言是上下文无关的,当且仅当存在一台下推自动机识别他
引理:一个语言是上下文无关的,则存在一台下推自动机识别他

上下文无关文法转下推自动机

AA是上下文无关语言,则存在一个上下文无关文法GG产生它,我们需要把GG转换为等价的PDA,称为PP


设上下文无关文法CFG为G=(V,Σ,R,S)G=(V, \Sigma, R, S),下推自动机P=(Q,Σ,Γ,δ,qstart,F)P=(Q, \Sigma, \Gamma, \delta, q_{start}, F),其中

  • 输入字母表Σ\Sigma就是GG的终结字符
  • 栈字母表Γ\Gamma等于GG的变元集VV

qqrrPP的状态,aa属于Σε\Sigma_\varepsilonbb属于Γε\Gamma_\varepsilon,我们要求PP,当它读aa并且弹出bb时,状态转移从qqrr,并且同时把整个字符串u=u1,u2,,ulu = u_1, u_2, \cdots, u_l推入栈,为了完成这个动作,我们引入新的状态q1,q2,,ql1q_1, q_2, \cdots, q_{l - 1},并且令转移函数

δ(q,a,s)包含(q1,u1)δ(q1,ε,ε)={(q2,ul1)}δ(q2,ε,ε)={(q3,ul2)}δ(ql1,ε,ε)={(r,u1)}\begin{aligned} \delta(q, a, s)&\text{包含}(q_1 ,u_1) \\ \delta(q_1, \varepsilon, \varepsilon) &= \lbrace (q_2, u_{l - 1}) \rbrace \\ \delta(q_2, \varepsilon, \varepsilon) &= \lbrace (q_3, u_{l - 2}) \rbrace \\ &\vdots \\ \delta(q_{l - 1}, \varepsilon, \varepsilon) &= \lbrace (r, u_1) \rbrace \end{aligned}

  • 使用记号(r,u)δ(q,a,s)(r, u) \in \delta(q, a, s)表示当qq是状态,aa是下一个输入符号以及ss是栈顶符号时,PDA PP能够读aa和弹出ss,然后把字符串uu推入栈和转移到状态rr

qa,sxyzrqa,szq1ε,εyq2ε,εxr\begin{aligned} \begin{aligned} &q& \\ &\downarrow& a,s\rightarrow xyz \\ &r& \end{aligned} \quad \Rightarrow \quad \begin{aligned} &q& \\ &\downarrow& a,s\rightarrow z \\ &q_1& \\ &\downarrow& \varepsilon,\varepsilon\rightarrow y \\ &q_2& \\ &\downarrow& \varepsilon,\varepsilon\rightarrow x \\ &r& \end{aligned} \end{aligned}

  • PP的状态集Q={qstart,qloop,qaccept}EQ = \lbrace q_{start}, q_{loop}, q_{accept} \rbrace \cup E,这里EE是实现刚才描述的缩写所需要的状态集合,只有一个接收状态qacceptq_{accept}
  • 庄毅函数定义如下,从初始化开始,把符号@和SS推入栈,实现步骤1的形式描述是:δ(qstart,ε,ε)={(qloop,S@)}\delta(q_{start, \varepsilon, \varepsilon}) = \lbrace (q_{loop}, S@) \rbrace。然后进行步骤2主循环中的转移

首先处理情况(a)(a),这时栈顶是一个变元,令δ(qloop,ε,A)={(qloop,w)}Aw\delta(q_{loop}, \varepsilon, A) = \lbrace (q_{loop}, w) \rbrace A \rightarrow wRR中的一条规则
其次处理情况(b)(b),这时栈顶是一个终结符,令δ(qloop,a,a)={(qloop,ε)}\delta(q_{loop}, a, a) = \lbrace (q_{loop}, \varepsilon) \rbrace
最后处理情况(c)(c),这时栈顶是空栈标记符@,令δ(qloop,ε,@)={(qaccept,ε)}\delta(q_{loop}, \varepsilon, @) = \lbrace (q_{accept}, \varepsilon) \rbrace

qstartε,εS@qloop{ε,Awa,aεε,@εqaccept\begin{aligned} \rightarrow &q_{start} \\ &\downarrow \varepsilon, \varepsilon \rightarrow S@ \\ &q_{loop} \rightleftharpoons \begin{cases} \varepsilon, A \rightarrow w \\ a, a \rightarrow \varepsilon \end{cases} \\ &\downarrow \varepsilon, @ \rightarrow \varepsilon \\ &q_{accept} \end{aligned}

上下文无关文法转下推自动机例子

例子:

SaTbbTTaε\begin{aligned} S &\rightarrow aTb|b \\ T &\rightarrow Ta|\varepsilon \end{aligned}

下推自动机转上下文无关文法

引理:一个语言被一台下推自动机识别,则它是上下文无关的

设PAD PP是一个下推自动机,要构造一个上下文无关文法GG,它产生PP接受的所有字符串

我们设计一个能够做更多事情的文法,对于PP的每一对状态ppqq,文法有一个变元ApqA_{pq},它产生所有能够把PPpp和空栈一块带到qq和空栈的字符串,可以看出不管栈的内容是什么,这样的字符串也能够把PPpp带到qq,并且保持栈的内容在状态qq和在状态pp时一样

先对PP进行一下修改,使得它有下面3个特点

  • 有位移的接收状态qacceptq_{accept}
  • 在接受之间排空栈
  • 每一个转移把一个符号推入栈(推入动作),或者把一个符合弹出栈(弹出动作),但是不能同时做这两个动作

对于特点3,要把每一个同时弹出和推入的转移替换成两个转移,中间要经过一个新的状态,把每一个既不弹出也不推入的转移替换成两个转移,先推入任意一个栈符号,然后再把它弹出。
对于任意一个空栈开始和结束的所有字符串,PP的每一个动作已经是推入或者时弹出但是对空栈不能弹出,所以PPxx的第一个动作一定是推入,同理在结束时,对xx的最后一个动作一定是弹出。
PPxx的计算过程可能出现两种情况

  • 仅在计算的开始和结束时,栈是空的
    • 最后弹出的符号一定就是开始时推入的那个符号:ApqaArsbA_{pq} \rightarrow aA_{rs}b
    • aa:做第一个动作时读的输入符号
    • bb:做最后一个动作时读的输入符号
    • rr是跟在pp后面的状态
    • ssqq前的一个状态
  • 除开始和结束时之外,在计算中的某个地方,栈变成空的
    • ApqAprArqA_{pq} \rightarrow A_{pr}A_{rq}
    • rr:是栈在计算中间变成空的时候的状态

关于GG的规则,设P=(Q,Σ,Γ,δ,q0,{qaccept})P=(Q, \Sigma, \Gamma, \delta, q_0, \lbrace q_{accept} \rbrace)GG的变元集是{Apqp,qQ}\lbrace A_{pq} | p,q \in Q \rbrace,其实变元是Aq0qacceptA_{q_0q_{accept}}

  • 对每一个p,q,r,sQ,tΓp, q, r, s \in Q, t \in \Gammaa,bΣεa, b \in \Sigma_\varepsilon,如果δ(p,a,ε)\delta(p, a, \varepsilon)包含(r,t)(r, t)δ(s,b,t)\delta(s, b, t)包含(q,ε)(q, \varepsilon),则把规则ApqaArsbA_{pq} \rightarrow aA_{rs}b放入GG
  • 对每一个p,q,rQp,q,r \in Q,把规则ApqAprArqA_{pq} \rightarrow A_{pr}A_{rq}放入GG
  • 最后,对每一个pQp \in Q,把规则AppεA_{pp} \rightarrow \varepsilon放入GG
对于规则ApqAprArqA_{pq} \rightarrow A_{pr}A_{rq}的PDA计算 对于规则ApqaArsbA_{pq} \rightarrow aA_{rs}b的PDA计算

下面证明ApqA_{pq}产生xx,当且仅当xx能够把PP从状态pp和空栈一块带到状态qq和空栈,从而证明上述构造是正确的,把当且仅当中的每一方向作为一个单独的断言

  • 断言:如果ApqA_{pq}产生xx,则xx能够把PPpp和空栈一块带到qq和空栈
  • 断言:如果xx能够把PPpp和空栈带到qq和空栈,则ApqA_{pq}产生xx

使用归纳法可以证明上述断言

每一个正则语言是上下文无关的

非上下文无关语言

如果AA是上下文无关语言,则存在数pp(泵长度),使得AA中任何一个长度不小于pp的字符串ss能够划分为55段,s=uvxyzs = uvxyz,满足下述条件

  • 对于每一个iiuvixyizAuv^ixy^iz \in A
  • vy>0|vy| > 0
  • vxyp|vxy| \leq p

ss倍划分为uvxyzuvxyz

  • 条件22:称vvyy不是空串,否则定理自动成立
  • 条件33:称vvxxyy三段在一起的长度不超过pp

丘奇-图灵论题

图灵机

  • 图灵机模型
    • 储存设备:用一个无限长的带子作为无限储存,还有一个读写头,这个读写头只能在带子上读,写和移动
    • 开始:带子上只有输入字符串,其他地方都是空的。
    • 储存:如果需要储存信息,它可能将这个信息写在带子上
    • 读取:为了读取已经写下的信息,它可能将读写头往回移动到这个信息所在的地方
    • 结束:机器不停地计算直到产生输出为止
  • 机器事先就被设置了两种状态
    • 接受状态和拒绝状态,如果进入这两种状态,就产生输出接受或拒绝,
    • 如果不进入任何接受状态或拒绝状态,就继续执行下去,永不停止

有穷自动机和图灵机的区别

  • 图灵机在带子上既能写也能读
  • 读写头既能向左移也能向右移
  • 带子时无限长的
  • 进入拒绝和接收状态将立刻停机

图灵机的形式定义

核心时转移函数δ\deltaQ×ΓQ×Γ×{L,R}Q \times \Gamma \rightarrow Q \times \Gamma \times \lbrace L, R \rbrace

若机器处于状态qq,读写头所在的带方格内包含符号aa,则当δ(q,a)=(r,b,L)\delta(q, a) = (r, b, L)时,机器写下符号bb以取代aa,并进入状态rr。第三个分量时LLRR,他指出在写带之后,读写头时向左还是向右移动

一个图灵机时一个7元组(Q,Σ,Γ,δ,q0,qaccept,qreject)(Q, \Sigma, \Gamma, \delta, q_0, q_{accept}, q_{reject}),其中:Q,Σ,ΓQ, \Sigma, \Gamma都是有穷集合,并且

  • QQ:状态集
  • Σ\Sigma:输入字母表,不包括特殊空白符号\sqcup
  • Γ\Gamma:带字母表,其中Γ,ΣΓ\sqcup \in \Gamma, \Sigma \supset \Gamma
  • δ\deltaQ×ΓQ×Γ×{L,R}Q \times \Gamma \rightarrow Q \times \Gamma \times \lbrace L, R \rbrace是转移函数
  • q0Qq_0 \in Q:起始状态
  • qacceptQq_{accept} \in Q:接受状态
  • qrejectQq_{reject} \in Q:拒绝状态,且qrejectqacceptq_{reject} \neq q_{accept}

其计算方式为

  • 开始:MM以最左边的nn个带方格接受输入w=w1w2wnΣw = w_1w_2\cdot w_n \in \Sigma^*,带的其余部分是空白
  • 读写头从最左边的带方格开始运行,Σ\Sigma不含空白符,则带上出现第一个空白符表示结束
  • 开始运行后,计算根据转移函数所描述的规则进行
  • 如果MM试图将读写头从带的左端点再向左移出,即使转移函数指示是LL,读写头也停在原地不动
  • 计算已知持续到它进入接受或拒绝状态
  • 此时停机,如果二者都不发生,则MM永远运行下去

图灵机的计算过程

格局当前状态当前带内容读写头当前未知会发生变化,这三项构成的整体叫做图灵机的格局

对于状态qq和带字母表上的两个串uuvv,以uqvuqv表示如下格局:

  • 当前状态是qq
  • 当前带内容是uvuv
  • 读写头的当前未知是vv的第一个符号,带上vv的最后符号以后的符号都是空白符

1011q7011111011q_701111

图灵机计算方式形式化

如果图灵机能合法地从格局C1C_1一步进入C2C_2,则称格局C1C_1产生格局C2C_2,这个概念的形式定义如下:

a,ba, bccΓ\Gamma中符号,uuvvΓ\Gamma^*中字符串,qiq_iqjq_j是状态,则uaqibvuaq_ibvuqjacvuq_jacv是两个格局,如果转移函数满足δ(qi,b)=(qj,c,L)\delta(q_i, b) = (q_j, c, L),则

  • 左移情形

uaqibv产生uqjacvuaq_ibv \quad \text{产生} \quad uq_jacv

  • 右移情形

uaqibv产生uacqjvuaq_ibv \quad \text{产生} \quad uacq_jv

  • 左端点
    • 如果转移为向左移动:则格局qibvq_ibv产生qjbvq_jbv(不准移出)
    • 如果转移为向右移动:则格局qibvq_ibv产生bqjvbq_jv
  • 右端点
    • bvqibvq_i等价bvqibvq_i\sqcup,按原来那样处理

其他情况

  • 起始格局:q0wq_0w(表示机器处于起始状态,读写头处于带最左端未知)
  • 接受格局:状态时qacceptq_{accept}
  • 拒绝格局:状态时qrejectq_{reject}
  • 停机状态:接受状态和拒绝状态(不再产生新的格局)

  • q10,Rq2q_1 \xrightarrow{0 \rightarrow \sqcup, R} q_2δ(q1,0)=(q2,,R)\delta(q_1, 0) = (q_2, \sqcup, R)
    • 当状态为q1q_1且读写头读00
    • 机器状态变为q2q_2,写下\sqcup
    • 并向右移动读写头
  • q10Rq2q_1 \xrightarrow{0 \rightarrow R} q_2δ(q1,0)=(q2,0,R)\delta(q_1, 0) = (q_2, 0, R)
    • 当状态为q1q_1且读写头读00
    • 机器状态变为q2q_2不改变带子
    • 并向右移动读写头
  • q10,1Rq2q_1 \xrightarrow{0,1 \rightarrow R} q_2
    • 当状态为q1q_1且读写头读0011
    • 机器状态变为q2q_2不改变带子
    • 并向右移动读写头

图灵机能根据输入,给出输出,并且可以再进行左右移动(不能不移动)

图灵机确定左端点
  • 在开始的时候写下\sqcup,当左移的时候读取到\sqcup时,则已到达左端点
  • 在左移之前记录下当前带上位置的符号,并写下一个特殊符号#,当左移后,当前位置上带子的符号还是#的话,则左移失败,读写头已经在左端点
图灵机作记号

图灵机可以通过做记号达到一些需要记忆位置的操作,比如对于11111# 00000# 111111这样字符串,可以将#改写为˙\dot{\sharp},从而达到做记号的目的

˙\sharp \rightarrow \dot{\sharp}

图灵机接受输入

图灵机接受输入ww,如果存在格局的序列C1,C2,CkC_1, C_2, \cdots C_k使得

  • C1C_1MM再输入ww上的起始格局
  • 每一个CiC_i产生Ci+1C_{i+1}
  • CkC_k是接受格局

MM接受的字符串的全体称为M的语言,即为L(M)L(M)

定义:如果有一个图灵机识别一个语言,则称语言是图灵可识别

在输入上运行一个TM时,可能出现三种结果:接受,拒绝,循环(不停机)
对于一个输入,图灵机有两种方式不接受它:进入拒绝状态,进入循环

定义:称一个语言时图灵可判定的,或简称可判定的

图灵可判定语言都是图灵可识别的,但某些图形可识别语言不是可判定的。

图灵机的变形

图灵机可以进行变形,如:多个带子,非确定性。这样的机器被称为图灵机模型的变形

  • 原来的模型与它的所有合理的变形有着同样的能力
    • 识别同样的语言类
    • 这样变化中的不变性称为稳健性
    • 图灵机有惊人的稳健性

假设图灵机可以在读取后不进行移动,则转移函数会有以下改变

Q×ΓQ×Γ×{L,R}Q×ΓQ×Γ×{L,R,S}\begin{aligned} Q \times \Gamma &\rightarrow Q \times \Gamma \times \lbrace L, R \rbrace \\ Q \times \Gamma &\rightarrow Q \times \Gamma \times \lbrace L, R, S \rbrace \end{aligned}

这个改变不会使图灵机能够识别更多的语言,为了证明两个模型时等价的,只要证明它们能互相模拟即可。

多带图灵机

Q×ΓkQ×Γk×{L,R}kQ \times \Gamma^k \rightarrow Q \times \Gamma^k \times \lbrace L, R \rbrace^k

多带图灵机还是和图灵机等价,虽然多带图灵机有多个带子,可以在单个带子上模拟出多个带子的效果,即用#分割每个带子,且对每个分割的部分多带图灵机读写头的位置的字符加上符号c˙\dot{c},从而达到类似多带图灵机的效果。

非确定性图灵机

定理:每一个非确定性图灵机都有一个与之等价的确定性图灵机

可以用确定性图灵机模拟非确定性图灵机的所有可能的分支,采用广度搜索的方式,若能够在某个分支中发现接受状态,则接受,否则永不停止。

可以由三带图灵机模拟非确定性图灵机,其带子分别为

  • 输入带:不会改变
  • 模拟带:存放非确定性图灵机中的内容,对应其某个分支
  • 地址带:记录确定性图灵机在非确定性图灵机中的位置

推论:一个语言时图灵可识别的,当且仅当有非确定性图灵机识别他
推论:一个语言时图灵是可判定的,当且仅当有非确定性图灵机判定他

枚举类

有时有些地方会使用递归可枚举语言来替代图灵可识别语言,这个术语起源于称为枚举器的机器,是图灵机的一种变形,简单地说,枚举器是带有打印机的图灵机,使其为一个输出设备

定理:一个语言是图灵可识别的,当且仅当有枚举器枚举它

其他模型的等价性

考虑程序设计语言中的类似情形,现在又许多程序设计语言,但是它们都可以实现同一个算法,这意味着这两个语言描述了完全相同的算法类,即计算模型间存在着普遍的等价性。

任意两个满足合理条件的计算模型都能互相模拟,从而在能力上等价

算法的定义

算法的直觉概念等于图灵机算法\boxed{\text{算法的直觉概念} \qquad \text{等于} \qquad \text{图灵机算法}}

上述被称为丘奇-图灵论题,简单的来说,图灵机刻画了所有的算法。

任何计算装置:用算盘的人、超级计算机、你手中的 iPhone 等等,都不能超越图灵机模型的计算能力

算法的描述

  • 形式描述:尽详细写出图灵机的状态,转移函数等, 这是最底层,最详细程度的描述
  • 实现描述:用日常语言描述图灵机的运行,如:如何移动读写头,储存数据,没有给出转移函数等的细节
  • 高水平描述:用日常语言进行描述,但是忽略了实现的模型,不需要提及如何移动带子或读写头

可判定性

有些问题算法上能够求解,而另一些则不能,我们需要研究算法可解性的局限。

可判定语言

一些语言,它们都是算法上可判定的。也叫递归(Recursive)语言

  • 图灵机识别一门语言:当图灵机接受属于这门文法的所有语言且不接受所有不属于这门文法的语言
    • A TM recognizes a language L if it accepts every xLx \in L and does not accept any xLx \notin L
    • A language is recognizable if there is a Turing machine that recognizes it
  • 图灵机判定一门语言:当图灵机接受属于这门文法的所有语言且拒绝所有不属于这门文法的语言
    • A TM decides a language L if it accepts every xLx \in L and it rejectst every xLx \notin L
    • A language is decidable if there is a Turing machine that decides it

定理:一门语言LL是可判定的,当且仅当LLL\overline{L}是课识别的

不可判定语言

下面以一个例子说明不可判定语言,假设存在M_1识别L,M_2识别L’,那么D是否判定L

1
2
3
def D(x):
if M_1(x) accepts: accepts
if M_2(x) accepts: rejects

因为D可能在M_1(x)出循环,所以D不判定L,即M_1(x)可能不会停机


再来一个例子

设语言L={<M>M 停机于 100010}L = \lbrace <M> | M\ \text{停机于}\ 100010 \rbrace

×
LL可识别?
L\overline{L}可识别?

因此LL不可判定


1
2
3
def D(D):
if D(D) accepts: rejects
if D(D) rejects: accepts

以上描述的是Dumaflache

  • 当D接受输入D,则拒绝
  • 当D拒绝输入D,则接受

很明显矛盾

正则语言相关的可判定性问题

因为已经建立了处理语言的术语,将用语言来表示各种计算问题,例如如下的问题

DFA接受问题

检测一个特定的自动机是否接受一个事先给定的串,此类问题可表示为语言ADFAA_{DFA},它包含了DFA及其接受的串的编码,令

ADFA={<B,w>  BDFA, w是串, B接受w}A_{DFA} = \lbrace <B, w>\ |\ B \text{是} DFA,\ w \text{是串},\ B \text{接受} w \rbrace

问题

  • DFA B是否接受输入w
  • <B,w><B, w>是否是ADFAA_{DFA}的元素

是相同的。类似的,其他一些计算问题也可以表示成检查语言的成员隶属关系,证明这个语言是可判定的与证明这个计算问题是可判定是同一回事

定理ADFAA_{DFA}是一个可判定语言

NFA接受问题

ANFA={<B,w>  BNFA, w是串, B接受w}A_{NFA} = \lbrace <B, w>\ |\ B \text{是} NFA,\ w \text{是串},\ B \text{接受} w \rbrace

定理ANFAA_{NFA}是一个可判定语言

REX接受问题

AREX={<R,w>  R是正则表达式, w是串, R派生w}A_{REX} = \lbrace <R, w>\ |\ R \text{是正则表达式},\ w \text{是串},\ R \text{派生} w \rbrace

定理AREXA_{REX}是一个可判定语言

DFA不接受问题

图灵机有关的另一种问题:有穷自动机语言的空性质测试,再以前的定理中,常常必须检查一个有穷自动机是否接受一个特殊的串,在下面的证明中,要检查一个有穷自动机是否根本不接受任何串,令

EDFA={<A>  ADFA, 且L(A)=}E_{DFA} = \lbrace <\text{A}>\ |\ A \text{是} DFA,\ \text{且} L(A) = \varnothing \rbrace

定理EDFAE_{DFA}是一个可判定语言

DFA相同接受问题

检查两个DFA是否识别同一个语言是可判定的,设

EQDFA={<A,B>  AB都是DFA, 且L(A)=L(B)}EQ_{DFA} = \lbrace <A, B>\ |\ A \text{和} B\text{都是} DFA,\ \text{且} L(A) = L(B) \rbrace

定理EDFAE_{DFA}是一个可判定语言

Mapping Reductions

A function f:Σ1Σ2f : \Sigma^*_1 \rightarrow \Sigma^*_2 is called a mapping reduction from A to B iff

  • For any w ∈ Σ1*, w ∈ A iff f(w) ∈ B.
  • f is a computable function.

Intuitively, a mapping reduction from A to B says that a computer can transform any instance of A into an instance of B such that the answer to B is the answer to A.

1
2
3
4
5
H = “On input w:
· Transform the input w into f(w).
· Run machine R on f(w).
· If R accepts f(w), then H accepts w.
· If R rejects f(w), then H rejects w.”

Mapping Reductions相关定理

  • R代表可以用图灵机解决的所有决定型问题问题。
    • 也就是所有递归语言的集合。R也等同于包含所有可计算函数的集合。
  • RE(Recursively Enumerable,参考递归可枚举集合)是一个决定型问题的复杂度类
    • RE也可以视为存在一个将问题里面"yes"的答案一一列举出来的图灵机(也就是这里所说’可枚举的’的意思)。
  • co-RE则是所有RE语言其补集(complement)的总集合。
    • 某种意义上我们可以说,co-RE包含的语言,其里面的问题要证明为错误,只要有限的时间;但是可能要无限的时间,才能证明这问题正确。
  • BRB \in RAMBA \leq_M B,则ARA \in R
  • BREB \in REAMBA \leq_M B,则AREA \in RE
  • BcoREB \in co-REAMBA \leq_M B,则AcoREA \in co-RE
  • 注释: AMBA \leq_M B means “A is not harder than B.”
  • ARA \notin RAMBA \leq_M B,则BRB \notin R
  • AREA \notin REAMBA \leq_M B,则BREB \notin RE
  • AcoREA \notin co-REAMBA \leq_M B,则BcoREB \notin co-RE

上下文无关语言相关的可判定性问题

定理:每个上下文无关语言都是可判定的

CGF派生问题

检查一个CFG是否派生一个特定的串

ACFG={<R,w>  RCFG, w是串, G派生w}A_{CFG} = \lbrace <R, w>\ |\ R \text{是} CFG,\ w \text{是串},\ G \text{派生} w \rbrace

定理ACFGA_{CFG}是一个可判定语言

CGF不派生问题

检查一个CFG是否不派生任何串

ECFG={<G>  GCFG,L(G)=}E_{CFG} = \lbrace <G>\ |\ G \text{是} CFG,\text{且}L(G) = \varnothing \rbrace

定理ECFGE_{CFG}是一个可判定语言

对角化问题

如果两个集合都是无限的,怎么比较它们的相对规模?

定义:设AABB是两个集合,ff是从AABB的函数

  • 如果ff从不将两个不同元素映射到同一个地方,即:只要abf(a)f(b)a \neq b \Rightarrow f(a) \neq f(b),则称ff一对一
  • 如果ff能击中BB的每个元素,即:对BB的每个元素bb,都存在aAa \in A,使得f(a)=bf(a) = b,则称ff到上的
  • 如果存在一对一且到上的函数f:ABf: A \rightarrow B,即是一对一又是到上的函数称为对应,称AABB有相同的规模
关系 对应
一对一 单射
到上的 全射
一对一且到上的 全单射

定义:称一个集合是可数的,如果它是有限的,或者它与N\mathbb{N}有相同的规模
定理R\mathbb{R}是不可数的(xR\exist x \in \mathbb{R}N\mathbb{N}中任何元素都不匹配)
推论:存在语言不是图灵可识别的(有不可数个语言,却只有可数个图灵机)

由于图灵机只能识别一个语言,而语言比图灵机更多,故有些语言不能由任何的图灵机识别,这样的语言就不是图灵可识别的

停机问题

下列语言是不可判定的

ATM={<M,w>  MTM,M接受w}A_{TM} = \lbrace <M, w>\ |\ M \text{是} TM,\text{且} M \text{接受} w \rbrace

HHATMA_{TM}的判定器,令MM是一个TMTMww是一个串,在输入<M,w><M, w>上,如果MM接受ww,则HH就停机且接受ww,如果MM不接受ww,则HH也会停机,但拒绝ww,即

H(<M,w>)={接受如果M接受w拒绝如果M不接受wH(<M, w>) = \begin{cases} \text{接受} & \text{如果}M\text{接受}w \\ \text{拒绝} & \text{如果}M\text{不接受}w \end{cases}

现在构造一个新的图灵机DD,它接受一个图灵机作为输入,调用HH进行判定

D(<M>)={接受如果M不接受w拒绝如果M接受wD(<M>) = \begin{cases} \text{接受} & \text{如果}M\text{不接受}w \\ \text{拒绝} & \text{如果}M\text{接受}w \end{cases}

DD作为输入,传进DD里面运行后,会出现一下矛盾

D(<D>)={接受如果D不接受D拒绝如果D接受DD(<D>) = \begin{cases} \text{接受} & \text{如果}D\text{不接受}D \\ \text{拒绝} & \text{如果}D\text{接受}D \end{cases}

因此DDHH都逻辑上不存在

时间复杂度

定义:令M是一个在所有输入上都停机的确定型图灵机,M的运行时间,或者说时间复杂度,是一个函数f:NNf: \mathcal{N} \rightarrow \mathcal{N},其中f(n)f(n)是M在所有长度上运行时所经过的最大步数。若f(n)f(n)是M的运行时间,则称M在时间f(n)f(n)内运行,M是f(n)f(n)时间图灵机

  • 大O记法:小于等于
  • 小o记法:小于
  • θ\theta记法:等于
  • Ω\Omega记法:大于等于
  • ω\omega记法:大于

定理:设t(n)t(n)是一个函数,t(n)nt(n) \geq n,则每一个t(n)t(n)时间的多带图灵机都与某一个O(t2(n))O(t^2(n))时间的单带图灵机等价
定理:设t(n)t(n)是一个函数,t(n)nt(n) \geq n,则每一个t(n)t(n)时间的非确定单带图灵机都与某一个2O(t(n))2^{O(t(n))}时间的确定型单带图灵机等价

多项式时间

多项式时间复杂度:算法的复杂度表示为O(nk)O(n^k),也就是问题的规模nn在底数
指数型时间复杂度:算法的复杂度表示为O(kn)O(k^n)O(n!)O(n!)

所有合理的确定型计算模型都是多项式等价的,也就是,它们中任何一个模型都可以模拟另一个,而运行时间只增长多项式倍。
忽略运行时间的多项式倍差异是让人疑惑的,实际上,真正的程序当然在乎这种差异,决定忽略多项式倍差异,并不是说这样的差异不重要,但是某些问题,如:因数分解问题,是多项式的还是非多项式的,与多项式倍差异无关,而这些问题也很重要,P,NP,NPC仅仅关注这种类型的问题。

P类

定义:P是确定型单带图灵机在多项式时间内可判定的语言类

P=kTIME(nk)P = \bigcup_k \text{TIME}(n^k)

  • 对于所有与确定型单带图灵机多项式等价的计算模型来说,P是不变的
    • P是一个稳健的类,它不受所采用的具体计算模型影响
  • P大致对应于在计算机上实际可解的问题类
    • 从实际的观点看,P是恰当的

通俗的说,P问题是可以找到一个只有多项式复杂度的算法的问题

定理:每一个上下文无关语言都是P的成员

NP类

定义:NP是具有多项式时间验证机的语言类,NP即非确定型多项式时间

NP=kNTIME(nk)NP = \bigcup_k \text{NTIME}(n^k)

通俗的说明NPNP问题,对于某些问题,我们很难找到一个多项式时间复杂度的算法,或许根本不存在算法可以解决这个问题,但是,如果给我们一个解,我们可以判断这个解是不是符合要求的,比如无法找到一个生成质数的表达式,但是我们可以验证一个数是否是质数。这就是NP问题。由此可知,所有的PP问题都是NPNP问题。

定理:一个语言在NP中,当且仅当它能够被某个非确定性多显示时间图灵机判定

NP问题:多项式时间内可以验证一个解的问题

P与NP问题

P=成员资格可以快速地判定的语言类NP=成员资格可以快速地验证的语言类\begin{aligned} P &= \text{成员资格可以快速地判定的语言类} \\ NP &= \text{成员资格可以快速地验证的语言类} \end{aligned}

对于HAMPATH和CLIQUE,它们是NP成员,但是不知道是否属于P,但是还不能证明在NP中存在一个不属于P的语言。

NPC类

也称NP完全,NP中某一些问题的复杂性与整个类的复杂性相关联,这些问题中任何一个如果存在多项式时间算法,那么所有NP问题都是多项式时间可解的,这类问题称为NP完全

定义:称语言B为NP完全的,如果它满足以下的两个条件

  • B属于NP
  • NP中的每个A都多项式时间内可归约到B

定理:若B是NP完全的,且BPB \in P,则P=NPP = NP
定理:若B是NP完全的,且BpCB \leq_p C,C属于NP,则C是NP完全的

NPH问题
任意的一类NPNP问题都可以在多项式时间内归类为某个XX问题,但是这个问题本身可能不是NPNP问题,如果我们要解决这类NP问题,我们需要解决问题XX,而解决问题XX就间接解决了这类NPNP问题。

NPC问题
这个问题既是NPNP问题又是NPHNPH问题

参考文献