如何高效存储大型稀疏数组

Posted

技术标签:

【中文标题】如何高效存储大型稀疏数组【英文标题】:How to efficiently store large sparse array 【发布时间】:2014-07-12 23:09:16 【问题描述】:

我正在将粒子跟踪到 3D 晶格中。每个格子元素都标有对应于展开的 3D 数组的索引

  S = x + WIDTH * (y + DEPTH * z)

我对从单元格 S1 到单元格 S2 的转换感兴趣。得到的过渡矩阵 M(S1,S2) 是稀疏的,因为粒子只能到达细胞附近。不幸的是,使用几何上接近的展开的 3D 数组单元格的索引可能在它们的索引上有很大的不同。例如,位于彼此顶部的单元格(例如在 z 和 z+1 处)的索引将移动 WIDTH*DEPTH。因此,如果我尝试累积生成的 2D 矩阵 M(S1,S2) ,S1 和 S2 将非常不同,即使细胞是相邻的。这是一个重大问题,因为我不能使用通常的稀疏矩阵存储。

一开始我尝试以坐标格式存储矩阵:

  I , J VALUE

不幸的是,我需要循环整个索引集以找到正确的 S1,S2 并存储累积的 M(S1,S2)。

异常稀疏的矩阵具有一些底层结构,因此索引非常简单。然而,在这种情况下,我在弄清楚如何索引我的单元格时遇到了一些麻烦。

感谢您的帮助 提前谢谢你,

【问题讨论】:

【参考方案1】:

有几种方法。哪个最好取决于需要对矩阵执行的操作。

一个好的通用方法是使用一个哈希表,其中键是索引元组,在你的情况下是 (i,j)。

如果相邻的(在欧几里得意义上)矩阵元素必须是可发现的,那么另一种策略是使用 Morton Order 键的平衡树。键 (i,j) 的 Morton 阶值只是整数 i 和 j,它们的位交错。您应该很快看到索引 2 空间中彼此靠近的索引元组也以线性 Morton 顺序接近。

当然,如果您一次构建所有矩阵,之后它是不可变的,那么您可以在数组而不是哈希表或平衡树中构建键值对,对它们进行排序(按字典顺序为 (i,j ) 对并线性地用于 Morton 键),然后使用简单的二进制搜索进行读取。

【讨论】:

您好,感谢您的帮助。哈希表看起来很方便。不幸的是,我无法使用 2 个键找到一个,我需要像 key1 = I key2 = J value = val 这样的东西。另一个问题是,如果一个特定的 I J 对已经存储,它应该只增加。是否可以编写具有此属性的 has 表? @AlexanderCska 关于你的第一个问题,当然。字符串由多个字符组成,不是吗?他们一直在散列。只需连接或交错两个索引即可生成密钥。抱歉,第二个问题我听不懂。 关于第一部分,如果我理解正确,我应该将I J 写入字符缓冲区并将其用作哈希键。关于我问题的第二部分。我正在累积值(计算积分)。如果我在迭代 1 并且我的代码生成 M(i,J) 我将只存储该值。如果我在第 2 次迭代并且产生了相同的 I,J,我想增加值 M(I,J) = M(I,J) + 1。有可能吗? @AlexanderCska 当然。您可以对存储的价值做任何您喜欢的事情。字符缓冲区可以,但太难了。您所需要的只是一种将 i 和 j 组合成一个整数哈希值的方法。对它们进行异或,在异或之前旋转一个,使用线性组合 A * i + j 其中 A 是质数常数,等等。对于莫顿顺序,如我一开始所说,交错 i 和 j 的位。使用 Morton 哈希,矩阵中彼此靠近的元素也具有相似的哈希值,因此落在彼此靠近的桶中。

以上是关于如何高效存储大型稀疏数组的主要内容,如果未能解决你的问题,请参考以下文章

Fortran:稀疏数组或列表

在 Mathematica 中的稀疏数组上有效替代 Outer?

:稀疏数组和队列 -- 稀疏数组链式存储压缩介绍队列

matlab中对大型非稀疏数组的有效操作

稀疏数组

多维数组-矩阵的压缩存储- 稀疏矩阵(一)