blob: 5e6a052f6bc468067a31c86364510c7c16b3bb81 [file]
// SPDX-FileCopyrightText: The Eigen Authors
// SPDX-License-Identifier: MPL-2.0
#include <benchmark/benchmark.h>
#include <Eigen/Eigenvalues>
#include <array>
#include <limits>
#include <random>
#ifndef SCALAR
#define SCALAR float
#endif
#ifndef MATRIX_SIZE
#define MATRIX_SIZE 2
#endif
static void BM_DirectSelfAdjoint(benchmark::State& state) {
using Scalar = SCALAR;
using MatrixType = Eigen::Matrix<Scalar, MATRIX_SIZE, MATRIX_SIZE>;
using WideMatrix = Eigen::Matrix<long double, MATRIX_SIZE, MATRIX_SIZE>;
using WideVector = Eigen::Matrix<long double, MATRIX_SIZE, 1>;
const int options = static_cast<int>(state.range(0));
Scalar scale = Scalar(1);
switch (state.range(1)) {
case 1:
scale = Eigen::numext::ldexp(Scalar(1), -20);
break;
case 2:
scale = (std::numeric_limits<Scalar>::min)();
break;
case 3:
scale = Eigen::NumTraits<Scalar>::highest() / Scalar(2);
break;
case 4:
scale = Scalar(0.001);
break;
case 5:
scale = Scalar(0.1);
break;
case 6:
scale = Scalar(8);
break;
case 7:
scale = Scalar(1000);
break;
case 8:
scale = Scalar(1000000);
break;
}
std::mt19937 generator(42);
std::uniform_real_distribution<double> random(-0.125, 0.125);
std::array<MatrixType, 32> inputs;
Eigen::SelfAdjointEigenSolver<MatrixType> solver;
const long double tolerance = 128 * MATRIX_SIZE * static_cast<long double>(Eigen::NumTraits<Scalar>::epsilon());
const long double quantum =
static_cast<long double>(std::numeric_limits<Scalar>::denorm_min()) / static_cast<long double>(scale);
for (auto& input : inputs) {
for (Eigen::Index col = 0; col < MATRIX_SIZE; ++col) {
for (Eigen::Index row = col; row < MATRIX_SIZE; ++row) {
input(row, col) = input(col, row) = Scalar(random(generator));
}
input(col, col) += Scalar(col) - Scalar(MATRIX_SIZE - 1) / Scalar(2);
}
input *= scale;
solver.computeDirect(input, options);
const WideMatrix normalized = input.template cast<long double>() / static_cast<long double>(scale);
Eigen::SelfAdjointEigenSolver<WideMatrix> reference(normalized, Eigen::EigenvaluesOnly);
const WideVector values = solver.eigenvalues().template cast<long double>() / static_cast<long double>(scale);
if (solver.info() != Eigen::Success || !values.allFinite() ||
!((values - reference.eigenvalues()).norm() <= tolerance * normalized.norm() + MATRIX_SIZE * quantum)) {
state.SkipWithError("Eigenvalue validation failed");
return;
}
if (options == Eigen::ComputeEigenvectors) {
const WideMatrix vectors = solver.eigenvectors().template cast<long double>();
if (!((normalized * vectors - vectors * values.asDiagonal()).norm() <=
tolerance * normalized.norm() + MATRIX_SIZE * quantum) ||
!((vectors.transpose() * vectors - WideMatrix::Identity()).norm() <= tolerance)) {
state.SkipWithError("Eigenvector validation failed");
return;
}
}
}
unsigned int index = 0;
for (auto _ : state) {
const MatrixType& input = inputs[index++ & 31];
benchmark::DoNotOptimize(input.data());
solver.computeDirect(input, options);
benchmark::DoNotOptimize(solver.eigenvalues().data());
benchmark::ClobberMemory();
}
}
BENCHMARK(BM_DirectSelfAdjoint)
->ArgsProduct({{Eigen::EigenvaluesOnly, Eigen::ComputeEigenvectors}, {0, 1, 2, 3, 4, 5, 6, 7, 8}})
->ArgNames({"options", "scale_case"});