Advertisement
roninkoi

Jacobi eigenvalues

Feb 11th, 2021
1,179
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 2.82 KB | None | 0 0
  1. #include <stdlib.h>
  2. #include <stdio.h>
  3. #include <math.h>
  4.  
  5. // sign of floating point number
  6. #define sign(x) (x >= 0.0 ? 1.0 : -1.0)
  7.  
  8. // random floating point number
  9. #define randf() (((double) rand() / (double) RAND_MAX - 0.5) * 2.0)
  10.  
  11. /*
  12.  * Construct diagonal n x n matrix a with value d.
  13.  */
  14. void constructDiag(double *a, int n, double d)
  15. {
  16.     for (int ij = 0; ij < n * n; ++ij) // go through entire matrix
  17.         a[ij] = (double) (ij % n == ij / n) * d; // and check if at diagonal
  18. }
  19.  
  20. /*
  21.  * Construct n x n Givens rotation matrix Qpq with row p and column q.
  22.  * Diagonal value c (cos) and off-diagonal value s (sin).
  23.  */
  24. void constructQpq(double *Qpq, int n, int p, int q, double c, double s)
  25. {
  26.     constructDiag(Qpq, n, 1.0); // identity matrix
  27.  
  28.     Qpq[p * n + p] = c;
  29.     Qpq[q * n + q] = c;
  30.     Qpq[p * n + q] = -s;
  31.     Qpq[q * n + p] = s;
  32. }
  33.  
  34. /*
  35.  * Computes value of n x n matrix expression Qpq^T B Qpq and places it into B.
  36.  */
  37. void computeQTBQ(double *Qpq, double *B, int n)
  38. {
  39.     double *Bn = (double *) malloc(n * n * sizeof(double));
  40.  
  41.     for (int i = 0; i < n; ++i) { // Bn = Qpq^T B
  42.         for (int j = 0; j < n; ++j) {
  43.             Bn[i * n + j] = 0.0;
  44.             for (int k = 0; k < n; ++k)
  45.                 Bn[i * n + j] += Qpq[k * n + i] * B[k * n + j];
  46.         }
  47.     }
  48.    
  49.     for (int i = 0; i < n; ++i) { // B = Bn Qpq
  50.         for (int j = 0; j < n; ++j) {
  51.             B[i * n + j] = 0.0;
  52.             for (int k = 0; k < n; ++k)
  53.                 B[i * n + j] += Bn[i * n + k] * Qpq[k * n + j];
  54.         }
  55.     }
  56.    
  57.     free(Bn);
  58. }
  59.  
  60. #define MAXIT 10000 // maximum iterations
  61. #define EPSILON 0.001 // maximum residual
  62.  
  63. /*
  64.  * Solve eigenvalues of n x n matrix Q using Jacobi method.
  65.  */
  66. void jacobi(double *Q, int n)
  67. {
  68.     double *B = (double *) malloc(n * n * sizeof(double));
  69.     double *Qpq = (double *) malloc(n * n * sizeof(double));
  70.  
  71.     for (int ij = 0; ij < n * n; ++ij) // initial value of b
  72.         B[ij] = Q[ij];
  73.  
  74.     double res; // residual
  75.    
  76.     for (int i = 0; i < MAXIT; ++i) {
  77.         for (int p = 0; p < n - 1; ++p) { // row
  78.             for (int q = p + 1; q < n; ++q) { // column
  79.                 double appqq = Q[p * n + p] - Q[q * n + q];
  80.                 double apq = Q[p * n + q];
  81.  
  82.                 if (appqq * appqq + 4.0 * apq * apq <= 0.0) {// NaN
  83.                     printf("Jacobi error: Bad matrix!\n");
  84.                     continue;
  85.                 }
  86.                
  87.                 double C = appqq / sqrt(appqq * appqq + 4.0 * apq * apq);
  88.                
  89.                 double c = sqrt((1.0 + C) / 2.0); // cos
  90.                 double s = sign(apq) * sqrt((1.0 - C) / 2.0); // sin
  91.  
  92.                 constructQpq(Qpq, n, p, q, c, s); // construct rotation matrix
  93.  
  94.                 computeQTBQ(Qpq, B, n); // get new value of B
  95.             }
  96.         }
  97.  
  98.         res = 0.0;
  99.         for (int ij = 0; ij < n * n; ++ij) { // next iteration value of Q
  100.             res += fabs(Q[ij] - B[ij]); // accumulate residual
  101.            
  102.             Q[ij] = B[ij];
  103.         }
  104.  
  105.         if (res < EPSILON) // if converged, stop iterating
  106.             break;
  107.     }
  108.  
  109.     if (res >= EPSILON)
  110.         printf("Jacobi error: Didn't converge!\n");
  111.    
  112.     free(Qpq);
  113.     free(B);
  114. }
  115.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement