12#ifndef EASY3D_CORE_EIGEN_SOLVER_H
13#define EASY3D_CORE_EIGEN_SOLVER_H
28 template <
class MAT,
typename T =
double>
94 static void tridiagonal_2(MAT& mat, T* diag, T* subd);
95 static void tridiagonal_3(MAT& mat, T* diag, T* subd);
96 static void tridiagonal_4(MAT& mat, T* diag, T* subd);
97 static void tridiagonal_n(
int n, MAT& mat, T* diag, T* subd);
100 static bool ql_algorithm(
int n, T* diag, T* subd, MAT& mat);
103 static void decreasing_sort(
int n, T* eigval, MAT& eigvec);
106 static void increasing_sort(
int n, T* eigval, MAT& eigvec);
113 template <
class MAT,
typename T>
118 diag_ =
new T[size_];
119 subd_ =
new T[size_];
122 template <
class MAT,
typename T>
130 template <
class MAT,
typename T>
131 void EigenSolver<MAT, T>::tridiagonal_2(MAT& matrix, T* diag, T* subd)
134 diag[0] = matrix(0, 0);
135 diag[1] = matrix(1, 1);
136 subd[0] = matrix(0, 1);
145 template <
class MAT,
typename T>
146 void EigenSolver<MAT, T>::tridiagonal_3(MAT& matrix, T* diag, T* subd)
148 T fM00 = matrix(0, 0);
149 T fM01 = matrix(0, 1);
150 T fM02 = matrix(0, 2);
151 T fM11 = matrix(1, 1);
152 T fM12 = matrix(1, 2);
153 T fM22 = matrix(2, 2);
159 T fLength = std::sqrt(fM01 * fM01 + fM02 * fM02);
160 T fInvLength = 1.0f / fLength;
163 T fQ = 2.0f * fM01 * fM12 + fM02 * (fM22 - fM11);
164 diag[1] = fM11 + fM02 * fQ;
165 diag[2] = fM22 - fM02 * fQ;
167 subd[1] = fM12 - fM01 * fQ;
176 matrix(2, 2) = -fM01;
197 template <
class MAT,
typename T>
198 void EigenSolver<MAT, T>::tridiagonal_4(MAT& matrix, T* diag, T* subd)
201 T fM00 = matrix(0, 0);
202 T fM01 = matrix(0, 1);
203 T fM02 = matrix(0, 2);
204 T fM03 = matrix(0, 3);
205 T fM11 = matrix(1, 1);
206 T fM12 = matrix(1, 2);
207 T fM13 = matrix(1, 3);
208 T fM22 = matrix(2, 2);
209 T fM23 = matrix(2, 3);
210 T fM33 = matrix(3, 3);
223 T fLength, fInvLength;
225 if (fM02 != 0.0f || fM03 != 0.0f)
232 fLength = std::sqrt(fM01 * fM01 + fM02 * fM02 + fM03 * fM03);
233 fInvLength = 1.0f / fLength;
234 fQ11 = fM01 * fInvLength;
235 fQ21 = fM02 * fInvLength;
236 fQ31 = fM03 * fInvLength;
241 T fV0 = fM11 * fQ11 + fM12 * fQ21 + fM13 * fQ31;
242 T fV1 = fM12 * fQ11 + fM22 * fQ21 + fM23 * fQ31;
243 T fV2 = fM13 * fQ11 + fM23 * fQ21 + fM33 * fQ31;
245 diag[1] = fQ11 * fV0 + fQ21 * fV1 + fQ31 * fV2;
248 fQ13 = fQ21 * fV2 - fQ31 * fV1;
249 fQ23 = fQ31 * fV0 - fQ11 * fV2;
250 fQ33 = fQ11 * fV1 - fQ21 * fV0;
251 fLength = std::sqrt(fQ13 * fQ13 + fQ23 * fQ23 + fQ33 * fQ33);
254 fInvLength = 1.0f / fLength;
260 fQ12 = fQ23 * fQ31 - fQ33 * fQ21;
261 fQ22 = fQ33 * fQ11 - fQ13 * fQ31;
262 fQ32 = fQ13 * fQ21 - fQ23 * fQ11;
264 fV0 = fQ12 * fM11 + fQ22 * fM12 + fQ32 * fM13;
265 fV1 = fQ12 * fM12 + fQ22 * fM22 + fQ32 * fM23;
266 fV2 = fQ12 * fM13 + fQ22 * fM23 + fQ32 * fM33;
267 subd[1] = fQ11 * fV0 + fQ21 * fV1 + fQ31 * fV2;
268 diag[2] = fQ12 * fV0 + fQ22 * fV1 + fQ32 * fV2;
269 subd[2] = fQ13 * fV0 + fQ23 * fV1 + fQ33 * fV2;
271 fV0 = fQ13 * fM11 + fQ23 * fM12 + fQ33 * fM13;
272 fV1 = fQ13 * fM12 + fQ23 * fM22 + fQ33 * fM23;
273 fV2 = fQ13 * fM13 + fQ23 * fM23 + fQ33 * fM33;
274 diag[3] = fQ13 * fV0 + fQ23 * fV1 + fQ33 * fV2;
281 fLength = fQ21 * fQ21 + fQ31 * fQ31;
284 fInvLength = 1.0f / fLength;
285 T fTmp = fQ11 - 1.0f;
287 fQ22 = 1.0f + fTmp * fQ21 * fQ21 * fInvLength;
288 fQ32 = fTmp * fQ21 * fQ31 * fInvLength;
292 fQ33 = 1.0f + fTmp * fQ31 * fQ31 * fInvLength;
294 fV0 = fQ12 * fM11 + fQ22 * fM12 + fQ32 * fM13;
295 fV1 = fQ12 * fM12 + fQ22 * fM22 + fQ32 * fM23;
296 fV2 = fQ12 * fM13 + fQ22 * fM23 + fQ32 * fM33;
297 diag[2] = fQ12 * fV0 + fQ22 * fV1 + fQ32 * fV2;
298 subd[2] = fQ13 * fV0 + fQ23 * fV1 + fQ33 * fV2;
300 fV0 = fQ13 * fM11 + fQ23 * fM12 + fQ33 * fM13;
301 fV1 = fQ13 * fM12 + fQ23 * fM22 + fQ33 * fM23;
302 fV2 = fQ13 * fM13 + fQ23 * fM23 + fQ33 * fM33;
303 diag[3] = fQ13 * fV0 + fQ23 * fV1 + fQ33 * fV2;
341 fLength = std::sqrt(fM12 * fM12 + fM13 * fM13);
342 fInvLength = 1.0f / fLength;
345 T fQ = 2.0f * fM12 * fM23 + fM13 * (fM33 - fM22);
347 diag[2] = fM22 + fM13 * fQ;
348 diag[3] = fM33 - fM13 * fQ;
350 subd[2] = fM23 - fM12 * fQ;
356 matrix(3, 3) = -fM12;
375 template <
class MAT,
typename T>
376 void EigenSolver<MAT, T>::tridiagonal_n(
int n, MAT& matrix, T* diag, T* subd)
380 for (i0 = n - 1, i3 = n - 2; i0 >= 1; i0--, i3--)
382 T fH = 0.0f, fScale = 0.0f;
386 for (i2 = 0; i2 <= i3; i2++)
387 fScale += std::abs(matrix(i0, i2));
390 subd[i0] = matrix(i0, i3);
394 T fInvScale = 1.0f / fScale;
395 for (i2 = 0; i2 <= i3; i2++)
397 matrix(i0, i2) *= fInvScale;
398 fH += matrix(i0, i2) * matrix(i0, i2);
400 T fF = matrix(i0, i3);
401 T fG = std::sqrt(fH);
404 subd[i0] = fScale * fG;
406 matrix(i0, i3) = fF - fG;
409 for (i1 = 0; i1 <= i3; i1++)
411 matrix(i1, i0) = matrix(i0, i1) * fInvH;
413 for (i2 = 0; i2 <= i1; i2++)
414 fG += matrix(i1, i2) * matrix(i0, i2);
415 for (i2 = i1 + 1; i2 <= i3; i2++)
416 fG += matrix(i2, i1) * matrix(i0, i2);
417 subd[i1] = fG * fInvH;
418 fF += subd[i1] * matrix(i0, i1);
420 T fHalfFdivH = 0.5f * fF * fInvH;
421 for (i1 = 0; i1 <= i3; i1++)
424 fG = subd[i1] - fHalfFdivH * fF;
426 for (i2 = 0; i2 <= i1; i2++)
428 matrix(i1, i2) -= fF * subd[i2] + fG * matrix(i0, i2);
435 subd[i0] = matrix(i0, i3);
443 for (i0 = 0, i3 = -1; i0 <= n - 1; i0++, i3++)
447 for (i1 = 0; i1 <= i3; i1++)
450 for (i2 = 0; i2 <= i3; i2++)
451 fSum += matrix(i0, i2) * matrix(i2, i1);
452 for (i2 = 0; i2 <= i3; i2++)
453 matrix(i2, i1) -= fSum * matrix(i2, i0);
456 diag[i0] = matrix(i0, i0);
457 matrix(i0, i0) = 1.0f;
458 for (i1 = 0; i1 <= i3; i1++)
460 matrix(i1, i0) = 0.0f;
461 matrix(i0, i1) = 0.0f;
466 for (i0 = 1, i3 = 0; i0 < n; i0++, i3++)
472 template <
class MAT,
typename T>
473 bool EigenSolver<MAT, T>::ql_algorithm(
int n, T* diag, T* subd, MAT& matrix)
475 const int iMaxIter = 32;
477 for (
int i0 = 0; i0 < n; i0++)
480 for (i1 = 0; i1 < iMaxIter; i1++)
483 for (i2 = i0; i2 <= n - 2; i2++)
485 T fTmp = std::abs(diag[i2]) +
486 std::abs(diag[i2 + 1]);
487 if (std::abs(subd[i2]) + fTmp == fTmp)
493 T fG = (diag[i0 + 1] - diag[i0]) / (2.0f * subd[i0]);
494 T fR = std::sqrt(fG * fG + 1.0f);
496 fG = diag[i2] - diag[i0] + subd[i0] / (fG - fR);
498 fG = diag[i2] - diag[i0] + subd[i0] / (fG + fR);
499 T fSin = 1.0f, fCos = 1.0, fP = 0.0f;
500 for (
int i3 = i2 - 1; i3 >= i0; i3--)
502 T fF = fSin * subd[i3];
503 T fB = fCos * subd[i3];
504 if (std::abs(fF) >= std::abs(fG))
507 fR = std::sqrt(fCos * fCos + 1.0f);
508 subd[i3 + 1] = fF * fR;
515 fR = std::sqrt(fSin * fSin + 1.0f);
516 subd[i3 + 1] = fG * fR;
520 fG = diag[i3 + 1] - fP;
521 fR = (diag[i3] - fG) * fSin + 2.0f * fB * fCos;
523 diag[i3 + 1] = fG + fP;
526 for (
int i4 = 0; i4 < n; i4++)
528 fF = matrix(i4, i3 + 1);
529 matrix(i4, i3 + 1) = fSin * matrix(i4, i3) + fCos * fF;
530 matrix(i4, i3) = fCos * matrix(i4, i3) - fSin * fF;
545 template <
class MAT,
typename T>
546 void EigenSolver<MAT, T>::decreasing_sort(
int n, T* eigval, MAT& eigvec)
549 for (
int i0 = 0, i1; i0 <= n - 2; i0++)
555 for (i2 = i0 + 1; i2 < n; i2++)
557 if (eigval[i2] > fMax)
567 eigval[i1] = eigval[i0];
571 for (i2 = 0; i2 < n; i2++)
573 T fTmp = eigvec(i2, i0);
574 eigvec(i2, i0) = eigvec(i2, i1);
575 eigvec(i2, i1) = fTmp;
582 template <
class MAT,
typename T>
583 void EigenSolver<MAT, T>::increasing_sort(
int n, T* eigval, MAT& eigvec)
586 for (
int i0 = 0, i1; i0 <= n - 2; i0++)
592 for (i2 = i0 + 1; i2 < n; i2++)
594 if (eigval[i2] < fMin)
604 eigval[i1] = eigval[i0];
608 for (i2 = 0; i2 < n; i2++)
610 T fTmp = eigvec(i2, i0);
611 eigvec(i2, i0) = eigvec(i2, i1);
612 eigvec(i2, i1) = fTmp;
619 template <
class MAT,
typename T>
627 tridiagonal_2(matrix_, diag_, subd_);
630 tridiagonal_3(matrix_, diag_, subd_);
633 tridiagonal_4(matrix_, diag_, subd_);
636 tridiagonal_n(size_, matrix_, diag_, subd_);
640 ql_algorithm(size_, diag_, subd_, matrix_);
645 increasing_sort(size_, diag_, matrix_);
648 decreasing_sort(size_, diag_, matrix_);
T eigen_value(int i) const
Retrieves the eigenvalue at the specified index.
Definition eigen_solver.h:65
void solve(const MAT &mat, SortingMethod sm=NO_SORTING)
Computes the eigenvalues and eigenvectors of the specified input matrix.
Definition eigen_solver.h:620
const MAT & eigen_vectors()
Retrieves the matrix of eigenvectors, stored as columns.
Definition eigen_solver.h:84
T eigen_vector(int comp, int i) const
Retrieves the specified component of the eigenvector at the given index.
Definition eigen_solver.h:72
T * eigen_values()
Retrieves the array of eigenvalues.
Definition eigen_solver.h:78
SortingMethod
Enumeration of sorting methods for eigenvalues and their corresponding eigenvectors.
Definition eigen_solver.h:36
@ INCREASING
Sort in increasing order.
Definition eigen_solver.h:38
@ DECREASING
Sort in decreasing order.
Definition eigen_solver.h:39
@ NO_SORTING
No sorting.
Definition eigen_solver.h:37
~EigenSolver()
Destructor.
Definition eigen_solver.h:123
EigenSolver(int n)
Constructs an EigenSolver with a specified matrix size.
Definition eigen_solver.h:114
Definition collider.cpp:182