各种实数矩阵与复数矩阵求逆算法的C++实现

头文件:

/*
 * Copyright (c) 2008-2011 Zhang Ming (M. Zhang), zmjerry@163.com
 *
 * 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
 */


/*****************************************************************************
 *                                  inverse.h
 *
 * Matrix Inverse
 *
 * Matrix's inverse is a very important algorithm. If 'A' is an n-by-n full
 * rank square matrix, then it's inverse 'invA' is also an n-by-n full rank
 * square matrix. The general method to compute such matrix's inverse is
 * use LU decomposition to solve A*invA=I, if 'A' is SPD, then Cholesky
 * decomposition will be more efficiency.
 *
 * The algorithms provided in this file can be applied both for REAL matrix
 * or COMPLEX matrix.
 *
 * Zhang Ming, 2010-08 (revised 2010-12), Xi'an Jiaotong University.
 *****************************************************************************/


#ifndef INVERSE_H
#define INVERSE_H


#include <string>
#include <matrix.h>
#include <cholesky.h>
#include <lud.h>


namespace splab
{

	template<typename Type> Matrix<Type> inv( const Matrix<Type>&,
                                              const string &type="nspd" );
    template<typename Type>
    Matrix<complex<Type> > cinv( const Matrix<complex<Type> >&,
                                 const string &type="nspd" );

	template<typename Type> Matrix<Type> colPivInv( const Matrix<Type>& );
    template<typename Type> Matrix<Type> cmpPivInv( const Matrix<Type>& );


	#include <inverse-impl.h>
}
// namespace splab


#endif
// INVERSE_H

实现文件:

/*
 * Copyright (c) 2008-2011 Zhang Ming (M. Zhang), zmjerry@163.com
 *
 * 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
 */


/*****************************************************************************
 *                               inverse-impl.h
 *
 * Implementation for matrix inverse
 *
 * Zhang Ming, 2010-08 (revised 2010-12), Xi'an Jiaotong University.
 *****************************************************************************/


/**
 * Cpmpute the inverse of square real matrix.
 */
template <typename Type>
Matrix<Type> inv( const Matrix<Type> &A, const string &type )
{
    int n = A.rows();
    assert( n == A.cols() );

    if( type == "spd" )
    {
        Cholesky<Type> cho;
        cho.dec(A);
        if( cho.isSpd() )
            return cho.solve( eye(n,Type(1)) );
        else
        {
            cerr << "The matrix is not symmetric!" << endl;
            return A;
        }
    }
    else
    {
        LUD<Type> lu;
        lu.dec(A);
        return lu.solve( eye(n,Type(1)) );
    }
}


/**
 * Gauss-jordan column pivot elimination for computing matrix's inverse.
 * The matrix can be both REAL or COMPLEX.
 */
template <typename Type>
Matrix<Type> colPivInv( const Matrix<Type> &A )
{
    int rows = A.rows();
    int clumns = A.cols();

    assert( rows == clumns );

    Matrix<Type> invA(A);
    Vector<int> index( rows );
    int i, j, k;
    Type tmp = 0;

    for( k=0; k<rows; ++k )
    {
        //Findint pivot and exchange if necessary.
        index[k] = k;
        Type mvl = invA[k][k];
        for( i=k+1; i<rows; ++i )
        {
            tmp = abs(invA[i][k]);
            if( abs(tmp) > abs(mvl) )
            {
                mvl = tmp;
                index[k] = i;
            }
        }
        if( abs(mvl) < EPS )
        {
            cerr << "\n" << "A is a singular matrix." << "\n";
            return Matrix<Type>(0,0);
        }

        if( index[k] != k )
        {
            tmp = 0;
            for( j=0; j<rows; ++j )
            {
                tmp = invA[k][j];
                invA[k][j] = invA[index[k]][j];
                invA[index[k]][j] = tmp;
            }
        }

        // Calculating the kth column.
        invA[k][k] = Type(1) / invA[k][k];
        for( i=0; i<rows; ++i )
            if( i != k )
                invA[i][k] = - invA[k][k]*invA[i][k];

        // Calculating all elements excptint the kth row and column.
        for( i=0; i<rows; ++i )
            if( i != k )
                for( j=0; j<rows; ++j )
                    if( j != k )
                        invA[i][j] += invA[i][k] * invA[k][j];

        // Calculating the kth row.
        for( j=0; j<rows; ++j )
            if( j != k )
                invA[k][j] *= invA[k][k];
    }

    //Exchanging back.
    for( k=rows-1; k>=0; --k )
        if( index[k] != k )
        {
            tmp = 0;
            for( i=0; i<rows; ++i )
            {
                tmp = invA[i][k];
                invA[i][k] = invA[i][index[k]];
                invA[i][index[k]] = tmp;
            }
        }

    return invA;
}


