public GMRESResult solve(Vector b, Vector x0 = null) { GMRESResult result = solveImpl(b, x0); Utils.QL_REQUIRE(result.Errors.Last() < relTol_, () => "could not converge"); return(result); }
public GMRESResult solveWithRestart(int restart, Vector b, Vector x0 = null) { GMRESResult result = solveImpl(b, x0); List <double> errors = result.Errors; for (int i = 0; i < restart - 1 && result.Errors.Last() >= relTol_; ++i) { result = solveImpl(b, result.X); errors.AddRange(result.Errors); } Utils.QL_REQUIRE(errors.Last() < relTol_, () => "could not converge"); result.Errors = errors; return(result); }
protected GMRESResult solveImpl(Vector b, Vector x0) { double bn = Vector.Norm2(b); GMRESResult result; if (bn.IsEqual(0.0)) { result = new GMRESResult(new InitializedList <double>(1, 0.0), b); return(result); } Vector x = !x0.empty() ? x0 : new Vector(b.size(), 0.0); Vector r = b - A_(x); double g = Vector.Norm2(r); if (g / bn < relTol_) { result = new GMRESResult(new InitializedList <double>(1, g / bn), x); return(result); } List <Vector> v = new InitializedList <Vector>(1, r / g); List <Vector> h = new InitializedList <Vector>(1, new Vector(maxIter_, 0.0)); List <double> c = new List <double>(maxIter_ + 1), s = new List <double>(maxIter_ + 1), z = new List <double>(maxIter_ + 1); z[0] = g; List <double> errors = new InitializedList <double>(1, g / bn); for (int j = 0; j < maxIter_ && errors.Last() >= relTol_; ++j) { h.Add(new Vector(maxIter_, 0.0)); Vector w = A_((M_ != null) ? M_(v[j]) : v[j]); for (int i = 0; i <= j; ++i) { h[i][j] = Vector.DotProduct(w, v[i]); w -= h[i][j] * v[i]; } h[j + 1][j] = Vector.Norm2(w); if (h[j + 1][j] < Const.QL_EPSILON * Const.QL_EPSILON) { break; } v.Add(w / h[j + 1][j]); for (int i = 0; i < j; ++i) { double h0 = c[i] * h[i][j] + s[i] * h[i + 1][j]; double h1 = -s[i] * h[i][j] + c[i] * h[i + 1][j]; h[i][j] = h0; h[i + 1][j] = h1; } double nu = Math.Sqrt((h[j][j]) * (h[j][j]) + (h[j + 1][j]) * (h[j + 1][j])); c[j] = h[j][j] / nu; s[j] = h[j + 1][j] / nu; h[j][j] = nu; h[j + 1][j] = 0.0; z[j + 1] = -s[j] * z[j]; z[j] = c[j] * z[j]; errors.Add(Math.Abs(z[j + 1] / bn)); } int k = v.Count - 1; Vector y = new Vector(k, 0.0); y[k - 1] = z[k - 1] / h[k - 1][k - 1]; for (int i = k - 2; i >= 0; --i) { y[i] = (z[i] - h[i].inner_product( i + 1, k, i + 1, y, 0.0)) / h[i][i]; } Vector xm = new Vector(x.Count, 0.0); for (int i = 0; i < x.Count; i++) { xm[i] = v[i].inner_product(0, k, 0, y, 0.0); } xm = x + ((M_ != null) ? M_(xm) : xm); result = new GMRESResult(errors, xm); return(result); }