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