00001 #ifndef OPENTISSUE_CORE_MATH_BIG_BIG_CHOLESKY_H
00002 #define OPENTISSUE_CORE_MATH_BIG_BIG_CHOLESKY_H
00003
00004
00005
00006
00007
00008
00009
00010 #include <OpenTissue/configuration.h>
00011
00012
00013
00014
00015
00016
00017
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040 #include <boost/numeric/ublas/vector.hpp>
00041 #include <boost/numeric/ublas/vector_proxy.hpp>
00042
00043 #include <boost/numeric/ublas/matrix.hpp>
00044 #include <boost/numeric/ublas/matrix_proxy.hpp>
00045
00046 #include <boost/numeric/ublas/vector_expression.hpp>
00047 #include <boost/numeric/ublas/matrix_expression.hpp>
00048
00049 #include <boost/numeric/ublas/triangular.hpp>
00050
00051 namespace ublas = boost::numeric::ublas;
00052 #include <cassert>
00053 #include <stdexcept>
00054
00055 namespace OpenTissue
00056 {
00057 namespace math
00058 {
00059 namespace big
00060 {
00061
00069 template < typename matrix_type, typename triangular_matrix_type >
00070 inline size_t cholesky_decompose(matrix_type const & A, triangular_matrix_type& L)
00071 {
00072 using std::sqrt;
00073 using namespace ublas;
00074
00075 typedef typename matrix_type::value_type T;
00076
00077 if( A.size1() != A.size2() )
00078 throw std::invalid_argument("A could not be a symmetric matrix.");
00079 if( A.size1() != L.size1() )
00080 throw std::invalid_argument("Incompatible dimensions of A and L");
00081 if( A.size2() != L.size2() )
00082 throw std::invalid_argument("Incompatible dimensions of A and L");
00083
00084 size_t const n = A.size1();
00085
00086 for (size_t k = 0 ; k < n; ++k)
00087 {
00088 double qL_kk = A(k,k) - inner_prod( project( row(L, k), range(0, k) ), project( row(L, k), range(0, k) ) );
00089 if (qL_kk <= 0)
00090 {
00091 return 1 + k;
00092 }
00093 else
00094 {
00095 double L_kk = sqrt( qL_kk );
00096 L(k,k) = L_kk;
00097
00098 matrix_column<triangular_matrix_type> cLk(L, k);
00099
00100 project( cLk, range(k+1, n) )
00101 = ( project( column(A, k), range(k+1, n) )
00102 - prod( project(L, range(k+1, n), range(0, k)),
00103 project(row(L, k), range(0, k) ) ) ) / L_kk;
00104 }
00105 }
00106 return 0;
00107 }
00108
00115 template < typename matrix_type >
00116 inline size_t cholesky_decompose(matrix_type & A)
00117 {
00118 using namespace ublas;
00119 using std::sqrt;
00120
00121 typedef typename matrix_type::value_type T;
00122
00123 matrix_type const & A_c(A);
00124 size_t const n = A.size1();
00125
00126 for (size_t k=0 ; k < n; ++k)
00127 {
00128 double qL_kk = A_c(k,k) - inner_prod( project( row(A_c, k), range(0, k) ), project( row(A_c, k), range(0, k) ) );
00129 if (qL_kk <= 0)
00130 {
00131 return 1 + k;
00132 }
00133 else
00134 {
00135 double L_kk = sqrt( qL_kk );
00136
00137 matrix_column<matrix_type> cLk(A, k);
00138
00139 project( cLk, range(k+1, n) )
00140 = ( project( column(A_c, k), range(k+1, n) )
00141 - prod( project(A_c, range(k+1, n), range(0, k)),
00142 project(row(A_c, k), range(0, k) ) ) ) / L_kk;
00143 A(k,k) = L_kk;
00144 }
00145 }
00146 return 0;
00147 }
00148
00155 template < typename matrix_type >
00156 inline size_t incomplete_cholesky_decompose(matrix_type & A)
00157 {
00158 using namespace ublas;
00159 using std::sqrt;
00160
00161 typedef typename matrix_type::value_type T;
00162
00163
00164 matrix_type const & A_c(A);
00165 size_t const n = A.size1();
00166
00167 for (size_t k=0 ; k < n; ++k)
00168 {
00169 double qL_kk = A_c(k,k) - inner_prod( project( row( A_c, k ), range(0, k) ), project( row( A_c, k ), range(0, k) ) );
00170
00171 if (qL_kk <= 0)
00172 {
00173 return 1 + k;
00174 }
00175 else
00176 {
00177 double L_kk = sqrt( qL_kk );
00178
00179 for (size_t i = k+1; i < A.size1(); ++i)
00180 {
00181 T* Aik = A.find_element(i, k);
00182
00183 if (Aik != 0)
00184 {
00185 *Aik = ( *Aik - inner_prod( project( row( A_c, k ), range(0, k) ), project( row( A_c, i ), range(0, k) ) ) ) / L_kk;
00186 }
00187 }
00188
00189 A(k,k) = L_kk;
00190 }
00191 }
00192
00193 return 0;
00194 }
00195
00202 template < typename triangular_matrix_type, typename vector_type >
00203 inline void cholesky_solve(triangular_matrix_type const & L, vector_type & x, ublas::lower)
00204 {
00205 using namespace ublas;
00206 inplace_solve(L, x, lower_tag() );
00207 inplace_solve(trans(L), x, upper_tag());
00208 }
00209
00217 template < typename T >
00218 inline void cholesky_solve(
00219 ublas::compressed_matrix<T> const & A
00220 , ublas::vector<T> & x
00221 , ublas::vector<T> const & b
00222 )
00223 {
00224 ublas::compressed_matrix<double> L(A);
00225 OpenTissue::math::big::incomplete_cholesky_decompose(L);
00226 x = b;
00227 OpenTissue::math::big::cholesky_solve(L, x, ublas::lower());
00228 }
00229
00237 template < typename T >
00238 inline void cholesky_solve(
00239 ublas::matrix<T> const & A
00240 , ublas::vector<T> & x
00241 , ublas::vector<T> const & b
00242 )
00243 {
00244 ublas::matrix<double> L(A);
00245 OpenTissue::math::big::cholesky_decompose(L);
00246 x = b;
00247 OpenTissue::math::big::cholesky_solve(L, x, ublas::lower());
00248 }
00249
00250 }
00251 }
00252 }
00253
00254
00255 #endif