Blender V2.61 - r43446

qr.h

Go to the documentation of this file.
00001 
00004 /*
00005 
00006 *
00007 * Template Numerical Toolkit (TNT): Linear Algebra Module
00008 *
00009 * Mathematical and Computational Sciences Division
00010 * National Institute of Technology,
00011 * Gaithersburg, MD USA
00012 *
00013 *
00014 * This software was developed at the National Institute of Standards and
00015 * Technology (NIST) by employees of the Federal Government in the course
00016 * of their official duties. Pursuant to title 17 Section 105 of the
00017 * United States Code, this software is not subject to copyright protection
00018 * and is in the public domain.  The Template Numerical Toolkit (TNT) is
00019 * an experimental system.  NIST assumes no responsibility whatsoever for
00020 * its use by other parties, and makes no guarantees, expressed or implied,
00021 * about its quality, reliability, or any other characteristic.
00022 *
00023 * BETA VERSION INCOMPLETE AND SUBJECT TO CHANGE
00024 * see http://math.nist.gov/tnt for latest updates.
00025 *
00026 */
00027 
00028 
00029 #ifndef QR_H
00030 #define QR_H
00031 
00032 // Classical QR factorization example, based on Stewart[1973].
00033 //
00034 //
00035 // This algorithm computes the factorization of a matrix A
00036 // into a product of an orthognal matrix (Q) and an upper triangular 
00037 // matrix (R), such that QR = A.
00038 //
00039 // Parameters:
00040 //
00041 //  A   (in):       Matrix(1:N, 1:N)
00042 //
00043 //  Q   (output):   Matrix(1:N, 1:N), collection of Householder
00044 //                      column vectors Q1, Q2, ... QN
00045 //
00046 //  R   (output):   upper triangular Matrix(1:N, 1:N)
00047 //
00048 // Returns:  
00049 //
00050 //  0 if successful, 1 if A is detected to be singular
00051 //
00052 
00053 
00054 #include <cmath>      //for sqrt() & fabs()
00055 #include "tntmath.h"  // for sign()
00056 
00057 // Classical QR factorization, based on Stewart[1973].
00058 //
00059 //
00060 // This algorithm computes the factorization of a matrix A
00061 // into a product of an orthognal matrix (Q) and an upper triangular 
00062 // matrix (R), such that QR = A.
00063 //
00064 // Parameters:
00065 //
00066 //  A   (in/out):  On input, A is square, Matrix(1:N, 1:N), that represents
00067 //                  the matrix to be factored.
00068 //
00069 //                 On output, Q and R is encoded in the same Matrix(1:N,1:N)
00070 //                 in the following manner:
00071 //
00072 //                  R is contained in the upper triangular section of A,
00073 //                  except that R's main diagonal is in D.  The lower
00074 //                  triangular section of A represents Q, where each
00075 //                  column j is the vector  Qj = I - uj*uj'/pi_j.
00076 //
00077 //  C  (output):    vector of Pi[j]
00078 //  D  (output):    main diagonal of R, i.e. D(i) is R(i,i)
00079 //
00080 // Returns:  
00081 //
00082 //  0 if successful, 1 if A is detected to be singular
00083 //
00084 
00085 namespace TNT
00086 {
00087 
00088 template <class MaTRiX, class Vector>
00089 int QR_factor(MaTRiX &A, Vector& C, Vector &D)
00090 {
00091     assert(A.lbound() == 1);        // ensure these are all 
00092     assert(C.lbound() == 1);        // 1-based arrays and vectors
00093     assert(D.lbound() == 1);
00094 
00095     Subscript M = A.num_rows();
00096     Subscript N = A.num_cols(); 
00097 
00098     assert(M == N);                 // make sure A is square
00099 
00100     Subscript i,j,k;
00101     typename MaTRiX::element_type eta, sigma, sum;
00102 
00103     // adjust the shape of C and D, if needed...
00104 
00105     if (N != C.size())  C.newsize(N);
00106     if (N != D.size())  D.newsize(N);
00107 
00108     for (k=1; k<N; k++)
00109     {
00110         // eta = max |M(i,k)|,  for k <= i <= n
00111         //
00112         eta = 0;
00113         for (i=k; i<=N; i++)
00114         {
00115             double absA = fabs(A(i,k));
00116             eta = ( absA >  eta ? absA : eta ); 
00117         }
00118 
00119         if (eta == 0)           // matrix is singular
00120         {
00121             cerr << "QR: k=" << k << "\n";
00122             return 1;
00123         }
00124 
00125         // form Qk and premiltiply M by it
00126         //
00127         for(i=k; i<=N; i++)
00128             A(i,k)  = A(i,k) / eta;
00129 
00130         sum = 0;
00131         for (i=k; i<=N; i++)
00132             sum = sum + A(i,k)*A(i,k);
00133         sigma = sign(A(k,k)) *  sqrt(sum);
00134 
00135 
00136         A(k,k) = A(k,k) + sigma;
00137         C(k) = sigma * A(k,k);
00138         D(k) = -eta * sigma;
00139 
00140         for (j=k+1; j<=N; j++)
00141         {
00142             sum = 0;
00143             for (i=k; i<=N; i++)
00144                 sum = sum + A(i,k)*A(i,j);
00145             sum = sum / C(k);
00146 
00147             for (i=k; i<=N; i++)
00148                 A(i,j) = A(i,j) - sum * A(i,k);
00149         }
00150 
00151         D(N) = A(N,N);
00152     }
00153 
00154     return 0;
00155 }
00156 
00157 // modified form of upper triangular solve, except that the main diagonal
00158 // of R (upper portion of A) is in D.
00159 //
00160 template <class MaTRiX, class Vector>
00161 int R_solve(const MaTRiX &A, /*const*/ Vector &D, Vector &b)
00162 {
00163     assert(A.lbound() == 1);        // ensure these are all 
00164     assert(D.lbound() == 1);        // 1-based arrays and vectors
00165     assert(b.lbound() == 1);
00166 
00167     Subscript i,j;
00168     Subscript N = A.num_rows();
00169 
00170     assert(N == A.num_cols());
00171     assert(N == D.dim());
00172     assert(N == b.dim());
00173 
00174     typename MaTRiX::element_type sum;
00175 
00176     if (D(N) == 0)
00177         return 1;
00178 
00179     b(N) = b(N) / 
00180             D(N);
00181 
00182     for (i=N-1; i>=1; i--)
00183     {
00184         if (D(i) == 0)
00185             return 1;
00186         sum = 0;
00187         for (j=i+1; j<=N; j++)
00188             sum = sum + A(i,j)*b(j);
00189         b(i) = ( b(i) - sum ) / 
00190             D(i);
00191     }
00192 
00193     return 0;
00194 }
00195 
00196 
00197 template <class MaTRiX, class Vector>
00198 int QR_solve(const MaTRiX &A, const Vector &c, /*const*/ Vector &d, 
00199         Vector &b)
00200 {
00201     assert(A.lbound() == 1);        // ensure these are all 
00202     assert(c.lbound() == 1);        // 1-based arrays and vectors
00203     assert(d.lbound() == 1);
00204 
00205     Subscript N=A.num_rows();
00206 
00207     assert(N == A.num_cols());
00208     assert(N == c.dim());
00209     assert(N == d.dim());
00210     assert(N == b.dim());
00211 
00212     Subscript i,j;
00213     typename MaTRiX::element_type sum, tau;
00214 
00215     for (j=1; j<N; j++)
00216     {
00217         // form Q'*b
00218         sum = 0;
00219         for (i=j; i<=N; i++)
00220             sum = sum + A(i,j)*b(i);
00221         if (c(j) == 0)
00222             return 1;
00223         tau = sum / c(j);
00224        for (i=j; i<=N; i++)
00225             b(i) = b(i) - tau * A(i,j);
00226     }
00227     return R_solve(A, d, b);        // solve Rx = Q'b
00228 }
00229 
00230 } // namespace TNT
00231 
00232 #endif // QR_H
00233