【问题标题】:Iterating over arma::mat and retrieving element locations遍历 arma::mat 并检索元素位置
【发布时间】:2020-10-29 11:26:08
【问题描述】:

我正在尝试按元素设置arma::mat 的值,每个元素的值取决于每个元素的多索引(行、列)。 有没有办法在迭代期间检索元素的当前位置?

基本上,我希望能够做一些事情like in the sparse matrix iterator,其中it.col()it.row() 允许检索当前元素的位置。 为了说明,arma::sp_mat iterator documentation)中给出的例子是:

sp_mat X = sprandu<sp_mat>(1000, 2000, 0.1);

sp_mat::const_iterator it     = X.begin();
sp_mat::const_iterator it_end = X.end();

for (; it != it_end; ++it) {
  cout << "val: " << (*it)    << endl;
  cout << "row: " << it.row() << endl;  // only available for arma::sp_mat, not arma::mat
  cout << "col: " << it.col() << endl;  // only available for arma::sp_mat, not arma::mat
}

当然,有许多解决方法可以为arma::mat 迭代获取元素位置,最直接的方法可能是:

  • 在行和列大小上使用嵌套的for-循环。
  • 使用单个 for 循环,并使用矩阵大小,将迭代次数转换为行和列索引。
  • 某种形式的“压缩”迭代,对象包含或计算相应的索引。

然而, 这些对我来说似乎相当笨拙且容易出错,因为它们需要使用矩阵大小,甚至需要手动处理索引。 我正在寻找一种更简洁(可能是内部优化)的解决方案。我觉得应该有一种方法可以实现这一目标......

除了用于arma::sp_mat 的解决方案之外,对我来说,其他这样的“不错”解决方案将使用.imbue.for_each,但使用的函子不仅接受元素的当前值,还接受其位置作为附加参数;目前这似乎是不可能的。

【问题讨论】:

    标签: c++ c++17 armadillo


    【解决方案1】:

    查看犰狳源代码,row_col_iterator 提供每个元素的行和列索引。这类似于稀疏矩阵迭代器,但不会跳过零。调整你的代码:

    mat X(10,10,fill::randu);
    
    mat::const_row_col_iterator it     = X.begin_row_col();
    mat::const_row_col_iterator it_end = X.end_row_col();
    
    for (; it != it_end; ++it) {
      cout << "val: " << (*it)    << endl;
      cout << "row: " << it.row() << endl;
      cout << "col: " << it.col() << endl;
    }
    

    【讨论】:

    • 这正是我要找的,感谢您深入研究源代码!它似乎至少从 9.900.x 开始就可用了——我想知道,为什么它不属于 official docs...
    【解决方案2】:

    您似乎已经自己回答了您的问题。我希望犰狳为我们提供了一个.imbue 方法重载,它接收了一个函子,其参数与犰狳对象的维度一样多,但目前它只接受一个没有参数的函子。那么可能最简单的选择(在我看来)是使用 lambda 捕获必要的信息,例如下面的代码

        arma::umat m(3, 3);
        {
            int i = 0;
            m.imbue([&i, num_rows = m.n_rows, num_cols = m.n_cols]() {
                arma::uvec sub = arma::ind2sub(arma::SizeMat{num_rows, num_cols}, i++);
                return 10 * (sub[0] + 1) + sub[1];
            });
        }
    

    在此示例中,每个元素的计算方式是其行索引加上其列索引的 10 倍。我在这里捕获ì 作为线性索引,并将其与 lambda 放在大括号内以划定其范围。

    我也希望我能写类似auto [row_idx, col_idx] = arma::ind2sub( ... ) 的东西,但不幸的是ind2sub 返回的内容不适用于结构化绑定。

    如果您愿意,也可以通过 const 引用捕获 m 并将 arma::size(m) 作为 arma::ind2sub 的第一个参数。

    【讨论】:

    • 谢谢,我不知道arma::ind2sub,它解决了我建议的变通办法的大部分问题。我想这回答了这个问题。 :) — 正如您似乎也希望这样的功能:您知道这是否故意丢失?如果没有,可能值得尝试实施并打开 MR ...
    • 我不知道这是否是故意遗漏的。如果你有兴趣,你的犰狳似乎托管在gitlab
    猜你喜欢
    • 2021-07-08
    • 1970-01-01
    • 2021-12-09
    • 1970-01-01
    • 1970-01-01
    • 2020-07-06
    • 1970-01-01
    • 1970-01-01
    • 2013-09-27
    相关资源
    最近更新 更多