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


/*****************************************************************************
 *                                    lud.h
 *
 * Class template of LU decomposition.
 *
 * For an m-by-n matrix A with m >= n, the LU decomposition is an m-by-n
 * unit lower triangular matrix L, an n-by-n upper triangular matrix U, and
 * a permutation vector piv of length m so that A(piv,:) = L*U. If m < n,
 * then L is m-by-m and U is m-by-n.
 *
 * The matrix can be both REAL or COMPLEX.
 *
 * The LU decompostion with pivoting always exists, even if the matrix is
 * singular, so the constructor will never fail. The primary use of the LU
 * decomposition is in the solution of square systems of simultaneouslinear
 * equations. This will fail if isNonsingular() returns false.
 *
 * Adapted form Template Numerical Toolkit.
 *
 * Zhang Ming, 2010-01 (revised 2010-12), Xi'an Jiaotong University.
 *****************************************************************************/


#ifndef LUD_H
#define LUD_H


#include <matrix.h>


namespace splab
{

	template <typename Type>
	class LUD
	{

	public :

        LUD();
		~LUD();

		void dec( const Matrix<Type> &A );
		Matrix<Type> getL();
		Matrix<Type> getU();
		Vector<int>  getPivot() const;

		Type det();
		bool isNonsingular();

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

    private:

        // Array for internal storage of decomposition.
		Matrix<Type> LU;
		int m;
		int n;

		int pivsign;
		Vector<int> piv;

		Vector<Type> permuteCopy( const Vector<Type> &A,
                                  const Vector<int> &piv );
		Matrix<Type> permuteCopy( const Matrix<Type> &A,
		                          const Vector<int> &piv, int j0, int j1 );

	};
	// class LUD


	#include <lud-impl.h>

}
// namespace splab


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


/*****************************************************************************
 *                               lud-impl.h
 *
 * Implementation for LUD class.
 *
 * Zhang Ming, 2010-01 (revised 2010-12), Xi'an Jiaotong University.
 *****************************************************************************/


/**
 * constructor and destructor
 */
template<typename Type>
LUD<Type>::LUD()
{
}

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


/**
 * permute copy
 */
template <typename Type>
Vector<Type> LUD<Type>::permuteCopy( const Vector<Type> &A,
                                     const Vector<int> &piv )
{
    int pivLength = piv.dim();
    if( pivLength != A.dim() )
        return Vector<Type>();

    Vector<Type> x(pivLength);
    for( int i=0; i<pivLength; ++i )
        x[i] = A[piv[i]];

    return x;
}

template <typename Type>
Matrix<Type> LUD<Type>::permuteCopy( const Matrix<Type> &A,
                                     const Vector<int> &piv, int j0, int j1 )
{
    int pivLength = piv.dim();
    Matrix<Type> X( pivLength, j1-j0+1 );

    for( int i=0; i<pivLength; ++i )
        for( int j=j0; j<=j1; ++j )
            X[i][j-j0] = A[piv[i]][j];

    return X;
}


/**
 * Return pivot permutation vector
 */
template<typename Type>
inline Vector<int> LUD<Type>::getPivot() const
{
    return piv;
}


/**
 * LU Decomposition
 */
template <typename Type>
void LUD<Type>::dec(const Matrix<Type> &A)
{
    m = A.rows();
    n = A.cols();
    piv.resize(m);
    LU = A;

    // Use a "left-looking", dot-product, Crout/Doolittle algorithm.
    for( int i=0; i<m; ++i )
        piv[i] = i;

    pivsign = 1;
    Type *LUrowi = 0;
    Vector<Type> LUcolj(m);

    // outer loop
    for( int j=0; j<n; ++j )
    {
        // Make a copy of the j-th column to localize references.
        for( int i=0; i<m; ++i )
            LUcolj[i] = LU[i][j];

        // Apply previous transformations.
        for( int i=0; i<m; ++i )
        {
            LUrowi = LU[i];

            // Most of the time is spent in the following dot product.
            int kmax = (i < j)? i : j;
            Type s = 0;

            for( int k=0; k<kmax; ++k )
                s += LUrowi[k]*LUcolj[k];

            LUrowi[j] = LUcolj[i] -= s;
        }

        // Find pivot and exchange if necessary.
        int p = j;
        for( int i=j+1; i<m; ++i )
            if( abs(LUcolj[i]) > abs(LUcolj[p]) )
                p = i;

        if( p != j )
        {
            int k=0;
            for( k=0; k<n; ++k )
                swap( LU[p][k], LU[j][k] );

            swap( piv[p], piv[j] );
            pivsign = -pivsign;
        }

        // compute multipliers
        if( (j < m) && ( abs(LU[j][j]) != 0 ) )
            for( int i=j+1; i<m; ++i )
                LU[i][j] /= LU[j][j];
    }
}


