• dfa最小化,修正了上个版本的一些错误。


    上个版本测试的时候,只用了两个非常简单的测试用例,所以好多情况有问题却没有测试出来

    bug1:在生成diff_matrix的时候,循环变量少循环了一次,导致最后一个节点在如果无法与其他点合并的情况下,程序不会给他生成一个群标号。

    修改:把循环变量那里加上等于号

    bug2:在遍历群的时候,程序是以碰到空指针为结束的,但是在malloc内存的时候,系统并不为这个内存初始化为0,而是0xcd,所以以是不是空指针来判断边界是不可行的,会造成错误,导致读取了而外的信息。

    修改:在遍历群的时候,直接以群的数目来做条件测试

    bug3:在nfa转dfa的时候,如果某一个dfa节点在某一个字母上的转换导致了目标位图temp_nfa_set的第一个字节为空的情况下,在插入hash的过程中,直接调用strcpy程序会导致只复制第一个字节即结束字符,而忽略后面的那几个字节。从而导致在之后的查表中找不到这个位图。

    修改:在hash复制名字的时候,用一个循环,直接一个字节一个字节的复制过去,这样就不会出现前面所说的情况了。

    bug4:在re转nfa的时候,对于or的处理,如果or之前有操作符,在弹出该操作符的时候,会忘记为他生成token_node,导致后面的步骤都出现错误。这个问题出现的原因,是当时忘记写了。。。。。

    修改:把忘记写的代码加上去。

    bug5:在判断两个节点是否在dfa最小化的时候合并调用了is_diff,但是这里可能会出现无限递归的情况,例如节点1在a上到节点2,而节点2在a上到节点1。如果这时利用is_diff(1,2),会导致无限递归。

    修改:每次调用is_diff(a,b)的时候,调用之前都在矩阵里面把这两个点所在的位置修改为2,2的意思是正在考虑。如果后面的调用查看到了标记为2的矩阵节点,则这次判断放弃,直接进入下次判断。如果is_diff返回了1,则把这个2修改为1,如果为0,则修改为0。

    bug6:在re生成nfa的时候,自做聪明的采取了非标准的转换策略,后来证明有非常大的错误。例如(a|b)*|abc,如果按照我的那个生成策略生成的nfa图,会接受aabc这种情况。。。

    修改 :把re转nfa全都按照课本来做了。

    目前我自己发现的就有这么多bug,欢迎大家测试

      1 #include "nfa_to_dfa.h"
      2 int* dfa_diff_matrix;
      3 
      4 int mini_dfa_number;//这个是最小化的 dfa表的索引
      5 typedef struct _min_dfa_node
      6 {
      7     pdfa_edge begin;
      8     int is_end;//记录是否是接受节点
      9 }min_dfa_node,*pmin_dfa_node;
     10 min_dfa_node mini_dfa_table[100];//设定为100,其实也可以malloc一下,因为我们已经知道了有多少个节点了
     11 //为了偷懒,算了
     12 is_diff(int input_a,int input_b)//判断两个点是不是等价的程序,注意我们传参数的时候默认a比b大
     13 {
     14     int destination_a,destination_b;//临时的转换目标地址,注意目标地址与矩阵索引是相差1的,注意啊
     15     pdfa_edge temp_edge;//遍历邻接表 
     16     char label_traverse;//用来遍历符号表
    
     17     int for_i;
     18     for(for_i=0;for_i<alpha_size;for_i++)
     19     {
     20         label_traverse=mini_alpha_set[for_i];
     21         temp_edge=current_dfa_table[input_a+1].begin;
     22         while((temp_edge!=NULL)&&(temp_edge->label!=label_traverse))
     23         {
     24             temp_edge=temp_edge->next;
     25         }
     26         if(temp_edge==NULL)
     27         {
     28             destination_a=0;
     29         }
     30         else
     31         {
     32             destination_a=temp_edge->dest_dfa_index;
     33         }//获得a的转换目标
     34         temp_edge=current_dfa_table[input_b+1].begin;
     35         while((temp_edge!=NULL)&&(temp_edge->label!=label_traverse))
     36         {
     37             temp_edge=temp_edge->next;
     38         }
     39         if(temp_edge==NULL)
     40         {
     41             destination_b=0;
     42         }
     43         else
     44         {
     45             destination_b=temp_edge->dest_dfa_index;
     46         }//获得b的转换目标
     47         if(destination_a==destination_b)
     48         {
     49             //目标相同,则无法判断,轮到下一次
     50         }
     51         else
     52         {
     53             if(destination_a*destination_b==0)
     54             {
     55                 //如果刚好一个为0,说明可以判断
     56                 return 1;
     57             }
     58             else
     59             {
     60                 //因为目标地址的索引与矩阵地址的索引是相差1的,所以我们要这样做
     61                 destination_a--;
     62                 destination_b--;
     63                 if( destination_a>destination_b)//按大小来分
     64                 {
     65                     if(dfa_diff_matrix[dfa_node_number*(destination_a)+(destination_b)]!=2)
     66                         //这里是为了防止重复依赖导致的无限递归调用
     67                     {
     68                         if(dfa_diff_matrix[dfa_node_number*(destination_a)+(destination_b)]!=1)//如果当前无法判别
     69                         {
     70                             dfa_diff_matrix[dfa_node_number*(destination_a)+(destination_b)]=2;
     71                             if(is_diff(destination_a,destination_b))//如果可以判别 
     72                             {
     73                                 dfa_diff_matrix[dfa_node_number*(destination_a)+(destination_b)]=1;
     74                                 return 1;
     75                             }
     76                             else
     77                             {
     78                                 dfa_diff_matrix[dfa_node_number*(destination_a)+(destination_b)]=0;
     79                             }
     80                         }
     81                         else
     82                         {
     83                             return 1;
     84                         }
     85                     }
     86                 }
     87                 else//如果b比a大
     88                 {
     89                     if(dfa_diff_matrix[dfa_node_number*(destination_b)+(destination_a)]!=2)
     90                     {
     91                         if(dfa_diff_matrix[dfa_node_number*(destination_b)+(destination_a)]!=1)//如果当前无法判别
     92                         {
     93                             dfa_diff_matrix[dfa_node_number*(destination_b)+(destination_a)]=2;
     94                             if(is_diff(destination_b,destination_a))//如果可以判别 
     95                             {
     96                                 dfa_diff_matrix[dfa_node_number*(destination_b)+(destination_a)]=1;
     97                                 return 1;
     98                             }
     99                             else
    100                             {
    101                                 dfa_diff_matrix[dfa_node_number*(destination_b)+(destination_a)]=0;
    102                             }
    103                         }
    104                         else
    105                         {
    106                             return 1;
    107                         }
    108                     }
    109                 }
    110             }
    111         }
    112     }
    113     return 0;//如果所有的输入都轮完了,说明当前无法比较。。。
    114 }
    115 void diff_matrix(void)
    116 {
    117     int already_diff_number;//这个是用来判断有多少个点已经经过了等价性测试
    118     int for_i,for_j;
    119     dfa_diff_matrix=malloc(sizeof(int)*dfa_node_number*dfa_node_number);//分配这个节点
    120     for(for_i=0;for_i<dfa_node_number;for_i++)
    121     {
    122         for(for_j=0;for_j<dfa_node_number;for_j++)
    123         {
    124             dfa_diff_matrix[(for_i)*dfa_node_number+for_j]=0;
    125         }
    126     }
    127     for(for_i=1;for_i<dfa_node_number;for_i++)
    128     {
    129         for(for_j=0;for_j<for_i;for_j++)//这里首先根据是否是接受节点来初始化矩阵
    130         {
    131             if(current_dfa_table[for_i+1].is_end!=current_dfa_table[for_j+1].is_end)
    132             {
    133                 dfa_diff_matrix[(for_i)*dfa_node_number+for_j]=1;
    134             }
    135         }
    136     }
    137     do{
    138         already_diff_number=0;
    139         for(for_i=1;for_i<dfa_node_number;for_i++)
    140         {
    141             for(for_j=0;for_j<for_i;for_j++)
    142             {
    143                 if(dfa_diff_matrix[(for_i)*dfa_node_number+for_j]!=1)
    144                 {
    145                     dfa_diff_matrix[(for_i)*dfa_node_number+for_j]=2;
    146                     //做这个标记是为了防止递归调用,表明当前正在考虑的节点有哪些,不要再去试图考虑这些节点对
    147                     if(is_diff(for_i,for_j)==1)
    148                     {
    149                         dfa_diff_matrix[(for_i)*dfa_node_number+for_j]=1;
    150                         already_diff_number++;
    151                     }
    152                     else
    153                     {
    154                         dfa_diff_matrix[(for_i)*dfa_node_number+for_j]=0;
    155                     }
    156                 }
    157             }
    158         }
    159     }while(already_diff_number!=0);//如果本趟处理没有找到新的可分节点,就结束 
    160     
    161     for(for_i=0;for_i<dfa_node_number;for_i++)
    162     {
    163         for(for_j=0;for_j<dfa_node_number;for_j++)
    164         {
    165             printf("%d ",dfa_diff_matrix[(for_i)*dfa_node_number+for_j]);
    166         }
    167         printf("
    ");
    168     }
    169 }
    170 void minimize_dfa_matrix(void)//在已经构建好了dfa_diff_matrix后,开始群聚,并建图
    171 {
    172     //现在开始群聚 
    173  int* already_in_group;//用来记录哪些点已经在群里面了
    174  int* temp_group;
    175  int* before_min_access;//这里来标注哪些节点已经通过了最简化dfa的转换 
    176  int group_number=0;//注意群号由0开始 
    177  int* index_of_group;
    178  pdfa_edge temp_edge;//这个是用来重新建立最小化dfa的临时边
    179  pdfa_edge temp_add_edge;//这个是用来往最小dfa里面增加边的临时边
    180  int dest_group_number;//这个是在增加边的时候的目标编号
    181  int **group_set;
    182  int for_i,for_j;
    183  group_set=malloc(sizeof(int)*dfa_node_number);
    184  already_in_group=malloc(sizeof(int)*dfa_node_number);
    185  for(for_i=0;for_i<dfa_node_number;for_i++)
    186  {
    187      already_in_group[for_i]=0;
    188      *(group_set+for_i)=NULL;
    189  }
    190  for(for_i=0;for_i<dfa_node_number;for_i++)//聚集 
    191  {
    192      if(already_in_group[for_i]==0)
    193      {
    194          already_in_group[for_i]=1;
    195          temp_group=malloc(sizeof(int)*dfa_node_number);
    196          *(group_set+group_number++)=temp_group;
    197          for(for_j=0;for_j<dfa_node_number;for_j++)
    198          {
    199              temp_group[for_j]=0;
    200          }//注意这里也需要考虑加减1的问题
    201          temp_group[for_i]=1;
    202          for(for_j=for_i+1;for_j<dfa_node_number;for_j++)
    203          {
    204              if(!dfa_diff_matrix[(for_j)*dfa_node_number+for_i])
    205              {
    206                  temp_group[for_j]=1;
    207                  already_in_group[for_j]=1;
    208              }
    209          }
    210      }
    211  }//现在已经完全都聚集为一团了
    212  mini_dfa_number=group_number;
    213  //现在再将节点和群的关系反转
    214  index_of_group=malloc(sizeof(int)*dfa_node_number);
    215  //这里又需要注意加减1的关系,由于这里dfa节点是从1标号的,而我们在index_of_group是从0标号的,要注意
    216  for(for_i=0;for_i<dfa_node_number;for_i++)
    217  {
    218      index_of_group[for_i]=0;
    219  }
    220  for_i=0;
    221  while(for_i<group_number)//前面开了一个索引数组,现在来赋值,这样就可以直接得到某个节点所在的群号
    222  {
    223      for(for_j=0;for_j<dfa_node_number;for_j++)
    224      {
    225          if(*(*(group_set+for_i)+for_j)==1)
    226          {
    227              index_of_group[for_j]=for_i;
    228          }
    229      }
    230      for_i++;
    231  }//现在关系已经翻转了
    232  //下一步就是利用这个点与群的关系来新建立一个dfa图
    233  //这里的群号就是节点的编号,由于每个群里面的节点都是等价的,所以只需要找一个节点就行了
    234  for(for_i=1;for_i<=group_number;for_i++)//这里的for_i是用来表示最小dfa图的标号,所以从1开始
    235  {
    236      //对每一个群进行遍历
    237      mini_dfa_table[for_i].begin=NULL;
    238      mini_dfa_table[for_i].is_end=0;
    239      for_j=0;
    240      while(*(*(group_set+for_i-1)+for_j)!=1)//由于group是从0开始标号的,所以要减去1
    241      {
    242          for_j++;
    243      }//找到这个群里面一个节点,注意加减一问题,少犯错误啊,1号节点存储在0号位置上
    244      if(current_dfa_table[for_j+1].is_end)//标记为结束节点
    245      {
    246          mini_dfa_table[for_i].is_end=1;
    247      }
    248      temp_edge=current_dfa_table[for_j+1].begin;
    249      while(temp_edge!=NULL)//重新建设邻接表
    250      {
    251          temp_add_edge=malloc(sizeof(struct _dfa_edge));
    252          temp_add_edge->label=temp_edge->label;
    253          temp_add_edge->next=mini_dfa_table[for_i].begin;
    254          dest_group_number=index_of_group[temp_edge->dest_dfa_index-1]+1;//特别要注意这里的加一和减一
    255          //由于temp_edge->dest_dfa_node是从1开始标号的,而index_of_group是从0开始标号的,所以我们要减一
    256          //同样,又由于最后的最简化dfa的图是从1开始标号的,所以我们要加1;
    257          temp_add_edge->dest_dfa_index=dest_group_number;
    258          mini_dfa_table[for_i].begin=temp_add_edge;
    259          temp_edge=temp_edge->next;
    260      }
    261      //本群的邻接表构建完成
    262  }//所有群的邻接表构建完成
    263 }
    264 void show_mini_dfa(void)//输出图
    265 {
    266     int for_i;
    267     pdfa_edge temp_dfa_edge;
    268     number_of_end_dfa=0;
    269     for(for_i=1;for_i<=mini_dfa_number;for_i++)
    270     {
    271         if(mini_dfa_table[for_i].is_end==1)
    272         {
    273             printf("this node is an destination node ,index is %d
    ",for_i);
    274         }
    275         temp_dfa_edge=mini_dfa_table[for_i].begin;
    276         while(temp_dfa_edge!=NULL)
    277         {
    278             printf("there is an dfa edge from %d to %d with label %c
    ",for_i,temp_dfa_edge->dest_dfa_index,temp_dfa_edge->label);
    279             temp_dfa_edge=temp_dfa_edge->next;
    280         }
    281     }
    282     printf("the minimized dfa is completed
    ");
    283 }
  • 相关阅读:
    IOS 微信 6.5.2 自动播放音乐 解决方案
    【转载】动态新增svg节点
    通过并行数据以及TS学习来增强ASR的鲁棒性
    针对领域不变训练的注意力对抗学习
    BLSTM的训练算法、解码算法以及模型的改进
    kaldi chain模型的序列鉴别性训练代码分析
    kaldi通用底层矩阵运算库——CUDA
    kaldi通用底层矩阵运算库——CBLAS
    Thrax-构建基于语法的语言模型工具
    gdb nnet3-compute
  • 原文地址:https://www.cnblogs.com/huangfeidian/p/3160285.html
Copyright © 2020-2023  润新知