連長圧縮(RLE)

任意のテキストを入力すると、それがランに分割される様子を確認できる — 同じ文字が連続して繰り返されると、単一の(記号, 個数)のペアに圧縮される。長いランはデータを縮小し、短いランはデータを増大させる。

インタラクティブシミュレーションを読み込んでいます...

レッスン

理論 — 連長圧縮(RLE)

ランレングス符号化は、同じ記号が続く極大の並び(ラン)を、ひとつの(記号, 個数)の組に置き換えます。読み取り欄に届くのはテキストではなく二つの数、N 文字と R ラン です。ページ上のそれ以外の数値は、すべてこの二つの商にすぎません。

各記号の意味

N
入力される文字数。入力した文字列の長さ、それだけです。
R
ランの数、つまり同じ記号が繰り返される極大ブロックの数。隣り合う二文字が異なるたびに R は 1 増えます。数えているのは境界であって、文字ではありません。
N/R、平均ラン長。結果を決めるのはこの量だけです。
ratio
N/2R、すなわち L̄/2。1 を超えれば出力は入力より小さくなります。

公式の導き方

  1. 文字ではなくランを数えます。0010111100001111 では隣同士が 5 か所で異なるので、ランは 6 本、行には R=6 と出ます。
  2. 符号化後の大きさは 2R、それ以外の要素はありません。ランが何でできているかは計算に一度も入らず、6 本のランは画素でも文字でも数字でも 12 単位です。
  3. 割り算します。ratio = N/2R = L̄/2。損益分岐点は L̄ = 2 にあり、しかもちょうど到達できます。AABB と入力すれば、棒グラフは入力 4 バイト、出力 4 バイトを示します。
  4. 上下の向きは対称ではありません。上には限りがなく、100 万文字のランひとつは組ひとつになります。下の床は 0.50× で、これより下はありません。入力にできる最悪のことは、各文字にそれぞれのランを与えることだからです。

表示の読み方

四つの見本はどれもちょうど 16 文字で、だからこそまとめて読む価値があります。画像の走査線はラン 3 本で 6 バイト。典型的なランは 4 本で 8。ビットマスクは 6 本で 12。最悪の場合は 16 本で 32。入力の長さは同じなのに、出力は 6 バイトから 32 バイトまで——5 倍の開きが、ひとえに R だけで決まります。次に hello world と入力してみてください。11 文字、10 ラン、出力 20 バイト。ふつうの文章はこの範囲の下端に落ち着きます。ランレングス符号化が単体の圧縮器ではなく圧縮器の部品である理由は、まさにそこにあります。

前提
組がちょうど 2 単位であること、記号と個数の幅が同じであること、そして個数がいくらでも大きくなれること。実際の符号化器は個数に固定幅——1 バイト、つまり 255——を与えるため、それより長いランは複数の組に分割せざるをえず、損益分岐点は 2 をわずかに上回ります。幅が同じという前提は、この方式が最も得意とするデータでこそ最も強く崩れます。1 ビットのファクス画像では、記号は 1 ビットですが、個数はそうではありません。
成り立たない場合
0.50× の床は、工夫で取り除ける欠陥ではありません。可逆符号化は元に戻せなければならず、異なる入力は異なる出力に対応する必要があります。そして写す先となる短い文字列は、長い文字列より数が少ない。したがって、ひとつでも入力を短くする方式は、必ずどこかの入力を長くします。これは数え上げの事実であって、ランレングス符号化の性質ではありません。上の三つ目の洞察にある PackBits は最悪の場合を 128 バイトにつき制御バイト 1 つ——1% 未満——まで下げますが、誰もそれ以上には行けません。床はいくらでも下げられる一方、決して到達できないからです。この方式はその費用を外側に、動くのを目で追える読み取り欄に置いているだけなのです。

なぜ損益分岐点はちょうど2なのか 🖖

