yos*_*ico 5 algorithm matrix sparse-matrix
我有一个大的二进制稀疏矩阵(任何单元格都可以保存0或1作为值).我不时想拍摄整个矩阵的快照. 快照必须尽可能小.
矩阵表示2d地图和发生在区域中的事件,因此它更像是看起来像示例A的快照而不是看起来像示例B的快照(它们都具有相同数量的"1"),尽管我需要支持算法中的两个示例.
Example A:
000000000000
000000011000
001100111100
001111111100
000000111100
000001111100
000000000000
Example B:
010010010010
001000001000
010010100100
000100101010
001000010010
010010001100
001000010000
Run Code Online (Sandbox Code Playgroud)
由于数据可以从单个"1"单元格到100%单元格变为"1"(在非常非常后的情况下)我认为我需要使用多个算法 - 并且当加载数据以加载它时存储它的算法相同.
例如,当只有一个单元格时,我只存储它的索引(和"索引"算法的标识符),当99%的矩阵为"1"时,我将它存储为位图(和"位图"算法的标识符) ).
所以我得到一个像这样的通用算法:
我的问题
底线: 如何以最小的方式存储位图矩阵?
编辑 用例:我有一个稀疏矩阵,我需要通过一个非常低的带宽介质传输.因此,假设介质两侧的计算能力很强,发送矩阵应包含尽可能少的位.
数据压缩是一个很大的领域(你可以从这里开始),并且你的问题没有明确的答案.如果我们知道如何以最佳速率压缩数据,那么每年都不会有新的压缩算法;)
话虽这么说,你建议的是一个好主意:从集合中选择最佳算法并在标题中识别它.实际上,大多数压缩格式都使用这种方案.
回答你的问题:
什么算法:
bool
/ boolean
类型存储在一个完整的字节中).您必须使用按位运算,专用语言功能(如bitfields
/ bitsets
或库).例如C++
,std::vector<bool>
实现一个真正的位图(一个简单的bool[]
没有).0
或只有一个1
是对称的情况应该以相同的方式处理.备用存储的最坏情况是使用零作为零.1111
如果您知道它是一种可能的模式,您可以存储少于4位.但这意味着将使用超过4位存储另一个(不太可能)的4位模式,因此在选择模式时要小心.有很多方法可以做到这一点:固定大小或可变大小的单词,编码可以是静态的,也可以是数据相关的.一些例子是:RLE,Huffman,LZ变体(在你最喜欢的压缩程序中使用的基于字典的算法)极简证明:
由于压缩实际上取决于数据的概率分布,因此通常没有最佳的压缩算法.实际上,你知道你的矩阵总是一样的,你甚至不需要编码它.你知道它是两个可能的矩阵之一,只有一个就足以编码它是哪一个.
在一般情况下,Shanon 熵估计编码消息所需的理论最小位数:
min = E( -log2(P(message)) )
Run Code Online (Sandbox Code Playgroud)
E
对所有可能消息的期望在哪里,P
是概率函数.在实践中,你不知道P
,所以你能做到的最好比以前的最佳算法做得更好;)
通常,您尝试压缩数据的次数越多,程序就越昂贵,无论是在运行时资源(CPU周期和内存)还是开发工作方面.
一个例子
只是把它放在你的例子1的实践中,给你灵感 - 即使从一个例子设计是一个非常糟糕的主意,因为它几乎没有给你代表性的概率!
初始数据(我将始终省略大小标题,因为它将保持不变) - 位图,84位(25个):
000000000000
000000011000
001100111100
001111111100
000000111100
000001111100
000000000000
Run Code Online (Sandbox Code Playgroud)
在您的index
方案中,您输出一个列表position
.如果您进行概括,则可以使用position
+ 列表pattern
.例如,pattern
可以是连续的数量,因此您不需要为一个块输出多个位置.让我们进一步说,我们编码2D模式,定义如下:
1位形状:
0
表示一行 - 例如1111
,一行大小为4;1
意味着一个正方形 - 例如:
11
11
Run Code Online (Sandbox Code Playgroud)
是一个2号的正方形.
然后让我们说取相对而不是绝对位置,这意味着每个位置position
编码自前一个位置以来你前进了多少.以您为例,我选择5位位置.以下是解码的工作原理:
-- block #1
00001 position +1
absolute position from top-left, since this is the first block
001 pattern-size 1
0 pattern-shape is row
for size 1, square and row are the same
(which means my coding isn't optimal)
-- block #2
00100 position +4
relative to last position 1, this means position 5
010 pattern-size 2
1 pattern-shape is square
-- decoded output below
0100011000...
0000011000...
0000000000...
.............
Run Code Online (Sandbox Code Playgroud)
因此,使用此方案,您可以使用45位对数据进行编码:
10100 (position [0]+20 from top-left)
010 0 (size: 2, shape: row)
00110 (position [20]+6)
010 1 (size: 2, shape: square)
00100 (position +4)
100 1 (size: 4, shape: square)
01000 (position +8)
100 0 (size: 4, shape: row)
11011 (position +27)
001 0 (size 1, shape: row)
Run Code Online (Sandbox Code Playgroud)
注意:通常您需要存储标题以了解块的数量(在本例中为5),但您可以从文件/网络有效负载大小中推断出它.同样在这个例子中,我们只需要3个模式大小(1,2,4),因此我们可以将大小存储在两个位上并将其增加到功率2,使有效负载为40位,但这使得该方案过于专业化.此外,shape
如果您没有足够的位position
来编码模式之间的大"洞" ,则必须至少有一个无意义的(这里有两个:000/0和000/1).例如,这个20 x 3矩阵:
10000000000000000000
00000000000000000000
00000000000000000001
Run Code Online (Sandbox Code Playgroud)
在0和59位置有一个.由于我不能将59编码为5位跳转,我们必须跳两次,我们将其编码为:
00000 (+0) 001 0 (a single 1)
11111 (+31) 000 0 (nothing)
11100 (+28) 001 0 (a single 1)
Run Code Online (Sandbox Code Playgroud)