复数矩阵Cholesky分解算法的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
 */


/*****************************************************************************
 *                               ccholesky.h
 *
 * Class template of complex matrix Cholesky factorization.
 *
 * For a conjugate symmetric, positive definite matrix A, this class computes
 * the Cholesky factorization, i.e. it computes a lower triangular matrix L
 * such that A = L*L^H. If the matrix is not conjugate symmetric or positive
 * definite, the class computes only a partial decomposition. This can be
 * tested with the isSpd() flag.
 *
 * Zhang Ming, 2010-12, Xi'an Jiaotong University.
 *****************************************************************************/


#ifndef CCHOLESKY_H
#define CCHOLESKY_H


#include <matrix.h>


namespace splab
{

    template <typename Type>
    class CCholesky
    {

    public:

        CCholesky();
        ~CCholesky();

        bool isSpd() const;
        void dec( const Matrix<Type> &A );
        Matrix<Type> getL() const;

        Vector<Type> solve( const Vector<Type> &b );
        Matrix<Type> solve( const Matrix<Type> &B );

    private:

        bool spd;
        Matrix<Type> L;

    };
    //	class CCholesky


    #include <ccholesky-impl.h>

}
// namespace splab


#endif
// CCHOLESKY_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
 */


/*****************************************************************************
 *                             ccholesky-impl.h
 *
 * Implementation for CCholesky (complex Cholesky) class.
 *
 * Zhang Ming, 2010-12, Xi'an Jiaotong University.
 *****************************************************************************/


/**
 * constructor and destructor
 */
template<typename Type>
CCholesky<Type>::CCholesky() : spd(true)
{
}

template<typename Type>
CCholesky<Type>::~CCholesky()
{
}


/**
 * return true, if original matrix is symmetric positive-definite.
 */
template<typename Type>
inline bool CCholesky<Type>::isSpd() const
{
    return spd;
}


/**
 * Constructs a lower triangular matrix L, such that L*L^H= A.
 * If A is not symmetric positive-definite (SPD), only a partial
 * factorization is performed. If isspd() evalutate true then
 * the factorizaiton was successful.
 */
template <typename Type>
void CCholesky<Type>::dec( const Matrix<Type> &A )
{
    int m = A.rows();
    int n = A.cols();

    spd = (m == n);
    if( !spd )
        return;

    L = Matrix<Type>(A.cols(),A.cols());

    // main loop
    for( int j=0; j<A.rows(); ++j )
    {
        Type d = 0;
        spd = spd && (imag(A[j][j]) == 0);

        for( int k=0; k<j; ++k )
        {
            Type s = 0;
            for( int i=0; i<k; ++i )
                s += L[k][i] * conj(L[j][i]);

            L[j][k] = s = (A[j][k]-s) / L[k][k];
            d = d + s*conj(s);
            spd = spd && (A[k][j] == conj(A[j][k]));
        }

        d = A[j][j] - d;
        spd = spd && ( real(d) > 0 );

        L[j][j] = sqrt( real(d) > 0 ? d : 0 );
        for( int k=j+1; k<A.rows(); ++k )
            L[j][k] = 0;
    }
}


/**
 * return the lower triangular factor, L, such that L*L'=A.
 */
template<typename Type>
inline Matrix<Type> CCholesky<Type>::getL() const
{
    return L;
}


/**
 * Solve a linear system A*x = b, using the previously computed
 * cholesky factorization of A: L*L'.
 */
template <typename Type>
Vector<Type> CCholesky<Type>::solve( const Vector<Type> &b )
{
    int n = L.rows();
    if( b.dim() != n )
        return Vector<Type>();

    Vector<Type> x = b;

    // solve L*y = b
    for( int k=0; k<n; ++k )
    {
        for( int i=0; i<k; ++i )
            x[k] -= x[i]*L[k][i];

        x[k] /= L[k][k];
    }

    // solve L^H*x = y
    for( int k=n-1; k>=0; --k )
    {
        for( int i=k+1; i<n; ++i )
            x[k] -= x[i]*conj(L[i][k]);

        x[k] /= L[k][k];
    }

    return x;
}


/**
 * Solve a linear system A*X = B, using the previously computed
 * cholesky factorization of A: L*L'.
 */
template <typename Type>
Matrix<Type> CCholesky<Type>::solve( const Matrix<Type> &B )
{
    int n = L.rows();
    if( B.rows() != n )
        return Matrix<Type>();

    Matrix<Type> X = B;
    int nx = B.cols();

    // solve L*Y = B
    for( int j=0; j<nx; ++j )
        for( int k=0; k<n; ++k )
        {
            for( int i=0; i<k; ++i )
                X[k][j] -= X[i][j]*L[k][i];

            X[k][j] /= L[k][k];
        }

    // solve L^H*x = y
    for( int j=0; j<nx; ++j )
        for( int k=n-1; k>=0; --k )
        {
            for( int i=k+1; i<n; ++i )
                X[k][j] -= X[i][j]*conj(L[i][k]);

            X[k][j] /= L[k][k];
        }

    return X;
}

测试代码:

/*****************************************************************************
 *                             ccholesky_test.cpp
 *
 * Comnplex Cholesky class testing.
 *
 * Zhang Ming, 2010-12, Xi'an Jiaotong University.
 *****************************************************************************/


#define BOUNDS_CHECK

#include <iostream>
#include <iomanip>
#include <ccholesky.h>


using namespace std;
using namespace splab;


typedef double  Type;
const   int     N = 5;


