Go to the documentation of this file.00001 #ifndef VIENNACL_CG_HPP_
00002 #define VIENNACL_CG_HPP_
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00024 #include <vector>
00025 #include <map>
00026 #include <cmath>
00027 #include "viennacl/forwards.h"
00028 #include "viennacl/tools/tools.hpp"
00029 #include "viennacl/linalg/ilu.hpp"
00030 #include "viennacl/linalg/prod.hpp"
00031 #include "viennacl/linalg/inner_prod.hpp"
00032 #include "viennacl/traits/clear.hpp"
00033 #include "viennacl/traits/size.hpp"
00034 #include "viennacl/meta/result_of.hpp"
00035
00036 namespace viennacl
00037 {
00038 namespace linalg
00039 {
00040
00043 class cg_tag
00044 {
00045 public:
00051 cg_tag(double tol = 1e-8, unsigned int max_iterations = 300) : _tol(tol), _iterations(max_iterations) {};
00052
00054 double tolerance() const { return _tol; }
00056 unsigned int max_iterations() const { return _iterations; }
00057
00059 unsigned int iters() const { return iters_taken_; }
00060 void iters(unsigned int i) const { iters_taken_ = i; }
00061
00063 double error() const { return last_error_; }
00065 void error(double e) const { last_error_ = e; }
00066
00067
00068 private:
00069 double _tol;
00070 unsigned int _iterations;
00071
00072
00073 mutable unsigned int iters_taken_;
00074 mutable double last_error_;
00075 };
00076
00077
00087 template <typename MatrixType, typename VectorType>
00088 VectorType solve(const MatrixType & matrix, VectorType const & rhs, cg_tag const & tag)
00089 {
00090
00091 typedef typename viennacl::result_of::value_type<VectorType>::type ScalarType;
00092 typedef typename viennacl::result_of::cpu_value_type<ScalarType>::type CPU_ScalarType;
00093
00094 std::size_t problem_size = viennacl::traits::size(rhs);
00095 VectorType result(problem_size);
00096 viennacl::traits::clear(result);
00097
00098 VectorType residual = rhs;
00099 VectorType p = rhs;
00100 VectorType tmp(problem_size);
00101
00102 ScalarType tmp_in_p;
00103 ScalarType residual_norm_squared;
00104 CPU_ScalarType ip_rr = viennacl::linalg::inner_prod(rhs,rhs);
00105 CPU_ScalarType alpha;
00106 CPU_ScalarType new_ip_rr = 0;
00107 CPU_ScalarType beta;
00108 CPU_ScalarType norm_rhs_squared = ip_rr;
00109
00110
00111
00112 for (unsigned int i = 0; i < tag.max_iterations(); ++i)
00113 {
00114 tag.iters(i+1);
00115 tmp = viennacl::linalg::prod(matrix, p);
00116
00117
00118 tmp_in_p = viennacl::linalg::inner_prod(tmp, p);
00119 alpha = ip_rr / static_cast<CPU_ScalarType>(tmp_in_p);
00120
00121 result += alpha * p;
00122 residual -= alpha * tmp;
00123
00124 residual_norm_squared = viennacl::linalg::inner_prod(residual,residual);
00125 new_ip_rr = static_cast<CPU_ScalarType>(residual_norm_squared);
00126 if (new_ip_rr / norm_rhs_squared < tag.tolerance() * tag.tolerance())
00127 break;
00128
00129 beta = new_ip_rr / ip_rr;
00130 ip_rr = new_ip_rr;
00131
00132
00133 p *= beta;
00134 p += residual;
00135 }
00136
00137
00138 tag.error(sqrt(new_ip_rr / norm_rhs_squared));
00139
00140 return result;
00141 }
00142
00143 template <typename MatrixType, typename VectorType>
00144 VectorType solve(const MatrixType & matrix, VectorType const & rhs, cg_tag const & tag, viennacl::linalg::no_precond)
00145 {
00146 return solve(matrix, rhs, tag);
00147 }
00148
00159 template <typename MatrixType, typename VectorType, typename PreconditionerType>
00160 VectorType solve(const MatrixType & matrix, VectorType const & rhs, cg_tag const & tag, PreconditionerType const & precond)
00161 {
00162 typedef typename viennacl::result_of::value_type<VectorType>::type ScalarType;
00163 typedef typename viennacl::result_of::cpu_value_type<ScalarType>::type CPU_ScalarType;
00164 unsigned int problem_size = viennacl::traits::size(rhs);
00165
00166 VectorType result(problem_size);
00167 result.clear();
00168
00169 VectorType residual = rhs;
00170 VectorType tmp(problem_size);
00171 VectorType z = rhs;
00172
00173 precond.apply(z);
00174 VectorType p = z;
00175
00176 ScalarType tmp_in_p;
00177 ScalarType residual_in_z;
00178 CPU_ScalarType ip_rr = viennacl::linalg::inner_prod(residual, z);
00179 CPU_ScalarType alpha;
00180 CPU_ScalarType new_ip_rr = 0;
00181 CPU_ScalarType beta;
00182 CPU_ScalarType norm_rhs_squared = ip_rr;
00183 CPU_ScalarType new_ipp_rr_over_norm_rhs;
00184
00185 for (unsigned int i = 0; i < tag.max_iterations(); ++i)
00186 {
00187 tag.iters(i+1);
00188 tmp = viennacl::linalg::prod(matrix, p);
00189
00190 tmp_in_p = viennacl::linalg::inner_prod(tmp, p);
00191 alpha = ip_rr / static_cast<CPU_ScalarType>(tmp_in_p);
00192
00193 result += alpha * p;
00194 residual -= alpha * tmp;
00195 z = residual;
00196 precond.apply(z);
00197
00198 residual_in_z = viennacl::linalg::inner_prod(residual, z);
00199 new_ip_rr = static_cast<CPU_ScalarType>(residual_in_z);
00200 new_ipp_rr_over_norm_rhs = new_ip_rr / norm_rhs_squared;
00201 if (std::fabs(new_ipp_rr_over_norm_rhs) < tag.tolerance() * tag.tolerance())
00202 break;
00203
00204 beta = new_ip_rr / ip_rr;
00205 ip_rr = new_ip_rr;
00206
00207
00208 p *= beta;
00209 p += z;
00210 }
00211
00212
00213 tag.error(sqrt(std::fabs(new_ip_rr / norm_rhs_squared)));
00214
00215 return result;
00216 }
00217
00218 }
00219 }
00220
00221 #endif