头文件:
/*
* 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.