edoCholesky.h
00001 /*
00002 The Evolving Distribution Objects framework (EDO) is a template-based,
00003 ANSI-C++ evolutionary computation library which helps you to write your
00004 own estimation of distribution algorithms.
00005 
00006 This library is free software; you can redistribute it and/or
00007 modify it under the terms of the GNU Lesser General Public
00008 License as published by the Free Software Foundation; either
00009 version 2.1 of the License, or (at your option) any later version.
00010 
00011 This library is distributed in the hope that it will be useful,
00012 but WITHOUT ANY WARRANTY; without even the implied warranty of
00013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014 Lesser General Public License for more details.
00015 
00016 You should have received a copy of the GNU Lesser General Public
00017 License along with this library; if not, write to the Free Software
00018 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
00019 
00020 Copyright (C) 2010 Thales group
00021 */
00022 /*
00023 Authors:
00024     Johann Dréo <johann.dreo@thalesgroup.com>
00025     Caner Candan <caner.candan@thalesgroup.com>
00026 */
00027 
00028 namespace cholesky {
00029 
00030 
00031 #ifdef WITH_BOOST
00032 
00040 template< typename T >
00041 class CholeskyBase
00042 {
00043 public:
00045     typedef ublas::symmetric_matrix< T, ublas::lower > CovarMat;
00046 
00048     // FIXME check if triangular types behaviour is like having 0
00049     typedef ublas::matrix< T > FactorMat;
00050 
00054     CholeskyBase( size_t s1 = 1, size_t s2 = 1 ) : 
00055         _L(ublas::zero_matrix<T>(s1,s2))
00056     {}
00057 
00061     CholeskyBase(const CovarMat& V) :
00062         _L(ublas::zero_matrix<T>(V.size1(),V.size2()))
00063     {
00064         (*this)( V );
00065     }
00066 
00068     virtual void factorize( const CovarMat& V ) = 0;
00069 
00071     virtual const FactorMat& operator()( const CovarMat& V ) 
00072     {
00073         this->factorize( V );
00074         return decomposition();
00075     }
00076 
00078     const FactorMat & decomposition() const 
00079     {
00080         return _L;
00081     }
00082 
00083 protected:
00084 
00089     unsigned assert_properties( const CovarMat& V )
00090     {
00091         unsigned int Vl = V.size1(); // number of lines
00092 
00093         // the result goes in _L
00094         _L = ublas::zero_matrix<T>(Vl,Vl);
00095 
00096 #ifndef NDEBUG
00097         assert(Vl > 0);
00098 
00099         unsigned int Vc = V.size2(); // number of columns
00100         assert(Vc > 0);
00101         assert( Vl == Vc );
00102 
00103         // partial assert that V is semi-positive definite
00104         // assert that all diagonal elements are positives
00105         for( unsigned int i=0; i < Vl; ++i ) {
00106             assert( V(i,i) > 0 );
00107         }
00108 
00109         /* FIXME what is the more efficient way to check semi-positive definite? Candidates are:
00110          * perform the cholesky factorization
00111          * check if all eigenvalues are positives
00112          * check if all of the leading principal minors are positive
00113          */
00114 #endif
00115 
00116         return Vl;
00117     }
00118 
00120     FactorMat _L;
00121 };
00122 
00123 
00132 template< typename T >
00133 class CholeskyLLT : public CholeskyBase<T>
00134 {
00135 public:
00136   virtual void factorize( const typename CholeskyBase<T>::CovarMat& V )
00137     {
00138         unsigned int N = assert_properties( V );
00139 
00140         unsigned int i=0, j=0, k;
00141         this->_L(0, 0) = sqrt( V(0, 0) );
00142 
00143         // end of the column
00144         for ( j = 1; j < N; ++j ) {
00145             this->_L(j, 0) = V(0, j) / this->_L(0, 0);
00146         }
00147 
00148         // end of the matrix
00149         for ( i = 1; i < N; ++i ) { // each column
00150             // diagonal
00151             double sum = 0.0;
00152             for ( k = 0; k < i; ++k) {
00153                 sum += this->_L(i, k) * this->_L(i, k);
00154             }
00155 
00156             this->_L(i,i) = L_i_i( V, i, sum );
00157 
00158             for ( j = i + 1; j < N; ++j ) { // rows
00159                 // one element
00160                 sum = 0.0;
00161                 for ( k = 0; k < i; ++k ) {
00162                     sum += this->_L(j, k) * this->_L(i, k);
00163                 }
00164 
00165                 this->_L(j, i) = (V(j, i) - sum) / this->_L(i, i);
00166 
00167             } // for j in ]i,N[
00168         } // for i in [1,N[
00169     }
00170 
00171 
00173     inline virtual T L_i_i( const typename CholeskyBase<T>::CovarMat& V, const unsigned int& i, const double& sum ) const
00174     {
00175         // round-off errors may appear here
00176         assert( V(i,i) - sum >= 0 );
00177         return sqrt( V(i,i) - sum );
00178     }
00179 };
00180 
00181 
00190 template< typename T >
00191 class CholeskyLLTabs : public CholeskyLLT<T>
00192 {
00193 public:
00194     inline virtual T L_i_i( const typename CholeskyBase<T>::CovarMat& V, const unsigned int& i, const double& sum ) const
00195     {
00196         /***** ugly hack *****/
00197         return sqrt( fabs( V(i,i) - sum) );
00198     }
00199 };
00200 
00201 
00209 template< typename T >
00210 class CholeskyLLTzero : public CholeskyLLT<T>
00211 {
00212 public:
00213     inline virtual T L_i_i( const typename CholeskyBase<T>::CovarMat& V, const unsigned int& i, const double& sum ) const
00214     {
00215         T Lii;
00216         if(  V(i,i) - sum >= 0 ) {
00217             Lii = sqrt( V(i,i) - sum);
00218         } else {
00219             /***** ugly hack *****/
00220             Lii = 0;
00221         }
00222         return Lii;
00223     }
00224 };
00225 
00226 
00233 template< typename T >
00234 class CholeskyLDLT : public CholeskyBase<T>
00235 {
00236 public:
00237     virtual void factorize( const typename CholeskyBase<T>::CovarMat& V )
00238     {
00239         // use "int" everywhere, because of the "j-1" operation
00240         int N = assert_properties( V );
00241         // example of an invertible matrix whose decomposition is undefined
00242         assert( V(0,0) != 0 ); 
00243 
00244         typename CholeskyBase<T>::FactorMat L = ublas::zero_matrix<T>(N,N);
00245         typename CholeskyBase<T>::FactorMat D = ublas::zero_matrix<T>(N,N);
00246         D(0,0) = V(0,0);
00247 
00248         for( int j=0; j<N; ++j ) { // each columns
00249             L(j, j) = 1;
00250 
00251             D(j,j) = V(j,j);
00252             for( int k=0; k<=j-1; ++k) { // sum
00253                 D(j,j) -= L(j,k) * L(j,k) * D(k,k);
00254             }
00255 
00256             for( int i=j+1; i<N; ++i ) { // remaining rows
00257 
00258                 L(i,j) = V(i,j);
00259                 for( int k=0; k<=j-1; ++k) { // sum
00260                     L(i,j) -= L(i,k)*L(j,k) * D(k,k);
00261                 }
00262                 L(i,j) /= D(j,j);
00263 
00264             } // for i in rows
00265         } // for j in columns
00266         
00267         this->_L = root( L, D );
00268     }
00269 
00270 
00271     inline typename CholeskyBase<T>::FactorMat root( typename CholeskyBase<T>::FactorMat& L, typename CholeskyBase<T>::FactorMat& D )
00272     {
00273         // now compute the final symetric matrix: this->_L = L D^1/2
00274         // remember that V = ( L D^1/2) ( L D^1/2)^T
00275 
00276         // fortunately, the square root of a diagonal matrix is the square 
00277         // root of all its elements
00278         typename CholeskyBase<T>::FactorMat sqrt_D = D;
00279         for( int i=0; i < D.size1(); ++i) {
00280             sqrt_D(i,i) = sqrt(D(i,i));
00281         }
00282 
00283         // the factorization is thus this->_L*D^1/2
00284         return ublas::prod( L, sqrt_D );
00285     }
00286 };
00287 
00288 #else
00289 #ifdef WITH_EIGEN
00290 
00291 #endif // WITH_EIGEN
00292 #endif // WITH_BOOST
00293 
00294 
00295 } // namespace cholesky
 All Classes Functions Variables Typedefs