text: // This file is part of Eigen, a lightweight C++ template library
  // for linear algebra.
  //
  // Copyright (C) 2011-2014 Gael Guennebaud <gael.guennebaud@inria.fr>
  //
  // This Source Code Form is subject to the terms of the Mozilla
  // Public License v. 2.0. If a copy of the MPL was not distributed
  // with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
  
  #ifndef EIGEN_ITERATIVE_SOLVER_BASE_H
  #define EIGEN_ITERATIVE_SOLVER_BASE_H
  
  namespace Eigen { 
  
  namespace internal {
  
  template<typename MatrixType>
  struct is_ref_compatible_impl
  {
  private:
    template <typename T0>
    struct any_conversion
    {
      template <typename T> any_conversion(const volatile T&);
      template <typename T> any_conversion(T&);
    };
    struct yes {int a[1];};
    struct no  {int a[2];};
  
    template<typename T>
    static yes test(const Ref<const T>&, int);
    template<typename T>
    static no  test(any_conversion<T>, ...);
  
  public:
    static MatrixType ms_from;
    enum { value = sizeof(test<MatrixType>(ms_from, 0))==sizeof(yes) };
  };
  
  template<typename MatrixType>
  struct is_ref_compatible
  {
    enum { value = is_ref_compatible_impl<typename remove_all<MatrixType>::type>::value };
  };
  
  template<typename MatrixType, bool MatrixFree = !internal::is_ref_compatible<MatrixType>::value>
  class generic_matrix_wrapper;
  
  // We have an explicit matrix at hand, compatible with Ref<>
  template<typename MatrixType>
  class generic_matrix_wrapper<MatrixType,false>
  {
  public:
    typedef Ref<const MatrixType> ActualMatrixType;
    template<int UpLo> struct ConstSelfAdjointViewReturnType {
      typedef typename ActualMatrixType::template ConstSelfAdjointViewReturnType<UpLo>::Type Type;
    };
  
    enum {
      MatrixFree = false
    };
  
    generic_matrix_wrapper()
      : m_dummy(0,0), m_matrix(m_dummy)
    {}
  
    template<typename InputType>
    generic_matrix_wrapper(const InputType &mat)
      : m_matrix(mat)
    {}
  
    const ActualMatrixType& matrix() const
    {
      return m_matrix;
    }
  
    template<typename MatrixDerived>
    void grab(const EigenBase<MatrixDerived> &mat)
    {
      m_matrix.~Ref<const MatrixType>();
      ::new (&m_matrix) Ref<const MatrixType>(mat.derived());
    }
  
    void grab(const Ref<const MatrixType> &mat)
    {
      if(&(mat.derived()) != &m_matrix)
      {
        m_matrix.~Ref<const MatrixType>();
        ::new (&m_matrix) Ref<const MatrixType>(mat);
      }
    }
  
  protected:
    MatrixType m_dummy; // used to default initialize the Ref<> object
    ActualMatrixType m_matrix;
  };
  
  // MatrixType is not compatible with Ref<> -> matrix-free wrapper
  template<typename MatrixType>
  class generic_matrix_wrapper<MatrixType,true>
  {
  public:
    typedef MatrixType ActualMatrixType;
    template<int UpLo> struct ConstSelfAdjointViewReturnType
    {
      typedef ActualMatrixType Type;
    };
  
    enum {
      MatrixFree = true
    };
  
    generic_matrix_wrapper()
      : mp_matrix(0)
    {}
  
    generic_matrix_wrapper(const MatrixType &mat)
      : mp_matrix(&mat)
    {}
  
    const ActualMatrixType& matrix() const
    {
      return *mp_matrix;
    }
  
    void grab(const MatrixType &mat)
    {
      mp_matrix = &mat;
    }
  
  protected:
    const ActualMatrixType *mp_matrix;
  };
  
  }
  
  /** \ingroup IterativeLinearSolvers_Module
    * \brief Base class for linear iterative solvers
    *
    * \sa class SimplicialCholesky, DiagonalPreconditioner, IdentityPreconditioner
    */
  template< typename Derived>
  class IterativeSolverBase : public SparseSolverBase<Derived>
  {
  protected:
    typedef SparseSolverBase<Derived> Base;
    using Base::m_isInitialized;
    
  public:
    typedef typename internal::traits<Derived>::MatrixType MatrixType;
    typedef typename internal::traits<Derived>::Preconditioner Preconditioner;
    typedef typename MatrixType::Scalar Scalar;
    typedef typename MatrixType::StorageIndex StorageIndex;
    typedef typename MatrixType::RealScalar RealScalar;
  
    enum {
      ColsAtCompileTime = MatrixType::ColsAtCompileTime,
      MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime
    };
  
  public:
  
    using Base::derived;
  
    /** Default constructor. */
    IterativeSolverBase()
    {
      init();
    }
  
    /** Initialize the solver with matrix \a A for further \c Ax=b solving.
      * 
      * This constructor is a shortcut for the default constructor followed
      * by a call to compute().
      * 
      * \warning this class stores a reference to the matrix A as well as some
      * precomputed values that depend on it. Therefore, if \a A is changed
      * this class becomes invalid. Call compute() to update it with the new
      * matrix A, or modify a copy of A.
      */
    template<typename MatrixDerived>
    explicit IterativeSolverBase(const EigenBase<MatrixDerived>& A)
      : m_matrixWrapper(A.derived())
    {
      init();
      compute(matrix());
    }
  
    ~IterativeSolverBase() {}
    
    /** Initializes the iterative solver for the sparsity pattern of the matrix \a A for further solving \c Ax=b problems.
      *
      * Currently, this function mostly calls analyzePattern on the preconditioner. In the future
      * we might, for instance, implement column reordering for faster matrix vector products.
      */
    template<typename MatrixDerived>
    Derived& analyzePattern(const EigenBase<MatrixDerived>& A)
    {
      grab(A.derived());
      m_preconditioner.analyzePattern(matrix());
      m_isInitialized = true;
      m_analysisIsOk = true;
      m_info = m_preconditioner.info();
      return derived();
    }
    
    /** Initializes the iterative solver with the numerical values of the matrix \a A for further solving \c Ax=b problems.
      *
      * Currently, this function mostly calls factorize on the preconditioner.
      *
      * \warning this class stores a reference to the matrix A as well as some
      * precomputed values that depend on it. Therefore, if \a A is changed
      * this class becomes invalid. Call compute() to update it with the new
      * matrix A, or modify a copy of A.
      */
    template<typename MatrixDerived>
    Derived& factorize(const EigenBase<MatrixDerived>& A)
    {
      eigen_assert(m_analysisIsOk && "You must first call analyzePattern()"); 
      grab(A.derived());
      m_preconditioner.factorize(matrix());
      m_factorizationIsOk = true;
      m_info = m_preconditioner.info();
      return derived();
    }
  
    /** Initializes the iterative solver with the matrix \a A for further solving \c Ax=b problems.
      *
      * Currently, this function mostly initializes/computes the preconditioner. In the future
      * we might, for instance, implement column reordering for faster matrix vector products.
      *
      * \warning this class stores a reference to the matrix A as well as some
      * precomputed values that depend on it. Therefore, if \a A is changed
      * this class becomes invalid. Call compute() to update it with the new
      * matrix A, or modify a copy of A.
      */
    template<typename MatrixDerived>
    Derived& compute(const EigenBase<MatrixDerived>& A)
    {
      grab(A.derived());
      m_preconditioner.compute(matrix());
      m_isInitialized = true;
      m_analysisIsOk = true;
      m_factorizationIsOk = true;
      m_info = m_preconditioner.info();
      return derived();
    }
  
    /** \internal */
    Index rows() const { return matrix().rows(); }
  
    /** \internal */
    Index cols() const { return matrix().cols(); }
  
    /** \returns the tolerance threshold used by the stopping criteria.
      * \sa setTolerance()
      */
    RealScalar tolerance() const { return m_tolerance; }
    
    /** Sets the tolerance threshold used by the stopping criteria.
      *
      * This value is used as an upper bound to the relative residual error: |Ax-b|/|b|.
      * The default value is the machine precision given by NumTraits<Scalar>::epsilon()
      */
    Derived& setTolerance(const RealScalar& tolerance)
    {
      m_tolerance = tolerance;
      return derived();
    }
  
    /** \returns a read-write reference to the preconditioner for custom configuration. */
    Preconditioner& preconditioner() { return m_preconditioner; }
    
    /** \returns a read-only reference to the preconditioner. */
    const Preconditioner& preconditioner() const { return m_preconditioner; }
  
    /** \returns the max number of iterations.
      * It is either the value setted by setMaxIterations or, by default,
      * twice the number of columns of the matrix.
      */
    Index maxIterations() const
    {
      return (m_maxIterations<0) ? 2*matrix().cols() : m_maxIterations;
    }
    
    /** Sets the max number of iterations.
      * Default is twice the number of columns of the matrix.
      */
    Derived& setMaxIterations(Index maxIters)
    {
      m_maxIterations = maxIters;
      return derived();
    }
  
    /** \returns the number of iterations performed during the last solve */
    Index iterations() const
    {
      eigen_assert(m_isInitialized && "ConjugateGradient is not initialized.");
      return m_iterations;
    }
  
    /** \returns the tolerance error reached during the last solve.
      * It is a close approximation of the true relative residual error |Ax-b|/|b|.
      */
    RealScalar error() const
    {
      eigen_assert(m_isInitialized && "ConjugateGradient is not initialized.");
      return m_error;
    }
  
    /** \returns the solution x of \f$ A x = b \f$ using the current decomposition of A
      * and \a x0 as an initial solution.
      *
      * \sa solve(), compute()
      */
    template<typename Rhs,typename Guess>
    inline const SolveWithGuess<Derived, Rhs, Guess>
    solveWithGuess(const MatrixBase<Rhs>& b, const Guess& x0) const
    {
      eigen_assert(m_isInitialized && "Solver is not initialized.");
      eigen_assert(derived().rows()==b.rows() && "solve(): invalid number of rows of the right hand side matrix b");
      return SolveWithGuess<Derived, Rhs, Guess>(derived(), b.derived(), x0);
    }
  
    /** \returns Success if the iterations converged, and NoConvergence otherwise. */
    ComputationInfo info() const
    {
      eigen_assert(m_isInitialized && "IterativeSolverBase is not initialized.");
      return m_info;
    }
    
    /** \internal */
    template<typename Rhs, typename DestDerived>
    void _solve_impl(const Rhs& b, SparseMatrixBase<DestDerived> &aDest) const
    {
      eigen_assert(rows()==b.rows());
      
      Index rhsCols = b.cols();
      Index size = b.rows();
      DestDerived& dest(aDest.derived());
      typedef typename DestDerived::Scalar DestScalar;
      Eigen::Matrix<DestScalar,Dynamic,1> tb(size);
      Eigen::Matrix<DestScalar,Dynamic,1> tx(cols());
      // We do not directly fill dest because sparse expressions have to be free of aliasing issue.
      // For non square least-square problems, b and dest might not have the same size whereas they might alias each-other.
      typename DestDerived::PlainObject tmp(cols(),rhsCols);
      for(Index k=0; k<rhsCols; ++k)
      {
        tb = b.col(k);
        tx = derived().solve(tb);
        tmp.col(k) = tx.sparseView(0);
      }
      dest.swap(tmp);
    }
  
  protected:
    void init()
    {
      m_isInitialized = false;
      m_analysisIsOk = false;
      m_factorizationIsOk = false;
      m_maxIterations = -1;
      m_tolerance = NumTraits<Scalar>::epsilon();
    }
  
    typedef internal::generic_matrix_wrapper<MatrixType> MatrixWrapper;
    typedef typename MatrixWrapper::ActualMatrixType ActualMatrixType;
  
    const ActualMatrixType& matrix() const
    {
      return m_matrixWrapper.matrix();
    }
    
    template<typename InputType>
    void grab(const InputType &A)
    {
      m_matrixWrapper.grab(A);
    }
    
    MatrixWrapper m_matrixWrapper;
    Preconditioner m_preconditioner;
  
    Index m_maxIterations;
    RealScalar m_tolerance;
    
    mutable RealScalar m_error;
    mutable Index m_iterations;
    mutable ComputationInfo m_info;
    mutable bool m_analysisIsOk, m_factorizationIsOk;
  };
  
  } // end namespace Eigen
  
  #endif // EIGEN_ITERATIVE_SOLVER_BASE_H
  