ViennaCL - The Vienna Computing Library
1.5.2
|
00001 #ifndef VIENNACL_LINALG_CG_HPP_ 00002 #define VIENNACL_LINALG_CG_HPP_ 00003 00004 /* ========================================================================= 00005 Copyright (c) 2010-2014, Institute for Microelectronics, 00006 Institute for Analysis and Scientific Computing, 00007 TU Wien. 00008 Portions of this software are copyright by UChicago Argonne, LLC. 00009 00010 ----------------- 00011 ViennaCL - The Vienna Computing Library 00012 ----------------- 00013 00014 Project Head: Karl Rupp rupp@iue.tuwien.ac.at 00015 00016 (A list of authors and contributors can be found in the PDF manual) 00017 00018 License: MIT (X11), see file LICENSE in the base directory 00019 ============================================================================= */ 00020 00025 #include <vector> 00026 #include <map> 00027 #include <cmath> 00028 #include "viennacl/forwards.h" 00029 #include "viennacl/tools/tools.hpp" 00030 #include "viennacl/linalg/ilu.hpp" 00031 #include "viennacl/linalg/prod.hpp" 00032 #include "viennacl/linalg/inner_prod.hpp" 00033 #include "viennacl/linalg/norm_2.hpp" 00034 #include "viennacl/traits/clear.hpp" 00035 #include "viennacl/traits/size.hpp" 00036 #include "viennacl/meta/result_of.hpp" 00037 00038 namespace viennacl 00039 { 00040 namespace linalg 00041 { 00042 00045 class cg_tag 00046 { 00047 public: 00053 cg_tag(double tol = 1e-8, unsigned int max_iterations = 300) : tol_(tol), iterations_(max_iterations) {} 00054 00056 double tolerance() const { return tol_; } 00058 unsigned int max_iterations() const { return iterations_; } 00059 00061 unsigned int iters() const { return iters_taken_; } 00062 void iters(unsigned int i) const { iters_taken_ = i; } 00063 00065 double error() const { return last_error_; } 00067 void error(double e) const { last_error_ = e; } 00068 00069 00070 private: 00071 double tol_; 00072 unsigned int iterations_; 00073 00074 //return values from solver 00075 mutable unsigned int iters_taken_; 00076 mutable double last_error_; 00077 }; 00078 00079 00089 template <typename MatrixType, typename VectorType> 00090 VectorType solve(const MatrixType & matrix, VectorType const & rhs, cg_tag const & tag) 00091 { 00092 //typedef typename VectorType::value_type ScalarType; 00093 typedef typename viennacl::result_of::value_type<VectorType>::type ScalarType; 00094 typedef typename viennacl::result_of::cpu_value_type<ScalarType>::type CPU_ScalarType; 00095 //std::cout << "Starting CG" << std::endl; 00096 VectorType result = rhs; 00097 viennacl::traits::clear(result); 00098 00099 VectorType residual = rhs; 00100 VectorType p = rhs; 00101 VectorType tmp = rhs; 00102 00103 CPU_ScalarType ip_rr = viennacl::linalg::inner_prod(rhs,rhs); 00104 CPU_ScalarType alpha; 00105 CPU_ScalarType new_ip_rr = 0; 00106 CPU_ScalarType beta; 00107 CPU_ScalarType norm_rhs = std::sqrt(ip_rr); 00108 00109 //std::cout << "Starting CG solver iterations... " << std::endl; 00110 if (norm_rhs == 0) //solution is zero if RHS norm is zero 00111 return result; 00112 00113 for (unsigned int i = 0; i < tag.max_iterations(); ++i) 00114 { 00115 tag.iters(i+1); 00116 tmp = viennacl::linalg::prod(matrix, p); 00117 00118 alpha = ip_rr / viennacl::linalg::inner_prod(tmp, p); 00119 result += alpha * p; 00120 residual -= alpha * tmp; 00121 00122 new_ip_rr = viennacl::linalg::norm_2(residual); 00123 if (new_ip_rr / norm_rhs < tag.tolerance()) 00124 break; 00125 new_ip_rr *= new_ip_rr; 00126 00127 beta = new_ip_rr / ip_rr; 00128 ip_rr = new_ip_rr; 00129 00130 p = residual + beta * p; 00131 } 00132 00133 //store last error estimate: 00134 tag.error(std::sqrt(new_ip_rr) / norm_rhs); 00135 00136 return result; 00137 } 00138 00139 template <typename MatrixType, typename VectorType> 00140 VectorType solve(const MatrixType & matrix, VectorType const & rhs, cg_tag const & tag, viennacl::linalg::no_precond) 00141 { 00142 return solve(matrix, rhs, tag); 00143 } 00144 00155 template <typename MatrixType, typename VectorType, typename PreconditionerType> 00156 VectorType solve(const MatrixType & matrix, VectorType const & rhs, cg_tag const & tag, PreconditionerType const & precond) 00157 { 00158 typedef typename viennacl::result_of::value_type<VectorType>::type ScalarType; 00159 typedef typename viennacl::result_of::cpu_value_type<ScalarType>::type CPU_ScalarType; 00160 00161 VectorType result = rhs; 00162 viennacl::traits::clear(result); 00163 00164 VectorType residual = rhs; 00165 VectorType tmp = rhs; 00166 VectorType z = rhs; 00167 00168 precond.apply(z); 00169 VectorType p = z; 00170 00171 CPU_ScalarType ip_rr = viennacl::linalg::inner_prod(residual, z); 00172 CPU_ScalarType alpha; 00173 CPU_ScalarType new_ip_rr = 0; 00174 CPU_ScalarType beta; 00175 CPU_ScalarType norm_rhs_squared = ip_rr; 00176 CPU_ScalarType new_ipp_rr_over_norm_rhs; 00177 00178 if (norm_rhs_squared == 0) //solution is zero if RHS norm is zero 00179 return result; 00180 00181 for (unsigned int i = 0; i < tag.max_iterations(); ++i) 00182 { 00183 tag.iters(i+1); 00184 tmp = viennacl::linalg::prod(matrix, p); 00185 00186 alpha = ip_rr / viennacl::linalg::inner_prod(tmp, p); 00187 00188 result += alpha * p; 00189 residual -= alpha * tmp; 00190 z = residual; 00191 precond.apply(z); 00192 00193 new_ip_rr = viennacl::linalg::inner_prod(residual, z); 00194 new_ipp_rr_over_norm_rhs = new_ip_rr / norm_rhs_squared; 00195 if (std::fabs(new_ipp_rr_over_norm_rhs) < tag.tolerance() * tag.tolerance()) //squared norms involved here 00196 break; 00197 00198 beta = new_ip_rr / ip_rr; 00199 ip_rr = new_ip_rr; 00200 00201 p = z + beta*p; 00202 } 00203 00204 //store last error estimate: 00205 tag.error(std::sqrt(std::fabs(new_ip_rr / norm_rhs_squared))); 00206 00207 return result; 00208 } 00209 00210 } 00211 } 00212 00213 #endif