我想使用 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
的重载(将执行策略作为其第一个参数)来执行并行处理.
行数在
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), ...);
}