|
ViennaCL - The Vienna Computing Library
1.1.2
|
00001 /* ======================================================================= 00002 Copyright (c) 2010, Institute for Microelectronics, TU Vienna. 00003 http://www.iue.tuwien.ac.at 00004 ----------------- 00005 ViennaCL - The Vienna Computing Library 00006 ----------------- 00007 00008 authors: Karl Rupp rupp@iue.tuwien.ac.at 00009 Florian Rudolf flo.rudy+viennacl@gmail.com 00010 Josef Weinbub weinbub@iue.tuwien.ac.at 00011 00012 license: MIT (X11), see file LICENSE in the ViennaCL base directory 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 //return values from solver 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 //typedef typename VectorType::value_type ScalarType; 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 //std::cout << "Starting CG solver... " << std::endl; 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 //alpha = ip_rr / viennacl::linalg::inner_prod(tmp, p); 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())//squared norms involved here 00122 break; 00123 00124 beta = new_ip_rr / ip_rr; 00125 ip_rr = new_ip_rr; 00126 00127 //p = residual + beta*p; 00128 p *= beta; 00129 p += residual; 00130 } 00131 00132 //store last error estimate: 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()) //squared norms involved here 00197 break; 00198 00199 beta = new_ip_rr / ip_rr; 00200 ip_rr = new_ip_rr; 00201 00202 //p = z + beta*p; 00203 p *= beta; 00204 p += z; 00205 } 00206 00207 //store last error estimate: 00208 tag.error(sqrt(std::fabs(new_ip_rr / norm_rhs_squared))); 00209 00210 return result; 00211 } 00212 00213 } 00214 } 00215 00216 #endif
1.7.6.1