|
| BlockSortingは、今までのデータ圧縮で有名な方法であるLZ法とは全く違う、ユニークな操作を用 いてデータを圧縮する方法であり、M.BurrowsさんとD.J.Wheelerさんが作者なので「BWTransform」 ともいいます。 このアルゴリズムは簡単に言ってしまえば、「データをぐるぐる回してソートして出力」というも ちなみに、このBlockSorting、単体では全く圧縮しません。ただ可逆な形にデータを変換すると このBlockSortingというアルゴリズムは非常にシンプルなアルゴリズムでありながら、実装が難し |
| BlockSortingの詳細
では、アルゴリズムの紹介です。例えば変換したいデータが「abraca」だとします。
元データ:abraca 回転した後のデータは次の通り 1 abraca (2)このように一文字ずつ回転させたら、これを辞書順(普通の国語辞書などのようにAの方がZ 6 aabrac (3)それぞれの文字列の最後の文字を出力します。すると、 6 aabra[c]
というふうにやっていくと、caraabですね。これを出力します。 それに加え、元データが何番目にあるかを 出力します。この場合だとabracaは2番目なので「2」を出力します。 これで終わりです。 非常に簡単でしょう? これで、なぜデータが圧縮しやすくなるのかというのは後から説明します。 |
復元
まずcaraabを一文字ずつソートさせます。 a 次にこのデータをBlockSortingした時のことを思い出しましょう。もちろん復元時は 6 aabrac ☆ こういうふうに並んでいて一番最初のaの前がc、二番目のaの前がaというのが分かるで この時点でBlockSorting前のデータはどうだったのかというのは c - a という風につながっているというところまで分かりました。この次はこれらがどのように c - a ということが分かります。ここまでは何となく分かるでしょうが、ここからが難しくなります。 (3)c - a よってこの段階では a - b - r - a a - c - a というふうにつながっているのが分かりますね。しかし、これが a - b - r - a - c - a とつながっているのか
c - a1 さらに戻ってBlockSorting前のことを考えてみます。(もちろん復元時には想像できない) 6 [a1]abrac すると、ここが復元の一番山場なのですが、ソートする時、最初に同じものが並んだ場合、次の文字の大小関係を調べますよね。 つまりこの場合だと 6 [a1] (a) brac この()で囲まれたところで大小関係を判断します。よって、上のデータが、一つずつ左に (a) brac [a1] のようになります。 c - a1 は、 c - a1 となります。よって、残りはこれをくっつけるだけ。 a2 - b - r - a3 - c - a1 番号は分かりやすいように付けたものですので、くっつけると、 abraca となります。復元できましたね。メデタシメデタシ |
BlockSortingの効果
t he・・・・ といろんな場所にあるtheがソートにより集まり、tが並ぶというわけです。 もちろんabracaという6文字のデータのソートでは全然揃わないわけですが、 実際サンプルを見てもらうといいと思います。次の文章 I have a cat. The cat is very cute. これをブロックソーティング(完全ソートとは違って後から話す限定ソート)すると ThccavicI h ttvaau .r aesy . etee となります。aやeが並んでいるのが分かるでしょう。これが何十万文字のデータとなると、 |
・BlockSortingの実装の前に
単純に考えると、1MBのデータを回転させると1MB*1MB =1TB つまり1TB必 まずは、回転させるという話ですが、実際これは仮想的に回転させると考えて実際はポジション abracaabraca このデータと、どこから始まる位置を指定したデータの二つで、回転したデータを表現することができます。 0 1 2 3 4 5 6 7 8 9 A a b r a c a
これでメモリの問題は解決しましたが、次はスピードの問題です。ブロックソーテ 例えばbzipはまず最初に2文字分布数えソートをします。これで最初の2文字だけ また、現在有望な方法にszipが使っている限定ソートという方法があります。 他にも様々な方法を用いることにより、十分に使用に耐えうる速度(LZ法に匹敵)にする 次に、ブロックソーティング後のデータに対し有効な圧縮法を紹介したいと思います。 aaaaaaaaaaaaabbbbbbb とならんだデータは 0000000000001000000 これ以外のブロックソーティングの有効な圧縮の方法を説明したいと思います。 この切り替えのタイミングは、実はソート時に分かります。というのも aabrac というふうに最初の文字が変わると、出力する文字が同じ物ばかりなのか、もしくは aaaaaaabaaaaaaaaaaa というふうに大量にaが並んでいる中、bが一つあったりすると 0000000110000000000 となります。つまりbが一つあるために1が二回出力されてしまうのです。 |
BlockSortingの実装
最初にbuffer[N * 2 + 1]とpos[N]とcount[0x100 * 0x100]を準備します。 unsigned char buffer[N * 2 + 1]; //始めに、bufferの 0-Nまでに加工したいデータを入れる //そして、後ろに同じ文字コピーする
//次に分布を数える /* count[] は、二文字の分布を数える。つまり、ab だったら a << 8
+ b //そして分布を足す //最後にposにポジションを入れる //ここまでで始め二文字のソートは完了した。次に残りの文字のソートを行う for (i = 0; i < 0x100 * 0x100 - 1; i++) //最後に出力 //最初の元データがある場所を出力 } void sort(int start,int last,int number) if (range > 100)
といってもわからないので具体的には次のプログラムを見て下さい。 bsEncoder.hpp 符号化 実際に実行ファイルを作りたい場合は、これらをビルドすればいいわけですが、ここにあります。 使い方は test.txtをtest1.bin というファイルに符号化したい場合 符号化の時、bsEncoder.hppの様々な設定をいじるとdebug.txtにいろんなdebug情報が出力されます 最適な方法とかちゃんとコメント書けとかあるかもしれませんが、即席なので、このくらいです。
|