实数矩阵与复数矩阵伪逆算法的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
 */


/*****************************************************************************
 *                               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), 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
 */


/*****************************************************************************
 *                             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.

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值