mirror of
https://gitlab.com/libeigen/eigen.git
synced 2026-04-10 11:34:33 +08:00
Add benchmarks for unsupported modules and extend supported benchmarks
libeigen/eigen!2179 Closes #3036 Co-authored-by: Rasmus Munk Larsen <rmlarsen@gmail.com>
This commit is contained in:
1
unsupported/benchmarks/AutoDiff/CMakeLists.txt
Normal file
1
unsupported/benchmarks/AutoDiff/CMakeLists.txt
Normal file
@@ -0,0 +1 @@
|
||||
eigen_add_benchmark(bench_autodiff bench_autodiff.cpp)
|
||||
177
unsupported/benchmarks/AutoDiff/bench_autodiff.cpp
Normal file
177
unsupported/benchmarks/AutoDiff/bench_autodiff.cpp
Normal file
@@ -0,0 +1,177 @@
|
||||
// Benchmarks for Eigen AutoDiff module.
|
||||
// Compares AutoDiff Jacobian computation against NumericalDiff and hand-coded Jacobians.
|
||||
|
||||
#include <benchmark/benchmark.h>
|
||||
#include <Eigen/Core>
|
||||
#include <unsupported/Eigen/AutoDiff>
|
||||
#include <unsupported/Eigen/NumericalDiff>
|
||||
|
||||
using namespace Eigen;
|
||||
|
||||
// --- Small functor: Rosenbrock-like (2 inputs -> 2 outputs) ---
|
||||
struct SmallFunctor {
|
||||
typedef Matrix<double, 2, 1> InputType;
|
||||
typedef Matrix<double, 2, 1> ValueType;
|
||||
typedef Matrix<double, 2, 2> JacobianType;
|
||||
|
||||
enum { InputsAtCompileTime = 2, ValuesAtCompileTime = 2 };
|
||||
|
||||
template <typename T>
|
||||
void operator()(const Matrix<T, 2, 1>& x, Matrix<T, 2, 1>* v) const {
|
||||
(*v)(0) = T(1) - x(0);
|
||||
(*v)(1) = T(10) * (x(1) - x(0) * x(0));
|
||||
}
|
||||
};
|
||||
|
||||
// --- Medium functor: chain of operations (6 inputs -> 6 outputs) ---
|
||||
struct MediumFunctor {
|
||||
typedef Matrix<double, 6, 1> InputType;
|
||||
typedef Matrix<double, 6, 1> ValueType;
|
||||
typedef Matrix<double, 6, 6> JacobianType;
|
||||
|
||||
enum { InputsAtCompileTime = 6, ValuesAtCompileTime = 6 };
|
||||
|
||||
template <typename T>
|
||||
void operator()(const Matrix<T, 6, 1>& x, Matrix<T, 6, 1>* v) const {
|
||||
(*v)(0) = sin(x(0)) * cos(x(1)) + x(2) * x(2);
|
||||
(*v)(1) = exp(x(1) * T(0.1)) + x(3);
|
||||
(*v)(2) = x(0) * x(2) - x(4) * x(5);
|
||||
(*v)(3) = sqrt(x(3) * x(3) + T(1)) + x(0);
|
||||
(*v)(4) = x(4) * x(4) + x(5) * x(5) + x(0) * x(1);
|
||||
(*v)(5) = log(x(2) * x(2) + T(1)) + x(3) * x(4);
|
||||
}
|
||||
};
|
||||
|
||||
// --- Dynamic-size functor (N inputs -> N outputs) ---
|
||||
struct DynamicFunctor {
|
||||
typedef Matrix<double, Dynamic, 1> InputType;
|
||||
typedef Matrix<double, Dynamic, 1> ValueType;
|
||||
typedef Matrix<double, Dynamic, Dynamic> JacobianType;
|
||||
|
||||
const int n_;
|
||||
DynamicFunctor(int n) : n_(n) {}
|
||||
|
||||
enum { InputsAtCompileTime = Dynamic, ValuesAtCompileTime = Dynamic };
|
||||
|
||||
int inputs() const { return n_; }
|
||||
int values() const { return n_; }
|
||||
|
||||
template <typename T>
|
||||
void operator()(const Matrix<T, Dynamic, 1>& x, Matrix<T, Dynamic, 1>* v) const {
|
||||
v->resize(n_);
|
||||
(*v)(0) = T(1) - x(0);
|
||||
for (int i = 1; i < n_; ++i) {
|
||||
(*v)(i) = T(10) * (x(i) - x(i - 1) * x(i - 1));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Wrapper for NumericalDiff compatibility.
|
||||
struct SmallFunctorND : SmallFunctor {
|
||||
typedef double Scalar;
|
||||
int inputs() const { return 2; }
|
||||
int values() const { return 2; }
|
||||
int operator()(const InputType& x, ValueType& v) const {
|
||||
SmallFunctor::operator()(x, &v);
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
struct MediumFunctorND : MediumFunctor {
|
||||
typedef double Scalar;
|
||||
int inputs() const { return 6; }
|
||||
int values() const { return 6; }
|
||||
int operator()(const InputType& x, ValueType& v) const {
|
||||
MediumFunctor::operator()(x, &v);
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
// --- AutoDiff Jacobian benchmarks ---
|
||||
template <typename Functor>
|
||||
static void BM_AutoDiffJacobian(benchmark::State& state, Functor func) {
|
||||
AutoDiffJacobian<Functor> adf(func);
|
||||
typename Functor::InputType x = Functor::InputType::Random();
|
||||
typename Functor::ValueType v;
|
||||
typename Functor::JacobianType jac;
|
||||
|
||||
for (auto _ : state) {
|
||||
adf(x, &v, &jac);
|
||||
benchmark::DoNotOptimize(jac.data());
|
||||
benchmark::ClobberMemory();
|
||||
}
|
||||
}
|
||||
|
||||
// --- Dynamic AutoDiff Jacobian ---
|
||||
static void BM_AutoDiffJacobian_Dynamic(benchmark::State& state) {
|
||||
int n = state.range(0);
|
||||
DynamicFunctor func(n);
|
||||
AutoDiffJacobian<DynamicFunctor> adf(func);
|
||||
|
||||
VectorXd x = VectorXd::Random(n);
|
||||
VectorXd v(n);
|
||||
MatrixXd jac(n, n);
|
||||
|
||||
for (auto _ : state) {
|
||||
adf(x, &v, &jac);
|
||||
benchmark::DoNotOptimize(jac.data());
|
||||
benchmark::ClobberMemory();
|
||||
}
|
||||
}
|
||||
|
||||
// --- NumericalDiff benchmarks ---
|
||||
template <typename Functor>
|
||||
static void BM_NumericalDiffJacobian(benchmark::State& state, Functor func) {
|
||||
NumericalDiff<Functor> ndf(func);
|
||||
typename Functor::InputType x = Functor::InputType::Random();
|
||||
typename Functor::JacobianType jac;
|
||||
|
||||
for (auto _ : state) {
|
||||
ndf.df(x, jac);
|
||||
benchmark::DoNotOptimize(jac.data());
|
||||
benchmark::ClobberMemory();
|
||||
}
|
||||
}
|
||||
|
||||
// --- Hand-coded Jacobian (Rosenbrock) for comparison ---
|
||||
static void BM_HandCoded_Small(benchmark::State& state) {
|
||||
Vector2d x = Vector2d::Random();
|
||||
Matrix2d jac;
|
||||
|
||||
for (auto _ : state) {
|
||||
jac(0, 0) = -1;
|
||||
jac(0, 1) = 0;
|
||||
jac(1, 0) = -20 * x(0);
|
||||
jac(1, 1) = 10;
|
||||
benchmark::DoNotOptimize(jac.data());
|
||||
benchmark::ClobberMemory();
|
||||
}
|
||||
}
|
||||
|
||||
// --- Scalar AutoDiff evaluation (no Jacobian, just forward pass) ---
|
||||
static void BM_AutoDiffScalar_Eval(benchmark::State& state) {
|
||||
int n = state.range(0);
|
||||
using ADScalar = AutoDiffScalar<VectorXd>;
|
||||
VectorXd x = VectorXd::Random(n);
|
||||
|
||||
for (auto _ : state) {
|
||||
ADScalar sum(0.0, VectorXd::Zero(n));
|
||||
for (int i = 0; i < n; ++i) {
|
||||
ADScalar xi(x(i), n, i);
|
||||
sum += xi * xi + sin(xi);
|
||||
}
|
||||
benchmark::DoNotOptimize(sum.value());
|
||||
benchmark::DoNotOptimize(sum.derivatives().data());
|
||||
benchmark::ClobberMemory();
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK_CAPTURE(BM_AutoDiffJacobian, Small, SmallFunctor());
|
||||
BENCHMARK_CAPTURE(BM_AutoDiffJacobian, Medium, MediumFunctor());
|
||||
BENCHMARK(BM_AutoDiffJacobian_Dynamic)->Arg(2)->Arg(6)->Arg(20)->Arg(50)->Arg(100);
|
||||
|
||||
BENCHMARK_CAPTURE(BM_NumericalDiffJacobian, Small, SmallFunctorND());
|
||||
BENCHMARK_CAPTURE(BM_NumericalDiffJacobian, Medium, MediumFunctorND());
|
||||
|
||||
BENCHMARK(BM_HandCoded_Small);
|
||||
BENCHMARK(BM_AutoDiffScalar_Eval)->Arg(2)->Arg(6)->Arg(20)->Arg(50)->Arg(100);
|
||||
Reference in New Issue
Block a user