eig33.cpp File Reference
#include <iostream>
#include <Eigen/Core>
#include <Eigen/Eigenvalues>
#include <Eigen/Geometry>
#include <bench/BenchTimer.h>

Functions

template<typename Matrix , typename Roots >
void computeRoots (const Matrix &m, Roots &roots)
 
template<typename Matrix , typename Vector >
void eigen33 (const Matrix &mat, Matrix &evecs, Vector &evals)
 
int main ()
 

Function Documentation

◆ computeRoots()

template<typename Matrix , typename Roots >
void computeRoots ( const Matrix m,
Roots &  roots 
)
inline
49  {
50  typedef typename Matrix::Scalar Scalar;
51  const Scalar s_inv3 = 1.0 / 3.0;
52  const Scalar s_sqrt3 = std::sqrt(Scalar(3.0));
53 
54  // The characteristic equation is x^3 - c2*x^2 + c1*x - c0 = 0. The
55  // eigenvalues are the roots to this equation, all guaranteed to be
56  // real-valued, because the matrix is symmetric.
57  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) -
58  m(1, 1) * m(0, 2) * m(0, 2) - m(2, 2) * m(0, 1) * m(0, 1);
59  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) -
60  m(1, 2) * m(1, 2);
61  Scalar c2 = m(0, 0) + m(1, 1) + m(2, 2);
62 
63  // Construct the parameters used in classifying the roots of the equation
64  // and in solving the equation for the roots in closed form.
65  Scalar c2_over_3 = c2 * s_inv3;
66  Scalar a_over_3 = (c1 - c2 * c2_over_3) * s_inv3;
67  if (a_over_3 > Scalar(0)) a_over_3 = Scalar(0);
68 
69  Scalar half_b = Scalar(0.5) * (c0 + c2_over_3 * (Scalar(2) * c2_over_3 * c2_over_3 - c1));
70 
71  Scalar q = half_b * half_b + a_over_3 * a_over_3 * a_over_3;
72  if (q > Scalar(0)) q = Scalar(0);
73 
74  // Compute the eigenvalues by solving for the roots of the polynomial.
75  Scalar rho = std::sqrt(-a_over_3);
76  Scalar theta = std::atan2(std::sqrt(-q), half_b) * s_inv3;
77  Scalar cos_theta = std::cos(theta);
78  Scalar sin_theta = std::sin(theta);
79  roots(2) = c2_over_3 + Scalar(2) * rho * cos_theta;
80  roots(0) = c2_over_3 - rho * (cos_theta + s_sqrt3 * sin_theta);
81  roots(1) = c2_over_3 - rho * (cos_theta - s_sqrt3 * sin_theta);
82 }
AnnoyingScalar cos(const AnnoyingScalar &x)
Definition: AnnoyingScalar.h:136
AnnoyingScalar atan2(const AnnoyingScalar &y, const AnnoyingScalar &x)
Definition: AnnoyingScalar.h:139
AnnoyingScalar sin(const AnnoyingScalar &x)
Definition: AnnoyingScalar.h:137
AnnoyingScalar sqrt(const AnnoyingScalar &x)
Definition: AnnoyingScalar.h:134
SCALAR Scalar
Definition: bench_gemm.cpp:45
int * m
Definition: level2_cplx_impl.h:294
double theta
Definition: two_d_biharmonic.cc:236
EIGEN_DEVICE_FUNC const Scalar & q
Definition: SpecialFunctionsImpl.h:2019

References atan2(), cos(), m, Eigen::numext::q, sin(), sqrt(), and BiharmonicTestFunctions2::theta.

Referenced by eigen33(), Eigen::internal::direct_selfadjoint_eigenvalues< SolverType, 3, false >::run(), and Eigen::internal::direct_selfadjoint_eigenvalues< SolverType, 2, false >::run().

◆ eigen33()

