Bitap Algorithm

透過 bitwise operation 實現 approximate string matching

精確搜索

給定一個字串 Text 以及欲搜索的內容 Query

Text : CATCATGGA
Query: CATGG

首先先建一個 Bitmask 的表, X 軸是 Query,Y 軸是所有的 Characters,如果 Query[i] == c 就設成 0 其他設成 1

Bitmask[c][i] = 0 if Query[i] == c
  C A T G G
A 1 0 1 1 1
C 0 1 1 1 1
T 1 1 0 1 1
G 1 1 1 0 0

演算法一開始初始化一個跟 Query 等長的 state bitmask,裡面全部設定為 1。

            1 == mismatch
            0 == match
CATCATGGA
               state = 11111

每次計算時,將 prevState = state,然後 prevState 左移 1 個 bit,跟 Bitmask[c] 做 OR operation,cText 最後面的 character iterate 到最前面。

下方 state 的結果其意義對應到上方的 sub-query,如果結果為 1 表示有 sub-query mismatch,結果為 0 表示 sub-query match。

Step 1:

CATCATGGA
        G      1
        GG     1
        TGG    1
        ATGG   1
        CATGG  1

               prevState = 11111
     ---------------------------
          prevState << 1 = 11110
        or) Bitmask[“A”] = 10111
     ---------------------------
                   state = 11111

Step 2:

CATCATGGA
       G      0
       GG     1
       TGG    1
       ATGG   1
       CATGG  1

              prevState = 11111
    ---------------------------
         prevState << 1 = 11110
       or) Bitmask[“G”] = 11100
    ---------------------------
                  state = 11110

Step 3:

CATCATGGA
      G      0
      GG     0
      TGG    1
      ATGG   1
      CATGG  1

             prevState = 11110
   ---------------------------
        prevState << 1 = 11100
      or) Bitmask[“G”] = 11100
   ---------------------------
                 state = 11100

Step 4:

CATCATGGA
     G      1
     GG     1
     TGG    0
     ATGG   1
     CATGG  1

            prevState = 11100
  ---------------------------
       prevState << 1 = 11000
     or) Bitmask[“T”] = 11011
  ---------------------------
                state = 11011

Step 5:

CATCATGGA
    G      1
    GG     1
    TGG    1
    ATGG   0
    CATGG  1

           prevState = 11011
 ---------------------------
      prevState << 1 = 10110
    or) Bitmask[“A”] = 10111
 ---------------------------
               state = 10111

Step 6: 當做發現 state 的 MSB 為 0 時,就代表找到 Text 中存在的 Query 了。

CATCATGGA
   G      1
   GG     1
   TGG    1
   ATGG   1
   CATGG  0

          prevState = 10111
---------------------------
     prevState << 1 = 01110
   or) Bitmask[“C”] = 01111
---------------------------
              state = 01111
                      |
                      `--- query hit!

模糊搜索

設定一個 Edit distance threshold,看 threshold 多少就用多少個 state vector 記錄。只是在有 edit distance tolerance 的 state vector 需要同時考慮以下四種狀況,並將結果 AND 起來(因為只要有任一個情況的 state vector 出現 0,就代表有 sub-query match)

Deletion

考量下一個 Text character 是 Deletion 的情況時,就代表下一個 Text character 不用去做比對,也就代表現在的狀態已經是比對過下一個 character 的狀態了,所以 state = prevState_R{E-1}

$E-1$ 是因為加上這個 character 的 deletion 就會讓目前的 edit distance 變成 $E$

拿上面範例的 Step 4 來看:

CATCATGGA
     _G      0
     _GG     0
     _TGG    1
     _ATGG   1
     _CATGG  1

            prevState = 11100
  ---------------------------
                state = 11100

Subsitution

考量下一個 Text character 是 Substitution 的情況時,無論下一個 Query character 是什麼結果都會是 match,也就代表不用去 OR bitmask,所以 state = prevState_R{E-1} << 1

拿上面範例的 Step 4 來看,可以看到沒有 OR Bitmask["T"],其實就是讓 G, GG 這兩個 sub-query 能夠容忍一個 Subsitution:

CATCATGGA
     G      0
     GG     0
     TGG    0
     ATGG   1
     CATGG  1

            prevState = 11100
  ---------------------------
       prevState << 1 = 11000

Insertion

考量下一個 Text character 是 Insertion 的情況時,因為除了原本就要比的下一個 character,還多了一個 insertion,所以 state = ((prevState_R{E-1} << 1) | Bitmask[c]) << 1

拿上面範例的 Step 4 來看,需要位移兩個 character 才能完成這輪的比對,一個是原本就要比的 "T" 跟一個 Insertion。

CATCA_TGGA
     G      0
     GG     1
     TGG    1
     ATGG   0
     CATGG  1

            prevState = 11100
  ---------------------------
       prevState << 1 = 11000
     or) Bitmask[“T”] = 11011
  ---------------------------
                state = 11011
           state << 1 = 10110

Match

考量下一個 Text character 是 Match 的情況時,跟原本的 Exactly match 計算方式相同,所以 state = (prevState_R{E} << 1) | Bitmask[c]

Example

下圖來自 GenASM: A High-Performance, Low-Power Approximate String Matching Acceleration Framework for Genome Sequence Analysis, Damla Senol Cali et al., MICRO 2020

References

GenASM: A High-Performance, Low-Power Approximate String Matching Acceleration Framework for Genome Sequence Analysis, Damla Senol Cali et al., MICRO 2020

SeGraM: A Universal Hardware Accelerator for Genomic Sequence-to-Graph and Sequence-to-Sequence Mapping, Damla Senol Cali et al., ISCA 2022

comments powered by Disqus