头文件:
/* * 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 */ /***************************************************************************** * pseudoinverse.h * * Matrix Pseudoinverse * * If 'A' is an m-by-n (where m != n) matrix, or n-by-n but nor full rank, * then we can't compute the ordinary inverse. In these cases, we should * compute the pseudoinverse. And here we use SVD to compute the pseudoinverse, * which is consistent with Matlab's "pinv". * * 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 PSEUDOINVERSE_H #define PSEUDOINVERSE_H #include <matrix.h> #include <svd.h> #include <csvd.h> namespace splab { template<typename Real> Matrix<Real> pinv( const Matrix<Real>&, Real tol=Real(-1.0) ); template<typename Type> Matrix<complex<Type> > pinv( const Matrix<complex<Type> >&, Type tol=Type(-1.0) ); #include <pseudoinverse-impl.h> } // namespace splab #endif // PSEUDOINVERSE_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 */ /***************************************************************************** * pseudoinverse-impl.h * * Implementation for matrix pseudoinverse * * Zhang Ming, 2010-08 (revised 2010-12), Xi'an Jiaotong University. *****************************************************************************/ /** * Compute the pseudoinverse of a real matrix. */ template <typename Real> Matrix<Real> pinv( const Matrix<Real> &A, Real tol ) { int m = A.rows(), n = A.cols(); SVD<Real> svd; svd.dec( A ); Matrix<Real> U = svd.getU(); Matrix<Real> V = svd.getV(); Vector<Real> s = svd.getSV(); int r = 0; if( tol <= 0 ) tol = max( m, n ) * s[0] * EPS; for( int i=0; i<s.size(); ++i ) if( s[i] >= tol ) r++; for( int i=0; i<n; ++i ) for( int k=0; k<r; ++k ) V[i][k] /= s[k]; Matrix<Real> invA( n, m ); for( int i=0; i<n; ++i ) for( int j=0; j<m; ++j ) { Real sum = 0; for( int k=0; k<r; ++k ) sum += V[i][k]*U[j][k]; invA[i][j] = sum; } return invA; } /** * Compute the pseudoinverse of a complex matrix. */ template <typename Type> Matrix<complex<Type> > pinv( const Matrix<complex<Type> > &A, Type tol ) { int m = A.rows(), n = A.cols(); CSVD<Type> svd; svd.dec( A ); Matrix<complex<Type> > U = svd.getU(); Matrix<complex<Type> > V = svd.getV(); Vector<Type> s = svd.getSV(); int r = 0; if( tol <= 0 ) tol = max( m, n ) * s[0] * EPS; for( int i=0; i<s.size(); ++i ) if( s[i] >= tol ) r++; for( int i=0; i<n; ++i ) for( int k=0; k<r; ++k ) V[i][k] /= s[k]; Matrix<complex<Type> >invA( n, m ); for( int i=0; i<n; ++i ) for( int j=0; j<m; ++j ) { complex<Type> sum = 0; for( int k=0; k<r; ++k ) sum += V[i][k]*conj(U[j][k]); invA[i][j] = sum; } return invA; }
测试代码:
/***************************************************************************** * pseudoinverse_test.cpp * * Matrix pseudoinverse testing. * * Zhang Ming, 2010-08 (revised 2010-12), Xi'an Jiaotong University. *****************************************************************************/ #define BOUNDS_CHECK #include <iostream> #include <iomanip> #include <pseudoinverse.h> using namespace std; using namespace splab; typedef double Type; int main() { Matrix<Type> A(8,6), invA; A[0][0]=64; A[0][1]=2; A[0][2]=3; A[0][3]=61; A[0][4]=60; A[0][5]=6; A[1][0]=9; A[1][1]=55; A[1][2]=54; A[1][3]=12; A[1][4]=13; A[1][5]=51; A[2][0]=17; A[2][1]=47; A[2][2]=46; A[2][3]=20; A[2][4]=21; A[2][5]=43; A[3][0]=40; A[3][1]=26; A[3][2]=27; A[3][3]=37; A[3][4]=36; A[3][5]=30; A[4][0]=32; A[4][1]=34; A[4][2]=35; A[4][3]=29; A[4][4]=28; A[4][5]=38; A[5][0]=41; A[5][1]=23; A[5][2]=22; A[5][3]=44; A[5][4]=45; A[5][5]=19; A[6][0]=49; A[6][1]=15; A[6][2]=14; A[6][3]=52; A[6][4]=53; A[6][5]=11; A[7][0]=8; A[7][1]=58; A[7][2]=59; A[7][3]=5; A[7][4]=4; A[7][5]=62; invA = pinv(A); cout << setiosflags(ios::fixed) << setprecision(4); cout << "The original matrix A is : " << A << endl; cout << "The pseudoinverse matrix of A is : " << invA << endl; cout << "The multiplication of A and its inverse is : " << A*invA << endl; Matrix<complex<Type> > cA = complexMatrix(A,-A); Matrix<complex<Type> > cPIA = pinv(cA); cout << "The original complex matrix A is : " << setprecision(0) << cA << endl; cout << setiosflags(ios::fixed) << setprecision(4); cout << "The real part of the pseudoinverse matrix of A is: " << real(cPIA) << endl; cout << "The real imaginary of the pseudoinverse matrix of A is: " << imag(cPIA) << endl; return 0; }
运行结果:
The original matrix A is : size: 8 by 6 64.0000 2.0000 3.0000 61.0000 60.0000 6.0000 9.0000 55.0000 54.0000 12.0000 13.0000 51.0000 17.0000 47.0000 46.0000 20.0000 21.0000 43.0000 40.0000 26.0000 27.0000 37.0000 36.0000 30.0000 32.0000 34.0000 35.0000 29.0000 28.0000 38.0000 41.0000 23.0000 22.0000 44.0000 45.0000 19.0000 49.0000 15.0000 14.0000 52.0000 53.0000 11.0000 8.0000 58.0000 59.0000 5.0000 4.0000 62.0000 The pseudoinverse matrix of A is : size: 6 by 8 0.0177 -0.0165 -0.0164 0.0174 0.0173 -0.0161 -0.0160 0.0170 -0.0121 0.0132 0.0130 -0.0114 -0.0112 0.0124 0.0122 -0.0106 -0.0055 0.0064 0.0060 -0.0043 -0.0040 0.0049 0.0045 -0.0028 -0.0020 0.0039 0.0046 -0.0038 -0.0044 0.0064 0.0070 -0.0063 -0.0086 0.0108 0.0115 -0.0109 -0.0117 0.0139 0.0147 -0.0141 0.0142 -0.0140 -0.0149 0.0169 0.0178 -0.0176 -0.0185 0.0205 The multiplication of A and its inverse is : size: 8 by 8 0.5417 -0.2083 -0.1250 0.2917 0.2083 0.1250 0.2083 -0.0417 -0.2083 0.3988 0.3393 -0.0298 0.0298 0.1607 0.1012 0.2083 -0.1250 0.3393 0.3036 -0.0179 0.0179 0.1964 0.1607 0.1250 0.2917 -0.0298 -0.0179 0.2560 0.2440 0.0179 0.0298 0.2083 0.2083 0.0298 0.0179 0.2440 0.2560 -0.0179 -0.0298 0.2917 0.1250 0.1607 0.1964 0.0179 -0.0179 0.3036 0.3393 -0.1250 0.2083 0.1012 0.1607 0.0298 -0.0298 0.3393 0.3988 -0.2083 -0.0417 0.2083 0.1250 0.2083 0.2917 -0.1250 -0.2083 0.5417 The original complex matrix A is : size: 8 by 6 (64,-64) (2,-2) (3,-3) (61,-61) (60,-60) (6,-6) (9,-9) (55,-55) (54,-54) (12,-12) (13,-13) (51,-51) (17,-17) (47,-47) (46,-46) (20,-20) (21,-21) (43,-43) (40,-40) (26,-26) (27,-27) (37,-37) (36,-36) (30,-30) (32,-32) (34,-34) (35,-35) (29,-29) (28,-28) (38,-38) (41,-41) (23,-23) (22,-22) (44,-44) (45,-45) (19,-19) (49,-49) (15,-15) (14,-14) (52,-52) (53,-53) (11,-11) (8,-8) (58,-58) (59,-59) (5,-5) (4,-4) (62,-62) The real part of the pseudoinverse matrix of A is: size: 6 by 8 0.0089 -0.0083 -0.0082 0.0087 0.0087 -0.0081 -0.0080 0.0085 -0.0060 0.0066 0.0065 -0.0057 -0.0056 0.0062 0.0061 -0.0053 -0.0027 0.0032 0.0030 -0.0022 -0.0020 0.0025 0.0023 -0.0014 -0.0010 0.0020 0.0023 -0.0019 -0.0022 0.0032 0.0035 -0.0031 -0.0043 0.0054 0.0058 -0.0055 -0.0059 0.0069 0.0073 -0.0070 0.0071 -0.0070 -0.0075 0.0085 0.0089 -0.0088 -0.0093 0.0103 The real imaginary of the pseudoinverse matrix of A is: size: 6 by 8 0.0089 -0.0083 -0.0082 0.0087 0.0087 -0.0081 -0.0080 0.0085 -0.0060 0.0066 0.0065 -0.0057 -0.0056 0.0062 0.0061 -0.0053 -0.0027 0.0032 0.0030 -0.0022 -0.0020 0.0025 0.0023 -0.0014 -0.0010 0.0020 0.0023 -0.0019 -0.0022 0.0032 0.0035 -0.0031 -0.0043 0.0054 0.0058 -0.0055 -0.0059 0.0069 0.0073 -0.0070 0.0071 -0.0070 -0.0075 0.0085 0.0089 -0.0088 -0.0093 0.0103 Process returned 0 (0x0) execution time : 0.140 s Press any key to continue.