user7431005
user7431005

Reputation: 4539

performance improvements for cube root in Eigen

I did profile my code using Valgrind (using the "release with debug information" build) and found out that a significant amount of time (~25%) is spent on one line where I calculate the element-wise cubic root of a big matrix. Now, I would like to accelerate this step if possible.

Currently, I'm simply using .pow( 1.0 / 3.0). I wonder if there is a way to improve this, maybe by using std::cbrt()? But how do I pass this function to Eigen in order to do an element-wise cubic root?

#include "iostream"
#include "eigen-3.3.7/Eigen/Dense"

using namespace Eigen;
int main() {
  // generate some random numbers
  VectorXd v = VectorXd::Random(10).array().abs() ;
  std::cout << v << std::endl << std::endl ;

  // calculate the cubic root
  VectorXd s = v.array().pow( 1.0 / 3.0 );
  std::cout << s << std::endl;
}

Upvotes: 3

Views: 409

Answers (1)

dtell
dtell

Reputation: 2568

You can use DenseBase::unaryExpr and a C++ lambda:

VectorXd s = v.unaryExpr([](double coeff){ return std::cbrt(coeff); });

A small benchmark using Google Benchmark:

#include <Eigen/Dense>
#include <benchmark/benchmark.h>

using namespace Eigen;

static void BM_Pow(benchmark::State& state)
{
  VectorXd v = VectorXd::Random(state.range(0)).array().abs();
  VectorXd s;
  for (auto _ : state) {
    benchmark::DoNotOptimize(s = v.array().pow( 1.0 / 3.0 ));
    benchmark::ClobberMemory();
  }
}

static void BM_Cbrt(benchmark::State& state)
{
  VectorXd v = VectorXd::Random(state.range(0)).array().abs();
  VectorXd s;
  for (auto _ : state) {
    benchmark::DoNotOptimize(s = v.unaryExpr([](double coeff){ return std::cbrt(coeff); }));
    benchmark::ClobberMemory();
  }
}

BENCHMARK(BM_Pow) -> Range(4, 10000);
BENCHMARK(BM_Cbrt) -> Range(4, 10000);

BENCHMARK_MAIN();

Compiling with -O3 gives the following on my machine:

-----------------------------------------------------
Benchmark              Time           CPU Iterations
-----------------------------------------------------
BM_Pow/4              69 ns         69 ns   10099698
BM_Pow/8             134 ns        134 ns    5391874
BM_Pow/64           1043 ns       1043 ns     673401
BM_Pow/512          8476 ns       8474 ns      82371
BM_Pow/4096        68708 ns      68702 ns      10839
BM_Pow/10000      160833 ns     160566 ns       4222
BM_Cbrt/4             23 ns         23 ns   31538209
BM_Cbrt/8             45 ns         45 ns   15129345
BM_Cbrt/64           358 ns        358 ns    1968338
BM_Cbrt/512         2810 ns       2809 ns     254678
BM_Cbrt/4096       23926 ns      23855 ns      31430
BM_Cbrt/10000      55692 ns      55568 ns      12765

so this seems to be worth.

Upvotes: 5

Related Questions