computation/solver/iterative/QmrSym.cxx

00001 // Copyright (C) 2003-2009 Marc Duruflé
00002 // Copyright (C) 2001-2009 Vivien Mallet
00003 //
00004 // This file is part of the linear-algebra library Seldon,
00005 // http://seldon.sourceforge.net/.
00006 //
00007 // Seldon is free software; you can redistribute it and/or modify it under the
00008 // terms of the GNU Lesser General Public License as published by the Free
00009 // Software Foundation; either version 2.1 of the License, or (at your option)
00010 // any later version.
00011 //
00012 // Seldon is distributed in the hope that it will be useful, but WITHOUT ANY
00013 // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
00014 // FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
00015 // more details.
00016 //
00017 // You should have received a copy of the GNU Lesser General Public License
00018 // along with Seldon. If not, see http://www.gnu.org/licenses/.
00019 
00020 
00021 #ifndef SELDON_FILE_ITERATIVE_QMRSYM_CXX
00022 
00023 namespace Seldon
00024 {
00025 
00027 
00041   template <class Titer, class Matrix1, class Vector1, class Preconditioner>
00042   int QmrSym(Matrix1& A, Vector1& x, const Vector1& b,
00043              Preconditioner& M, Iteration<Titer> & iter)
00044   {
00045     const int N = A.GetM();
00046     if (N <= 0)
00047       return 0;
00048 
00049     typedef typename Vector1::value_type Complexe;
00050     Complexe delta, ep(0), beta;
00051     Titer  rho, rho_1;
00052     Complexe theta_1, gamma_1;
00053     Complexe theta(0), gamma(1), eta(-1);
00054 
00055     Vector1 r(b), y(b);
00056     Vector1 v(b), p_tld(b);
00057     Vector1 p(b), d(b), s(b);
00058 
00059     // we initialize iter
00060     int success_init = iter.Init(b);
00061     if (success_init != 0)
00062       return iter.ErrorCode();
00063 
00064     // r = b - Ax
00065     Copy(b, r);
00066     if (!iter.IsInitGuess_Null())
00067       MltAdd(Complexe(-1), A, x, Complexe(1), r);
00068     else
00069       x.Zero();
00070 
00071     Copy(r, v);
00072 
00073     M.Solve(A, v, y);
00074     rho = Norm2(y);
00075 
00076     iter.SetNumberIteration(0);
00077     // Loop until the stopping criteria are reached
00078     while (! iter.Finished(r))
00079       {
00080 
00081         if (rho == Titer(0))
00082           {
00083             iter.Fail(1, "Qmr breakdown #1");
00084             break;
00085           }
00086 
00087         // v = v / rho
00088         // y = y / rho
00089         Mlt(Complexe(1./rho), v);
00090         Mlt(Complexe(1./rho), y);
00091 
00092         delta = DotProd(v, y);
00093         if (delta == Complexe(0))
00094           {
00095             iter.Fail(3, "Qmr breakdown #2");
00096             break;
00097           }
00098 
00099         if (iter.First())
00100           Copy(y, p);
00101         else
00102           {
00103             // p = y - (rho delta / ep) p
00104             Mlt(Complexe(-(rho  * delta / ep)), p);
00105             Add(Complexe(1), y, p);
00106           }
00107 
00108         // product matrix vector p_tld = A*p
00109         Mlt(A, p, p_tld);
00110 
00111         ep = DotProd(p, p_tld);
00112         if (ep == Complexe(0))
00113           {
00114             iter.Fail(4, "Qmr breakdown #3");
00115             break;
00116           }
00117 
00118         beta = ep / delta;
00119         if (beta == Complexe(0))
00120           {
00121             iter.Fail(5, "Qmr breakdown #4");
00122             break;
00123           }
00124 
00125         // v = -beta v + p_tld
00126         Mlt(Complexe(-beta), v); Add(Complexe(1), p_tld, v);
00127         M.Solve(A, v, y);
00128 
00129         rho_1 = rho;
00130         rho = Norm2(y);
00131 
00132         gamma_1 = gamma;
00133         theta_1 = theta;
00134 
00135         theta = rho / (gamma_1 * beta);
00136         gamma = Complexe(1) / sqrt(1.0 + theta * theta);
00137 
00138         if (gamma == Titer(0))
00139           {
00140             iter.Fail(6, "Qmr breakdown #5");
00141             break;
00142           }
00143 
00144         eta = -eta * rho_1 * gamma * gamma / (beta * gamma_1 * gamma_1);
00145 
00146         if (iter.First())
00147           {
00148             Copy(p, d);
00149             Mlt(eta, d);
00150             Copy(p_tld, s);
00151             Mlt(eta, s);
00152           }
00153         else
00154           {
00155             Complexe tmp = (theta_1 * theta_1 * gamma * gamma);
00156             Mlt(tmp, d);
00157             Add(eta, p, d);
00158             Mlt(tmp, s);
00159             Add(eta, p_tld, s);
00160           }
00161         Add(Complexe(1), d, x);
00162         Add(-Complexe(1), s, r);
00163 
00164         ++iter;
00165       }
00166 
00167     return iter.ErrorCode();
00168   }
00169 
00170 } // end namespace
00171 
00172 #define SELDON_FILE_ITERATIVE_QMRSYM_CXX
00173 #endif