blob: dddaf4fed743790ba07244a583d105c400894bec [file]
// Benchmarks for PolynomialSolver::compute on batches of random polynomials.
// SPDX-FileCopyrightText: The Eigen Authors
// SPDX-License-Identifier: MPL-2.0
#include <benchmark/benchmark.h>
#include <Eigen/Core>
#include <contrib/Eigen/Polynomials>
#include <complex>
#include <vector>
using namespace Eigen;
namespace {
constexpr int kBatch = 64;
// Largest componentwise backward error |p(z)| / sum_k |a_k| |z|^k over the roots, in units of eps, evaluated in
// long double so that the check does not share the solver's rounding.
template <typename Scalar, int Deg, typename Polynomial>
double maxBackwardError(const PolynomialSolver<Scalar, Deg>& solver, const Polynomial& poly) {
using Real = typename NumTraits<Scalar>::Real;
double worst = 0;
for (Index i = 0; i < solver.roots().size(); ++i) {
const std::complex<long double> z(solver.roots()[i].real(), solver.roots()[i].imag());
std::complex<long double> value(0);
long double magnitude = 0;
for (Index k = poly.size() - 1; k >= 0; --k) {
value = value * z + std::complex<long double>(poly[k]);
magnitude = magnitude * std::abs(z) + std::abs(std::complex<long double>(poly[k]));
}
worst = std::max(worst, double(std::abs(value) / magnitude / NumTraits<Real>::epsilon()));
}
return worst;
}
template <typename Scalar, int Deg>
static void BM_PolynomialSolver(benchmark::State& state) {
const Index degree = Deg == Dynamic ? Index(state.range(0)) : Index(Deg);
using Polynomial = Matrix<Scalar, Deg == Dynamic ? Dynamic : Deg + 1, 1>;
std::srand(1);
std::vector<Polynomial, aligned_allocator<Polynomial>> polys;
for (int b = 0; b < kBatch; ++b) polys.push_back(Polynomial::Random(degree + 1));
PolynomialSolver<Scalar, Deg> solver;
for (const Polynomial& poly : polys) {
solver.compute(poly);
// A backward-stable root finder stays within a small multiple of degree * eps.
if (!(maxBackwardError(solver, poly) <= 1024.0 * double(degree))) {
state.SkipWithError("root backward error too large");
return;
}
}
for (auto _ : state) {
for (const Polynomial& poly : polys) {
solver.compute(poly);
benchmark::DoNotOptimize(solver.roots().data());
}
}
state.counters["polys/s"] = benchmark::Counter(kBatch, benchmark::Counter::kIsIterationInvariantRate);
}
} // namespace
BENCHMARK_TEMPLATE(BM_PolynomialSolver, float, Dynamic)->Arg(5)->Arg(10)->Arg(20)->Arg(50);
BENCHMARK_TEMPLATE(BM_PolynomialSolver, double, Dynamic)->Arg(5)->Arg(10)->Arg(20)->Arg(50)->Arg(100);
BENCHMARK_TEMPLATE(BM_PolynomialSolver, std::complex<double>, Dynamic)->Arg(5)->Arg(20);
BENCHMARK_TEMPLATE(BM_PolynomialSolver, double, 5);
BENCHMARK_TEMPLATE(BM_PolynomialSolver, std::complex<double>, 5);