blob: 89f5b10f847c50bf29aa2dd8006d63d5b93f5a65 [file]
// SPDX-FileCopyrightText: The Eigen Authors
// SPDX-License-Identifier: MPL-2.0
#include <benchmark/benchmark.h>
#include <Eigen/Jacobi>
#include <array>
#include <complex>
#include <cstdlib>
template <typename Scalar>
static void BM_MakeJacobi(benchmark::State& state) {
using RealScalar = typename Eigen::NumTraits<Scalar>::Real;
struct Input {
RealScalar x;
Scalar y;
RealScalar z;
};
std::array<Input, 256> inputs;
std::srand(5489);
const RealScalar couplingScale =
state.range(0) == 0 ? RealScalar(1) : Eigen::numext::sqrt(Eigen::NumTraits<RealScalar>::epsilon());
for (auto& input : inputs) {
input.x = Eigen::internal::random<RealScalar>();
input.z = Eigen::internal::random<RealScalar>();
input.y = Eigen::internal::random<Scalar>() * couplingScale;
}
// Hide the generated range, not just the outputs: range propagation can eliminate branches under test.
benchmark::DoNotOptimize(inputs.data());
benchmark::ClobberMemory();
const RealScalar tolerance = RealScalar(64) * Eigen::NumTraits<RealScalar>::epsilon();
for (const auto& input : inputs) {
Eigen::JacobiRotation<Scalar> rotation;
rotation.makeJacobi(input.x, input.y, input.z);
const Scalar c = rotation.c();
const Scalar s = rotation.s();
const Scalar conjugateS = Eigen::numext::conj(s);
const Scalar offdiag =
c * conjugateS * (input.x - input.z) + c * c * input.y - conjugateS * conjugateS * Eigen::numext::conj(input.y);
if (!(Eigen::numext::abs(Eigen::numext::abs2(c) + Eigen::numext::abs2(s) - RealScalar(1)) <= tolerance) ||
!(Eigen::numext::abs(offdiag) <= tolerance * Eigen::numext::abs(input.y))) {
state.SkipWithError("Jacobi rotation failed unitarity or annihilation check");
return;
}
}
for (auto _ : state) {
benchmark::ClobberMemory();
for (const auto& input : inputs) {
Eigen::JacobiRotation<Scalar> rotation;
rotation.makeJacobi(input.x, input.y, input.z);
Scalar c = rotation.c();
Scalar s = rotation.s();
benchmark::DoNotOptimize(c);
benchmark::DoNotOptimize(s);
}
}
state.SetItemsProcessed(state.iterations() * static_cast<int64_t>(inputs.size()));
}
// 0: mixed ordinary couplings; 1: small couplings representative of later Jacobi sweeps.
BENCHMARK_TEMPLATE(BM_MakeJacobi, float)->DenseRange(0, 1);
BENCHMARK_TEMPLATE(BM_MakeJacobi, double)->DenseRange(0, 1);
BENCHMARK_TEMPLATE(BM_MakeJacobi, std::complex<float>)->DenseRange(0, 1);
BENCHMARK_TEMPLATE(BM_MakeJacobi, std::complex<double>)->DenseRange(0, 1);