/**
 * Gauss-jordan complete pivot elimination for computing matrix's inverse.
 * The matrix can be both REAL or COMPLEX.
 */
template <typename Type>
Matrix<Type> cmpPivInv( const Matrix<Type> &A )
{
    int n = A.rows();
    assert( n == A.cols() );
    Matrix<Type> invA(A);

    int k;
    Type tmp = 0,
         mvl = 0;
    Vector<int> rowIndex(n),
                colIndex(n);

    for( k=0; k<n; ++k )
    {
        //finding pivot
        mvl = 0;
        for( int i=k; i<n; ++i )
            for( int j=k; j<n; ++j )
            {
                tmp = abs(invA[i][j]);
                if( abs(invA[i][j]) > abs(mvl) )
                {
                    mvl = tmp;
                    rowIndex[k] = i;
                    colIndex[k] = j;
                }
            }

        if( abs(mvl) < EPS )
        {
           cerr << endl << "A is a singular matrix." << endl;
            return invA;
        }

        // row exchange
        if( rowIndex[k] != k )
            for( int i=0; i<n; ++i )
                swap( invA[k][i], invA[rowIndex[k]][i] );

        // column exchange
        if( colIndex[k] != k )
            for( int j=0; j<n; ++j )
                swap( invA[j][k], invA[j][rowIndex[k]] );

        // Calculating the kth column.
        invA[k][k] = Type(1) / invA[k][k];
        for( int j=0; j<n; ++j )
            if( j != k )
                invA[k][j] = invA[k][j]*invA[k][k];

        // Calculating all elements excptint the kth row and column.
        for( int i=0; i<n; ++i )
            if( i != k )
                for( int j=0; j<n; ++j )
                    if( j != k )
                        invA[i][j] -= invA[i][k]*invA[k][j];

        for( int i=0; i<n; ++i )
            if( i != k )
                invA[i][k] = -invA[i][k]*invA[k][k];
    }

    //Exchanging back.
    for( k=n-1; k>=0; --k )
    {
        if( colIndex[k] != k )
            for( int j=0; j<n; ++j )
                swap( invA[k][j], invA[colIndex[k]][j] );
        if( rowIndex[k] != k )
            for( int i=0; i<n; ++i )
                swap( invA[i][k], invA[i][rowIndex[k]] );
    }

    return invA;
}


/**
 * Cpmpute the inverse of square complex matrix. This algorithm translate
 * complex matrix inverse to real matrix inverse, but the amount of
 * calculation is very great.
 */
template <typename Type>
Matrix<complex<Type> > cinv( const Matrix<complex<Type> > &M,
                             const string &type )
{
    int n = M.rows();
    assert( n == M.cols() );

    Matrix<Type> A = real(M),
                 B = imag(M),
                 C = inv( A + B*inv(A,type)*B ),
                 D = -inv( B + A*inv(B,type)*A );

    Matrix<complex<Type> > IM(n,n);
    for( int i=0; i<n; ++i )
        for( int j=0; j<n; ++j )
            IM[i][j] = complex<Type>( C[i][j], D[i][j] );

    return IM;
}

测试代码:

/*****************************************************************************
 *                              inverse_test.cpp
 *
 * Matrix inverse testing.
 *
 * Zhang Ming, 2010-08 (revised 2010-12), Xi'an Jiaotong University.
 *****************************************************************************/


#define BOUNDS_CHECK

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


using namespace std;
using namespace splab;


typedef double  Type;
const   int     N = 3;

