VectorType solve(const MatrixType & matrix, VectorType const & rhs, bicgstab_tag const & tag) { typedef typename viennacl::result_of::value_type<VectorType>::type ScalarType; typedef typename viennacl::result_of::cpu_value_type<ScalarType>::type CPU_ScalarType; VectorType result = rhs; viennacl::traits::clear(result); VectorType residual = rhs; VectorType p = rhs; VectorType r0star = rhs; VectorType tmp0 = rhs; VectorType tmp1 = rhs; VectorType s = rhs; CPU_ScalarType norm_rhs_host = viennacl::linalg::norm_2(residual); CPU_ScalarType ip_rr0star = norm_rhs_host * norm_rhs_host; CPU_ScalarType beta; CPU_ScalarType alpha; CPU_ScalarType omega; //ScalarType inner_prod_temp; //temporary variable for inner product computation CPU_ScalarType new_ip_rr0star = 0; CPU_ScalarType residual_norm = norm_rhs_host; if (norm_rhs_host == 0) //solution is zero if RHS norm is zero return result; bool restart_flag = true; vcl_size_t last_restart = 0; for (vcl_size_t i = 0; i < tag.max_iterations(); ++i) { if (restart_flag) { residual = rhs; residual -= viennacl::linalg::prod(matrix, result); p = residual; r0star = residual; ip_rr0star = viennacl::linalg::norm_2(residual); ip_rr0star *= ip_rr0star; restart_flag = false; last_restart = i; } tag.iters(i+1); tmp0 = viennacl::linalg::prod(matrix, p); alpha = ip_rr0star / viennacl::linalg::inner_prod(tmp0, r0star); s = residual - alpha*tmp0; tmp1 = viennacl::linalg::prod(matrix, s); CPU_ScalarType norm_tmp1 = viennacl::linalg::norm_2(tmp1); omega = viennacl::linalg::inner_prod(tmp1, s) / (norm_tmp1 * norm_tmp1); result += alpha * p + omega * s; residual = s - omega * tmp1; new_ip_rr0star = viennacl::linalg::inner_prod(residual, r0star); residual_norm = viennacl::linalg::norm_2(residual); if (std::fabs(residual_norm / norm_rhs_host) < tag.tolerance()) break; beta = new_ip_rr0star / ip_rr0star * alpha/omega; ip_rr0star = new_ip_rr0star; if (ip_rr0star == 0 || omega == 0 || i - last_restart > tag.max_iterations_before_restart()) //search direction degenerate. A restart might help restart_flag = true; // Execution of // p = residual + beta * (p - omega*tmp0); // without introducing temporary vectors: p -= omega * tmp0; p = residual + beta * p; } //store last error estimate: tag.error(residual_norm / norm_rhs_host); return result; }
VectorType solve(const MatrixType & matrix, VectorType const & rhs, bicgstab_tag const & tag, PreconditionerType const & precond) { typedef typename viennacl::result_of::value_type<VectorType>::type ScalarType; typedef typename viennacl::result_of::cpu_value_type<ScalarType>::type CPU_ScalarType; VectorType result = rhs; viennacl::traits::clear(result); VectorType residual = rhs; VectorType r0star = residual; //can be chosen arbitrarily in fact VectorType tmp0 = rhs; VectorType tmp1 = rhs; VectorType s = rhs; VectorType p = residual; CPU_ScalarType ip_rr0star = viennacl::linalg::norm_2(residual); CPU_ScalarType norm_rhs_host = viennacl::linalg::norm_2(residual); CPU_ScalarType beta; CPU_ScalarType alpha; CPU_ScalarType omega; CPU_ScalarType new_ip_rr0star = 0; CPU_ScalarType residual_norm = norm_rhs_host; if (!norm_rhs_host) //solution is zero if RHS norm is zero return result; bool restart_flag = true; vcl_size_t last_restart = 0; for (unsigned int i = 0; i < tag.max_iterations(); ++i) { if (restart_flag) { residual = rhs; residual -= viennacl::linalg::prod(matrix, result); precond.apply(residual); p = residual; r0star = residual; ip_rr0star = viennacl::linalg::norm_2(residual); ip_rr0star *= ip_rr0star; restart_flag = false; last_restart = i; } tag.iters(i+1); tmp0 = viennacl::linalg::prod(matrix, p); precond.apply(tmp0); alpha = ip_rr0star / viennacl::linalg::inner_prod(tmp0, r0star); s = residual - alpha*tmp0; tmp1 = viennacl::linalg::prod(matrix, s); precond.apply(tmp1); CPU_ScalarType norm_tmp1 = viennacl::linalg::norm_2(tmp1); omega = viennacl::linalg::inner_prod(tmp1, s) / (norm_tmp1 * norm_tmp1); result += alpha * p + omega * s; residual = s - omega * tmp1; residual_norm = viennacl::linalg::norm_2(residual); if (residual_norm / norm_rhs_host < tag.tolerance()) break; new_ip_rr0star = viennacl::linalg::inner_prod(residual, r0star); beta = new_ip_rr0star / ip_rr0star * alpha/omega; ip_rr0star = new_ip_rr0star; if (!ip_rr0star || !omega || i - last_restart > tag.max_iterations_before_restart()) //search direction degenerate. A restart might help restart_flag = true; // Execution of // p = residual + beta * (p - omega*tmp0); // without introducing temporary vectors: p -= omega * tmp0; p = residual + beta * p; //std::cout << "Rel. Residual in current step: " << std::sqrt(std::fabs(viennacl::linalg::inner_prod(residual, residual) / norm_rhs_host)) << std::endl; } //store last error estimate: tag.error(residual_norm / norm_rhs_host); return result; }