blob: c54735f6a3b32fbb0c29715a6c64ccce8e69f291 [file]
// SPDX-FileCopyrightText: The Eigen Authors
// SPDX-License-Identifier: MPL-2.0
#include <benchmark/benchmark.h>
#include <Eigen/Eigenvalues>
#include <random>
template <typename Scalar>
static void BM_TridiagonalScaling(benchmark::State& state) {
using Vector = Eigen::Matrix<Scalar, Eigen::Dynamic, 1>;
using Matrix = Eigen::Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic>;
const Eigen::Index n = state.range(0);
const int exponent = static_cast<int>(state.range(1));
const bool vectors = state.range(2) != 0;
std::mt19937 random(42);
Vector diag(n), sub(n - 1);
for (Eigen::Index i = 0; i < n; ++i) diag[i] = Scalar(int(random() % 2001) - 1000) / Scalar(1000);
for (Eigen::Index i = 0; i < n - 1; ++i) sub[i] = Scalar(int(random() % 2001) - 1000) / Scalar(1000);
Eigen::SelfAdjointEigenSolver<Eigen::MatrixXd> reference;
reference.computeFromTridiagonal(diag.template cast<double>(), sub.template cast<double>(), Eigen::EigenvaluesOnly);
if (reference.info() != Eigen::Success) {
state.SkipWithError("Reference failed");
return;
}
const Vector expected = reference.eigenvalues().template cast<Scalar>();
const Scalar scale = Eigen::numext::ldexp(Scalar(1), exponent);
const Vector d = diag * scale, e = sub * scale, values = expected * scale;
Eigen::TridiagonalEigenSolver<Scalar> solver(n);
const auto compute = [&]() {
if (vectors)
solver.computeEigenvectors(d, e, values);
else
solver.computeEigenvalues(d, e);
};
compute();
if (solver.info() != Eigen::Success) {
state.SkipWithError("Solver failed");
return;
}
const Scalar tolerance = Scalar(64 * n) * Eigen::NumTraits<Scalar>::epsilon();
if (vectors) {
Matrix matrix = Matrix::Zero(n, n);
matrix.diagonal() = diag;
matrix.diagonal(1) = sub;
matrix.diagonal(-1) = sub;
const Matrix& v = solver.eigenvectors();
if (!v.allFinite() || !((matrix * v - v * expected.asDiagonal()).norm() <= tolerance * matrix.norm()) ||
!((v.transpose() * v - Matrix::Identity(n, n)).norm() <= tolerance)) {
state.SkipWithError("Invalid eigenvectors");
return;
}
} else {
const Vector normalized = solver.eigenvalues() / scale;
if (!normalized.allFinite() || !((normalized - expected).norm() <= tolerance * expected.norm())) {
state.SkipWithError("Invalid eigenvalues");
return;
}
}
for (auto _ : state) {
compute();
benchmark::DoNotOptimize(solver);
benchmark::ClobberMemory();
}
}
BENCHMARK_TEMPLATE(BM_TridiagonalScaling, float)->ArgsProduct({{3, 32, 128}, {-60, 0, 60}, {0, 1}});
BENCHMARK_TEMPLATE(BM_TridiagonalScaling, double)->ArgsProduct({{3, 32, 128}, {-60, 0, 60}, {0, 1}});