最小二乘解与极小范数解算法的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
 */


/*****************************************************************************
 *                                linequs2.h
 *
 * Function template for solving linear equations.
 *
 * For a m-by-n (m!=n) coefficient matrix A and m-by-1 constant vector b, if
 * m>n, the exact solution of Ax=b is not existent, but we can find the least
 * square solution that minimize norm of Ax-b; if m<n, there are infinite
 * many solutions, but we can find the minimum norm sulution that minimize
 * norm of x.
 *
 * These functions, except QR domposition based methods, in this file can be
 * used by both REAL or COMPLEX linear equations.
 *
 * Zhang Ming, 2010-07 (revised 2010-12), Xi'an Jiaotong University.
 *****************************************************************************/


#ifndef UNDETLINEQUS_H
#define UNDETLINEQUS_H


#include <qrd.h>
#include <svd.h>
#include <cqrd.h>
#include <csvd.h>
#include <linequs1.h>


namespace splab
{

	template<typename Type>
	Vector<Type> lsSolver( const Matrix<Type>&, const Vector<Type>& );
	template<typename Real>
	Vector<Real> qrLsSolver( const Matrix<Real>&, const Vector<Real>& );
	template<typename Real>
	Vector<Real> svdLsSolver( const Matrix<Real>&, const Vector<Real>& );
	template<typename Type>
	Vector<complex<Type> > qrLsSolver( const Matrix<complex<Type> >&,
                                       const Vector<complex<Type> >& );
	template<typename Type>
	Vector<complex<Type> > svdLsSolver( const Matrix<complex<Type> >&,
                                        const Vector<complex<Type> >& );

	template<typename Type>
	Vector<Type> lnSolver( const Matrix<Type>&, const Vector<Type>& );
	template<typename Real>
	Vector<Real> qrLnSolver( const Matrix<Real>&, const Vector<Real>& );
	template<typename Real>
	Vector<Real> svdLnSolver( const Matrix<Real>&, const Vector<Real>& );
	template<typename Type>
	Vector<complex<Type> > qrLnSolver( const Matrix<complex<Type> >&,
                                       const Vector<complex<Type> >& );
	template<typename Type>
	Vector<complex<Type> > svdLnSolver( const Matrix<complex<Type> >&,
                                        const Vector<complex<Type> >& );


	#include <linequs2-impl.h>

}
// namespace splab


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


/*****************************************************************************
 *                               linequs2-impl.h
 *
 * Implementation for solving overdetermined and underdetermined linear
 * equations.
 *
 * Zhang Ming, 2010-07 (revised 2010-12), Xi'an Jiaotong University.
 *****************************************************************************/


/**
 * Overdetermined linear equationequations solution by Least Squares
 * Generalized Inverse.
 * A  --->  The m-by-n(m>n) coefficient matrix(Full Column Rank);
 * b  --->  The n-by-1 right-hand side vector;
 * x  --->  The n-by-1 least squares solution vector.
 */
template <typename Type>
Vector<Type> lsSolver( const Matrix<Type> &A, const Vector<Type> &b )
{
    assert( A.rows() == b.size() );
    assert( A.rows() > A.cols() );

    Cholesky<Type> cho;
    cho.dec( trMult(A,A) );
    if( cho.isSpd() )
        return cho.solve( trMult(A,b) );
    else
        return luSolver( trMult(A,A), trMult(A,b) );
}


/**
 * Overdetermined linear equationequations solution by QR Decomposition.
 * A  --->  The m-by-n(m>n) coefficient matrix(Full Column Rank);
 * b  --->  The n-by-1 right-hand side vector;
 * x  --->  The n-by-1 least squares solution vector.
 */
template <typename Real>
Vector<Real> qrLsSolver( const Matrix<Real> &A, const Vector<Real> &b )
{
    assert( A.rows() == b.size() );
    assert( A.rows() > A.cols() );

    QRD<Real> qr;
    qr.dec( A );
    if( !qr.isFullRank() )
    {
        cerr << "The matrix A is not Full Rank!" << endl;
        return Vector<Real>();
    }
    else
        return qr.solve( b );
}


/**
 * Overdetermined linear equationequations solution by SVD Decomposition.
 * A  --->  The m-by-n(m>n) coefficient matrix(Full Column Rank);
 * b  --->  The n-by-1 right-hand side vector;
 * x  --->  The n-by-1 least squares solution vector.
 */
