复数矩阵特征值分解算法的C++实现

头文件:

/*
 * 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.

你可能感兴趣的:(复数矩阵特征值分解算法的C++实现)