| // SPDX-FileCopyrightText: The Eigen Authors |
| // SPDX-License-Identifier: MPL-2.0 |
| |
| #include <benchmark/benchmark.h> |
| #include <Eigen/Core> |
| #include <Eigen/Eigenvalues> |
| #include <Eigen/Geometry> |
| |
| using namespace Eigen; |
| |
| template <typename Matrix, typename Roots> |
| inline void computeRoots(const Matrix& m, Roots& roots) { |
| typedef typename Matrix::Scalar Scalar; |
| const Scalar s_inv3 = 1.0 / 3.0; |
| const Scalar s_sqrt3 = std::sqrt(Scalar(3.0)); |
| Scalar c0 = m(0, 0) * m(1, 1) * m(2, 2) + Scalar(2) * m(0, 1) * m(0, 2) * m(1, 2) - m(0, 0) * m(1, 2) * m(1, 2) - |
| m(1, 1) * m(0, 2) * m(0, 2) - m(2, 2) * m(0, 1) * m(0, 1); |
| Scalar c1 = m(0, 0) * m(1, 1) - m(0, 1) * m(0, 1) + m(0, 0) * m(2, 2) - m(0, 2) * m(0, 2) + m(1, 1) * m(2, 2) - |
| m(1, 2) * m(1, 2); |
| Scalar c2 = m(0, 0) + m(1, 1) + m(2, 2); |
| Scalar c2_over_3 = c2 * s_inv3; |
| Scalar a_over_3 = (c1 - c2 * c2_over_3) * s_inv3; |
| if (a_over_3 > Scalar(0)) a_over_3 = Scalar(0); |
| Scalar half_b = Scalar(0.5) * (c0 + c2_over_3 * (Scalar(2) * c2_over_3 * c2_over_3 - c1)); |
| Scalar q = half_b * half_b + a_over_3 * a_over_3 * a_over_3; |
| if (q > Scalar(0)) q = Scalar(0); |
| Scalar rho = std::sqrt(-a_over_3); |
| Scalar theta = std::atan2(std::sqrt(-q), half_b) * s_inv3; |
| Scalar cos_theta = std::cos(theta); |
| Scalar sin_theta = std::sin(theta); |
| roots(2) = c2_over_3 + Scalar(2) * rho * cos_theta; |
| roots(0) = c2_over_3 - rho * (cos_theta + s_sqrt3 * sin_theta); |
| roots(1) = c2_over_3 - rho * (cos_theta - s_sqrt3 * sin_theta); |
| } |
| |
| template <typename Matrix, typename Vector> |
| void eigen33(const Matrix& mat, Matrix& evecs, Vector& evals) { |
| typedef typename Matrix::Scalar Scalar; |
| Scalar shift = mat.trace() / 3; |
| Matrix scaledMat = mat; |
| scaledMat.diagonal().array() -= shift; |
| Scalar scale = scaledMat.cwiseAbs().maxCoeff(); |
| scale = std::max(scale, Scalar(1)); |
| scaledMat /= scale; |
| computeRoots(scaledMat, evals); |
| if ((evals(2) - evals(0)) <= Eigen::NumTraits<Scalar>::epsilon()) { |
| evecs.setIdentity(); |
| } else { |
| Matrix tmp; |
| tmp = scaledMat; |
| tmp.diagonal().array() -= evals(2); |
| evecs.col(2) = tmp.row(0).cross(tmp.row(1)).normalized(); |
| tmp = scaledMat; |
| tmp.diagonal().array() -= evals(1); |
| evecs.col(1) = tmp.row(0).cross(tmp.row(1)); |
| Scalar n1 = evecs.col(1).norm(); |
| if (n1 <= Eigen::NumTraits<Scalar>::epsilon()) |
| evecs.col(1) = evecs.col(2).unitOrthogonal(); |
| else |
| evecs.col(1) /= n1; |
| evecs.col(1) = evecs.col(2).cross(evecs.col(1).cross(evecs.col(2))).normalized(); |
| evecs.col(0) = evecs.col(2).cross(evecs.col(1)); |
| } |
| evals *= scale; |
| evals.array() += shift; |
| } |
| |
| static void BM_Eig33_Iterative(benchmark::State& state) { |
| Matrix3d A = Matrix3d::Random(); |
| A = A.adjoint() * A; |
| SelfAdjointEigenSolver<Matrix3d> eig(A); |
| for (auto _ : state) { |
| eig.compute(A); |
| benchmark::DoNotOptimize(eig.eigenvalues().data()); |
| } |
| } |
| BENCHMARK(BM_Eig33_Iterative); |
| |
| static void BM_Eig33_Direct(benchmark::State& state) { |
| Matrix3d A = Matrix3d::Random(); |
| A = A.adjoint() * A; |
| SelfAdjointEigenSolver<Matrix3d> eig(A); |
| for (auto _ : state) { |
| eig.computeDirect(A); |
| benchmark::DoNotOptimize(eig.eigenvalues().data()); |
| } |
| } |
| BENCHMARK(BM_Eig33_Direct); |
| |
| static void BM_Eig33_Custom(benchmark::State& state) { |
| Matrix3d A = Matrix3d::Random(); |
| A = A.adjoint() * A; |
| Matrix3d evecs; |
| Vector3d evals; |
| for (auto _ : state) { |
| eigen33(A, evecs, evals); |
| benchmark::DoNotOptimize(evals.data()); |
| } |
| } |
| BENCHMARK(BM_Eig33_Custom); |