computation/solver/iterative/BiCgStabl.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_BICGSTABL_CXX
00022 
00023 namespace Seldon
00024 {
00025 
00027 
00043   template <class Titer, class Matrix1, class Vector1, class Preconditioner>
00044   int BiCgStabl(Matrix1& A, Vector1& x, const Vector1& b,
00045                 Preconditioner& M, Iteration<Titer> & iter)
00046   {
00047     const int N = A.GetM();
00048     if (N <= 0)
00049       return 0;
00050 
00051     typedef typename Vector1::value_type Complexe;
00052     int m = iter.GetRestart();
00053     int l = m;
00054     Complexe rho_0, rho_1, alpha, beta, omega, sigma, zero, unity;
00055     zero = 0.0; unity = 1.0;
00056 
00057     // q temporary vector before preconditioning, r0 initial residual
00058     Vector1 q(b), r0(b);
00059     Vector<Complexe> gamma(l+1), gamma_prime(l+1), gamma_twice(l+1);
00060     Matrix<Complexe, General, RowMajor> tau(l+1,l+1);
00061     // history of u and residual r
00062     std::vector<Vector1> r(l+1, b), u(l+1, b);
00063     for (int i = 0; i <= l; i++)
00064       {
00065         r[i].Zero();
00066         u[i].Zero();
00067       }
00068     tau.Zero(); gamma.Zero(); gamma_prime.Zero(); gamma_twice.Zero();
00069 
00070     // we compute the residual r = (b - Ax)
00071     Copy(b, r[0]);
00072     if (!iter.IsInitGuess_Null())
00073       MltAdd(Complexe(-1), A, x, Complexe(1), r[0]);
00074     else
00075       x.Zero();
00076 
00077     // we initialize iter
00078     int success_init = iter.Init(b);
00079     if (success_init !=0 )
00080       return iter.ErrorCode();
00081 
00082     Copy(r[0], r0); // we keep the first residual
00083 
00084     // we initialize constants
00085     rho_0 = unity; alpha = zero; omega = unity; tau.Zero();
00086 
00087     iter.SetNumberIteration(0);
00088     // Loop until the stopping criteria are satisfied
00089     while (! iter.Finished(r[0]))
00090       {
00091         rho_0 *= -omega;
00092 
00093         // Bi-CG Part
00094         for (int j = 0; j < l; j++)
00095           {
00096             rho_1 = DotProd(r[j], r0);
00097             if (rho_0 == zero)
00098               {
00099                 iter.Fail(1, "Bicgstabl breakdown #1");
00100                 break;
00101               }
00102             beta = alpha*(rho_1/rho_0);
00103             rho_0 = rho_1;
00104             for (int i = 0; i <= j; i++)
00105               {
00106                 Mlt(-beta, u[i]); Add(unity, r[i], u[i]);
00107               }
00108             M.Solve(A, u[j], q); // preconditioning
00109             Mlt(A, q, u[j+1]); // product Matrix Vector
00110 
00111             ++iter;
00112             sigma = DotProd(u[j+1], r0);
00113             if (sigma == zero)
00114               {
00115                 iter.Fail(2, "Bicgstabl Breakdown #2");
00116                 break;
00117               }
00118             alpha = rho_1/sigma;
00119             Add(alpha, u[0], x);
00120             for (int i = 0; i <= j; i++)
00121               Add(-alpha, u[i+1], r[i]);
00122 
00123             M.Solve(A, r[j], q); // preconditioning
00124             Mlt(A, q, r[j+1]); // product matrix vector
00125 
00126             ++iter;
00127           }
00128 
00129         // MR Part  modified Gram-Schmidt
00130         for (int j = 1; j <= l; j++)
00131           {
00132             for (int i = 1; i < j; i++)
00133               {
00134                 if (gamma(i) != zero)
00135                   {
00136                     tau(i,j) = DotProd(r[j], r[i])/gamma(i);
00137                     Add(-tau(i,j), r[i], r[j]);
00138                   }
00139               }
00140             gamma(j) = DotProd(r[j], r[j]);
00141             if (gamma(j) != zero)
00142               gamma_prime(j) = DotProd(r[0], r[j])/gamma(j);
00143           }
00144 
00145         // gamma = tau-1 * gamma_prime
00146         gamma(l) = gamma_prime(l); omega = gamma(l);
00147         for (int j = l-1; j >= 1; j--)
00148           {
00149             sigma = zero;
00150             for (int i = j+1; i <= l; i++)
00151               sigma += tau(j,i)*gamma(i);
00152 
00153             gamma(j) = gamma_prime(j)-sigma;
00154           }
00155 
00156         // gamma_twice=T*S*gamma
00157         for (int j = 1; j <= l-1; j++)
00158           {
00159             sigma = zero;
00160             for (int i = j+1; i <= l-1; i++)
00161               sigma += tau(j,i)*gamma(i+1);
00162 
00163             gamma_twice(j) = gamma(j+1)+sigma;
00164           }
00165 
00166         // update
00167         Add(gamma(1), r[0], x);
00168         Add(-gamma_prime(l), r[l], r[0]);
00169         Add(-gamma(l), u[l], u[0]);
00170         for (int j = 1;j <= l-1; j++)
00171           {
00172             Add(-gamma(j), u[j], u[0]);
00173             Add(gamma_twice(j), r[j], x);
00174             Add(-gamma_prime(j), r[j], r[0]);
00175           }
00176       }
00177     // change of coordinates (right preconditioning)
00178     Copy(x,q); M.Solve(A, q, x);
00179     return iter.ErrorCode();
00180   }
00181 
00182 }
00183 
00184 #define SELDON_FILE_ITERATIVE_BICGSTABL_CXX
00185 #endif