DFA最小化

一、实验名称

确定有穷自动机的最小化

 

二、实验目的

  1. 输入DFA,输出等价的状态数最少的DFA
  2. 实现子集划分算法
  3. 输入和输出均以定义的形式

 

三、实验原理

1、DFA的定义

一个确定的有穷自动机M是一个五元组,M=(K,E,f,S,Z)其中

a. K是一个有穷集,它的每个元素称为一个状态;

b. E是一个有穷字母表,它的每个元素称为一个输入符号;

c. f是转换函数,是K×E->K上的映像,即,如f(ki,a)=kj(ki∈K,kj∈K)就意味着,当前状态为ki,输入字符为a时,将转换到下一状态kj,我们把kj称作ki的一个后继状态;

d. S∈K,是唯一的一个初态;

e. Z包含于K,是一个终态集,终态也称可接受状态或结束状态。

 

2、无用状态

所谓有穷自动机的无用状态,是指这样的状态:从该自动机的开始状态出发,任何串也不能到达的那个状态。或者从这个状态没有通路到达状态。

 

3、状态等价条件

​ a.一致性条件——状态s和t必须同时为可接受状态或不可接受状态

​ b.蔓延性条件——对于所有输入符号,状态s和状态t必须转换到等价的状态里。

 

四、实验思路

1、输入

​ 根据实验要求,以DFA的定义形式输入,即输入M=(K,E,f,S,Z),其中f另外输入。采用putin作为输入函数,首先输入定义形式,用split函数按照’}‘进行分割,再按照’}’分割。最后对得到的二维列表zanshi1中的元素进行输出,得到K,E,S,Z。再输入f中弧的条数,依次输入弧。

 

2、move算法

​ move算法与NFA的确定化里的算法一样,在这里为了求某一子集经过弧到达什么子集而使用move算法。思路是:建立一个新列表存放move算法产生的状态集合,若f中的弧的输入符号为a或者b,求经过紧跟a或者b的下一个状态,将这些状态放于新列表中。

 

3、子集划分算法

​ 定义operation()函数为子集划分算法函数,具体执行步骤如下:

​ a.将K中的状态集分为两种:终态集和非终态集,存于KK中,KK存放最终划分后得到的集合。

​ b.设立循环条件,子集划分算法划分最细的情况是每个状态都为一个子集,所以以此作为循环条件。若KK中集合个数不等于K中状态个数,则继续循环。

​ c.设立标志位llag=0用来决定是否跳出循环,每不执行一次划分算法则llag加1,若最终llag等于KK长度,说明此次循环没有子集划分,则说明划分完毕,退出循环。

​ d.对KK中的集合依次进行操作,判断他们进过move算法得到的集合是否是KK中已有的集合,若是则不执行划分,否则执行划分算法。

​ e. 若执行划分算法,则先算出集合中首个状态的move算法得到的集合属于哪个已知集合,再对其他状态进行同样操作,和首个状态move算法属于相同集合的放于同一个列表中,其他的放于另一个列表中。

​ f.将KK中原来要划分的集合删除,加入划分后的两个集合。循环执行上述步骤,知道KK中集合个数和标志位llag值相同或者KK中集合个数等于K中状态个数,则退出循环。

 

4、输出

​ 输出同样为DFA的定义形式,先输出M=(K,E,f,S,Z),再输出其中的f。

 

五、实验小结

​ 本次实验主要遇到了以下问题:

1、输入存储问题

​ 输入要求使用定义形式,需要区分输入的元素,分别得到状态集,输入符号集,初态集以及终态集。通过python中的split函数将输入的字符串分别以’{‘和’}’分开,再通过循环操作取出得到的二维列表中每一个元素的第二个元素,即为所求的状态集,输入符号集,初态集以及终态集,再输出f的具体弧。

 

2、子集划分算法问题

​ 子集划分算法需要对划分后得到的集合一直执行划分算法,但是会有一个表示划分完毕的结果,在程序中通过设立两个条件来判断是否划分完毕,一是划分得到的子集个数是否等于状态集中状态个数,若是则说明每个状态都为一个子集,即肯定划分结束。另一判断条件为设置一个标志位,通过观察标志位的数值来判断本次划分算法是否执行,若没有执行则说明已经划分完毕,同样退出循环。

 

3、输出问题

