稀疏的多维数据表示

时间:2009-08-12 09:41:49

标签: c matrix sparse-matrix

我正在研究一种使用四维数据的心脏模拟工具,即3D空间中的几个(3-30)变量。

我现在正在添加一些组织几何图形,它将在要模拟的组织外面的包含3D框中留下超过2/3的点,因此我需要一种方法来有效地存储活动点而不是其他点。

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

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

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

我正在使用C.

3 个答案:

答案 0 :(得分:5)

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

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

含义:

  1. 保存包含所有相关点及其数据的链接列表
  2. 保存哈希以轻松获取此数据:key = coordinates,data =指向链接列表的指针。
  3. 行动的实施将是:
    添加一个框:浏览完整的链接列表,只将相关元素带入“工作”链表中 迭代:浏览“工作”链表
    查找邻居:查找哈希中的每个邻居。

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

答案 1 :(得分:2)

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

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 */

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

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

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

答案 2 :(得分:1)

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

话虽如此,这就是我的建议。将完整的3D区域划分为立方体块,大小相同。对于每个块,将块中的所有点存储在密集阵列中,包括布尔isTissue数组,以确定每个点是否在组织区域中。仅分配其中包含点的块。创建一个(密集)指向块的指针数组,为未分配的块指定NULL指针。

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

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

要迭代3D框中的所有点,您可以只为每个点执行查找,或者(更有效地)找出框接触的块,并迭代框内的块中的区域,跳过isTissue为假的那些。

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

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