Comments
Description
Transcript
6/11
配列解析アルゴリズム特論 渋谷 圧縮 渋谷 東京大学医科学研究所ヒトゲノム解析センター (兼)情報理工学系研究科コンピュータ科学専攻 http://www.hgc.jp/~tshibuya 本日の話題 配列解析アルゴリズム特論 渋谷 文字列圧縮アルゴリズムのいろいろ 統計的手法 Huffman code Tunstall Golomb Arithmetic code PPM 辞書的手法 LZ77, LZ78, LZW Block sorting Sequitur 接尾辞配列の圧縮 圧縮とは 配列解析アルゴリズム特論 渋谷 2種類の戦略 Lossless圧縮: 完全に復元可能 (本講義) Lossy圧縮: 画像などで、完全に復元できなくてもよい。 何を圧縮するか? 本講義では文字列が対象 情報源のモデルを考える必要性 何故圧縮できるか? 情報に「重複」があるから 情報源のエントロピー モデル A 32% C 22% G 15% T 31% ATGCCGTAATAACGATCAATACTAGCC... 出力例 エントロピーとは (おそらく学部の復習?) 配列解析アルゴリズム特論 渋谷 情報「量」にあるべき性質 非負 確率が小さい事象は「びっくり度」が大きい 足し算できる I(p·q) = I(p) + I(q) そんなわけで情報量は イチローがヒットをうつ: 0.372 松井がヒットをうつ: 0.299 比較 I(p) = − log2(p) 単位は「ビット」 確率 0.5 の事象は1ビットで表現可能! エントロピー エントロピー 情報量の期待値 1 H(p1, p2, p3, ... , pn) = − Σpi log pi 性質 pi =1ならばH=0 一番Hが高いのはpi =1/nのとき 情報源に対する圧縮率の期待値の下限 圧縮率はエントロピーに近づくと嬉しい 「正しい」情報源のモデルを考えることも重要 モデルによってはエントロピーの計算自体が難しいことも 0 片方の確率 1 2つの事象に対する エントロピー 関連した2つの情報源のエントロピーの解析 配列解析アルゴリズム特論 渋谷 同時に2つの事象A, Bがあるとする H(A,B) = −Σp(ai,bi) log p(ai, bi) するとその性質 ATGCCT... ∈ {ai }n CTTGGA... ∈ {bi }n こんなかんじ H(A,B) = H(B,A) H(A), H(B) ≤ H(A,B) ≤ H(A) + H(B) 関連のある質問を2つするのは損 A: ヒットを打った B: ヒットを打たなかった T/F T/F 情報としては同じなのでH(A,B) = H(A) = H(B) A: ヒットを打った B: 桶屋が儲かった T/F T/F ほぼ関係ないのでH(A,B) ~H(A)+H(B) A: ヒットを打った B: 勝った T/F T/F その中間 条件付エントロピー 配列解析アルゴリズム特論 渋谷 Aがaiの時のBのエントロピー H(B|ai) = −Σjp(bj|ai) log p(bj|ai) 条件付エントロピーはその期待値 0: 完全に相関 H(B|A) = −Σi,jp(ai,bj) log p(bj|ai) 性質 H(A,B) = H(A) + H(B|A) H(B|A) ≥ 0 H(B) ≥ H(B|A) 下2つは H(A), H(B) ≤ H(A,B) ≤ H(A) + H(B) というエントロピー の性質から導くことができる 相互情報量 I(A;B) = H(B) − H(B|A) = H(A) − H(A|B) どれくらい情報に重なりがあるか? Relative Entropy (Kullback-Leibler Distance) 配列解析アルゴリズム特論 渋谷 2つの確率事象の差異を見る指標 本当の情報源はPなのに、何を間違えたかQだと思ったとき に(たとえばそう思って圧縮したときに)損をする量 P, Qを逆にした時の値は異なる 対象性が必要な場合は両者の平均を距離として扱うことも多い » ただし、そこに理論的な正当性があるわけではないことに注意 必ず正の値をとる 情報源の推定を間違えないことが、最高の圧縮率を達成する条件 p( x ) D ( p || q) = ∑ p( x ) log q( x ) x 通信路・圧縮超入門 配列解析アルゴリズム特論 渋谷 圧縮 0.9 0 0 情報の出し手 情報の受け手 0.1 1 1 情報量の少ない文章(0ばっかり、など) を送るのはもったいない 情報量が1000ビットであれば、1000ビット送るだけでよい筈!→Huffman符号など 通信路符号化 0 情報の出し手 1 0.9 0.1 0.1 0.9 0 情報の受け手 1 間違いが起こる通信路でできる だけ正確に情報を送るには? 両サイドの相互情報量分のビット数は送ることができる筈!→Hamming符号など 2種類の戦略 配列解析アルゴリズム特論 渋谷 統計的手法 文字の使用頻度の偏りに基づく Huffman code Tunstall Golomb Arithmetic code PPM ... 辞書的手法 「よく出てくる語」を辞書化する LZ77, LZ78, LZW Block sorting Sequitur ... Huffman Code (1) 配列解析アルゴリズム特論 渋谷 考え方 確率の高い事象は短いコードで表す 文字のビット数は変更可能 Model A C G T 12.5% 12.5% 25% 50% 4文字なので普通に 表現すれば2ビットで 1文字を表現できる entropy = 1.75bit Code 100 101 11 0 理想的な場合 期待値としては1文字あたり 1.75ビットで表現される →圧縮できた(しかも理想的) Huffman Code (2) 配列解析アルゴリズム特論 渋谷 計算時間: O(s log s) s: アルファベットサイズ ヒープを用いる 888 0 1 381 507 0 0 1 283 0 C 155 205 224 1 128 H 118 106 91 1 0 F 0 1 B 21 176 1 0 0 57 J 36 D 1 0 G 1 49 E 47 I 85 1 A 44 頻度 一番頻度の低い2つをまとめる Huffman Code (3) 配列解析アルゴリズム特論 渋谷 性質 Prefix code (Instantaneous code) あるコードが他のコードのprefixになっていない 文字のコード化だけで圧縮する場合、最適 エントロピー的にもいい線を行っている H(X)≦L<H(X)+1 確率piの長さが log(1 / pi )以下となっているため k文字まとめれば、 H(X)≦L<H(X)+1/k AAAA AAAC AAAG AAAT AACA ... 0.47% 0.37% 0.35% 0.41% 0.32% Adaptive Coding (Feller-Gallager-Knuth) 配列解析アルゴリズム特論 渋谷 ハフマン符号はそのままでは一度全テキストは見ないと 文字の出現頻度がわからない 出現頻度表を更新しながら圧縮する 初出の文字に対応する頻度0の葉を一つ用意する 更新はルートから該当ノードまでのパス長に比例した時間で可 能 デコードも同様に表を更新しながらデコードする 0 0 形を調整 new 00を出力 new 頻度1の新しいノード Shanon-Fano 符号 配列解析アルゴリズム特論 渋谷 トップダウンに作ろうとした符号 出現頻度でソート できるだけ半分に近いように分割し、片方に0、もう片方に1 を割り当てる H(X)≦L<H(X)+1 は満たす ただしハフマン符号と異なり、最適とは限らない A T 0.7 0.11 G 0.1 C N 0.07 0.02 Huffman Codingの欠点 配列解析アルゴリズム特論 渋谷 出現確率に大きな偏りがあるとうまく扱えない H(S)≦平均長<H(S)+p+0.086 (p: 最大出現確率) ほとんどが0、といったコードなどではあまり圧縮で きない Tunstall Code 配列解析アルゴリズム特論 渋谷 逆にソース側の長さを可変とする方法もある a a a a 001 a b 000 a b b 100 b b 101 b a 110 b 111 011 010 さらにHuffman 符号と組み合わせることが可能 0がたくさん続くような01列の圧縮 配列解析アルゴリズム特論 渋谷 Run-length coding FAX画像など 0101000110000010100000000100100010001 1 1 3 0 5 1 8 2 3 3 Golombコード ソース 頻度 00000 0001 001 01 1 121 45 21 15 10 Huffman符号化 Arithmetic Code (1) 配列解析アルゴリズム特論 渋谷 [0,1)の実数は01列で表すことが可能 0.0 1.0 Arithmetic Code (2) 配列解析アルゴリズム特論 渋谷 考え方 文字列を2つの実数からなる範囲に対応させる 確率の高い文字列は大きい範囲で→表すのに必要なビット 数が少なくなる 実数とは別に文字数を記憶しておく必要がある aa a aba abaa 0.0 ab b abb abab 0111 011 1.0 Decoding Arithmetic Codes 配列解析アルゴリズム特論 渋谷 3つのステップ 比較 文字出力 スケーリング(対象となる区間を[0.1)に拡大する) aa a aba abaa 0.0 ab b abb abab 0111 011 1.0 Adaptive Arithmetic Coding 配列解析アルゴリズム特論 渋谷 最初はすべての文字を等確率、とおき、2文字目以 降はそれを更新していく、ということが簡単に可能 デコードも可能 もっと賢く予測といえばマルコフモデル→PPM圧縮 きわめて高い圧縮率を誇る 処理速度は遅い A C 1 2 1 1 2 G T 1 2 3 1 1 2 1 PPM (Prediction with Partial Matching) 配列解析アルゴリズム特論 渋谷 長さm以下の部分文字列に対し、次に来る文字を予測 新しい「出現」時は、より短い部分文字列からの予測率を用いる 区別するための記号(ESC)を用意 ESCの頻度はすでに表れたことのある文字の種類の数 いろんなバリエーションが存在:例えばPPMAでは単に1とおく 初めての出現文字の並びの場合にはすべての文字が等確率に出現、と 仮定 頻度表はデコード時にも作成できるので、記憶する必要はない 直前の文字 次の文字の頻度 ATGCG A:2 C:1 ESC: 2 ATGCT A:7 C:4 G:21 T:3 ESC: 4 ATGGA G:2 ESC: 1 頻度表を作成する JBIG1: Binary imageの圧縮 配列解析アルゴリズム特論 渋谷 直前の10bitの「画像」から予測 1 2 3 4 5 6 7 9 10 8 Arithmetic Coding LZ77 (Ziv-Lempel '77) 配列解析アルゴリズム特論 渋谷 辞書法 一度出てきた単語はまた出てくることが多い 出てきた文字列で一番長く一致する部分をみつけ、その 場所と長さでコーディング 計算方法 接尾辞木を使えば線形時間! ただしメモリは多く必要 とてもまともなとまとももともとまともなとまとではなかった 4,2 12,2 4,7 さらにHuffman符号と組み合わせる→LZH,zip,PNG Shanon-Fano符号と組み合わせる→gzip LZ78 (Ziv-Lempel '78) 配列解析アルゴリズム特論 渋谷 すべての位置から探すのは大変なので、コードとして 既に使われたものを用いる すでにコードされたもの+1文字でコード 位置ではなく位置の差分で とてもまともなとまとももともとまともなとまとではなかった 4, も 6, ま 3, も 4, と 6, と 8, な 5, と 以前に出てきた場所との差+1文字でコード 9, か LZW (Welch) 配列解析アルゴリズム特論 渋谷 先に1文字だけの辞書を用意し、さらに、辞書を先に 作成しておけば、場所だけの記憶でコードできる 辞書はエンコード時に作成できるので、特に覚える必要 はない 高速だが圧縮率はさほど高くない 事前に作成してあるアルファベット表 1:と 2:て 3:も 4:ま 5:な 6:で 7:は 8:た 9:か 10:っ とてもまともなとまとももともとまともなとまとではなかった 11 13 12 15 14 17 16 19 18 3 3 15 21 20 18 15 23 22 17 14 25 24 6 7 5 9 10 8 27 26 29 28 31 30 gif や tiffで使用 暗黙的なコード 1 2 3 4 1 3 5 1 14 文法型圧縮 (SEQUITUR) 配列解析アルゴリズム特論 渋谷 文脈自由文法で表す=圧縮になっている 表したものをさらに算術符号(等)で圧縮する とてもまともなとまとももともとまともなとまとではなかった S D C B A → → → → → とてもDBCCDAではなかった Bなと もと Aも まと 変換した文字列: とてもD(B(A(まと)も)なと)BC(もと)CDAではなかった さらに算術符号で圧縮 Block Sorting [Burrows, Wheeler '94] 配列解析アルゴリズム特論 渋谷 BWT (Burrows-Wheeler Transform) Suffix Array と極めて関連が深い (FM-Index) MTF(move to front) coding ここまでは全く圧縮されていない状態 これらを行った後、通常のハフマン符号・算術符号等を用いる 処理するのに巨大すぎる場合はブロック化→ブロックソーティング BW変換するためのメモリ・計算時間に限界 cf. 0: 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 10: i$ mississippi$ 7: ippi$ ississippi$ 4: issippi$ ssissippi$ 1: ississippi$ sissippi$ 0: mississippi$ issippi$ 9: pi$ ssippi$ 8: ppi$ sippi$ ソート 6: sippi$ ippi$ 3: sissippi$ ppi$ 5: ssippi$ pi$ i$ 接尾辞配列 2: ssissippi$ BWT (Burrows-Wheeler Transform) 配列解析アルゴリズム特論 渋谷 接尾辞配列:SA[0..n] ただし、文字列はサイクル化したものを考える 文字列の最後に$を入れておけば、通常のSAと特に違いはない BWT[i] = T[SA[i]−1] BWT サイクル化した全接尾辞 0: 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: mississippi$ ississippi$m ssissippi$mi sissippi$mis issippi$miss ssippi$missi sippi$missis ippi$mississ ppi$mississi pi$mississip i$mississipp $mississippi ソート 10: 9: 6: 3: 0: 11: 8: 7: 5: 2: 4: 1: 接尾辞配列 i 11: $mississippi p 10: i$mississipp s 7: ippi$mississ s 4: issippi$miss m 1: ississippi$m $ 0: mississippi$ p 9: pi$mississip i 8: ppi$mississi s 6: sippi$missis s 3: sissippi$mis i 5: ssippi$missi i 2: ssissippi$mi 同じ BWTの性質 配列解析アルゴリズム特論 渋谷 似た文字がかたまって出現する 似た文字列の前は同じ文字が出現しやすいから! この性質を利用して圧縮するとかなり小さくできる MTF変換+算術符号等 この文字列からもとの文字列を復元できる! BWT mississippi$ 復元 10: 9: 6: 3: 0: 11: 8: 7: 5: 2: 4: 1: 接尾辞配列 i 11: $mississippi p 10: i$mississipp s 7: ippi$mississ s 4: issippi$miss m 1: ississippi$m $ 0: mississippi$ p 9: pi$mississip i 8: ppi$mississi s 6: sippi$missis s 3: sissippi$mis i 5: ssippi$missi i 2: ssissippi$mi BWTの復元 配列解析アルゴリズム特論 渋谷 n 桁のRadix Sortを行うだけ 計算量: O(n2) 実はO(n)にできる! BWT i p s s m $ p i Sort s s i i i$ $ pi i si i si i mi i $m m pp p p BWTを ip Radix s 頭に加 ss Sort s えて ss is s is s 1文字目が 得られる i$m $m pi$ i$ sip ip sis is mis is $mi mi ppi pi pp BWTを ipp si 頭に加 ssi si えて ssi iss ss iss ss 2文字目が 得られる $mississippi i$mississipp ippi$mississ issippi$miss ississippi$m mississippi$ pi$mississip Radix Sortを ppi$mississi 繰り返して、 sippi$missis 最終的には sissippi$mis ssippi$missi ssissippi$mi すべてを得る ことができる BWTの線形時間復元 配列解析アルゴリズム特論 渋谷 (一桁分の)ソートの矢印を逆に辿っていく 最初の文字がどれに相当するか覚えておく ただし、覚えてなくても $ を探してそこから始めればOK 最初の文字からスタート →を辿りながら、BWT 側の文字を出力 BWT i p s s m $ p i s s i i ソートされた文字 (接尾辞配列の最初の文字) $ i i i i m p p s s s s Bucket Sort (同じ文字ならば順番は変えない = Radix sortの基本) MTF(move to front) Coding 配列解析アルゴリズム特論 渋谷 同じ文字が前回出現してから、何種類の他の文字が出現したか? 初出の文字は適当に処理 BWT後の文字列を変換すれば偏りのある数字列になる 小さい数字が多く現れる 算術符号その他の適当なアルゴリズムで圧縮すれば、かなり小さくできる デコードは簡単 計算量 バランス木で表現すればO(n log s) テキスト 変換した数字 変換表 0 1 2 3 adbdbaabacdadc 03211201133212 aadbdbaabacdadc bbadbdbbabacdad ccbaaaddddbacca ddccccccccdbbbb 出来の悪いウィンドウズのメニューみたいな 適当 BW変換による索引: FM-Index (1) 配列解析アルゴリズム特論 渋谷 BW変換を用いて検索もできる! 逆方向検索: 接尾辞木のWeiner Algorithmの逆suffix linkを辿 ることに相当する 1文字前に着目! BW変換した 文字列に Aがいくつあるか がわかれば、 α の接尾辞配列 上の場所から、 Aαの接尾辞配列 上の場所が 計算できる 文字列 Aα Aで始まる接尾辞 Cで始まる接尾辞 Gで始まる接尾辞 文字列 α Tで始まる接尾辞 Suffix Array FM-Index (2): 例 配列解析アルゴリズム特論 渋谷 BW変換された文字列 Suffixes starting with A #T = 89 #G = 431 #T = 150 C Suffixes starting with C #G = 455 431 455 89 150 TC GTC Suffixes starting with G Suffixes starting with T FM-Index (3) 配列解析アルゴリズム特論 渋谷 位置を知るには? BW-変換されたテキストのある位置が 元のどの位置に対応するのか(=すな わちsuffix arrayの値)は、そこから decodeを行えばよい BWTの復元の要領で ただし、それでは O(n) の時間がかかる 間引きされたsuffix arrayを持っておくと よい z ごとに間引くと、 z 倍のオーバーヘッドが かかる BWT i p s s m $ p i s s i i $ i i i i m p p s s s s FM-Index (4) : WeinerのPrefix Linkと検索 配列解析アルゴリズム特論 渋谷 葉のSuffix link(群)を逆にたどる(すなわちPrefix linkを辿る)と 逆順の部分文字列になる、ということと対応している Suffix tree of 'mississippi$' mississippi$ ississippi$ ssissippi$ sissippi$ issippi$ ssippi$ sippi$ ippi$ ppi$ pi$ i$ All the suffixes これに注目し ていることと 同じ $ i s p $ pp$ i$ ssi pi$ i ppi$ ssippi$ ‘s’で始まる葉 ppi$ i s si ppi$ ssippi$ mississippi$ i ひとつ前が ‘i’ の ものは2つ ssippi$ s ‘s’の前が’i’である葉 ‘s’ の前が ‘i’ であるものを探す FM-Index (5) : 検索に必要なデータ構造 配列解析アルゴリズム特論 渋谷 この時、BW変換した文字列以外に必要なもの: なんと、接尾辞配列、元の文字列は保持しなくてよい!!! すなわち、以下の補助データ構造のサイズが十分小さければ、これ は極めてコンパクトな索引構造として利用することができる! さらに、(遅さを気にしなければ)BW変換した文字列は圧縮可能! ただし、任意の i に対し i 文字目に、(圧縮率のために速さを犠牲にした としても)何らかの方法でアクセス可能な圧縮方法でないといけない 各文字が何文字ずつあるか これを覚えておくことで、 次のindexを計算できる 逆に、indexからそれに対応する文字が何か計算できる BW変換した文字列BW[0..n]上で(多少遅くてもよいので) BW[0..i]に文字xがいくつあるか が計算可能な(なるべく小さな)データ構造 (Rank/Select データ構造) Rank / Select データ構造 配列解析アルゴリズム特論 渋谷 3つの操作 access(A, i) = A[i] rankc(A, i) = #j s.t., A[j]=c, j<i selectc (A, i) = j s.t., rankc(A, j) = i ナイーブに表を持つと access 元の文字列を持っているだけでOK rank select a b c b c c a b c 1 0 0 1 1 0 1 1 1 1 2 1 1 2 2 1 2 3 A ナイーブなrank表 いずれも、(文字の種類数)×(文字列長)×(整数のサイズ)のサイ ズの表で、constant timeを(線形時間の前処理で)実現できる 片方がconstant timeでできれば、他方は二分探索でO(log n)が可能 が、これではBW変換の補助データ構造のサイズが 通常の接尾辞配列のアルファベットサイズ倍、という 巨大なものになってしまう!(それではほとんど意味がない) 小さくする方法: ブロック化による間引き 配列解析アルゴリズム特論 渋谷 01列の場合(簡単化のため) wビットずつに分割して、wビットずつの間引きされたrank結果 は覚えておく 2w種類のすべてに関してrankの結果を計算し、保管する RMQのアルゴリズムと少し類似 すると必要なメモリは 𝑛𝑛 𝑤𝑤 ( ) · log 𝑛𝑛 + 2𝑤𝑤 log 𝑤𝑤 bit 𝑤𝑤 = log 𝑛𝑛 とすると これは 𝑛𝑛 + 𝑛𝑛 log log 𝑛𝑛 bit 接尾辞配列(𝑛𝑛 log 𝑛𝑛 bit)よりは小さそう が、BW変換後の文字列 (𝑛𝑛 bit)よりは大きい rankの計算時間は constant timeで可能 0110101110101100010101100001110100110 ブロック化による間引き その2 配列解析アルゴリズム特論 渋谷 先ほどのブロック化では、間引いたrankはすべての桁を保持し ていた(=大きな数字を覚えていて無駄) 2段階ブロック化 l ビットごとにブロック化(大ブロック) 先頭のrankはすべて記憶 途中については、大ブロック先頭からの差分で記憶する それぞれのブロックをwビットごとにブロック化 この中は先ほど(その1)と同様の計算を行う すると、それだけで 𝑛𝑛 𝑙𝑙 𝑛𝑛 log 𝑙𝑙 + 2𝑤𝑤 log 𝑤𝑤 bitで格納できる 𝑤𝑤 log 2 𝑛𝑛、𝑤𝑤 = (log 𝑤𝑤)/2 の時、o(n)ビット log 𝑛𝑛 + これは𝑙𝑙 = → 無視できる! 0110101110101100010101100001110100110 - select も同様のことが可能だが、通常は2分探索で実現することが多い - アルファベットサイズが大きい場合も同様のことは可能だが、大きくなってしまう。 Wavelet 木 Wavelet 木(概要) 配列解析アルゴリズム特論 渋谷 rank/selectをアルファベットの2分探索的に行うデータ 構造 それぞれの01列に対し先ほどのデータ構造を作成すれば、 オーバーヘッドはlog(アルファベットサイズ)倍ですむ ATGCGCGATACTGAT 011010101001101 AC/GT で分類 ACのみ抽出 GTのみ抽出 A/Cで分類 A 1 0 ACCAACA 0110010 0 1 0 1 C TGGGTTGT 10001101 G T G/Tで分類 様々な応用がある! Yet Another 圧縮索引: 圧縮接尾辞配列 配列解析アルゴリズム特論 渋谷 接尾辞配列を(もう少しストレートに)圧縮するには? Ψ(プサイ、接尾辞配列上のSuffix Link)を用いることが可能 すなわち、FM-Indexとは完全に逆の考え方! (FM-Index同様)エントロピーに比例した圧縮が可能 順方向の検索がメインとなる 0: 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: mississippi$ ississippi$ ssissippi$ sissippi$ issippi$ ssippi$ sippi$ ippi$ ppi$ pi$ i$ ソート 接尾辞配列 10: 7: 4: 1: 0: 9: 8: 6: 3: 5: 2: i$ ippi$ issippi$ ississippi$ mississippi$ pi$ ppi$ sippi$ sissippi$ ssippi$ ssissippi$ Suffix Array 上の Suffix Link 配列解析アルゴリズム特論 渋谷 プサイ Ψ (接尾辞配列上のSuffix Link) 逆接尾辞配列から簡単に作成可能 Textは記憶しなくてよい 必要ならばΨ(とアルファベットリスト)から計算可能なため Index / All suffixes 0: 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: mississippi$ ississippi$ ssissippi$ sissippi$ issippi$ ssippi$ sippi$ ippi$ ppi$ pi$ i$ $ Index / Suffix array / suffixes ソート 0:11: 1:10: 2: 7: 3: 4: 4: 1: 5: 0: 6: 9: 7: 8: 8: 6: 9: 3: 10:5: 11:2: $ i$ ippi$ issippi$ ississippi$ mississippi$ pi$ ppi$ sippi$ sissippi$ ssippi$ ssissippi$ Ψ 0 7 10 11 4 1 6 2 3 8 9 Ψからのテキストの復元 配列解析アルゴリズム特論 渋谷 一番長い接尾辞がどこにあるかを覚えておいて、そ こからΨを辿っていくだけで、復元できる アルファベットがそれぞれ何個あるかは覚えておく Index / Suffix array / suffixes i m p s 0:11: 1:10: 2: 7: 3: 4: 4: 1: 5: 0: 6: 9: 7: 8: 8: 6: 9: 3: 10:5: 11:2: $ i$ ippi$ issippi$ ississippi$ mississippi$ pi$ ppi$ sippi$ sissippi$ ssippi$ ssissippi$ Ψ 0 7 10 11 4 1 6 2 3 8 9 ここから開始 Ψの圧縮 配列解析アルゴリズム特論 渋谷 アルファベットごとに区切ると単調増加 差分で覚える すると、小さい値が非常に多くなり、圧縮しやすくなる しかも、似たもののsuffix link先も似ているため類似部分列も多い → 圧縮効率も良い! cf. 接尾辞木のDAG化 Index / Suffix array / suffixes i m p s 0:11: 1:10: 2: 7: 3: 4: 4: 1: 5: 0: 6: 9: 7: 8: 8: 6: 9: 3: 10:5: 11:2: $ i$ ippi$ issippi$ ississippi$ mississippi$ pi$ ppi$ sippi$ sissippi$ ssippi$ ssissippi$ Ψ 0 7 10 11 4 1 6 2 3 8 9 Ψi - Ψi-1 7 3 1 5 1 5 1 Ψの圧縮 配列解析アルゴリズム特論 渋谷 しかし、差分で覚えると、実際の値を計算するのに 時間がかかってしまう 間引いて途中の値を適当に覚えておけばよい O(n/log n)程度のサイズに間引けば、O(log n)時間で計算 できる、といったかんじ スピード⇔圧縮率 のトレードオフあり 元の数列: 3 4 7 8 13 24 26 32 37 45 54 61 70 ... 差分: - 1 4 1 5 9 2 6 5 8 9 7 9 ... Ψを用いた検索 配列解析アルゴリズム特論 渋谷 SA上のある位置のsuffixはΨから簡単に復元可能 これを利用して二分探索が普通にできる O(m log n) Index / Suffix array / suffixes i m p s 0:11: 1:10: 2: 7: 3: 4: 4: 1: 5: 0: 6: 9: 7: 8: 8: 6: 9: 3: 10:5: 11:2: $ i$ ippi$ issippi$ ississippi$ mississippi$ pi$ ppi$ sippi$ sissippi$ ssippi$ ssissippi$ Ψ 0 7 10 11 4 1 6 2 3 8 9 ippi$ Ψ(suffix link)をたどっていき、それ ぞれどのアルファベットの領域にあ るかをチェックしていく 検索結果の位置を知るには? 配列解析アルゴリズム特論 渋谷 SA[i]の値がわかればよい テキスト全体の復元と同様に Ψを辿っていけば、計算でき Index / Suffix array / suffixes る 0:11: $ 1:10: i$ ただそれだとO(n)時間かかっ てしまうため、間引いた接尾 i 2: 7: ippi$ 3: 4: issippi$ 辞配列をもっておけば、その 4: 1: ississippi$ 計算時間を短縮できる。 たとえばO(n / log n)サイズ にまで間引いておけば大幅 に時間が短縮できる上に、さ ほどサイズは大きくなくてす む。 こうしておけば、テキストを部 分的に復元することもできる ようになる。 m p s 5: 0: 6: 9: 7: 8: 8: 6: 9: 3: 10:5: 11:2: mississippi$ pi$ ppi$ sippi$ sissippi$ ssippi$ ssissippi$ Ψ 0 7 10 11 4 1 6 2 3 8 9 まとめ 配列解析アルゴリズム特論 渋谷 文字列圧縮アルゴリズムのいろいろ Huffman coding Shannon-Fano coding Tunstall coding Run-length coding Golomb coding Adaptive Huffman coding Arithmetic coding PPM LZ77, LZ78, LZW Sequitur Block sorting (BWT+MTF) FM-Index, Compressed suffix array 次回 文字列上のパタン発見・学習