【问题标题】:iterating through TWO sparse matrices遍历两个稀疏矩阵
【发布时间】:2010-11-22 16:26:40
【问题描述】:

我正在使用bool 的bool 稀疏矩阵并尝试编写一个比较函数来将它们存储在地图中。这是一个非常简单的比较功能。基本上,这个想法是将矩阵视为二进制数(在被展平为向量之后)并根据该数字的值进行排序。这可以通过这种方式完成:

for(unsigned int j = 0; j < maxJ; j++)
{
  for(unsigned int i = 0; i < maxI; i++)
  {
    if(matrix1(i,j) < matrix2(i,j) return true;
    else if(matrix1(i,j) > matrix2(i,j) return false;
  }
}
return false;

但是,由于矩阵的稀疏性,这是低效的,我想使用迭代器来获得相同的结果。使用迭代器的算法看起来很简单,即 1) 获取每个矩阵中的第一个非零单元,2) 比较两者的 j*maxJ+i,3) 如果相等,则获取每个矩阵中的下一个非零单元并重复。不幸的是,在代码中这是非常乏味的,我担心会出错。

我想知道的是(a)是否有更好的方法来做到这一点,(b)是否有一种简单的方法可以为两个矩阵获取“下一个非零单元格”?显然,我不能使用嵌套的 for 循环来遍历一个稀疏矩阵。

感谢您的帮助。

--

由于我上面提出的算法似乎是我的特定应用程序中的最佳解决方案,我想我应该发布我为棘手部分开发的代码,在两个稀疏矩阵中获取下一个非零单元格。这段代码并不理想,也不是很清楚,但我不知道如何改进它。如果有人发现错误或知道如何改进它,我将不胜感激一些 cmets。否则,我希望这对其他人有用。

typedef boost::numeric::ublas::mapped_matrix<bool>::const_iterator1 iter1;
typedef boost::numeric::ublas::mapped_matrix<bool>::const_iterator2 iter2;

// Grabs the next nonzero cell in a sparse matrix after the cell pointed to by i1, i2.
std::pair<iter1, iter2> next_cell(iter1 i1, iter2 i2, iter1 end) const
{
    if(i2 == i1.end())
    {
        if (i1 == end)
            return std::pair<iter1, iter2>(i1, i2);
        ++i1;
        i2 = i1.begin();
    }
    else
    {
        ++i2;
    }

    for(; i1 != end;)
    {
        for(; i2 != i1.end(); ++i2)
        {
            return std::pair<iter1, iter2>(i1,i2);
        }
        ++i1;
        if(i1 != end) i2 = i1.begin();
    }
    return std::pair<iter1, iter2>(i1, i2);
}

【问题讨论】:

  • 你为什么将布尔值与 进行比较?即使您可以相信 false
  • 我不想写一个
  • @scan: 编辑了我的答案

标签: c++ boost iterator sparse-matrix


【解决方案1】:

顺便说一句,我喜欢这个问题。

让我伪代码说出我认为你在问什么

declare list of sparse matrices ListA
declare map MatMAp with a sparse Matrix type mapping to a double, along with a
`StrictWeakMatrixOrderer` function which takes two sparse matrices.

Insert ListA into MatMap. 

问题:如何高效地编写 StrictWeakMatrixOrderer?

这是一种方法。我正在即时发明这个....


定义一个函数flatten() 并预先计算扁平矩阵,将扁平向量存储在一个向量(或另一个具有随机索引上限的容器)中。 flatten() 可以像将每一行(或列)与前一行连接起来一样简单(如果你有一个固定时间函数来抓取一行/列,这可以在线性时间内完成)。

这会产生一组大小约为 10^6 的向量。这是一个折衷——保存这些信息而不是即时计算它。如果您要进行大量比较,这将很有用。

请记住,零包含信息 - 删除它们可能会产生两个彼此相等的向量,而它们的生成矩阵可能不相等。

然后,我们将算法问题从“阶矩阵”转化为“阶向量”。 我从未听说过矩阵的距离度量,但我听说过向量的距离度量。

您可以使用“差异总和”排序,也就是汉明距离。 (foreach 元素不同,加 1)。这将是一个 O(n) 算法:

for i = 0 to max.
  if(a[i] != b[i])
     distance++

return distance

汉明距离满足这些条件

d(a,b) = d(b,a)
d(a,a) = 0
d(x, z) <= d(x, y) + d(y, z) 

现在做一些即兴分析....

  • 10^6 矩阵(或其对应向量)中的元素。
  • O(n) 距离度量。
    • 但它是O(n) 比较。如果每个数组访问都有O(m) 时间,那么您将有一个O(n*(n+n)) = O(n^2) 指标。所以你have 拥有&lt; O(n) 访问权限。根据 SGI 的 STL 站点,std::vector [] 运算符提供了“对任意元素的摊销恒定时间访问”。
  • 如果您有足够的内存来存储k*2*10^6,其中k 是您管理的矩阵的数量,这是一个使用大量内存来换取线性的有效解决方案。

【讨论】:

  • 键类型是稀疏矩阵,映射到双精度。 (该应用程序与稀疏矩阵上的概率分布有关。)否则,您的评估是正确的。关于您的问题,不,只要它实现严格的弱排序并且只有相同的矩阵是等价的,这并不重要。
  • 矩阵有多大?最宽边是 10^3 吗? 10^5?矩阵的百分之几是零?
  • 矩阵的大小不同,但通常在 10^2 到 10^3 之间。矩阵的稀疏度变化很大,因为矩阵代表了扩散过程的状态。
  • 这是一个可行的替代方案,但在我的特定应用程序中,由于内存使用情况,不如我提出的初始解决方案理想。感谢您的建议,解决此问题的其他人可能会从您的回答中受益匪浅。
【解决方案2】:

在我看来,我们正在谈论在 boost::sparse_matrix 上实现按位、逐元素运算符,因为在不使用任何标准矢量规范的情况下比较一个向量(或矩阵)是否小于另一个向量(或矩阵)需要特殊运算符(或特殊映射/规范)。

据我所知,boost 不提供二进制矩阵的特殊运算符(更不用说稀疏二进制矩阵)。使用 BLAS 级矩阵/向量代数不太可能有任何直接的解决方案。二进制矩阵在线性代数领域中占有一席之地,因此有技巧和定理,但我怀疑这些比您的解决方案更容易。

您的问题可以重新表述为:我如何有效地对由 2d 位图表示的天文数字大数字进行排序(n=100,因此 100x100 元素会给您一个像 2^10000 这样的数字)。

好问题!

【讨论】:

  • 是的,显然没有灵丹妙药。矩阵中真实条目的数量是稀疏的,因此我们可以得到一个在可接受的时间内运行的解决方案(通过我提到的算法)。问题是同时获取两个矩阵的下一个迭代器的代码不一定干净,我想知道是否有一个好的方法可以一起迭代两个稀疏的二维矩阵。
【解决方案3】:

(a) 我不完全理解您要完成的工作,但是如果您想比较两个矩阵是否在同一索引处具有相同的值,则使用元素矩阵乘法就足够了(应该实现稀疏的):

matrix3 = element_prod (matrix1, matrix2);

这样你会得到每个索引:

0 (false) * 1 (true) = 0 (false)
0*0 = 0
1*1 = 1

因此,生成的 matrix3 将在一行中提供您的解决方案 :)

【讨论】:

  • 这是一个有趣的建议,但我需要
猜你喜欢
  • 2018-01-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多