Homepage Demos Overview Downloads Tutorials Reference
Credits

cholesky.cpp

Go to the documentation of this file.
00001 //$$ cholesky.cpp                     cholesky decomposition
00002 
00003 // Copyright (C) 1991,2,3,4: R B Davies
00004 
00005 #define WANT_MATH
00006 //#define WANT_STREAM
00007 
00008 #include "include.h"
00009 
00010 #include "newmat.h"
00011 #include "newmatrm.h"
00012 
00013 #ifdef use_namespace
00014 namespace NEWMAT {
00015 #endif
00016 
00017 #ifdef DO_REPORT
00018 #define REPORT { static ExeCounter ExeCount(__LINE__,14); ++ExeCount; }
00019 #else
00020 #define REPORT {}
00021 #endif
00022 
00023 /********* Cholesky decomposition of a positive definite matrix *************/
00024 
00025 // Suppose S is symmetrix and positive definite. Then there exists a unique
00026 // lower triangular matrix L such that L L.t() = S;
00027 
00028 
00029 ReturnMatrix Cholesky(const SymmetricMatrix& S)
00030 {
00031    REPORT
00032    Tracer trace("Cholesky");
00033    int nr = S.Nrows();
00034    LowerTriangularMatrix T(nr);
00035    Real* s = S.Store(); Real* t = T.Store(); Real* ti = t;
00036    for (int i=0; i<nr; i++)
00037    {
00038       Real* tj = t; Real sum; int k;
00039       for (int j=0; j<i; j++)
00040       {
00041          Real* tk = ti; sum = 0.0; k = j;
00042          while (k--) { sum += *tj++ * *tk++; }
00043          *tk = (*s++ - sum) / *tj++;
00044       }
00045       sum = 0.0; k = i;
00046       while (k--) { sum += square(*ti++); }
00047       Real d = *s++ - sum;
00048       if (d<=0.0)  Throw(NPDException(S));
00049       *ti++ = sqrt(d);
00050    }
00051    T.Release(); return T.ForReturn();
00052 }
00053 
00054 ReturnMatrix Cholesky(const SymmetricBandMatrix& S)
00055 {
00056    REPORT
00057    Tracer trace("Band-Cholesky");
00058    int nr = S.Nrows(); int m = S.lower;
00059    LowerBandMatrix T(nr,m);
00060    Real* s = S.Store(); Real* t = T.Store(); Real* ti = t;
00061 
00062    for (int i=0; i<nr; i++)
00063    {
00064       Real* tj = t; Real sum; int l;
00065       if (i<m) { REPORT l = m-i; s += l; ti += l; l = i; }
00066       else { REPORT t += (m+1); l = m; }
00067 
00068       for (int j=0; j<l; j++)
00069       {
00070          Real* tk = ti; sum = 0.0; int k = j; tj += (m-j);
00071          while (k--) { sum += *tj++ * *tk++; }
00072          *tk = (*s++ - sum) / *tj++;
00073       }
00074       sum = 0.0;
00075       while (l--) { sum += square(*ti++); }
00076       Real d = *s++ - sum;
00077       if (d<=0.0)  Throw(NPDException(S));
00078       *ti++ = sqrt(d);
00079    }
00080 
00081    T.Release(); return T.ForReturn();
00082 }
00083 
00084 
00085 
00086 
00087 // Contributed by Nick Bennett of Schlumberger-Doll Research; modified by RBD
00088 
00089 // The enclosed routines can be used to update the Cholesky decomposition of
00090 // a positive definite symmetric matrix.  A good reference for this routines
00091 // can be found in
00092 // LINPACK User's Guide, Chapter 10, Dongarra et. al., SIAM, Philadelphia, 1979
00093 
00094 // produces the Cholesky decomposition of A + x.t() * x where A = chol.t() * chol
00095 void UpdateCholesky(UpperTriangularMatrix &chol, RowVector r1Modification)
00096 {
00097    int nc = chol.Nrows();
00098    ColumnVector cGivens(nc); cGivens = 0.0;
00099    ColumnVector sGivens(nc); sGivens = 0.0;
00100   
00101    for(int j = 1; j <= nc; ++j) // process the jth column of chol
00102    {
00103       // apply the previous Givens rotations k = 1,...,j-1 to column j
00104       for(int k = 1; k < j; ++k)
00105          GivensRotation(cGivens(k), sGivens(k), chol(k,j), r1Modification(j));
00106 
00107       // determine the jth Given's rotation
00108       pythag(chol(j,j), r1Modification(j), cGivens(j), sGivens(j));
00109 
00110       // apply the jth Given's rotation
00111       {
00112          Real tmp0 = cGivens(j) * chol(j,j) + sGivens(j) * r1Modification(j);
00113          chol(j,j) = tmp0; r1Modification(j) = 0.0;
00114       }
00115 
00116    }
00117 
00118 }
00119 
00120 
00121 // produces the Cholesky decomposition of A - x.t() * x where A = chol.t() * chol
00122 void DowndateCholesky(UpperTriangularMatrix &chol, RowVector x)
00123 {
00124    int nRC = chol.Nrows();
00125   
00126    // solve R^T a = x
00127    LowerTriangularMatrix L = chol.t();
00128    ColumnVector a(nRC); a = 0.0;
00129    int i, j;
00130   
00131    for (i = 1; i <= nRC; ++i)
00132    {
00133       // accumulate subtr sum
00134       Real subtrsum = 0.0;
00135       for(int k = 1; k < i; ++k) subtrsum += a(k) * L(i,k);
00136 
00137       a(i) = (x(i) - subtrsum) / L(i,i);
00138    }
00139 
00140    // test that l2 norm of a is < 1
00141    Real squareNormA = a.SumSquare();
00142    if (squareNormA >= 1.0)
00143       Throw(ProgramException("DowndateCholesky() fails", chol));
00144 
00145    Real alpha = sqrt(1.0 - squareNormA);
00146 
00147    // compute and apply Givens rotations to the vector a
00148    ColumnVector cGivens(nRC);  cGivens = 0.0;
00149    ColumnVector sGivens(nRC);  sGivens = 0.0;
00150    for(i = nRC; i >= 1; i--)
00151       alpha = pythag(alpha, a(i), cGivens(i), sGivens(i));
00152 
00153    // apply Givens rotations to the jth column of chol
00154    ColumnVector xtilde(nRC); xtilde = 0.0;
00155    for(j = nRC; j >= 1; j--)
00156    {
00157       // only the first j rotations have an affect on chol,0
00158       for(int k = j; k >= 1; k--)
00159          GivensRotation(cGivens(k), -sGivens(k), chol(k,j), xtilde(j));
00160    }
00161 }
00162 
00163 
00164 
00165 // produces the Cholesky decomposition of EAE where A = chol.t() * chol
00166 // and E produces a RIGHT circular shift of the rows and columns from
00167 // 1,...,k-1,k,k+1,...l,l+1,...,p to
00168 // 1,...,k-1,l,k,k+1,...l-1,l+1,...p
00169 void RightCircularUpdateCholesky(UpperTriangularMatrix &chol, int k, int l)
00170 {
00171    int nRC = chol.Nrows();
00172    int i, j;
00173   
00174    // I. compute shift of column l to the kth position
00175    Matrix cholCopy = chol;
00176    // a. grab column l
00177    ColumnVector columnL = cholCopy.Column(l);
00178    // b. shift columns k,...l-1 to the RIGHT
00179    for(j = l-1; j >= k; --j)
00180       cholCopy.Column(j+1) = cholCopy.Column(j);
00181    // c. copy the top k-1 elements of columnL into the kth column of cholCopy
00182    cholCopy.Column(k) = 0.0;
00183    for(i = 1; i < k; ++i) cholCopy(i,k) = columnL(i);
00184 
00185     // II. determine the l-k Given's rotations
00186    int nGivens = l-k;
00187    ColumnVector cGivens(nGivens); cGivens = 0.0;
00188    ColumnVector sGivens(nGivens); sGivens = 0.0;
00189    for(i = l; i > k; i--)
00190    {
00191       int givensIndex = l-i+1;
00192       columnL(i-1) = pythag(columnL(i-1), columnL(i),
00193          cGivens(givensIndex), sGivens(givensIndex));
00194       columnL(i) = 0.0;
00195    }
00196    // the kth entry of columnL is the new diagonal element in column k of cholCopy
00197    cholCopy(k,k) = columnL(k);
00198   
00199    // III. apply these Given's rotations to subsequent columns
00200    // for columns k+1,...,l-1 we only need to apply the last nGivens-(j-k) rotations
00201    for(j = k+1; j <= nRC; ++j)
00202    {
00203       ColumnVector columnJ = cholCopy.Column(j);
00204       int imin = nGivens - (j-k) + 1; if (imin < 1) imin = 1;
00205       for(int gIndex = imin; gIndex <= nGivens; ++gIndex)
00206       {
00207          // apply gIndex Given's rotation
00208          int topRowIndex = k + nGivens - gIndex;
00209          GivensRotationR(cGivens(gIndex), sGivens(gIndex),
00210             columnJ(topRowIndex), columnJ(topRowIndex+1));
00211       }
00212       cholCopy.Column(j) = columnJ;
00213    }
00214 
00215    chol << cholCopy;
00216 }
00217 
00218 
00219 
00220 // produces the Cholesky decomposition of EAE where A = chol.t() * chol
00221 // and E produces a LEFT circular shift of the rows and columns from
00222 // 1,...,k-1,k,k+1,...l,l+1,...,p to
00223 // 1,...,k-1,k+1,...l,k,l+1,...,p to
00224 void LeftCircularUpdateCholesky(UpperTriangularMatrix &chol, int k, int l)
00225 {
00226    int nRC = chol.Nrows();
00227    int i, j;
00228 
00229    // I. compute shift of column k to the lth position
00230    Matrix cholCopy = chol;
00231    // a. grab column k
00232    ColumnVector columnK = cholCopy.Column(k);
00233    // b. shift columns k+1,...l to the LEFT
00234    for(j = k+1; j <= l; ++j)
00235       cholCopy.Column(j-1) = cholCopy.Column(j);
00236    // c. copy the elements of columnK into the lth column of cholCopy
00237    cholCopy.Column(l) = 0.0;
00238    for(i = 1; i <= k; ++i)
00239       cholCopy(i,l) = columnK(i);
00240 
00241    // II. apply and compute Given's rotations
00242    int nGivens = l-k;
00243    ColumnVector cGivens(nGivens); cGivens = 0.0;
00244    ColumnVector sGivens(nGivens); sGivens = 0.0;
00245    for(j = k; j <= nRC; ++j)
00246    {
00247       ColumnVector columnJ = cholCopy.Column(j);
00248 
00249       // apply the previous Givens rotations to columnJ
00250       int imax = j - k; if (imax > nGivens) imax = nGivens;
00251       for(int i = 1; i <= imax; ++i)
00252       {
00253          int gIndex = i;
00254          int topRowIndex = k + i - 1;
00255          GivensRotationR(cGivens(gIndex), sGivens(gIndex),
00256             columnJ(topRowIndex), columnJ(topRowIndex+1));
00257       }
00258 
00259       // compute a new Given's rotation when j < l
00260       if(j < l)
00261       {
00262          int gIndex = j-k+1;
00263          columnJ(j) = pythag(columnJ(j), columnJ(j+1), cGivens(gIndex), sGivens(gIndex));
00264          columnJ(j+1) = 0.0;
00265       }
00266 
00267       cholCopy.Column(j) = columnJ;
00268    }
00269 
00270    chol << cholCopy;
00271   
00272 }
00273 
00274 
00275 
00276 
00277 #ifdef use_namespace
00278 }
00279 #endif
00280 

newmat11b
Generated Tue Jan 4 15:42:10 2005 by Doxygen 1.4.0