// Copyright (C) 2003-2009 Marc Duruflé
//
// 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_CXX

#include <vector>

// headers of class Iteration and Preconditioner_Base
#include "Iterative.hxx"

// and all iterative solvers
#include "Cg.cxx"
#include "Cgne.cxx"
#include "Lsqr.cxx"
#include "Cgs.cxx"
#include "BiCg.cxx"
#include "BiCgStab.cxx"
#include "BiCgStabl.cxx"
#include "BiCgcr.cxx"
#include "Gcr.cxx"
#include "CoCg.cxx"
#include "Gmres.cxx"
#include "MinRes.cxx"
#include "Qmr.cxx"
#include "QmrSym.cxx"
#include "QCgs.cxx"
#include "TfQmr.cxx"
#include "Symmlq.cxx"


namespace Seldon
{
  
  //! Default constructor
  Preconditioner_Base::Preconditioner_Base()
  {
  }
  
  
  //! Solves M z = r
  /*!
    Identity preconditioner M = I
  */
  template<class Matrix1, class Vector1>
  void Preconditioner_Base::Solve(const Matrix1& A, const Vector1& r,
				  Vector1& z)
  {
    Copy(r,z);
  }
  
  
  //! Solves M^t z = r
  /*!
    Identity preconditioner M = I
  */
  template<class Matrix1, class Vector1>
  void Preconditioner_Base::
  TransSolve(const Matrix1& A, const Vector1 & r, Vector1 & z)
  {
    Solve(A, r, z);
  }
  
  
  //! Default constructor
  template<class Titer>
  Iteration<Titer>::Iteration()
  {
    tolerance = 1e-6;
    max_iter = 100;
    nb_iter = 0;
    error_code = 0;
    fail_convergence = false;
    print_level = 1;
    init_guess_null = true;
    type_solver = 0; parameter_restart = 10;
    type_preconditioning = 0;
  }
  
  
  //! Constructor with maximum number of iterations and stopping criterion
  template<class Titer>
  Iteration<Titer>::Iteration(int max_iteration, const Titer& tol)
  {
    max_iter = max_iteration;
    tolerance = tol;
    nb_iter = 0;
    error_code = 0;
    fail_convergence = false;
    print_level = 1;
    init_guess_null = true;
    type_solver = 0; parameter_restart = 10;
    type_preconditioning = 0;
  }
  

