computation/solver/iterative/Cgne.cxx

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_CGNE_CXX
00021 
00022 namespace Seldon
00023 {
00024 
00026 
00040   template <class Titer, class Matrix1, class Vector1, class Preconditioner>
00041   int Cgne(Matrix1& A, Vector1& x, const Vector1& b,
00042            Preconditioner& M, Iteration<Titer> & iter)
00043   {
00044     const int N = A.GetM();
00045     if (N <= 0)
00046       return 0;
00047 
00048     typedef typename Vector1::value_type Complexe;
00049     Complexe rho(1), rho_1(0), alpha, beta, delta;
00050     Vector1 p(b), q(b), r(b), z(b);
00051     Titer dp;
00052 
00053     // x should be equal to 0
00054     // see Cg to understand implementation
00055     // we solve A^t A x = A^t b
00056     // left-preconditioner is equal to M M^t
00057 
00058     // q = A^t b
00059     Mlt(SeldonTrans, A, b, q);
00060     // we initialize iter
00061     int success_init = iter.Init(q);
00062     if (success_init != 0)
00063       return iter.ErrorCode();
00064 
00065     if (!iter.IsInitGuess_Null())
00066       {
00067         // r = A^t b - A^t A x
00068         Mlt(A, x, p);
00069         Mlt(SeldonTrans, A, p, r); Mlt(Complexe(-1), r);
00070         Add(Complexe(1), q, r);
00071       }
00072     else
00073       {
00074         Copy(q, r);
00075         x.Zero();
00076       }
00077 
00078     dp = Norm2(q);
00079     iter.SetNumberIteration(0);
00080     // Loop until the stopping criteria are satisfied
00081     while (! iter.Finished(dp))
00082       {
00083         // Preconditioning
00084         M.TransSolve(A, r, q);
00085         M.Solve(A, q, z);
00086 
00087         rho = DotProd(r,z);
00088         if (rho == Complexe(0))
00089           {
00090             iter.Fail(1, "Cgne breakdown #1");
00091             break;
00092           }
00093 
00094         if (iter.First())
00095           Copy(z, p);
00096         else
00097           {
00098             beta = rho / rho_1;
00099             Mlt(beta, p);
00100             Add(Complexe(1), z, p);
00101           }
00102 
00103         // instead of q = A*p, we compute q = A^t A *p
00104         Mlt(A, p, q);
00105         Mlt(SeldonTrans, A, q, z);
00106 
00107         delta = DotProd(p, z);
00108         if (delta == Complexe(0))
00109           {
00110             iter.Fail(2, "Cgne breakdown #2");
00111             break;
00112           }
00113         alpha = rho / delta;
00114 
00115         Add(alpha, p, x);
00116         Add(-alpha, z, r);
00117 
00118         rho_1 = rho;
00119         dp = Norm2(r);
00120 
00121         // two iterations, because of two multiplications with A
00122         ++iter;
00123         ++iter;
00124       }
00125 
00126     return iter.ErrorCode();
00127   }
00128 
00129 
00130 } // end namespace
00131 
00132 #define SELDON_FILE_ITERATIVE_CGNE_CXX
00133 #endif