有限自动机转换的时空有效编码

Space and Time Efficient Encoding of Transitions for Finite Automata

本文关键字:有效 编码 转换 有限自动机      更新时间:2023-10-16

我一直在思考如何有效地对有限自动机的转换进行空间编码,并保证快速查找时间。对我来说,一个听起来不错的想法是,如果我知道每个状态最多有32个输出转换,那么使用int,有效地将转换符号编码为int位中的1或0。

那么,我有一个类将类型T(例如字符串)映射为int。ID(string)返回分配给字符串作为其整数编码的ID。将字符串"fish", "cat"answers"tree"依次添加到一个空ID对象中,将把"fish"赋值为0,"cat"赋值为1,"tree"赋值为2。

之后,我将2的幂与单个转换符号联系起来。功率由分配给过渡符号的ID决定。

如果ID类被输入的是英文字母,而不是"fish", "cat"answers"tree",那么得到的映射将是

a : 0
b : 1
c : 2
...
j : 9
...
z : 26

因此,具有"a","c","e"answers"f"的出边的状态的outgoing_symbols场看起来像这样:

00000000 00000000 00000000 00110101
      zy xwvutsrq ponmlkji hgfedcba

现在我可以简单地做state.outgoing_symbols+=pow(2,ID(transition_symbol))当添加一个过渡到一个现有的状态

我将执行state.outgoing_symbols+=pow(2,ID(j))将2^9添加到outgoing_symbols,从而得到

00000000 00000000 00000010 00110101
      zy xwvutsrq ponmlkji hgfedcba

这种表示的优点是我可以在一个int中存储32个符号,并且我可以在常量时间内查询状态是否与给定符号有转换:

假设是如下结构体的向量

┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┐
│ 0 │ 1 │ 2 │ 3 │ 4 │ 5 │ 6 │ 7 │ 8 │ 9 │...│   │   │   │   │   │   │   │   │   │   │ n │
├───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┤
└───┴───┴───┴───┴───┴───┴───┴─┬─┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┘
                              │ 
                              │
                              │
                              │
                              │
                              ├───────────────────────────────────────────────────────────────────────┐
                              │   sym_enc outgoing_symbols     00000000 00001000 10000010 00110100    │
                              │                                                                       │
                              │   T mapping_of_symbols_onto_target_states                             |
                              └───────────────────────────────────────────────────────────────────────┘

将状态id 0到n映射到outgoing_symbols的结构体,以及从符号到目标状态的映射。然后我可以写这个函数:

bool has_outgoing_symbol(int state, int symbolID)
{
    return delta[state].outgoing_symbols & pow(2, symbolID) == symbolID;
}

最大的问题是,到目前为止,我还没有将转换符号与目标状态联系起来,我想不出任何方法来使用这种非常有效的转换编码和必要的映射的有效编码。

我可以有2个向量,一个是转换符号id,一个是存储目标状态id的向量的向量。这两个向量将被"同步",因此对于所有i, vector1[i]对应于vectpr2[i]。在

类型的结构体中使用两个向量而不是一个向量的原因
struct transition
{
    std::vector to_states;
    int transition_symbol;
};

是利用一些我不明白的处理器魔法,显然有几个简单类型的向量比有一个简单类型的结构体的向量要好。

在任何情况下,必须以线性或对数查找方式查找目标状态,这使得通过编码作为2的幂来查找转换符号的恒定查找的优势被浪费了。但是我想不出任何方法来利用这种编码将符号映射到目标状态。

有没有人能给我建议,在哪里读到这样的东西,或者甚至直接有一个想法,如何做到这一点?

如果我理解正确的话,您希望为每个在位掩码中设置了位的符号在向量中存储一个条目,并有效地查找给定符号的条目。

在这种情况下,你可以通过计算掩码中小于你要检查的符号的位数来计算条目的索引:

int getSymbolIndex(int state, int symbolID)
{
      if(symbolID == 0)
        return 0;
    return NumberOfSetBits(delta[state].outgoing_symbols & ((1 << symbolID) -1));
}

使用返回的索引在为状态存储的目标状态向量中查找条目。它只给出实际存在于集合中的符号的有效结果。

一个有效的计算整数位数的方法,参见这个问题:如何计算32位整数中设置的位数?