blob: d71f0e1184a58ec2efff7a1bc8d72143c0fe6672 [file] [edit]
// SPDX-FileCopyrightText: The Eigen Authors
// SPDX-License-Identifier: MPL-2.0
#include <benchmark/benchmark.h>
#include <Eigen/SVD>
template <typename Scalar, int Options>
static void BM_BDCSVDBidiagonal(benchmark::State& state) {
using Matrix = Eigen::Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic>;
using Vector = Eigen::Matrix<Scalar, Eigen::Dynamic, 1>;
const Eigen::Index size = state.range(0);
const int pattern = static_cast<int>(state.range(1));
Vector diagonal(size), superdiagonal(size - 1);
for (Eigen::Index i = 0; i < size; ++i) diagonal(i) = Scalar(1) + Scalar((i * 17) % 31) / Scalar(32);
for (Eigen::Index i = 0; i + 1 < size; ++i) {
superdiagonal(i) = Scalar(0.25) + Scalar((i * 13) % 23) / Scalar(32);
if (pattern == 1) superdiagonal(i) *= Eigen::NumTraits<Scalar>::epsilon();
if (pattern == 2 && i % 7 == 3) superdiagonal(i) = Scalar(0);
}
Matrix input = Matrix::Zero(size, size);
input.diagonal() = diagonal;
input.template diagonal<1>() = superdiagonal;
Eigen::BDCSVD<Matrix, Eigen::ComputeThinU | Eigen::ComputeThinV> reference(diagonal, superdiagonal);
const Scalar tolerance = Scalar(32) * Scalar(size) * Eigen::NumTraits<Scalar>::epsilon();
const Matrix identity = Matrix::Identity(size, size);
if (reference.info() != Eigen::Success ||
!((reference.matrixU() * reference.singularValues().asDiagonal() * reference.matrixV().transpose() - input)
.norm() <= tolerance * input.norm()) ||
!((reference.matrixU().transpose() * reference.matrixU() - identity).norm() <= tolerance) ||
!((reference.matrixV().transpose() * reference.matrixV() - identity).norm() <= tolerance)) {
state.SkipWithError("BDCSVD failed reconstruction or orthogonality check");
return;
}
Eigen::BDCSVD<Matrix, Options> svd(size, size);
svd.compute(diagonal, superdiagonal);
if (svd.info() != Eigen::Success ||
!((svd.singularValues() - reference.singularValues()).norm() <= tolerance * input.norm())) {
state.SkipWithError("BDCSVD failed singular-value check");
return;
}
for (auto _ : state) {
svd.compute(diagonal, superdiagonal);
benchmark::DoNotOptimize(svd.singularValues().data());
if (Options & Eigen::ComputeThinU) benchmark::DoNotOptimize(svd.matrixU().data());
if (Options & Eigen::ComputeThinV) benchmark::DoNotOptimize(svd.matrixV().data());
benchmark::ClobberMemory();
}
state.SetItemsProcessed(state.iterations());
}
// Patterns: coupled, near deflation, and split into small blocks.
#define BDC_BIDIAGONAL_CASES \
->ArgsProduct({{15, 16, 17, 31, 32, 33, 64, 65, 128, 129, 256, 512, 1024}, {0, 1, 2}})->ArgNames({"size", "pattern"})
BENCHMARK_TEMPLATE(BM_BDCSVDBidiagonal, float, 0) BDC_BIDIAGONAL_CASES;
BENCHMARK_TEMPLATE(BM_BDCSVDBidiagonal, double, 0) BDC_BIDIAGONAL_CASES;
BENCHMARK_TEMPLATE(BM_BDCSVDBidiagonal, float, Eigen::ComputeThinU | Eigen::ComputeThinV) BDC_BIDIAGONAL_CASES;
BENCHMARK_TEMPLATE(BM_BDCSVDBidiagonal, double, Eigen::ComputeThinU | Eigen::ComputeThinV) BDC_BIDIAGONAL_CASES;
#undef BDC_BIDIAGONAL_CASES