我们被要求找到一种尽可能多地压缩方形二进制矩阵的方法,如果可能的话,添加冗余位以检查并纠正错误。
在我看来,冗余的东西很容易实现。复杂的部分是压缩矩阵。我想在将矩阵重新整形为矢量后使用游程长度,因为会有更多的零,但是我只实现了40位压缩(我们正在处理小尺寸),尽管我认为它会更好。
此外,在游程后,一个想法是霍夫曼编码矩阵,但必须发送字典才能恢复原始信息。
我想知道压缩二进制矩阵的最佳方法是什么?
阅读了一些评论后,是的,@ Adam你是对的,14x14矩阵应该用128位压缩,所以如果我只使用每个非零元素的坐标(行和列),那么它仍然是160位(因为有二十个)。我不是在寻找一个确切的解决方案,而是一个有用的想法。
答案 0 :(得分:5)
如果您有分发和表示,您只能谈论压缩某些内容。这是你必须发送的字典的问题:你总是需要某种协议字典来解压缩一些东西。恰好像.zip
和.mpeg
之类的东西已经有了这些字典/编解码器。甚至像霍夫曼编码一样简单的算法也是算法;在通信通道的另一端(您可以将压缩视为通信),另一个人已经有一些代码(字典)来执行霍夫曼解压缩方案。
因此,你甚至不能开始谈论压缩某些东西而不首先考虑“我期望看到什么样的矩阵?”,“数据真的是随机的,还是有秩序的?”,如果是这样的话,“我怎么能代表矩阵以利用数据中的顺序?“。
如果不增加其他对象的大小(至少1位),则无法压缩某些矩阵。如果所有矩阵都是同样可能的话,这是个坏消息,你同样关心它们。
<强>附录强>
使用稀疏矩阵机制的答案不一定是正确的答案。例如,矩阵可以用python表示为[[(r+c)%2 for c in range (cols)] for r in range(rows)]
(棋盘图案),稀疏矩阵根本不会压缩它,但矩阵的Kolmogorov复杂度是上述程序的长度。
嗯,我知道每个矩阵都有相同数量的矩阵,所以这是确定性的。唯一的想法我不知道是1的位置。此外,如果我使用字典传输矩阵并且存在突发错误,那么字典可能会受到影响所以...不会导致结果信息损坏?这就是我尝试使用无损数据压缩(如游程长度)的原因,解码器只是不需要字典。 - 原始海报
矩阵有多少1作为其大小的一小部分,它的大小是多少(NxN
- 什么是N
)?
此外,这是一个不正确的断言,不应该用作期望行程长度编码的理由(它仍然需要一个程序);当您通过通道传输数据时,您始终可以为此数据添加错误更正。 “数据”只是一点点。您可以通过频道传输数据和任何所需的词典。纠错机器完全不关心你传输的比特是什么。
附录2:
有(14*14) choose 20
种可能的安排,我认为是随机选择的。如果这个数字大于128^2
那么你要做的就是不可能。幸运的是log_2((14*14) choose 20) ~= 90bits < 128bits
所以这是可能的。
写下32,2,67,175,52,...,168
等20个数字的简单解决方案将无效,因为log_2(14*14)*20 ~= 153bits > 128bits
。这相当于行程编码。我们想做这样的事情,但我们的预算非常严格,而且不能用比特“浪费”。
因为你平等关心每种可能性,你的“字典”/“程序”将模拟一个巨大的查找表。 Matlab的稀疏矩阵实现可能有效但无法保证工作,因此不是正确的解决方案。
如果您可以在数字范围[0,2^128)
和尺寸为20的子集之间创建双射,那么您就可以了。这对应于枚举将http://en.wikipedia.org/wiki/Binomial_coefficient中的金字塔下降到第196行的第20个元素的方法。这与枚举所有“k-组合”相同。见http://en.wikipedia.org/wiki/Combination#Enumerating_k-combinations
幸运的是,我知道Mathematica和Sage以及其他CAS软件显然可以生成“第5”或“第12”或任意编号的k子集。通过他们的文档,我们得到了一个名为“rank”的函数,例如http://www.sagemath.org/doc/reference/sage/combinat/subset.html
然后我们再做一些搜索,并遇到一些神秘的Fortran代码,例如http://people.sc.fsu.edu/~jburkardt/m_src/subset/ksub_rank.m和http://people.sc.fsu.edu/~jburkardt/m_src/subset/ksub_unrank.m
我们可以对它进行逆向工程,但它有点密集。但现在我们有足够的信息来搜索k-subset rank unrank
,这会导致我们http://www.site.uottawa.ca/~lucia/courses/5165-09/GenCombObj.pdf - 请参阅本节
“生成k-子集(n-集):词典
在接下来的几页中订购“以及rank
和unrank
算法。
为了实现精确的理论上最佳压缩,在1s的均匀随机分布的情况下,我们必须使用该技术将矩阵生成到我们的范围<2^128
的输出数。恰好相反,组合具有自然排序,称为排名和组合的排名。您为每个组合(排名)分配一个数字,如果您知道该数字,则自动知道该组合(排名)。谷歌搜索k-subset rank unrank
可能会产生其他算法。
因此,您的解决方案将如下所示:
serialize the matrix into a list
e.g. [[0,0,1][0,1,1][1,0,0]] -> [0,0,1,0,1,1,1,0,0]
take the indices of the 1s:
e.g. [0,0,1,0,1,1,1,0,0] -> [3,5,6,7]
1 2 3 4 5 6 7 8 9 a k=4-subset of an n=9 set
take the rank
e.g. compressed = rank([3,5,6,7], n=9)
compressed==412 (or something, I made that up)
you're done!
e.g. 412 -binary-> 110011100 (at most n=9bits, less than 2^n=2^9=512)
to uncompress, unrank it
答案 1 :(得分:3)
您的输入是稀疏矩阵的完美候选。你说你正在使用Matlab,所以你已经为你构建了一个很好的稀疏矩阵。
spm = sparse(dense_matrix)
Matlab的稀疏矩阵实现使用压缩稀疏列,其内存使用量为2*(# of nonzeros) + (# of columns)
,在20个非零和14列的情况下应该相当不错。存储20个值肯定比存储196 ...
还记得Matlab中的所有矩阵都是由双精度组成的。仅仅因为您的矩阵可以存储为1位布尔值并不意味着Matlab不会将其粘贴到64位浮点值中...如果您确实需要它作为布尔值,那么您将不得不制作它您自己的C类型,并使用.mex文件与Matlab进行交互。
答案 2 :(得分:3)
我将在一秒内达到128位,首先是你如何将14x14布尔矩阵与20位非零值匹配到136位。它基于CSC稀疏矩阵格式。
您有一个数组c
,其中包含14个4位计数器,可以告诉您每列中有多少非零值。
你有另一个数组r
,有20个4位行索引。
56位(c)+ 80位(r)= 136位。
让我们从c
中挤出8位:
而不是4位计数器,使用2位。 c
现在是2 * 14 = 28位,但每列不能支持超过3个非零值。这给我们留下128-80-28 = 20位。将该空间用于数组a4c
,其中包含5个4位元素,这些元素将4位元素指定的“c添加4”。因此,如果a4c={2,2,10,15, 15}
表示c[2] += 4; c[2] += 4 (again); c[10] += 4;
。
非零的“最浪费”的分布是列数需要add-4来支持1个额外的非零值的分布:所以5列,每列有4个非零值。幸运的是,我们有5个add-4可用。
总空间= 28位(c)+ 20位 (a4c)+ 80位(r)= 128位。
答案 3 :(得分:-1)
再次考虑这个之后,如果你的所有矩阵都变得很小并且它们都是二进制的,那么只需将它们存储为二进制向量(位掩码)。关闭14x14示例,需要196位或25个字节(如果尺寸不恒定,则加n,m)。 Matlab中的相同向量将使用每个元素64位,或1568字节。因此,将矩阵存储为位掩码需要与Matlab中原始矩阵的4个元素一样多的空间,压缩比为62x。
不幸的是,我不知道Matlab本身是否支持位掩码,或者你是否必须使用.mex文件。如果你进入C ++,你可以使用STL的vector<bool>
为你实现位掩码。