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