#include #include #include #include #include #include #include using namespace Eigen; // ============================================================================ // Fixed-size matrix multiply (the fundamental operation) // ============================================================================ template static void BM_MatMul(benchmark::State& state) { Matrix a, b, c; a.setRandom(); b.setRandom(); for (auto _ : state) { c.noalias() = a * b; benchmark::DoNotOptimize(c.data()); } } // Matrix-vector multiply template static void BM_MatVec(benchmark::State& state) { Matrix a; Matrix v, r; a.setRandom(); v.setRandom(); for (auto _ : state) { r.noalias() = a * v; benchmark::DoNotOptimize(r.data()); } } // ============================================================================ // Fixed-size inverse (critical for transform operations) // ============================================================================ template EIGEN_DONT_INLINE void do_inverse(const Matrix& a, Matrix& r) { r = a.inverse(); } template static void BM_Inverse(benchmark::State& state) { Matrix a, r; a.setRandom(); a += Matrix::Identity() * Scalar(N); // ensure well-conditioned for (auto _ : state) { do_inverse(a, r); benchmark::DoNotOptimize(r.data()); } } // ============================================================================ // Fixed-size determinant // ============================================================================ template static void BM_Determinant(benchmark::State& state) { Matrix a; a.setRandom(); Scalar d; for (auto _ : state) { d = a.determinant(); benchmark::DoNotOptimize(d); } } // ============================================================================ // LLT (Cholesky) — for SPD matrices (covariance, mass matrices) // ============================================================================ template static void BM_LLT_Compute(benchmark::State& state) { Matrix a; a.setRandom(); a = a.transpose() * a + Matrix::Identity(); // SPD LLT> llt; for (auto _ : state) { llt.compute(a); benchmark::DoNotOptimize(&llt); } } template static void BM_LLT_Solve(benchmark::State& state) { Matrix a; a.setRandom(); a = a.transpose() * a + Matrix::Identity(); Matrix b = Matrix::Random(); LLT> llt(a); Matrix x; for (auto _ : state) { x = llt.solve(b); benchmark::DoNotOptimize(x.data()); } } // ============================================================================ // LDLT — for semi-definite matrices // ============================================================================ template static void BM_LDLT_Compute(benchmark::State& state) { Matrix a; a.setRandom(); a = a.transpose() * a + Matrix::Identity(); LDLT> ldlt; for (auto _ : state) { ldlt.compute(a); benchmark::DoNotOptimize(&ldlt); } } // ============================================================================ // PartialPivLU — for general square systems // ============================================================================ template static void BM_PartialPivLU_Compute(benchmark::State& state) { Matrix a; a.setRandom(); a += Matrix::Identity() * Scalar(N); PartialPivLU> lu; for (auto _ : state) { lu.compute(a); benchmark::DoNotOptimize(lu.matrixLU().data()); } } template static void BM_PartialPivLU_Solve(benchmark::State& state) { Matrix a; a.setRandom(); a += Matrix::Identity() * Scalar(N); Matrix b = Matrix::Random(); PartialPivLU> lu(a); Matrix x; for (auto _ : state) { x = lu.solve(b); benchmark::DoNotOptimize(x.data()); } } // ============================================================================ // ColPivHouseholderQR — for least-squares (camera calibration, etc.) // ============================================================================ template static void BM_ColPivQR_Compute(benchmark::State& state) { Matrix a; a.setRandom(); ColPivHouseholderQR> qr; for (auto _ : state) { qr.compute(a); benchmark::DoNotOptimize(qr.matrixR().data()); } } // ============================================================================ // JacobiSVD — the workhorse for small matrices in CV // ============================================================================ template static void BM_JacobiSVD_Compute(benchmark::State& state) { Matrix a; a.setRandom(); JacobiSVD, Options> svd; for (auto _ : state) { svd.compute(a); benchmark::DoNotOptimize(svd.singularValues().data()); } } template static void BM_JacobiSVD_Solve(benchmark::State& state) { Matrix a; a.setRandom(); Matrix b = Matrix::Random(); JacobiSVD, ComputeThinU | ComputeThinV> svd(a); Matrix x; for (auto _ : state) { x = svd.solve(b); benchmark::DoNotOptimize(x.data()); } } // ============================================================================ // SelfAdjointEigenSolver — PCA, normal estimation // ============================================================================ template static void BM_SelfAdjointEig_Compute(benchmark::State& state) { Matrix a; a.setRandom(); a = a.transpose() * a; SelfAdjointEigenSolver> eig; for (auto _ : state) { eig.compute(a); benchmark::DoNotOptimize(eig.eigenvalues().data()); } } // SelfAdjointEigenSolver::computeDirect — closed-form for 2x2 and 3x3 template static void BM_SelfAdjointEig_ComputeDirect(benchmark::State& state) { Matrix a; a.setRandom(); a = a.transpose() * a; SelfAdjointEigenSolver> eig; for (auto _ : state) { eig.computeDirect(a); benchmark::DoNotOptimize(eig.eigenvalues().data()); } } // ============================================================================ // Registration — focus on robotics/CV sizes // ============================================================================ // Matrix multiply: 2x2, 3x3, 4x4, 6x6 BENCHMARK(BM_MatMul); BENCHMARK(BM_MatMul); BENCHMARK(BM_MatMul); BENCHMARK(BM_MatMul); BENCHMARK(BM_MatMul); BENCHMARK(BM_MatMul); BENCHMARK(BM_MatMul); BENCHMARK(BM_MatMul); // Matrix-vector multiply BENCHMARK(BM_MatVec); BENCHMARK(BM_MatVec); BENCHMARK(BM_MatVec); BENCHMARK(BM_MatVec); BENCHMARK(BM_MatVec); BENCHMARK(BM_MatVec); // Inverse BENCHMARK(BM_Inverse); BENCHMARK(BM_Inverse); BENCHMARK(BM_Inverse); BENCHMARK(BM_Inverse); BENCHMARK(BM_Inverse); BENCHMARK(BM_Inverse); // Determinant BENCHMARK(BM_Determinant); BENCHMARK(BM_Determinant); BENCHMARK(BM_Determinant); BENCHMARK(BM_Determinant); BENCHMARK(BM_Determinant); BENCHMARK(BM_Determinant); // LLT (Cholesky) BENCHMARK(BM_LLT_Compute); BENCHMARK(BM_LLT_Compute); BENCHMARK(BM_LLT_Compute); BENCHMARK(BM_LLT_Compute); BENCHMARK(BM_LLT_Compute); BENCHMARK(BM_LLT_Compute); BENCHMARK(BM_LLT_Solve); BENCHMARK(BM_LLT_Solve); // LDLT BENCHMARK(BM_LDLT_Compute); BENCHMARK(BM_LDLT_Compute); // PartialPivLU BENCHMARK(BM_PartialPivLU_Compute); BENCHMARK(BM_PartialPivLU_Compute); BENCHMARK(BM_PartialPivLU_Compute); BENCHMARK(BM_PartialPivLU_Compute); BENCHMARK(BM_PartialPivLU_Solve); BENCHMARK(BM_PartialPivLU_Solve); // ColPivHouseholderQR BENCHMARK(BM_ColPivQR_Compute); BENCHMARK(BM_ColPivQR_Compute); BENCHMARK(BM_ColPivQR_Compute); BENCHMARK(BM_ColPivQR_Compute); // overdetermined least-squares // JacobiSVD — the key CV sizes BENCHMARK(BM_JacobiSVD_Compute); BENCHMARK(BM_JacobiSVD_Compute); BENCHMARK(BM_JacobiSVD_Compute); BENCHMARK(BM_JacobiSVD_Compute); BENCHMARK(BM_JacobiSVD_Compute); BENCHMARK(BM_JacobiSVD_Compute); BENCHMARK(BM_JacobiSVD_Compute); // projection matrix BENCHMARK(BM_JacobiSVD_Compute); // manipulator Jacobian BENCHMARK(BM_JacobiSVD_Compute); // fundamental matrix (8-point) BENCHMARK(BM_JacobiSVD_Solve); BENCHMARK(BM_JacobiSVD_Solve); // Values-only SVD (when you just need singular values) BENCHMARK((BM_JacobiSVD_Compute)); BENCHMARK((BM_JacobiSVD_Compute)); // SelfAdjointEigenSolver — PCA, normal estimation BENCHMARK(BM_SelfAdjointEig_Compute); BENCHMARK(BM_SelfAdjointEig_Compute); BENCHMARK(BM_SelfAdjointEig_Compute); BENCHMARK(BM_SelfAdjointEig_Compute); BENCHMARK(BM_SelfAdjointEig_Compute); // SelfAdjointEigenSolver::computeDirect (closed-form, 2x2 and 3x3 only) BENCHMARK(BM_SelfAdjointEig_ComputeDirect); BENCHMARK(BM_SelfAdjointEig_ComputeDirect); BENCHMARK(BM_SelfAdjointEig_ComputeDirect); BENCHMARK(BM_SelfAdjointEig_ComputeDirect);