是否有可能避免for循环计算矩阵条目?

时间:2017-11-13 16:46:52

标签: c++ for-loop eigen

我必须使用嵌套的for循环来逐列计算Eigen :: MatrixXd类型矩阵输出的条目。这里输入[0],输入[1]和输入[2]被定义为Eigen :: ArrayXXd,以便使用元素运算。这部分似乎是我的代码的瓶颈。任何人都可以帮我加速这个循环吗?谢谢!

 for (int i = 0; i < r; i++) {
    for (int j = 0; j < r; j++) {
      for (int k = 0; k < r; k++) {
        output.col(i * (r * r) + j * r + k) =
            input[0].col(i) * input[1].col(j) * input[2].col(k);
      }
    }
  }

2 个答案:

答案 0 :(得分:1)

在考虑优化for循环的代码时,有助于思考,“我可以消除冗余计算吗?”

请注意,在最内层循环中,只有k正在发生变化。您应该将涉及k的所有可能计算移出该循环:

for (int i = 0; i < r; i++) {
  int temp1 = i * (r * r);
  for (int j = 0; j < r; j++) {
    int temp2 = j * r;
    for (int k = 0; k < r; k++) {
      output.col(temp1 + temp2 + k) =
          input[0].col(i) * input[1].col(j) * input[2].col(k);
    }
  }
}

注意i * (r * r)是如何反复计算的,但答案总是一样的!您只需在i增量时重新计算。 j * r也是如此。

希望这有帮助!

答案 1 :(得分:1)

要减少翻牌次数,您应该缓存input[0]*input[1]的结果:

ArrayXd tmp(input[0].rows());
for (int i = 0; i < r; i++) {
 for (int j = 0; j < r; j++) {
  tmp = input[0].col(i) * input[1].col(j);
  for (int k = 0; k < r; k++) {
    output.col(i * (r * r) + j * r + k) = tmp * input[2].col(k);
  }
 }
}

然后,要完全使用您的CPU,请使用-march=native启用AVX / FMA,当然还有编译器优化(-O3)。

然后,为了了解你可以获得更多的东西,准确测量这部分所花费的时间,计算乘法次数(r ^ 2 *(n + r * n)),然后计算出的数量你实现的每秒浮点运算。然后将其与CPU的容量进行比较。如果你做得好,那么唯一的选择是使用例如OpenMP多线程for循环之一。循环的选择取决于输入的大小,但您可以尝试使用外部输入,确保每个线程都有自己的tmp数组。