11

負の数と正の数の「分離された合計」、カハン、ペアワイズ、およびマトリックスから要素を取得する順序が問題にならないその他のもののようなことを行う関数をいくつか作成しています。次に例を示します。

template <typename T, int R, int C>
inline T sum(const Eigen::Matrix<T,R,C>& xs)
{
  T sumP(0);
  T sumN(0);
  for (size_t i = 0, nRows = xs.rows(), nCols = xs.cols(); i < nRows; ++i)
   for (size_t j = 0; j < nCols; ++j)
   {
        if (xs(i,j)>0)
          sumP += xs(i,j);
        else if (xs(i,j)<0) //ignore 0 elements: improvement for sparse matrices I think
          sumN += xs(i,j);
   }
 return sumP+sumN;
}

今、私はこれをできるだけ効率的にしたいので、私の質問は、上記のように各行の各列をループする方が良いでしょうか、それとも次のように反対のことをする方が良いでしょうか:

for (size_t i = 0, nRows = xs.rows(), nCols = xs.cols(); i < nCols; ++i)
  for (size_t j = 0; j < nRows; ++j)

(これは、行列要素がメモリに割り当てられる順序に依存すると思いますが、Eigen のマニュアルではこれを見つけることができませんでした)。

また、イテレータを使用するような他の代替方法はありますか (Eigen には存在しますか?)、少し高速になる可能性がありますか?

4

4 に答える 4

4

コードは、マトリックス内のすべてのエントリの合計と同等であることに気付きました。つまり、次のようにすることができます。

return xs.sum();

単一のパスにすぎないため、パフォーマンスが向上すると思います。さらに、Eigen は、最適なパフォーマンスのためにパスを配置する方法を「知っている」必要があります。

ただし、2 つのパスを保持したい場合は、次のように係数ごとのリダクション メカニズムを使用してこれを表現できます。

return (xs.array() > 0).select(xs, 0).sum() +
       (xs.array() < 0).select(xs, 0).sum();

ブール係数ごとの選択を使用して、正と負のエントリを選択します。手巻きループよりもパフォーマンスが優れているかどうかはわかりませんが、理論的には、このようにコーディングすると、Eigen (およびコンパイラ) が意図についてより多くのことを知ることができ、結果を改善できる可能性があります。

于 2015-08-20T01:10:48.283 に答える
1

ループ内の一時変数内に xs(i,j) を格納して、関数を 1 回だけ呼び出すようにしてください。

于 2013-04-29T17:15:46.860 に答える