头文件:
/* * Copyright (c) 2008-2011 Zhang Ming (M. Zhang), [email protected] * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation, either version 2 or any later version. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. A copy of the GNU General Public License is available at: * http://www.fsf.org/licensing/licenses */ /***************************************************************************** * evd.h * * Class template of eigenvalues and eigenvectors decomposition. * * For a real matrix A, we have A*V = V*D, where the eigenvalue matrix D is * diagonal and the eigenvector matrix V is linear independence. That is the * kth diagonal value of D is the eigenvalue and the kth column of V * represents the corresponding eigenvector of D[k][k]. If A is symmetric, * then V is a orthogonal matrix, which means A = V*D*V', and eigenvalues * are all real numbers. * * 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 * * u + iv . . . . . * . u - iv . . . . * . . a + ib . . . * . . . a - ib . . * . . . . x . * . . . . . y * * then D looks like * * u v . . . . * -v u . . . . * . . a b . . * . . -b a . . * . . . . x . * . . . . . y * * This keeps V a real matrix in both symmetric and non-symmetric cases, and * A*V = V*D. * * 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. * * Adapted form Template Numerical Toolkit. * * Zhang Ming, 2010-01 (revised 2010-12), Xi'an Jiaotong University. *****************************************************************************/ #ifndef EVD_H #define EVD_H #include <matrix.h> namespace splab { template <typename Real> class EVD { public: EVD(); ~EVD(); // decomposition void dec( const Matrix<Real> &A ); // the eigenvalues are real or complex bool isSymmetric() const; bool isComplex( Real tol=Real(EPS) ); // get eigenvectors Matrix<Real> getV() const; Matrix<complex<Real> > getCV(); // get eigenvalues Vector<Real> getD() const; Vector<complex<Real> > getCD(); // Matrix<Real> getDM(); // Matrix<complex<Real> > getCDM(); private: int n; bool symmetric; Real cdivr, cdivi; // eigenvalues and its real and image part Matrix<Real> V; Vector<Real> d; Vector<Real> e; // temporary storage for internal variables Vector<Real> ort; Matrix<Real> H; void tred2(); void tql2(); void cdiv( Real xr, Real xi, Real yr, Real yi ); void hqr2(); void others(); void normalized(); }; // class EVD #include <evd-impl.h> } // namespace splab #endif // EVD_H
实现文件:
/* * Copyright (c) 2008-2011 Zhang Ming (M. Zhang), [email protected] * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation, either version 2 or any later version. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. A copy of the GNU General Public License is available at: * http://www.fsf.org/licensing/licenses */ /***************************************************************************** * evd-impl.h * * Implementation for EVD class. * * Zhang Ming, 2010-01 (revised 2010-12), Xi'an Jiaotong University. *****************************************************************************/ /** * constructor and destructor */ template<typename Real> EVD<Real>::EVD() : symmetric(true) { } template<typename Real> EVD<Real>::~EVD() { } /** * Check for symmetry, then construct the eigenvalue decomposition */ template <typename Real> void EVD<Real>::dec( const Matrix<Real> &A ) { n = A.cols(); assert( A.rows() == n ); V = Matrix<Real>(n,n); d = Vector<Real>(n); e = Vector<Real>(n); symmetric = true; for( int j=0; (j<n) && symmetric; ++j ) for( int i=0; (i<n) && symmetric; ++i ) symmetric = ( A[i][j] == A[j][i] ); if(symmetric) { for( int i=0; i<n; ++i ) for( int j=0; j<n; ++j ) V[i][j] = A[i][j]; // tridiagonalize. tred2(); // diagonalize. tql2(); } else { H = Matrix<Real>(n,n); ort = Vector<Real>(n); for( int j=0; j<n; ++j ) for( int i=0; i<n; ++i ) H[i][j] = A[i][j]; // reduce to Hessenberg form others(); // reduce Hessenberg to real Schur form hqr2(); } // normalized(); } /** * If the matrix is symmetric, then return true. */ template <typename Real> bool EVD<Real>::isSymmetric() const { return symmetric; } /** * If the eigenvalues are complex, then return true. */ template <typename Real> bool EVD<Real>::isComplex( Real tol ) { if( symmetric ) return false; Real crt = 0; for( int i=0; i<n; ++i ) crt += abs(e[i]); if( crt > tol ) return true; else return false; } /** * Return the REAL eigenvector matrix */ template <typename Real> inline Matrix<Real> EVD<Real>::getV() const { return V; } /** * Return the COMPLEX eigenvector matrix */ template <typename Real> Matrix<complex<Real> > EVD<Real>::getCV() { Matrix<complex<Real> > cV(n,n); int col = 0; while( col < n-1 ) { // eigenvalues d[col] and d[col+1] are complex if( d[col] == d[col+1] ) { for( int i=0; i<n; ++i ) { cV[i][col] = complex<Real>( V[i][col], V[i][col+1] ); cV[i][col+1] = conj(cV[i][col]); } col += 2; } // eigenvalue d[col] is real else { for( int i=0; i<n; ++i ) cV[i][col] = V[i][col]; col += 1; } } // eigenvalue d[n-1] is real if( col == n-1 ) { for( int i=0; i<n; ++i ) cV[i][col] = V[i][col]; col += 1; } return cV; } /** * Return the real eigenvalues */ template <typename Real> inline Vector<Real> EVD<Real>::getD() const { return d; } /** * Return the complex eigenvalues */ template <typename Real> inline Vector<complex<Real> > EVD<Real>::getCD() { return complexVector( d, e ); } ///** // * Computes the block diagonal eigenvalue matrix. // * If the original matrix 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. // */ //template <typename Real> //Matrix<Real> EVD<Real>::getDM() //{ // Matrix<Real> tmp(n,n); // for( int i=0; i<n; ++i ) // { // tmp[i][i] = d[i]; // // if( e[i] > 0 ) // tmp[i][i+1] = e[i]; // else if( e[i] < 0 ) // tmp[i][i-1] = e[i]; // } // // return tmp; //} // // ///** // * Return the COMPLEX diagonal eigenvalue matrix. // */ //template <typename Real> //Matrix<complex<Real> > EVD<Real>::getCDM() //{ // Matrix<complex<Real> > cD(n,n); // for( int i=0; i<n; ++i ) // cD[i][i] = complex<Real>( d[i], e[i] ); // // return cD; //} /** * Symmetric Householder reduction to tridiagonal form. */ template <typename Real> void EVD<Real>::tred2() { 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; Real h = 0; for( int k=0; k<i; ++k ) scale += abs(d[k]); if( scale == 0 ) { e[i] = d[i-1]; for( int j=0; j<i; ++j ) { d[j] = V[i-1][j]; V[i][j] = 0; V[j][i] = 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; // 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; 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; } } d[i] = h; } // accumulate transformations for( int i=0; i<n-1; i++ ) { V[n-1][i] = V[i][i]; V[i][i] = 1; Real h = d[i+1]; if( h != 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; 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; } for( int j=0; j<n; ++j ) { d[j] = V[n-1][j]; V[n-1][j] = 0; } V[n-1][n-1] = 1; e[0] = 0; } /** * Symmetric tridiagonal QL algorithm. */ template <typename Real> void EVD<Real>::tql2() { for( int i=1; i<n; ++i ) e[i-1] = e[i]; e[n-1] = 0; Real f = 0; Real tst1 = 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; // 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 += h; // implicit QL transformation. p = d[m]; Real c = 1; Real c2 = c; Real c3 = c; Real el1 = e[l+1]; Real s = 0; Real s2 = 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; } while( abs(e[l]) > eps*tst1 ); } d[l] += f; e[l] = 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 ) swap( V[j][i], V[j][k] ); } } } /** * Nonsymmetric reduction to Hessenberg form. */ template <typename Real> void EVD<Real>::others() { int low = 0; int high = n-1; for( int m=low+1; m<=high-1; ++m ) { // scale column. Real scale = 0; for( int i=m; i<=high; ++i ) scale += abs(H[i][m-1]); if( scale != 0 ) { // compute Householder transformation. Real h = 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. for( int j=m; j<n; ++j ) { Real f = 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; 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 ; for( int m=high-1; m>=low+1; --m ) if( H[m][m-1] != 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; 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. */ template <typename Real> void EVD<Real>::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. */ template <typename Real> void EVD<Real>::hqr2() { // 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; 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; for( int i=0; i<nn; ++i ) { if( (i < low) || (i > high) ) { d[i] = H[i][i]; e[i] = 0; } for( int j=max(i-1,0); j<nn; ++j ) 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 ) s = norm; if( abs(H[l][l-1]) < eps*s ) break; l--; } // one root found if( l == n ) { H[n][n] = H[n][n] + exshift; d[n] = H[n][n]; e[n] = 0; n--; iter = 0; } // two roots found else if( l == n-1 ) { w = H[n][n-1] * H[n-1][n]; p = (H[n-1][n-1] - H[n][n]) / 2.0; q = p * p + w; z = sqrt(abs(q)); H[n][n] = H[n][n] + exshift; H[n-1][n-1] = H[n-1][n-1] + exshift; x = H[n][n]; // real pair if( q >= 0 ) { if( p >= 0 ) z = p + z; else z = p - z; d[n-1] = x + z; d[n] = d[n-1]; if( z != 0 ) d[n] = x - w / z; e[n-1] = 0; e[n] = 0; x = H[n][n-1]; s = abs(x) + abs(z); p = x / s; q = z / s; r = sqrt(p * p+q * q); p = p / r; q = q / r; // row modification for( int j=n-1; j<nn; ++j ) { z = H[n-1][j]; H[n-1][j] = q * z + p * H[n][j]; H[n][j] = q * H[n][j] - p * z; } // column modification for( int i=0; i<=n; ++i ) { z = H[i][n-1]; H[i][n-1] = q * z + p * H[i][n]; H[i][n] = q * H[i][n] - p * z; } // accumulate transformations for( int i=low; i<=high; ++i ) { z = V[i][n-1]; V[i][n-1] = q * z + p * V[i][n]; V[i][n] = q * V[i][n] - p * z; } } // complex pair else { d[n-1] = x + p; d[n] = x + p; e[n-1] = z; e[n] = -z; } n = n - 2; iter = 0; } else { // form shift x = H[n][n]; y = 0; w = 0; if( l < n ) { y = H[n-1][n-1]; w = H[n][n-1] * H[n-1][n]; } // Wilkinson's original ad hoc shift if( iter == 10 ) { exshift += x; for( int i = low; i <= n; ++i ) H[i][i] -= x; s = abs(H[n][n-1]) + abs(H[n-1][n-2]); x = y = 0.75 * s; w = -0.4375 * s * s; } // MATLAB's new ad hoc shift if( iter == 30 ) { s = ( y - x ) / 2.0; s = s * s + w; if( s > 0 ) { s = sqrt(s); if( y < x ) s = -s; s = x - w / ( (y - x) / 2.0 + s ); for( int i=low; i<=n; ++i ) H[i][i] -= s; exshift += s; x = y = w = 0.964; } } iter = iter + 1; // Look for two consecutive small sub-diagonal elements. int m = n-2; while( m >= l ) { z = H[m][m]; r = x - z; s = y - z; p = (r * s - w) / H[m+1][m] + H[m][m+1]; q = H[m+1][m+1] - z - r - s; r = H[m+2][m+1]; s = abs(p) + abs(q) + abs(r); p = p / s; q = q / s; r = r / s; if( m == l ) break; if( abs(H[m][m-1]) * (abs(q) + abs(r)) < eps * ( abs(p) * ( abs(H[m-1][m-1]) + abs(z) + abs(H[m+1][m+1]) ) ) ) break; m--; } for( int i=m+2; i<=n; ++i ) { H[i][i-2] = 0; if( i > m+2 ) H[i][i-3] = 0; } // double QR step involving rows l:n and columns m:n for( int k=m; k<=n-1; ++k ) { int notlast = ( k != n-1 ); if( k != m ) { p = H[k][k-1]; q = H[k+1][k-1]; r = (notlast ? H[k+2][k-1] : 0); x = abs(p) + abs(q) + abs(r); if( x != 0 ) { p = p / x; q = q / x; r = r / x; } } if( x == 0 ) break; s = sqrt(p * p + q * q + r * r); if( p < 0 ) s = -s; if( s != 0 ) { if( k != m ) H[k][k-1] = -s * x; else if( l != m ) H[k][k-1] = -H[k][k-1]; p = p + s; x = p / s; y = q / s; z = r / s; q = q / p; r = r / p; // row modification for( int j=k; j<nn; ++j ) { p = H[k][j] + q * H[k+1][j]; if( notlast ) { p = p + r * H[k+2][j]; H[k+2][j] = H[k+2][j] - p * z; } H[k][j] = H[k][j] - p * x; H[k+1][j] = H[k+1][j] - p * y; } // column modification for( int i=0; i<=min(n,k+3); ++i ) { p = x * H[i][k] + y * H[i][k+1]; if(notlast) { p = p + z * H[i][k+2]; H[i][k+2] = H[i][k+2] - p * r; } H[i][k] = H[i][k] - p; H[i][k+1] = H[i][k+1] - p * q; } // accumulate transformations for( int i=low; i<=high; ++i ) { p = x * V[i][k] + y * V[i][k+1]; if(notlast) { p = p + z * V[i][k+2]; V[i][k+2] = V[i][k+2] - p * r; } V[i][k] = V[i][k] - p; V[i][k+1] = V[i][k+1] - p * q; } } // (s != 0 ) } // k loop } // check convergence } // while ( n >= low ) // Backsubstitute to find vectors of upper triangular form. if( norm == 0 ) return; for( n=nn-1; n>=0; --n ) { p = d[n]; q = e[n]; // real vector if( q == 0 ) { int l = n; H[n][n] = 1; for( int i=n-1; i>=0; --i ) { w = H[i][i] - p; r = 0; for( int j=l; j<=n; ++j ) r = r + H[i][j] * H[j][n]; if( e[i] < 0 ) { z = w; s = r; } else { l = i; if( e[i] == 0 ) { if( w != 0 ) H[i][n] = -r / w; else H[i][n] = -r / (eps * norm); } // solve real equations else { x = H[i][i+1]; y = H[i+1][i]; q = (d[i] - p) * (d[i] - p) + e[i] * e[i]; t = (x * s - z * r) / q; H[i][n] = t; if( abs(x) > abs(z) ) H[i+1][n] = (-r - w * t) / x; else H[i+1][n] = ( -s - y * t ) / z; } // overflow control t = abs(H[i][n]); if( (eps*t)*t > 1 ) for( int j=i; j<=n; ++j ) H[j][n] = H[j][n] / t; } } } // complex vector else if( q < 0 ) { int l = n-1; // last vector component imaginary so matrix is triangular if( abs(H[n][n-1]) > abs(H[n-1][n]) ) { H[n-1][n-1] = q / H[n][n-1]; H[n-1][n] = -(H[n][n] - p) / H[n][n-1]; } else { cdiv(0,-H[n-1][n],H[n-1][n-1]-p,q); H[n-1][n-1] = cdivr; H[n-1][n] = cdivi; } H[n][n-1] = 0; H[n][n] = 1; for( int i=n-2; i>=0; --i ) { Real ra,sa,vr,vi; ra = 0; sa = 0; for( int j=l; j<=n; ++j ) { ra = ra + H[i][j] * H[j][n-1]; sa = sa + H[i][j] * H[j][n]; } w = H[i][i] - p; if( e[i] < 0 ) { z = w; r = ra; s = sa; } else { l = i; if( e[i] == 0 ) { cdiv(-ra,-sa,w,q); H[i][n-1] = cdivr; H[i][n] = cdivi; } else { // solve complex equations x = H[i][i+1]; y = H[i+1][i]; vr = (d[i]-p) * (d[i]-p) + e[i]*e[i] - q*q; vi = (d[i]-p) * 2.0 * q; if( (vr == 0) && (vi == 0) ) vr = eps * norm * ( abs(w) + abs(q) + abs(x) + abs(y) + abs(z) ); cdiv( x*r-z*ra+q*sa, x*s-z*sa-q*ra, vr, vi ); H[i][n-1] = cdivr; H[i][n] = cdivi; if( abs(x) > (abs(z)+abs(q)) ) { H[i+1][n-1] = (-ra - w*H[i][n-1] + q*H[i][n]) / x; H[i+1][n] = (-sa - w*H[i][n] - q*H[i][n-1]) / x; } else { cdiv( -r-y*H[i][n-1], -s-y*H[i][n], z, q ); H[i+1][n-1] = cdivr; H[i+1][n] = cdivi; } } // overflow control t = max( abs(H[i][n-1]), abs(H[i][n]) ); if( (eps*t)*t > 1 ) for( int j=i; j<=n; ++j ) { H[j][n-1] = H[j][n-1] / t; H[j][n] = H[j][n] / t; } } } } } // vectors of isolated roots for( int i=0; i<nn; ++i ) if( (i < low) || (i > high) ) for( int j=i; j<nn; ++j ) V[i][j] = H[i][j]; // Back transformation to get eigenvectors of original matrix. for( int j=nn-1; j>=low; --j ) for( int i=low; i<=high; ++i ) { z = 0; for( int k=low; k<=min(j,high); ++k ) z += V[i][k] * H[k][j]; V[i][j] = z; } } /** * Making normalization and sorting. */ template <typename Real> void EVD<Real>::normalized() { Real norm2; for( int j=0; j<n; ++j ) { norm2 = 0; for( int i=0; i<n; ++i ) norm2 += V[i][j]*V[i][j]; norm2 = sqrt(norm2); for( int i=0; i<n; ++i ) V[i][j] /= norm2; } }
测试代码:
/***************************************************************************** * evd_test.cpp * * EVD class testing. * * Zhang Ming, 2010-01 (revised 2010-12), Xi'an Jiaotong University. *****************************************************************************/ #define BOUNDS_CHECK #include <iostream> #include <iomanip> #include <evd.h> using namespace std; using namespace splab; typedef double Type; const int N = 2; int main() { Matrix<Type> B(N,N); B[0][0] = 3.0; B[0][1] = -2.0; B[1][0] = -2.0; B[1][1] = 4.0; Matrix<Type> A(2*N,2*N), D, V; Matrix<complex<Type> > cA(2*N,2*N), cD, cV; for( int i=0; i<N; ++i ) for( int j=0; j<N; ++j ) { A[i][j] = B[i][j]; A[i][j+N] = -B[j][i]; A[i+N][j] = B[j][i]; A[i+N][j+N] = B[i][j]; } // A = B; cA = complexMatrix(A); cout << setiosflags(ios::fixed) << setprecision(2); cout << "The original matrix A : " << A << endl; EVD<Type> eig; eig.dec(A); if( !eig.isComplex() ) { V = eig.getV(); D = diag(eig.getD()); cout << "The eigenvectors matrix V : " << V << endl; cout << "The eigenvalue D : " << D << endl; cout << "The V'*V : " << trMult(V,V) << endl; cout << "The A*V - V*D : " << A*V - V*D << endl; } else { cV = eig.getCV(); cD = diag(eig.getCD()); cout << "The complex eigenvectors matrix V : " << cV << endl; cout << "The complex eigenvalue D : " << cD << endl; cout << "The A*V - V*D : " << cA*cV - cV*cD << endl; } return 0; }
运行结果:
The original matrix A : size: 4 by 4 3.00 -2.00 -3.00 2.00 -2.00 4.00 2.00 -4.00 3.00 -2.00 3.00 -2.00 -2.00 4.00 -2.00 4.00 The complex eigenvectors matrix V : size: 4 by 4 (-0.06,-0.61) (-0.06,0.61) (0.06,-0.79) (0.06,0.79) (0.08,0.78) (0.08,-0.78) (0.05,-0.61) (0.05,0.61) (-0.61,0.06) (-0.61,-0.06) (-0.79,-0.06) (-0.79,0.06) (0.78,-0.08) (0.78,0.08) (-0.61,-0.05) (-0.61,0.05) The complex eigenvalue D : size: 4 by 4 (5.56,5.56) (0.00,0.00) (0.00,0.00) (0.00,0.00) (0.00,0.00) (5.56,-5.56) (0.00,0.00) (0.00,0.00) (0.00,0.00) (0.00,0.00) (1.44,1.44) (0.00,0.00) (0.00,0.00) (0.00,0.00) (0.00,0.00) (1.44,-1.44) The A*V - V*D : size: 4 by 4 (0.00,-0.00) (0.00,0.00) (-0.00,0.00) (-0.00,-0.00) (-0.00,0.00) (-0.00,-0.00) (0.00,0.00) (0.00,-0.00) (0.00,-0.00) (0.00,0.00) (0.00,0.00) (0.00,-0.00) (-0.00,-0.00) (-0.00,0.00) (0.00,-0.00) (0.00,0.00) Process returned 0 (0x0) execution time : 0.094 s Press any key to continue.