blob: c04c91cd36a6e7f74c5c92ffa320f26c40562574 [file] [edit]
// SPDX-FileCopyrightText: The Eigen Authors
// SPDX-License-Identifier: MPL-2.0
//
// Micro-benchmark for the Bunch-Kaufman factorization of symmetric/Hermitian indefinite matrices,
// compared against the other dense solvers that can handle indefinite systems (LDLT, PartialPivLU)
// and against LLT (definite-only) as a lower bound on achievable performance.
#include <benchmark/benchmark.h>
#include <Eigen/Core>
#include <Eigen/Cholesky>
#include <Eigen/LU>
using namespace Eigen;
#ifndef SCALAR
#define SCALAR double
#endif
typedef SCALAR Scalar;
typedef Matrix<Scalar, Dynamic, Dynamic> MatrixType;
typedef Matrix<Scalar, Dynamic, 1> VectorType;
// Half-flops symmetric-factorization cost (multiply + add counted separately), matching bench_cholesky.cpp.
static double symmetric_factorization_cost(int n) {
double cost = 0;
for (int j = 0; j < n; ++j) {
int rem = std::max(n - j - 1, 0);
cost += 2 * (double(rem) * j + rem + j);
}
return cost;
}
// A symmetric/Hermitian indefinite test matrix.
static MatrixType make_indefinite(int n) {
MatrixType a = MatrixType::Random(n, n);
return (a + a.adjoint()).eval();
}
static void BM_BunchKaufman(benchmark::State& state) {
const int n = state.range(0);
MatrixType A = make_indefinite(n);
const int r = internal::random<int>(0, n - 1);
Scalar acc = 0;
for (auto _ : state) {
BunchKaufman<MatrixType> bk(A);
acc += bk.matrixLDLT().coeff(r, r);
benchmark::DoNotOptimize(acc);
}
state.counters["GFLOPS"] = benchmark::Counter(
symmetric_factorization_cost(n), benchmark::Counter::kIsIterationInvariantRate, benchmark::Counter::kIs1000);
}
BENCHMARK(BM_BunchKaufman)->RangeMultiplier(2)->Range(8, 2048);
static void BM_BunchKaufman_Solve(benchmark::State& state) {
const int n = state.range(0);
MatrixType A = make_indefinite(n);
VectorType b = VectorType::Random(n);
for (auto _ : state) {
BunchKaufman<MatrixType> bk(A);
VectorType x = bk.solve(b);
benchmark::DoNotOptimize(x.data());
}
}
BENCHMARK(BM_BunchKaufman_Solve)->RangeMultiplier(2)->Range(8, 2048);
static void BM_LDLT(benchmark::State& state) {
const int n = state.range(0);
MatrixType A = make_indefinite(n);
const int r = internal::random<int>(0, n - 1);
Scalar acc = 0;
for (auto _ : state) {
LDLT<MatrixType> ldlt(A);
acc += ldlt.matrixLDLT().coeff(r, r);
benchmark::DoNotOptimize(acc);
}
state.counters["GFLOPS"] = benchmark::Counter(
symmetric_factorization_cost(n), benchmark::Counter::kIsIterationInvariantRate, benchmark::Counter::kIs1000);
}
BENCHMARK(BM_LDLT)->RangeMultiplier(2)->Range(8, 2048);
static void BM_PartialPivLU(benchmark::State& state) {
const int n = state.range(0);
MatrixType A = make_indefinite(n);
const int r = internal::random<int>(0, n - 1);
Scalar acc = 0;
for (auto _ : state) {
PartialPivLU<MatrixType> lu(A);
acc += lu.matrixLU().coeff(r, r);
benchmark::DoNotOptimize(acc);
}
// LU does roughly twice the work of a symmetric factorization.
state.counters["GFLOPS"] = benchmark::Counter(
2 * symmetric_factorization_cost(n), benchmark::Counter::kIsIterationInvariantRate, benchmark::Counter::kIs1000);
}
BENCHMARK(BM_PartialPivLU)->RangeMultiplier(2)->Range(8, 2048);
BENCHMARK_MAIN();