CholeskyDecomp.h

Go to the documentation of this file.
00001 // @(#)root/smatrix:$Id: CholeskyDecomp.h 36350 2010-10-14 13:40:45Z moneta $
00002 // Author: M. Schiller    2009
00003 
00004 #ifndef ROOT_Math_CholeskyDecomp
00005 #define ROOT_Math_CholeskyDecomp
00006 
00007 /** @file
00008  * header file containing the templated implementation of matrix inversion
00009  * routines for use with ROOT's SMatrix classes (symmetric positive
00010  * definite case)
00011  *
00012  * @author Manuel Schiller
00013  * @date Aug 29 2008
00014  *      initial release inside LHCb
00015  * @date May 7 2009
00016  *      factored code to provide a nice Cholesky decomposition class, along
00017  *      with separate methods for solving a single linear system and to
00018  *      obtain the inverse matrix from the decomposition
00019  */
00020 
00021 #include <cmath>
00022 #include <algorithm>
00023 
00024 namespace ROOT { 
00025 
00026    namespace Math { 
00027 
00028 /// helpers for CholeskyDecomp
00029 namespace CholeskyDecompHelpers {
00030    // forward decls
00031    template<class F, unsigned N, class M> struct _decomposer;
00032    template<class F, unsigned N, class M> struct _inverter;
00033    template<class F, unsigned N, class V> struct _solver;
00034 }
00035 
00036 /// class to compute the Cholesky decomposition of a matrix
00037 /** class to compute the Cholesky decomposition of a symmetric
00038  * positive definite matrix
00039  *
00040  * provides routines to check if the decomposition succeeded (i.e. if
00041  * matrix is positive definite and non-singular), to solve a linear
00042  * system for the given matrix and to obtain its inverse
00043  *
00044  * the actual functionality is implemented in templated helper
00045  * classes which have specializations for dimensions N = 1 to 6
00046  * to achieve a gain in speed for common matrix sizes
00047  *
00048  * usage example:
00049  * @code
00050  * // let m be a symmetric positive definite SMatrix (use type float
00051  * // for internal computations, matrix size is 4x4)
00052  * CholeskyDecomp<float, 4> decomp(m);
00053  * // check if the decomposition succeeded
00054  * if (!decomp) {
00055  *   std::cerr << "decomposition failed!" << std::endl;
00056  * } else {
00057  *   // let rhs be a vector; we seek a vector x such that m * x = rhs
00058  *   decomp.Solve(rhs);
00059  *   // rhs now contains the solution we are looking for
00060  *
00061  *   // obtain the inverse of m, put it into m itself
00062  *   decomp.Invert(m);
00063  * }
00064  * @endcode
00065  */
00066 template<class F, unsigned N> class CholeskyDecomp
00067 {
00068 private:
00069    /// lower triangular matrix L
00070    /** lower triangular matrix L, packed storage, with diagonal
00071     * elements pre-inverted */
00072    F fL[N * (N + 1) / 2];
00073    /// flag indicating a successful decomposition
00074    bool fOk;
00075    /// adapter for packed arrays (to SMatrix indexing conventions)
00076    template<typename G> class PackedArrayAdapter
00077    {
00078    private:
00079       G* fArr; ///< pointer to first array element
00080    public:
00081       /// constructor
00082       PackedArrayAdapter(G* arr) : fArr(arr) {}
00083       /// read access to elements (make sure that j <= i)
00084       const G operator()(unsigned i, unsigned j) const
00085       { return fArr[((i * (i + 1)) / 2) + j]; }
00086       /// write access to elements (make sure that j <= i)
00087       G& operator()(unsigned i, unsigned j)
00088       { return fArr[((i * (i + 1)) / 2) + j]; }
00089    };
00090 public:
00091    /// perform a Cholesky decomposition
00092    /** perfrom a Cholesky decomposition of a symmetric positive
00093     * definite matrix m
00094     *
00095     * this is the constructor to uses with an SMatrix (and objects
00096     * that behave like an SMatrix in terms of using
00097     * operator()(int i, int j) for access to elements)
00098     */
00099    template<class M> CholeskyDecomp(const M& m) : 
00100       fL( ), fOk(false)
00101    {
00102       using CholeskyDecompHelpers::_decomposer;
00103       fOk = _decomposer<F, N, M>()(fL, m);
00104    }
00105 
00106    /// perform a Cholesky decomposition
00107    /** perfrom a Cholesky decomposition of a symmetric positive
00108     * definite matrix m
00109     * 
00110     * this is the constructor to use in special applications where
00111     * plain arrays are used
00112     *
00113     * NOTE: the matrix is given in packed representation, matrix
00114     * element m(i,j) (j <= i) is supposed to be in array element
00115     * (i * (i + 1)) / 2 + j
00116     */
00117    template<typename G> CholeskyDecomp(G* m) : 
00118       fL(), fOk(false)
00119    {
00120       using CholeskyDecompHelpers::_decomposer;
00121       fOk = _decomposer<F, N, PackedArrayAdapter<G> >()(
00122          fL, PackedArrayAdapter<G>(m));
00123    }
00124 
00125    /// returns true if decomposition was successful
00126    /** @returns true if decomposition was successful */
00127    bool ok() const { return fOk; }
00128    /// returns true if decomposition was successful
00129    /** @returns true if decomposition was successful */
00130    operator bool() const { return fOk; }
00131 
00132    /// solves a linear system for the given right hand side
00133    /** solves a linear system for the given right hand side
00134     *
00135     * Note that you can use both SVector classes and plain arrays for
00136     * rhs. (Make sure that the sizes match!). It will work with any vector 
00137     * implementing the operator [i]
00138     *
00139     * @returns if the decomposition was successful
00140     */
00141    template<class V> bool Solve(V& rhs) const
00142    {
00143       using CholeskyDecompHelpers::_solver;
00144       if (fOk) _solver<F,N,V>()(rhs, fL); return fOk;
00145    }
00146 
00147    /// place the inverse into m
00148    /** place the inverse into m
00149     *
00150     * This is the method to use with an SMatrix.
00151     *
00152     * @returns if the decomposition was successful
00153     */
00154    template<class M> bool Invert(M& m) const
00155    {
00156       using CholeskyDecompHelpers::_inverter;
00157       if (fOk) _inverter<F,N,M>()(m, fL); return fOk;
00158    }
00159 
00160    /// place the inverse into m
00161    /** place the inverse into m
00162     *
00163     * This is the method to use with a plain array.
00164     *
00165     * @returns if the decomposition was successful
00166     *
00167     * NOTE: the matrix is given in packed representation, matrix
00168     * element m(i,j) (j <= i) is supposed to be in array element
00169     * (i * (i + 1)) / 2 + j
00170     */
00171    template<typename G> bool Invert(G* m) const
00172    {
00173       using CholeskyDecompHelpers::_inverter;
00174       if (fOk) {
00175          PackedArrayAdapter<G> adapted(m);
00176          _inverter<F,N,PackedArrayAdapter<G> >()(adapted, fL);
00177       }
00178       return fOk;
00179    }
00180 };
00181 
00182 
00183 namespace CholeskyDecompHelpers {
00184    /// struct to do a Cholesky decomposition
00185    template<class F, unsigned N, class M> struct _decomposer
00186    {
00187       /// method to do the decomposition
00188       /** @returns if the decomposition was successful */
00189       bool operator()(F* dst, const M& src) const
00190       {
00191          // perform Cholesky decomposition of matrix: M = L L^T
00192          // only thing that can go wrong: trying to take square
00193          // root of negative number or zero (matrix is
00194          // ill-conditioned or singular in these cases)
00195 
00196          // element L(i,j) is at array position (i * (i+1)) / 2 + j
00197 
00198          // quirk: we may need to invert L later anyway, so we can
00199          // invert elements on diagonale straight away (we only
00200          // ever need their reciprocals!)
00201 
00202          // cache starting address of rows of L for speed reasons
00203          F *base1 = &dst[0];
00204          for (unsigned i = 0; i < N; base1 += ++i) {
00205             F tmpdiag = F(0);   // for element on diagonale
00206             // calculate off-diagonal elements
00207             F *base2 = &dst[0];
00208             for (unsigned j = 0; j < i; base2 += ++j) {
00209                F tmp = src(i, j);
00210                for (unsigned k = j; k--; )
00211                   tmp -= base1[k] * base2[k];
00212                base1[j] = tmp *= base2[j];
00213                // keep track of contribution to element on diagonale
00214                tmpdiag += tmp * tmp;
00215             }
00216             // keep truncation error small
00217             tmpdiag = src(i, i) - tmpdiag;
00218             // check if positive definite
00219             if (tmpdiag <= F(0)) return false;
00220             else base1[i] = std::sqrt(F(1) / tmpdiag);
00221          }
00222          return true;
00223       }
00224    };
00225 
00226    /// struct to obtain the inverse from a Cholesky decomposition
00227    template<class F, unsigned N, class M> struct _inverter
00228    {
00229       /// method to do the inversion
00230       void operator()(M& dst, const F* src) const
00231       {
00232          // make working copy
00233          F l[N * (N + 1) / 2];
00234          std::copy(src, src + ((N * (N + 1)) / 2), l);
00235          // ok, next step: invert off-diagonal part of matrix
00236          F* base1 = &l[1];
00237          for (unsigned i = 1; i < N; base1 += ++i) {
00238             for (unsigned j = 0; j < i; ++j) {
00239                F tmp = F(0);
00240                const F *base2 = &l[(i * (i - 1)) / 2];
00241                for (unsigned k = i; k-- > j; base2 -= k)
00242                   tmp -= base1[k] * base2[j];
00243                base1[j] = tmp * base1[i];
00244             }
00245          }
00246 
00247          // Li = L^(-1) formed, now calculate M^(-1) = Li^T Li
00248          for (unsigned i = N; i--; ) {
00249             for (unsigned j = i + 1; j--; ) {
00250                F tmp = F(0);
00251                base1 = &l[(N * (N - 1)) / 2];
00252                for (unsigned k = N; k-- > i; base1 -= k)
00253                   tmp += base1[i] * base1[j];
00254                dst(i, j) = tmp;
00255             }
00256          }
00257       }
00258    };
00259 
00260    /// struct to solve a linear system using its Cholesky decomposition
00261    template<class F, unsigned N, class V> struct _solver
00262    {
00263       /// method to solve the linear system
00264       void operator()(V& rhs, const F* l) const
00265       {
00266          // solve Ly = rhs
00267          for (unsigned k = 0; k < N; ++k) {
00268             const unsigned base = (k * (k + 1)) / 2;
00269             F sum = F(0);
00270             for (unsigned i = k; i--; )
00271                sum += rhs[i] * l[base + i];
00272             // elements on diagonale are pre-inverted!
00273             rhs[k] = (rhs[k] - sum) * l[base + k];
00274          }
00275          // solve L^Tx = y
00276          for (unsigned k = N; k--; ) {
00277             F sum = F(0);
00278             for (unsigned i = N; --i > k; )
00279                sum += rhs[i] * l[(i * (i + 1)) / 2 + k];
00280             // elements on diagonale are pre-inverted!
00281             rhs[k] = (rhs[k] - sum) * l[(k * (k + 1)) / 2 + k];
00282          }
00283       }
00284    };
00285 
00286    /// struct to do a Cholesky decomposition (specialized, N = 6)
00287    template<class F, class M> struct _decomposer<F, 6, M>
00288    {
00289       /// method to do the decomposition
00290       bool operator()(F* dst, const M& src) const
00291       {
00292          if (src(0,0) <= F(0)) return false;
00293          dst[0] = std::sqrt(F(1) / src(0,0));
00294          dst[1] = src(1,0) * dst[0];
00295          dst[2] = src(1,1) - dst[1] * dst[1];
00296          if (dst[2] <= F(0)) return false;
00297          else dst[2] = std::sqrt(F(1) / dst[2]);
00298          dst[3] = src(2,0) * dst[0];
00299          dst[4] = (src(2,1) - dst[1] * dst[3]) * dst[2];
00300          dst[5] = src(2,2) - (dst[3] * dst[3] + dst[4] * dst[4]);
00301          if (dst[5] <= F(0)) return false;
00302          else dst[5] = std::sqrt(F(1) / dst[5]);
00303          dst[6] = src(3,0) * dst[0];
00304          dst[7] = (src(3,1) - dst[1] * dst[6]) * dst[2];
00305          dst[8] = (src(3,2) - dst[3] * dst[6] - dst[4] * dst[7]) * dst[5];
00306          dst[9] = src(3,3) - (dst[6] * dst[6] + dst[7] * dst[7] + dst[8] * dst[8]);
00307          if (dst[9] <= F(0)) return false;
00308          else dst[9] = std::sqrt(F(1) / dst[9]);
00309          dst[10] = src(4,0) * dst[0];
00310          dst[11] = (src(4,1) - dst[1] * dst[10]) * dst[2];
00311          dst[12] = (src(4,2) - dst[3] * dst[10] - dst[4] * dst[11]) * dst[5];
00312          dst[13] = (src(4,3) - dst[6] * dst[10] - dst[7] * dst[11] - dst[8] * dst[12]) * dst[9];
00313          dst[14] = src(4,4) - (dst[10]*dst[10]+dst[11]*dst[11]+dst[12]*dst[12]+dst[13]*dst[13]);
00314          if (dst[14] <= F(0)) return false;
00315          else dst[14] = std::sqrt(F(1) / dst[14]);
00316          dst[15] = src(5,0) * dst[0];
00317          dst[16] = (src(5,1) - dst[1] * dst[15]) * dst[2];
00318          dst[17] = (src(5,2) - dst[3] * dst[15] - dst[4] * dst[16]) * dst[5];
00319          dst[18] = (src(5,3) - dst[6] * dst[15] - dst[7] * dst[16] - dst[8] * dst[17]) * dst[9];
00320          dst[19] = (src(5,4) - dst[10] * dst[15] - dst[11] * dst[16] - dst[12] * dst[17] - dst[13] * dst[18]) * dst[14];
00321          dst[20] = src(5,5) - (dst[15]*dst[15]+dst[16]*dst[16]+dst[17]*dst[17]+dst[18]*dst[18]+dst[19]*dst[19]);
00322          if (dst[20] <= F(0)) return false;
00323          else dst[20] = std::sqrt(F(1) / dst[20]);
00324          return true;
00325       }
00326    };
00327    /// struct to do a Cholesky decomposition (specialized, N = 5)
00328    template<class F, class M> struct _decomposer<F, 5, M>
00329    {
00330       /// method to do the decomposition
00331       bool operator()(F* dst, const M& src) const
00332       {
00333          if (src(0,0) <= F(0)) return false;
00334          dst[0] = std::sqrt(F(1) / src(0,0));
00335          dst[1] = src(1,0) * dst[0];
00336          dst[2] = src(1,1) - dst[1] * dst[1];
00337          if (dst[2] <= F(0)) return false;
00338          else dst[2] = std::sqrt(F(1) / dst[2]);
00339          dst[3] = src(2,0) * dst[0];
00340          dst[4] = (src(2,1) - dst[1] * dst[3]) * dst[2];
00341          dst[5] = src(2,2) - (dst[3] * dst[3] + dst[4] * dst[4]);
00342          if (dst[5] <= F(0)) return false;
00343          else dst[5] = std::sqrt(F(1) / dst[5]);
00344          dst[6] = src(3,0) * dst[0];
00345          dst[7] = (src(3,1) - dst[1] * dst[6]) * dst[2];
00346          dst[8] = (src(3,2) - dst[3] * dst[6] - dst[4] * dst[7]) * dst[5];
00347          dst[9] = src(3,3) - (dst[6] * dst[6] + dst[7] * dst[7] + dst[8] * dst[8]);
00348          if (dst[9] <= F(0)) return false;
00349          else dst[9] = std::sqrt(F(1) / dst[9]);
00350          dst[10] = src(4,0) * dst[0];
00351          dst[11] = (src(4,1) - dst[1] * dst[10]) * dst[2];
00352          dst[12] = (src(4,2) - dst[3] * dst[10] - dst[4] * dst[11]) * dst[5];
00353          dst[13] = (src(4,3) - dst[6] * dst[10] - dst[7] * dst[11] - dst[8] * dst[12]) * dst[9];
00354          dst[14] = src(4,4) - (dst[10]*dst[10]+dst[11]*dst[11]+dst[12]*dst[12]+dst[13]*dst[13]);
00355          if (dst[14] <= F(0)) return false;
00356          else dst[14] = std::sqrt(F(1) / dst[14]);
00357          return true;
00358       }
00359    };
00360    /// struct to do a Cholesky decomposition (specialized, N = 4)
00361    template<class F, class M> struct _decomposer<F, 4, M>
00362    {
00363       /// method to do the decomposition
00364       bool operator()(F* dst, const M& src) const
00365       {
00366          if (src(0,0) <= F(0)) return false;
00367          dst[0] = std::sqrt(F(1) / src(0,0));
00368          dst[1] = src(1,0) * dst[0];
00369          dst[2] = src(1,1) - dst[1] * dst[1];
00370          if (dst[2] <= F(0)) return false;
00371          else dst[2] = std::sqrt(F(1) / dst[2]);
00372          dst[3] = src(2,0) * dst[0];
00373          dst[4] = (src(2,1) - dst[1] * dst[3]) * dst[2];
00374          dst[5] = src(2,2) - (dst[3] * dst[3] + dst[4] * dst[4]);
00375          if (dst[5] <= F(0)) return false;
00376          else dst[5] = std::sqrt(F(1) / dst[5]);
00377          dst[6] = src(3,0) * dst[0];
00378          dst[7] = (src(3,1) - dst[1] * dst[6]) * dst[2];
00379          dst[8] = (src(3,2) - dst[3] * dst[6] - dst[4] * dst[7]) * dst[5];
00380          dst[9] = src(3,3) - (dst[6] * dst[6] + dst[7] * dst[7] + dst[8] * dst[8]);
00381          if (dst[9] <= F(0)) return false;
00382          else dst[9] = std::sqrt(F(1) / dst[9]);
00383          return true;
00384       }
00385    };
00386    /// struct to do a Cholesky decomposition (specialized, N = 3)
00387    template<class F, class M> struct _decomposer<F, 3, M>
00388    {
00389       /// method to do the decomposition
00390       bool operator()(F* dst, const M& src) const
00391       {
00392          if (src(0,0) <= F(0)) return false;
00393          dst[0] = std::sqrt(F(1) / src(0,0));
00394          dst[1] = src(1,0) * dst[0];
00395          dst[2] = src(1,1) - dst[1] * dst[1];
00396          if (dst[2] <= F(0)) return false;
00397          else dst[2] = std::sqrt(F(1) / dst[2]);
00398          dst[3] = src(2,0) * dst[0];
00399          dst[4] = (src(2,1) - dst[1] * dst[3]) * dst[2];
00400          dst[5] = src(2,2) - (dst[3] * dst[3] + dst[4] * dst[4]);
00401          if (dst[5] <= F(0)) return false;
00402          else dst[5] = std::sqrt(F(1) / dst[5]);
00403          return true;
00404       }
00405    };
00406    /// struct to do a Cholesky decomposition (specialized, N = 2)
00407    template<class F, class M> struct _decomposer<F, 2, M>
00408    {
00409       /// method to do the decomposition
00410       bool operator()(F* dst, const M& src) const
00411       {
00412          if (src(0,0) <= F(0)) return false;
00413          dst[0] = std::sqrt(F(1) / src(0,0));
00414          dst[1] = src(1,0) * dst[0];
00415          dst[2] = src(1,1) - dst[1] * dst[1];
00416          if (dst[2] <= F(0)) return false;
00417          else dst[2] = std::sqrt(F(1) / dst[2]);
00418          return true;
00419       }
00420    };
00421    /// struct to do a Cholesky decomposition (specialized, N = 1)
00422    template<class F, class M> struct _decomposer<F, 1, M>
00423    {
00424       /// method to do the decomposition
00425       bool operator()(F* dst, const M& src) const
00426       {
00427          if (src(0,0) <= F(0)) return false;
00428          dst[0] = std::sqrt(F(1) / src(0,0));
00429          return true;
00430       }
00431    };
00432    /// struct to do a Cholesky decomposition (specialized, N = 0)
00433    template<class F, class M> struct _decomposer<F, 0, M>
00434    {
00435    private:
00436       _decomposer() { };
00437       bool operator()(F* dst, const M& src) const;
00438    };
00439 
00440    /// struct to obtain the inverse from a Cholesky decomposition (N = 6)
00441    template<class F, class M> struct _inverter<F,6,M>
00442    {
00443       /// method to do the inversion
00444       inline void operator()(M& dst, const F* src) const
00445       {
00446          const F li21 = -src[1] * src[0] * src[2];
00447          const F li32 = -src[4] * src[2] * src[5];
00448          const F li31 = (src[1] * src[4] * src[2] - src[3]) * src[0] * src[5];
00449          const F li43 = -src[8] * src[9] * src[5];
00450          const F li42 = (src[4] * src[8] * src[5] - src[7]) * src[2] * src[9];
00451          const F li41 = (-src[1] * src[4] * src[8] * src[2] * src[5] +
00452                          src[1] * src[7] * src[2] + src[3] * src[8] * src[5] - src[6]) * src[0] * src[9];
00453          const F li54 = -src[13] * src[14] * src[9];
00454          const F li53 = (src[13] * src[8] * src[9] - src[12]) * src[5] * src[14];
00455          const F li52 = (-src[4] * src[8] * src[13] * src[5] * src[9] +
00456                          src[4] * src[12] * src[5] + src[7] * src[13] * src[9] - src[11]) * src[2] * src[14];
00457          const F li51 = (src[1]*src[4]*src[8]*src[13]*src[2]*src[5]*src[9] -
00458                          src[13]*src[8]*src[3]*src[9]*src[5] - src[12]*src[4]*src[1]*src[2]*src[5] - src[13]*src[7]*src[1]*src[9]*src[2] +
00459                          src[11]*src[1]*src[2] + src[12]*src[3]*src[5] + src[13]*src[6]*src[9] -src[10]) * src[0] * src[14];
00460          const F li65 = -src[19] * src[20] * src[14];
00461          const F li64 = (src[19] * src[13] * src[14] - src[18]) * src[9] * src[20];
00462          const F li63 = (-src[8] * src[13] * src[19] * src[9] * src[14] +
00463                          src[8] * src[18] * src[9] + src[12] * src[19] * src[14] - src[17]) * src[5] * src[20];
00464          const F li62 = (src[4]*src[8]*src[13]*src[19]*src[5]*src[9]*src[14] -
00465                          src[18]*src[8]*src[4]*src[9]*src[5] - src[19]*src[12]*src[4]*src[14]*src[5] -src[19]*src[13]*src[7]*src[14]*src[9] +
00466                          src[17]*src[4]*src[5] + src[18]*src[7]*src[9] + src[19]*src[11]*src[14] - src[16]) * src[2] * src[20];
00467          const F li61 = (-src[19]*src[13]*src[8]*src[4]*src[1]*src[2]*src[5]*src[9]*src[14] +
00468                          src[18]*src[8]*src[4]*src[1]*src[2]*src[5]*src[9] + src[19]*src[12]*src[4]*src[1]*src[2]*src[5]*src[14] +
00469                          src[19]*src[13]*src[7]*src[1]*src[2]*src[9]*src[14] + src[19]*src[13]*src[8]*src[3]*src[5]*src[9]*src[14] -
00470                          src[17]*src[4]*src[1]*src[2]*src[5] - src[18]*src[7]*src[1]*src[2]*src[9] - src[19]*src[11]*src[1]*src[2]*src[14] -
00471                          src[18]*src[8]*src[3]*src[5]*src[9] - src[19]*src[12]*src[3]*src[5]*src[14] - src[19]*src[13]*src[6]*src[9]*src[14] +
00472                          src[16]*src[1]*src[2] + src[17]*src[3]*src[5] + src[18]*src[6]*src[9] + src[19]*src[10]*src[14] - src[15]) *
00473             src[0] * src[20];
00474 
00475          dst(0,0) = li61*li61 + li51*li51 + li41*li41 + li31*li31 + li21*li21 + src[0]*src[0];
00476          dst(1,0) = li61*li62 + li51*li52 + li41*li42 + li31*li32 + li21*src[2];
00477          dst(1,1) = li62*li62 + li52*li52 + li42*li42 + li32*li32 + src[2]*src[2];
00478          dst(2,0) = li61*li63 + li51*li53 + li41*li43 + li31*src[5];
00479          dst(2,1) = li62*li63 + li52*li53 + li42*li43 + li32*src[5];
00480          dst(2,2) = li63*li63 + li53*li53 + li43*li43 + src[5]*src[5];
00481          dst(3,0) = li61*li64 + li51*li54 + li41*src[9];
00482          dst(3,1) = li62*li64 + li52*li54 + li42*src[9];
00483          dst(3,2) = li63*li64 + li53*li54 + li43*src[9];
00484          dst(3,3) = li64*li64 + li54*li54 + src[9]*src[9];
00485          dst(4,0) = li61*li65 + li51*src[14];
00486          dst(4,1) = li62*li65 + li52*src[14];
00487          dst(4,2) = li63*li65 + li53*src[14];
00488          dst(4,3) = li64*li65 + li54*src[14];
00489          dst(4,4) = li65*li65 + src[14]*src[14];
00490          dst(5,0) = li61*src[20];
00491          dst(5,1) = li62*src[20];
00492          dst(5,2) = li63*src[20];
00493          dst(5,3) = li64*src[20];
00494          dst(5,4) = li65*src[20];
00495          dst(5,5) = src[20]*src[20];
00496       }
00497    };
00498    /// struct to obtain the inverse from a Cholesky decomposition (N = 5)
00499    template<class F, class M> struct _inverter<F,5,M>
00500    {
00501       /// method to do the inversion
00502       inline void operator()(M& dst, const F* src) const
00503       {
00504          const F li21 = -src[1] * src[0] * src[2];
00505          const F li32 = -src[4] * src[2] * src[5];
00506          const F li31 = (src[1] * src[4] * src[2] - src[3]) * src[0] * src[5];
00507          const F li43 = -src[8] * src[9] * src[5];
00508          const F li42 = (src[4] * src[8] * src[5] - src[7]) * src[2] * src[9];
00509          const F li41 = (-src[1] * src[4] * src[8] * src[2] * src[5] +
00510                          src[1] * src[7] * src[2] + src[3] * src[8] * src[5] - src[6]) * src[0] * src[9];
00511          const F li54 = -src[13] * src[14] * src[9];
00512          const F li53 = (src[13] * src[8] * src[9] - src[12]) * src[5] * src[14];
00513          const F li52 = (-src[4] * src[8] * src[13] * src[5] * src[9] +
00514                          src[4] * src[12] * src[5] + src[7] * src[13] * src[9] - src[11]) * src[2] * src[14];
00515          const F li51 = (src[1]*src[4]*src[8]*src[13]*src[2]*src[5]*src[9] -
00516                          src[13]*src[8]*src[3]*src[9]*src[5] - src[12]*src[4]*src[1]*src[2]*src[5] - src[13]*src[7]*src[1]*src[9]*src[2] +
00517                          src[11]*src[1]*src[2] + src[12]*src[3]*src[5] + src[13]*src[6]*src[9] -src[10]) * src[0] * src[14];
00518 
00519          dst(0,0) = li51*li51 + li41*li41 + li31*li31 + li21*li21 + src[0]*src[0];
00520          dst(1,0) = li51*li52 + li41*li42 + li31*li32 + li21*src[2];
00521          dst(1,1) = li52*li52 + li42*li42 + li32*li32 + src[2]*src[2];
00522          dst(2,0) = li51*li53 + li41*li43 + li31*src[5];
00523          dst(2,1) = li52*li53 + li42*li43 + li32*src[5];
00524          dst(2,2) = li53*li53 + li43*li43 + src[5]*src[5];
00525          dst(3,0) = li51*li54 + li41*src[9];
00526          dst(3,1) = li52*li54 + li42*src[9];
00527          dst(3,2) = li53*li54 + li43*src[9];
00528          dst(3,3) = li54*li54 + src[9]*src[9];
00529          dst(4,0) = li51*src[14];
00530          dst(4,1) = li52*src[14];
00531          dst(4,2) = li53*src[14];
00532          dst(4,3) = li54*src[14];
00533          dst(4,4) = src[14]*src[14];
00534       }
00535    };
00536    /// struct to obtain the inverse from a Cholesky decomposition (N = 4)
00537    template<class F, class M> struct _inverter<F,4,M>
00538    {
00539       /// method to do the inversion
00540       inline void operator()(M& dst, const F* src) const
00541       {
00542          const F li21 = -src[1] * src[0] * src[2];
00543          const F li32 = -src[4] * src[2] * src[5];
00544          const F li31 = (src[1] * src[4] * src[2] - src[3]) * src[0] * src[5];
00545          const F li43 = -src[8] * src[9] * src[5];
00546          const F li42 = (src[4] * src[8] * src[5] - src[7]) * src[2] * src[9];
00547          const F li41 = (-src[1] * src[4] * src[8] * src[2] * src[5] +
00548                          src[1] * src[7] * src[2] + src[3] * src[8] * src[5] - src[6]) * src[0] * src[9];
00549 
00550          dst(0,0) = li41*li41 + li31*li31 + li21*li21 + src[0]*src[0];
00551          dst(1,0) = li41*li42 + li31*li32 + li21*src[2];
00552          dst(1,1) = li42*li42 + li32*li32 + src[2]*src[2];
00553          dst(2,0) = li41*li43 + li31*src[5];
00554          dst(2,1) = li42*li43 + li32*src[5];
00555          dst(2,2) = li43*li43 + src[5]*src[5];
00556          dst(3,0) = li41*src[9];
00557          dst(3,1) = li42*src[9];
00558          dst(3,2) = li43*src[9];
00559          dst(3,3) = src[9]*src[9];
00560       }
00561    };
00562    /// struct to obtain the inverse from a Cholesky decomposition (N = 3)
00563    template<class F, class M> struct _inverter<F,3,M>
00564    {
00565       /// method to do the inversion
00566       inline void operator()(M& dst, const F* src) const
00567       {
00568          const F li21 = -src[1] * src[0] * src[2];
00569          const F li32 = -src[4] * src[2] * src[5];
00570          const F li31 = (src[1] * src[4] * src[2] - src[3]) * src[0] * src[5];
00571 
00572          dst(0,0) = li31*li31 + li21*li21 + src[0]*src[0];
00573          dst(1,0) = li31*li32 + li21*src[2];
00574          dst(1,1) = li32*li32 + src[2]*src[2];
00575          dst(2,0) = li31*src[5];
00576          dst(2,1) = li32*src[5];
00577          dst(2,2) = src[5]*src[5];
00578       }
00579    };
00580    /// struct to obtain the inverse from a Cholesky decomposition (N = 2)
00581    template<class F, class M> struct _inverter<F,2,M>
00582    {
00583       /// method to do the inversion
00584       inline void operator()(M& dst, const F* src) const
00585       {
00586          const F li21 = -src[1] * src[0] * src[2];
00587 
00588          dst(0,0) = li21*li21 + src[0]*src[0];
00589          dst(1,0) = li21*src[2];
00590          dst(1,1) = src[2]*src[2];
00591       }
00592    };
00593    /// struct to obtain the inverse from a Cholesky decomposition (N = 1)
00594    template<class F, class M> struct _inverter<F,1,M>
00595    {
00596       /// method to do the inversion
00597       inline void operator()(M& dst, const F* src) const
00598       {
00599          dst(0,0) = src[0]*src[0];
00600       }
00601    };
00602    /// struct to obtain the inverse from a Cholesky decomposition (N = 0)
00603    template<class F, class M> struct _inverter<F,0,M>
00604    {
00605    private:
00606       _inverter();
00607       void operator()(M& dst, const F* src) const;
00608    };
00609 
00610    /// struct to solve a linear system using its Cholesky decomposition (N=6)
00611    template<class F, class V> struct _solver<F,6,V>
00612    {
00613       /// method to solve the linear system
00614       void operator()(V& rhs, const F* l) const
00615       {
00616          // solve Ly = rhs
00617          const F y0 = rhs[0] * l[0];
00618          const F y1 = (rhs[1]-l[1]*y0)*l[2];
00619          const F y2 = (rhs[2]-(l[3]*y0+l[4]*y1))*l[5];
00620          const F y3 = (rhs[3]-(l[6]*y0+l[7]*y1+l[8]*y2))*l[9];
00621          const F y4 = (rhs[4]-(l[10]*y0+l[11]*y1+l[12]*y2+l[13]*y3))*l[14];
00622          const F y5 = (rhs[5]-(l[15]*y0+l[16]*y1+l[17]*y2+l[18]*y3+l[19]*y4))*l[20];
00623          // solve L^Tx = y, and put x into rhs
00624          rhs[5] = y5 * l[20];
00625          rhs[4] = (y4-l[19]*rhs[5])*l[14];
00626          rhs[3] = (y3-(l[18]*rhs[5]+l[13]*rhs[4]))*l[9];
00627          rhs[2] = (y2-(l[17]*rhs[5]+l[12]*rhs[4]+l[8]*rhs[3]))*l[5];
00628          rhs[1] = (y1-(l[16]*rhs[5]+l[11]*rhs[4]+l[7]*rhs[3]+l[4]*rhs[2]))*l[2];
00629          rhs[0] = (y0-(l[15]*rhs[5]+l[10]*rhs[4]+l[6]*rhs[3]+l[3]*rhs[2]+l[1]*rhs[1]))*l[0];
00630       }
00631    };
00632    /// struct to solve a linear system using its Cholesky decomposition (N=5)
00633    template<class F, class V> struct _solver<F,5,V>
00634    {
00635       /// method to solve the linear system
00636       void operator()(V& rhs, const F* l) const
00637       {
00638          // solve Ly = rhs
00639          const F y0 = rhs[0] * l[0];
00640          const F y1 = (rhs[1]-l[1]*y0)*l[2];
00641          const F y2 = (rhs[2]-(l[3]*y0+l[4]*y1))*l[5];
00642          const F y3 = (rhs[3]-(l[6]*y0+l[7]*y1+l[8]*y2))*l[9];
00643          const F y4 = (rhs[4]-(l[10]*y0+l[11]*y1+l[12]*y2+l[13]*y3))*l[14];
00644          // solve L^Tx = y, and put x into rhs
00645          rhs[4] = (y4)*l[14];
00646          rhs[3] = (y3-(l[13]*rhs[4]))*l[9];
00647          rhs[2] = (y2-(l[12]*rhs[4]+l[8]*rhs[3]))*l[5];
00648          rhs[1] = (y1-(l[11]*rhs[4]+l[7]*rhs[3]+l[4]*rhs[2]))*l[2];
00649          rhs[0] = (y0-(l[10]*rhs[4]+l[6]*rhs[3]+l[3]*rhs[2]+l[1]*rhs[1]))*l[0];
00650       }
00651    };
00652    /// struct to solve a linear system using its Cholesky decomposition (N=4)
00653    template<class F, class V> struct _solver<F,4,V>
00654    {
00655       /// method to solve the linear system
00656       void operator()(V& rhs, const F* l) const
00657       {
00658          // solve Ly = rhs
00659          const F y0 = rhs[0] * l[0];
00660          const F y1 = (rhs[1]-l[1]*y0)*l[2];
00661          const F y2 = (rhs[2]-(l[3]*y0+l[4]*y1))*l[5];
00662          const F y3 = (rhs[3]-(l[6]*y0+l[7]*y1+l[8]*y2))*l[9];
00663          // solve L^Tx = y, and put x into rhs
00664          rhs[3] = (y3)*l[9];
00665          rhs[2] = (y2-(l[8]*rhs[3]))*l[5];
00666          rhs[1] = (y1-(l[7]*rhs[3]+l[4]*rhs[2]))*l[2];
00667          rhs[0] = (y0-(l[6]*rhs[3]+l[3]*rhs[2]+l[1]*rhs[1]))*l[0];
00668       }
00669    };
00670    /// struct to solve a linear system using its Cholesky decomposition (N=3)
00671    template<class F, class V> struct _solver<F,3,V>
00672    {
00673       /// method to solve the linear system
00674       void operator()(V& rhs, const F* l) const
00675       {
00676          // solve Ly = rhs
00677          const F y0 = rhs[0] * l[0];
00678          const F y1 = (rhs[1]-l[1]*y0)*l[2];
00679          const F y2 = (rhs[2]-(l[3]*y0+l[4]*y1))*l[5];
00680          // solve L^Tx = y, and put x into rhs
00681          rhs[2] = (y2)*l[5];
00682          rhs[1] = (y1-(l[4]*rhs[2]))*l[2];
00683          rhs[0] = (y0-(l[3]*rhs[2]+l[1]*rhs[1]))*l[0];
00684       }
00685    };
00686    /// struct to solve a linear system using its Cholesky decomposition (N=2)
00687    template<class F, class V> struct _solver<F,2,V>
00688    {
00689       /// method to solve the linear system
00690       void operator()(V& rhs, const F* l) const
00691       {
00692          // solve Ly = rhs
00693          const F y0 = rhs[0] * l[0];
00694          const F y1 = (rhs[1]-l[1]*y0)*l[2];
00695          // solve L^Tx = y, and put x into rhs
00696          rhs[1] = (y1)*l[2];
00697          rhs[0] = (y0-(l[1]*rhs[1]))*l[0];
00698       }
00699    };
00700    /// struct to solve a linear system using its Cholesky decomposition (N=1)
00701    template<class F, class V> struct _solver<F,1,V>
00702    {
00703       /// method to solve the linear system
00704       void operator()(V& rhs, const F* l) const
00705       {
00706          // solve LL^T x = rhs, put y into rhs
00707          rhs[0] *= l[0] * l[0];
00708       }
00709    };
00710    /// struct to solve a linear system using its Cholesky decomposition (N=0)
00711    template<class F, class V> struct _solver<F,0,V>
00712    {
00713    private:
00714       _solver();
00715       void operator()(V& rhs, const F* l) const;
00716    };
00717 }
00718 
00719 
00720    }  // namespace Math
00721 
00722 }  // namespace ROOT
00723 
00724 #endif // ROOT_Math_CHOLESKYDECOMP
00725 

Generated on Tue Jul 5 14:25:10 2011 for ROOT_528-00b_version by  doxygen 1.5.1