TMatrixDEigen.cxx

Go to the documentation of this file.
00001 // @(#)root/matrix:$Id: TMatrixDEigen.cxx 23492 2008-04-23 20:42:49Z brun $
00002 // Authors: Fons Rademakers, Eddy Offermann  Dec 2003
00003 
00004 /*************************************************************************
00005  * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
00006  * All rights reserved.                                                  *
00007  *                                                                       *
00008  * For the licensing terms see $ROOTSYS/LICENSE.                         *
00009  * For the list of contributors see $ROOTSYS/README/CREDITS.             *
00010  *************************************************************************/
00011 
00012 //////////////////////////////////////////////////////////////////////////
00013 //                                                                      //
00014 // TMatrixDEigen                                                        //
00015 //                                                                      //
00016 // Eigenvalues and eigenvectors of a real matrix.                       //
00017 //                                                                      //
00018 // If A is not symmetric, then the eigenvalue matrix D is block         //
00019 // diagonal with the real eigenvalues in 1-by-1 blocks and any complex  //
00020 // eigenvalues, a + i*b, in 2-by-2 blocks, [a, b; -b, a].  That is, if  //
00021 // the complex eigenvalues look like                                    //
00022 //                                                                      //
00023 //     u + iv     .        .          .      .    .                     //
00024 //       .      u - iv     .          .      .    .                     //
00025 //       .        .      a + ib       .      .    .                     //
00026 //       .        .        .        a - ib   .    .                     //
00027 //       .        .        .          .      x    .                     //
00028 //       .        .        .          .      .    y                     //
00029 //                                                                      //
00030 // then D looks like                                                    //
00031 //                                                                      //
00032 //       u        v        .          .      .    .                     //
00033 //      -v        u        .          .      .    .                     //
00034 //       .        .        a          b      .    .                     //
00035 //       .        .       -b          a      .    .                     //
00036 //       .        .        .          .      x    .                     //
00037 //       .        .        .          .      .    y                     //
00038 //                                                                      //
00039 // This keeps V a real matrix in both symmetric and non-symmetric       //
00040 // cases, and A*V = V*D.                                                //
00041 //                                                                      //
00042 //////////////////////////////////////////////////////////////////////////
00043 
00044 #include "TMatrixDEigen.h"
00045 #include "TMath.h"
00046 
00047 ClassImp(TMatrixDEigen)
00048 
00049 //______________________________________________________________________________
00050 TMatrixDEigen::TMatrixDEigen(const TMatrixD &a)
00051 {
00052 // Constructor for eigen-problem of matrix A .
00053 
00054    R__ASSERT(a.IsValid());
00055  
00056    const Int_t nRows  = a.GetNrows();
00057    const Int_t nCols  = a.GetNcols();
00058    const Int_t rowLwb = a.GetRowLwb();
00059    const Int_t colLwb = a.GetColLwb();
00060 
00061    if (nRows != nCols || rowLwb != colLwb)
00062    {
00063       Error("TMatrixDEigen(TMatrixD &)","matrix should be square");
00064       return;
00065    }
00066 
00067    const Int_t rowUpb = rowLwb+nRows-1;
00068    fEigenVectors.ResizeTo(rowLwb,rowUpb,rowLwb,rowUpb);
00069    fEigenValuesRe.ResizeTo(rowLwb,rowUpb);
00070    fEigenValuesIm.ResizeTo(rowLwb,rowUpb);
00071 
00072    TVectorD ortho;
00073    Double_t work[kWorkMax];
00074    if (nRows > kWorkMax) ortho.ResizeTo(nRows);
00075    else                  ortho.Use(nRows,work);
00076 
00077    TMatrixD mH = a;
00078 
00079    // Reduce to Hessenberg form.
00080    MakeHessenBerg(fEigenVectors,ortho,mH);
00081 
00082    // Reduce Hessenberg to real Schur form.
00083    MakeSchurr(fEigenVectors,fEigenValuesRe,fEigenValuesIm,mH);
00084 
00085    // Sort eigenvalues and corresponding vectors in descending order of Re^2+Im^2
00086    // of the complex eigenvalues .
00087    Sort(fEigenVectors,fEigenValuesRe,fEigenValuesIm);
00088 }
00089 
00090 //______________________________________________________________________________
00091 TMatrixDEigen::TMatrixDEigen(const TMatrixDEigen &another)
00092 {
00093 // Copy constructor
00094 
00095    *this = another;
00096 }
00097 
00098 //______________________________________________________________________________
00099 void TMatrixDEigen::MakeHessenBerg(TMatrixD &v,TVectorD &ortho,TMatrixD &H)
00100 {
00101 // Nonsymmetric reduction to Hessenberg form.
00102 // This is derived from the Algol procedures orthes and ortran, by Martin and Wilkinson,
00103 // Handbook for Auto. Comp., Vol.ii-Linear Algebra, and the corresponding
00104 // Fortran subroutines in EISPACK.
00105 
00106    Double_t *pV = v.GetMatrixArray();
00107    Double_t *pO = ortho.GetMatrixArray();
00108    Double_t *pH = H.GetMatrixArray();
00109 
00110    const Int_t n = v.GetNrows();
00111 
00112    const Int_t low  = 0;
00113    const Int_t high = n-1;
00114 
00115    Int_t i,j,m;
00116    for (m = low+1; m <= high-1; m++) {
00117       const Int_t off_m = m*n;
00118 
00119       // Scale column.
00120 
00121       Double_t scale = 0.0;
00122       for (i = m; i <= high; i++) {
00123          const Int_t off_i = i*n;
00124          scale = scale + TMath::Abs(pH[off_i+m-1]);
00125       }
00126       if (scale != 0.0) {
00127 
00128          // Compute Householder transformation.
00129 
00130          Double_t h = 0.0;
00131          for (i = high; i >= m; i--) {
00132             const Int_t off_i = i*n;
00133             pO[i] = pH[off_i+m-1]/scale;
00134             h += pO[i]*pO[i];
00135          }
00136          Double_t g = TMath::Sqrt(h);
00137          if (pO[m] > 0)
00138             g = -g;
00139          h = h-pO[m]*g;
00140          pO[m] = pO[m]-g;
00141 
00142          // Apply Householder similarity transformation
00143          // H = (I-u*u'/h)*H*(I-u*u')/h)
00144 
00145          for (j = m; j < n; j++) {
00146             Double_t f = 0.0;
00147             for (i = high; i >= m; i--) {
00148                const Int_t off_i = i*n;
00149                f += pO[i]*pH[off_i+j];
00150             }
00151             f = f/h;
00152             for (i = m; i <= high; i++) {
00153                const Int_t off_i = i*n;
00154                pH[off_i+j] -= f*pO[i];
00155             }
00156          }
00157 
00158          for (i = 0; i <= high; i++) {
00159             const Int_t off_i = i*n;
00160             Double_t f = 0.0;
00161             for (j = high; j >= m; j--)
00162                f += pO[j]*pH[off_i+j];
00163             f = f/h;
00164             for (j = m; j <= high; j++)
00165                pH[off_i+j] -= f*pO[j];
00166          }
00167          pO[m] = scale*pO[m];
00168          pH[off_m+m-1] = scale*g;
00169       }
00170    }
00171 
00172    // Accumulate transformations (Algol's ortran).
00173 
00174    for (i = 0; i < n; i++) {
00175       const Int_t off_i = i*n;
00176       for (j = 0; j < n; j++)
00177          pV[off_i+j] = (i == j ? 1.0 : 0.0);
00178    }
00179 
00180    for (m = high-1; m >= low+1; m--) {
00181       const Int_t off_m = m*n;
00182       if (pH[off_m+m-1] != 0.0) {
00183          for (i = m+1; i <= high; i++) {
00184             const Int_t off_i = i*n;
00185             pO[i] = pH[off_i+m-1];
00186          }
00187          for (j = m; j <= high; j++) {
00188             Double_t g = 0.0;
00189             for (i = m; i <= high; i++) {
00190                const Int_t off_i = i*n;
00191                g += pO[i]*pV[off_i+j];
00192             }
00193             // Double division avoids possible underflow
00194             g = (g/pO[m])/pH[off_m+m-1];
00195             for (i = m; i <= high; i++) {
00196                const Int_t off_i = i*n;
00197                pV[off_i+j] += g*pO[i];
00198             }
00199          }
00200       }
00201    }
00202 }
00203 
00204 //______________________________________________________________________________
00205 static Double_t gCdivr, gCdivi;
00206 static void cdiv(Double_t xr,Double_t xi,Double_t yr,Double_t yi) {
00207 // Complex scalar division.
00208    Double_t r,d;
00209    if (TMath::Abs(yr) > TMath::Abs(yi)) {
00210       r = yi/yr;
00211       d = yr+r*yi;
00212       gCdivr = (xr+r*xi)/d;
00213       gCdivi = (xi-r*xr)/d;
00214    } else {
00215       r = yr/yi;
00216       d = yi+r*yr;
00217       gCdivr = (r*xr+xi)/d;
00218       gCdivi = (r*xi-xr)/d;
00219    }
00220 }
00221 
00222 //______________________________________________________________________________
00223 void TMatrixDEigen::MakeSchurr(TMatrixD &v,TVectorD &d,TVectorD &e,TMatrixD &H)
00224 {
00225 // Nonsymmetric reduction from Hessenberg to real Schur form.
00226 // This is derived from the Algol procedure hqr2, by Martin and Wilkinson,
00227 // Handbook for Auto. Comp., Vol.ii-Linear Algebra, and the corresponding
00228 // Fortran subroutine in EISPACK.
00229 
00230    // Initialize
00231 
00232    const Int_t nn = v.GetNrows();
00233          Int_t n = nn-1;
00234    const Int_t low = 0;
00235    const Int_t high = nn-1;
00236    const Double_t eps = TMath::Power(2.0,-52.0);
00237    Double_t exshift = 0.0;
00238    Double_t p=0,q=0,r=0,s=0,z=0,t,w,x,y;
00239 
00240    Double_t *pV = v.GetMatrixArray();
00241    Double_t *pD = d.GetMatrixArray();
00242    Double_t *pE = e.GetMatrixArray();
00243    Double_t *pH = H.GetMatrixArray();
00244 
00245    // Store roots isolated by balanc and compute matrix norm
00246 
00247    Double_t norm = 0.0;
00248    Int_t i,j,k;
00249    for (i = 0; i < nn; i++) {
00250       const Int_t off_i = i*nn;
00251       if ((i < low) || (i > high)) {
00252          pD[i] = pH[off_i+i];
00253          pE[i] = 0.0;
00254       }
00255       for (j = TMath::Max(i-1,0); j < nn; j++)
00256          norm += TMath::Abs(pH[off_i+j]);
00257    }
00258 
00259    // Outer loop over eigenvalue index
00260 
00261    Int_t iter = 0;
00262    while (n >= low) {
00263       const Int_t off_n  = n*nn;
00264       const Int_t off_n1 = (n-1)*nn;
00265 
00266       // Look for single small sub-diagonal element
00267 
00268       Int_t l = n;
00269       while (l > low) {
00270          const Int_t off_l1 = (l-1)*nn;
00271          const Int_t off_l  = l*nn;
00272          s = TMath::Abs(pH[off_l1+l-1])+TMath::Abs(pH[off_l+l]);
00273          if (s == 0.0)
00274             s = norm;
00275          if (TMath::Abs(pH[off_l+l-1]) < eps*s)
00276             break;
00277          l--;
00278       }
00279 
00280       // Check for convergence
00281       // One root found
00282 
00283       if (l == n) {
00284          pH[off_n+n] = pH[off_n+n]+exshift;
00285          pD[n] = pH[off_n+n];
00286          pE[n] = 0.0;
00287          n--;
00288          iter = 0;
00289 
00290          // Two roots found
00291 
00292       } else if (l == n-1) {
00293          w = pH[off_n+n-1]*pH[off_n1+n];
00294          p = (pH[off_n1+n-1]-pH[off_n+n])/2.0;
00295          q = p*p+w;
00296          z = TMath::Sqrt(TMath::Abs(q));
00297          pH[off_n+n] = pH[off_n+n]+exshift;
00298          pH[off_n1+n-1] = pH[off_n1+n-1]+exshift;
00299          x = pH[off_n+n];
00300 
00301          // Double_t pair
00302 
00303          if (q >= 0) {
00304             if (p >= 0)
00305                z = p+z;
00306             else
00307                z = p-z;
00308             pD[n-1] = x+z;
00309             pD[n] = pD[n-1];
00310             if (z != 0.0)
00311                pD[n] = x-w/z;
00312             pE[n-1] = 0.0;
00313             pE[n] = 0.0;
00314             x = pH[off_n+n-1];
00315             s = TMath::Abs(x)+TMath::Abs(z);
00316             p = x/s;
00317             q = z/s;
00318             r = TMath::Sqrt((p*p)+(q*q));
00319             p = p/r;
00320             q = q/r;
00321 
00322             // Row modification
00323 
00324             for (j = n-1; j < nn; j++) {
00325                z = pH[off_n1+j];
00326                pH[off_n1+j] = q*z+p*pH[off_n+j];
00327                pH[off_n+j]  = q*pH[off_n+j]-p*z;
00328             }
00329 
00330             // Column modification
00331 
00332             for (i = 0; i <= n; i++) {
00333                const Int_t off_i = i*nn;
00334                z = pH[off_i+n-1];
00335                pH[off_i+n-1] = q*z+p*pH[off_i+n];
00336                pH[off_i+n]  = q*pH[off_i+n]-p*z;
00337             }
00338 
00339             // Accumulate transformations
00340 
00341             for (i = low; i <= high; i++) {
00342                const Int_t off_i = i*nn;
00343                z = pV[off_i+n-1];
00344                pV[off_i+n-1] = q*z+p*pV[off_i+n];
00345                pV[off_i+n]   = q*pV[off_i+n]-p*z;
00346             }
00347 
00348             // Complex pair
00349 
00350          } else {
00351             pD[n-1] = x+p;
00352             pD[n] = x+p;
00353             pE[n-1] = z;
00354             pE[n] = -z;
00355          }
00356          n = n-2;
00357          iter = 0;
00358 
00359          // No convergence yet
00360 
00361       } else {
00362 
00363          // Form shift
00364 
00365          x = pH[off_n+n];
00366          y = 0.0;
00367          w = 0.0;
00368          if (l < n) {
00369             y = pH[off_n1+n-1];
00370             w = pH[off_n+n-1]*pH[off_n1+n];
00371          }
00372 
00373          // Wilkinson's original ad hoc shift
00374 
00375          if (iter == 10) {
00376             exshift += x;
00377             for (i = low; i <= n; i++) {
00378                const Int_t off_i = i*nn;
00379                pH[off_i+i] -= x;
00380             }
00381             s = TMath::Abs(pH[off_n+n-1])+TMath::Abs(pH[off_n1+n-2]);
00382             x = y = 0.75*s;
00383             w = -0.4375*s*s;
00384          }
00385 
00386          // MATLAB's new ad hoc shift
00387 
00388          if (iter == 30) {
00389             s = (y-x)/2.0;
00390             s = s*s+w;
00391             if (s > 0) {
00392                s = TMath::Sqrt(s);
00393                if (y<x)
00394                   s = -s;
00395                s = x-w/((y-x)/2.0+s);
00396                for (i = low; i <= n; i++) {
00397                   const Int_t off_i = i*nn;
00398                   pH[off_i+i] -= s;
00399                }
00400                exshift += s;
00401                x = y = w = 0.964;
00402             }
00403          }
00404 
00405          if (iter++ == 50) {  // (check iteration count here.)
00406             Error("MakeSchurr","too many iterations");
00407             break;
00408          }
00409 
00410          // Look for two consecutive small sub-diagonal elements
00411 
00412          Int_t m = n-2;
00413          while (m >= l) {
00414             const Int_t off_m   = m*nn;
00415             const Int_t off_m_1 = (m-1)*nn;
00416             const Int_t off_m1  = (m+1)*nn;
00417             const Int_t off_m2  = (m+2)*nn;
00418             z = pH[off_m+m];
00419             r = x-z;
00420             s = y-z;
00421             p = (r*s-w)/pH[off_m1+m]+pH[off_m+m+1];
00422             q = pH[off_m1+m+1]-z-r-s;
00423             r = pH[off_m2+m+1];
00424             s = TMath::Abs(p)+TMath::Abs(q)+TMath::Abs(r);
00425             p = p /s;
00426             q = q/s;
00427             r = r/s;
00428             if (m == l)
00429                break;
00430             if (TMath::Abs(pH[off_m+m-1])*(TMath::Abs(q)+TMath::Abs(r)) <
00431                eps*(TMath::Abs(p)*(TMath::Abs(pH[off_m_1+m-1])+TMath::Abs(z)+
00432                TMath::Abs(pH[off_m1+m+1]))))
00433                break;
00434                m--;
00435             }
00436 
00437             for (i = m+2; i <= n; i++) {
00438                const Int_t off_i = i*nn;
00439                pH[off_i+i-2] = 0.0;
00440                if (i > m+2)
00441                   pH[off_i+i-3] = 0.0;
00442             }
00443 
00444             // Double QR step involving rows l:n and columns m:n
00445 
00446             for (k = m; k <= n-1; k++) {
00447                const Int_t off_k  = k*nn;
00448                const Int_t off_k1 = (k+1)*nn;
00449                const Int_t off_k2 = (k+2)*nn;
00450                const Int_t notlast = (k != n-1);
00451                if (k != m) {
00452                   p = pH[off_k+k-1];
00453                   q = pH[off_k1+k-1];
00454                   r = (notlast ? pH[off_k2+k-1] : 0.0);
00455                   x = TMath::Abs(p)+TMath::Abs(q)+TMath::Abs(r);
00456                   if (x != 0.0) {
00457                      p = p/x;
00458                      q = q/x;
00459                      r = r/x;
00460                   }
00461                }
00462                if (x == 0.0)
00463                   break;
00464                s = TMath::Sqrt(p*p+q*q+r*r);
00465                if (p < 0) {
00466                   s = -s;
00467                }
00468                if (s != 0) {
00469                   if (k != m)
00470                      pH[off_k+k-1] = -s*x;
00471                   else if (l != m)
00472                      pH[off_k+k-1] = -pH[off_k+k-1];
00473                   p = p+s;
00474                   x = p/s;
00475                   y = q/s;
00476                   z = r/s;
00477                   q = q/p;
00478                   r = r/p;
00479 
00480                   // Row modification
00481 
00482                   for (j = k; j < nn; j++) {
00483                      p = pH[off_k+j]+q*pH[off_k1+j];
00484                      if (notlast) {
00485                         p = p+r*pH[off_k2+j];
00486                         pH[off_k2+j] = pH[off_k2+j]-p*z;
00487                      }
00488                      pH[off_k+j]  = pH[off_k+j]-p*x;
00489                      pH[off_k1+j] = pH[off_k1+j]-p*y;
00490                   }
00491 
00492                   // Column modification
00493 
00494                   for (i = 0; i <= TMath::Min(n,k+3); i++) {
00495                      const Int_t off_i = i*nn;
00496                      p = x*pH[off_i+k]+y*pH[off_i+k+1];
00497                      if (notlast) {
00498                         p = p+z*pH[off_i+k+2];
00499                         pH[off_i+k+2] = pH[off_i+k+2]-p*r;
00500                      }
00501                      pH[off_i+k]   = pH[off_i+k]-p;
00502                      pH[off_i+k+1] = pH[off_i+k+1]-p*q;
00503                   }
00504 
00505                   // Accumulate transformations
00506 
00507                   for (i = low; i <= high; i++) {
00508                      const Int_t off_i = i*nn;
00509                      p = x*pV[off_i+k]+y*pV[off_i+k+1];
00510                      if (notlast) {
00511                         p = p+z*pV[off_i+k+2];
00512                         pV[off_i+k+2] = pV[off_i+k+2]-p*r;
00513                      }
00514                      pV[off_i+k]   = pV[off_i+k]-p;
00515                      pV[off_i+k+1] = pV[off_i+k+1]-p*q;
00516                   }
00517                }  // (s != 0)
00518             }  // k loop
00519          }  // check convergence
00520       }  // while (n >= low)
00521 
00522       // Backsubstitute to find vectors of upper triangular form
00523 
00524       if (norm == 0.0)
00525          return;
00526 
00527       for (n = nn-1; n >= 0; n--) {
00528          p = pD[n];
00529          q = pE[n];
00530 
00531          // Double_t vector
00532 
00533          const Int_t off_n = n*nn;
00534          if (q == 0) {
00535             Int_t l = n;
00536             pH[off_n+n] = 1.0;
00537             for (i = n-1; i >= 0; i--) {
00538                const Int_t off_i  = i*nn;
00539                const Int_t off_i1 = (i+1)*nn;
00540                w = pH[off_i+i]-p;
00541                r = 0.0;
00542                for (j = l; j <= n; j++) {
00543                   const Int_t off_j = j*nn;
00544                   r = r+pH[off_i+j]*pH[off_j+n];
00545                }
00546                if (pE[i] < 0.0) {
00547                   z = w;
00548                   s = r;
00549                } else {
00550                   l = i;
00551                   if (pE[i] == 0.0) {
00552                      if (w != 0.0)
00553                         pH[off_i+n] = -r/w;
00554                   else
00555                      pH[off_i+n] = -r/(eps*norm);
00556 
00557                   // Solve real equations
00558 
00559                } else {
00560                   x = pH[off_i+i+1];
00561                   y = pH[off_i1+i];
00562                   q = (pD[i]-p)*(pD[i]-p)+pE[i]*pE[i];
00563                   t = (x*s-z*r)/q;
00564                   pH[off_i+n] = t;
00565                   if (TMath::Abs(x) > TMath::Abs(z))
00566                      pH[i+1+n] = (-r-w*t)/x;
00567                   else
00568                      pH[i+1+n] = (-s-y*t)/z;
00569                }
00570 
00571                // Overflow control
00572 
00573                t = TMath::Abs(pH[off_i+n]);
00574                if ((eps*t)*t > 1) {
00575                   for (j = i; j <= n; j++) {
00576                      const Int_t off_j = j*nn;
00577                      pH[off_j+n] = pH[off_j+n]/t;
00578                   }
00579                }
00580             }
00581          }
00582 
00583          // Complex vector
00584 
00585       } else if (q < 0) {
00586          Int_t l = n-1;
00587          const Int_t off_n1 = (n-1)*nn;
00588 
00589          // Last vector component imaginary so matrix is triangular
00590 
00591          if (TMath::Abs(pH[off_n+n-1]) > TMath::Abs(pH[off_n1+n])) {
00592             pH[off_n1+n-1] = q/pH[off_n+n-1];
00593             pH[off_n1+n]   = -(pH[off_n+n]-p)/pH[off_n+n-1];
00594          } else {
00595             cdiv(0.0,-pH[off_n1+n],pH[off_n1+n-1]-p,q);
00596             pH[off_n1+n-1] = gCdivr;
00597             pH[off_n1+n]   = gCdivi;
00598          }
00599          pH[off_n+n-1] = 0.0;
00600          pH[off_n+n]   = 1.0;
00601          for (i = n-2; i >= 0; i--) {
00602             const Int_t off_i  = i*nn;
00603             const Int_t off_i1 = (i+1)*nn;
00604             Double_t ra = 0.0;
00605             Double_t sa = 0.0;
00606             for (j = l; j <= n; j++) {
00607                const Int_t off_j = j*nn;
00608                ra += pH[off_i+j]*pH[off_j+n-1];
00609                sa += pH[off_i+j]*pH[off_j+n];
00610             }
00611             w = pH[off_i+i]-p;
00612 
00613             if (pE[i] < 0.0) {
00614                z = w;
00615                r = ra;
00616                s = sa;
00617             } else {
00618                l = i;
00619                if (pE[i] == 0) {
00620                   cdiv(-ra,-sa,w,q);
00621                   pH[off_i+n-1] = gCdivr;
00622                   pH[off_i+n]   = gCdivi;
00623                } else {
00624 
00625                   // Solve complex equations
00626 
00627                   x = pH[off_i+i+1];
00628                   y = pH[off_i1+i];
00629                   Double_t vr = (pD[i]-p)*(pD[i]-p)+pE[i]*pE[i]-q*q;
00630                   Double_t vi = (pD[i]-p)*2.0*q;
00631                   if ((vr == 0.0) && (vi == 0.0)) {
00632                      vr = eps*norm*(TMath::Abs(w)+TMath::Abs(q)+
00633                           TMath::Abs(x)+TMath::Abs(y)+TMath::Abs(z));
00634                   }
00635                   cdiv(x*r-z*ra+q*sa,x*s-z*sa-q*ra,vr,vi);
00636                   pH[off_i+n-1] = gCdivr;
00637                   pH[off_i+n]   = gCdivi;
00638                   if (TMath::Abs(x) > (TMath::Abs(z)+TMath::Abs(q))) {
00639                      pH[off_i1+n-1] = (-ra-w*pH[off_i+n-1]+q*pH[off_i+n])/x;
00640                      pH[off_i1+n]   = (-sa-w*pH[off_i+n]-q*pH[off_i+n-1])/x;
00641                   } else {
00642                      cdiv(-r-y*pH[off_i+n-1],-s-y*pH[off_i+n],z,q);
00643                      pH[off_i1+n-1] = gCdivr;
00644                      pH[off_i1+n]   = gCdivi;
00645                   }
00646                }
00647 
00648                // Overflow control
00649 
00650                t = TMath::Max(TMath::Abs(pH[off_i+n-1]),TMath::Abs(pH[off_i+n]));
00651                if ((eps*t)*t > 1) {
00652                   for (j = i; j <= n; j++) {
00653                      const Int_t off_j = j*nn;
00654                      pH[off_j+n-1] = pH[off_j+n-1]/t;
00655                      pH[off_j+n]   = pH[off_j+n]/t;
00656                   }
00657                }
00658             }
00659          }
00660       }
00661    }
00662 
00663    // Vectors of isolated roots
00664 
00665    for (i = 0; i < nn; i++) {
00666       if (i < low || i > high) {
00667          const Int_t off_i = i*nn;
00668          for (j = i; j < nn; j++)
00669             pV[off_i+j] = pH[off_i+j];
00670       }
00671    }
00672 
00673    // Back transformation to get eigenvectors of original matrix
00674 
00675    for (j = nn-1; j >= low; j--) {
00676       for (i = low; i <= high; i++) {
00677          const Int_t off_i = i*nn;
00678          z = 0.0;
00679          for (k = low; k <= TMath::Min(j,high); k++) {
00680             const Int_t off_k = k*nn;
00681             z = z+pV[off_i+k]*pH[off_k+j];
00682          }
00683          pV[off_i+j] = z;
00684       }
00685    }
00686 
00687 }
00688 
00689 //______________________________________________________________________________
00690 void TMatrixDEigen::Sort(TMatrixD &v,TVectorD &d,TVectorD &e)
00691 {
00692 // Sort eigenvalues and corresponding vectors in descending order of Re^2+Im^2
00693 // of the complex eigenvalues .
00694 
00695    // Sort eigenvalues and corresponding vectors.
00696    Double_t *pV = v.GetMatrixArray();
00697    Double_t *pD = d.GetMatrixArray();
00698    Double_t *pE = e.GetMatrixArray();
00699 
00700    const Int_t n = v.GetNrows();
00701 
00702    for (Int_t i = 0; i < n-1; i++) {
00703       Int_t k = i;
00704       Double_t norm = pD[i]*pD[i]+pE[i]*pE[i];
00705       Int_t j;
00706       for (j = i+1; j < n; j++) {
00707          const Double_t norm_new = pD[j]*pD[j]+pE[j]*pE[j];
00708          if (norm_new > norm) {
00709             k = j;
00710             norm = norm_new;
00711          }
00712       }
00713       if (k != i) {
00714          Double_t tmp;
00715          tmp   = pD[k];
00716          pD[k] = pD[i];
00717          pD[i] = tmp;
00718          tmp   = pE[k];
00719          pE[k] = pE[i];
00720          pE[i] = tmp;
00721          for (j = 0; j < n; j++) {
00722             const Int_t off_j = j*n;
00723             tmp = pV[off_j+i];
00724             pV[off_j+i] = pV[off_j+k];
00725             pV[off_j+k] = tmp;
00726          }
00727       }
00728    }
00729 }
00730 
00731 //______________________________________________________________________________
00732 TMatrixDEigen &TMatrixDEigen::operator=(const TMatrixDEigen &source)
00733 {
00734 // Assignment operator
00735 
00736    if (this != &source) {
00737       fEigenVectors.ResizeTo(source.fEigenVectors);
00738       fEigenValuesRe.ResizeTo(source.fEigenValuesRe);
00739       fEigenValuesIm.ResizeTo(source.fEigenValuesIm);
00740    }
00741    return *this;
00742 }
00743 
00744 //______________________________________________________________________________
00745 const TMatrixD TMatrixDEigen::GetEigenValues() const
00746 {
00747 // Computes the block diagonal eigenvalue matrix.
00748 // If the original matrix A is not symmetric, then the eigenvalue
00749 // matrix D is block diagonal with the real eigenvalues in 1-by-1
00750 // blocks and any complex eigenvalues,
00751 //    a + i*b, in 2-by-2 blocks, [a, b; -b, a].
00752 //  That is, if the complex eigenvalues look like
00753 //
00754 //     u + iv     .        .          .      .    .
00755 //       .      u - iv     .          .      .    .
00756 //       .        .      a + ib       .      .    .
00757 //       .        .        .        a - ib   .    .
00758 //       .        .        .          .      x    .
00759 //       .        .        .          .      .    y
00760 //
00761 // then D looks like
00762 //
00763 //     u        v        .          .      .    .
00764 //    -v        u        .          .      .    .
00765 //     .        .        a          b      .    .
00766 //     .        .       -b          a      .    .
00767 //     .        .        .          .      x    .
00768 //     .        .        .          .      .    y
00769 //
00770 // This keeps V a real matrix in both symmetric and non-symmetric
00771 // cases, and A*V = V*D.
00772 //
00773 // Indexing:
00774 //  If matrix A has the index/shape (rowLwb,rowUpb,rowLwb,rowUpb)
00775 //  each eigen-vector must have the shape (rowLwb,rowUpb) .
00776 //  For convinience, the column index of the eigen-vector matrix
00777 //  also runs from rowLwb to rowUpb so that the returned matrix
00778 //  has also index/shape (rowLwb,rowUpb,rowLwb,rowUpb) .
00779 //
00780    const Int_t nrows  = fEigenVectors.GetNrows();
00781    const Int_t rowLwb = fEigenVectors.GetRowLwb();
00782    const Int_t rowUpb = rowLwb+nrows-1;
00783 
00784    TMatrixD mD(rowLwb,rowUpb,rowLwb,rowUpb);
00785 
00786    Double_t *pD = mD.GetMatrixArray();
00787    const Double_t * const pd = fEigenValuesRe.GetMatrixArray();
00788    const Double_t * const pe = fEigenValuesIm.GetMatrixArray();
00789 
00790    for (Int_t i = 0; i < nrows; i++) {
00791       const Int_t off_i = i*nrows;
00792       for (Int_t j = 0; j < nrows; j++)
00793          pD[off_i+j] = 0.0;
00794       pD[off_i+i] = pd[i];
00795       if (pe[i] > 0) {
00796          pD[off_i+i+1] = pe[i];
00797       } else if (pe[i] < 0) {
00798          pD[off_i+i-1] = pe[i];
00799       }
00800    }
00801 
00802    return mD;
00803 }

Generated on Tue Jul 5 14:36:27 2011 for ROOT_528-00b_version by  doxygen 1.5.1