229 static const scalar_type zero = math::zero<scalar_type>();
230 static const scalar_type one = math::identity<scalar_type>();
234 if (prm.always_reset) {
238 scalar_type norm_rhs = norm(rhs);
239 if (norm_rhs < Alina::detail::eps<scalar_type>(1)) {
241 norm_rhs = math::identity<scalar_type>();
249 scalar_type norm_r = zero;
250 scalar_type eps = std::max(prm.tol * norm_rhs, prm.abstol);
253 unsigned n_outer = 0;
255 if (prm.pside == ePreconditionerSideType::left) {
256 backend::residual(rhs, A, x, *vs[0]);
260 backend::residual(rhs, A, x, *r);
265 if (norm_r < eps || iter >= prm.maxiter)
269 backend::axpby(math::inverse(norm_r), *r, zero, *vs[0]);
271 std::fill(s.begin(), s.end(), 0);
306 vector& v_new = *vs[j + 1];
308 std::shared_ptr<vector> z;
309 if (j >= M - outer_v.size()) {
310 z = outer_v[j - (M - outer_v.size())];
318 preconditioner_spmv(prm.pside, P, A, *z, v_new, *r);
320 for (
unsigned k = 0; k <= j; ++k) {
321 H0(k, j) = H(k, j) = inner_product(v_new, *vs[k]);
322 backend::axpby(-H(k, j), *vs[k], one, v_new);
324 H0(j + 1, j) = H(j + 1, j) = norm(v_new);
326 backend::axpby(math::inverse(H(j + 1, j)), v_new, zero, v_new);
328 for (
unsigned k = 0; k < j; ++k)
329 detail::apply_plane_rotation(H(k, j), H(k + 1, j), cs[k], sn[k]);
331 detail::generate_plane_rotation(H(j, j), H(j + 1, j), cs[j], sn[j]);
332 detail::apply_plane_rotation(H(j, j), H(j + 1, j), cs[j], sn[j]);
333 detail::apply_plane_rotation(s[j], s[j + 1], cs[j], sn[j]);
335 scalar_type inner_res = std::abs(s[j + 1]);
337 if (prm.verbose && iter % 5 == 0)
338 std::cout << iter <<
"\t" << std::scientific << inner_res / norm_rhs << std::endl;
342 if (iter >= prm.maxiter || j >= M || inner_res <= eps)
347 for (
unsigned i = j; i-- > 0;) {
349 for (
unsigned k = 0; k < i; ++k)
350 s[k] -= H(k, i) * s[i];
354 backend::lin_comb(j, s, ws, zero, dx);
357 if (prm.pside == ePreconditionerSideType::left) {
358 backend::axpby(one, dx, one, x);
361 vector& tmp = *ws[0];
363 backend::axpby(one, tmp, one, x);
367 scalar_type norm_dx = norm(dx);
369 if (prm.K > 0 && !math::is_zero(norm_dx)) {
370 unsigned outer_slot = n_outer % prm.K;
373 norm_dx = math::inverse(norm_dx);
374 backend::axpby(norm_dx, dx, zero, *outer_v_data[outer_slot]);
375 outer_v.push_back(outer_v_data[outer_slot]);