⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 jama_eig.h

📁 一个矩阵计算的库 包括几乎所有需要的矩阵运算 对3d计算和图形处理有很大帮助
💻 H
📖 第 1 页 / 共 2 页
字号:
#ifndef JAMA_EIG_H#define JAMA_EIG_H#include "tnt_array1d.h"#include "tnt_array2d.h"#include "tnt_math_utils.h"#include <algorithm>// for min(), max() below#include <cmath>// for abs() belowusing namespace TNT;using namespace std;namespace JAMA{/**     Computes eigenvalues and eigenvectors of a real (non-complex)    matrix. <P>    If A is symmetric, then A = V*D*V' where the eigenvalue matrix D is    diagonal and the eigenvector matrix V is orthogonal. That is,	the diagonal values of D are the eigenvalues, and    V*V' = I, where I is the identity matrix.  The columns of V     represent the eigenvectors in the sense that A*V = V*D.    <P>    If A is not symmetric, then the eigenvalue matrix D is block diagonal    with the real eigenvalues in 1-by-1 blocks and any complex eigenvalues,    a + i*b, in 2-by-2 blocks, [a, b; -b, a].  That is, if the complex    eigenvalues look like<pre>          u + iv     .        .          .      .    .            .      u - iv     .          .      .    .            .        .      a + ib       .      .    .            .        .        .        a - ib   .    .            .        .        .          .      x    .            .        .        .          .      .    y</pre>        then D looks like<pre>            u        v        .          .      .    .           -v        u        .          .      .    .             .        .        a          b      .    .            .        .       -b          a      .    .            .        .        .          .      x    .            .        .        .          .      .    y</pre>    This keeps V a real matrix in both symmetric and non-symmetric    cases, and A*V = V*D.                <p>    The matrix V may be badly    conditioned, or even singular, so the validity of the equation    A = V*D*inverse(V) depends upon the condition number of V.   <p>	(Adapted from JAMA, a Java Matrix Library, developed by jointly 	by the Mathworks and NIST; see  http://math.nist.gov/javanumerics/jama).**/template <class Real>class Eigenvalue{   /** Row and column dimension (square matrix).  */    int n;   int issymmetric; /* boolean*/   /** Arrays for internal storage of eigenvalues. */   TNT::Array1D<Real> d;         /* real part */   TNT::Array1D<Real> e;         /* img part */   /** Array for internal storage of eigenvectors. */    TNT::Array2D<Real> V;   /** Array for internal storage of nonsymmetric Hessenberg form.   @serial internal storage of nonsymmetric Hessenberg form.   */   TNT::Array2D<Real> H;      /** Working storage for nonsymmetric algorithm.   @serial working storage for nonsymmetric algorithm.   */   TNT::Array1D<Real> ort;   // Symmetric Householder reduction to tridiagonal form.   void tred2() {   //  This is derived from the Algol procedures tred2 by   //  Bowdler, Martin, Reinsch, and Wilkinson, Handbook for   //  Auto. Comp., Vol.ii-Linear Algebra, and the corresponding   //  Fortran subroutine in EISPACK.      for (int j = 0; j < n; j++) {         d[j] = V[n-1][j];      }      // Householder reduction to tridiagonal form.         for (int i = n-1; i > 0; i--) {            // Scale to avoid under/overflow.            Real scale = 0.0;         Real h = 0.0;         for (int k = 0; k < i; k++) {            scale = scale + abs(d[k]);         }         if (scale == 0.0) {            e[i] = d[i-1];            for (int j = 0; j < i; j++) {               d[j] = V[i-1][j];               V[i][j] = 0.0;               V[j][i] = 0.0;            }         } else {               // Generate Householder vector.               for (int k = 0; k < i; k++) {               d[k] /= scale;               h += d[k] * d[k];            }            Real f = d[i-1];            Real g = sqrt(h);            if (f > 0) {               g = -g;            }            e[i] = scale * g;            h = h - f * g;            d[i-1] = f - g;            for (int j = 0; j < i; j++) {               e[j] = 0.0;            }               // Apply similarity transformation to remaining columns.               for (int j = 0; j < i; j++) {               f = d[j];               V[j][i] = f;               g = e[j] + V[j][j] * f;               for (int k = j+1; k <= i-1; k++) {                  g += V[k][j] * d[k];                  e[k] += V[k][j] * f;               }               e[j] = g;            }            f = 0.0;            for (int j = 0; j < i; j++) {               e[j] /= h;               f += e[j] * d[j];            }            Real hh = f / (h + h);            for (int j = 0; j < i; j++) {               e[j] -= hh * d[j];            }            for (int j = 0; j < i; j++) {               f = d[j];               g = e[j];               for (int k = j; k <= i-1; k++) {                  V[k][j] -= (f * e[k] + g * d[k]);               }               d[j] = V[i-1][j];               V[i][j] = 0.0;            }         }         d[i] = h;      }         // Accumulate transformations.         for (int i = 0; i < n-1; i++) {         V[n-1][i] = V[i][i];         V[i][i] = 1.0;         Real h = d[i+1];         if (h != 0.0) {            for (int k = 0; k <= i; k++) {               d[k] = V[k][i+1] / h;            }            for (int j = 0; j <= i; j++) {               Real g = 0.0;               for (int k = 0; k <= i; k++) {                  g += V[k][i+1] * V[k][j];               }               for (int k = 0; k <= i; k++) {                  V[k][j] -= g * d[k];               }            }         }         for (int k = 0; k <= i; k++) {            V[k][i+1] = 0.0;         }      }      for (int j = 0; j < n; j++) {         d[j] = V[n-1][j];         V[n-1][j] = 0.0;      }      V[n-1][n-1] = 1.0;      e[0] = 0.0;   }    // Symmetric tridiagonal QL algorithm.      void tql2 () {   //  This is derived from the Algol procedures tql2, by   //  Bowdler, Martin, Reinsch, and Wilkinson, Handbook for   //  Auto. Comp., Vol.ii-Linear Algebra, and the corresponding   //  Fortran subroutine in EISPACK.         for (int i = 1; i < n; i++) {         e[i-1] = e[i];      }      e[n-1] = 0.0;         Real f = 0.0;      Real tst1 = 0.0;      Real eps = pow(2.0,-52.0);      for (int l = 0; l < n; l++) {         // Find small subdiagonal element            tst1 = max(tst1,abs(d[l]) + abs(e[l]));         int m = l;        // Original while-loop from Java code         while (m < n) {            if (abs(e[m]) <= eps*tst1) {               break;            }            m++;         }            // If m == l, d[l] is an eigenvalue,         // otherwise, iterate.            if (m > l) {            int iter = 0;            do {               iter = iter + 1;  // (Could check iteration count here.)                  // Compute implicit shift                  Real g = d[l];               Real p = (d[l+1] - g) / (2.0 * e[l]);               Real r = hypot(p,1.0);               if (p < 0) {                  r = -r;               }               d[l] = e[l] / (p + r);               d[l+1] = e[l] * (p + r);               Real dl1 = d[l+1];               Real h = g - d[l];               for (int i = l+2; i < n; i++) {                  d[i] -= h;               }               f = f + h;                  // Implicit QL transformation.                  p = d[m];               Real c = 1.0;               Real c2 = c;               Real c3 = c;               Real el1 = e[l+1];               Real s = 0.0;               Real s2 = 0.0;               for (int i = m-1; i >= l; i--) {                  c3 = c2;                  c2 = c;                  s2 = s;                  g = c * e[i];                  h = c * p;                  r = hypot(p,e[i]);                  e[i+1] = s * r;                  s = e[i] / r;                  c = p / r;                  p = c * d[i] - s * g;                  d[i+1] = h + s * (c * g + s * d[i]);                     // Accumulate transformation.                     for (int k = 0; k < n; k++) {                     h = V[k][i+1];                     V[k][i+1] = s * V[k][i] + c * h;                     V[k][i] = c * V[k][i] - s * h;                  }               }               p = -s * s2 * c3 * el1 * e[l] / dl1;               e[l] = s * p;               d[l] = c * p;                  // Check for convergence.               } while (abs(e[l]) > eps*tst1);         }         d[l] = d[l] + f;         e[l] = 0.0;      }           // Sort eigenvalues and corresponding vectors.         for (int i = 0; i < n-1; i++) {         int k = i;         Real p = d[i];         for (int j = i+1; j < n; j++) {            if (d[j] < p) {               k = j;               p = d[j];            }         }         if (k != i) {            d[k] = d[i];            d[i] = p;            for (int j = 0; j < n; j++) {               p = V[j][i];               V[j][i] = V[j][k];               V[j][k] = p;            }         }      }   }   // Nonsymmetric reduction to Hessenberg form.   void orthes () {         //  This is derived from the Algol procedures orthes and ortran,      //  by Martin and Wilkinson, Handbook for Auto. Comp.,      //  Vol.ii-Linear Algebra, and the corresponding      //  Fortran subroutines in EISPACK.         int low = 0;      int high = n-1;         for (int m = low+1; m <= high-1; m++) {            // Scale column.            Real scale = 0.0;         for (int i = m; i <= high; i++) {            scale = scale + abs(H[i][m-1]);         }         if (scale != 0.0) {               // Compute Householder transformation.               Real h = 0.0;            for (int i = high; i >= m; i--) {               ort[i] = H[i][m-1]/scale;               h += ort[i] * ort[i];            }            Real g = sqrt(h);            if (ort[m] > 0) {               g = -g;            }            h = h - ort[m] * g;            ort[m] = ort[m] - g;               // Apply Householder similarity transformation            // H = (I-u*u'/h)*H*(I-u*u')/h)               for (int j = m; j < n; j++) {               Real f = 0.0;               for (int i = high; i >= m; i--) {                  f += ort[i]*H[i][j];               }               f = f/h;               for (int i = m; i <= high; i++) {                  H[i][j] -= f*ort[i];               }           }              for (int i = 0; i <= high; i++) {               Real f = 0.0;               for (int j = high; j >= m; j--) {                  f += ort[j]*H[i][j];               }               f = f/h;               for (int j = m; j <= high; j++) {                  H[i][j] -= f*ort[j];               }            }            ort[m] = scale*ort[m];            H[m][m-1] = scale*g;         }      }         // Accumulate transformations (Algol's ortran).      for (int i = 0; i < n; i++) {         for (int j = 0; j < n; j++) {            V[i][j] = (i == j ? 1.0 : 0.0);         }      }      for (int m = high-1; m >= low+1; m--) {         if (H[m][m-1] != 0.0) {            for (int i = m+1; i <= high; i++) {               ort[i] = H[i][m-1];            }            for (int j = m; j <= high; j++) {               Real g = 0.0;               for (int i = m; i <= high; i++) {                  g += ort[i] * V[i][j];               }               // Double division avoids possible underflow               g = (g / ort[m]) / H[m][m-1];               for (int i = m; i <= high; i++) {                  V[i][j] += g * ort[i];               }            }         }      }   }   // Complex scalar division.   Real cdivr, cdivi;   void cdiv(Real xr, Real xi, Real yr, Real yi) {      Real r,d;      if (abs(yr) > abs(yi)) {         r = yi/yr;         d = yr + r*yi;         cdivr = (xr + r*xi)/d;         cdivi = (xi - r*xr)/d;      } else {         r = yr/yi;         d = yi + r*yr;         cdivr = (r*xr + xi)/d;         cdivi = (r*xi - xr)/d;      }   }   // Nonsymmetric reduction from Hessenberg to real Schur form.   void hqr2 () {         //  This is derived from the Algol procedure hqr2,      //  by Martin and Wilkinson, Handbook for Auto. Comp.,      //  Vol.ii-Linear Algebra, and the corresponding      //  Fortran subroutine in EISPACK.         // Initialize         int nn = this->n;      int n = nn-1;      int low = 0;      int high = nn-1;      Real eps = pow(2.0,-52.0);      Real exshift = 0.0;      Real p=0,q=0,r=0,s=0,z=0,t,w,x,y;         // Store roots isolated by balanc and compute matrix norm         Real norm = 0.0;      for (int i = 0; i < nn; i++) {         if ((i < low) || (i > high)) {            d[i] = H[i][i];            e[i] = 0.0;         }         for (int j = max(i-1,0); j < nn; j++) {            norm = norm + abs(H[i][j]);         }      }         // Outer loop over eigenvalue index         int iter = 0;      while (n >= low) {            // Look for single small sub-diagonal element            int l = n;         while (l > low) {            s = abs(H[l-1][l-1]) + abs(H[l][l]);            if (s == 0.0) {               s = norm;            }            if (abs(H[l][l-1]) < eps * s) {               break;            }            l--;         }                // Check for convergence         // One root found            if (l == n) {            H[n][n] = H[n][n] + exshift;            d[n] = H[n][n];            e[n] = 0.0;            n--;            iter = 0;            // Two roots found   

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -