def calcSolution(k): mat = Matrix(k + 1, k + 1, is_complex) for i in range(k + 1): mat[:, i] = H[i][:k + 1] rs = Vector(k + 1, is_complex) rs[:] = beta[:k + 1] y = mat.I * rs if xstart: x.data = xstart for i in range(k + 1): x.data += y[i] * Q[i]
def PINVIT(mata, matm, pre, num=1, maxit=20, printrates=True, GramSchmidt=False): """preconditioned inverse iteration""" r = mata.CreateRowVector() uvecs = MultiVector(r, num) vecs = MultiVector(r, 2 * num) # hv = MultiVector(r, 2*num) for v in vecs[0:num]: v.SetRandom() uvecs[:] = pre * vecs[0:num] lams = Vector(num * [1]) for i in range(maxit): vecs[0:num] = mata * uvecs - (matm * uvecs).Scale(lams) vecs[num:2 * num] = pre * vecs[0:num] vecs[0:num] = uvecs vecs.Orthogonalize() # matm) # hv[:] = mata * vecs # asmall = InnerProduct (vecs, hv) # hv[:] = matm * vecs # msmall = InnerProduct (vecs, hv) asmall = InnerProduct(vecs, mata * vecs) msmall = InnerProduct(vecs, matm * vecs) ev, evec = scipy.linalg.eigh(a=asmall, b=msmall) lams = Vector(ev[0:num]) if printrates: print(i, ":", list(lams)) uvecs[:] = vecs * Matrix(evec[:, 0:num]) return lams, uvecs
def calcSolution(k): # if callback_sol is set we need to recompute solution in every step if self.callback_sol is not None: sol.data = sol_start mat = Matrix(k + 1, k + 1, is_complex) for i in range(k + 1): mat[:, i] = H[i][:k + 1] rs = Vector(k + 1, is_complex) rs[:] = beta[:k + 1] y = mat.I * rs for i in range(k + 1): sol.data += y[i] * Q[i]
def arnoldi(A, Q, k): q = rhs.CreateVector() tmp.data = A * Q[k] q.data = pre * tmp h = Vector(m + 1, is_complex) h[:] = 0 for i in range(k + 1): h[i] = innerproduct(Q[i], q) q.data += (-1) * h[i] * Q[i] h[k + 1] = norm(q) if abs(h[k + 1]) < 1e-12: return h, None q *= 1. / h[k + 1].real return h, q
def Arnoldi(mat, tol=1e-10, maxiter=200): H = Matrix(maxiter, maxiter, complex=mat.is_complex) H[:, :] = 0 v = mat.CreateVector(colvector=False) abv = MultiVector(v, 0) v.SetRandom() v /= Norm(v) for i in range(maxiter): abv.Append(v) v = (mat * v).Evaluate() for j in range(i + 1): H[j, i] = InnerProduct(v, abv[j]) v -= H[j, i] * abv[j] if i + 1 < maxiter: H[i + 1, i] = Norm(v) v = 1 / Norm(v) * v lam, ev = scipy.linalg.eig(H) return Vector(lam), (abv * Matrix(ev)).Evaluate()
def _SolveImpl(self, rhs: BaseVector, sol: BaseVector): is_complex = rhs.is_complex A, pre, innerproduct, norm = self.mat, self.pre, self.innerproduct, self.norm n = len(rhs) m = self.maxiter sn = Vector(m, is_complex) cs = Vector(m, is_complex) sn[:] = 0 cs[:] = 0 if self.callback_sol is not None: sol_start = sol.CreateVector() sol_start.data = sol r = rhs.CreateVector() tmp = rhs.CreateVector() tmp.data = rhs - A * sol r.data = pre * tmp Q = [] H = [] Q.append(rhs.CreateVector()) r_norm = norm(r) if self.CheckResidual(abs(r_norm)): return sol Q[0].data = 1. / r_norm * r beta = Vector(m + 1, is_complex) beta[:] = 0 beta[0] = r_norm def arnoldi(A, Q, k): q = rhs.CreateVector() tmp.data = A * Q[k] q.data = pre * tmp h = Vector(m + 1, is_complex) h[:] = 0 for i in range(k + 1): h[i] = innerproduct(Q[i], q) q.data += (-1) * h[i] * Q[i] h[k + 1] = norm(q) if abs(h[k + 1]) < 1e-12: return h, None q *= 1. / h[k + 1].real return h, q def givens_rotation(v1, v2): if v2 == 0: return 1, 0 elif v1 == 0: return 0, v2 / abs(v2) else: t = sqrt((v1.conjugate() * v1 + v2.conjugate() * v2).real) cs = abs(v1) / t sn = v1 / abs(v1) * v2.conjugate() / t return cs, sn def apply_givens_rotation(h, cs, sn, k): for i in range(k): temp = cs[i] * h[i] + sn[i] * h[i + 1] h[i + 1] = -sn[i].conjugate() * h[i] + cs[i].conjugate() * h[i + 1] h[i] = temp cs[k], sn[k] = givens_rotation(h[k], h[k + 1]) h[k] = cs[k] * h[k] + sn[k] * h[k + 1] h[k + 1] = 0 def calcSolution(k): # if callback_sol is set we need to recompute solution in every step if self.callback_sol is not None: sol.data = sol_start mat = Matrix(k + 1, k + 1, is_complex) for i in range(k + 1): mat[:, i] = H[i][:k + 1] rs = Vector(k + 1, is_complex) rs[:] = beta[:k + 1] y = mat.I * rs for i in range(k + 1): sol.data += y[i] * Q[i] for k in range(m): h, q = arnoldi(A, Q, k) H.append(h) if q is None: break Q.append(q) apply_givens_rotation(h, cs, sn, k) beta[k + 1] = -sn[k].conjugate() * beta[k] beta[k] = cs[k] * beta[k] error = abs(beta[k + 1]) if self.callback_sol is not None: calcSolution(k) if self.CheckResidual(error): break if self.restart is not None and ( k + 1 == self.restart and not (self.restart == self.maxiter)): calcSolution(k) del Q restarted_solver = GMResSolver(mat=self.mat, pre=self.pre, tol=0, atol=self._final_residual, callback=self.callback, callback_sol=self.callback_sol, maxiter=self.maxiter, restart=self.restart, printrates=self.printrates) restarted_solver.iterations = self.iterations sol = restarted_solver.Solve(rhs=rhs, sol=sol, initialize=False) self.residuals += restarted_solver.residuals self.iterations = restarted_solver.iterations return sol calcSolution(k) return sol
def GMRes(A, b, pre=None, freedofs=None, x=None, maxsteps=100, tol=1e-7, innerproduct=None, callback=None, restart=None, startiteration=0, printrates=True): """ Restarting preconditioned gmres solver for A*x=b. Minimizes the preconditioned residuum pre*(b-A*x) Parameters ---------- A : BaseMatrix The left hand side of the linear system. b : BaseVector The right hand side of the linear system. pre : BaseMatrix = None The preconditioner for the system. If no preconditioner is given, the freedofs of the system must be given. freedofs : BitArray = None Freedofs to solve on, only necessary if no preconditioner is given. x : BaseVector = None Startvector, if given it will be modified in the routine and returned. Will be created if not given. maxsteps : int = 100 Maximum iteration steps. tol : float = 1e-7 Tolerance to be computed to. Gmres breaks if norm(pre*(b-A*x)) < tol. innerproduct : function = None Innerproduct to be used in iteration, all orthogonalizations/norms are computed with respect to that inner product. callback : function = None If given, this function is called with the solution vector x in each step. Only for debugging purposes, since it requires the overhead of computing x in every step. restart : int = None If given, gmres is restarted with the current solution x every 'restart' steps. startiteration : int = 0 Internal value to count total number of iterations in restarted setup, no user input required here. printrates : bool = True Print norm of preconditioned residual in each step. """ if not innerproduct: innerproduct = lambda x, y: y.InnerProduct(x, conjugate=True) norm = Norm else: norm = lambda x: sqrt(innerproduct(x, x).real) is_complex = b.is_complex if not pre: assert freedofs is not None pre = Projector(freedofs, True) n = len(b) m = maxsteps if not x: x = b.CreateVector() x[:] = 0 if callback: xstart = x.CreateVector() xstart.data = x else: xstart = None sn = Vector(m, is_complex) cs = Vector(m, is_complex) sn[:] = 0 cs[:] = 0 r = b.CreateVector() tmp = b.CreateVector() tmp.data = b - A * x r.data = pre * tmp Q = [] H = [] Q.append(b.CreateVector()) r_norm = norm(r) if abs(r_norm) < tol: return x Q[0].data = 1. / r_norm * r beta = Vector(m + 1, is_complex) beta[:] = 0 beta[0] = r_norm def arnoldi(A, Q, k): q = b.CreateVector() tmp.data = A * Q[k] q.data = pre * tmp h = Vector(m + 1, is_complex) h[:] = 0 for i in range(k + 1): h[i] = innerproduct(Q[i], q) q.data += (-1) * h[i] * Q[i] h[k + 1] = norm(q) if abs(h[k + 1]) < 1e-12: return h, None q *= 1. / h[k + 1].real return h, q def givens_rotation(v1, v2): if v2 == 0: return 1, 0 elif v1 == 0: return 0, v2 / abs(v2) else: t = sqrt((v1.conjugate() * v1 + v2.conjugate() * v2).real) cs = abs(v1) / t sn = v1 / abs(v1) * v2.conjugate() / t return cs, sn def apply_givens_rotation(h, cs, sn, k): for i in range(k): temp = cs[i] * h[i] + sn[i] * h[i + 1] h[i + 1] = -sn[i].conjugate() * h[i] + cs[i].conjugate() * h[i + 1] h[i] = temp cs[k], sn[k] = givens_rotation(h[k], h[k + 1]) h[k] = cs[k] * h[k] + sn[k] * h[k + 1] h[k + 1] = 0 def calcSolution(k): mat = Matrix(k + 1, k + 1, is_complex) for i in range(k + 1): mat[:, i] = H[i][:k + 1] rs = Vector(k + 1, is_complex) rs[:] = beta[:k + 1] y = mat.I * rs if xstart: x.data = xstart for i in range(k + 1): x.data += y[i] * Q[i] for k in range(m): startiteration += 1 h, q = arnoldi(A, Q, k) H.append(h) if q is None: break Q.append(q) apply_givens_rotation(h, cs, sn, k) beta[k + 1] = -sn[k].conjugate() * beta[k] beta[k] = cs[k] * beta[k] error = abs(beta[k + 1]) if printrates: print("Step", startiteration, ", error = ", error) if callback: calcSolution(k) callback(x) if error < tol: break if restart and k + 1 == restart and not (restart == maxsteps): calcSolution(k) del Q return GMRes(A, b, freedofs=freedofs, pre=pre, x=x, maxsteps=maxsteps - restart, callback=callback, tol=tol, innerproduct=innerproduct, restart=restart, startiteration=startiteration, printrates=printrates) calcSolution(k) return x