我可以使用 std::for_each 一次转换一列 arma::mat 吗?

问题描述 投票:0回答:1

我想使用 std::for_each 或算法标题中的类似方法对犰狳矩阵执行按列转换。原因是我将执行的实际转换很繁重,因此可能会从并行化中受益。此外,在并行运行时,我需要一次处理一列矩阵,因为转换函数取决于给定列中的所有值,而不是其他列中的值。

下面是一个可行的解决方法,在这个小例子中是 4 x 3 矩阵。我没有使用尺寸为 4 x 3 的

arma::mat
,而是定义了尺寸为 3 的
std::vector
,其元素为尺寸为 4 的
arma::vec
。因此,我隐式地拥有一个 4 x 3 矩阵。

#include <armadillo>
#include <iostream>
#include <algorithm>

int main()
{
  std::vector<arma::vec> v{arma::randu(4), arma::randu(4), arma::randu(4)};

  for(auto x : v) {
    std::cout << x << std::endl;
  }
  
  std::for_each(v.begin(), v.end(), [](arma::vec& x){ x = arma::ones(4); });

  for(auto x : v) {
    std::cout << x << std::endl;
  }
  
  return 0;
}

这确实有效,但由于我在代码的其他地方使用线性代数函数,因此替换以下行会更方便:

std::vector<arma::vec> v{arma::randu(4), arma::randu(4), arma::randu(4)};

像这样的东西

arma::mat v{4, 3, arma::randu};

然后跟随类似的内容

// does not work! Gives a double, and iterates over all elements.
std::for_each(v.begin(), v.end(), [](arma::vec& x) {x = foo(); });

但是,在这种情况下,我不知道如何定义赋予

std::for_each
的迭代器,以便它一次只处理一列,并另外给出一个
arma::vec
犰狳文档中描述的迭代器似乎给了我给定列的开头,但随后一次迭代一个元素。

我还知道 Armadillo 中提供的

for_each 成员函数可以按顺序工作,但这里的目标是通过最终使用 
std::for_each
的重载(将执行策略作为其第一个参数)来执行并行处理
.

c++ armadillo
1个回答
0
投票

行数在

arma::mat.n_rows
中可用,并且您可以使用
v.begin_row(row_index)
v.end_row(row_index)
获得每行的迭代器。

如果您想在 v 中的

outer
向量上使用并行执行策略,您可以执行以下操作(仅打印值):

#include <armadillo>
#include <boost/iterator/counting_iterator.hpp>
//
#include <algorithm>
#include <execution>
#include <iostream>

int main() {
    arma::mat v{4, 3, arma::fill::randu};

    // create a pair of counting iterator to iterate through
    // the indices [0, v.n_cols) :
    boost::counting_iterator<std::size_t> beg(0);
    boost::counting_iterator<std::size_t> end(v.n_rows);

    // for_each with an execution policy on the outer part of v:
    std::for_each(std::execution::par, beg, end, [&](std::size_t idx) {
        std::for_each(v.begin_row(idx), v.end_row(idx),
                      [](auto&& colval) {
                          std::cout << colval << ' '; 
                      });
        std::cout << '\n';
    });
}

如果您不想使用 boost,您可以创建自己的计数迭代器 - 或用您想要迭代的索引填充

std::vector<std::size_t>
。填充需要一点时间,因此如果您需要经常这样做,请使用计数迭代器。


如果您想在 v 中的

inner
向量上使用并行执行策略,那就简单得多:

for(std::size_t idx = 0; idx < v.n_rows; ++idx) {
    // execution policy on the inner part of v:
    std::for_each(std::execution::par, v.begin_row(idx), v.end_row(idx), ...);
}
© www.soinside.com 2019 - 2024. All rights reserved.