压缩稀疏行(CSR)稀疏矩阵的快速访问元素

时间:2012-10-23 08:14:50

标签: graph fortran sparse-matrix circuit pardiso

我想测试一些较新的稀疏线性求解器,我想知道是否有一种快速填充矩阵的方法。我感兴趣的格式是CSR(http://goo.gl/hLXYd)。假设CSR格式的矩阵由下式给出:

values(num non-zero elements)
columns(num non-zero elements)
rowIndex(num rows + 1)

正在考虑的稀疏矩阵来自网络。所以,我有数千个节点,其中一些节点通过线路连接在一起。因此,矩阵在结构上是对称的。每个连接(i,j)向对角线项(i,i)和(j,j)以及非对角线(i,j)和(j,i)添加一些东西。我可以在相同的节点(i,j,1),(i,j,2)之间建立多个连接......所以,我可能需要多次重新访问2个对角线和2个非对角线元素。

我知道我可以通过执行rowIndex(i)来获得行的开头。然后,我必须遍历元素列(rowIndex(i):rowIndex(i + 1)-1)以找到j所在的位置。

问题:

有没有办法以CSR格式更快地访问元素,而不必每次都想更新元素时​​都进行搜索?

一些澄清: 我只需要从头开始填写矩阵。矩阵在结构上是对称的,并不是真正对称的。保存的值与网络数据(阻抗,电阻等)有关,它们具有实际值。通常,值(i,j)<>值(j,i)。我有形式的元组(name1,i1,j1,value1),(name2,i2,j2,value2)等。这些元组没有排序,2个元组可以引用相同的i,j值,这意味着它们需要加入

提前致谢!

2 个答案:

答案 0 :(得分:2)

你所拥有的是所谓的三元组稀疏格式。可以非常有效地实现CRS的创建,包括删除重复条目和对值进行求和。在自己编程之前,请查看SuiteSparse library。它是用C语言编写的,但我相信你会明白这个原理。您感兴趣的是cholmod_triplet.c文件,它实现了您需要的功能。

基本上,转换是在行和列索引上使用两阶段桶排序执行的。该算法具有线性复杂度,如果您对处理大型数据集感兴趣,这一点很重要。

编辑如果要一起跳过显式创建三元组格式,可以通过动态生成(row, col)连接并将其添加到动态稀疏结构来实现。我通常使用插入排序和排序列表来实现,这在实践中是最快的。它还比CRT转换快三倍,并且使用更少的内存。方法如下:

  • 如果您大致知道,每行中有多少非零条目,为每行预分配一个(空)列索引数组,以及一个单独的数组用于值(不是链表,但是一个简单的数组)。像

    这样的东西

    static_lists_cols[row] = malloc(sizeof(int)*expected_number_of_non_zeros) static_lists_vals[row] = malloc(sizeof(double)*expected_number_of_non_zeros)

  • 如果你不知道,你选择一个初始大小并根据需要重新分配(使用一些足够大的块大小以避免重新分配开销)。当行列表已满时。

  • 对于每个(row, col)对,您使用插入排序将col插入到与row对应的排序列表中。对于每行的小(最多几百)非零,线性搜索是最快的。对于每行的大量非零,您可以使用二分来找到插入col索引的正确位置。
  • 通过在排序列表中移动具有更高列索引的非零条目,将
  • col插入到row排序列表中。这是缓存友好的,因为行实际上足够小,可以适应任何缓存。
  • 完成后,您需要将各个排序列表组合成一个有效的CRS结构,方法是将各个行列表复制到最终的columns中。与价值观相同。
  • 如果你确定某些行可以没有条目,你实际上可以通过预先分配一个静态的“列表数组”来避免最后一步。因此,每行将有一个恒定数量的条目,其中一些可能为零。有时候还可以。

这种方法比使用三元组稀疏转换更快,至少对于我使用它的FEM模型。一般原因是内存带宽是这里的瓶颈,而上述方案使用的内存要少得多:

  • 创建三元组格式需要时间,您需要将三元组写入内存
  • 转换为CRS需要至少读取和写入三元组以对它们进行排序(实际上不止一次,如果你看一下算法。你排序两次,你需要辅助数据结构。)
  • 取决于连接结构,您最终可能会以三元组格式存在大量(row, col)个重复项,这些副本在组装期间通过添加相应的值而被删除。上述方法中不存在此开销 - 如果行列表中已存在col,则只需更新相应的值。
  • 如果为各个工作人员分配行范围,则可以并行更新已排序的列表。不需要通信,也不需要同步。确保负载平衡是另一个故事......

在2D中查看a performance comparison of using those two methods (Figure 1)的三角形元素。请注意,性能差异取决于三元组中条目数与汇编稀疏矩阵格式的比率(表2)。但总的来说,该方法永远不会比三元组转换为crs,和三元组需要首先创建。您还可以下载MATLAB MEX函数sparse_create,它是mutils包的一部分(参见下载部分)。

答案 1 :(得分:1)

您的问题似乎混淆了两个相当不同的问题:

  1. 以CSR形式创建矩阵的快速方法是什么?
  2. 是否有更快的方法从已存储在CSR表单中的矩阵中读取值? (更快,也就是说,比你描述的简单方法)
  3. 所以这里有两个答案:

    1. 一般情况下,将网络数据从其所处的任何形式读取为dictionary of keys(其他中间形式可用,并且由于速度或其他原因可能对您更具吸引力);然后将该中间结构转换为矩阵的CSR形式。更多内容如下。
    2. 我不相信,不是以CSR形式存储的矩阵。这种相对较慢的访问速度是您为节省空间而付出的代价的一部分。你根据自己的观点交换了空间或时间空间。
    3. 您对输入数据的描述表明您应该考虑设计自己的中间形式来整理原始数据。由于您的邻接矩阵是对称的,您只需要以任何形式存储其中的一半。此外,您可能不需要沿主对角线存储元素 - 我猜测节点i始终连接到节点i或永远不会因此网络的性质决定存储在(i,i)的值。我对你想要存储在矩阵的每个节点的信息有点不确定,是ij之间的连接数量还是其他什么?