どのランも — どれほど長くても — 記号に1、個数に1と、保存には常に同じ2単位のコストがかかる。長さLのランを符号化する価値があるのは、そのコストがL個の生の文字を書き出すより安い場合、つまりLが2より大きい場合だけである。入力全体で平均すると、この条件はL̄ = N/Rが2より大きいこと(Nは総長、Rはランの数)になる — これがまさに上の式が検証している境界線である。これはまた、RLEが汎用の圧縮アルゴリズムとしては貧弱である理由でもある。英語のテキスト、ソースコード、ランダムなデータでは、2より長いランはめったに現れない。そのためRLEは、1ビットのFAXスキャン、疎なビットマップ、単色領域を持つパレット画像など、意図的に長いランを持つように設計されたデータに限って使われる。実際のフォーマットはこの発想をさらに推し進めている。PNGは圧縮の前に各走査線にPaeth/Sub/Upの差分フィルタをかけ、まず滑らかなグラデーションをゼロに近い差分の長いランに変換する — その後をRLE(DEFLATE経由)が引き受ける。上の最悪ケースの例を試してみよう。16種類の異なる文字は長さ1のランを16個生み出すため、符号化には16文字を保存するのに32単位が必要になる — 入力サイズは2倍に膨張する。

自分でも思いつく圧縮 🖖

ランレングス符号化は、自力でも再発明できる唯一の圧縮アイデアです。WWWWWWW を一文字ずつ書き出す代わりに、ただ「W が7つ」と言うだけ——電話番号を「7を3回」と読むときの近道とまったく同じです。データを左から右へ一度だけ走査し、いま数えている連続部分より先は何も覚えないので、高速でストリーミングにも向きます。しかも可逆です。(記号, 個数) の組から元のデータを完全に復元できる点が、細部を永久に捨てる JPEG や MP3 とは違います。

膨張しないRLEの親戚 🖖

素朴な RLE は圧縮しにくいデータを2倍にしかねませんが、Apple の PackBits——1980年代の MacPaint で生まれ、今も TIFF の標準的な圧縮モード——はほとんど膨張しないよう設計されています。各ブロックは符号付きの1つの制御バイトで始まり、非負の値は「続くバイトはそのまま」、負の値は「次のバイトを繰り返す」を意味します。ユニークなデータは最大128バイトのまとまりでそのままコピーされるため、最悪でも128バイトあたり制御バイト1つしか増えません——素朴な RLE が達しうる100%ではなく、1%未満のオーバーヘッドです。

全プロセスの詳細解説

  1. AAAAAABBBCCDDDDD の四つのペアへのランレングス符号化 5 ステップ

    ランレングス符号化により、AAAAAABBBCCDDDDD は4つのペアに変換される。圧縮率を計算し、さらにこの方式がファイルをかえって大きくしてしまう正確な条件を求めよ。

    1. 符号化は明快である。連続する各ランを、文字とその長さに置き換える。16文字が4つのペアへと縮小される。

    2. この方式へのあらゆる入力を記述するのは、長さとランの数の2つの数値であり、その比率が平均ラン長となる。ここでは 4 である。

    3. 正確に数えてみよう。各ペアは文字と個数という2つのトークンを消費するため、入力の N に対し、出力は 2R となる。データに関するそれ以外の要素は影響しない。

    4. したがって、この方式が効果を発揮するのはまさに 2R < N のときであり、これは平均ラン長が 2 を超える条件に変形できる。ここでは 16 に対し 8 となり、きれいに半減している。パネルの判定行も1つの記号で同じことを表している。

    5. そのしきい値を下回ると圧縮効果は失われ、平均ラン長が 1 のとき損失は最大となる。すべての文字がペアになり、ファイルサイズは2倍に膨れ上がる。

    解答

    ツールには N = 16 および R = 4 が表示され、平均ラン長は 4、2倍の削減となる。覚えておくべきなのは次の条件である。RLEが圧縮効果を持つのは、ランの平均が2を超えるとき、かつそのときに限られる。そしてRLEは、損益分岐点を目視で確認できる単一の数値として表せる数少ない圧縮方式の1つである。入力欄に ABCD と入力してみると、サイズが2倍に拡大するのがわかる。これは欠陥ではない。ファクス走査線、疎なビットマップ、量子化後のJPEGにおける平坦な領域など、構造上ランが保証されている領域でのみRLEが使用され続けている理由がここにある。一般的なテキストでは決して機能しない。

学習の道すじ

手作業によるデータ圧縮

この次に ハフマン

参考文献 (3)

例題

  • 典型的なラン - "AAAAAABBBCCDDDDD" → (A,6)(B,3)(C,2)(D,5) — 16文字が8組に圧縮される
  • 最悪ケース - "ABCDEFGHIJKLMNOP" — すべて異なる文字で、どの組も元より長くなってしまう
  • ビットマップマスク - "0010111100001111" — PNGがRLEの前にプレフィルタを行う理由を示すピクセル行
  • 画像の走査線 - "WWWWWWWBBBBBWWWW" — シンプルな白黒画像の一行、ラン構造が強い