Advertisement
Guest User

C#

a guest
Feb 18th, 2013
1,919
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 20.95 KB | None | 0 0
  1. namespace Mapack
  2. {
  3.     using System;
  4.     /// <summary>
  5.     /// Determines the eigenvalues and eigenvectors of a real square matrix.
  6.     /// </summary>
  7.     /// <remarks>
  8.     /// If <c>A</c> is symmetric, then <c>A = V * D * V'</c> and <c>A = V * V'</c>
  9.     /// where the eigenvalue matrix <c>D</c> is diagonal and the eigenvector matrix <c>V</c> is orthogonal.
  10.     /// If <c>A</c> is not symmetric, the eigenvalue matrix <c>D</c> is block diagonal
  11.     /// with the real eigenvalues in 1-by-1 blocks and any complex eigenvalues,
  12.     /// <c>lambda+i*mu</c>, in 2-by-2 blocks, <c>[lambda, mu; -mu, lambda]</c>.
  13.     /// The columns of <c>V</c> represent the eigenvectors in the sense that <c>A * V = V * D</c>.
  14.     /// The matrix V may be badly conditioned, or even singular, so the validity of the equation
  15.     /// <c>A=V*D*inverse(V)</c> depends upon the condition of <c>V</c>.
  16.     /// </remarks>
  17.     public class EigenvalueDecomposition
  18.     {
  19.         private int n;              // matrix dimension
  20.         private double[] d, e;      // storage of eigenvalues.
  21.         private Matrix V;           // storage of eigenvectors.
  22.         private Matrix H;           // storage of nonsymmetric Hessenberg form.
  23.         private double[] ort;       // storage for nonsymmetric algorithm.
  24.         private double cdivr, cdivi;
  25.         private bool symmetric;
  26.  
  27.         /// <summary>Construct an eigenvalue decomposition.</summary>
  28.         public EigenvalueDecomposition(Matrix value)
  29.         {
  30.             if (value == null)
  31.             {
  32.                 throw new ArgumentNullException("value");              
  33.             }
  34.  
  35.             if (value.Rows != value.Columns)
  36.             {
  37.                 throw new ArgumentException("Matrix is not a square matrix.", "value");
  38.             }
  39.            
  40.             n = value.Columns;
  41.             V = new Matrix(n,n);
  42.             d = new double[n];
  43.             e = new double[n];
  44.    
  45.             // Check for symmetry.
  46.             this.symmetric = value.Symmetric;
  47.    
  48.             if (this.symmetric)
  49.             {
  50.                 for (int i = 0; i < n; i++)
  51.                 {
  52.                     for (int j = 0; j < n; j++)
  53.                     {
  54.                         V[i,j] = value[i,j];
  55.                     }
  56.                 }
  57.          
  58.                 // Tridiagonalize.
  59.                 this.tred2();
  60.  
  61.                 // Diagonalize.
  62.                 this.tql2();
  63.             }
  64.             else
  65.             {
  66.                 H = new Matrix(n,n);
  67.                 ort = new double[n];
  68.                      
  69.                 for (int j = 0; j < n; j++)
  70.                 {
  71.                     for (int i = 0; i < n; i++)
  72.                     {
  73.                         H[i,j] = value[i,j];
  74.                     }
  75.                 }
  76.          
  77.                 // Reduce to Hessenberg form.
  78.                 this.orthes();
  79.          
  80.                 // Reduce Hessenberg to real Schur form.
  81.                 this.hqr2();
  82.             }
  83.         }
  84.        
  85.         private void tred2()
  86.         {
  87.             // Symmetric Householder reduction to tridiagonal form.
  88.             // This is derived from the Algol procedures tred2 by Bowdler, Martin, Reinsch, and Wilkinson,
  89.             // Handbook for Auto. Comp., Vol.ii-Linear Algebra, and the corresponding Fortran subroutine in EISPACK.
  90.             for (int j = 0; j < n; j++)
  91.                 d[j] = V[n-1,j];
  92.    
  93.             // Householder reduction to tridiagonal form.
  94.             for (int i = n-1; i > 0; i--)
  95.             {
  96.                 // Scale to avoid under/overflow.
  97.                 double scale = 0.0;
  98.                 double h = 0.0;
  99.                 for (int k = 0; k < i; k++)
  100.                     scale = scale + Math.Abs(d[k]);
  101.                
  102.                 if (scale == 0.0)
  103.                 {
  104.                     e[i] = d[i-1];
  105.                     for (int j = 0; j < i; j++)
  106.                     {
  107.                         d[j] = V[i-1,j];
  108.                         V[i,j] = 0.0;
  109.                         V[j,i] = 0.0;
  110.                     }
  111.                 }
  112.                 else
  113.                 {
  114.                     // Generate Householder vector.
  115.                     for (int k = 0; k < i; k++)
  116.                     {
  117.                         d[k] /= scale;
  118.                         h += d[k] * d[k];
  119.                     }
  120.    
  121.                     double f = d[i-1];
  122.                     double g = Math.Sqrt(h);
  123.                     if (f > 0) g = -g;
  124.    
  125.                     e[i] = scale * g;
  126.                     h = h - f * g;
  127.                     d[i-1] = f - g;
  128.                     for (int j = 0; j < i; j++)
  129.                         e[j] = 0.0;
  130.          
  131.                     // Apply similarity transformation to remaining columns.
  132.                     for (int j = 0; j < i; j++)
  133.                     {
  134.                         f = d[j];
  135.                         V[j,i] = f;
  136.                         g = e[j] + V[j,j] * f;
  137.                         for (int k = j+1; k <= i-1; k++)
  138.                         {
  139.                             g += V[k,j] * d[k];
  140.                             e[k] += V[k,j] * f;
  141.                         }
  142.                         e[j] = g;
  143.                     }
  144.                            
  145.                     f = 0.0;
  146.                     for (int j = 0; j < i; j++)
  147.                     {
  148.                         e[j] /= h;
  149.                         f += e[j] * d[j];
  150.                     }
  151.                    
  152.                     double hh = f / (h + h);
  153.                     for (int j = 0; j < i; j++)
  154.                         e[j] -= hh * d[j];
  155.    
  156.                     for (int j = 0; j < i; j++)
  157.                     {
  158.                         f = d[j];
  159.                         g = e[j];
  160.                         for (int k = j; k <= i-1; k++)
  161.                             V[k,j] -= (f * e[k] + g * d[k]);
  162.    
  163.                         d[j] = V[i-1,j];
  164.                         V[i,j] = 0.0;
  165.                     }
  166.                 }
  167.                 d[i] = h;
  168.             }
  169.          
  170.             // Accumulate transformations.
  171.             for (int i = 0; i < n-1; i++)
  172.             {
  173.                 V[n-1,i] = V[i,i];
  174.                 V[i,i] = 1.0;
  175.                 double h = d[i+1];
  176.                 if (h != 0.0)
  177.                 {
  178.                     for (int k = 0; k <= i; k++)
  179.                         d[k] = V[k,i+1] / h;
  180.    
  181.                     for (int j = 0; j <= i; j++)
  182.                     {
  183.                         double g = 0.0;
  184.                         for (int k = 0; k <= i; k++)
  185.                             g += V[k,i+1] * V[k,j];
  186.                         for (int k = 0; k <= i; k++)
  187.                             V[k,j] -= g * d[k];
  188.                     }
  189.                 }
  190.        
  191.                 for (int k = 0; k <= i; k++)
  192.                     V[k,i+1] = 0.0;
  193.             }
  194.        
  195.             for (int j = 0; j < n; j++)
  196.             {
  197.                 d[j] = V[n-1,j];
  198.                 V[n-1,j] = 0.0;
  199.             }
  200.                
  201.             V[n-1,n-1] = 1.0;
  202.             e[0] = 0.0;
  203.         }
  204.          
  205.         private void tql2()
  206.         {
  207.             // Symmetric tridiagonal QL algorithm.
  208.             // This is derived from the Algol procedures tql2, by Bowdler, Martin, Reinsch, and Wilkinson,
  209.             // Handbook for Auto. Comp., Vol.ii-Linear Algebra, and the corresponding Fortran subroutine in EISPACK.
  210.             for (int i = 1; i < n; i++)
  211.                 e[i-1] = e[i];
  212.    
  213.             e[n-1] = 0.0;
  214.          
  215.             double f = 0.0;
  216.             double tst1 = 0.0;
  217.             double eps = Math.Pow(2.0,-52.0);
  218.    
  219.             for (int l = 0; l < n; l++)
  220.             {
  221.                 // Find small subdiagonal element.
  222.                 tst1 = Math.Max(tst1,Math.Abs(d[l]) + Math.Abs(e[l]));
  223.                 int m = l;
  224.                 while (m < n)
  225.                 {
  226.                     if (Math.Abs(e[m]) <= eps*tst1)
  227.                         break;
  228.                     m++;
  229.                 }
  230.          
  231.                 // If m == l, d[l] is an eigenvalue, otherwise, iterate.
  232.                 if (m > l)
  233.                 {
  234.                     int iter = 0;
  235.                     do
  236.                     {
  237.                         iter = iter + 1;  // (Could check iteration count here.)
  238.          
  239.                         // Compute implicit shift
  240.                         double g = d[l];
  241.                         double p = (d[l+1] - g) / (2.0 * e[l]);
  242.                         double r = Hypotenuse(p,1.0);
  243.                         if (p < 0)
  244.                         {
  245.                             r = -r;
  246.                         }
  247.    
  248.                         d[l] = e[l] / (p + r);
  249.                         d[l+1] = e[l] * (p + r);
  250.                         double dl1 = d[l+1];
  251.                         double h = g - d[l];
  252.                         for (int i = l+2; i < n; i++)
  253.                         {
  254.                             d[i] -= h;
  255.                         }
  256.  
  257.                         f = f + h;
  258.          
  259.                         // Implicit QL transformation.
  260.                         p = d[m];
  261.                         double c = 1.0;
  262.                         double c2 = c;
  263.                         double c3 = c;
  264.                         double el1 = e[l+1];
  265.                         double s = 0.0;
  266.                         double s2 = 0.0;
  267.                         for (int i = m-1; i >= l; i--)
  268.                         {
  269.                             c3 = c2;
  270.                             c2 = c;
  271.                             s2 = s;
  272.                             g = c * e[i];
  273.                             h = c * p;
  274.                             r = Hypotenuse(p,e[i]);
  275.                             e[i+1] = s * r;
  276.                             s = e[i] / r;
  277.                             c = p / r;
  278.                             p = c * d[i] - s * g;
  279.                             d[i+1] = h + s * (c * g + s * d[i]);
  280.          
  281.                             // Accumulate transformation.
  282.                             for (int k = 0; k < n; k++)
  283.                             {
  284.                                 h = V[k,i+1];
  285.                                 V[k,i+1] = s * V[k,i] + c * h;
  286.                                 V[k,i] = c * V[k,i] - s * h;
  287.                             }
  288.                         }
  289.                            
  290.                         p = -s * s2 * c3 * el1 * e[l] / dl1;
  291.                         e[l] = s * p;
  292.                         d[l] = c * p;
  293.          
  294.                         // Check for convergence.
  295.                     }
  296.                     while (Math.Abs(e[l]) > eps*tst1);
  297.                 }
  298.                 d[l] = d[l] + f;
  299.                 e[l] = 0.0;
  300.             }
  301.              
  302.             // Sort eigenvalues and corresponding vectors.
  303.             for (int i = 0; i < n-1; i++)
  304.             {
  305.                 int k = i;
  306.                 double p = d[i];
  307.                 for (int j = i+1; j < n; j++)
  308.                 {
  309.                     if (d[j] < p)
  310.                     {
  311.                         k = j;
  312.                         p = d[j];
  313.                     }
  314.                 }
  315.                      
  316.                 if (k != i)
  317.                 {
  318.                     d[k] = d[i];
  319.                     d[i] = p;
  320.                     for (int j = 0; j < n; j++)
  321.                     {
  322.                         p = V[j,i];
  323.                         V[j,i] = V[j,k];
  324.                         V[j,k] = p;
  325.                     }
  326.                 }
  327.             }
  328.         }
  329.          
  330.         private void orthes()
  331.         {
  332.             // Nonsymmetric reduction to Hessenberg form.
  333.             // This is derived from the Algol procedures orthes and ortran, by Martin and Wilkinson,
  334.             // Handbook for Auto. Comp., Vol.ii-Linear Algebra, and the corresponding Fortran subroutines in EISPACK.
  335.             int low = 0;
  336.             int high = n-1;
  337.          
  338.             for (int m = low+1; m <= high-1; m++)
  339.             {
  340.                 // Scale column.
  341.          
  342.                 double scale = 0.0;
  343.                 for (int i = m; i <= high; i++)
  344.                     scale = scale + Math.Abs(H[i,m-1]);
  345.    
  346.                 if (scale != 0.0)
  347.                 {
  348.                     // Compute Householder transformation.
  349.                     double h = 0.0;
  350.                     for (int i = high; i >= m; i--)
  351.                     {
  352.                         ort[i] = H[i,m-1]/scale;
  353.                         h += ort[i] * ort[i];
  354.                     }
  355.                        
  356.                     double g = Math.Sqrt(h);
  357.                     if (ort[m] > 0) g = -g;
  358.    
  359.                     h = h - ort[m] * g;
  360.                     ort[m] = ort[m] - g;
  361.          
  362.                     // Apply Householder similarity transformation
  363.                     // H = (I - u * u' / h) * H * (I - u * u') / h)
  364.                     for (int j = m; j < n; j++)
  365.                     {
  366.                         double f = 0.0;
  367.                         for (int i = high; i >= m; i--)
  368.                             f += ort[i]*H[i,j];
  369.    
  370.                         f = f/h;
  371.                         for (int i = m; i <= high; i++)
  372.                             H[i,j] -= f*ort[i];
  373.                     }
  374.          
  375.                     for (int i = 0; i <= high; i++)
  376.                     {
  377.                         double f = 0.0;
  378.                         for (int j = high; j >= m; j--)
  379.                             f += ort[j]*H[i,j];
  380.    
  381.                         f = f/h;
  382.                         for (int j = m; j <= high; j++)
  383.                             H[i,j] -= f*ort[j];
  384.                     }
  385.    
  386.                     ort[m] = scale*ort[m];
  387.                     H[m,m-1] = scale*g;
  388.                 }
  389.             }
  390.          
  391.             // Accumulate transformations (Algol's ortran).
  392.             for (int i = 0; i < n; i++)
  393.                 for (int j = 0; j < n; j++)
  394.                     V[i,j] = (i == j ? 1.0 : 0.0);
  395.    
  396.             for (int m = high-1; m >= low+1; m--)
  397.             {
  398.                 if (H[m,m-1] != 0.0)
  399.                 {
  400.                     for (int i = m+1; i <= high; i++)
  401.                         ort[i] = H[i,m-1];
  402.    
  403.                     for (int j = m; j <= high; j++)
  404.                     {
  405.                         double g = 0.0;
  406.                         for (int i = m; i <= high; i++)
  407.                             g += ort[i] * V[i,j];
  408.    
  409.                         // Double division avoids possible underflow.
  410.                         g = (g / ort[m]) / H[m,m-1];
  411.                         for (int i = m; i <= high; i++)
  412.                             V[i,j] += g * ort[i];
  413.                     }
  414.                 }
  415.             }
  416.         }
  417.          
  418.         private void cdiv(double xr, double xi, double yr, double yi)
  419.         {
  420.             // Complex scalar division.
  421.             double r;
  422.             double d;
  423.             if (Math.Abs(yr) > Math.Abs(yi))
  424.             {
  425.                 r = yi/yr;
  426.                 d = yr + r*yi;
  427.                 cdivr = (xr + r*xi)/d;
  428.                 cdivi = (xi - r*xr)/d;
  429.             }
  430.             else
  431.             {
  432.                 r = yr/yi;
  433.                 d = yi + r*yr;
  434.                 cdivr = (r*xr + xi)/d;
  435.                 cdivi = (r*xi - xr)/d;
  436.             }
  437.         }
  438.  
  439.         private void hqr2()
  440.         {
  441.             // Nonsymmetric reduction from Hessenberg to real Schur form.  
  442.             // This is derived from the Algol procedure hqr2, by Martin and Wilkinson, Handbook for Auto. Comp.,
  443.             // Vol.ii-Linear Algebra, and the corresponding  Fortran subroutine in EISPACK.
  444.             int nn = this.n;
  445.             int n = nn-1;
  446.             int low = 0;
  447.             int high = nn-1;
  448.             double eps = Math.Pow(2.0,-52.0);
  449.             double exshift = 0.0;
  450.             double p = 0;
  451.             double q = 0;
  452.             double r = 0;
  453.             double s = 0;
  454.             double z = 0;
  455.             double t;
  456.             double w;
  457.             double x;
  458.             double y;
  459.          
  460.             // Store roots isolated by balanc and compute matrix norm
  461.             double norm = 0.0;
  462.             for (int i = 0; i < nn; i++)
  463.             {
  464.                 if (i < low | i > high)
  465.                 {
  466.                     d[i] = H[i,i];
  467.                     e[i] = 0.0;
  468.                 }
  469.                    
  470.                 for (int j = Math.Max(i-1,0); j < nn; j++)
  471.                     norm = norm + Math.Abs(H[i,j]);
  472.             }
  473.          
  474.             // Outer loop over eigenvalue index
  475.             int iter = 0;
  476.             while (n >= low)
  477.             {
  478.                 // Look for single small sub-diagonal element
  479.                 int l = n;
  480.                 while (l > low)
  481.                 {
  482.                     s = Math.Abs(H[l-1,l-1]) + Math.Abs(H[l,l]);
  483.                     if (s == 0.0) s = norm;
  484.                     if (Math.Abs(H[l,l-1]) < eps * s)
  485.                         break;
  486.    
  487.                     l--;
  488.                 }
  489.                  
  490.                 // Check for convergence
  491.                 if (l == n)
  492.                 {
  493.                     // One root found
  494.                     H[n,n] = H[n,n] + exshift;
  495.                     d[n] = H[n,n];
  496.                     e[n] = 0.0;
  497.                     n--;
  498.                     iter = 0;
  499.                 }
  500.                 else if (l == n-1)
  501.                 {
  502.                     // Two roots found
  503.                     w = H[n,n-1] * H[n-1,n];
  504.                     p = (H[n-1,n-1] - H[n,n]) / 2.0;
  505.                     q = p * p + w;
  506.                     z = Math.Sqrt(Math.Abs(q));
  507.                     H[n,n] = H[n,n] + exshift;
  508.                     H[n-1,n-1] = H[n-1,n-1] + exshift;
  509.                     x = H[n,n];
  510.          
  511.                     if (q >= 0)
  512.                     {
  513.                         // Real pair
  514.                         z = (p >= 0) ? (p + z) : (p - z);
  515.                         d[n-1] = x + z;
  516.                         d[n] = d[n-1];
  517.                         if (z != 0.0)
  518.                             d[n] = x - w / z;
  519.                         e[n-1] = 0.0;
  520.                         e[n] = 0.0;
  521.                         x = H[n,n-1];
  522.                         s = Math.Abs(x) + Math.Abs(z);
  523.                         p = x / s;
  524.                         q = z / s;
  525.                         r = Math.Sqrt(p * p+q * q);
  526.                         p = p / r;
  527.                         q = q / r;
  528.          
  529.                         // Row modification
  530.                         for (int j = n-1; j < nn; j++)
  531.                         {
  532.                             z = H[n-1,j];
  533.                             H[n-1,j] = q * z + p * H[n,j];
  534.                             H[n,j] = q * H[n,j] - p * z;
  535.                         }
  536.              
  537.                         // Column modification
  538.                         for (int i = 0; i <= n; i++)
  539.                         {
  540.                             z = H[i,n-1];
  541.                             H[i,n-1] = q * z + p * H[i,n];
  542.                             H[i,n] = q * H[i,n] - p * z;
  543.                         }
  544.              
  545.                         // Accumulate transformations
  546.                         for (int i = low; i <= high; i++)
  547.                         {
  548.                             z = V[i,n-1];
  549.                             V[i,n-1] = q * z + p * V[i,n];
  550.                             V[i,n] = q * V[i,n] - p * z;
  551.                         }
  552.                     }
  553.                     else
  554.                     {
  555.                         // Complex pair
  556.                         d[n-1] = x + p;
  557.                         d[n] = x + p;
  558.                         e[n-1] = z;
  559.                         e[n] = -z;
  560.                     }
  561.                        
  562.                     n = n - 2;
  563.                     iter = 0;
  564.                 }
  565.                 else
  566.                 {
  567.                     // No convergence yet    
  568.                    
  569.                     // Form shift
  570.                     x = H[n,n];
  571.                     y = 0.0;
  572.                     w = 0.0;
  573.                     if (l < n)
  574.                     {
  575.                         y = H[n-1,n-1];
  576.                         w = H[n,n-1] * H[n-1,n];
  577.                     }
  578.          
  579.                     // Wilkinson's original ad hoc shift
  580.                     if (iter == 10)
  581.                     {
  582.                         exshift += x;
  583.                         for (int i = low; i <= n; i++)
  584.                             H[i,i] -= x;
  585.    
  586.                         s = Math.Abs(H[n,n-1]) + Math.Abs(H[n-1,n-2]);
  587.                         x = y = 0.75 * s;
  588.                         w = -0.4375 * s * s;
  589.                     }
  590.    
  591.                     // MATLAB's new ad hoc shift
  592.                     if (iter == 30)
  593.                     {
  594.                         s = (y - x) / 2.0;
  595.                         s = s * s + w;
  596.                         if (s > 0)
  597.                         {
  598.                             s = Math.Sqrt(s);
  599.                             if (y < x) s = -s;
  600.                             s = x - w / ((y - x) / 2.0 + s);
  601.                             for (int i = low; i <= n; i++)
  602.                                 H[i,i] -= s;
  603.                             exshift += s;
  604.                             x = y = w = 0.964;
  605.                         }
  606.                     }
  607.          
  608.                     iter = iter + 1;
  609.          
  610.                     // Look for two consecutive small sub-diagonal elements
  611.                     int m = n-2;
  612.                     while (m >= l)
  613.                     {
  614.                         z = H[m,m];
  615.                         r = x - z;
  616.                         s = y - z;
  617.                         p = (r * s - w) / H[m+1,m] + H[m,m+1];
  618.                         q = H[m+1,m+1] - z - r - s;
  619.                         r = H[m+2,m+1];
  620.                         s = Math.Abs(p) + Math.Abs(q) + Math.Abs(r);
  621.                         p = p / s;
  622.                         q = q / s;
  623.                         r = r / s;
  624.                         if (m == l)
  625.                             break;
  626.                         if (Math.Abs(H[m,m-1]) * (Math.Abs(q) + Math.Abs(r)) < eps * (Math.Abs(p) * (Math.Abs(H[m-1,m-1]) + Math.Abs(z) +   Math.Abs(H[m+1,m+1]))))
  627.                             break;
  628.                         m--;
  629.                     }
  630.          
  631.                     for (int i = m+2; i <= n; i++)
  632.                     {
  633.                         H[i,i-2] = 0.0;
  634.                         if (i > m+2)
  635.                             H[i,i-3] = 0.0;
  636.                     }
  637.          
  638.                     // Double QR step involving rows l:n and columns m:n
  639.                     for (int k = m; k <= n-1; k++)
  640.                     {
  641.                         bool notlast = (k != n-1);
  642.                         if (k != m)
  643.                         {
  644.                             p = H[k,k-1];
  645.                             q = H[k+1,k-1];
  646.                             r = (notlast ? H[k+2,k-1] : 0.0);
  647.                             x = Math.Abs(p) + Math.Abs(q) + Math.Abs(r);
  648.                             if (x != 0.0)
  649.                             {
  650.                                 p = p / x;
  651.                                 q = q / x;
  652.                                 r = r / x;
  653.                             }
  654.                         }
  655.                            
  656.                         if (x == 0.0)   break;
  657.    
  658.                         s = Math.Sqrt(p * p + q * q + r * r);
  659.                         if (p < 0) s = -s;
  660.                                  
  661.                         if (s != 0)
  662.                         {
  663.                             if (k != m)
  664.                                 H[k,k-1] = -s * x;
  665.                             else
  666.                                 if (l != m)
  667.                                 H[k,k-1] = -H[k,k-1];
  668.    
  669.                             p = p + s;
  670.                             x = p / s;
  671.                             y = q / s;
  672.                             z = r / s;
  673.                             q = q / p;
  674.                             r = r / p;
  675.          
  676.                             // Row modification
  677.                             for (int j = k; j < nn; j++)
  678.                             {
  679.                                 p = H[k,j] + q * H[k+1,j];
  680.                                 if (notlast)
  681.                                 {
  682.                                     p = p + r * H[k+2,j];
  683.                                     H[k+2,j] = H[k+2,j] - p * z;
  684.                                 }
  685.                                
  686.                                 H[k,j] = H[k,j] - p * x;
  687.                                 H[k+1,j] = H[k+1,j] - p * y;
  688.                             }
  689.          
  690.                             // Column modification
  691.                             for (int i = 0; i <= Math.Min(n,k+3); i++)
  692.                             {
  693.                                 p = x * H[i,k] + y * H[i,k+1];
  694.                                 if (notlast)
  695.                                 {
  696.                                     p = p + z * H[i,k+2];
  697.                                     H[i,k+2] = H[i,k+2] - p * r;
  698.                                 }
  699.                                
  700.                                 H[i,k] = H[i,k] - p;
  701.                                 H[i,k+1] = H[i,k+1] - p * q;
  702.                             }
  703.          
  704.                             // Accumulate transformations
  705.                             for (int i = low; i <= high; i++)
  706.                             {
  707.                                 p = x * V[i,k] + y * V[i,k+1];
  708.                                 if (notlast)
  709.                                 {
  710.                                     p = p + z * V[i,k+2];
  711.                                     V[i,k+2] = V[i,k+2] - p * r;
  712.                                 }
  713.                                
  714.                                 V[i,k] = V[i,k] - p;
  715.                                 V[i,k+1] = V[i,k+1] - p * q;
  716.                             }
  717.                         }
  718.                     }
  719.                 }
  720.             }
  721.                
  722.             // Backsubstitute to find vectors of upper triangular form
  723.             if (norm == 0.0)
  724.             {
  725.                 return;
  726.             }
  727.          
  728.             for (n = nn-1; n >= 0; n--)
  729.             {
  730.                 p = d[n];
  731.                 q = e[n];
  732.          
  733.                 // Real vector
  734.                 if (q == 0)
  735.                 {
  736.                     int l = n;
  737.                     H[n,n] = 1.0;
  738.                     for (int i = n-1; i >= 0; i--)
  739.                     {
  740.                         w = H[i,i] - p;
  741.                         r = 0.0;
  742.                         for (int j = l; j <= n; j++)
  743.                             r = r + H[i,j] * H[j,n];
  744.                        
  745.                         if (e[i] < 0.0)
  746.                         {
  747.                             z = w;
  748.                             s = r;
  749.                         }
  750.                         else
  751.                         {
  752.                             l = i;
  753.                             if (e[i] == 0.0)
  754.                             {
  755.                                 H[i,n] = (w != 0.0) ? (-r / w) : (-r / (eps * norm));
  756.                             }
  757.                             else
  758.                             {
  759.                                 // Solve real equations
  760.                                 x = H[i,i+1];
  761.                                 y = H[i+1,i];
  762.                                 q = (d[i] - p) * (d[i] - p) + e[i] * e[i];
  763.                                 t = (x * s - z * r) / q;
  764.                                 H[i,n] = t;
  765.                                 H[i+1,n] = (Math.Abs(x) > Math.Abs(z)) ? ((-r - w * t) / x) : ((-s - y * t) / z);
  766.                             }
  767.          
  768.                             // Overflow control
  769.                             t = Math.Abs(H[i,n]);
  770.                             if ((eps * t) * t > 1)
  771.                                 for (int j = i; j <= n; j++)
  772.                                     H[j,n] = H[j,n] / t;
  773.                         }
  774.                     }
  775.                 }
  776.                 else if (q < 0)
  777.                 {
  778.                     // Complex vector
  779.                     int l = n-1;
  780.    
  781.                     // Last vector component imaginary so matrix is triangular
  782.                     if (Math.Abs(H[n,n-1]) > Math.Abs(H[n-1,n]))
  783.                     {
  784.                         H[n-1,n-1] = q / H[n,n-1];
  785.                         H[n-1,n] = -(H[n,n] - p) / H[n,n-1];
  786.                     }
  787.                     else
  788.                     {
  789.                         cdiv(0.0,-H[n-1,n],H[n-1,n-1]-p,q);
  790.                         H[n-1,n-1] = cdivr;
  791.                         H[n-1,n] = cdivi;
  792.                     }
  793.                        
  794.                     H[n,n-1] = 0.0;
  795.                     H[n,n] = 1.0;
  796.                     for (int i = n-2; i >= 0; i--)
  797.                     {
  798.                         double ra,sa,vr,vi;
  799.                         ra = 0.0;
  800.                         sa = 0.0;
  801.                         for (int j = l; j <= n; j++)
  802.                         {
  803.                             ra = ra + H[i,j] * H[j,n-1];
  804.                             sa = sa + H[i,j] * H[j,n];
  805.                         }
  806.                        
  807.                         w = H[i,i] - p;
  808.          
  809.                         if (e[i] < 0.0)
  810.                         {
  811.                             z = w;
  812.                             r = ra;
  813.                             s = sa;
  814.                         }
  815.                         else
  816.                         {
  817.                             l = i;
  818.                             if (e[i] == 0)
  819.                             {
  820.                                 cdiv(-ra,-sa,w,q);
  821.                                 H[i,n-1] = cdivr;
  822.                                 H[i,n] = cdivi;
  823.                             }
  824.                             else
  825.                             {
  826.                                 // Solve complex equations
  827.                                 x = H[i,i+1];
  828.                                 y = H[i+1,i];
  829.                                 vr = (d[i] - p) * (d[i] - p) + e[i] * e[i] - q * q;
  830.                                 vi = (d[i] - p) * 2.0 * q;
  831.                                 if (vr == 0.0 & vi == 0.0)
  832.                                     vr = eps * norm * (Math.Abs(w) + Math.Abs(q) + Math.Abs(x) + Math.Abs(y) + Math.Abs(z));
  833.                                 cdiv(x*r-z*ra+q*sa,x*s-z*sa-q*ra,vr,vi);
  834.                                 H[i,n-1] = cdivr;
  835.                                 H[i,n] = cdivi;
  836.                                 if (Math.Abs(x) > (Math.Abs(z) + Math.Abs(q)))
  837.                                 {
  838.                                     H[i+1,n-1] = (-ra - w * H[i,n-1] + q * H[i,n]) / x;
  839.                                     H[i+1,n] = (-sa - w * H[i,n] - q * H[i,n-1]) / x;
  840.                                 }
  841.                                 else
  842.                                 {
  843.                                     cdiv(-r-y*H[i,n-1],-s-y*H[i,n],z,q);
  844.                                     H[i+1,n-1] = cdivr;
  845.                                     H[i+1,n] = cdivi;
  846.                                 }
  847.                             }
  848.          
  849.                             // Overflow control
  850.                             t = Math.Max(Math.Abs(H[i,n-1]),Math.Abs(H[i,n]));
  851.                             if ((eps * t) * t > 1)
  852.                                 for (int j = i; j <= n; j++)
  853.                                 {
  854.                                     H[j,n-1] = H[j,n-1] / t;
  855.                                     H[j,n] = H[j,n] / t;
  856.                                 }
  857.                         }
  858.                     }
  859.                 }
  860.             }
  861.          
  862.             // Vectors of isolated roots
  863.             for (int i = 0; i < nn; i++)
  864.                 if (i < low | i > high)
  865.                     for (int j = i; j < nn; j++)
  866.                         V[i,j] = H[i,j];
  867.          
  868.             // Back transformation to get eigenvectors of original matrix
  869.             for (int j = nn-1; j >= low; j--)
  870.                 for (int i = low; i <= high; i++)
  871.                 {
  872.                     z = 0.0;
  873.                     for (int k = low; k <= Math.Min(j,high); k++)
  874.                         z = z + V[i,k] * H[k,j];
  875.                     V[i,j] = z;
  876.                 }
  877.         }
  878.  
  879.         /// <summary>Returns the real parts of the eigenvalues.</summary>
  880.         public double[] RealEigenvalues
  881.         {
  882.             get
  883.             {
  884.                 return this.d;
  885.             }
  886.         }
  887.    
  888.         /// <summary>Returns the imaginary parts of the eigenvalues.</summary> 
  889.         public double[] ImaginaryEigenvalues
  890.         {
  891.             get
  892.             {
  893.                 return this.e;
  894.             }
  895.         }
  896.  
  897.         /// <summary>Returns the eigenvector matrix.</summary>
  898.         public Matrix EigenvectorMatrix
  899.         {
  900.             get
  901.             {
  902.                 return this.V;
  903.             }
  904.         }
  905.    
  906.         /// <summary>Returns the block diagonal eigenvalue matrix.</summary>
  907.         public Matrix DiagonalMatrix
  908.         {
  909.             get
  910.             {
  911.                 Matrix X = new Matrix(n, n);
  912.                 double[][] x = X.Array;
  913.    
  914.                 for (int i = 0; i < n; i++)
  915.                 {
  916.                     for (int j = 0; j < n; j++)
  917.                         x[i][j] = 0.0;
  918.    
  919.                     x[i][i] = d[i];
  920.                     if (e[i] > 0)
  921.                     {
  922.                         x[i][i+1] = e[i];
  923.                     }
  924.                     else if (e[i] < 0)
  925.                     {
  926.                         x[i][i-1] = e[i];
  927.                     }
  928.                 }
  929.                
  930.                 return X;
  931.             }          
  932.         }
  933.  
  934.         private static double Hypotenuse(double a, double b)
  935.         {
  936.             if (Math.Abs(a) > Math.Abs(b))
  937.             {
  938.                 double r = b / a;
  939.                 return Math.Abs(a) * Math.Sqrt(1 + r * r);
  940.             }
  941.  
  942.             if (b != 0)
  943.             {
  944.                 double r = a / b;
  945.                 return Math.Abs(b) * Math.Sqrt(1 + r * r);
  946.             }
  947.  
  948.             return 0.0;
  949.         }
  950.     }
  951. }
  952.  ...
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement