为什么liblzma无法压缩任何随机字符串?

时间:2015-05-07 10:02:11

标签: string random compression complexity-theory

我正在使用ruby绑定ruby-xz

random_string = SecureRandom.random_bytes(100)
compressed_string = XZ.compress(random_string, compression_level = 9, check = :none, extreme = true)
compressed_string.size # => always 148

我已经用不同长度的琴弦测试了数千次。

我知道至少有一半的字符串是1不可压缩的(不能超过1位压缩),3/4的字符串是2不可压缩的等等。(这是从计数参数开始的。) ,显然,没有说可压缩字符串数量的下限,但肯定有一些,不存在吗?

1 个答案:

答案 0 :(得分:1)

解释

有几个原因:

  1. liblzma,当不处于RAW模式时,会添加一个描述字典大小的标题和一些其他设置。这是它增长的原因之一。

  2. 与许多其他压缩器一样,LZMA使用范围编码器以最少的位数编码字典压缩的输出(实质上是LZ77的badass版本)。因此,在比特流的末尾,填充最后的比特以使其成为一个完整的字节。

  3. 您正在压缩随机噪音,正如您所说,难以压缩。范围编码器试图找到最少量的比特来编码由字典压缩轮输出的符号。所以在这种情况下,会有很多符号。如果LZMA发现了一个(或两个)重复模式,那么最终它只能从输出中节省一两个。如第2点所述,您无法在字节级别上观察。

  4. 实验

    观察开销的一些小实验。

    在原始模式下使用lzma的空文件:

    $ dd if=/dev/urandom bs=1k count=0 2>/dev/null | xz -9 -e --format=raw -c 2>/dev/null | wc -c
           1     
    

    它需要至少一个或两个比特才能说它到达流的末尾,这被填充到一个字节

    1k文件用零填充

    $ dd if=/dev/zero bs=1k count=1 2>/dev/null | xz -9 -e --format=raw -c 2>/dev/null | wc -c
          19
    

    非常好,但复杂性理论明智,仍然可能是几个字节到很多(1000x'\ 0'将是最佳编码)

    1k文件,所有位均为1

    $ dd if=/dev/zero bs=1k count=1 2>/dev/null | sed 's/\x00/\xFF/g'| xz -9 -e --format=raw -c 2>/dev/null | wc -c
          21
    
    有趣的是,xz压缩比全零更糟糕。很可能与LZMA字典在一定程度上有效(这是LZMA的新颖思想之一)有关。

    1k随机文件:

    $ dd if=/dev/urandom bs=1k count=1 2>/dev/null | xz -9 -e --format=raw -c 2>/dev/null | wc -c
        1028
    

    比输入多4个字节,还不错。

    1000个1k随机文件:

    $ for i in {1..1000}; do dd if=/dev/urandom bs=1k count=1 2>/dev/null | xz -9 -e --format=raw -c 2>/dev/null | wc -c; done | sort | uniq -c
    1000     1028
    

    所以每次都需要1028个字节。