头文件:
/* * 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 */ /***************************************************************************** * lud.h * * Class template of LU decomposition. * * For an m-by-n matrix A with m >= n, the LU decomposition is an m-by-n * unit lower triangular matrix L, an n-by-n upper triangular matrix U, and * a permutation vector piv of length m so that A(piv,:) = L*U. If m < n, * then L is m-by-m and U is m-by-n. * * The matrix can be both REAL or COMPLEX. * * The LU decompostion with pivoting always exists, even if the matrix is * singular, so the constructor will never fail. The primary use of the LU * decomposition is in the solution of square systems of simultaneouslinear * equations. This will fail if isNonsingular() returns false. * * Adapted form Template Numerical Toolkit. * * Zhang Ming, 2010-01 (revised 2010-12), Xi'an Jiaotong University. *****************************************************************************/ #ifndef LUD_H #define LUD_H #include <matrix.h> namespace splab { template <typename Type> class LUD { public : LUD(); ~LUD(); void dec( const Matrix<Type> &A ); Matrix<Type> getL(); Matrix<Type> getU(); Vector<int> getPivot() const; Type det(); bool isNonsingular(); Vector<Type> solve( const Vector<Type> &b ); Matrix<Type> solve( const Matrix<Type> &B ); private: // Array for internal storage of decomposition. Matrix<Type> LU; int m; int n; int pivsign; Vector<int> piv; Vector<Type> permuteCopy( const Vector<Type> &A, const Vector<int> &piv ); Matrix<Type> permuteCopy( const Matrix<Type> &A, const Vector<int> &piv, int j0, int j1 ); }; // class LUD #include <lud-impl.h> } // namespace splab #endif // LUD_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 */ /***************************************************************************** * lud-impl.h * * Implementation for LUD class. * * Zhang Ming, 2010-01 (revised 2010-12), Xi'an Jiaotong University. *****************************************************************************/ /** * constructor and destructor */ template<typename Type> LUD<Type>::LUD() { } template<typename Type> LUD<Type>::~LUD() { } /** * permute copy */ template <typename Type> Vector<Type> LUD<Type>::permuteCopy( const Vector<Type> &A, const Vector<int> &piv ) { int pivLength = piv.dim(); if( pivLength != A.dim() ) return Vector<Type>(); Vector<Type> x(pivLength); for( int i=0; i<pivLength; ++i ) x[i] = A[piv[i]]; return x; } template <typename Type> Matrix<Type> LUD<Type>::permuteCopy( const Matrix<Type> &A, const Vector<int> &piv, int j0, int j1 ) { int pivLength = piv.dim(); Matrix<Type> X( pivLength, j1-j0+1 ); for( int i=0; i<pivLength; ++i ) for( int j=j0; j<=j1; ++j ) X[i][j-j0] = A[piv[i]][j]; return X; } /** * Return pivot permutation vector */ template<typename Type> inline Vector<int> LUD<Type>::getPivot() const { return piv; } /** * LU Decomposition */ template <typename Type> void LUD<Type>::dec(const Matrix<Type> &A) { m = A.rows(); n = A.cols(); piv.resize(m); LU = A; // Use a "left-looking", dot-product, Crout/Doolittle algorithm. for( int i=0; i<m; ++i ) piv[i] = i; pivsign = 1; Type *LUrowi = 0; Vector<Type> LUcolj(m); // outer loop for( int j=0; j<n; ++j ) { // Make a copy of the j-th column to localize references. for( int i=0; i<m; ++i ) LUcolj[i] = LU[i][j]; // Apply previous transformations. for( int i=0; i<m; ++i ) { LUrowi = LU[i]; // Most of the time is spent in the following dot product. int kmax = (i < j)? i : j; Type s = 0; for( int k=0; k<kmax; ++k ) s += LUrowi[k]*LUcolj[k]; LUrowi[j] = LUcolj[i] -= s; } // Find pivot and exchange if necessary. int p = j; for( int i=j+1; i<m; ++i ) if( abs(LUcolj[i]) > abs(LUcolj[p]) ) p = i; if( p != j ) { int k=0; for( k=0; k<n; ++k ) swap( LU[p][k], LU[j][k] ); swap( piv[p], piv[j] ); pivsign = -pivsign; } // compute multipliers if( (j < m) && ( abs(LU[j][j]) != 0 ) ) for( int i=j+1; i<m; ++i ) LU[i][j] /= LU[j][j]; } } /** * Return lower triangular matrix L. */ template <typename Type> Matrix<Type> LUD<Type>::getL() { int p = min( m, n ); Matrix<Type> tmp( m, p ); for( int i=0; i<m; ++i ) for( int j=0; j<i && j<n; ++j ) tmp[i][j] = LU[i][j]; for( int i=0; i<p; ++i ) tmp[i][i] = 1; return tmp; } /** * Return upper triangular matrix U. */ template <typename Type> Matrix<Type>LUD<Type>::getU() { int p = min( m, n ); Matrix<Type> tmp( p, n ); for( int i=0; i<m; ++i ) for( int j=i; j<n; ++j ) tmp[i][j] = LU[i][j]; return tmp; } /** * Compute determinant using LU factors. */ template <typename Type> Type LUD<Type>::det() { if( m != n ) return 0; Type d = Type(pivsign); for( int j=0; j<n; ++j ) d *= LU[j][j]; return d; } /** * true if upper triangular factor U is nonsingular, 0 otherwise. */ template <typename Type> inline bool LUD<Type>::isNonsingular() { for( int j=0; j<n; ++j ) if( abs(LU[j][j]) == 0 ) return false; return true; } /** * Solve A*x = b, where x and b are vectors of length equal * to the number of rows in A. */ template <typename Type> Vector<Type> LUD<Type>::solve( const Vector<Type> &b ) { // dimensions: A is mxn, X is nxk, B is mxk if( b.dim() != m ) return Vector<Type>(); if( !isNonsingular() ) return Vector<Type>(); Vector<Type> x = permuteCopy( b, piv ); // solve L*Y = B(piv) for( int k=0; k<n; ++k ) for( int i=k+1; i<n; ++i ) x[i] -= x[k]*LU[i][k]; // solve U*x = y; for( int k=n-1; k>=0; --k ) { x[k] /= LU[k][k]; for( int i=0; i<k; ++i ) x[i] -= x[k]*LU[i][k]; } return x; } /** * Solve A*X = B */ template <typename Type> Matrix<Type> LUD<Type>::solve( const Matrix<Type> &B ) { // dimensions: A is mxn, X is nxk, B is mxk if( B.rows() != m ) return Matrix<Type>(0,0); if( !isNonsingular() ) return Matrix<Type>(0,0); // copy right hand side with pivoting int nx = B.cols(); Matrix<Type> X = permuteCopy( B, piv, 0, nx-1 ); // solve L*Y = B(piv,:) for( int k=0; k<n; ++k ) for( int i=k+1; i<n; ++i ) for( int j=0; j<nx; ++j ) X[i][j] -= X[k][j]*LU[i][k]; // solve U*X = Y; for( int k=n-1; k>=0; --k ) { for( int j=0; j<nx; ++j ) X[k][j] /= LU[k][k]; for( int i=0; i<k; ++i ) for( int j=0; j<nx; ++j ) X[i][j] -= X[k][j]*LU[i][k]; } return X; }
测试代码:
/***************************************************************************** * lud_test.cpp * * LUD class testing. * * Zhang Ming, 2010-01 (revised 2010-12), Xi'an Jiaotong University. *****************************************************************************/ #define BOUNDS_CHECK #include <iostream> #include <iomanip> #include <lud.h> using namespace std; using namespace splab; typedef double Type; const int M = 3; const int N = 4; int main() { Matrix<Type> A(3,3), B(3,3), L, U; Vector<Type> b(3); A[0][0] = 1; A[0][1] = 2; A[0][2] = 1; A[1][0] = 2; A[1][1] = 5; A[1][2] = 4; A[2][0] = 1; A[2][1] = 1; A[2][2] = 0; B[0][0] = 1; B[0][1] = 0; B[0][2] = 0; B[1][0] = 0; B[1][1] = 1; B[1][2] = 0; B[2][0] = 0; B[2][1] = 0; B[2][2] = 1; b[0] = 1; b[1] = 0; b[2] = 1; LUD<Type> lu; lu.dec(A); L = lu.getL(); U = lu.getU(); cout << setiosflags(ios::fixed) << setprecision(4); cout << "The original matrix A is : " << A << endl; cout << "The unit lower triangular matrix L is : " << L << endl; cout << "The upper triangular matrix U is : " << U << endl; Vector<Type> x = lu.solve(b); cout << "The constant vector b : " << b << endl; cout << "The solution of A * x = b : " << x << endl; cout << "The solution of A * x - b : " << A*x - b << endl; cout << "The inverse matrix of A : " << lu.solve(B) << endl; cout << "The A * inverse(A) : " << A*lu.solve(B) << endl; cout << "The determinant of A : " << endl; cout << lu.det() << endl << endl << endl; Matrix<complex<Type> > cA(M,N), cPA(M,N), invcA, cL, cU; for( int i=0; i<M; i++ ) for( int j=0; j<N; j++ ) cA[i][j] = complex<Type>( Type(0.3*i+0.7*j), sin(Type(i+j)) ); LUD<complex<Type> > clu; clu.dec(cA); cL = clu.getL(); cU = clu.getU(); Vector<int> p = clu.getPivot(); for( int i=0; i<M; ++i ) cPA.setRow( cA.getRow(p[i]), i ); cout << setiosflags(ios::fixed) << setprecision(3); cout << "The original complex matrix cA is : " << cA << endl; cout << "The unit lower triangular matrix cL is : " << cL << endl; cout << "The upper triangular matrix cU is : " << cU << endl; cout << "cP*cA - cL*cU is : " << cPA - cL*cU << endl; if( M == N ) { invcA = clu.solve( eye( M, complex<Type>(1.0,0) ) ); cout << "The inverse matrix of cA : " << invcA << endl; cout << "The cA * inverse(cA) : " << cA*invcA << endl; } return 0; }
运行结果:
The original matrix A is : size: 3 by 3 1.0000 2.0000 1.0000 2.0000 5.0000 4.0000 1.0000 1.0000 0.0000 The unit lower triangular matrix L is : size: 3 by 3 1.0000 0.0000 0.0000 0.5000 1.0000 0.0000 0.5000 0.3333 1.0000 The upper triangular matrix U is : size: 3 by 3 2.0000 5.0000 4.0000 0.0000 -1.5000 -2.0000 0.0000 0.0000 -0.3333 The constant vector b : size: 3 by 1 1.0000 0.0000 1.0000 The solution of A * x = b : size: 3 by 1 -1.0000 2.0000 -2.0000 The solution of A * x - b : size: 3 by 1 -0.0000 0.0000 0.0000 The inverse matrix of A : size: 3 by 3 -4.0000 1.0000 3.0000 4.0000 -1.0000 -2.0000 -3.0000 1.0000 1.0000 The A * inverse(A) : size: 3 by 3 1.0000 0.0000 0.0000 0.0000 1.0000 0.0000 0.0000 0.0000 1.0000 The determinant of A : 1.0000 The original complex matrix cA is : size: 3 by 4 (0.000,0.000) (0.700,0.841) (1.400,0.909) (2.100,0.141) (0.300,0.841) (1.000,0.909) (1.700,0.141) (2.400,-0.757) (0.600,0.909) (1.300,0.141) (2.000,-0.757) (2.700,-0.959) The unit lower triangular matrix cL is : size: 3 by 3 (1.000,0.000) (0.000,0.000) (0.000,0.000) (0.000,0.000) (1.000,0.000) (0.000,0.000) (0.796,0.196) (0.377,0.322) (1.000,0.000) The upper triangular matrix cU is : size: 3 by 4 (0.600,0.909) (1.300,0.141) (2.000,-0.757) (2.700,-0.959) (0.000,0.000) (0.700,0.841) (1.400,0.909) (2.100,0.141) (0.000,0.000) (0.000,0.000) (-0.275,-0.441) (-0.683,-1.252) cP*cA - cL*cU is : size: 3 by 4 (0.000,0.000) (0.000,0.000) (0.000,0.000) (0.000,0.000) (0.000,0.000) (0.000,0.000) (0.000,0.000) (0.000,0.000) (0.000,0.000) (0.000,0.000) (0.000,-0.000) (0.000,0.000) Process returned 0 (0x0) execution time : 0.109 s Press any key to continue.