12#ifndef EASY3D_CORE_EIGEN_SOLVER_H
13#define EASY3D_CORE_EIGEN_SOLVER_H
23 template <
typename FT>
43 FT
eigen_vector(
int comp,
int i)
const {
return matrix_[comp][i]; }
58 static void tridiagonal_2(FT** mat, FT* diag, FT* subd);
59 static void tridiagonal_3(FT** mat, FT* diag, FT* subd);
60 static void tridiagonal_4(FT** mat, FT* diag, FT* subd);
61 static void tridiagonal_n(
int n, FT** mat, FT* diag, FT* subd);
64 static bool ql_algorithm(
int n, FT* diag, FT* subd, FT** mat);
67 static void decreasing_sort(
int n, FT* eigval, FT** eigvec);
70 static void increasing_sort(
int n, FT* eigval, FT** eigvec);
77 template <
typename FT>
85 diag_ =
new FT[size_];
86 subd_ =
new FT[size_];
89 template <
typename FT>
97 template <
typename FT>
98 inline void EigenSolver<FT>::tridiagonal_2(FT** matrix_, FT* diag_, FT* subd_)
101 diag_[0] = matrix_[0][0];
102 diag_[1] = matrix_[1][1];
103 subd_[0] = matrix_[0][1];
105 matrix_[0][0] = 1.0f;
106 matrix_[0][1] = 0.0f;
107 matrix_[1][0] = 0.0f;
108 matrix_[1][1] = 1.0f;
112 template <
typename FT>
113 inline void EigenSolver<FT>::tridiagonal_3(FT** matrix_, FT* diag_, FT* subd_)
115 FT fM00 = matrix_[0][0];
116 FT fM01 = matrix_[0][1];
117 FT fM02 = matrix_[0][2];
118 FT fM11 = matrix_[1][1];
119 FT fM12 = matrix_[1][2];
120 FT fM22 = matrix_[2][2];
126 FT fLength = std::sqrt(fM01*fM01+fM02*fM02);
127 FT fInvLength = 1.0f/fLength;
130 FT fQ = 2.0f*fM01*fM12+fM02*(fM22-fM11);
131 diag_[1] = fM11+fM02*fQ;
132 diag_[2] = fM22-fM02*fQ;
134 subd_[1] = fM12-fM01*fQ;
135 matrix_[0][0] = 1.0f; matrix_[0][1] = 0.0f; matrix_[0][2] = 0.0f;
136 matrix_[1][0] = 0.0f; matrix_[1][1] = fM01; matrix_[1][2] = fM02;
137 matrix_[2][0] = 0.0f; matrix_[2][1] = fM02; matrix_[2][2] = -fM01;
145 matrix_[0][0] = 1.0f; matrix_[0][1] = 0.0f; matrix_[0][2] = 0.0f;
146 matrix_[1][0] = 0.0f; matrix_[1][1] = 1.0f; matrix_[1][2] = 0.0f;
147 matrix_[2][0] = 0.0f; matrix_[2][1] = 0.0f; matrix_[2][2] = 1.0f;
152 template <
typename FT>
153 inline void EigenSolver<FT>::tridiagonal_4(FT** matrix_, FT* diag_, FT* subd_)
156 FT fM00 = matrix_[0][0];
157 FT fM01 = matrix_[0][1];
158 FT fM02 = matrix_[0][2];
159 FT fM03 = matrix_[0][3];
160 FT fM11 = matrix_[1][1];
161 FT fM12 = matrix_[1][2];
162 FT fM13 = matrix_[1][3];
163 FT fM22 = matrix_[2][2];
164 FT fM23 = matrix_[2][3];
165 FT fM33 = matrix_[3][3];
170 matrix_[0][0] = 1.0f;
171 matrix_[0][1] = 0.0f;
172 matrix_[0][2] = 0.0f;
173 matrix_[0][3] = 0.0f;
174 matrix_[1][0] = 0.0f;
175 matrix_[2][0] = 0.0f;
176 matrix_[3][0] = 0.0f;
178 FT fLength, fInvLength;
180 if( fM02 != 0.0f || fM03 != 0.0f )
187 fLength = std::sqrt(fM01*fM01+fM02*fM02+fM03*fM03);
188 fInvLength = 1.0f/fLength;
189 fQ11 = fM01*fInvLength;
190 fQ21 = fM02*fInvLength;
191 fQ31 = fM03*fInvLength;
196 FT fV0 = fM11*fQ11+fM12*fQ21+fM13*fQ31;
197 FT fV1 = fM12*fQ11+fM22*fQ21+fM23*fQ31;
198 FT fV2 = fM13*fQ11+fM23*fQ21+fM33*fQ31;
200 diag_[1] = fQ11*fV0+fQ21*fV1+fQ31*fV2;
203 fQ13 = fQ21*fV2-fQ31*fV1;
204 fQ23 = fQ31*fV0-fQ11*fV2;
205 fQ33 = fQ11*fV1-fQ21*fV0;
206 fLength = std::sqrt(fQ13*fQ13+fQ23*fQ23+fQ33*fQ33);
209 fInvLength = 1.0f/fLength;
215 fQ12 = fQ23*fQ31-fQ33*fQ21;
216 fQ22 = fQ33*fQ11-fQ13*fQ31;
217 fQ32 = fQ13*fQ21-fQ23*fQ11;
219 fV0 = fQ12*fM11+fQ22*fM12+fQ32*fM13;
220 fV1 = fQ12*fM12+fQ22*fM22+fQ32*fM23;
221 fV2 = fQ12*fM13+fQ22*fM23+fQ32*fM33;
222 subd_[1] = fQ11*fV0+fQ21*fV1+fQ31*fV2;
223 diag_[2] = fQ12*fV0+fQ22*fV1+fQ32*fV2;
224 subd_[2] = fQ13*fV0+fQ23*fV1+fQ33*fV2;
226 fV0 = fQ13*fM11+fQ23*fM12+fQ33*fM13;
227 fV1 = fQ13*fM12+fQ23*fM22+fQ33*fM23;
228 fV2 = fQ13*fM13+fQ23*fM23+fQ33*fM33;
229 diag_[3] = fQ13*fV0+fQ23*fV1+fQ33*fV2;
236 fLength = fQ21*fQ21+fQ31*fQ31;
239 fInvLength = 1.0f/fLength;
242 fQ22 = 1.0f+fTmp*fQ21*fQ21*fInvLength;
243 fQ32 = fTmp*fQ21*fQ31*fInvLength;
247 fQ33 = 1.0f+fTmp*fQ31*fQ31*fInvLength;
249 fV0 = fQ12*fM11+fQ22*fM12+fQ32*fM13;
250 fV1 = fQ12*fM12+fQ22*fM22+fQ32*fM23;
251 fV2 = fQ12*fM13+fQ22*fM23+fQ32*fM33;
252 diag_[2] = fQ12*fV0+fQ22*fV1+fQ32*fV2;
253 subd_[2] = fQ13*fV0+fQ23*fV1+fQ33*fV2;
255 fV0 = fQ13*fM11+fQ23*fM12+fQ33*fM13;
256 fV1 = fQ13*fM12+fQ23*fM22+fQ33*fM23;
257 fV2 = fQ13*fM13+fQ23*fM23+fQ33*fM33;
258 diag_[3] = fQ13*fV0+fQ23*fV1+fQ33*fV2;
263 fQ12 = 0.0f; fQ22 = 1.0f; fQ32 = 0.0f;
264 fQ13 = 0.0f; fQ23 = 0.0f; fQ33 = 1.0f;
272 matrix_[1][1] = fQ11; matrix_[1][2] = fQ12; matrix_[1][3] = fQ13;
273 matrix_[2][1] = fQ21; matrix_[2][2] = fQ22; matrix_[2][3] = fQ23;
274 matrix_[3][1] = fQ31; matrix_[3][2] = fQ32; matrix_[3][3] = fQ33;
280 matrix_[1][1] = 1.0f;
281 matrix_[2][1] = 0.0f;
282 matrix_[3][1] = 0.0f;
286 fLength = std::sqrt(fM12*fM12+fM13*fM13);
287 fInvLength = 1.0f/fLength;
290 FT fQ = 2.0f*fM12*fM23+fM13*(fM33-fM22);
292 diag_[2] = fM22+fM13*fQ;
293 diag_[3] = fM33-fM13*fQ;
295 subd_[2] = fM23-fM12*fQ;
296 matrix_[1][2] = 0.0f;
297 matrix_[1][3] = 0.0f;
298 matrix_[2][2] = fM12;
299 matrix_[2][3] = fM13;
300 matrix_[3][2] = fM13;
301 matrix_[3][3] = -fM12;
309 matrix_[1][2] = 0.0f;
310 matrix_[1][3] = 0.0f;
311 matrix_[2][2] = 1.0f;
312 matrix_[2][3] = 0.0f;
313 matrix_[3][2] = 0.0f;
314 matrix_[3][3] = 1.0f;
320 template <
typename FT>
321 inline void EigenSolver<FT>::tridiagonal_n(
int n, FT** matrix_, FT* diag_, FT* subd_)
325 for(i0 = n-1, i3 = n-2; i0 >= 1; i0--, i3--)
327 FT fH = 0.0f, fScale = 0.0f;
331 for(i2 = 0; i2 <= i3; i2++)
332 fScale += std::abs(matrix_[i0][i2]);
335 subd_[i0] = matrix_[i0][i3];
339 FT fInvScale = 1.0f/fScale;
340 for(i2 = 0; i2 <= i3; i2++)
342 matrix_[i0][i2] *= fInvScale;
343 fH += matrix_[i0][i2]*matrix_[i0][i2];
345 FT fF = matrix_[i0][i3];
346 FT fG = std::sqrt(fH);
349 subd_[i0] = fScale*fG;
351 matrix_[i0][i3] = fF-fG;
354 for(i1 = 0; i1 <= i3; i1++)
356 matrix_[i1][i0] = matrix_[i0][i1]*fInvH;
358 for(i2 = 0; i2 <= i1; i2++)
359 fG += matrix_[i1][i2]*matrix_[i0][i2];
360 for(i2 = i1+1; i2 <= i3; i2++)
361 fG += matrix_[i2][i1]*matrix_[i0][i2];
362 subd_[i1] = fG*fInvH;
363 fF += subd_[i1]*matrix_[i0][i1];
365 FT fHalfFdivH = 0.5f*fF*fInvH;
366 for(i1 = 0; i1 <= i3; i1++)
368 fF = matrix_[i0][i1];
369 fG = subd_[i1] - fHalfFdivH*fF;
371 for(i2 = 0; i2 <= i1; i2++)
373 matrix_[i1][i2] -= fF*subd_[i2] +
381 subd_[i0] = matrix_[i0][i3];
389 for(i0 = 0, i3 = -1; i0 <= n-1; i0++, i3++)
393 for(i1 = 0; i1 <= i3; i1++)
396 for(i2 = 0; i2 <= i3; i2++)
397 fSum += matrix_[i0][i2]*matrix_[i2][i1];
398 for(i2 = 0; i2 <= i3; i2++)
399 matrix_[i2][i1] -= fSum*matrix_[i2][i0];
402 diag_[i0] = matrix_[i0][i0];
403 matrix_[i0][i0] = 1.0f;
404 for(i1 = 0; i1 <= i3; i1++)
406 matrix_[i1][i0] = 0.0f;
407 matrix_[i0][i1] = 0.0f;
412 for(i0 = 1, i3 = 0; i0 < n; i0++, i3++)
413 subd_[i3] = subd_[i0];
418 template <
typename FT>
419 inline bool EigenSolver<FT>::ql_algorithm(
int n, FT* diag_, FT* subd_, FT** matrix_)
421 const int iMaxIter = 32;
423 for(
int i0 = 0; i0 < n; i0++)
426 for(i1 = 0; i1 < iMaxIter; i1++)
429 for(i2 = i0; i2 <= n-2; i2++)
431 FT fTmp = std::abs(diag_[i2]) +
432 std::abs(diag_[i2+1]);
433 if( std::abs(subd_[i2]) + fTmp == fTmp )
439 FT fG =(diag_[i0+1]-diag_[i0])/(2.0f*subd_[i0]);
440 FT fR = std::sqrt(fG*fG+1.0f);
442 fG = diag_[i2]-diag_[i0]+subd_[i0]/(fG-fR);
444 fG = diag_[i2]-diag_[i0]+subd_[i0]/(fG+fR);
445 FT fSin = 1.0f, fCos = 1.0, fP = 0.0f;
446 for(
int i3 = i2-1; i3 >= i0; i3--)
448 FT fF = fSin*subd_[i3];
449 FT fB = fCos*subd_[i3];
450 if( std::abs(fF) >= std::abs(fG) )
453 fR = std::sqrt(fCos*fCos+1.0f);
461 fR = std::sqrt(fSin*fSin+1.0f);
467 fR =(diag_[i3]-fG)*fSin+2.0f*fB*fCos;
472 for(
int i4 = 0; i4 < n; i4++)
474 fF = matrix_[i4][i3+1];
475 matrix_[i4][i3+1] = fSin*matrix_[i4][i3]+fCos*fF;
476 matrix_[i4][i3] = fCos*matrix_[i4][i3]-fSin*fF;
491 template <
typename FT>
492 inline void EigenSolver<FT>::decreasing_sort(
int n, FT* eigval, FT** eigvec)
495 for(
int i0 = 0, i1; i0 <= n-2; i0++)
499 FT fMax = eigval[i1];
501 for(i2 = i0+1; i2 < n; i2++)
503 if( eigval[i2] > fMax )
513 eigval[i1] = eigval[i0];
517 for(i2 = 0; i2 < n; i2++)
519 FT fTmp = eigvec[i2][i0];
520 eigvec[i2][i0] = eigvec[i2][i1];
521 eigvec[i2][i1] = fTmp;
528 template <
typename FT>
529 inline void EigenSolver<FT>::increasing_sort(
int n, FT* eigval, FT** eigvec)
532 for(
int i0 = 0, i1; i0 <= n-2; i0++)
536 FT fMin = eigval[i1];
538 for(i2 = i0+1; i2 < n; i2++)
540 if( eigval[i2] < fMin )
550 eigval[i1] = eigval[i0];
554 for(i2 = 0; i2 < n; i2++)
556 FT fTmp = eigvec[i2][i0];
557 eigvec[i2][i0] = eigvec[i2][i1];
558 eigvec[i2][i1] = fTmp;
565 template <
typename FT>
573 tridiagonal_2(matrix_,diag_,subd_);
576 tridiagonal_3(matrix_,diag_,subd_);
579 tridiagonal_4(matrix_,diag_,subd_);
582 tridiagonal_n(size_,matrix_,diag_,subd_);
586 ql_algorithm(size_,diag_,subd_,matrix_);
591 increasing_sort(size_,diag_,matrix_);
594 decreasing_sort(size_,diag_,matrix_);
An easy-to-use eigen solver.
Definition: eigen_solver.h:25
FT eigen_value(int i) const
Returns the i_th eigenvalue.
Definition: eigen_solver.h:41
FT * eigen_values()
Returns the eigenvalues.
Definition: eigen_solver.h:46
void solve(FT **mat, SortingMethod sm=NO_SORTING)
Computes the eigenvalues and eigenvectors of the input matrix mat.
Definition: eigen_solver.h:566
FT eigen_vector(int comp, int i) const
Returns the comp_th component of the i_th eigenvector.
Definition: eigen_solver.h:43
FT ** eigen_vectors()
Returns the eigenvectors (stored as the columns of the returned matrix).
Definition: eigen_solver.h:48
SortingMethod
The sorting method for the eigenvalues and their corresponding eigen vectors.
Definition: eigen_solver.h:28
EigenSolver(int n)
Default constructor.
Definition: eigen_solver.h:78
Definition: collider.cpp:182