Warning: this documentation for the development version is under construction.
00001 // Copyright (C) 2003-2009 Marc Duruflé 00002 // 00003 // This file is part of the linear-algebra library Seldon, 00004 // http://seldon.sourceforge.net/. 00005 // 00006 // Seldon is free software; you can redistribute it and/or modify it under the 00007 // terms of the GNU Lesser General Public License as published by the Free 00008 // Software Foundation; either version 2.1 of the License, or (at your option) 00009 // any later version. 00010 // 00011 // Seldon is distributed in the hope that it will be useful, but WITHOUT ANY 00012 // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 00013 // FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for 00014 // more details. 00015 // 00016 // You should have received a copy of the GNU Lesser General Public License 00017 // along with Seldon. If not, see http://www.gnu.org/licenses/. 00018 00019 00020 #ifndef SELDON_FILE_ITERATIVE_GMRES_CXX 00021 00022 namespace Seldon 00023 { 00024 00026 00044 template <class Titer, class MatrixSparse, class Vector1, class Preconditioner> 00045 int Gmres(MatrixSparse& A, Vector1& x, const Vector1& b, 00046 Preconditioner& M, Iteration<Titer> & outer) 00047 { 00048 const int N = A.GetM(); 00049 if (N <= 0) 00050 return 0; 00051 00052 typedef typename Vector1::value_type Complexe; 00053 Complexe zero(0); 00054 00055 int m = outer.GetRestart(); 00056 // V is the array of orthogonal basis contructed 00057 // from the Krylov subspace (v0,A*v0,A^2*v0,...,A^m*v0) 00058 std::vector<Vector1> V(m+1, b); 00059 00060 // Upper triangular hessenberg matrix 00061 // we don't store the sub-diagonal 00062 // we apply rotations to eliminate this sub-diagonal 00063 Matrix<Complexe, General, ColUpTriang> H(m+1,m+1); H.Fill(zero); 00064 00065 // s is the vector of residual norm for each inner iteration 00066 // w is used in the Arnoldi algorithm 00067 // u is a temporary vector which contains the product A*v(i) 00068 // r is the residual 00069 Vector1 w(b), r(b), u(b); 00070 Vector<Complexe> s(m+1); 00071 s.Fill(zero); w.Fill(zero); r.Fill(zero); u.Fill(zero); 00072 00073 for (int i = 0; i < m+1; i++) 00074 V[i].Fill(zero); 00075 00076 Vector<Complexe> rotations_sin(m+1); 00077 rotations_sin.Fill(zero); 00078 Vector<Titer> rotations_cos(m+1); 00079 rotations_cos.Fill(Titer(0)); 00080 00081 // we compute residual 00082 Copy(b, w); 00083 if (!outer.IsInitGuess_Null()) 00084 MltAdd(Complexe(-1), A, x, Complexe(1), w); 00085 else 00086 x.Fill(zero); 00087 00088 // preconditioning 00089 M.Solve(A, w, r); 00090 Titer beta = Norm2(r); 00091 00092 // we initialize outer 00093 int success_init = outer.Init(r); 00094 if (success_init != 0) 00095 return outer.ErrorCode(); 00096 00097 // the coefficient H(m+1,m) 00098 Complexe hi_ip1; 00099 00100 outer.SetNumberIteration(0); 00101 // Loop until the stopping criteria are reached 00102 while (! outer.Finished(beta)) 00103 { 00104 // we normalize V(0) and we init s 00105 Copy(r, V[0]); 00106 Mlt(Complexe(Complexe(1)/beta), V[0]); 00107 s.Fill(zero); 00108 s(0) = beta; 00109 00110 int i = 0, k; 00111 00112 // we initialize the iter iteration 00113 // m is the maximum number of inner iterations 00114 Iteration<Titer> inner(outer); 00115 inner.SetNumberIteration(outer.GetNumberIteration()); 00116 inner.SetMaxNumberIteration(outer.GetNumberIteration()+m); 00117 00118 do 00119 { 00120 // product matrix vector u=A*V(i) 00121 Mlt(A, V[i], u); 00122 00123 // preconditioning 00124 M.Solve(A, u, w); 00125 00126 // Arnoldi algorithm 00127 for (k = 0; k <= i; k++) 00128 { 00129 // h_{k,i} = \bar{v(k)} w 00130 H.Val(k, i) = DotProdConj(V[k], w); 00131 Add(-H(k,i), V[k], w); 00132 } 00133 00134 // we compute h(i+1,i) 00135 hi_ip1 = Norm2(w); 00136 Copy(w, V[i+1]); 00137 00138 // we normalize V(i+1) 00139 if (hi_ip1 != zero) 00140 Mlt(Complexe(1)/hi_ip1, V[i+1]); 00141 00142 // we apply precedent generated rotations 00143 // to the last column we computed. 00144 for (k = 0; k < i; k++) 00145 ApplyRot(H.Val(k,i), H.Val(k+1,i), 00146 rotations_cos(k), rotations_sin(k)); 00147 00148 // we generate a new rotation Omega=[c s;-conj(s) c] in order to 00149 // cancel h(i+1,i) and we store this rotation 00150 if (hi_ip1 != zero) 00151 { 00152 GenRot(H.Val(i,i), hi_ip1, 00153 rotations_cos(i), rotations_sin(i)); 00154 // After this call we must have hi_ip1=0 00155 // GenRot must modify the entries H(i,i) hi_ip1 00156 // we apply the rotation to the right hand side s 00157 ApplyRot(s(i), s(i+1), rotations_cos(i), rotations_sin(i)); 00158 } 00159 00160 ++inner, ++outer, ++i; 00161 00162 } while (! inner.Finished(abs(s(i)))); 00163 00164 // Now we solve the triangular system H 00165 H.Resize(i, i); s.Resize(i); 00166 Solve(H, s); s.Resize(m+1); 00167 00168 // new iterate x = x + sum_0^{i-1} s(k)*V(k) 00169 for (k = 0; k < i; k++) 00170 Add(s(k), V[k], x); 00171 00172 // we compute the new residual 00173 Copy(b, w); 00174 MltAdd(Complexe(-1), A, x, Complexe(1), w); 00175 M.Solve(A, w, r); 00176 00177 // residual norm 00178 beta = Norm2(r); 00179 } 00180 00181 return outer.ErrorCode(); 00182 00183 } 00184 00185 } // end namespace 00186 00187 #define SELDON_FILE_ITERATIVE_GMRES_CXX 00188 #endif