26template<sp_d data_t, HasEvaluate<data_t> System>
int GMRES(
const System* system, Col<data_t>& x,
const Col<data_t>& b, SolverSetting<data_t>& setting) {
27 constexpr sp_d auto ZERO = data_t(0);
28 constexpr sp_d auto ONE = data_t(1);
30 const auto& conditioner = setting.preconditioner;
32 auto generate_rotation = [](
const data_t dx,
const data_t dy, data_t& cs, data_t& sn) ->
void {
37 else if(std::fabs(dy) > std::fabs(dx)) {
38 const data_t fraction = dx / dy;
39 sn =
ONE / std::sqrt(
ONE + fraction * fraction);
43 const data_t fraction = dy / dx;
44 cs =
ONE / std::sqrt(
ONE + fraction * fraction);
49 auto apply_rotation = [](data_t& dx, data_t& dy,
const data_t cs,
const data_t sn) ->
void {
50 const data_t factor = cs * dx + sn * dy;
51 dy = cs * dy - sn * dx;
55 if(x.empty()) x = conditioner->apply(b);
56 else x.zeros(arma::size(b));
58 const auto mp = setting.restart + 1;
60 Mat<data_t> hessenberg(mp, setting.restart, fill::zeros);
63 data_t beta, residual;
64 Col<data_t> s(mp, fill::none), cs(mp, fill::none), sn(mp, fill::none), r;
66 auto norm_b = arma::norm(conditioner->apply(b));
69 auto stop_criterion = [&] {
70 residual = (beta = arma::norm(r = conditioner->apply(b - system->evaluate(x)))) / norm_b;
71 suanpan_debug(
"GMRES iterative solver residual: {:.5E}.\n", residual);
73 setting.tolerance = residual;
74 setting.max_iteration = counter;
80 Mat<data_t> v(b.n_rows, mp, fill::none);
82 auto update = [&](
const int k) -> Col<data_t> {
83 Col<data_t> y = s.head(k + 1llu);
85 for(
auto i = k; i >= 0; --i) {
86 y(i) /= hessenberg(i, i);
87 y.head(i) -= hessenberg.col(i).head(i) * y(i);
90 return v.head_cols(k + 1llu) * y;
93 while(counter <= setting.max_iteration) {
98 for(
auto i = 0, j = 1; i < setting.restart && counter <= setting.max_iteration; ++i, ++j, ++counter) {
99 auto w = conditioner->apply(system->evaluate(v.col(i)));
100 for(
auto k = 0; k <= i; ++k) w -= (hessenberg(k, i) = arma::dot(w, v.col(k))) * v.col(k);
101 v.col(j) = w / (hessenberg(j, i) = arma::norm(w));
103 for(
auto k = 0; k < i; ++k) apply_rotation(hessenberg(k, i), hessenberg(k + 1llu, i), cs(k), sn(k));
105 generate_rotation(hessenberg(i, i), hessenberg(j, i), cs(i), sn(i));
106 apply_rotation(hessenberg(i, i), hessenberg(j, i), cs(i), sn(i));
107 apply_rotation(s(i), s(j), cs(i), sn(i));
109 residual = std::fabs(s(j)) / norm_b;
110 suanpan_debug(
"GMRES iterative solver residual: {:.5E}.\n", residual);
111 if(residual < setting.tolerance) {
113 setting.tolerance = residual;
114 setting.max_iteration = counter;
119 x += update(setting.restart - 1);
123 setting.tolerance = residual;
127template<sp_d data_t, HasEvaluate<data_t> System>
int BiCGSTAB(
const System* system, Col<data_t>& x,
const Col<data_t>& b, SolverSetting<data_t>& setting) {
128 constexpr sp_d auto ZERO = data_t(0);
129 constexpr sp_d auto ONE = data_t(1);
131 const auto& conditioner = setting.preconditioner;
133 data_t norm_b = arma::norm(b);
136 if(x.empty()) x = conditioner->apply(b);
137 else x.zeros(arma::size(b));
139 Col<data_t> r = b - system->evaluate(x);
140 const auto initial_r = r;
142 data_t residual = arma::norm(r) / norm_b;
143 suanpan_debug(
"BiCGSTAB iterative solver residual: {:.5E}.\n", residual);
144 if(residual < setting.tolerance) {
145 setting.tolerance = residual;
146 setting.max_iteration = 0;
153 for(
auto i = 1; i <= setting.max_iteration; ++i) {
154 const auto rho = arma::dot(initial_r, r);
156 setting.tolerance = residual;
157 setting.max_iteration = i;
162 else p = r + rho / pre_rho * alpha / omega * (p - omega * v);
164 const auto phat = conditioner->apply(p);
165 v = system->evaluate(phat);
166 alpha = rho / arma::dot(initial_r, v);
167 const Col<data_t> s = r - alpha * v;
169 suanpan_debug(
"BiCGSTAB iterative solver residual: {:.5E}.\n", residual = arma::norm(s) / norm_b);
170 if(residual < setting.tolerance) {
172 setting.tolerance = residual;
173 setting.max_iteration = i;
177 const auto shat = conditioner->apply(s);
178 const Col<data_t> t = system->evaluate(shat);
179 omega = arma::dot(t, s) / arma::dot(t, t);
180 x += alpha * phat + omega * shat;
185 suanpan_debug(
"BiCGSTAB iterative solver residual: {:.5E}.\n", residual = arma::norm(r) / norm_b);
186 if(residual < setting.tolerance) {
187 setting.tolerance = residual;
188 setting.max_iteration = i;
193 setting.tolerance = residual;
194 setting.max_iteration = i;
199 setting.tolerance = residual;