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