​ 输出的形式为DFA的定义形式,通过对格式的控制,将原本定义中的列表类型都转为集合类型,最后输出。同时定义中的f需要单独输出。

 

六、附件

1、源代码
K = []  # 状态
E = []  # 符号
f = []  # 弧
f1 = [] # 新弧
S = []  # 初态
Z = []  # 终态
zanshi1 = []  # 存放五元组形式1
KK = []  # 最终状态集

#M=({1,2,3,4,5,6,7},{a,b},f,{1},{5,6,7})
# 输入
def putin():
    print('输入DFA M')
    M = input('以定义形式输入DFA(如:M=(K,E,f,S,Z):)')
    N = M.split('}')
    for i in N:
        zanshi1.append(i.split('{'))
    K1 = (zanshi1[0][1])
    K1 =K1.split(',')
    for i in K1:
        K.append(i)
    E1 = (zanshi1[1][1])
    E1 =E1.split(',')
    for i in E1:
        E.append(i)
    S1 = (zanshi1[2][1])
    S1 =S1.split(',')
    for i in S1:
        S.append(i)
    Z1 = (zanshi1[3][1])
    Z1 =Z1.split(',')
    for i in Z1:
        Z.append(i)
    print('输入f中弧的条数:')
    n = int(input())
    print('输入弧(分别输入状态1,输入符号,状态2,以空格区分换行结束,ε表示为$)')
    for i in range(n):
        f.append([])
        a = input()
        f[len(f)-1] = a.split(' ')
def move(a, e, f):  # a为列表 e为一个符号
      s = []
      for i in a:
          for j in range(len(f)):
              if i == f[j][0] and f[j][1] == e:
                  s.append(f[j][2])
      return sorted(s)

# 子集划分算法
def operation():
    a = []
    for x in K:
        if x not in Z:
            a.append(x)
    KK.append(a)
    KK.append(Z)
    while len(KK) != len(K):
        llag = 0
        for i in range(len(KK)):
            ziji = KK[i]
            glag = 0
            for jj in range(len(E)):
                ziji1 = move(ziji, E[jj], f)
                flag = 0
                for k in range(len(KK)):
                    if len(set(ziji1).difference(set(KK[k]))) != 0:
                        flag = flag+1
                if flag == len(KK):
                    glag = glag + 1
                    break
            if glag == 1:
                ilag = jj
                zhenziji1 = []
                zhenziji1.append(ziji[0])
                ziji1 = move(zhenziji1, E[ilag], f)
                for k in range(len(KK)):
                    if len(set(ziji1).difference(set(KK[k]))) == 0:
                        hlag = k
                        break
                zhenziji2 = []
                for j in range(1, len(ziji)):
                    zz = []
                    zz.append(ziji[j])
                    ziji1 = move(zz, E[ilag], f)
                    if len(set(ziji1).difference(set(KK[hlag]))) == 0:
                        zhenziji1.append(ziji[j])
                    else:
                        zhenziji2.append(ziji[j])
                KK.pop(i)
                KK.append(zhenziji1)
                KK.append(zhenziji2)
            else:
                llag = llag+1
        if llag == len(KK):
            break

# 运行
putin()
operation()
for yy in KK:
    if len(yy) >= 2:
        for i in range(1, len(yy)):
            if yy[i] in K:
                K.remove(yy[i])
            if yy[i] in S:
                S.remove(yy[i])
            if yy[i] in Z:
                Z.remove(yy[i])
            for yyy in f:
                if yyy[0] == yy[i]:
                    yyy[0] = yy[0]
                if yyy[2] == yy[i]:
                    yyy[2] = yy[0]
for yy in f:
    if yy not in f1:
        f1.append(yy)
for i in range(len(K)):
    K[i] = int(K[i])
for i in range(len(S)):
    S[i] = int(S[i])
for i in range(len(Z)):
    Z[i] = int(Z[i])
print('输出最小化DFA M')
print('M1=(',set(K),',',set(E), ',', 'f', ',',set(S), ',', set(Z), ')')
print('其中f为')
k = 0
for yy in f1:
    print('f(',yy[0],',',yy[1],')=',yy[2],end='   ')
    k = k+1
    if k == 4:
        print('\n')
        k = 0
2、运行结果截图

DFA最小化_第1张图片

 

 

 


你可能感兴趣的:(程序员)