00001 #ifndef OPENTISSUE_CORE_MATH_BIG_CONJUGATE_GRADIENT_H
00002 #define OPENTISSUE_CORE_MATH_BIG_CONJUGATE_GRADIENT_H
00003
00004
00005
00006
00007
00008
00009
00010 #include <OpenTissue/configuration.h>
00011
00012 #include <OpenTissue/core/math/big/big_types.h>
00013 #include <OpenTissue/core/math/math_value_traits.h>
00014
00015 #include <boost/cast.hpp>
00016 #include <stdexcept>
00017 #include <cmath>
00018
00019
00020 namespace OpenTissue
00021 {
00022 namespace math
00023 {
00024 namespace big
00025 {
00026
00041 template<typename matrix_type, typename vector_type>
00042 inline void conjugate_gradient(
00043 matrix_type const & A
00044 , vector_type & x
00045 , vector_type const & b
00046 , size_t const & max_iterations
00047 , typename vector_type::value_type const & epsilon
00048 , size_t & iterations
00049 )
00050 {
00051 typedef typename vector_type::value_type value_type;
00052 typedef typename vector_type::size_type size_type;
00053 typedef OpenTissue::math::ValueTraits<value_type> value_traits;
00054
00055 if(max_iterations <= 0)
00056 throw std::invalid_argument("Max iterations should be positive" );
00057
00058 if(epsilon <= value_traits::zero())
00059 throw std::invalid_argument("epsilon should be positive" );
00060
00061 if(A.size1() <= 0 || A.size2() <= 0)
00062 throw std::invalid_argument("A was empty");
00063
00064 if(b.size() != A.size1())
00065 throw std::invalid_argument("The size of b must be the same as the number of rows in A");
00066
00067 if(x.size() != A.size2())
00068 throw std::invalid_argument("The size of x must be the same as the number of columns in A");
00069
00070 if(A.size1() != A.size2())
00071 throw std::invalid_argument("A is not quadratic");
00072
00073 iterations = 0;
00074
00075 size_type const size = x.size();
00076
00077 vector_type r( size );
00078 vector_type g( size );
00079 vector_type d( size );
00080
00081 value_type alpha, alpha2, beta, gamma;
00082
00083
00084 ublas::noalias( r ) = b;
00085 ublas::axpy_prod( A, -x, r, false );
00086
00087 ublas::noalias( g ) = r;
00088 alpha2 = ublas::inner_prod( r, r );
00089
00090 ++iterations;
00091
00092 value_type const threshold = epsilon * epsilon * alpha2;
00093
00094 while ( ( iterations < max_iterations ) && ( alpha2 > threshold ) )
00095 {
00096
00097 ublas::axpy_prod( A, g, d, true );
00098
00099 gamma = ublas::inner_prod( g, d );
00100 alpha = alpha2;
00101
00102 ublas::noalias( x ) += ( alpha / gamma ) * g;
00103 ublas::noalias( r ) += ( -alpha / gamma ) * d;
00104
00105 alpha2 = ublas::inner_prod( r, r );
00106 beta = alpha2 / alpha;
00107
00108 ublas::noalias( g ) = r + beta * g;
00109
00110 ++iterations;
00111 }
00112 }
00113
00122 template<typename matrix_type, typename vector_type>
00123 inline void conjugate_gradient(
00124 matrix_type const & A
00125 , vector_type & x
00126 , vector_type const & b
00127 , size_t & iterations
00128 )
00129 {
00130 typedef typename vector_type::value_type value_type;
00131 value_type epsilon = boost::numeric_cast<value_type>(10e-6);
00132 conjugate_gradient(A,x,b,15u,epsilon,iterations);
00133 }
00134
00142 template<typename matrix_type, typename vector_type>
00143 inline void conjugate_gradient(
00144 matrix_type const & A
00145 , vector_type & x
00146 , vector_type const & b
00147 )
00148 {
00149 typedef typename vector_type::value_type value_type;
00150 value_type epsilon = boost::numeric_cast<value_type>(10e-4);
00151 size_t iterations;
00152 conjugate_gradient(A,x,b,15u,epsilon,iterations);
00153 }
00154
00163 class ConjugateGradientFunctor
00164 {
00165 public:
00166
00167 template<typename matrix_type, typename vector_type>
00168 void operator() (
00169 matrix_type const & A
00170 , vector_type & x
00171 , vector_type const & b
00172 , size_t const & max_iterations
00173 , typename vector_type::value_type const & epsilon
00174 , size_t & iterations
00175 )
00176 {
00177 conjugate_gradient(A,x,b,max_iterations,epsilon,iterations);
00178 }
00179
00180 template<typename matrix_type, typename vector_type>
00181 void operator()(
00182 matrix_type const & A
00183 , vector_type & x
00184 , vector_type const & b
00185 )
00186 {
00187 conjugate_gradient(A,x,b);
00188 }
00189
00190 template<typename matrix_type, typename vector_type>
00191 void operator()(
00192 matrix_type const & A
00193 , vector_type & x
00194 , vector_type const & b
00195 , size_t & iterations
00196 )
00197 {
00198 conjugate_gradient(A,x,b,iterations);
00199 }
00200
00201 };
00202
00203 }
00204 }
00205 }
00206
00207
00208 #endif