我真的是觉得这门课太虚了。。这个总结基于名教材《自动机理论、语言和计算导论》(机械工业),也可以说是这本书的总结。由于这门课里很多罗马字母,打字很困难所以能省略的公式都不写了,可以算是入门介绍了。这里省略的内容,看看书就明白了。
A. 概念入门
1.有穷自动机:对于一个系统,如果说他有有限个状态,在这些状态间响应外部输入并按照一定规则切换,又能记忆当前状态,则称该系统为有穷自动机。比如一个开关。有开和关两态,如果当前态为开,拨动开关状态将成为关,反之亦然。所以开关是一个有穷自动机。
2.形式化证明:计算机也可以认为是复杂的自动机,对于一个自动机系统能够做什么并不显而易见,比如人们认为很多事情是计算机无法实现的。为了验证这种可能性避免无用功,引入了形式化证明的概念。包括演绎证明和归纳证明。分别对应我们高中学过的一般证明和归纳法。技巧包括反证法等等。
3.自动机理论的中心概念:就是字母表,串和语言。顾名思义字母组成串(句子),串组成语言。
看看这些东西觉得这门课真够虚。。。= =
B.有穷自动机的分类
我们知道有穷自动机之所以有穷,是说其状态有限,但是在某个时刻自动机能否只处于一个状态来看,有穷自动机可以分为确定型和非确定型有穷自动机。后者可以利用算法“编译”成前者。
1.确定型有穷自动机(DFA):有有穷状态集合和输入符号集合,转移函数,初始状态,以及一个终结状态集合。表示为 。DFA的状态图:用箭头来表示状态间的转换,用圆圈+文字表示状态,用一个同心圆表示终结状态,用start表示开始状态。状态表:可以想象。
2.DFA上的语言——正则语言:正则语言定义为让初始状态到达一个结束状态的串的集合。
这个串必须能满足DFA的转移函数,也就是自动机改变状态的那个规则。为了让这个函数能够处理一串输入,我们假设xa是一个以a结尾的串,并且σ是处理一个状态和一个输入的函数,σ0为一个状态和一串输入的函数,那么σ0(q,xa)=σ(σ0(q,x),a)。如果学过动态规划,这个和状态转移函数很像,不难理解。如果假设σ0(q,x)=p,那么相当于σ0(q,xa)=σ(p,a),可以用这个思想逐步分解一个串输入。
3.非确定型有穷自动机(NFA):可以说是另一种看事物的角度吧。举个例子,要接受所有以01结尾的字串,用q0表示开始搜索状态,q1表示找到了一个0的状态,q2表示紧接着找到了1(也就是说查找结束)。对于q0来说,如果下一个符号是1,他必须返回自身,因为这肯定不是我们要找的01结尾,如果下一个是0,他也不一定就是结尾的那个0,也可以返回自身,但是毕竟他是0,所以一旦找到一个0,就是可以进入状态q1了。也就是说,对于输入0来说,可以处在q0q1两个状态,所以就是NFA了。NFA也可以扩展转移函数σ
4.NFA和DFA的等价性。任何NFA都可以用DFA描述,但是状态可能略多。下面通过一个例子来看看怎么转化
0 1
->p {p,q} {p}
q {r} {r}
r {s} Φ
*s {s} {s}
算法是,初始状态为p,他指向两个状态,我们把{p,q}作为一个状态考虑,输入0的时候,p->{p,q},q->{r},也就是说{p,q}->{p,q,r},同理输入1时{p,q}->{p,r}。终结状态是S,
而包含s的状态集包括{s},{ps},{pqs},{qs},{rs},{prs},{qrs},{qprs},这些都是DFA的终结状态,但是其中很多不可能达到。
相信大家已经知道怎么算了A = {p}; B = {p,q}; C = {p,r}; D = {p,q,r}; E = {p,q,s}; F = {p,q,r,s}; G = {p,r,s}; H = {p,s}.
->A B A
B D C
C E A
D F C
*E F G
*F F G
*G E H
*H E H
5.带ε转移的有穷自动机
这种自动机的思想就是允许无条件状态转向。举例,在一串字符中查找字符串web和ebay,可以将任意字符状态定义成q0,将进入查找A设为q1,查找B设为q2。q0到q1q2是无条件的带ε转移,因为这三个状态都没有触发关键字(比如w和e),都是任意字符输入状态。
ε闭包ECLOSE(P)定义为从状态P通过ε通路能到达的所有状态(包括P)的集合。从上面的描述可以看出ε转移是可以消去的(比如我们可以不定义q1q2,直接设置一个触发w的状态q3和触发e的状态q4)。具体的方法看课本P55-56
C.正则表达式
1. 运算符:取并的+运算,连接,*是正则表达式的三种基本运算。*代表任意数量个他左边的单位。
比如:字母表{a,b,c}上至少一个a和至少一个b的集合:分析一下,如果a在b之前,那么出现第一个a之前,可以有任意个c,即为c*,随后出现1个a,任意数量的a或c(或的概念往往通过取并表示),然后出现一个b,后面的字符串就可以随便取a或b或c,那么表达为c*a(a+c)*b(a+b+c)*,类似b在a前面也一样,最终结果是c*a(a+c)*b(a+b+c)* + c*b(b+c)*a(a+b+c)*
2.正则表达式的代数定律
把这个放到前面来会让问题更简单。除了一些结合律交换律分配律等等大家可以自己衡量对错的数学定律,此外:
ε称作单位元,εR=Rε=R. Φ称作零元。 Φ*R=R*Φ=Φ,Φ+R=R。此外还有幂等律L+L=L,(L*)*=L*, Φ*=ε,ε*=ε
2.将DFA转化为正则表达式
这个算法有点恶心所以花点篇幅。把DFA的状态用自然数1~N表示,定义一个正则表达式Rij(K),表示DFA中从状态i到j且中间不经过大于k的节点的输入串,另外i=j的时候考虑到一个状态的ε转移就是它自身,所以ε也是一个符合要求的串。拿我们上面用的那个DFA的图来看,R00(0)=ε+b,R01(0)=b。
确定了k=0的情况,就可以用归纳法了。我们来考虑k时的情形,所有不经过大于k的节点的路径中,肯定包括不大于k-1的,因为不大于k-1肯定也就不大于k,换个角度看,这些路径也根本不经过k;那么肯定还包括一些路径是包括k的,这些路径在第一次遇到k以前,可以认为是Rik(k-1),随后包括任意数量的k节点上的闭包Rkk(k-1),随后包括从k到j的一条已经没k了的路径Rkj(k-1),综上这种路径表示为Rij(k)=Rij(k-1)+Rik(k-1)Rkk(k-1)*Rkj(k-1)。这也就是我们要找的计算任意k的公式。但是这样带入后得到的正则表达式很长,需要化简。
最终,DFA对应的正则表达式是所有以初始状态为i,终结状态为j的表达式的并。
3.消除状态简化运算
对于任意一个不是初始状态也不是终结状态的状态,都肯定有一定的前驱节点和后继结点,要消去这个节点,只需要用适当的正则式在它的每个前驱和每个后继之间做一个连接就行了。具体的方法在P66-67,很简单。
4.正则表达式转化为自动机(一般是ε-NFA)简单地说,正则表达式有三种微元,分别是R+S型,RS型,R*型,这三种可以转化成三种基本的NFA,任何正则表达式都能通过三种微元组合成。这三种NFA见课本P70-71
D. 正则语言性质
1.正则语言具有封闭性,这和集合上的运算封闭性差不多,不多说了。能够保证正则的运算包括:并,连接,闭包,交,补,差,反转,同态和逆同态。同态就是把输入串中每一个输入都通过一个函数转变成另一个串,该函数叫做串的同态。如果一个语言是正则的,针对其字母表的同态也是正则的,这是显然的,因为就是做了个替换而已没有本质变化啊。
2.泵引理:为了验证一个语言是不是正则的,我们需要使用泵引理,该引理称,对于任意一个正则语言W,一定能把他分解成W=xyz,其中|xyz|>=n,y!=Φ,|xy|<=n,而且xy*z一定也属于w。下面通过一个例子说明一下泵引理的用法。
我们假设这个语言是正则的,那么由于该语言的长度至少是2,所以n=2,将该语言分解成三部分,且|xy|<=2,
3.测试正则语言是否为空:可以分别测试子正则语言是否为空
4.验证正则语言中一对状态是否等价:使用的填表算法是,横轴为A.....(N-1),纵轴为中间状态和接收状态B.....N, 建一个三角形的表。如果A不是接收状态但B是,那么{A,B}是一个可区分对,在其对应位置画X,对于任意一对状态{M,N},如果某个输入下M指向A,N指向B,那么这一对状态可区分,可以根据这个特点递归直到无法推出更多可区分状态对为止,那么无法推出的状态对就是等价的。
5.自动机最小化:可以想象求出等价状态就是为了消去他们……自动机的最小化要求首先把等价状态作为一个状态,然后把从初始状态不可达的状态除去,重构自动机即可。
E. 上下文无关文法和语言
相比前面的内容,这一章更虚了……几乎都是些不用脑子的东西
1. 上下文无关语言:可以认为是比正则语言更广泛的一种语言,其“自然的递归记号”称作文法。这些定义是什么意思无关紧要。简单地说,文法就是描述语言的方法。而文法包括四个要素:符号的有穷集合(这些符号被称作终结符号,类似于英语中的字母),变元的有穷集合(变元也被称作非终结符或语法范畴,每一个变元代表了一类串,也就是一种语言),一个变元被称作初始符号,以及一个规则(也称作产生式)的集合。通俗地说,包括字母,语言集,一个基本语言和一个语法规则。文法缩写式CFG,表达式是G=(V,T,P,S)。主要的应用是CFG描述语言并转化为语法分析器,以及XML等标记语言语言结构。下面的例子可以迅速理解这些乱七八糟的东西
分析:该文法需要两个变元,一个代表了整个表达式称作E(也是一个初始符号),一个代表了其中的标识符称作I,我们能得到下面的“文法”
E->I //表示表达式可以由标识符组成
E->E+E //表达式可以由两个表达式+成
E->E*E //表达式可以由两个表达式*成
E->(E)
I->a //表达式可以由a组成
I->b
I->Ia //表达式可以由I与a连接成
I->Ib
I->I0
I->I1
我们来看看a*(a+b00)是否属于这个语言。E=>E*E=>I*E=>a*E=>a*(E)=>a*(E+E)=>a*(I+I)=>a*(a+I0)=>a*(a+I00)=>a*(a+b00)
可见属于这个语言。
上面的文法可以表示为I=>a|b|Ia|Ib|I0|I1 ,E=>I|E+E|E*E|(E),上述验证过程称作推导。如果每次只替换最左边的变元,就称作最左推导,反之称作最右推导。利于该文法在终结符号集合上产生的语言称作上下文无关语言(CFL)。由初始符号得到的表达式称作句型,比如E+E就是一个句型,和最左最右推导融合后还有左句型和右句型的概念。
2. 语法分析树:也就是推导的另一种表示法。对于一个文法G来说,语法分析树满足每个内部节点的标号都是V的变元,每个叶节点可以是变元、终结符或者ε。一个节点的所有子节点按顺序排列是这个节点对应变元的一个变换。推理和树的互推非常浅显,看两个例子就明白了。
3. CFG和语言的歧义性:类似于1+2*3中先加还是先乘的问题,一个串可能有多个语法生成树或者对应地,有多个最左推导或者最右推导,那么这个语言是有歧义的。某些文法无法消除歧义性,有些则没有歧义性。一般的文法,消除歧义的方法就是使用优先级和结合律,比如规定始终左结合或者右结合。对应地,无歧义文法只有唯一最左或最右推导。
强制优先级是有效的消歧义方法,做法是引入不同的变元,其中因子是不能被相邻运算符打断的表达式,属于因子的包括标识符本身和括号表达式。第二,项是不能被低级运算符打断的表达式,第三就是普通的表达式。
由于这一部分很难语言描述,看题目比较容易明白,下面简单说几个习题的做法:
证明:如果串长度为1,首先他当然是括号匹配的,设为T,可以用T->TT->Tε生成,假设成立。
现在假设串长度为K成立,设串为TK,那么K+1时,要想串是括号匹配的,则他只能是用若干个匹配串组合即T(K+1)->T(M)T(N)或者组合后加括号,或者添加若干ε,都可以用该文法生成。归纳结束
2.证明S->aS|aSbS|ε这个文法是歧义的,即对串aab有两个语法分析树,最左最右推导。思考在证明歧义性上面分析树和最左右推导数量的等价性。
证明:最左推导:S->aS->aaSbS->aaεbS->aaεbε->aab, S->aSbS->aaSbS->aaεbε->aab,最右推导和分析树类似。
如果要制定一个没有歧义的文法,因为原来文法的问题在于aab=(aa)b或者a(ab),所以需要强制结合性,这三个子表达式我们只能把结合性考虑在a、b都出现的aSbS上面,令b强制和前面的a结合就行了。做法是S->aTbS, T->aTbT|ε
F. 下推自动机
如同正则语言和有穷自动机等价,上下文无关语言和下推自动机(PDA)等价。下推自动机是附加了堆栈的ε-NFA。简单地说,PDA有一个初始状态和初始堆栈符号,之后他接受输入改变状态,根据当前输入和状态决定堆栈操作(压栈或者弹出符号),最终到达终结状态。公式P=(Q ,Σ, Γ, σ, Q0,Z0, F),分别对应状态集合,输入符号集合,堆栈字母表,转移函数,初始状态,初始堆栈符号和接收状态集合。其中σ的自变量是状态,输入内容和堆栈字母符号(栈顶),输出则是新状态和堆栈符号串的对的有限集合,即σ(q,a,X)={(q' , r), ....}
下推自动机的图形表示和NFA类似,但是从状态p到q的标号a,X/r表示σ(p,a,X)的输出集合中包含了(q,r)对。
PDA的每个状态可以用三个变量描述,q代表一个状态,w是剩余的串,r为堆栈内容,(q,w,r)是一个PDA的瞬时描述(ID)。定义├符号是PDA从一个ID到另一个ID,用法如(q,aw,xβ)├(p,w,αβ),表示用剩余串的字符a代替了栈顶元素x,思考一下,如果x=ε,这个式子代表了压栈操作。
PDA有两种接受方法,一种是到达终结状态,称作终结状态方式接受, 一种是空栈方式接受。两种构造方式下,PDA等价。那么自然,两种方式可以相互转化。从
终结状态方式转化到空栈,常用的方法是添加一个栈底标记符号X0,到达终结状态的时候,添加一个转移是从该状态的ε输入,弹出所有元素到空栈。例如σ(q, ε ,Y)={(q,ε)}
从文法到PDA,转化方法是,对于每一个变元A,σ(q, ε, A)={(q,β)|A->β是文法的一个产生式}, 对于每一个终结符a,σ(q,a,a)={(q, ε)}
从PDA到文法,转化方法是, 首先我们定义一个符号S为初始符号,以及所有形式为[pxq]的符号,pq是PDA中的状态,X则是堆栈中的符号。
首先对于每一个状态p,文法G都有产生式S->[q0Z0P], 也就是说初始符号能够生成所有从初始ID出发到达空栈状态的串w。其次,令 σ(q, a, X)包含一个输出对(r,Y1Y2Y3.......YK),那么G应该有一个产生式[qXrk]->a[rY1r1][r1Y2r2]... [r(k-1)Ykrk],思考一下,这代表从状态q到达状态r(k)并从栈弹出X的一个方法是读入a,之后读入某些输入,从栈中依次弹出 Y1Y2Y3.......YK,并转过一些中间状态r r1 r2.....r(k-1),最后达到rk。而r1r2...rk代表状态集的每一个有序序列,比如一个PDA有pq两个状态,那么按照pq和qp的顺序要生成两次。(我承认没说明白= =)
首先σ(q, ε , S)={(q, 0S1), (q, A)}, σ(q, ε, A)={(q,1A0), (q,S), (q, ε )}
然后σ(q, 0, 0)={(q, ε)}, σ(q, 1, 1)={(q,ε)}
这就是我们构造出的PDA的转移函数,对应PDA是P=( {q}, {0,1}, {0, 1, S, A}, σ, q, S)
下面我们把这个PDA转成文法
设置一个初始状态S,那么S->[qSq], 而因为σ(q, ε , S)={(q, 0S1), (q, A)},[qSq]->ε[q0q][qSq][q1q]
[qSq]->ε[qAq], [qAq]->[q1q][qAq][q0q], [qAq]->[qSq], [qAq]->[qεq]
[q0q]->0[qεq]=0, [q1q]->1[qεq]=1;
简化上面的式子,可以看到
[qSq]->0[qSq]1 | [qAq] , [qAq]->1[qAq]0 | [qSq] | ε
用A代替[qAq], S代替[qSq],可以得到题目中的文法
可以进一步感受到文法和PDA的等价性。
G.CFL的性质
1.首先讨论所谓CFG的范式,即任何不是ε的CFL都能用只有A->BC或者A->a形式的产生式的CFG产生,其中ABC是变元,a是终结符,这种形式称作乔姆斯基范式。为了求出范式,我们要先给出一些定义。首先如果某个终结串w有X-*>w(-*>为任意多步数转化),称X是产生的。任何终结符都是产生的。此外,如果对于某个串 α和β有S-*>αXβ,称X是可达的。
首先去掉无用符号,做法是去掉非产生符号和所有包含这些符号的产生式,之后去除非可达符号。而且他们产生的语言是相同的。在这个过程中有几点注意事项:首先,文法G的终结符号集合T中的符号都是产生的,那么假定一个产生式A->α,而串α中的符号都是产生的,那么A也是产生的。通过这种方法得到的符号集也是这个文法中全部产生符号了。可见,寻找产生符号的过程是自底向上的,同样,寻找可达符号是自顶向下的,而且得到的也是全部可达符号。然后去ε产生式。回想一下 ε,它在一个语言中不是必需的,如果一个语言有对应的CFG,那么他去掉ε后也有一个对应的不含ε产生式的CFG,如果CFG有一个产生式A->w,w中所有符号都可空或者w就是ε,那么A是可空符号。构造一个除ε产生式的CFG的方法是,对于每个产生式A->BCDEF....,假定其中有m个可空符号,那么新文法中,这些可空符号每个都有存在和不存在两种可能,共有2m种组合,但是如果这些符号都可空,他们都不存在的话就是A->,这在新文法中不能出现,所以除去这种情况。这样得到的文法是去ε产生式的。
A,B都能直接生成ε,他们都是可空的,S生成符号都可空所以S可空。现在考虑生成式S->AB,A和B存在不存在共4中组合,但是AB都不存在是ε,要去掉,所以新文法中:S->AB|A|B,类似地,A->aAA|aA|a, B->bBB|bB|b
首先去ε产生式,只有S是可空的,那么检查所有带S的生成式并改正,为:
S->AB|ASB, A->aA|aAS|a,B->Sb|bS|SbS|A|bb|b
然后去掉单位产生式,只有(B,A)是一个单位对,所以其它不变, B -> SbS | bS | Sb | b | aAS | aA | a | bb
最后检查无用符号,结果是没有
那么下面引入C->a,D->b
这样还是有长度是3的生成式,引入新的变元代替他们,最后
S -> AE | AB
A -> CF | CA | a
B -> SG | DS | SD | b | CF | CA | a | DD
C -> a
D -> b
E -> SB
F -> AS
G -> DS
2.下面给出CFL的泵引理证明某个语言不是上下文无关的:对于一个CFL L,存在常数n满足:若L中的串z的长度>=n,就可以令z=uvwxy, 且:|vwx|<=n, vx!=ε, 对于所有i>=0,uviwxiy也属于L。
3. CFL在代入、并、连接、闭包、反转和逆同态运算下都封闭,但是交补运算下不封闭,但CFL和正则语言的交依旧是CFL。
4.存在算法可以判断CFG是否产生至少一个串,CYK算法可以判定一个串是否属于一个给定的CFL,测试时间是O(n3) ,n是串长度。详细算法看课本。有些问题是不可判定的,比如某个CFG是不是歧义的,是不是固有歧义的,两个CFG交是否为空……等等。
H. 图灵机导引
首先要说明的是某些问题是不能判定的。为了证明一个问题是不是不可判定的,可以对他进行构造抽象,再特殊化得到一个实例,再对实例构造……最后对一个抽象实例判定,即所谓归约技术。但是有个更方便简单的计算机模型就是图灵机。简单地说(其实也就是这样)图灵机(TM)由一条划分成单元的带子和一个有穷控制单位组成。 单元上记录有一个输入符号,图灵机的一步可以改变状态或者在扫描的单元中写符号或者移动带头。没有输入的单元用空格填充。空格不是输入符号,但是是图灵机的一个带符号。图灵机M=(Q, Σ, Γ, σ ,q0,B,F),分别代表状态的有穷集合,输入符号集合,带符号集合,转移函数,初始状态,空格和终结状态。其中σ(q,X)=(p,Y,D),表示某个状态q下正在扫描X,转移到状态p,在X的位置上写下Y,并向左或右移(D=L或R).同样图灵机也有ID,是用X1X2...Xi-1qXiXi+1...Xn表示的,其中q是TM的当前状态,而带头正在扫描第i个符号(Xi),剩下的内容表示Xi左边和右边空格之内的部分。图灵机的转移图上弧标记形如0/0->,表示在此状态下将0改写成0,并右移。
同样图灵机也和一种语言等价,即递归可枚举语言(RE)。此外,如果图灵机在某状态下扫描到一个未定义的输入 ,则停机。为了用图灵机生成字符串,比较有用的技巧包括用状态存储,多道和子程序。此外还有多带图灵机,并可以证明它和单带图灵机等价。类似DFA和NFA的关系,也存在非确定图灵机(NTM),同样NTM和TM也能相互转化。对TM稍作改造可以形成半无穷带TM、多堆栈机器和计数器机器。此外计算机和图灵机可以互相模拟。
I. 不可判定性
图灵机接受RE,对于一个输入语言,TM有两种行为。一种是经过状态转变最终停机,不管是接收状态的停机还是不接受状态停机,这种情形称作有算法。而另一种就是陷入死循环,这种问题称作不可判定性问题。首先,对角化语言非RE:简单地说,将一个图灵机进行编码。图灵机的状态和符号都可以枚举成数字,方向有两个,转移函数也就因此可以编码,从而图灵机可以编码成二进制串。而这些二进制串也可以枚举。方法是在串前面加个1然后转十进制,比如串0编码是第2个串。之后建表将对角线取补得到的语言可以确定不被任何图灵机接受。对角化语言Ld是非递归可枚举的。
从前面可以看到,RE也非为递归语言和非递归语言。递归语言的补也递归,同样,语言L和他的补都是RE,那么L递归。
对于每个TM M和它接受的语言w可以组成有序对(M,w),有序对的集合产生的语言即所谓通用语言Lu,而Lu一定有接受它的图灵机,即通用图灵机。尽管如此,Lu不可判定。
-------------------------------------
到此自动机的总结完成,虽然说不可判定性和难解问题还有一些没有说,但是貌似考试大纲不包括这些内容。下面为了方便有一个缩略词表:
CFG 上下文无关文法 CFL 上下文无关语言 CNF 合取范式 DFA有穷状态自动机 DPDA 确定型下推自动机 ID 瞬时描述 NFA 非确定型有穷自动机 PDA 下推自动机 TM 图灵机 RE 递归可枚举语言 NTM 非确定图灵机