【问题标题】:Sparse Multi-Dimensional Data Representation稀疏多维数据表示
【发布时间】:2010-11-18 21:49:44
【问题描述】:

我正在开发一个使用 4 维数据的心脏模拟工具,即 3D 空间中位置的几个 (3-30) 个变量。

我现在添加了一些组织几何结构,这将使包含 3D 框内超过 2/3 的点留在要模拟的组织之外,因此我需要一种有效存储活动点而不是其他点的方法。

至关重要的是,我需要能够:

  • 迭代受限 3D 框内的所有活动点(也许是迭代器?)
  • 访问一个点后,找到它的正交邻居 (x,y,z) +/- 1。

这可能不止一个问题!我主要关心的是如何有效地表示稀疏数据。

我正在使用 C。

【问题讨论】:

  • 我只是好奇...您会使用组织几何数据进行某种渲染吗?
  • 我不完全清楚你的几何形状在这里。您提到每个点都有正交邻居,这意味着点的规则网格,但是您指的是稀疏数据。我是否正确理解您的点集本质上是规则网格上点的(连接)子集?

标签: c matrix sparse-matrix


【解决方案1】:

您多久添加一次组织,需要多长时间?

一个简单的解决方案是使用链表+散列和一个指向另一个的指针。

意思:

  1. 保存包含所有相关点及其数据的链接列表
  2. 保存哈希以轻松获取此数据:键 = 坐标,数据 = 指向链表的指针。

操作的实现是:
添加一个框:遍历整个链表,只将相关元素放入“工作”链表
迭代:遍历“工作”链表
查找邻居:查找哈希中的每个邻居。

复杂性:
添加:O(n),迭代 O(1) 以找到下一个元素,邻居 O(1) 平均(由于哈希)。

【讨论】:

  • 嗨安娜,这似乎是最简单的解决方案,因此我最有可能实施!再次查看代码访问当前密集数组的方式,似乎即使在介质上迭代的部分在每一步都使用索引函数引用一个点。所以,通过实现你的哈希,我应该能够只使用哈希。正如您所说,哈希将提供恒定的访问时间。谢谢,罗斯
【解决方案2】:

如果你想使用普通数组索引,你可以在 POSIX 系统上使用 mmap() 创建一个稀疏数组:

float (*a)[500][500];

a = mmap(0, (size_t)500 * sizeof a[0], PROT_READ | PROT_WRITE,
    MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);

if (a && (void *)a != MAP_FAILED)
{
    /* a is now 500 x 500 x 500 sparse array of floats */

然后,您可以随意访问 a[x][y][z],它只会为每个被触摸的页面分配实际内存。数组将被初始化为零字节。

如果您的系统没有 MAP_ANONYMOUS,您可以通过从 /dev/zero 映射来达到相同的效果。

请注意,在许多系统上,会为整个阵列保留(尽管不使用)交换空间。

【讨论】:

    【解决方案3】:

    首先,我认为值得考虑您的真正需求是什么。我怀疑这不仅仅是“以尽可能节省空间的方式存储活动点和其他任何点”,而且还有一定数量的“将相邻点存储在附近的内存位置,以便获得良好的缓存行为”和“以可以有效进行查找的方式存储点”。

    话虽如此,这就是我的建议。将完整的 3D 区域分成大小相同的立方体块。对于每个块,将块中的所有点存储在密集数组中,包括一个布尔 isTissue 数组,用于判断每个点是否在组织区域中。仅分配其中有点的块。制作一个(密集)指向块的指针数组,对于未分配的块使用 NULL 指针。

    因此,要找到 (i,j) 处的点,首先计算 ii=i/blockside,jj=j/blocksize,然后查看 (ii,jj) 处的指针块表以找到包含您的观点的块。如果该指针为 NULL,则您的点不在组织中。如果它不为空,则查看该块中的 (i mod blocksize, j mod blocksize) ,并且存在您的 (i,j) 点。您可以检查它的 isTissue 标志以查看它是否是“当前”点。

    您需要选择块大小作为在最小化跨块边界的相邻点计算次数与最小化块中但不在组织区域中的点数之间的平衡。我猜你至少希望块的一行是一个高速缓存行。可能最优值比这大得多,尽管它至少在某种程度上取决于您的几何形状。

    要遍历 3D 盒子中的所有点,您可以只对每个点进行查找,或者(更有效地)找出盒子接触的块,然后遍历盒子内这些块中的区域,跳过 isTissue 为假的那些。

    如果您要进行大量的块释放和重新分配,您可能希望通过将块放入“未使用”池中来“释放”块,然后将块从该池中拉出而不是重新分配它们。这还有一个好处是这些块已经将它们的所有点设置为“不存在”(因为这就是你释放块的原因),所以你不需要初始化它们。

    有经验的读者可能会认识到这与为并行计算布置数据的方式之间的相似之处;如果你有一个非常大的模拟,你可以很容易地将块分布在多个节点上,你只需要为跨块计算进行跨节点通信。对于这种应用程序,您可能会发现执行嵌套级别的块很有用,其中您的元块(用于跨节点通信)包含较小的块(用于几何)。

    【讨论】:

    • 作为附录,如果您的几何图形具有强烈的各向异性 - 即由大部分对齐的股线或板组成的东西 - 您可能需要非立方块。
    • 嗨 Brooks,碰巧的是,大多数访问媒体不需要邻居。我怀疑这些点的访问时间的增加对整体运行时间几乎没有影响,只要它保持不变。感谢您的回答。它帮助我澄清了我正在尝试解决的问题,并让我以不同的方式思考它。非常感谢。
    猜你喜欢
    • 2015-07-04
    • 1970-01-01
    • 2018-08-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-04-28
    • 1970-01-01
    相关资源
    最近更新 更多