# 序列演算法 ## 1. Basic Algorithmic Strategies - Huffman Codes - Input:字元 with 頻率 - Output:把字元編碼,使得長度越小越好 - 方法:依照頻率最小的兩個 node 依序合成後建一棵樹,然後 left edge 編碼成 0,right edge 編碼成 1 - Divide and Conquer - $T(n)=2T(n/2)+O(logn) \rightarrow O(n)$ - $T(n)=2T(n/2)+O(n) \rightarrow O(nlogn)$ - $T(n)=2T(n/2)+O(nlogn) \rightarrow O(nlog^2n)$ - Dynamic Programming - Principle of optimality - Overlapping subproblems - **LCS**:目前幾乎都是 $O(mn)$ 頂多 $O(mn/logmn)$ 的方法 - **LIS**:$O(nlogn)$ 演算法 - ![](https://i.imgur.com/iGEKKyY.png) - [**LCIS 2005 Yang, Huang and Chao**](https://reader.elsevier.com/reader/sd/pii/S0020019004003242?token=215D879C620B6BE779392F0891D1A9EBF8F619FA951C0A55ACA1EF25A2FE7C90FCA75664A7041E1BAB5317F60E20B091) ## 2. Alignment - 問題: 給定兩字串 $A$、$B$,找出對齊的方式使得 cost 最小。 - 定義 match / mismatch / insertion gap / deletion gap 的 cost - 使用 dash "-" 代表 gap ( insertion / deletion ) - Dot Matrix: 把兩字串畫成表格,相同部分標點 - Global Alignment : - 找出對齊方式,使得兩字串全部對齊的 score 最大 - $S_{i,j}=max(~S_{i-1,j}+gap~,~S_{i,j-1}+gap~,~S_{i-1,j-1}+matchscore~)$ - 同樣的問題可以用來解決 LCS / Edit Distance - LCS : 1/0/0/0 - ED : 0/-1/-1/-1 - Local Alignment : - 從兩個字串個找出某一小片段,使得對齊的 score 是全部裡面最大 → 找出最相似的部分 - 定義 $S_{i,j}$ 為 $a_1a_2...a_i$ 和 $b_1b_2...b_j$ ,恰好結束在 $(i,j)$ 的 optimal local alignment 分數 - $S_{i,j}=max(~S_{i-1,j}+gap~,~S_{i,j-1}+gap~,~S_{i-1,j-1}+matchscore~,~0~)$ - Maximum Sum Query : - Query Segment Sum in O(1) : sum(i,j) = prefix(j) - prefix(i-1) - Method 1 : 紀錄結束在位置 i 的 Maximum Sum - dp[i] = a[i] + max(dp[i-1],0) - Method 2 : 先計算 prefix 及 prefixminbefore - maxsum[i] = prefix[i] - prefixminbefore[i]; - Scoring Scheme : - Affine Gap Penalties - 長度 $k$ 的 gap,penalty 設定為 $x+k*y$ - $x$ opening penalty,$y$ gap penalty - $D(i, j)$ : 最佳解 ending with deletion - $I(i, j)$ : 最佳解 ending with insertion - $S(i, j)$ : 最佳解 ending - $D(i,j)=max(D(i-1,j)-y,~S(i-1,j)-x-y)$ - $I(i,j)=max(I(i,j-1)-y,~S(i,j-1)-x-y)$ - $S(i,j)=max(D(i,j),~I(i,j),~S(i-1,j-1)+w(a_i,b_j))$ - Constant Gap Penalties - 任何長度的 gap,penalty 皆為 $x$,所以等價於 affine 把 $y$ 設成 $0$ - Restricted Affine Gap Penalties - 長度 $k$ 的 gap,penalty 設定為 $x+f(k)*y$ - 其中 $f(k)$ 最多就只有 $c$ 而已, $f(k)=min(k,c)$ - $D'(i,j)=max(D'(i-1,j),S(i-1,j)-x-cy)$ - $I'(i,j)=max(I'(i,j-1),S(i,j-1)-x-cy)$ ## 3. Space Saving Alignments - Constrained Sequence Alignment - 在生物序列的應用中,我們可以限制 insertion 和 deletion 的次數不要差太多,如給定 $u\le v$,$a_i$ 和 $b_j$ 要滿足 $u\le i-j\le v$ 才可以配對。 - 時間複雜度從 $O(nm)$ 降為 $O(nw)$ - 定義: - $S^-(i,j)$ 為 $a_1a_2...a_i$ 和 $b_1b_2...b_j$ 的最好 align cost - $S^+(i,j)$ 為 $a_{i+1}a_{i+2}...a_m$ 和 $b_{j+1}b_{j+2}...b_n$ 的最好 align cost - 性質:找一個點 maximize $S^-(m/2,j)+S^+(m/2,j)$ - Hirschberg 演算法 ```clike= Linear_Space_Align(A,B,i1,j1,i2,j2){ forward_SCORE(A,B,i1,j1,imid,j2) //find the best score from (i_1,j_1) backward_SCORE(A,B,imid,j1,i2,j2) //find the best score to (i_2,j_2) jmid = max index 使得 S_-[j]+s_+[j] 最大 Linear_Space_Align(A,B,i1,j1,imid,jmid) Linear_Space_Align(A,B,imid,jmid,i2,j2) } ``` - 空間複雜度:$O(n)$ - 時間複雜度:$O(mn(1+\frac{1}{2}+\frac{1}{4}...))=O(mn)$ - Hirschberg 演算法的應用(線性空間) - Affine Gap Penalty : $x+k*y$ - 用線性空間來計算 $D,~I,~S$ - 用 $S$ 來切割問題 - Local alignment space saving: - 用線性空間先找到後端點,再找到前端點 - 對於該問題用 Hirschberg 演算法 - Constrained Sequence Alignment - naive 的方法,時間複雜度為 $O(nwlogn)$ - 需要好的 subdivide 問題的作法 - 使用中間對角線來分割,根據平行四邊形,size 必定減少一半 - 使用矩形來分割 ## 4. Suboptimal Alignments ($\Delta$ Point) - 目標:找出 $S-$ 和 $S+$ 加總的矩陣中,數值 $\ge \Delta$ 的欄位 - 滿足該性質的點稱為 **$\Delta$ Point** - 方法一:$O(MN)$ 時間, $O(MN)$ 空間 - 直接用矩陣去存 $S-$ 和 $S+$ - 方法二:$O(M^2N)$ 時間, $O(N)$ 空間 - 用 Hirschberg 演算法 - 每一個 row,用 $O(MN)$ 時間和 $O(N)$ 空間去找 $\Delta$ Point - 方法三: - $S-$ 只能從上往下算,$S+$ 只能從下往上算,不能逆推 - 因此若用 Hirschberg 演算法,相鄰的 row 不可以直接轉移 - 方法四:$O(MNlogM)$ 時間, $O(NlogM)$ 空間 - ![](https://i.imgur.com/8D3CmGI.png) - 有 $logM$ 層,每次只有一個 subproblem 是 active - 每一層總時間是 $O(MN)$ - 每一層 working 空間是 $O(N)$ - 方法五:$O(MN~log\min{\{M,N\}})$ 時間, $O(M+N)$ 空間 - ![](https://i.imgur.com/IAgUBcb.png) - 有 $log\min{\{M,N\}}$ 層,每次只有一個 subproblem 是 active - 每一層總時間是 $O(MN)$ - 每一層 working 空間是 $4(M+N)\times \frac{1}{2^i}$ - 方法六:$O(MN~loglog\min{\{M,N\}})$ 時間, $O(M+N)$ 空間 - ![](https://i.imgur.com/nyBg0Bm.png) - 盡量切成更小的問題以降低層數,但要保證每一層 working space 成比例降低 - 有 $loglog\min{\{M,N\}}$ 層,每次只有一個 subproblem 是 active - 每一層總時間是 $O(MN)$ - 每一層 working 空間是 $4(M+N)\times \frac{1}{2^i}$ - 方法七:$O(\frac{1}{\epsilon}MN)$ 時間, $O(\frac{1}{\epsilon}M^\epsilon N)$ 空間 - ![](https://i.imgur.com/cWT3ljW.png) - 有 $1/\epsilon$ 層,每次只有一個 subproblem 是 active - 每一層總時間是 $O(MN)$ - 每一層總空間是 $O(M^\epsilon N)$ - 方法八:$O(\frac{1}{\epsilon}MN)$ 時間, $O(\frac{1}{\epsilon}M^{1+\epsilon}+N)$ 空間 - ![](https://i.imgur.com/8B9B8Ea.png) - 一開始花 $O(MN)$ 時間,$O(N)$ 空間準備好 $S+$ 和 $S-$ - 有 $N/M$ 個 blocks,每一個 block 中: - $O(\frac{1}{\epsilon}M^2)$ 時間 - $O(\frac{1}{\epsilon}M^{1+\epsilon})$ 空間 ## 5.Multiple Alignments - 目標:給定多個 sequence,找出對齊的方式使得 cost 最小 - Sum of Pairs (SP):兩兩 sequence 的 cost 加總 - Tree Score:也有人用但比較複雜所以不提 - 解決的方法: - $k$ 個長度 $n$ 的 sequence,時間 $O(n^k)$ - 因此是 NP-hard 問題 - 近似解:$2-\frac{l}{k}$ 對任意的 $l$。 ( $l$ 越大,近似解越好,但要花更多時間得到) - Heuristic Approach:Progressive Alignment 沒有理論保證,但通常解尚可接受 - "Once a gap, always a gap" , 時間複雜度 $O(k^2n^2)$ - Guide Tree - 1.用 species 的相似度 - 2.先用 $O(k^2)\times O(n^2)$ 算兩兩的相似度 - Aligning Alignments - ![](https://i.imgur.com/UyRBXr3.png) - 在 affine gap 的應用中,不知道 gap 種類時,通常會直接把 gap 當作 open --- --- --- ## 6.Fast Alignments - 目標:使用 $o(mn)$ 時間與空間,尋找 Exact Word Matches - 給定兩個序列 $A、B$,事先決定好 Exact Word 長度 $k$ - 是否有長度 $k$ 的 common substring - 方法一:Hash Tables - 將 $A$ 每長度 $k$ 的 substring 用 hash table 紀錄 - 將 $B$ 每長度 $k$ 的 substring 去同一個 hash table 查詢 - 方法二:Suffix Tree - 將 $A$ 的每個 suffix 用 suffix Tree 紀錄 - 將 $B$ 從左到右 (每個 suffix) 去 suffix tree 查詢 - 看是否可以有長度為 $k$ 的 prefix - 方法三:Suffix Array - 將 $A$ 轉換成 suffix array - 將 $B$ 從左到右 (每個 suffix) 去 suffix array 查詢 - 用 binary search 尋找是否有 entry - 看看這兩個 string 的 common prefix 是否為 $k$ - 方法四:BWT - Burrows-Wheeler Transform - 給定 T=abaaba\$,定義 BWT(T)=abba\$aa - 給定 $T$ ,我們可以構造 $BWT(T)$ - Naive 構造:$O(n^2)$ - ![](https://i.imgur.com/vM9pTkl.png) - **Suffix Array 構造:$O(n)$** - ![](https://i.imgur.com/mN0K6YE.png) - 給定 $BWT(T)$ ,我們可以回推 $T$ - Bind and Sort:$O(n^2)$ - ![](https://i.imgur.com/jE9HRBy.png) - **LF mapping reverse:$O(n)$** - ![](https://i.imgur.com/Xd6l1QO.png) - T ranking 性質:(第一 row 的字元,從左至右編號) - 最左邊的 column 和最右邊的 column,同一字元的出現順序保持一致 - B ranking 性質:(最後一 column 的字元,從上至下編號) - 根據此編號及 T ranking 性質可以設計 LF mapping 方法來 reverse - $FM$ index backward search - 功用:給定 T=abaaba\$,BWT(T)=abba\$aa,我們想要 query $q="aba"$ 是否為 $T$ 的 substring - 前置處理:計算 $C、OCC$ - ![](https://i.imgur.com/wqV7aeV.png) - Query 階段: - ![](https://i.imgur.com/JgzOLQl.png) - ![](https://i.imgur.com/zljazOO.png) - FASTA - 1.挑出最相近 region ( 用 exact word match ) - 2.用 PAM Matrix rescore ( 不同的字元 match 時有不同的權重 ) - 3.刪除掉不相近的 matches - 4.在 band 當中做 alignment - BLAST - 目標在找 MSP ( Maximum segment pair) - Match : 5,Mismatch : -4 - 對每個 diagonal 去找 maximum sum segment - PAM Matrix - ![](https://i.imgur.com/3U5r0ub.png) - 1.對 Sequence A 建立 Hash Table - 2.用 Sequence B 去尋找 hit 的地方 - 3.延伸 hit - PatternHunter - Spaced Seed - ![](https://i.imgur.com/0kImB2k.png) - $l = 18$ - $w = 11$ - 比起 blastn,不要求連續的 match - 若兩 sequence 有一段 region 相似度 > 61 % (過多的 1),則 seed 1 1 \* 1 必定 hit - 證明:如果 seed 1 1 \* 1 沒有 hit ,則 similarity <= 61 % - 如果 seed 1 1 \* 1 沒有 hit ,每 100 個位置當中,最多只有 61 個 matches - 開頭有一些 $0$ - $10^b,~~b\ge 1$ - $110^b,~~b\ge 2$ - $1110^b,~~b\ge 2$ - 結尾最多 $\le 3$ 個 $1$ ## 7.Genome Reconstruction - Newspaper Problem - ![](https://i.imgur.com/a9xCZjM.png) - 透過許多片面的資訊,重構出完整的內容 - 一些圖論問題: - Eulerian Cycle Problem:走過每個 "邊" 的 cycle 是否存在 - Balanced Graphs : indegree(v) = outdegree(v) 對於每一個點 v. - 任意 Connected 的 Balanced Graph 都有 Eulerian Cycle - Hamiltonian Cycle Problem:走過每個 "點" 的 cycle 是否存在 - NP-hard 問題 - Fragment Assembly - 假設: - 每一個 k-mer 都有出現 - 每一個 k-mer 都只出現一次 - 沒有任何 error - 是由一個 circular 的基因序列產生 - 舉例:我們有以下的 read,我們想要重構出 circular 的基因序列 - GTG GCG GCA ATG TGG TGC GGC CGT CAA AAT - 方法一: - 把每個 read 建立一個節點,建邊 - ![](https://i.imgur.com/m1PJSKa.png) - 在此圖上找一個 Hamiltonian cycle - 方法二: - 建立節點為 k-1-mer,把每個 read 建立一個邊 - ![](https://i.imgur.com/46XMNwR.png) - 在此圖上找一個 Eulerian cycle - 放寬條件假設 - Generating (nearly) all k-mers - Handling Errors in Reads - Handling Repeated k-mers - From Circular to Linear Genomes - [De Brujin Sequence](https://en.wikipedia.org/wiki/De_Bruijn_sequence) B(n,k) - B(3,2) -> 0 0 0 1 1 1 0 1 、 1 1 1 0 0 0 1 0 - 找出 super string,包含所有長度 n、k 種 character 的 string (共有 $k^n$ 種) - B(n,k) 長度為 $k^n$ - B(n,k) 的種類數為 $\frac{(k!)^{k^{(n-1)}}}{k^n}$ - 其他有趣問題 - Counting number of Eularien Curcuits - http://www.cdam.lse.ac.uk/Reports/Files/cdam-2004-12.pdf - Shortest Superstring Problem - http://fileadmin.cs.lth.se/cs/Personal/Andrzej_Lingas/superstring.pdf ## 8.Pattern Identification in a Haplotype Block - 名詞定義: - Single Nucleotide Polymorphism (**SNP**) : 單核苷酸多態性 - 序列中的某一位置,有 $\ge1\%$ 機率發生變異 - 該位置可以分成 **主等位基因、副等位基因** - Mutation : 突變,是序列中的某一位置,有 $<1\%$ 機率發生變異 - Haplotype (pattern): 單倍型 - 一組基因序列,不同的物種、疾病會有不同的序列 - Ordered list of SNPs - 一組基因序列可以由 recombination hotspots 切割成一些 Haplotype Blocks 區塊 - Tag SNPs : 演算法的目標,取出一部分的 SNP 來區分不同的 Haplotype patterns - 問題定義: - 給定一些 SNP,以及 Haplotype pattern,從 SNP 中找出最少的 Tag SNPs,使得我們可以區分任意的 haplotype sample。 - 這是一個 NP-hard 問題,又稱為 minimum test set problem - e.g. ![](https://i.imgur.com/hltoUOH.png) - 我們可以取 Tag SNPs 為 $S_3、S_4$ - Haplotype pattern 為 $P_1\sim P_4$,每一個 pattern 用四個 SNP 描述 - 不管 haplotype sample 為何,只要看他的 $S_3、S_4$,就可以把它 match 到 $P_1\sim P_4$ 的某一個 Haplotype pattern - 規約到別的 Np-Hard 問題 - Set Cover - ![](https://i.imgur.com/E1A2uQi.png) - 我們需要選擇適合的 tag SNPs,來區分不同的 pattern - 相當於我們需要選適合的 set,來 cover 底下六個 element - Greedy 演算法,可以保證被最佳解乘以 log factor 所 bound 住 - $U=\{1,2,3,4,5,6,7,8,9\}$ - $C_1=\{2,3,4,5,6,7\}$ - $C_2=\{1,2,3,4,5\}$ - $C_3=\{6,7,8,9\}$ - Greedy 解: - $~~~~~~~~[2,3,4,5,6,7,8,9,1]$ - $S=[\frac{1}{6},\frac{1}{6},\frac{1}{6},\frac{1}{6},\frac{1}{6},\frac{1}{6},\frac{1}{2},\frac{1}{2},0]$ - 每一個分數 $S_i$ 不會超過最佳解的平均分數 $\frac{|C^*|}{i}$ - $|C|=\sum S_i\le\sum\frac{|C^*|}{i}=|C^*|(\frac{1}{1}+\frac{1}{2}+...\frac{1}{n})=|C^*|logn$ - Integer Programming - ![](https://i.imgur.com/1GUVo6m.png) - 為了區分 $P_1$ 和 $P_2$ $:~~\rightarrow x_3+x_4\ge 1$ - 為了區分 $P_2$ 和 $P_4$ $:~~\rightarrow x_1+x_2+x_3\ge 1$ - 可以使用 Iterative LP-relaxation Algorithm - Missing Data - 如果 haplotype sample 可能有些 SNP 是缺失的,仍然要能區分出來。 - 問題定義:假設 haplotype sample 最多有 $m$ 個 SNP 是缺失的,我們想要從 SNP 中找出最少的 Tag SNPs 出來,使得我們總是可以區分。 - Set Cover: - 我們要 cover 每一個 element $m+1$ 次 - Integer Programming: - ![](https://i.imgur.com/xGcWnSx.png) ## 9.Haplotype Inference - Haplotype data 和 Genotype data 的比較 - ![](https://i.imgur.com/xWqvPi5.png) - 問題定義 - 給定 $n$ 個 genotypes ,以及 $m$ 個可能的 haplotypes,求出最小的 haplotypes 集合,可以解釋所有給定的 genotypes。 - 這是一個 NP-hard 問題,又稱為 Haplotype Inference - 轉換成整數規劃問題 - 符號定義: - 每一個 haplotypes 對應到變數 $x_i$ - 每一個 genotypes 對應到集合 $S_j$,裏頭包含了許多 $(h_r,h_t)$ 配對 - 每一個配對可以解釋此 genotype - 方法一:轉換成 IQP 問題,有近似演算法理論保證 - 選到為 1 不選為 -1。 - ![](https://i.imgur.com/9fbjgyv.png) - 方法二: - 選到為 1 不選為 0。 - 目標函數:$\min \sum\limits_{i=1}^mx_i$ - 限制函數:$\sum\limits_{(h_r,h_t)\in S_j}x_rx_t\ge 1$ - 方法三: - 選到為 1 不選為 0。 - 目標函數:$\min \sum\limits_{i=1}^mx_i$ - 限制函數:$\sum\limits_{(h_r,h_t)\in S_j}\lfloor\frac{x_r+x_t}{2}\rfloor\ge 1$ - 方法四: - $x_i\in\{0,1\},~~w_{jrt}\in\{0,1\}$ - 目標函數:$\min \sum\limits_{i=1}^mx_i$ - 限制函數:$\sum\limits_{(h_r,h_t)\in S_j}w_{jrt}=1$ 而且 $x_r\ge w_{jrt},~~x_t\ge w_{jrt}$ ## 10.Heaviest Segments - Maximum-sum segment O(n) time - 給定一整數序列,找出子序列使得總和最大 - 方法一:停在每個位置的總和最大子序列,只要考慮是否接進上一位置 - 因此就可以知道結尾在每個位置的總和最大子序列 - 方法二:紀錄每個位置的 prefix sum 以及 prefix min - Maximum-average segment O(n) time - 給定一整數序列,找出子序列使得平均最大 - 方法:直接找最大值即可 - Maximum-average segment 結尾在每個位置 O(n) time - 給定一整數序列,找出起點在每個位置的平均最大子序列 - 方法:Decreasingly right-skew decomposition - 目標:把整數序列 partition 成遞減的 right-skew 序列 - 1.Right skew 表示 prefix 的平均小於 suffix 的平均 - 2.遞減表示各個 right-skew 的平均越來越小 - 步驟:由後往前建立 pointer 及 average - ![](https://i.imgur.com/EMjoZ5Z.png) - 也可以找 Increasingly left-skew decomposition ## 11.RMSQ - **Range Maxima Query (RMQ)** - 給定一整數序列,每次詢問時,給定一段範圍,找出此範圍的最大數字 - https://www.youtube.com/watch?v=ZBHKZF5w4YU - https://codertw.com/%E7%A8%8B%E5%BC%8F%E8%AA%9E%E8%A8%80/561565/ - https://zh.wikipedia.org/wiki/%E8%8C%83%E5%9B%B4%E6%9C%80%E5%80%BC%E6%9F%A5%E8%AF%A2 - 演算法: ```clike= int input[n]; int dp[i][j]; void preprocess(){ for(int i=1;i<=n;i=2*i) for(int pos=1;(pos+i-1)<=n;pos++) dp[pos][i]=min(dp[pos][i],dp[pos+i/2][i]); } int query(int a, int b){ int k = log(b-a); return min(dp[a][k],dp[b-k+1][k]); } ``` - **Range Maximum-Sum Segment Query (RMSQ) 版本一** - 給定一整數序列,每次詢問時,給定一段範圍 $[k,j]$,找出此範圍的總和最大子序列 - 1.事先算出 prefix sum,然後每個點 $i$ 紀錄兩個位置 - 1.$Left\_bound(i)$ 指向前面大於等於自己中最近的位置 - 2.$partner(i)$ 指向 $[Left\_bound(i),i]$ 中的最低位置 - 2.先用 RMQ 找出最大的 $(partner(i), i)$ 配對 - 1.沒有超出範圍,即為答案 - 2.有超出範圍,更新 $Left\_bound(i)$ - 3.答案只會是 (new_partner(i), i) 或 (partner(j), j) 其中之一 - **Range Maximum-Sum Segment Query (RMSQ) 版本二** - 給定一整數序列,每次詢問時,給定兩段範圍,找出起點和終點分別在這兩段範圍得總和最大子序列 - 方法:首先要建立 prefix sum array - 1.如果兩區間不重疊:直接使用 RMQ 問題的解法,找前半區間的 maxima 及後半區間的 minima - 2.如果兩區間重疊,可以區分三種 case - 2a.最佳解用到前半部不重疊部分:和 1. 相同 - 2b.最佳解用到後半部不重疊部分:和 1. 相同 - 2c.最佳解都在重疊部分:和 RMSQ 版本一相同 ## Suffix Array Linear Time Construction - [Suffix Array](https://www.cs.helsinki.fi/u/tpkarkka/opetus/10s/spa/lecture11.pdf)