template<typename Matrix , typename Vector >
void eigen33 ( const Matrix mat,
Matrix evecs,
Vector evals 
)
85  {
86  typedef typename Matrix::Scalar Scalar;
87  // Scale the matrix so its entries are in [-1,1]. The scaling is applied
88  // only when at least one matrix entry has magnitude larger than 1.
89 
90  Scalar shift = mat.trace() / 3;
91  Matrix scaledMat = mat;
92  scaledMat.diagonal().array() -= shift;
93  Scalar scale = scaledMat.cwiseAbs() /*.template triangularView<Lower>()*/.maxCoeff();
94  scale = std::max(scale, Scalar(1));
95  scaledMat /= scale;
96 
97  // Compute the eigenvalues
98  // scaledMat.setZero();
99  computeRoots(scaledMat, evals);
100 
101  // compute the eigen vectors
102  // **here we assume 3 different eigenvalues**
103 
104  // "optimized version" which appears to be slower with gcc!
105  // Vector base;
106  // Scalar alpha, beta;
107  // base << scaledMat(1,0) * scaledMat(2,1),
108  // scaledMat(1,0) * scaledMat(2,0),
109  // -scaledMat(1,0) * scaledMat(1,0);
110  // for(int k=0; k<2; ++k)
111  // {
112  // alpha = scaledMat(0,0) - evals(k);
113  // beta = scaledMat(1,1) - evals(k);
114  // evecs.col(k) = (base + Vector(-beta*scaledMat(2,0), -alpha*scaledMat(2,1), alpha*beta)).normalized();
115  // }
116  // evecs.col(2) = evecs.col(0).cross(evecs.col(1)).normalized();
117 
118  // // naive version
119  // Matrix tmp;
120  // tmp = scaledMat;
121  // tmp.diagonal().array() -= evals(0);
122  // evecs.col(0) = tmp.row(0).cross(tmp.row(1)).normalized();
123  //
124  // tmp = scaledMat;
125  // tmp.diagonal().array() -= evals(1);
126  // evecs.col(1) = tmp.row(0).cross(tmp.row(1)).normalized();
127  //
128  // tmp = scaledMat;
129  // tmp.diagonal().array() -= evals(2);
130  // evecs.col(2) = tmp.row(0).cross(tmp.row(1)).normalized();
131 
132  // a more stable version:
133  if ((evals(2) - evals(0)) <= Eigen::NumTraits<Scalar>::epsilon()) {
134  evecs.setIdentity();
135  } else {
136  Matrix tmp;
137  tmp = scaledMat;
138  tmp.diagonal().array() -= evals(2);
139  evecs.col(2) = tmp.row(0).cross(tmp.row(1)).normalized();
140 
141  tmp = scaledMat;
142  tmp.diagonal().array() -= evals(1);
143  evecs.col(1) = tmp.row(0).cross(tmp.row(1));
144  Scalar n1 = evecs.col(1).norm();
146  evecs.col(1) = evecs.col(2).unitOrthogonal();
147  else
148  evecs.col(1) /= n1;
149 
150  // make sure that evecs[1] is orthogonal to evecs[2]
151  evecs.col(1) = evecs.col(2).cross(evecs.col(1).cross(evecs.col(2))).normalized();
152  evecs.col(0) = evecs.col(2).cross(evecs.col(1));
153  }
154 
155  // Rescale back to the original size.
156  evals *= scale;
157  evals.array() += shift;
158 }
Eigen::SparseMatrix< double > mat
Definition: EigenUnitTest.cpp:10
The matrix class, also used for vectors and row-vectors.
Definition: Eigen/Eigen/src/Core/Matrix.h:186
#define max(a, b)
Definition: datatypes.h:23
void computeRoots(const Matrix &m, Roots &roots)
Definition: eig33.cpp:49
Eigen::Matrix< Scalar, Dynamic, Dynamic, ColMajor > tmp
Definition: level3_impl.h:365
Holds information about the various numeric (i.e. scalar) types allowed by Eigen.
Definition: NumTraits.h:217

References computeRoots(), max, and tmp.

Referenced by main().

◆ main()

int main ( )
160  {
161  BenchTimer t;
162  int tries = 10;
163  int rep = 400000;
164  typedef Matrix3d Mat;
165  typedef Vector3d Vec;
166  Mat A = Mat::Random(3, 3);
167  A = A.adjoint() * A;
168  // Mat Q = A.householderQr().householderQ();
169  // A = Q * Vec(2.2424567,2.2424566,7.454353).asDiagonal() * Q.transpose();
170 
172  BENCH(t, tries, rep, eig.compute(A));
173  std::cout << "Eigen iterative: " << t.best() << "s\n";
174 
175  BENCH(t, tries, rep, eig.computeDirect(A));
176  std::cout << "Eigen direct : " << t.best() << "s\n";
177 
178  Mat evecs;
179  Vec evals;
180  BENCH(t, tries, rep, eigen33(A, evecs, evals));
181  std::cout << "Direct: " << t.best() << "s\n\n";
182 
183  // std::cerr << "Eigenvalue/eigenvector diffs:\n";
184  // std::cerr << (evals - eig.eigenvalues()).transpose() << "\n";
185  // for(int k=0;k<3;++k)
186  // if(evecs.col(k).dot(eig.eigenvectors().col(k))<0)
187  // evecs.col(k) = -evecs.col(k);
188  // std::cerr << evecs - eig.eigenvectors() << "\n\n";
189 }
#define BENCH(TIMER, TRIES, REP, CODE)
Definition: BenchTimer.h:150
Matrix< SCALARA, Dynamic, Dynamic, opt_A > A
Definition: bench_gemm.cpp:47
Definition: BenchTimer.h:55
Computes eigenvalues and eigenvectors of selfadjoint matrices.
Definition: SelfAdjointEigenSolver.h:82
void eigen33(const Matrix &mat, Matrix &evecs, Vector &evals)
Definition: eig33.cpp:85
Matrix< Scalar, Dynamic, Dynamic > Mat
Definition: gemm_common.h:15
Matrix< Scalar, Dynamic, 1 > Vec
Definition: gemv_common.h:17
t
Definition: plotPSD.py:36

References BENCH, Eigen::SelfAdjointEigenSolver< MatrixType_ >::compute(), Eigen::SelfAdjointEigenSolver< MatrixType_ >::computeDirect(), eigen33(), and plotPSD::t.