int main()
{
	Matrix<Type> A, invA, B(N,N);
	A.resize(3,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;

	cout << setiosflags(ios::fixed) << setprecision(4);
	cout << "The original matrix A is : " << A << endl;
	invA = inv(A);
	cout << "The inverse matrix of A (LUD) : " << invA << endl;
    invA = colPivInv(A);
    cout << "The inverse matrix of A (column pivot) : " << invA << endl;
    invA = cmpPivInv(A);
    cout << "The invese matrix of A (complete pivot) : " << invA << endl;
    cout << "The multiplication of A and its inverse: " << A*invA << endl;

    for( int i=1; i<=N; ++i )
	{
		for( int j=1; j<=N; ++j )
			if( i == j )
				B(i,i) = i;
			else if( i < j )
                B(i,j) = i;
            else
                B(i,j) = j;
	}
	cout << "The original matrix B is : " << B << endl;
	invA = inv(B,"spd");
    cout << "The inverse matrix of B (Cholesky) : " << invA << endl;
    invA = colPivInv(B);
    cout << "The inverse matrix of B (column pivot) : " << invA << endl;
    invA = cmpPivInv(B);
    cout << "The inverse matrix of B (complete pivot) : " << invA << endl;
    cout << "The multiplication of B and its inverse: " << B*invA << endl;

    cout << setiosflags(ios::fixed) << setprecision(3);
    Matrix<complex<Type> > cA(N,N), cIA;
    cA = complexMatrix( A, B );

    cIA = inv(cA);
    cout << "The original complex matrix cA is: " << cA << endl;
    cout << "The inverse matrix of cA is (general method): " << inv(cA) << endl;
    cout << "The inverse matrix of cA is (column pivot): " << colPivInv(cA) << endl;
    cout << "The inverse matrix of cA is (complete pivot): " << cmpPivInv(cA) << endl;
    cout << "The inverse matrix of cA is (real inverse): " << cinv(cA) << endl;
    cout << "The multiplication of cA and its inverse: " << cA*cIA << 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 inverse matrix of A (LUD) : size: 3 by 3
-4.0000 1.0000  3.0000
4.0000  -1.0000 -2.0000
-3.0000 1.0000  1.0000

The inverse matrix of A (column pivot) : size: 3 by 3
-4.0000 1.0000  3.0000
4.0000  -1.0000 -2.0000
-3.0000 1.0000  1.0000

The invese matrix of A (complete pivot) : size: 3 by 3
-4.0000 1.0000  3.0000
4.0000  -1.0000 -2.0000
-3.0000 1.0000  1.0000

The multiplication of A and its inverse: size: 3 by 3
1.0000  0.0000  0.0000
0.0000  1.0000  0.0000
0.0000  0.0000  1.0000

The original matrix B is : size: 3 by 3
1.0000  1.0000  1.0000
1.0000  2.0000  2.0000
1.0000  2.0000  3.0000

The inverse matrix of B (Cholesky) : size: 3 by 3
2.0000  -1.0000 0.0000
-1.0000 2.0000  -1.0000
0.0000  -1.0000 1.0000

The inverse matrix of B (column pivot) : size: 3 by 3
2.0000  -1.0000 -0.0000
-1.0000 2.0000  -1.0000
0.0000  -1.0000 1.0000

The inverse matrix of B (complete pivot) : size: 3 by 3
2.0000  -1.0000 -0.0000
-1.0000 2.0000  -1.0000
-0.0000 -1.0000 1.0000

The multiplication of B and its inverse: size: 3 by 3
1.0000  0.0000  0.0000
0.0000  1.0000  0.0000
0.0000  0.0000  1.0000

The original complex matrix cA is: size: 3 by 3
(1.000,1.000)   (2.000,1.000)   (1.000,1.000)
(2.000,1.000)   (5.000,2.000)   (4.000,2.000)
(1.000,1.000)   (1.000,2.000)   (0.000,3.000)

The inverse matrix of cA is (general method): size: 3 by 3
(1.400,-3.200)  (-0.200,1.600)  (-1.400,0.200)
(-2.000,1.000)  (1.000,-1.000)  (1.000,1.000)
(1.600,0.200)   (-0.800,0.400)  (-0.600,-1.200)

The inverse matrix of cA is (column pivot): size: 3 by 3
(1.400,-3.200)  (-0.200,1.600)  (-1.400,0.200)
(-2.000,1.000)  (1.000,-1.000)  (1.000,1.000)
(1.600,0.200)   (-0.800,0.400)  (-0.600,-1.200)

The inverse matrix of cA is (complete pivot): size: 3 by 3
(1.400,-3.200)  (-0.200,1.600)  (-1.400,0.200)
(-2.000,1.000)  (1.000,-1.000)  (1.000,1.000)
(1.600,0.200)   (-0.800,0.400)  (-0.600,-1.200)

The inverse matrix of cA is (real inverse): size: 3 by 3
(1.400,-3.200)  (-0.200,1.600)  (-1.400,0.200)
(-2.000,1.000)  (1.000,-1.000)  (1.000,1.000)
(1.600,0.200)   (-0.800,0.400)  (-0.600,-1.200)

The multiplication of cA and its inverse: 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.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.

转载于:https://my.oschina.net/zmjerry/blog/3774

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值