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