template<typename Real>
Vector<Real> svdLsSolver( const Matrix<Real> &A, const Vector<Real> &b )
{
    assert( A.rows() == b.size() );
    assert( A.rows() > A.cols() );

    SVD<Real> svd;
    svd.dec( A );
    Matrix<Real> U = svd.getU();
    Matrix<Real> V = svd.getV();
    Vector<Real> s = svd.getSV();

//    for( int i=0; i<V.rows(); ++i )
//        for( int k=0; k<s.dim(); ++k )
//            V[i][k] /= s[k];
//
//    return V * trMult(U,b);

    return V * ( trMult(U,b) / s );
}


/**
 * Overdetermined linear equationequations solution by QR Decomposition.
 * A  --->  The m-by-n(m>n) coefficient matrix(Full Column Rank);
 * b  --->  The n-by-1 right-hand side vector;
 * x  --->  The n-by-1 least squares solution vector.
 */
template<typename Type>
Vector<complex<Type> > qrLsSolver( const Matrix<complex<Type> > &A,
                                   const Vector<complex<Type> > &b )
{
    assert( A.rows() == b.size() );
    assert( A.rows() > A.cols() );

    CQRD<Type> qr;
    qr.dec( A );
    if( !qr.isFullRank() )
    {
        cerr << "The matrix A is not Full Rank!" << endl;
        return Vector<complex<Type> >();
    }
    else
        return qr.solve( b );
}


/**
 * Overdetermined linear equationequations solution by SVD Decomposition.
 * A  --->  The m-by-n(m>n) coefficient matrix(Full Column Rank);
 * b  --->  The n-by-1 right-hand side vector;
 * x  --->  The n-by-1 least squares solution vector.
 */
