// Copyright (C) 2003-2009 Marc Duruflé
// Copyright (C) 2001-2009 Vivien Mallet
//
// This file is part of the linear-algebra library Seldon,
// http://seldon.sourceforge.net/.
//
// Seldon is free software; you can redistribute it and/or modify it under the
// terms of the GNU Lesser General Public License as published by the Free
// Software Foundation; either version 2.1 of the License, or (at your option)
// any later version.
//
// Seldon is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
// more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with Seldon. If not, see http://www.gnu.org/licenses/.
#ifndef SELDON_FILE_ITERATIVE_TFQMR_CXX
namespace Seldon
{
//! Solves a linear system by using Transpose Free Quasi-Minimal Residual
/*!
Solves the unsymmetric linear system Ax = b using TFQMR.
return value of 0 indicates convergence within the
maximum number of iterations (determined by the iter object).
return value of 1 indicates a failure to converge.
See: R. W. Freund, A Transpose-Free Quasi-Minimal Residual algorithm for
non-Hermitian linear system. SIAM J. on Sci. Comp. 14(1993), pp. 470-482
\param[in] A Complex General Matrix
\param[in,out] x Vector on input it is the initial guess
on output it is the solution
\param[in] b Vector right hand side of the linear system
\param[in] M Right preconditioner
\param[in] iter Iteration parameters
*/
template <class Titer, class Matrix1, class Vector1, class Preconditioner>
int TfQmr(Matrix1& A, Vector1& x, const Vector1& b,
Preconditioner& M, Iteration<Titer> & iter)
{
const int N = A.GetM();
if (N <= 0)
return 0;
Vector1 tmp(b), r0(b), v(b), h(b), w(b),
y1(b), g(b), y0(b), rtilde(b), d(b);
typedef typename Vector1::value_type Complexe;
Complexe sigma, alpha, beta, eta, rho, rho0;
Titer c, kappa, tau, theta;
tmp.Zero();
// x is initial value
// 1. r0 = M^{-1} (b - A x)
Copy(b, tmp);
if (!iter.IsInitGuess_Null())
MltAdd(Complexe(-1), A, x, Complexe(1), tmp);
else
x.Zero();
M.Solve(A, tmp, r0);
// we initialize iter
int success_init = iter.Init(r0);
if (success_init != 0)
return iter.ErrorCode();
// 2. w=y=r
Copy(r0, w);
Copy(r0, y1);
// 3. g=v=M^{-1}Ay
Copy(y1, v);
Mlt(A, v, tmp);
M.Solve(A, tmp, v);
++iter;
Copy(v, g);
// 4. d=0
d.Zero();
// 5. tau = ||r||
tau = Norm2(r0);
// 6. theta = eta = 0
theta = 0.0;
eta = 0.0;
// 7. rtilde = r
Copy(r0, rtilde);
// 8. rho=dot(rtilde, r)
rho = DotProd(rtilde, r0);
rho0 = rho;
iter.SetNumberIteration(0);
// Loop until the stopping criteria are reached
for (;;)
{
// 9. 10. 11.
// sigma=dot(rtilde,v)
// alpha=rho/sigma
// y2k=y(2k-1)-alpha*v
sigma = DotProd(rtilde, v);
if (sigma == Complexe(0))
{
iter.Fail(1, "Tfqmr breakdown: sigma=0");
break;
}
alpha = rho / sigma;
//y0 = y1 - alpha * v;
Copy(y1, y0);
Add(-alpha, v, y0);
// 12. h=M^{-1}*A*y
Copy(y0, h);
Mlt(A, h, tmp);
M.Solve(A, tmp, h);
//split the loop of "for m = 2k-1, 2k"
//The first one
// 13. w = w-alpha*M^{-1} A y0
//w = w - alpha * g;
Add(-alpha, g, w);
// 18. d=y0+((theta0^2)*eta0/alpha)*d //need check breakdown
if (alpha == Complexe(0))
{
iter.Fail(2, "Tfqmr breakdown: alpha=0");
break;
}
//d = y1 + ( theta * theta * eta / alpha ) * d;
Mlt(theta * theta * eta / alpha,d);
Add(Complexe(1), y1, d);
// 14. theta=||w||_2/tau0 //need check breakdown
if (tau == Titer(0))
{
iter.Fail(3, "Tfqmr breakdown: tau=0");
break;
}
theta = Norm2(w) / tau;
// 15. c = 1/sqrt(1+theta^2)
c = Titer(1) / sqrt(Titer(1) + theta * theta);
// 16. tau = tau0*theta*c
tau = tau * c * theta;
// 17. eta = (c^2)*alpha
eta = c * c * alpha;
// 19. x = x+eta*d
Add(eta, d, x);
// 20. kappa = tau*sqrt(m+1)
kappa = tau * sqrt( 2.* (iter.GetNumberIteration()+1) );
// 21. check stopping criterion
if ( iter.Finished(kappa) )
{
break;
}
++iter;
// g = h;
Copy(h, g);
//The second one
// 13. w = w-alpha*M^{-1} A y0
// w = w - alpha * g;
Add(-alpha,g,w);
// 18. d = y0+((theta0^2)*eta0/alpha)*d
Mlt(theta * theta * eta / alpha,d);
Add(Complexe(1), y0, d);
// 14. theta=||w||_2/tau0
if (tau == Titer(0))
{
iter.Fail(4, "Tfqmr breakdown: tau=0");
break;
}
theta = Norm2(w) / tau;
// 15. c = 1/sqrt(1+theta^2)
c = Titer(1) / sqrt(Titer(1) + theta * theta);
// 16. tau = tau0*theta*c
tau = tau * c * theta;
// 17. eta = (c^2)*alpha
eta = c * c * alpha;
// 19. x = x+eta*d
Add(eta, d, x);
// 20. kappa = tau*sqrt(m+1)
kappa = tau * sqrt(2.* (iter.GetNumberIteration()+1) + 1.);
// 21. check stopping criterion
if ( iter.Finished(kappa) )
{
break;
}
// 22. rho = dot(rtilde,w)
// 23. beta = rho/rho0 //need check breakdown
rho0 = rho;
rho = DotProd(rtilde, w);
if (rho0 == Complexe(0))
{
iter.Fail(5, "tfqmr breakdown: beta=0");
break;
}
beta = rho/rho0;
// 24. y = w+beta*y0
Copy(w, y1);
Add(beta, y0, y1);
// 25. g=M^{-1} A y
Copy(y1, g);
Mlt(A, g, tmp);
M.Solve(A, tmp, g);
// 26. v = M^{-1}A y + beta*( M^{-1} A y0 + beta*v)
Mlt(beta*beta, v);
Add(beta, h, v);
Add(Complexe(1), g, v);
++iter;
}
return iter.ErrorCode();
}
} // end namespace
#define SELDON_FILE_ITERATIVE_TFQMR_CXX
#endif