  //! Copy constructor
  template<class Titer>
  Iteration<Titer>::Iteration(const Iteration<Titer>& outer)
  {
    tolerance = outer.tolerance; facteur_reste = outer.facteur_reste;
    max_iter = outer.max_iter;
    nb_iter = 0;
    print_level = outer.print_level; error_code = outer.error_code;
    init_guess_null = true;
    type_solver = outer.type_solver;
    parameter_restart = outer.parameter_restart;
    type_preconditioning = outer.type_preconditioning;
  }
  
  
  //! Returns the type of solver
  template<class Titer>
  int Iteration<Titer>::GetTypeSolver() const
  {
    return type_solver;
  }
  
  
  //! Returns the restart parameter
  template<class Titer>
  int Iteration<Titer>::GetRestart() const
  {
    return parameter_restart;
  }
  
  
  //! Returns used coefficient to compute relative residual
  template<class Titer>
  Titer Iteration<Titer>::GetFactor() const
  {
    return facteur_reste;
  }
  
  
  //! Returns stopping criterion
  template<class Titer>
  Titer Iteration<Titer>::GetTolerance() const
  {
    return tolerance;
  }
  
  
  //! Returns the number of iterations
  template<class Titer>
  int Iteration<Titer>::GetNumberIteration() const
  {
    return nb_iter;
  }
  
  
  //! Changes the type of solver and preconditioning
  template<class Titer>
  void Iteration<Titer>::SetSolver(int type_resolution,
				   int param_restart, int type_prec)
  {
    type_solver = type_resolution;
    parameter_restart = param_restart;
    type_preconditioning = type_prec;
  }
  
  
  //! Changes the restart parameter
  template<class Titer>
  void Iteration<Titer>::SetRestart(int m)
  {
    parameter_restart = m;
  }
  
  
  //! Changes the stopping criterion
  template<class Titer>
  void Iteration<Titer>::SetTolerance(Titer stopping_criterion)
  {
    tolerance = stopping_criterion;
  }
  
  
  //! Changes the maximum number of iterations
  template<class Titer>
  void Iteration<Titer>::SetMaxNumberIteration(int max_iteration)
  {
    max_iter=max_iteration;
  }

  
  //! Changes the number of iterations
  template<class Titer>
  void Iteration<Titer>::SetNumberIteration(int nb)
  {
    nb_iter = nb;
  }
  
  
  //! Sets to a normal display (residual each 100 iterations)
  template<class Titer>
  void Iteration<Titer>::ShowMessages()
  {
    print_level = 1;
  }
  
  
  //! Sets to a complete display (residual each iteration)
  template<class Titer>
  void Iteration<Titer>::ShowFullHistory()
  {
    print_level = 6;
  }
  
  
  //! Doesn't display any information
  template<class Titer>
  void Iteration<Titer>::HideMessages()
  {
    print_level = 0;
  }
  
  
  //! Initialization with the right hand side
  template<class Titer> template<class Vector1>
  int Iteration<Titer>::Init(const Vector1& r)
  {
    Titer norme_rhs = Titer(Norm2(r));
    // test of a null right hand side
    if (norme_rhs == Titer(0))
      return -1;
    
    // coefficient used later to compute relative residual
    facteur_reste = Titer(1)/norme_rhs;
    
    // initialization of iterations
    nb_iter = 0;
    return 0; // successful initialization
  }
  
  
  //! Returns true if it is the first iteration
  template<class Titer>
  inline bool Iteration<Titer>::First() const
  {
    if (nb_iter == 0)
      return true;
    
    return false;
  }
  
  
  //! Returns true if the initial guess is null
  template<class Titer>
  inline bool Iteration<Titer>::IsInitGuess_Null() const
  {
    return init_guess_null;
  }
  
  
  //! Returns true if the iterative solver has reached its end
  template<class Titer> template<class Vector1>
  inline bool Iteration<Titer>::
  Finished(const Vector1& r) const
  {
    // absolute residual
    Titer reste = Norm2(r);
    // computation of relative residual
    reste = facteur_reste*reste;
    
    // displaying residual if required
    if ((print_level >= 1)&&(nb_iter%100 == 0))
      cout<<"Residu at iteration number "<<
	GetNumberIteration()<<"  "<<reste<<endl;
    else if (print_level >= 6)
      cout<<"Residu at iteration number "<<
	GetNumberIteration()<<"  "<<reste<<endl;
    
    // end of iterative solver when residual is small enough
    // or when the number of iterations is too high
    if ((reste < tolerance)||(nb_iter >= max_iter))
      return true;
    
    return false;
  }
  
  
  //! Returns true if the iterative solver has reached its end
  template<class Titer>
  inline bool Iteration<Titer>::Finished(const Titer& r) const
  {
    // relative residual
    Titer reste = facteur_reste*r;
    
    // displaying residual if required
    if ((print_level >= 1)&&(nb_iter%100 == 0))
      cout<<"Residu at iteration number "<<
	GetNumberIteration()<<"  "<<reste<<endl;
    else if (print_level >= 6)
      cout<<"Residu at iteration number "<<
	GetNumberIteration()<<"  "<<reste<<endl;
    
    // end of iterative solver when residual is small enough
    // or when the number of iterations is too high
    if ((reste < tolerance)||(nb_iter >= max_iter))
      return true;
    
    return false;
  }
  
  
  //! Informs of a failure in the iterative solver
  template<class Titer>
  void Iteration<Titer>::Fail(int i, const string& s)
  {
    fail_convergence = true;
    error_code = i;
    // displays information if required
    if ((print_level >= 1)&&(nb_iter%100==0))
      cout<<"Error during resolution : "<<s<<endl;
  }
  
  
  //! Increment the number of iterations
  template<class Titer>
  inline Iteration<Titer>& Iteration<Titer>::operator ++ (void)
  {
    ++nb_iter;
    return *this;
  }
  
  
  //! Returns the error code (if an error occured)
  template<class Titer>
  int Iteration<Titer>::ErrorCode() const
  {
    if (nb_iter >= max_iter)
      return -2;
    
    if (fail_convergence)
      return error_code;
    
    return 0;
  }
  
} // end namespace

#define SELDON_FILE_ITERATIVE_CXX
#endif