template<typename Type>
Vector<complex<Type> > svdLsSolver( const Matrix<complex<Type> > &A,
                                    const Vector<complex<Type> > &b )
{
    assert( A.rows() == b.size() );
    assert( A.rows() > 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();

//    for( int i=0; i<V.rows(); ++i )
//        for( int k=0; k<s.dim(); ++k )
//            V[i][k] /= s[k];
//
//    return V * trMult(U,b);

    return V * ( trMult(U,b) / complexVector(s) );
}


/**
 * Undetermined linear equationequations solution by Minimum Norm
 * Generalized Inverse.
 * A  --->  The m-by-n(m<n) coefficient matrix(Full Row Rank);
 * b  --->  The n-by-1 right-hand side vector;
 * x  --->  The n-by-1 minimum norm solution vector.
 */
template <typename Type>
Vector<Type> lnSolver( const Matrix<Type> &A, const Vector<Type> &b )
{
    assert( A.rows() == b.size() );
    assert( A.rows() < A.cols() );

    Cholesky<Type> cho;
    cho.dec( multTr(A,A) );
    if( cho.isSpd() )
        return trMult( A, cho.solve(b) );
    else
        return trMult( A, luSolver(multTr(A,A),b) );
}


/**
 * Undetermined linear equationequations solution by QR Decomposition.
 * A  --->  The m-by-n(m<n) coefficient matrix(Full Row Rank);
 * b  --->  The n-by-1 right-hand side vector;
 * x  --->  The n-by-1 minimum norm solution vector.
 */
template <typename Real>
Vector<Real> qrLnSolver( const Matrix<Real> &A, const Vector<Real> &b )
{
    assert( A.rows() == b.size() );
    assert( A.rows() < A.cols() );

    Matrix<Real> At( trT( A ) );
    QRD<Real> qr;
    qr.dec( At );
    if( !qr.isFullRank() )
    {
        cerr << "The matrix A is not Full Rank!" << endl;
        return Vector<Real>();
    }
    else
    {
        Matrix<Real> Q, R;
        Q = qr.getQ();
        R = qr.getR();
        Vector<Real> y( ltSolver( trT( R ), b ) );
        return Q * y;
    }
}


/**
 * Undetermined complex linear equationequations solution by SVD
 * Decomposition.
 * A  --->  The m-by-n(m<n) coefficient matrix(Full Row Rank);
 * b  --->  The n-by-1 right-hand side vector;
 * x  --->  The n-by-1 minimum norm solution vector.
 */
template<typename Real>
Vector<Real> svdLnSolver( const Matrix<Real> &A, const Vector<Real> &b )
{
    assert( A.rows() == b.size() );
    assert( A.rows() < A.cols() );

    SVD<Real> svd;
    svd.dec( A );
    Matrix<Real> U = svd.getU();
    Matrix<Real> V = svd.getV();
    Vector<Real> s = svd.getSV();

//    for( int i=0; i<V.rows(); ++i )
//        for( int k=0; k<s.dim(); ++k )
//            V[i][k] /= s[k];
//
//    return V * trMult(U,b);

    return V * ( trMult(U,b) / s );
}


/**
 * Undetermined complex linear equationequations solution by QR
 * Decomposition.
 * A  --->  The m-by-n(m<n) coefficient matrix(Full Row Rank);
 * b  --->  The n-by-1 right-hand side vector;
 * x  --->  The n-by-1 minimum norm solution vector.
 */
template<typename Type>
Vector<complex<Type> > qrLnSolver( const Matrix<complex<Type> > &A,
                                   const Vector<complex<Type> > &b )
{
    assert( A.rows() == b.size() );
    assert( A.rows() < A.cols() );

    Matrix<complex<Type> > At( trH( A ) );
    CQRD<Type> qr;
    qr.dec( At );
    if( !qr.isFullRank() )
    {
        cerr << "The matrix A is not Full Rank!" << endl;
        return Vector<complex<Type> >();
    }
    else
    {
        Matrix<complex<Type> > Q, R;
        Q = qr.getQ();
        R = qr.getR();
        Vector<complex<Type> > y( ltSolver( trH( R ), b ) );
        return Q * y;
    }
}


/**
 * Undetermined complex linear equationequations solution by SVD
 * Decomposition.
 * A  --->  The m-by-n(m<n) coefficient matrix(Full Row Rank);
 * b  --->  The n-by-1 right-hand side vector;
 * x  --->  The n-by-1 minimum norm solution vector.
 */
template<typename Type>
Vector<complex<Type> > svdLnSolver( const Matrix<complex<Type> > &A,
                                    const Vector<complex<Type> > &b )
{
    assert( A.rows() == b.size() );
    assert( A.rows() < 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();

//    for( int i=0; i<V.rows(); ++i )
//        for( int k=0; k<s.dim(); ++k )
//            V[i][k] /= s[k];
//
//    return V * trMult(U,b);

    return V * ( trMult(U,b) / complexVector(s) );
}

测试代码:

/*****************************************************************************
 *                              linequs2_test.cpp
 *
 * Undetermined Linear Equations testing.
 *
 * Zhang Ming, 2010-07 (revised 2010-12), Xi'an Jiaotong University.
 *****************************************************************************/


#define BOUNDS_CHECK

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


using namespace std;
using namespace splab;


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


int main()
{
	Matrix<Type> A(M,N), B(M,N);
	Vector<Type> b(N);

    // overdetermined linear equations
    A.resize( 4, 3 );
	A[0][0] = 1;	A[0][1] = -1;	A[0][2] = 1;
	A[1][0] = 1;	A[1][1] = 2;	A[1][2] = 4;
	A[2][0] = 1;	A[2][1] = 3;	A[2][2] = 9;
	A[3][0] = 1;	A[3][1] = -4;	A[3][2] = 16;
	b.resize( 4 );
	b[0]= 1;    b[1] = 2;   b[2] = 3;   b[3] = 4;

	cout << setiosflags(ios::fixed) << setprecision(3);
    cout << "The original matrix A : " << A << endl;
    cout << "The constant vector b : " << b << endl;
	cout << "The least square solution is (using generalized inverse) : "
         << lsSolver( A, b ) << endl;
    cout << "The least square solution is (using QR decomposition) : "
         << qrLsSolver( A, b ) << endl;
    cout << "The least square solution is (using SVD decomposition) : "
         << svdLsSolver( A, b ) << endl;

    Matrix<complex<Type> > cA = complexMatrix( A, A );
    Vector<complex<Type> > cb = complexVector( b );
    cout << "The original complex matrix cA : " << cA << endl;
    cout << "The constant complex vector cb : " << cb << endl;
	cout << "The least square solution is (using generalized inverse) : "
         << lsSolver( cA, cb ) << endl;
    cout << "The least square solution is (using QR decomposition) : "
         << qrLsSolver( cA, cb ) << endl;
    cout << "The least square solution is (using SVD decomposition) : "
         << svdLsSolver( cA, cb ) << endl;

    // undetermined linear equations
    Matrix<Type> At( trT( A ) );
	b.resize( 3 );
	b[0]= 1;	b[1] = 2;   b[2]= 3;
	cout << "The original matrix A : " << At << endl;
    cout << "The constant vector b : " << b << endl;
	cout << "The least norm solution is (using generalized inverse) : "
         << lnSolver( At, b ) << endl;
	cout << "The least norm solution is (using QR decomposition) : "
         << qrLnSolver( At, b ) << endl;
    cout << "The least norm solution is (using SVD decomposition) : "
         << svdLnSolver( At, b ) << endl;

    cA = complexMatrix( At, -At );
    cb = complexVector( b );
    cout << "The original complex matrix cA : " << cA << endl;
    cout << "The constant complex vector cb : " << cb << endl;
	cout << "The least square solution is (using generalized inverse) : "
         << lnSolver( cA, cb ) << endl;
    cout << "The least square solution is (using QR decomposition) : "
         << qrLnSolver( cA, cb ) << endl;
    cout << "The least square solution is (using SVD decomposition) : "
         << svdLnSolver( cA, cb ) << endl;

	return 0;
}

运行结果:

The original matrix A : size: 4 by 3
1.000   -1.000  1.000
1.000   2.000   4.000
1.000   3.000   9.000
1.000   -4.000  16.000

The constant vector b : size: 4 by 1
1.000
2.000
3.000
4.000

The least square solution is (using generalized inverse) : size: 3 by 1
0.909
0.079
0.212

The least square solution is (using QR decomposition) : size: 3 by 1
0.909
0.079
0.212

The least square solution is (using SVD decomposition) : size: 3 by 1
0.909
0.079
0.212

The original complex matrix cA : size: 4 by 3
(1.000,1.000)   (-1.000,-1.000) (1.000,1.000)
(1.000,1.000)   (2.000,2.000)   (4.000,4.000)
(1.000,1.000)   (3.000,3.000)   (9.000,9.000)
(1.000,1.000)   (-4.000,-4.000) (16.000,16.000)

The constant complex vector cb : size: 4 by 1
(1.000,0.000)
(2.000,0.000)
(3.000,0.000)
(4.000,0.000)

The least square solution is (using generalized inverse) : size: 3 by 1
(0.455,-0.455)
(0.039,-0.039)
(0.106,-0.106)

The least square solution is (using QR decomposition) : size: 3 by 1
(0.455,-0.455)
(0.039,-0.039)
(0.106,-0.106)

The least square solution is (using SVD decomposition) : size: 3 by 1
(0.455,-0.455)
(0.039,-0.039)
(0.106,-0.106)

The original matrix A : size: 3 by 4
1.000   1.000   1.000   1.000
-1.000  2.000   3.000   -4.000
1.000   4.000   9.000   16.000

The constant vector b : size: 3 by 1
1.000
2.000
3.000

The least norm solution is (using generalized inverse) : size: 4 by 1
0.373
0.421
0.336
-0.130

The least norm solution is (using QR decomposition) : size: 4 by 1
0.373
0.421
0.336
-0.130

The least norm solution is (using SVD decomposition) : size: 4 by 1
0.373
0.421
0.336
-0.130

The original complex matrix cA : size: 3 by 4
(1.000,-1.000)  (1.000,-1.000)  (1.000,-1.000)  (1.000,-1.000)
(-1.000,1.000)  (2.000,-2.000)  (3.000,-3.000)  (-4.000,4.000)
(1.000,-1.000)  (4.000,-4.000)  (9.000,-9.000)  (16.000,-16.000)

The constant complex vector cb : size: 3 by 1
(1.000,0.000)
(2.000,0.000)
(3.000,0.000)

The least square solution is (using generalized inverse) : size: 4 by 1
(0.186,0.186)
(0.211,0.211)
(0.168,0.168)
(-0.065,-0.065)

The least square solution is (using QR decomposition) : size: 4 by 1
(0.186,0.186)
(0.211,0.211)
(0.168,0.168)
(-0.065,-0.065)

The least square solution is (using SVD decomposition) : size: 4 by 1
(0.186,0.186)
(0.211,0.211)
(0.168,0.168)
(-0.065,-0.065)


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

你可能感兴趣的:(最小二乘解与极小范数解算法的C++实现(支持复系数方程组))