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

newmat11b
Generated Mon May 9 04:54:17 2016 by Doxygen 1.6.3