159 const params& prm = params(),
160 const backend_params& bprm = backend_params(),
161 const InnerProduct& inner_product = InnerProduct())
162 : SolverBase(context)
165 , inner_product(inner_product)
169 , r(Backend::create_vector(n, bprm))
170 , v(Backend::create_vector(n, bprm))
171 , t(Backend::create_vector(n, bprm))
173 static const scalar_type one = math::identity<scalar_type>();
174 static const scalar_type zero = math::zero<scalar_type>();
177 x_s = Backend::create_vector(n, bprm);
178 r_s = Backend::create_vector(n, bprm);
183 for (
Int32 i = 0; i < prm.s; ++i) {
184 G.push_back(Backend::create_vector(n, bprm));
185 U.push_back(Backend::create_vector(n, bprm));
191 std::vector<rhs_type> p(n);
193 int pid = inner_product.rank();
197 std::mt19937 rng(pid * nt + tid);
198 std::uniform_real_distribution<scalar_type> rnd(-1, 1);
200 for (
unsigned j = 0; j < prm.s; ++j) {
201 for (ptrdiff_t i = 0; i < n; ++i) {
202 p[i] = math::constant<rhs_type>(rnd(rng));
204 P.push_back(Backend::copy_vector(p, bprm));
207 for (
unsigned j = 0; j < prm.s; ++j) {
208 for (
unsigned k = 0; k < j; ++k) {
209 coef_type alpha = inner_product(*P[k], *P[j]);
210 backend::axpby(-alpha, *P[k], one, *P[j]);
212 scalar_type norm_pj = norm(*P[j]);
213 backend::axpby(math::inverse(norm_pj), *P[j], zero, *P[j]);
236 static const scalar_type one = math::identity<scalar_type>();
237 static const scalar_type zero = math::zero<scalar_type>();
241 scalar_type norm_rhs = norm(rhs);
242 if (norm_rhs < Alina::detail::eps<scalar_type>(1)) {
244 norm_rhs = math::identity<scalar_type>();
252 scalar_type eps = std::max(prm.tol * norm_rhs, prm.abstol);
255 backend::residual(rhs, A, x, *r);
257 scalar_type res_norm = norm(*r);
258 if (res_norm <= eps) {
264 backend::copy(x, *x_s);
265 backend::copy(*r, *r_s);
269 coef_type om = math::identity<coef_type>();
271 for (
unsigned i = 0; i < prm.s; ++i) {
272 backend::clear(*G[i]);
273 backend::clear(*U[i]);
275 for (
unsigned j = 0; j < prm.s; ++j)
281 while (iter < prm.maxiter && res_norm > eps) {
283 for (
unsigned i = 0; i < prm.s; ++i)
284 f[i] = inner_product(*r, *P[i]);
286 for (
unsigned k = 0; k < prm.s; ++k) {
288 backend::copy(*r, *v);
292 for (
unsigned i = k; i < prm.s; ++i) {
294 for (
unsigned j = k; j < i; ++j)
295 c[i] -= M(i, j) * c[j];
296 c[i] = math::inverse(M(i, i)) * c[i];
298 backend::axpby(-c[i], *G[i], one, *v);
304 backend::axpby(om, *t, c[k], *U[k]);
305 for (
unsigned i = k + 1; i < prm.s; ++i)
306 backend::axpby(c[i], *U[i], one, *U[k]);
309 backend::spmv(one, A, *U[k], zero, *G[k]);
312 for (
unsigned i = 0; i < k; ++i) {
313 coef_type alpha = inner_product(*G[k], *P[i]) / M(i, i);
315 backend::axpby(-alpha, *G[i], one, *G[k]);
316 backend::axpby(-alpha, *U[i], one, *U[k]);
320 for (
unsigned i = k; i < prm.s; ++i)
321 M(i, k) = inner_product(*G[k], *P[i]);
323 precondition(!math::is_zero(M(k, k)),
"IDR(s) breakdown: zero M[k,k]");
326 coef_type beta = math::inverse(M(k, k)) * f[k];
327 backend::axpby(-beta, *G[k], one, *r);
328 backend::axpby(beta, *U[k], one, x);
334 backend::axpbypcz(one, *r_s, -one, *r, zero, *t);
335 coef_type gamma = inner_product(*t, *r_s) / inner_product(*t, *t);
336 backend::axpby(-gamma, *t, one, *r_s);
337 backend::axpbypcz(-gamma, *x_s, gamma, x, one, *x_s);
338 res_norm = norm(*r_s);
341 if (prm.verbose && iter % 5 == 0)
342 std::cout << iter <<
"\t" << std::scientific << res_norm / norm_rhs << std::endl;
343 if (res_norm <= eps || ++iter >= prm.maxiter)
347 for (
unsigned i = k + 1; i < prm.s; ++i)
348 f[i] -= beta * M(i, k);
351 if (res_norm <= eps || iter >= prm.maxiter)
358 backend::spmv(one, A, *v, zero, *t);
362 precondition(!math::is_zero(om),
"IDR(s) breakdown: zero omega");
364 backend::axpby(-om, *t, one, *r);
365 backend::axpby(om, *v, one, x);
367 if (prm.replacement) {
368 backend::residual(rhs, A, x, *r);
374 backend::axpbypcz(one, *r_s, -one, *r, zero, *t);
375 coef_type gamma = inner_product(*t, *r_s) / inner_product(*t, *t);
376 backend::axpby(-gamma, *t, one, *r_s);
377 backend::axpbypcz(-gamma, *x_s, gamma, x, one, *x_s);
378 res_norm = norm(*r_s);
385 backend::copy(*x_s, x);