C:/programs/SCPPNT/src/include/lu.h

Go to the documentation of this file.
00001 /*! \file lu.h
00002  \brief Definition of functions LU_factor and LU_solve.
00003  
00004  Definition of functions LU_factor and LU_solve
00005  for solving system of linear equations Ax = b.
00006 
00007  Typical usage:
00008 
00009  Matrix<double> A;
00010  Vector<Subscript> ipiv;
00011  Vector<double> b;
00012 
00013  LU_Factor(A,ipiv);
00014  LU_Solve(A,ipiv,b);
00015 
00016  Now b has the solution x.  Note that both A and b
00017  are overwritten.  If these values need to be preserved, 
00018  one can make temporary copies, as in 
00019 
00020  Matrix<double> T = A;
00021  LU_Factor(T,ipiv);
00022  Vector<double> x=b;
00023  LU_Solve(T,ipiv,x);
00024 
00025  Contains modified version of the functions in lu.h from the
00026  Template Numerical Toolkit (TNT) using matrix iterators rather than
00027  matrix subscripting.
00028 
00029  */
00030 
00031 /*
00032 
00033  Simple C++ Numerical Toolkit (SCPPNT)
00034  http://www.smallwaters.com/software/cpp/scppnt.html
00035  This release updates original work contributed by 
00036  Brad Hanson (http://www.b-a-h.com/) in 2001.
00037 
00038  */
00039 
00040 // This is a modified version of the file lu.h from:
00041 /*
00042  *
00043  * Template Numerical Toolkit (TNT): Linear Algebra Module
00044  *
00045  * Mathematical and Computational Sciences Division
00046  * National Institute of Technology,
00047  * Gaithersburg, MD USA
00048  *
00049  *
00050  * This software was developed at the National Institute of Standards and
00051  * Technology (NIST) by employees of the Federal Government in the course
00052  * of their official duties. Pursuant to title 17 Section 105 of the
00053  * United States Code, this software is not subject to copyright protection
00054  * and is in the public domain.  The Template Numerical Toolkit (TNT) is
00055  * an experimental system.  NIST assumes no responsibility whatsoever for
00056  * its use by other parties, and makes no guarantees, expressed or implied,
00057  * about its quality, reliability, or any other characteristic.
00058  *
00059  * BETA VERSION INCOMPLETE AND SUBJECT TO CHANGE
00060  * see http://math.nist.gov/tnt for latest updates.
00061  *
00062  */
00063 
00064 #ifndef SCPPNT_LU_H
00065 #define SCPPNT_LU_H
00066 
00067 #include <cmath> // for fabs
00068 #ifdef BOOST_NO_STDC_NAMESPACE
00069 namespace std
00070 { using ::fabs;}
00071 #endif
00072 
00073 #ifdef SCPPNT_NO_DIR_PREFIX
00074 #include "scppnt.h"
00075 #include "scppnt_error.h"
00076 #else
00077 #include "scppnt/scppnt.h"
00078 #include "scppnt/scppnt_error.h"
00079 #endif
00080 
00081 namespace SCPPNT
00082 {
00083 
00084   /*! \brief Right-looking LU factorization algorithm (unblocked)
00085    
00086    Factors matrix A into lower and upper  triangular matrices 
00087    (L and U respectively) in solving the linear equation Ax=b. 
00088    LU_solve can be used to solve a system of linear equating using
00089    factorization computed.
00090    
00091    Return value:
00092    
00093    int      (0 if successful, 1 otherwise)
00094    
00095    Args:
00096    
00097    \param A        (input/output) Matrix(1:n, 1:n)  In input, matrix to be
00098    factored.  On output, overwritten with lower and 
00099    upper triangular factors.
00100    
00101    \param indx     (output) Vector(1:n)    Pivot vector. Describes how
00102    the rows of A were reordered to increase
00103    numerical stability.
00104    
00105    */
00106   template<class MaTRiX, class VecToRSubscript> int LU_factor(MaTRiX &A, VecToRSubscript &indx)
00107   {
00108     // currently for 1-offset
00109     // vectors and matrices
00110     //if (A.lbound() != 1) throw InvalidArgument("Matrix not 1-offset", "SCPPNT::LU_factor");
00111     //if (indx.lbound() != 1) throw InvalidArgument("Subscript vector not 1-offset", "SCPPNT::LU_factor");
00112 
00113     typedef typename MaTRiX::column_iterator column_iterator;
00114     typedef typename MaTRiX::row_iterator row_iterator;
00115 
00116     Subscript M = A.num_rows();
00117     Subscript N = A.num_columns();
00118 
00119     if (M == 0 || N==0)
00120       return 0;
00121     if (indx.dim() != M)
00122       indx.newsize(M);
00123 
00124     Subscript i, j, k;
00125     Subscript jp;
00126 
00127     typename MaTRiX::element_type t;
00128 
00129     Subscript minMN = (M < N ? M : N); // min(M,N);
00130 
00131     typename MaTRiX::diag_iterator adiag = A.begin_diagonal(1, 1);
00132     typename MaTRiX::columns_iterator icolumns = A.begin_columns();
00133     for (j=1; j<= minMN; j++, ++adiag, ++icolumns)
00134     {
00135       // find pivot in column j and  test for singularity.
00136 
00137       jp = j;
00138       t = std::fabs(*adiag); //t = fabs(A(j,j));
00139 
00140       column_iterator ic = *icolumns + j;
00141       for (i=j+1; i<=M; i++, ++ic)
00142       {
00143         double ab = std::fabs(*ic);
00144         if (ab > t) // if ( fabs(A(i,j)) > t)
00145         {
00146           jp = i;
00147           t = ab; //t = fabs(A(i,j));
00148         }
00149       }
00150 
00151       indx(j) = jp;
00152 
00153       // jp now has the index of maximum element 
00154       // of column j, below the diagonal
00155 
00156       if ((*icolumns)[jp-1] == 0) // if ( A(jp,j) == 0 )
00157         return 1; // factorization failed because of zero pivot
00158 
00159       if (jp != j) // swap rows j and jp
00160       {
00161         row_iterator irowj = A.begin_row(j);
00162         row_iterator irowjp = A.begin_row(jp);
00163 
00164         for (k=1; k<=N; k++, ++irowj, ++irowjp)
00165         {
00166           t = *irowj; //  t = A(j,k);
00167           *irowj = *irowjp; //  A(j,k) = A(jp,k);
00168           *irowjp = t; // A(jp,k) =t;
00169         }
00170       }
00171 
00172       if (j<M) // compute elements j+1:M of jth column
00173       {
00174         // note A(j,j), was A(jp,p) previously which was
00175         // guarranteed not to be zero (Label #1)
00176         //
00177         typename MaTRiX::element_type recp = 1.0 / *adiag; // 1.0 / A(j,j)
00178 
00179         ic = *icolumns + j;
00180         for (k=j+1; k<=M; k++, ++ic)
00181           *ic *= recp; //A(k,j) *= recp;
00182 
00183       }
00184 
00185       if (j < minMN)
00186       {
00187         // rank-1 update to trailing submatrix:   E = E - x*y;
00188         //
00189         // E is the region A(j+1:M, j+1:N)
00190         // x is the column vector A(j+1:M,j)
00191         // y is row vector A(j,j+1:N)
00192 
00193         Subscript ii, jj;
00194 
00195         column_iterator ix = *icolumns + j;
00196         for (ii=j+1; ii<=M; ii++, ++ix) // for (ii=j+1; ii<=M; ii++)
00197         {
00198           row_iterator iE = A.begin_row(ii) + j;
00199           row_iterator iy = A.begin_row(j) + j;
00200           for (jj=j+1; jj<=N; jj++, ++iE, ++iy)
00201             // for (jj=j+1; jj<=N; jj++)
00202             *iE -= *ix * *iy; // A(ii,jj) -= A(ii,j)*A(j,jj);
00203         }
00204       }
00205     }
00206     return 0;
00207   }
00208 
00209   /*!
00210    \brief Solve system of linear equations using LU factorization computed from LU_factor.
00211    
00212    Typical usage for solving system of linear equations Ax = b:
00213    
00214    Matrix<double> A;
00215    Vector<Subscript> ipiv;
00216    Vector<double> b;
00217    
00218    LU_Factor(A,ipiv);
00219    LU_Solve(A,ipiv,b);
00220    
00221    Now b has the solution x.  Note that both A and b
00222    are overwritten.
00223    */
00224   template<class MaTRiX, class VecToR, class VecToRSubscripts> int LU_solve(const MaTRiX &A,
00225       const VecToRSubscripts &indx, VecToR &b)
00226   {
00227     // currently for 1-offset
00228     // vectors and matrices
00229     //if (A.lbound() != 1) throw InvalidArgument("Matrix not 1-offset", "SCPPNT::LU_solve");
00230     //if (indx.lbound() != 1) throw InvalidArgument("Subscript vector not 1-offset", "SCPPNT::LU_solve");
00231     //if (b.lbound() != 1) throw InvalidArgument("Vector not 1-offset", "SCPPNT::LU_solve");
00232 
00233     typedef typename MaTRiX::const_row_iterator row_iterator;
00234     typedef typename VecToR::iterator vector_iterator;
00235 
00236     Subscript i, ii=0, ip, j;
00237     Subscript n = b.dim();
00238     typename MaTRiX::element_type sum;
00239 
00240     for (i=1; i<=n; i++)
00241     {
00242       ip=indx(i);
00243       sum=b(ip);
00244       b(ip)=b(i);
00245       if (ii)
00246       {
00247         row_iterator Aj = A.begin_row(i) + ii-1;
00248         vector_iterator bj = b.begin() + ii - 1;
00249         for (j=ii; j<=i-1; j++, ++Aj, ++bj)
00250           sum -= *Aj * *bj; //sum -= A(i,j)*b(j);
00251       }
00252       else if (sum)
00253         ii=i;
00254       b(i)=sum;
00255     }
00256 
00257     typename MaTRiX::const_diag_iterator adiag = A.begin_diagonal(1, 1) + n - 1;
00258     for (i=n; i>=1; --i, --adiag)
00259     {
00260       sum=b(i);
00261       row_iterator Aj = A.begin_row(i) + i;
00262       vector_iterator bj = b.begin() + i;
00263       for (j=i+1; j<=n; j++, ++Aj, ++bj)
00264         sum -= *Aj * *bj; //sum -= A(i,j)*b(j);
00265       b(i)=sum / *adiag; //  b(i)=sum/A(i,i)
00266     }
00267     return 0;
00268   }
00269 
00270 } // namespace SCPPNT
00271 
00272 #endif
00273 // SCPPNT_LU_H

Generated on Tue Dec 18 23:34:05 2007 for SCPPNT by  doxygen 1.5.4