int main()
{
    cout << setiosflags(ios::fixed) << setprecision(3);
	Matrix<complex<Type> > A(N,N), L(N,N);
	Vector<complex<Type> > b(N);

	for( int i=1; i<N+1; ++i )
	{
		for( int j=1; j<N+1; ++j )
			if( i == j )
				A(i,i) = complex<Type>(N+i,0);
			else
				if( i < j )
					A(i,j) = complex<Type>(Type(i),cos(Type(i)));
				else
					A(i,j) = complex<Type>(Type(j),-cos(Type(j)));

		b(i) = i*(i+1)/2 + i*(N-i);
	}

    cout << "The original matrix A : " << A << endl;
	CCholesky<complex<Type> > cho;
    cho.dec(A);
	if( !cho.isSpd() )
		cout << "Factorization was not complete." << endl;
	else
    {
        L = cho.getL();
        cout << "The lower triangular matrix L is : " << L << endl;
        cout << "A - L*L^H is : " << A - L*trH(L) << endl;

        Vector<complex<Type> > x = cho.solve(b);
        cout << "The constant vector b : " << b << endl;
        cout << "The solution of Ax = b : " << x << endl;
        cout << "The solution of Ax - b : " << A*x-b << endl;

        Matrix<complex<Type> > IA = cho.solve(eye(N,complex<Type>(1,0)));
        cout << "The inverse matrix of A : " << IA << endl;
        cout << "The product of  A*inv(A) : " << A*IA << endl;
    }

	return 0;
}

运行结果:

The original matrix A : size: 5 by 5
(6.000,0.000)   (1.000,0.540)   (1.000,0.540)   (1.000,0.540)   (1.000,0.540)

(1.000,-0.540)  (7.000,0.000)   (2.000,-0.416)  (2.000,-0.416)  (2.000,-0.416)

(1.000,-0.540)  (2.000,0.416)   (8.000,0.000)   (3.000,-0.990)  (3.000,-0.990)

(1.000,-0.540)  (2.000,0.416)   (3.000,0.990)   (9.000,0.000)   (4.000,-0.654)

(1.000,-0.540)  (2.000,0.416)   (3.000,0.990)   (4.000,0.654)   (10.000,0.000)


The lower triangular matrix L is : size: 5 by 5
(2.449,0.000)   (0.000,0.000)   (0.000,0.000)   (0.000,0.000)   (0.000,0.000)

(0.408,-0.221)  (2.605,0.000)   (0.000,0.000)   (0.000,0.000)   (0.000,0.000)

(0.408,-0.221)  (0.685,0.160)   (2.700,0.000)   (0.000,0.000)   (0.000,0.000)

(0.408,-0.221)  (0.685,0.160)   (0.848,0.367)   (2.727,0.000)   (0.000,0.000)

(0.408,-0.221)  (0.685,0.160)   (0.848,0.367)   (0.893,0.240)   (2.753,0.000)


A - L*L^H is : size: 5 by 5
(0.000,0.000)   (0.000,0.000)   (0.000,0.000)   (0.000,0.000)   (0.000,0.000)

(0.000,0.000)   (0.000,0.000)   (0.000,0.000)   (0.000,0.000)   (0.000,0.000)

(0.000,0.000)   (0.000,0.000)   (0.000,0.000)   (0.000,0.000)   (0.000,0.000)

(0.000,0.000)   (0.000,0.000)   (0.000,0.000)   (-0.000,0.000)  (0.000,0.000)

(0.000,0.000)   (0.000,0.000)   (0.000,0.000)   (0.000,0.000)   (0.000,0.000)


The constant vector b : size: 5 by 1
(5.000,0.000)
(9.000,0.000)
(12.000,0.000)
(14.000,0.000)
(15.000,0.000)

The solution of Ax = b : size: 5 by 1
(0.356,-0.310)
(0.562,0.207)
(0.746,0.284)
(0.843,-0.037)
(0.842,-0.214)

The solution of Ax - b : size: 5 by 1
(0.000,-0.000)
(-0.000,0.000)
(-0.000,0.000)
(-0.000,0.000)
(0.000,0.000)

The inverse matrix of A : size: 5 by 5
(0.177,0.000)   (-0.018,-0.007) (-0.014,-0.004) (-0.008,-0.006) (-0.005,-0.007)

(-0.018,0.007)  (0.164,-0.000)  (-0.024,0.013)  (-0.020,0.003)  (-0.017,-0.002)

(-0.014,0.004)  (-0.024,-0.013) (0.160,-0.000)  (-0.032,0.018)  (-0.029,0.008)

(-0.008,0.006)  (-0.020,-0.003) (-0.032,-0.018) (0.150,0.000)   (-0.043,0.012)

(-0.005,0.007)  (-0.017,0.002)  (-0.029,-0.008) (-0.043,-0.012) (0.132,0.000)


The product of  A*inv(A) : size: 5 by 5
(1.000,0.000)   (-0.000,-0.000) (-0.000,-0.000) (-0.000,-0.000) (0.000,-0.000)

(0.000,-0.000)  (1.000,0.000)   (-0.000,0.000)  (0.000,-0.000)  (0.000,-0.000)

(0.000,-0.000)  (-0.000,-0.000) (1.000,0.000)   (-0.000,0.000)  (-0.000,-0.000)

(0.000,-0.000)  (0.000,0.000)   (-0.000,-0.000) (1.000,0.000)   (0.000,0.000)

(0.000,-0.000)  (0.000,0.000)   (-0.000,0.000)  (0.000,0.000)   (1.000,-0.000)



Process returned 0 (0x0)   execution time : 0.125 s
Press any key to continue.

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