/**
 * Return lower triangular matrix L.
 */
template <typename Type>
Matrix<Type> LUD<Type>::getL()
{
    int p = min( m, n );
    Matrix<Type> tmp( m, p );

    for( int i=0; i<m; ++i )
        for( int j=0; j<i && j<n; ++j )
            tmp[i][j] = LU[i][j];
   for( int i=0; i<p; ++i )
        tmp[i][i] = 1;

    return tmp;
}


/**
 * Return upper triangular matrix U.
 */
template <typename Type>
Matrix<Type>LUD<Type>::getU()
{
    int p = min( m, n );
    Matrix<Type> tmp( p, n );

    for( int i=0; i<m; ++i )
        for( int j=i; j<n; ++j )
            tmp[i][j] = LU[i][j];

    return tmp;
}


/**
 * Compute determinant using LU factors.
 */
template <typename Type>
Type LUD<Type>::det()
{
    if( m != n )
        return 0;

    Type d = Type(pivsign);
    for( int j=0; j<n; ++j )
        d *= LU[j][j];

    return d;
}


/**
 * true if upper triangular factor U is nonsingular, 0 otherwise.
 */
template <typename Type>
inline bool LUD<Type>::isNonsingular()
{
    for( int j=0; j<n; ++j )
        if( abs(LU[j][j]) == 0 )
            return false;

    return true;
}


/**
 * Solve A*x = b, where x and b are vectors of length equal
 * to the number of rows in A.
 */
template <typename Type>
Vector<Type> LUD<Type>::solve( const Vector<Type> &b )
{
    // dimensions: A is mxn, X is nxk, B is mxk
    if( b.dim() != m )
        return Vector<Type>();

    if( !isNonsingular() )
        return Vector<Type>();

    Vector<Type> x = permuteCopy( b, piv );

    // solve L*Y = B(piv)
    for( int k=0; k<n; ++k )
        for( int i=k+1; i<n; ++i )
            x[i] -= x[k]*LU[i][k];

    // solve U*x = y;
    for( int k=n-1; k>=0; --k )
    {
        x[k] /= LU[k][k];
        for( int i=0; i<k; ++i )
            x[i] -= x[k]*LU[i][k];
    }

    return x;
}


/**
 * Solve A*X = B
 */
template <typename Type>
Matrix<Type> LUD<Type>::solve( const Matrix<Type> &B )
{
    // dimensions: A is mxn, X is nxk, B is mxk
    if( B.rows() != m )
        return Matrix<Type>(0,0);

    if( !isNonsingular() )
        return Matrix<Type>(0,0);

    // copy right hand side with pivoting
    int nx = B.cols();
    Matrix<Type> X = permuteCopy( B, piv, 0, nx-1 );

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

    // solve U*X = Y;
    for( int k=n-1; k>=0; --k )
    {
        for( int j=0; j<nx; ++j )
            X[k][j] /= LU[k][k];

        for( int i=0; i<k; ++i )
            for( int j=0; j<nx; ++j )
                X[i][j] -= X[k][j]*LU[i][k];
    }

    return X;
}

测试代码:

/*****************************************************************************
 *                               lud_test.cpp
 *
 * LUD class testing.
 *
 * Zhang Ming, 2010-01 (revised 2010-12), Xi'an Jiaotong University.
 *****************************************************************************/


#define BOUNDS_CHECK

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


using namespace std;
using namespace splab;


typedef double  Type;
const   int     M = 3;
const   int     N = 4;


