Advertisement
Guest User

Untitled

a guest
Mar 21st, 2018
90
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 5.45 KB | None | 0 0
  1. // function computes all eigenvalues and eigenvectors of a real symmetric matrix A[0..n-1][0..n-1]
  2. // stored in the top left of a 10x10 array A[10][10]
  3. // A[][] is changed on output.
  4. // eigval[0..n-1] returns the eigenvalues of A[][].
  5. // eigvec[0..n-1][0..n-1] returns the normalized eigenvectors of A[][]
  6. // the eigenvectors are not sorted by value
  7. void eigencompute(float A[][10], float eigval[], float eigvec[][10], int8 n)
  8. {
  9.     // maximum number of iterations to achieve convergence: in practice 6 is typical
  10. #define NITERATIONS 15
  11.  
  12.     // various trig functions of the jacobi rotation angle phi
  13.     float cot2phi, tanhalfphi, tanphi, sinphi, cosphi;
  14.     // scratch variable to prevent over-writing during rotations
  15.     float ftmp;
  16.     // residue from remaining non-zero above diagonal terms
  17.     float residue;
  18.     // matrix row and column indices
  19.     int8 ir, ic;
  20.     // general loop counter
  21.     int8 j;
  22.     // timeout ctr for number of passes of the algorithm
  23.     int8 ctr;
  24.  
  25.     // initialize eigenvectors matrix and eigenvalues array
  26.     for (ir = 0; ir < n; ir++)
  27.     {
  28.         // loop over all columns
  29.         for (ic = 0; ic < n; ic++)
  30.         {
  31.             // set on diagonal and off-diagonal elements to zero
  32.             eigvec[ir][ic] = 0.0F;
  33.         }
  34.  
  35.         // correct the diagonal elements to 1.0
  36.         eigvec[ir][ir] = 1.0F;
  37.  
  38.         // initialize the array of eigenvalues to the diagonal elements of m
  39.         eigval[ir] = A[ir][ir];
  40.     }
  41.  
  42.     // initialize the counter and loop until converged or NITERATIONS reached
  43.     ctr = 0;
  44.     do
  45.     {
  46.         // compute the absolute value of the above diagonal elements as exit criterion
  47.         residue = 0.0F;
  48.         // loop over rows excluding last row
  49.         for (ir = 0; ir < n - 1; ir++)
  50.         {
  51.             // loop over above diagonal columns
  52.             for (ic = ir + 1; ic < n; ic++)
  53.             {
  54.                 // accumulate the residual off diagonal terms which are being driven to zero
  55.                 residue += fabs(A[ir][ic]);
  56.             }
  57.         }
  58.  
  59.         // check if we still have work to do
  60.         if (residue > 0.0F)
  61.         {
  62.             // loop over all rows with the exception of the last row (since only rotating above diagonal elements)
  63.             for (ir = 0; ir < n - 1; ir++)
  64.             {
  65.                 // loop over columns ic (where ic is always greater than ir since above diagonal)
  66.                 for (ic = ir + 1; ic < n; ic++)
  67.                 {
  68.                     // only continue with this element if the element is non-zero
  69.                     if (fabs(A[ir][ic]) > 0.0F)
  70.                     {
  71.                         // calculate cot(2*phi) where phi is the Jacobi rotation angle
  72.                         cot2phi = 0.5F * (eigval[ic] - eigval[ir]) / (A[ir][ic]);
  73.  
  74.                         // calculate tan(phi) correcting sign to ensure the smaller solution is used
  75.                         tanphi = 1.0F / (fabs(cot2phi) + sqrtf(1.0F + cot2phi * cot2phi));
  76.                         if (cot2phi < 0.0F)
  77.                         {
  78.                             tanphi = -tanphi;
  79.                         }
  80.  
  81.                         // calculate the sine and cosine of the Jacobi rotation angle phi
  82.                         cosphi = 1.0F / sqrtf(1.0F + tanphi * tanphi);
  83.                         sinphi = tanphi * cosphi;
  84.  
  85.                         // calculate tan(phi/2)
  86.                         tanhalfphi = sinphi / (1.0F + cosphi);
  87.  
  88.                         // set tmp = tan(phi) times current matrix element used in update of leading diagonal elements
  89.                         ftmp = tanphi * A[ir][ic];
  90.  
  91.                         // apply the jacobi rotation to diagonal elements [ir][ir] and [ic][ic] stored in the eigenvalue array
  92.                         // eigval[ir] = eigval[ir] - tan(phi) *  A[ir][ic]
  93.                         eigval[ir] -= ftmp;
  94.                         // eigval[ic] = eigval[ic] + tan(phi) * A[ir][ic]
  95.                         eigval[ic] += ftmp;
  96.  
  97.                         // by definition, applying the jacobi rotation on element ir, ic results in 0.0
  98.                         A[ir][ic] = 0.0F;
  99.  
  100.                         // apply the jacobi rotation to all elements of the eigenvector matrix
  101.                         for (j = 0; j < n; j++)
  102.                         {
  103.                             // store eigvec[j][ir]
  104.                             ftmp = eigvec[j][ir];
  105.                             // eigvec[j][ir] = eigvec[j][ir] - sin(phi) * (eigvec[j][ic] + tan(phi/2) * eigvec[j][ir])
  106.                             eigvec[j][ir] = ftmp - sinphi * (eigvec[j][ic] + tanhalfphi * ftmp);
  107.                             // eigvec[j][ic] = eigvec[j][ic] + sin(phi) * (eigvec[j][ir] - tan(phi/2) * eigvec[j][ic])
  108.                             eigvec[j][ic] = eigvec[j][ic] + sinphi * (ftmp - tanhalfphi * eigvec[j][ic]);
  109.                         }
  110.  
  111.                         // apply the jacobi rotation only to those elements of matrix m that can change
  112.                         for (j = 0; j <= ir - 1; j++)
  113.                         {
  114.                             // store A[j][ir]
  115.                             ftmp = A[j][ir];
  116.                             // A[j][ir] = A[j][ir] - sin(phi) * (A[j][ic] + tan(phi/2) * A[j][ir])
  117.                             A[j][ir] = ftmp - sinphi * (A[j][ic] + tanhalfphi * ftmp);
  118.                             // A[j][ic] = A[j][ic] + sin(phi) * (A[j][ir] - tan(phi/2) * A[j][ic])
  119.                             A[j][ic] = A[j][ic] + sinphi * (ftmp - tanhalfphi * A[j][ic]);
  120.                         }
  121.                         for (j = ir + 1; j <= ic - 1; j++)
  122.                         {
  123.                             // store A[ir][j]
  124.                             ftmp = A[ir][j];
  125.                             // A[ir][j] = A[ir][j] - sin(phi) * (A[j][ic] + tan(phi/2) * A[ir][j])
  126.                             A[ir][j] = ftmp - sinphi * (A[j][ic] + tanhalfphi * ftmp);
  127.                             // A[j][ic] = A[j][ic] + sin(phi) * (A[ir][j] - tan(phi/2) * A[j][ic])
  128.                             A[j][ic] = A[j][ic] + sinphi * (ftmp - tanhalfphi * A[j][ic]);
  129.                         }
  130.                         for (j = ic + 1; j < n; j++)
  131.                         {
  132.                             // store A[ir][j]
  133.                             ftmp = A[ir][j];
  134.                             // A[ir][j] = A[ir][j] - sin(phi) * (A[ic][j] + tan(phi/2) * A[ir][j])
  135.                             A[ir][j] = ftmp - sinphi * (A[ic][j] + tanhalfphi * ftmp);
  136.                             // A[ic][j] = A[ic][j] + sin(phi) * (A[ir][j] - tan(phi/2) * A[ic][j])
  137.                             A[ic][j] = A[ic][j] + sinphi * (ftmp - tanhalfphi * A[ic][j]);
  138.                         }
  139.                     }   // end of test for matrix element already zero
  140.                 }   // end of loop over columns
  141.             }   // end of loop over rows
  142.         }  // end of test for non-zero residue
  143.     } while ((residue > 0.0F) && (ctr++ < NITERATIONS)); // end of main loop
  144.  
  145.     return;
  146. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement