| // 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); |