Wm4Eigen.cpp
Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017 #include "Wm4FoundationPCH.h"
00018 #include "Wm4Eigen.h"
00019
00020 namespace Wm4
00021 {
00022
00023 template <class Real>
00024 Eigen<Real>::Eigen (int iSize)
00025 :
00026 m_kMat(iSize,iSize)
00027 {
00028 assert(iSize >= 2);
00029 m_iSize = iSize;
00030 m_afDiag = WM4_NEW Real[m_iSize];
00031 m_afSubd = WM4_NEW Real[m_iSize];
00032 m_bIsRotation = false;
00033 }
00034
00035 template <class Real>
00036 Eigen<Real>::Eigen (const Matrix2<Real>& rkM)
00037 :
00038 m_kMat(2,2,(const Real*)rkM)
00039 {
00040 m_iSize = 2;
00041 m_afDiag = WM4_NEW Real[m_iSize];
00042 m_afSubd = WM4_NEW Real[m_iSize];
00043 m_bIsRotation = false;
00044 }
00045
00046 template <class Real>
00047 Eigen<Real>::Eigen (const Matrix3<Real>& rkM)
00048 :
00049 m_kMat(3,3,(const Real*)rkM)
00050 {
00051 m_iSize = 3;
00052 m_afDiag = WM4_NEW Real[m_iSize];
00053 m_afSubd = WM4_NEW Real[m_iSize];
00054 m_bIsRotation = false;
00055 }
00056
00057 template <class Real>
00058 Eigen<Real>::Eigen (const GMatrix<Real>& rkM)
00059 :
00060 m_kMat(rkM)
00061 {
00062 m_iSize = rkM.GetRows();
00063 assert(m_iSize >= 2 && (rkM.GetColumns() == m_iSize));
00064 m_afDiag = WM4_NEW Real[m_iSize];
00065 m_afSubd = WM4_NEW Real[m_iSize];
00066 m_bIsRotation = false;
00067 }
00068
00069 template <class Real>
00070 Eigen<Real>::~Eigen ()
00071 {
00072 WM4_DELETE[] m_afSubd;
00073 WM4_DELETE[] m_afDiag;
00074 }
00075
00076 template <class Real>
00077 Real& Eigen<Real>::operator() (int iRow, int iCol)
00078 {
00079 return m_kMat[iRow][iCol];
00080 }
00081
00082 template <class Real>
00083 Eigen<Real>& Eigen<Real>::operator= (const Matrix2<Real>& rkM)
00084 {
00085 m_kMat.SetMatrix(2,2,(const Real*)rkM);
00086 m_iSize = 2;
00087 WM4_DELETE[] m_afDiag;
00088 WM4_DELETE[] m_afSubd;
00089 m_afDiag = WM4_NEW Real[m_iSize];
00090 m_afSubd = WM4_NEW Real[m_iSize];
00091 return *this;
00092 }
00093
00094 template <class Real>
00095 Eigen<Real>& Eigen<Real>::operator= (const Matrix3<Real>& rkM)
00096 {
00097 m_kMat.SetMatrix(3,3,(const Real*)rkM);
00098 m_iSize = 3;
00099 WM4_DELETE[] m_afDiag;
00100 WM4_DELETE[] m_afSubd;
00101 m_afDiag = WM4_NEW Real[m_iSize];
00102 m_afSubd = WM4_NEW Real[m_iSize];
00103 return *this;
00104 }
00105
00106 template <class Real>
00107 Eigen<Real>& Eigen<Real>::operator= (const GMatrix<Real>& rkM)
00108 {
00109 m_kMat = rkM;
00110 return *this;
00111 }
00112
00113 template <class Real>
00114 Real Eigen<Real>::GetEigenvalue (int i) const
00115 {
00116 return m_afDiag[i];
00117 }
00118
00119 template <class Real>
00120 const Real* Eigen<Real>::GetEigenvalues () const
00121 {
00122 return m_afDiag;
00123 }
00124
00125 template <class Real>
00126 void Eigen<Real>::GetEigenvector (int i, Vector2<Real>& rkV) const
00127 {
00128 assert(m_iSize == 2);
00129 if (m_iSize == 2)
00130 {
00131 for (int iRow = 0; iRow < m_iSize; iRow++)
00132 {
00133 rkV[iRow] = m_kMat[iRow][i];
00134 }
00135 }
00136 else
00137 {
00138 rkV = Vector2<Real>::ZERO;
00139 }
00140 }
00141
00142 template <class Real>
00143 void Eigen<Real>::GetEigenvector (int i, Vector3<Real>& rkV) const
00144 {
00145 assert(m_iSize == 3);
00146 if (m_iSize == 3)
00147 {
00148 for (int iRow = 0; iRow < m_iSize; iRow++)
00149 {
00150 rkV[iRow] = m_kMat[iRow][i];
00151 }
00152 }
00153 else
00154 {
00155 rkV = Vector3<Real>::ZERO;
00156 }
00157 }
00158
00159 template <class Real>
00160 GVector<Real> Eigen<Real>::GetEigenvector (int i) const
00161 {
00162 return m_kMat.GetColumn(i);
00163 }
00164
00165 template <class Real>
00166 const GMatrix<Real>& Eigen<Real>::GetEigenvectors () const
00167 {
00168 return m_kMat;
00169 }
00170
00171 template <class Real>
00172 void Eigen<Real>::Tridiagonal2 ()
00173 {
00174
00175 m_afDiag[0] = m_kMat[0][0];
00176 m_afDiag[1] = m_kMat[1][1];
00177 m_afSubd[0] = m_kMat[0][1];
00178 m_afSubd[1] = (Real)0.0;
00179 m_kMat[0][0] = (Real)1.0;
00180 m_kMat[0][1] = (Real)0.0;
00181 m_kMat[1][0] = (Real)0.0;
00182 m_kMat[1][1] = (Real)1.0;
00183
00184 m_bIsRotation = true;
00185 }
00186
00187 template <class Real>
00188 void Eigen<Real>::Tridiagonal3 ()
00189 {
00190 Real fM00 = m_kMat[0][0];
00191 Real fM01 = m_kMat[0][1];
00192 Real fM02 = m_kMat[0][2];
00193 Real fM11 = m_kMat[1][1];
00194 Real fM12 = m_kMat[1][2];
00195 Real fM22 = m_kMat[2][2];
00196
00197 m_afDiag[0] = fM00;
00198 m_afSubd[2] = (Real)0.0;
00199 if (Math<Real>::FAbs(fM02) > Math<Real>::ZERO_TOLERANCE)
00200 {
00201 Real fLength = Math<Real>::Sqrt(fM01*fM01+fM02*fM02);
00202 Real fInvLength = ((Real)1.0)/fLength;
00203 fM01 *= fInvLength;
00204 fM02 *= fInvLength;
00205 Real fQ = ((Real)2.0)*fM01*fM12+fM02*(fM22-fM11);
00206 m_afDiag[1] = fM11+fM02*fQ;
00207 m_afDiag[2] = fM22-fM02*fQ;
00208 m_afSubd[0] = fLength;
00209 m_afSubd[1] = fM12-fM01*fQ;
00210 m_kMat[0][0] = (Real)1.0;
00211 m_kMat[0][1] = (Real)0.0;
00212 m_kMat[0][2] = (Real)0.0;
00213 m_kMat[1][0] = (Real)0.0;
00214 m_kMat[1][1] = fM01;
00215 m_kMat[1][2] = fM02;
00216 m_kMat[2][0] = (Real)0.0;
00217 m_kMat[2][1] = fM02;
00218 m_kMat[2][2] = -fM01;
00219 m_bIsRotation = false;
00220 }
00221 else
00222 {
00223 m_afDiag[1] = fM11;
00224 m_afDiag[2] = fM22;
00225 m_afSubd[0] = fM01;
00226 m_afSubd[1] = fM12;
00227 m_kMat[0][0] = (Real)1.0;
00228 m_kMat[0][1] = (Real)0.0;
00229 m_kMat[0][2] = (Real)0.0;
00230 m_kMat[1][0] = (Real)0.0;
00231 m_kMat[1][1] = (Real)1.0;
00232 m_kMat[1][2] = (Real)0.0;
00233 m_kMat[2][0] = (Real)0.0;
00234 m_kMat[2][1] = (Real)0.0;
00235 m_kMat[2][2] = (Real)1.0;
00236 m_bIsRotation = true;
00237 }
00238 }
00239
00240 template <class Real>
00241 void Eigen<Real>::TridiagonalN ()
00242 {
00243 int i0, i1, i2, i3;
00244
00245 for (i0 = m_iSize-1, i3 = m_iSize-2; i0 >= 1; i0--, i3--)
00246 {
00247 Real fH = (Real)0.0, fScale = (Real)0.0;
00248
00249 if (i3 > 0)
00250 {
00251 for (i2 = 0; i2 <= i3; i2++)
00252 {
00253 fScale += Math<Real>::FAbs(m_kMat[i0][i2]);
00254 }
00255 if (fScale == (Real)0.0)
00256 {
00257 m_afSubd[i0] = m_kMat[i0][i3];
00258 }
00259 else
00260 {
00261 Real fInvScale = ((Real)1.0)/fScale;
00262 for (i2 = 0; i2 <= i3; i2++)
00263 {
00264 m_kMat[i0][i2] *= fInvScale;
00265 fH += m_kMat[i0][i2]*m_kMat[i0][i2];
00266 }
00267 Real fF = m_kMat[i0][i3];
00268 Real fG = Math<Real>::Sqrt(fH);
00269 if (fF > (Real)0.0)
00270 {
00271 fG = -fG;
00272 }
00273 m_afSubd[i0] = fScale*fG;
00274 fH -= fF*fG;
00275 m_kMat[i0][i3] = fF-fG;
00276 fF = (Real)0.0;
00277 Real fInvH = ((Real)1.0)/fH;
00278 for (i1 = 0; i1 <= i3; i1++)
00279 {
00280 m_kMat[i1][i0] = m_kMat[i0][i1]*fInvH;
00281 fG = (Real)0.0;
00282 for (i2 = 0; i2 <= i1; i2++)
00283 {
00284 fG += m_kMat[i1][i2]*m_kMat[i0][i2];
00285 }
00286 for (i2 = i1+1; i2 <= i3; i2++)
00287 {
00288 fG += m_kMat[i2][i1]*m_kMat[i0][i2];
00289 }
00290 m_afSubd[i1] = fG*fInvH;
00291 fF += m_afSubd[i1]*m_kMat[i0][i1];
00292 }
00293 Real fHalfFdivH = ((Real)0.5)*fF*fInvH;
00294 for (i1 = 0; i1 <= i3; i1++)
00295 {
00296 fF = m_kMat[i0][i1];
00297 fG = m_afSubd[i1] - fHalfFdivH*fF;
00298 m_afSubd[i1] = fG;
00299 for (i2 = 0; i2 <= i1; i2++)
00300 {
00301 m_kMat[i1][i2] -= fF*m_afSubd[i2] +
00302 fG*m_kMat[i0][i2];
00303 }
00304 }
00305 }
00306 }
00307 else
00308 {
00309 m_afSubd[i0] = m_kMat[i0][i3];
00310 }
00311
00312 m_afDiag[i0] = fH;
00313 }
00314
00315 m_afDiag[0] = (Real)0.0;
00316 m_afSubd[0] = (Real)0.0;
00317 for (i0 = 0, i3 = -1; i0 <= m_iSize-1; i0++, i3++)
00318 {
00319 if (m_afDiag[i0] != (Real)0.0)
00320 {
00321 for (i1 = 0; i1 <= i3; i1++)
00322 {
00323 Real fSum = (Real)0.0;
00324 for (i2 = 0; i2 <= i3; i2++)
00325 {
00326 fSum += m_kMat[i0][i2]*m_kMat[i2][i1];
00327 }
00328 for (i2 = 0; i2 <= i3; i2++)
00329 {
00330 m_kMat[i2][i1] -= fSum*m_kMat[i2][i0];
00331 }
00332 }
00333 }
00334 m_afDiag[i0] = m_kMat[i0][i0];
00335 m_kMat[i0][i0] = (Real)1.0;
00336 for (i1 = 0; i1 <= i3; i1++)
00337 {
00338 m_kMat[i1][i0] = (Real)0.0;
00339 m_kMat[i0][i1] = (Real)0.0;
00340 }
00341 }
00342
00343
00344 for (i0 = 1, i3 = 0; i0 < m_iSize; i0++, i3++)
00345 {
00346 m_afSubd[i3] = m_afSubd[i0];
00347 }
00348 m_afSubd[m_iSize-1] = (Real)0.0;
00349
00350 m_bIsRotation = ((m_iSize % 2) == 0);
00351 }
00352
00353 template <class Real>
00354 bool Eigen<Real>::QLAlgorithm ()
00355 {
00356 const int iMaxIter = 32;
00357
00358 for (int i0 = 0; i0 < m_iSize; i0++)
00359 {
00360 int i1;
00361 for (i1 = 0; i1 < iMaxIter; i1++)
00362 {
00363 int i2;
00364 for (i2 = i0; i2 <= m_iSize-2; i2++)
00365 {
00366 Real fTmp = Math<Real>::FAbs(m_afDiag[i2]) +
00367 Math<Real>::FAbs(m_afDiag[i2+1]);
00368
00369 if (Math<Real>::FAbs(m_afSubd[i2]) + fTmp == fTmp)
00370 {
00371 break;
00372 }
00373 }
00374 if (i2 == i0)
00375 {
00376 break;
00377 }
00378
00379 Real fG = (m_afDiag[i0+1] - m_afDiag[i0])/(((Real)2.0) *
00380 m_afSubd[i0]);
00381 Real fR = Math<Real>::Sqrt(fG*fG+(Real)1.0);
00382 if ( fG < (Real)0.0 )
00383 {
00384 fG = m_afDiag[i2]-m_afDiag[i0]+m_afSubd[i0]/(fG-fR);
00385 }
00386 else
00387 {
00388 fG = m_afDiag[i2]-m_afDiag[i0]+m_afSubd[i0]/(fG+fR);
00389 }
00390 Real fSin = (Real)1.0, fCos = (Real)1.0, fP = (Real)0.0;
00391 for (int i3 = i2-1; i3 >= i0; i3--)
00392 {
00393 Real fF = fSin*m_afSubd[i3];
00394 Real fB = fCos*m_afSubd[i3];
00395 if (Math<Real>::FAbs(fF) >= Math<Real>::FAbs(fG))
00396 {
00397 fCos = fG/fF;
00398 fR = Math<Real>::Sqrt(fCos*fCos+(Real)1.0);
00399 m_afSubd[i3+1] = fF*fR;
00400 fSin = ((Real)1.0)/fR;
00401 fCos *= fSin;
00402 }
00403 else
00404 {
00405 fSin = fF/fG;
00406 fR = Math<Real>::Sqrt(fSin*fSin+(Real)1.0);
00407 m_afSubd[i3+1] = fG*fR;
00408 fCos = ((Real)1.0)/fR;
00409 fSin *= fCos;
00410 }
00411 fG = m_afDiag[i3+1]-fP;
00412 fR = (m_afDiag[i3]-fG)*fSin+((Real)2.0)*fB*fCos;
00413 fP = fSin*fR;
00414 m_afDiag[i3+1] = fG+fP;
00415 fG = fCos*fR-fB;
00416
00417 for (int i4 = 0; i4 < m_iSize; i4++)
00418 {
00419 fF = m_kMat[i4][i3+1];
00420 m_kMat[i4][i3+1] = fSin*m_kMat[i4][i3]+fCos*fF;
00421 m_kMat[i4][i3] = fCos*m_kMat[i4][i3]-fSin*fF;
00422 }
00423 }
00424 m_afDiag[i0] -= fP;
00425 m_afSubd[i0] = fG;
00426 m_afSubd[i2] = (Real)0.0;
00427 }
00428 if (i1 == iMaxIter)
00429 {
00430 return false;
00431 }
00432 }
00433
00434 return true;
00435 }
00436
00437 template <class Real>
00438 void Eigen<Real>::DecreasingSort ()
00439 {
00440
00441 for (int i0 = 0, i1; i0 <= m_iSize-2; i0++)
00442 {
00443
00444 i1 = i0;
00445 Real fMax = m_afDiag[i1];
00446 int i2;
00447 for (i2 = i0+1; i2 < m_iSize; i2++)
00448 {
00449 if (m_afDiag[i2] > fMax)
00450 {
00451 i1 = i2;
00452 fMax = m_afDiag[i1];
00453 }
00454 }
00455
00456 if (i1 != i0)
00457 {
00458
00459 m_afDiag[i1] = m_afDiag[i0];
00460 m_afDiag[i0] = fMax;
00461
00462
00463 for (i2 = 0; i2 < m_iSize; i2++)
00464 {
00465 Real fTmp = m_kMat[i2][i0];
00466 m_kMat[i2][i0] = m_kMat[i2][i1];
00467 m_kMat[i2][i1] = fTmp;
00468 m_bIsRotation = !m_bIsRotation;
00469 }
00470 }
00471 }
00472 }
00473
00474 template <class Real>
00475 void Eigen<Real>::IncreasingSort ()
00476 {
00477
00478 for (int i0 = 0, i1; i0 <= m_iSize-2; i0++)
00479 {
00480
00481 i1 = i0;
00482 Real fMin = m_afDiag[i1];
00483 int i2;
00484 for (i2 = i0+1; i2 < m_iSize; i2++)
00485 {
00486 if (m_afDiag[i2] < fMin)
00487 {
00488 i1 = i2;
00489 fMin = m_afDiag[i1];
00490 }
00491 }
00492
00493 if (i1 != i0)
00494 {
00495
00496 m_afDiag[i1] = m_afDiag[i0];
00497 m_afDiag[i0] = fMin;
00498
00499
00500 for (i2 = 0; i2 < m_iSize; i2++)
00501 {
00502 Real fTmp = m_kMat[i2][i0];
00503 m_kMat[i2][i0] = m_kMat[i2][i1];
00504 m_kMat[i2][i1] = fTmp;
00505 m_bIsRotation = !m_bIsRotation;
00506 }
00507 }
00508 }
00509 }
00510
00511 template <class Real>
00512 void Eigen<Real>::GuaranteeRotation ()
00513 {
00514 if (!m_bIsRotation)
00515 {
00516
00517 for (int iRow = 0; iRow < m_iSize; iRow++)
00518 {
00519 m_kMat[iRow][0] = -m_kMat[iRow][0];
00520 }
00521 }
00522 }
00523
00524 template <class Real>
00525 void Eigen<Real>::EigenStuff2 ()
00526 {
00527 Tridiagonal2();
00528 QLAlgorithm();
00529 GuaranteeRotation();
00530 }
00531
00532 template <class Real>
00533 void Eigen<Real>::EigenStuff3 ()
00534 {
00535 Tridiagonal3();
00536 QLAlgorithm();
00537 GuaranteeRotation();
00538 }
00539
00540 template <class Real>
00541 void Eigen<Real>::EigenStuffN ()
00542 {
00543 TridiagonalN();
00544 QLAlgorithm();
00545 GuaranteeRotation();
00546 }
00547
00548 template <class Real>
00549 void Eigen<Real>::EigenStuff ()
00550 {
00551 switch (m_iSize)
00552 {
00553 case 2: Tridiagonal2(); break;
00554 case 3: Tridiagonal3(); break;
00555 default: TridiagonalN(); break;
00556 }
00557 QLAlgorithm();
00558 GuaranteeRotation();
00559 }
00560
00561 template <class Real>
00562 void Eigen<Real>::DecrSortEigenStuff2 ()
00563 {
00564 Tridiagonal2();
00565 QLAlgorithm();
00566 DecreasingSort();
00567 GuaranteeRotation();
00568 }
00569
00570 template <class Real>
00571 void Eigen<Real>::DecrSortEigenStuff3 ()
00572 {
00573 Tridiagonal3();
00574 QLAlgorithm();
00575 DecreasingSort();
00576 GuaranteeRotation();
00577 }
00578
00579 template <class Real>
00580 void Eigen<Real>::DecrSortEigenStuffN ()
00581 {
00582 TridiagonalN();
00583 QLAlgorithm();
00584 DecreasingSort();
00585 GuaranteeRotation();
00586 }
00587
00588 template <class Real>
00589 void Eigen<Real>::DecrSortEigenStuff ()
00590 {
00591 switch (m_iSize)
00592 {
00593 case 2: Tridiagonal2(); break;
00594 case 3: Tridiagonal3(); break;
00595 default: TridiagonalN(); break;
00596 }
00597 QLAlgorithm();
00598 DecreasingSort();
00599 GuaranteeRotation();
00600 }
00601
00602 template <class Real>
00603 void Eigen<Real>::IncrSortEigenStuff2 ()
00604 {
00605 Tridiagonal2();
00606 QLAlgorithm();
00607 IncreasingSort();
00608 GuaranteeRotation();
00609 }
00610
00611 template <class Real>
00612 void Eigen<Real>::IncrSortEigenStuff3 ()
00613 {
00614 Tridiagonal3();
00615 QLAlgorithm();
00616 IncreasingSort();
00617 GuaranteeRotation();
00618 }
00619
00620 template <class Real>
00621 void Eigen<Real>::IncrSortEigenStuffN ()
00622 {
00623 TridiagonalN();
00624 QLAlgorithm();
00625 IncreasingSort();
00626 GuaranteeRotation();
00627 }
00628
00629 template <class Real>
00630 void Eigen<Real>::IncrSortEigenStuff ()
00631 {
00632 switch (m_iSize)
00633 {
00634 case 2: Tridiagonal2(); break;
00635 case 3: Tridiagonal3(); break;
00636 default: TridiagonalN(); break;
00637 }
00638 QLAlgorithm();
00639 IncreasingSort();
00640 GuaranteeRotation();
00641 }
00642
00643
00644
00645
00646
00647 template WM4_FOUNDATION_ITEM
00648 class Eigen<float>;
00649
00650 template WM4_FOUNDATION_ITEM
00651 class Eigen<double>;
00652
00653 }