头文件:
/* * 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 */ /***************************************************************************** * cevd.h * * Class template of eigenvalues decomposition for complex matrix. * * For a complex 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 diagonal values of D are the eigenvalues and the columns of V represent * the corresponding eigenvectors of D. If A is Hermitian, then V is a unitary * matrix, which means A = V*D*V', and eigenvalues are all real numbers. * * 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. * * Zhang Ming, 2010-12, Xi'an Jiaotong University. *****************************************************************************/ #ifndef CEVD_H #define CEVD_H #include <evd.h> namespace splab { template <typename Type> class CEVD { public: CEVD(); ~CEVD(); // decomposition void dec( const Matrix<complex<Type> > &A ); // the eigenvalues are real or complex bool isHertimian() const; // get eigenvectors and Matrix<complex<Type> > getV() const; Vector<complex<Type> > getD() const; Vector<Type> getRD() const; private: bool hermitian; // eigenvectors and eigenvalues Matrix<complex<Type> > V; Vector<complex<Type> > d; Vector<Type> rd; }; // class CEVD #include <cevd-impl.h> } // namespace splab #endif // CEVD_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 */ /***************************************************************************** * cevd-impl.h * * Implementation for CEVD class. * * Zhang Ming, 2010-12, Xi'an Jiaotong University. *****************************************************************************/ /** * constructor and destructor */ template<typename Type> CEVD<Type>::CEVD() : hermitian(true) { } template<typename Type> CEVD<Type>::~CEVD() { } /** * Check for symmetry, then construct the eigenvalue decomposition */ template <typename Type> void CEVD<Type>::dec( const Matrix<complex<Type> > &A ) { int N = A.cols(); assert( A.rows() == N ); V = Matrix<complex<Type> >(N,N); Matrix<Type> S(2*N,2*N); for( int i=0; i<N; ++i ) for( int j=0; j<N; ++j ) { S[i][j] = A[i][j].real(); S[i][j+N] = -A[i][j].imag(); S[i+N][j] = -S[i][j+N]; S[i+N][j+N] = S[i][j]; } EVD<Type> eig; eig.dec(S); if( eig.isSymmetric() ) { hermitian = true; rd = Vector<Type>(N); Matrix<Type> RV = eig.getV(); Vector<Type> Rd = eig.getD(); for( int i=0; i<N; ++i ) rd[i] = Rd[2*i]; for( int j=0; j<N; ++j ) { int j2 = 2*j; for( int i=0; i<N; ++i ) V[i][j] = complex<Type>( RV[i][j2], RV[i+N][j2] ); } } else { hermitian = false; d = Vector<complex<Type> >(N); Matrix<complex<Type> > cV = eig.getCV(); Vector<complex<Type> > cd = eig.getCD(); for( int i=0; i<N; ++i ) d[i] = cd[2*i]; for( int j=0; j<N; ++j ) { int j2 = 2*j; for( int i=0; i<N; ++i ) V[i][j] = complex<Type>( cV[i][j2].real()-cV[i+N][j2].imag(), cV[i][j2].imag()+cV[i+N][j2].real() ); } } } /** * If the matrix is Hermitian, then return true. */ template <typename Type> bool CEVD<Type>::isHertimian() const { return hermitian; } /** * Return the COMPLEX eigenvector matrix */ template <typename Type> inline Matrix<complex<Type> > CEVD<Type>::getV() const { return V; } /** * Return the complex eigenvalues vector. */ template <typename Type> inline Vector<complex<Type> > CEVD<Type>::getD() const { return d; } /** * Return the real eigenvalues vector. */ template <typename Type> inline Vector<Type> CEVD<Type>::getRD() const { return rd; }
测试代码:
/***************************************************************************** * cevd_test.cpp * * CEVD class testing. * * Zhang Ming, 2010-12, Xi'an Jiaotong University. *****************************************************************************/ #define BOUNDS_CHECK #include <iostream> #include <iomanip> #include <cevd.h> using namespace std; using namespace splab; typedef double Type; const int N = 4; int main() { Matrix<Type> B(N,N); B[0][0] = 3.0; B[0][1] = -2.0; B[0][2] = -0.9; B[0][3] = 0.0; B[1][0] = -2.0; B[1][1] = 4.0; B[1][2] = 1.0; B[1][3] = 0.0; B[2][0] = 0.0; B[2][1] = 0.0; B[2][2] = -1.0; B[2][3] = 0.0; B[3][0] = -0.5; B[3][1] = -0.5; B[3][2] = 0.1; B[3][3] = 1.0; Matrix<complex<Type> > A = complexMatrix( B, elemMult(B,B) ); // A = multTr(A,A); cout << setiosflags(ios::fixed) << setprecision(2); cout << "The original complex matrix A : " << A << endl; CEVD<Type> eig; eig.dec(A); if( eig.isHertimian() ) { Matrix<complex<Type> > V = eig.getV(); Vector<Type> D = eig.getRD(); Matrix<complex<Type> > DM = diag( complexVector(D) ); cout << "The eigenvectors matrix V is : " << V << endl; cout << "The eigenvalue D is : " << diag(D) << endl; cout << "The V'*V : " << trMult(V,V) << endl; cout << "The A*V - V*D : " << A*V - V*DM << endl; } else { Matrix<complex<Type> > V = eig.getV(); Vector<complex<Type> > D = eig.getD(); Matrix<complex<Type> > DM = diag( D ); cout << "The complex eigenvectors matrix V : " << V << endl; cout << "The complex eigenvalue D : " << DM << endl; cout << "The A*V - V*D : " << A*V - V*DM << endl; } return 0; }
运行结果:
The original complex matrix A : size: 4 by 4 (3.00,9.00) (-2.00,4.00) (-0.90,0.81) (0.00,0.00) (-2.00,4.00) (4.00,16.00) (1.00,1.00) (0.00,0.00) (0.00,0.00) (0.00,0.00) (-1.00,1.00) (0.00,0.00) (-0.50,0.25) (-0.50,0.25) (0.10,0.01) (1.00,1.00) The complex eigenvectors matrix V : size: 4 by 4 (-0.54,-0.75) (1.50,-1.10) (0.00,0.00) (-0.19,-0.09) (-1.49,-0.96) (-0.94,0.24) (-0.00,-0.00) (0.05,0.23) (0.00,0.00) (0.00,0.00) (-0.00,0.00) (0.54,-1.92) (0.03,-0.08) (0.06,0.05) (-1.11,1.67) (-0.05,0.15) The complex eigenvalue D : size: 4 by 4 (2.26,17.55) (0.00,0.00) (0.00,0.00) (0.00,0.00) (0.00,0.00) (4.74,7.45) (0.00,0.00) (0.00,0.00) (0.00,0.00) (0.00,0.00) (1.00,1.00) (0.00,0.00) (0.00,0.00) (0.00,0.00) (0.00,0.00) (-1.00,1.00) 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.