int main()
{
	Matrix<Type> A(3,3), B(3,3), L, U;
	Vector<Type> b(3);

	A[0][0] = 1;	A[0][1] = 2;	A[0][2] = 1;
	A[1][0] = 2;	A[1][1] = 5;	A[1][2] = 4;
	A[2][0] = 1;	A[2][1] = 1;	A[2][2] = 0;

	B[0][0] = 1;	B[0][1] = 0;	B[0][2] = 0;
	B[1][0] = 0;	B[1][1] = 1;	B[1][2] = 0;
	B[2][0] = 0;	B[2][1] = 0;	B[2][2] = 1;

	b[0] = 1;	b[1] = 0;	b[2] = 1;

    LUD<Type> lu;
	lu.dec(A);
	L = lu.getL();
	U = lu.getU();
    cout << setiosflags(ios::fixed) << setprecision(4);
	cout << "The original matrix A is : " << A << endl;
	cout << "The unit lower triangular matrix L is : " << L << endl;
	cout << "The upper triangular matrix U is : " << U << endl;

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

	cout << "The inverse matrix of A : " << lu.solve(B) << endl;
	cout << "The A * inverse(A) : " << A*lu.solve(B) << endl;
	cout << "The determinant of A : " << endl;
	cout << lu.det() << endl << endl << endl;

    Matrix<complex<Type> > cA(M,N), cPA(M,N), invcA, cL, cU;
    for( int i=0; i<M; i++ )
		for( int j=0; j<N; j++ )
			cA[i][j] = complex<Type>( Type(0.3*i+0.7*j), sin(Type(i+j)) );
	LUD<complex<Type> > clu;

	clu.dec(cA);
	cL = clu.getL();
	cU = clu.getU();
	Vector<int> p = clu.getPivot();
	for( int i=0; i<M; ++i )
        cPA.setRow( cA.getRow(p[i]), i );

    cout << setiosflags(ios::fixed) << setprecision(3);
	cout << "The original complex matrix cA is : " << cA << endl;
	cout << "The unit lower triangular matrix cL is : " << cL << endl;
	cout << "The upper triangular matrix cU is : " << cU << endl;
	cout << "cP*cA - cL*cU is : " << cPA - cL*cU << endl;

	if( M == N )
	{
	    invcA = clu.solve( eye( M, complex<Type>(1.0,0) ) );
	    cout << "The inverse matrix of cA : " << invcA << endl;
	    cout << "The cA * inverse(cA) : " << cA*invcA << endl;
	}

	return 0;
}

运行结果:

The original matrix A is : size: 3 by 3
1.0000  2.0000  1.0000
2.0000  5.0000  4.0000
1.0000  1.0000  0.0000

The unit lower triangular matrix L is : size: 3 by 3
1.0000  0.0000  0.0000
0.5000  1.0000  0.0000
0.5000  0.3333  1.0000

The upper triangular matrix U is : size: 3 by 3
2.0000  5.0000  4.0000
0.0000  -1.5000 -2.0000
0.0000  0.0000  -0.3333

The constant vector b : size: 3 by 1
1.0000
0.0000
1.0000

The solution of A * x = b : size: 3 by 1
-1.0000
2.0000
-2.0000

The solution of A * x - b : size: 3 by 1
-0.0000
0.0000
0.0000

The inverse matrix of A : size: 3 by 3
-4.0000 1.0000  3.0000
4.0000  -1.0000 -2.0000
-3.0000 1.0000  1.0000

The A * inverse(A) : size: 3 by 3
1.0000  0.0000  0.0000
0.0000  1.0000  0.0000
0.0000  0.0000  1.0000

The determinant of A :
1.0000


The original complex matrix cA is : size: 3 by 4
(0.000,0.000)   (0.700,0.841)   (1.400,0.909)   (2.100,0.141)
(0.300,0.841)   (1.000,0.909)   (1.700,0.141)   (2.400,-0.757)
(0.600,0.909)   (1.300,0.141)   (2.000,-0.757)  (2.700,-0.959)

The unit lower triangular matrix cL is : size: 3 by 3
(1.000,0.000)   (0.000,0.000)   (0.000,0.000)
(0.000,0.000)   (1.000,0.000)   (0.000,0.000)
(0.796,0.196)   (0.377,0.322)   (1.000,0.000)

The upper triangular matrix cU is : size: 3 by 4
(0.600,0.909)   (1.300,0.141)   (2.000,-0.757)  (2.700,-0.959)
(0.000,0.000)   (0.700,0.841)   (1.400,0.909)   (2.100,0.141)
(0.000,0.000)   (0.000,0.000)   (-0.275,-0.441) (-0.683,-1.252)

cP*cA - cL*cU is : size: 3 by 4
(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)


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

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