17faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez// This file is part of Eigen, a lightweight C++ template library
27faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez// for linear algebra.
37faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez//
47faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez// Copyright (C) 2012 Désiré Nuentsa-Wakam <desire.nuentsa_wakam@inria.fr>
57faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez//
67faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez// This Source Code Form is subject to the terms of the Mozilla
77faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez// Public License v. 2.0. If a copy of the MPL was not distributed
87faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
97faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez
107faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez#ifndef EIGEN_DGMRES_H
117faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez#define EIGEN_DGMRES_H
127faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez
137faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez#include <Eigen/Eigenvalues>
147faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez
157faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandeznamespace Eigen {
167faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez
177faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandeztemplate< typename _MatrixType,
187faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez          typename _Preconditioner = DiagonalPreconditioner<typename _MatrixType::Scalar> >
197faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandezclass DGMRES;
207faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez
217faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandeznamespace internal {
227faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez
237faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandeztemplate< typename _MatrixType, typename _Preconditioner>
247faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandezstruct traits<DGMRES<_MatrixType,_Preconditioner> >
257faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez{
267faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  typedef _MatrixType MatrixType;
277faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  typedef _Preconditioner Preconditioner;
287faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez};
297faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez
307faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez/** \brief Computes a permutation vector to have a sorted sequence
317faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  * \param vec The vector to reorder.
327faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  * \param perm gives the sorted sequence on output. Must be initialized with 0..n-1
337faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  * \param ncut Put  the ncut smallest elements at the end of the vector
347faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  * WARNING This is an expensive sort, so should be used only
357faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  * for small size vectors
367faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  * TODO Use modified QuickSplit or std::nth_element to get the smallest values
377faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  */
387faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandeztemplate <typename VectorType, typename IndexType>
397faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandezvoid sortWithPermutation (VectorType& vec, IndexType& perm, typename IndexType::Scalar& ncut)
407faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez{
417faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  eigen_assert(vec.size() == perm.size());
427faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  typedef typename IndexType::Scalar Index;
437faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  typedef typename VectorType::Scalar Scalar;
447faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  bool flag;
457faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  for (Index k  = 0; k < ncut; k++)
467faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  {
477faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    flag = false;
487faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    for (Index j = 0; j < vec.size()-1; j++)
497faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    {
507faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez      if ( vec(perm(j)) < vec(perm(j+1)) )
517faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez      {
527faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez        std::swap(perm(j),perm(j+1));
537faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez        flag = true;
547faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez      }
557faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez      if (!flag) break; // The vector is in sorted order
567faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    }
577faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  }
587faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez}
597faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez
607faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez}
617faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez/**
627faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez * \ingroup IterativeLInearSolvers_Module
637faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez * \brief A Restarted GMRES with deflation.
647faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez * This class implements a modification of the GMRES solver for
657faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez * sparse linear systems. The basis is built with modified
667faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez * Gram-Schmidt. At each restart, a few approximated eigenvectors
677faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez * corresponding to the smallest eigenvalues are used to build a
687faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez * preconditioner for the next cycle. This preconditioner
697faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez * for deflation can be combined with any other preconditioner,
707faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez * the IncompleteLUT for instance. The preconditioner is applied
717faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez * at right of the matrix and the combination is multiplicative.
727faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez *
737faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez * \tparam _MatrixType the type of the sparse matrix A, can be a dense or a sparse matrix.
747faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez * \tparam _Preconditioner the type of the preconditioner. Default is DiagonalPreconditioner
757faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez * Typical usage :
767faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez * \code
777faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez * SparseMatrix<double> A;
787faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez * VectorXd x, b;
797faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez * //Fill A and b ...
807faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez * DGMRES<SparseMatrix<double> > solver;
817faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez * solver.set_restart(30); // Set restarting value
827faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez * solver.setEigenv(1); // Set the number of eigenvalues to deflate
837faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez * solver.compute(A);
847faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez * x = solver.solve(b);
857faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez * \endcode
867faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez *
877faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez * References :
887faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez * [1] D. NUENTSA WAKAM and F. PACULL, Memory Efficient Hybrid
897faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez *  Algebraic Solvers for Linear Systems Arising from Compressible
907faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez *  Flows, Computers and Fluids, In Press,
917faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez *  http://dx.doi.org/10.1016/j.compfluid.2012.03.023
927faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez * [2] K. Burrage and J. Erhel, On the performance of various
937faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez * adaptive preconditioned GMRES strategies, 5(1998), 101-121.
947faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez * [3] J. Erhel, K. Burrage and B. Pohl, Restarted GMRES
957faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez *  preconditioned by deflation,J. Computational and Applied
967faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez *  Mathematics, 69(1996), 303-318.
977faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez
987faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez *
997faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez */
1007faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandeztemplate< typename _MatrixType, typename _Preconditioner>
1017faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandezclass DGMRES : public IterativeSolverBase<DGMRES<_MatrixType,_Preconditioner> >
1027faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez{
1037faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    typedef IterativeSolverBase<DGMRES> Base;
1047faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    using Base::mp_matrix;
1057faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    using Base::m_error;
1067faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    using Base::m_iterations;
1077faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    using Base::m_info;
1087faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    using Base::m_isInitialized;
1097faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    using Base::m_tolerance;
1107faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  public:
1117faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    typedef _MatrixType MatrixType;
1127faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    typedef typename MatrixType::Scalar Scalar;
1137faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    typedef typename MatrixType::Index Index;
1147faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    typedef typename MatrixType::RealScalar RealScalar;
1157faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    typedef _Preconditioner Preconditioner;
1167faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    typedef Matrix<Scalar,Dynamic,Dynamic> DenseMatrix;
1177faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    typedef Matrix<RealScalar,Dynamic,Dynamic> DenseRealMatrix;
1187faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    typedef Matrix<Scalar,Dynamic,1> DenseVector;
1197faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    typedef Matrix<RealScalar,Dynamic,1> DenseRealVector;
1207faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    typedef Matrix<std::complex<RealScalar>, Dynamic, 1> ComplexVector;
1217faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez
1227faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez
1237faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  /** Default constructor. */
1247faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  DGMRES() : Base(),m_restart(30),m_neig(0),m_r(0),m_maxNeig(5),m_isDeflAllocated(false),m_isDeflInitialized(false) {}
1257faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez
1267faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  /** Initialize the solver with matrix \a A for further \c Ax=b solving.
1277faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    *
1287faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    * This constructor is a shortcut for the default constructor followed
1297faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    * by a call to compute().
1307faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    *
1317faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    * \warning this class stores a reference to the matrix A as well as some
1327faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    * precomputed values that depend on it. Therefore, if \a A is changed
1337faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    * this class becomes invalid. Call compute() to update it with the new
1347faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    * matrix A, or modify a copy of A.
1357faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    */
1367faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  DGMRES(const MatrixType& A) : Base(A),m_restart(30),m_neig(0),m_r(0),m_maxNeig(5),m_isDeflAllocated(false),m_isDeflInitialized(false)
1377faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  {}
1387faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez
1397faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  ~DGMRES() {}
1407faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez
1417faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  /** \returns the solution x of \f$ A x = b \f$ using the current decomposition of A
1427faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    * \a x0 as an initial solution.
1437faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    *
1447faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    * \sa compute()
1457faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    */
1467faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  template<typename Rhs,typename Guess>
1477faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  inline const internal::solve_retval_with_guess<DGMRES, Rhs, Guess>
1487faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  solveWithGuess(const MatrixBase<Rhs>& b, const Guess& x0) const
1497faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  {
1507faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    eigen_assert(m_isInitialized && "DGMRES is not initialized.");
1517faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    eigen_assert(Base::rows()==b.rows()
1527faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez              && "DGMRES::solve(): invalid number of rows of the right hand side matrix b");
1537faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    return internal::solve_retval_with_guess
1547faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez            <DGMRES, Rhs, Guess>(*this, b.derived(), x0);
1557faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  }
1567faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez
1577faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  /** \internal */
1587faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  template<typename Rhs,typename Dest>
1597faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  void _solveWithGuess(const Rhs& b, Dest& x) const
1607faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  {
1617faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    bool failed = false;
1627faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    for(int j=0; j<b.cols(); ++j)
1637faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    {
1647faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez      m_iterations = Base::maxIterations();
1657faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez      m_error = Base::m_tolerance;
1667faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez
1677faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez      typename Dest::ColXpr xj(x,j);
1687faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez      dgmres(*mp_matrix, b.col(j), xj, Base::m_preconditioner);
1697faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    }
1707faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    m_info = failed ? NumericalIssue
1717faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez           : m_error <= Base::m_tolerance ? Success
1727faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez           : NoConvergence;
1737faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    m_isInitialized = true;
1747faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  }
1757faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez
1767faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  /** \internal */
1777faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  template<typename Rhs,typename Dest>
1787faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  void _solve(const Rhs& b, Dest& x) const
1797faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  {
1807faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    x = b;
1817faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    _solveWithGuess(b,x);
1827faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  }
1837faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  /**
1847faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez   * Get the restart value
1857faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    */
1867faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  int restart() { return m_restart; }
1877faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez
1887faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  /**
1897faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez   * Set the restart value (default is 30)
1907faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez   */
1917faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  void set_restart(const int restart) { m_restart=restart; }
1927faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez
1937faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  /**
1947faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez   * Set the number of eigenvalues to deflate at each restart
1957faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez   */
1967faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  void setEigenv(const int neig)
1977faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  {
1987faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    m_neig = neig;
1997faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    if (neig+1 > m_maxNeig) m_maxNeig = neig+1; // To allow for complex conjugates
2007faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  }
2017faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez
2027faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  /**
2037faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez   * Get the size of the deflation subspace size
2047faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez   */
2057faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  int deflSize() {return m_r; }
2067faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez
2077faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  /**
2087faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez   * Set the maximum size of the deflation subspace
2097faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez   */
2107faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  void setMaxEigenv(const int maxNeig) { m_maxNeig = maxNeig; }
2117faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez
2127faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  protected:
2137faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    // DGMRES algorithm
2147faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    template<typename Rhs, typename Dest>
2157faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    void dgmres(const MatrixType& mat,const Rhs& rhs, Dest& x, const Preconditioner& precond) const;
2167faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    // Perform one cycle of GMRES
2177faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    template<typename Dest>
2187faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    int dgmresCycle(const MatrixType& mat, const Preconditioner& precond, Dest& x, DenseVector& r0, RealScalar& beta, const RealScalar& normRhs, int& nbIts) const;
2197faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    // Compute data to use for deflation
2207faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    int dgmresComputeDeflationData(const MatrixType& mat, const Preconditioner& precond, const Index& it, Index& neig) const;
2217faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    // Apply deflation to a vector
2227faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    template<typename RhsType, typename DestType>
2237faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    int dgmresApplyDeflation(const RhsType& In, DestType& Out) const;
2247faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    ComplexVector schurValues(const ComplexSchur<DenseMatrix>& schurofH) const;
2257faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    ComplexVector schurValues(const RealSchur<DenseMatrix>& schurofH) const;
2267faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    // Init data for deflation
2277faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    void dgmresInitDeflation(Index& rows) const;
2287faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    mutable DenseMatrix m_V; // Krylov basis vectors
2297faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    mutable DenseMatrix m_H; // Hessenberg matrix
2307faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    mutable DenseMatrix m_Hes; // Initial hessenberg matrix wihout Givens rotations applied
2317faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    mutable Index m_restart; // Maximum size of the Krylov subspace
2327faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    mutable DenseMatrix m_U; // Vectors that form the basis of the invariant subspace
2337faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    mutable DenseMatrix m_MU; // matrix operator applied to m_U (for next cycles)
2347faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    mutable DenseMatrix m_T; /* T=U^T*M^{-1}*A*U */
2357faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    mutable PartialPivLU<DenseMatrix> m_luT; // LU factorization of m_T
2367faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    mutable int m_neig; //Number of eigenvalues to extract at each restart
2377faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    mutable int m_r; // Current number of deflated eigenvalues, size of m_U
2387faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    mutable int m_maxNeig; // Maximum number of eigenvalues to deflate
2397faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    mutable RealScalar m_lambdaN; //Modulus of the largest eigenvalue of A
2407faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    mutable bool m_isDeflAllocated;
2417faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    mutable bool m_isDeflInitialized;
2427faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez
2437faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    //Adaptive strategy
2447faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    mutable RealScalar m_smv; // Smaller multiple of the remaining number of steps allowed
2457faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    mutable bool m_force; // Force the use of deflation at each restart
2467faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez
2477faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez};
2487faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez/**
2497faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez * \brief Perform several cycles of restarted GMRES with modified Gram Schmidt,
2507faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez *
2517faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez * A right preconditioner is used combined with deflation.
2527faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez *
2537faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez */
2547faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandeztemplate< typename _MatrixType, typename _Preconditioner>
2557faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandeztemplate<typename Rhs, typename Dest>
2567faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandezvoid DGMRES<_MatrixType, _Preconditioner>::dgmres(const MatrixType& mat,const Rhs& rhs, Dest& x,
2577faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez              const Preconditioner& precond) const
2587faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez{
2597faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  //Initialization
2607faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  int n = mat.rows();
2617faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  DenseVector r0(n);
2627faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  int nbIts = 0;
2637faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  m_H.resize(m_restart+1, m_restart);
2647faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  m_Hes.resize(m_restart, m_restart);
2657faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  m_V.resize(n,m_restart+1);
2667faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  //Initial residual vector and intial norm
2677faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  x = precond.solve(x);
2687faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  r0 = rhs - mat * x;
2697faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  RealScalar beta = r0.norm();
2707faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  RealScalar normRhs = rhs.norm();
2717faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  m_error = beta/normRhs;
2727faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  if(m_error < m_tolerance)
2737faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    m_info = Success;
2747faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  else
2757faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    m_info = NoConvergence;
2767faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez
2777faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  // Iterative process
2787faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  while (nbIts < m_iterations && m_info == NoConvergence)
2797faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  {
2807faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    dgmresCycle(mat, precond, x, r0, beta, normRhs, nbIts);
2817faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez
2827faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    // Compute the new residual vector for the restart
2837faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    if (nbIts < m_iterations && m_info == NoConvergence)
2847faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez      r0 = rhs - mat * x;
2857faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  }
2867faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez}
2877faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez
2887faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez/**
2897faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez * \brief Perform one restart cycle of DGMRES
2907faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez * \param mat The coefficient matrix
2917faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez * \param precond The preconditioner
2927faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez * \param x the new approximated solution
2937faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez * \param r0 The initial residual vector
2947faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez * \param beta The norm of the residual computed so far
2957faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez * \param normRhs The norm of the right hand side vector
2967faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez * \param nbIts The number of iterations
2977faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez */
2987faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandeztemplate< typename _MatrixType, typename _Preconditioner>
2997faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandeztemplate<typename Dest>
3007faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandezint DGMRES<_MatrixType, _Preconditioner>::dgmresCycle(const MatrixType& mat, const Preconditioner& precond, Dest& x, DenseVector& r0, RealScalar& beta, const RealScalar& normRhs, int& nbIts) const
3017faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez{
3027faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  //Initialization
3037faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  DenseVector g(m_restart+1); // Right hand side of the least square problem
3047faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  g.setZero();
3057faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  g(0) = Scalar(beta);
3067faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  m_V.col(0) = r0/beta;
3077faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  m_info = NoConvergence;
3087faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  std::vector<JacobiRotation<Scalar> >gr(m_restart); // Givens rotations
3097faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  int it = 0; // Number of inner iterations
3107faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  int n = mat.rows();
3117faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  DenseVector tv1(n), tv2(n);  //Temporary vectors
3127faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  while (m_info == NoConvergence && it < m_restart && nbIts < m_iterations)
3137faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  {
3147faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    // Apply preconditioner(s) at right
3157faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    if (m_isDeflInitialized )
3167faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    {
3177faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez      dgmresApplyDeflation(m_V.col(it), tv1); // Deflation
3187faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez      tv2 = precond.solve(tv1);
3197faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    }
3207faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    else
3217faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    {
3227faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez      tv2 = precond.solve(m_V.col(it)); // User's selected preconditioner
3237faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    }
3247faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    tv1 = mat * tv2;
3257faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez
3267faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    // Orthogonalize it with the previous basis in the basis using modified Gram-Schmidt
3277faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    Scalar coef;
3287faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    for (int i = 0; i <= it; ++i)
3297faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    {
3307faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez      coef = tv1.dot(m_V.col(i));
3317faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez      tv1 = tv1 - coef * m_V.col(i);
3327faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez      m_H(i,it) = coef;
3337faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez      m_Hes(i,it) = coef;
3347faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    }
3357faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    // Normalize the vector
3367faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    coef = tv1.norm();
3377faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    m_V.col(it+1) = tv1/coef;
3387faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    m_H(it+1, it) = coef;
3397faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez//     m_Hes(it+1,it) = coef;
3407faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez
3417faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    // FIXME Check for happy breakdown
3427faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez
3437faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    // Update Hessenberg matrix with Givens rotations
3447faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    for (int i = 1; i <= it; ++i)
3457faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    {
3467faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez      m_H.col(it).applyOnTheLeft(i-1,i,gr[i-1].adjoint());
3477faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    }
3487faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    // Compute the new plane rotation
3497faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    gr[it].makeGivens(m_H(it, it), m_H(it+1,it));
3507faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    // Apply the new rotation
3517faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    m_H.col(it).applyOnTheLeft(it,it+1,gr[it].adjoint());
3527faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    g.applyOnTheLeft(it,it+1, gr[it].adjoint());
3537faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez
3547faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    beta = std::abs(g(it+1));
3557faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    m_error = beta/normRhs;
3567faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    std::cerr << nbIts << " Relative Residual Norm " << m_error << std::endl;
3577faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    it++; nbIts++;
3587faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez
3597faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    if (m_error < m_tolerance)
3607faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    {
3617faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez      // The method has converged
3627faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez      m_info = Success;
3637faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez      break;
3647faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    }
3657faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  }
3667faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez
3677faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  // Compute the new coefficients by solving the least square problem
3687faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez//   it++;
3697faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  //FIXME  Check first if the matrix is singular ... zero diagonal
3707faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  DenseVector nrs(m_restart);
3717faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  nrs = m_H.topLeftCorner(it,it).template triangularView<Upper>().solve(g.head(it));
3727faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez
3737faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  // Form the new solution
3747faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  if (m_isDeflInitialized)
3757faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  {
3767faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    tv1 = m_V.leftCols(it) * nrs;
3777faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    dgmresApplyDeflation(tv1, tv2);
3787faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    x = x + precond.solve(tv2);
3797faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  }
3807faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  else
3817faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    x = x + precond.solve(m_V.leftCols(it) * nrs);
3827faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez
3837faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  // Go for a new cycle and compute data for deflation
3847faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  if(nbIts < m_iterations && m_info == NoConvergence && m_neig > 0 && (m_r+m_neig) < m_maxNeig)
3857faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    dgmresComputeDeflationData(mat, precond, it, m_neig);
3867faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  return 0;
3877faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez
3887faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez}
3897faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez
3907faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez
3917faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandeztemplate< typename _MatrixType, typename _Preconditioner>
3927faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandezvoid DGMRES<_MatrixType, _Preconditioner>::dgmresInitDeflation(Index& rows) const
3937faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez{
3947faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  m_U.resize(rows, m_maxNeig);
3957faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  m_MU.resize(rows, m_maxNeig);
3967faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  m_T.resize(m_maxNeig, m_maxNeig);
3977faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  m_lambdaN = 0.0;
3987faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  m_isDeflAllocated = true;
3997faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez}
4007faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez
4017faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandeztemplate< typename _MatrixType, typename _Preconditioner>
4027faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandezinline typename DGMRES<_MatrixType, _Preconditioner>::ComplexVector DGMRES<_MatrixType, _Preconditioner>::schurValues(const ComplexSchur<DenseMatrix>& schurofH) const
4037faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez{
4047faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  return schurofH.matrixT().diagonal();
4057faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez}
4067faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez
4077faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandeztemplate< typename _MatrixType, typename _Preconditioner>
4087faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandezinline typename DGMRES<_MatrixType, _Preconditioner>::ComplexVector DGMRES<_MatrixType, _Preconditioner>::schurValues(const RealSchur<DenseMatrix>& schurofH) const
4097faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez{
4107faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  typedef typename MatrixType::Index Index;
4117faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  const DenseMatrix& T = schurofH.matrixT();
4127faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  Index it = T.rows();
4137faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  ComplexVector eig(it);
4147faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  Index j = 0;
4157faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  while (j < it-1)
4167faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  {
4177faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    if (T(j+1,j) ==Scalar(0))
4187faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    {
4197faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez      eig(j) = std::complex<RealScalar>(T(j,j),RealScalar(0));
4207faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez      j++;
4217faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    }
4227faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    else
4237faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    {
4247faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez      eig(j) = std::complex<RealScalar>(T(j,j),T(j+1,j));
4257faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez      eig(j+1) = std::complex<RealScalar>(T(j,j+1),T(j+1,j+1));
4267faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez      j++;
4277faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    }
4287faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  }
4297faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  if (j < it-1) eig(j) = std::complex<RealScalar>(T(j,j),RealScalar(0));
4307faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  return eig;
4317faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez}
4327faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez
4337faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandeztemplate< typename _MatrixType, typename _Preconditioner>
4347faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandezint DGMRES<_MatrixType, _Preconditioner>::dgmresComputeDeflationData(const MatrixType& mat, const Preconditioner& precond, const Index& it, Index& neig) const
4357faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez{
4367faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  // First, find the Schur form of the Hessenberg matrix H
4377faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  typename internal::conditional<NumTraits<Scalar>::IsComplex, ComplexSchur<DenseMatrix>, RealSchur<DenseMatrix> >::type schurofH;
4387faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  bool computeU = true;
4397faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  DenseMatrix matrixQ(it,it);
4407faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  matrixQ.setIdentity();
4417faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  schurofH.computeFromHessenberg(m_Hes.topLeftCorner(it,it), matrixQ, computeU);
4427faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez
4437faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  ComplexVector eig(it);
4447faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  Matrix<Index,Dynamic,1>perm(it);
4457faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  eig = this->schurValues(schurofH);
4467faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez
4477faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  // Reorder the absolute values of Schur values
4487faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  DenseRealVector modulEig(it);
4497faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  for (int j=0; j<it; ++j) modulEig(j) = std::abs(eig(j));
4507faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  perm.setLinSpaced(it,0,it-1);
4517faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  internal::sortWithPermutation(modulEig, perm, neig);
4527faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez
4537faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  if (!m_lambdaN)
4547faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  {
4557faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    m_lambdaN = (std::max)(modulEig.maxCoeff(), m_lambdaN);
4567faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  }
4577faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  //Count the real number of extracted eigenvalues (with complex conjugates)
4587faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  int nbrEig = 0;
4597faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  while (nbrEig < neig)
4607faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  {
4617faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    if(eig(perm(it-nbrEig-1)).imag() == RealScalar(0)) nbrEig++;
4627faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    else nbrEig += 2;
4637faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  }
4647faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  // Extract the  Schur vectors corresponding to the smallest Ritz values
4657faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  DenseMatrix Sr(it, nbrEig);
4667faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  Sr.setZero();
4677faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  for (int j = 0; j < nbrEig; j++)
4687faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  {
4697faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    Sr.col(j) = schurofH.matrixU().col(perm(it-j-1));
4707faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  }
4717faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez
4727faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  // Form the Schur vectors of the initial matrix using the Krylov basis
4737faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  DenseMatrix X;
4747faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  X = m_V.leftCols(it) * Sr;
4757faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  if (m_r)
4767faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  {
4777faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez   // Orthogonalize X against m_U using modified Gram-Schmidt
4787faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez   for (int j = 0; j < nbrEig; j++)
4797faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez     for (int k =0; k < m_r; k++)
4807faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez      X.col(j) = X.col(j) - (m_U.col(k).dot(X.col(j)))*m_U.col(k);
4817faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  }
4827faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez
4837faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  // Compute m_MX = A * M^-1 * X
4847faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  Index m = m_V.rows();
4857faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  if (!m_isDeflAllocated)
4867faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    dgmresInitDeflation(m);
4877faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  DenseMatrix MX(m, nbrEig);
4887faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  DenseVector tv1(m);
4897faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  for (int j = 0; j < nbrEig; j++)
4907faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  {
4917faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    tv1 = mat * X.col(j);
4927faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    MX.col(j) = precond.solve(tv1);
4937faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  }
4947faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez
4957faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  //Update m_T = [U'MU U'MX; X'MU X'MX]
4967faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  m_T.block(m_r, m_r, nbrEig, nbrEig) = X.transpose() * MX;
4977faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  if(m_r)
4987faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  {
4997faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    m_T.block(0, m_r, m_r, nbrEig) = m_U.leftCols(m_r).transpose() * MX;
5007faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    m_T.block(m_r, 0, nbrEig, m_r) = X.transpose() * m_MU.leftCols(m_r);
5017faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  }
5027faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez
5037faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  // Save X into m_U and m_MX in m_MU
5047faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  for (int j = 0; j < nbrEig; j++) m_U.col(m_r+j) = X.col(j);
5057faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  for (int j = 0; j < nbrEig; j++) m_MU.col(m_r+j) = MX.col(j);
5067faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  // Increase the size of the invariant subspace
5077faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  m_r += nbrEig;
5087faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez
5097faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  // Factorize m_T into m_luT
5107faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  m_luT.compute(m_T.topLeftCorner(m_r, m_r));
5117faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez
5127faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  //FIXME CHeck if the factorization was correctly done (nonsingular matrix)
5137faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  m_isDeflInitialized = true;
5147faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  return 0;
5157faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez}
5167faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandeztemplate<typename _MatrixType, typename _Preconditioner>
5177faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandeztemplate<typename RhsType, typename DestType>
5187faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandezint DGMRES<_MatrixType, _Preconditioner>::dgmresApplyDeflation(const RhsType &x, DestType &y) const
5197faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez{
5207faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  DenseVector x1 = m_U.leftCols(m_r).transpose() * x;
5217faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  y = x + m_U.leftCols(m_r) * ( m_lambdaN * m_luT.solve(x1) - x1);
5227faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  return 0;
5237faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez}
5247faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez
5257faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandeznamespace internal {
5267faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez
5277faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  template<typename _MatrixType, typename _Preconditioner, typename Rhs>
5287faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandezstruct solve_retval<DGMRES<_MatrixType, _Preconditioner>, Rhs>
5297faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  : solve_retval_base<DGMRES<_MatrixType, _Preconditioner>, Rhs>
5307faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez{
5317faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  typedef DGMRES<_MatrixType, _Preconditioner> Dec;
5327faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  EIGEN_MAKE_SOLVE_HELPERS(Dec,Rhs)
5337faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez
5347faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  template<typename Dest> void evalTo(Dest& dst) const
5357faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  {
5367faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez    dec()._solve(rhs(),dst);
5377faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez  }
5387faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez};
5397faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez} // end namespace internal
5407faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez
5417faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez} // end namespace Eigen
5427faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez#endif
543