ConjugateGradient.h 9.07 KB
Newer Older
Don Gagne's avatar
Don Gagne committed
1 2 3
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
4
// Copyright (C) 2011-2014 Gael Guennebaud <gael.guennebaud@inria.fr>
Don Gagne's avatar
Don Gagne committed
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
//
// 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_CONJUGATE_GRADIENT_H
#define EIGEN_CONJUGATE_GRADIENT_H

namespace Eigen { 

namespace internal {

/** \internal Low-level conjugate gradient algorithm
  * \param mat The matrix A
  * \param rhs The right hand side vector b
  * \param x On input and initial solution, on output the computed solution.
  * \param precond A preconditioner being able to efficiently solve for an
  *                approximation of Ax=b (regardless of b)
  * \param iters On input the max number of iteration, on output the number of performed iterations.
  * \param tol_error On input the tolerance error, on output an estimation of the relative error.
  */
template<typename MatrixType, typename Rhs, typename Dest, typename Preconditioner>
EIGEN_DONT_INLINE
void conjugate_gradient(const MatrixType& mat, const Rhs& rhs, Dest& x,
29
                        const Preconditioner& precond, Index& iters,
Don Gagne's avatar
Don Gagne committed
30 31 32 33 34 35 36 37 38
                        typename Dest::RealScalar& tol_error)
{
  using std::sqrt;
  using std::abs;
  typedef typename Dest::RealScalar RealScalar;
  typedef typename Dest::Scalar Scalar;
  typedef Matrix<Scalar,Dynamic,1> VectorType;
  
  RealScalar tol = tol_error;
39
  Index maxIters = iters;
Don Gagne's avatar
Don Gagne committed
40
  
41
  Index n = mat.cols();
Don Gagne's avatar
Don Gagne committed
42 43 44 45 46 47 48 49 50 51 52

  VectorType residual = rhs - mat * x; //initial residual

  RealScalar rhsNorm2 = rhs.squaredNorm();
  if(rhsNorm2 == 0) 
  {
    x.setZero();
    iters = 0;
    tol_error = 0;
    return;
  }
53 54
  const RealScalar considerAsZero = (std::numeric_limits<RealScalar>::min)();
  RealScalar threshold = numext::maxi(tol*tol*rhsNorm2,considerAsZero);
Don Gagne's avatar
Don Gagne committed
55 56 57 58 59 60 61
  RealScalar residualNorm2 = residual.squaredNorm();
  if (residualNorm2 < threshold)
  {
    iters = 0;
    tol_error = sqrt(residualNorm2 / rhsNorm2);
    return;
  }
62

Don Gagne's avatar
Don Gagne committed
63
  VectorType p(n);
64
  p = precond.solve(residual);      // initial search direction
Don Gagne's avatar
Don Gagne committed
65 66 67

  VectorType z(n), tmp(n);
  RealScalar absNew = numext::real(residual.dot(p));  // the square of the absolute value of r scaled by invM
68
  Index i = 0;
Don Gagne's avatar
Don Gagne committed
69 70
  while(i < maxIters)
  {
71
    tmp.noalias() = mat * p;                    // the bottleneck of the algorithm
Don Gagne's avatar
Don Gagne committed
72

73 74 75
    Scalar alpha = absNew / p.dot(tmp);         // the amount we travel on dir
    x += alpha * p;                             // update solution
    residual -= alpha * tmp;                    // update residual
Don Gagne's avatar
Don Gagne committed
76 77 78 79 80
    
    residualNorm2 = residual.squaredNorm();
    if(residualNorm2 < threshold)
      break;
    
81
    z = precond.solve(residual);                // approximately solve for "A z = residual"
Don Gagne's avatar
Don Gagne committed
82 83 84

    RealScalar absOld = absNew;
    absNew = numext::real(residual.dot(z));     // update the absolute value of r
85 86
    RealScalar beta = absNew / absOld;          // calculate the Gram-Schmidt value used to create the new search direction
    p = z + beta * p;                           // update search direction
Don Gagne's avatar
Don Gagne committed
87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110
    i++;
  }
  tol_error = sqrt(residualNorm2 / rhsNorm2);
  iters = i;
}

}

template< typename _MatrixType, int _UpLo=Lower,
          typename _Preconditioner = DiagonalPreconditioner<typename _MatrixType::Scalar> >
class ConjugateGradient;

namespace internal {

template< typename _MatrixType, int _UpLo, typename _Preconditioner>
struct traits<ConjugateGradient<_MatrixType,_UpLo,_Preconditioner> >
{
  typedef _MatrixType MatrixType;
  typedef _Preconditioner Preconditioner;
};

}

/** \ingroup IterativeLinearSolvers_Module
111
  * \brief A conjugate gradient solver for sparse (or dense) self-adjoint problems
Don Gagne's avatar
Don Gagne committed
112
  *
113 114
  * This class allows to solve for A.x = b linear problems using an iterative conjugate gradient algorithm.
  * The matrix A must be selfadjoint. The matrix A and the vectors x and b can be either dense or sparse.
Don Gagne's avatar
Don Gagne committed
115
  *
116 117
  * \tparam _MatrixType the type of the matrix A, can be a dense or a sparse matrix.
  * \tparam _UpLo the triangular part that will be used for the computations. It can be Lower,
118 119
  *               \c Upper, or \c Lower|Upper in which the full matrix entries will be considered.
  *               Default is \c Lower, best performance is \c Lower|Upper.
Don Gagne's avatar
Don Gagne committed
120 121
  * \tparam _Preconditioner the type of the preconditioner. Default is DiagonalPreconditioner
  *
122 123
  * \implsparsesolverconcept
  *
Don Gagne's avatar
Don Gagne committed
124 125 126 127
  * The maximal number of iterations and tolerance value can be controlled via the setMaxIterations()
  * and setTolerance() methods. The defaults are the size of the problem for the maximal number of iterations
  * and NumTraits<Scalar>::epsilon() for the tolerance.
  * 
128 129 130 131 132 133 134
  * The tolerance corresponds to the relative residual error: |Ax-b|/|b|
  * 
  * \b Performance: Even though the default value of \c _UpLo is \c Lower, significantly higher performance is
  * achieved when using a complete matrix and \b Lower|Upper as the \a _UpLo template parameter. Moreover, in this
  * case multi-threading can be exploited if the user code is compiled with OpenMP enabled.
  * See \ref TopicMultiThreading for details.
  * 
Don Gagne's avatar
Don Gagne committed
135
  * This class can be used as the direct solver classes. Here is a typical usage example:
136 137 138 139 140 141 142 143 144 145 146 147 148
    \code
    int n = 10000;
    VectorXd x(n), b(n);
    SparseMatrix<double> A(n,n);
    // fill A and b
    ConjugateGradient<SparseMatrix<double>, Lower|Upper> cg;
    cg.compute(A);
    x = cg.solve(b);
    std::cout << "#iterations:     " << cg.iterations() << std::endl;
    std::cout << "estimated error: " << cg.error()      << std::endl;
    // update b, and solve again
    x = cg.solve(b);
    \endcode
Don Gagne's avatar
Don Gagne committed
149 150
  * 
  * By default the iterations start with x=0 as an initial guess of the solution.
151
  * One can control the start using the solveWithGuess() method.
Don Gagne's avatar
Don Gagne committed
152
  * 
153 154 155
  * ConjugateGradient can also be used in a matrix-free context, see the following \link MatrixfreeSolverExample example \endlink.
  *
  * \sa class LeastSquaresConjugateGradient, class SimplicialCholesky, DiagonalPreconditioner, IdentityPreconditioner
Don Gagne's avatar
Don Gagne committed
156 157 158 159 160
  */
template< typename _MatrixType, int _UpLo, typename _Preconditioner>
class ConjugateGradient : public IterativeSolverBase<ConjugateGradient<_MatrixType,_UpLo,_Preconditioner> >
{
  typedef IterativeSolverBase<ConjugateGradient> Base;
161
  using Base::matrix;
Don Gagne's avatar
Don Gagne committed
162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190
  using Base::m_error;
  using Base::m_iterations;
  using Base::m_info;
  using Base::m_isInitialized;
public:
  typedef _MatrixType MatrixType;
  typedef typename MatrixType::Scalar Scalar;
  typedef typename MatrixType::RealScalar RealScalar;
  typedef _Preconditioner Preconditioner;

  enum {
    UpLo = _UpLo
  };

public:

  /** Default constructor. */
  ConjugateGradient() : Base() {}

  /** 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.
    */
191 192
  template<typename MatrixDerived>
  explicit ConjugateGradient(const EigenBase<MatrixDerived>& A) : Base(A.derived()) {}
Don Gagne's avatar
Don Gagne committed
193 194 195 196 197

  ~ConjugateGradient() {}

  /** \internal */
  template<typename Rhs,typename Dest>
198
  void _solve_with_guess_impl(const Rhs& b, Dest& x) const
Don Gagne's avatar
Don Gagne committed
199
  {
200 201 202 203 204 205 206 207 208 209
    typedef typename Base::MatrixWrapper MatrixWrapper;
    typedef typename Base::ActualMatrixType ActualMatrixType;
    enum {
      TransposeInput  =   (!MatrixWrapper::MatrixFree)
                      &&  (UpLo==(Lower|Upper))
                      &&  (!MatrixType::IsRowMajor)
                      &&  (!NumTraits<Scalar>::IsComplex)
    };
    typedef typename internal::conditional<TransposeInput,Transpose<const ActualMatrixType>, ActualMatrixType const&>::type RowMajorWrapper;
    EIGEN_STATIC_ASSERT(EIGEN_IMPLIES(MatrixWrapper::MatrixFree,UpLo==(Lower|Upper)),MATRIX_FREE_CONJUGATE_GRADIENT_IS_COMPATIBLE_WITH_UPPER_UNION_LOWER_MODE_ONLY);
210
    typedef typename internal::conditional<UpLo==(Lower|Upper),
211 212 213
                                           RowMajorWrapper,
                                           typename MatrixWrapper::template ConstSelfAdjointViewReturnType<UpLo>::Type
                                          >::type SelfAdjointWrapper;
Don Gagne's avatar
Don Gagne committed
214 215 216
    m_iterations = Base::maxIterations();
    m_error = Base::m_tolerance;

217
    for(Index j=0; j<b.cols(); ++j)
Don Gagne's avatar
Don Gagne committed
218 219 220 221 222
    {
      m_iterations = Base::maxIterations();
      m_error = Base::m_tolerance;

      typename Dest::ColXpr xj(x,j);
223 224
      RowMajorWrapper row_mat(matrix());
      internal::conjugate_gradient(SelfAdjointWrapper(row_mat), b.col(j), xj, Base::m_preconditioner, m_iterations, m_error);
Don Gagne's avatar
Don Gagne committed
225 226 227 228 229 230 231
    }

    m_isInitialized = true;
    m_info = m_error <= Base::m_tolerance ? Success : NoConvergence;
  }
  
  /** \internal */
232
  using Base::_solve_impl;
Don Gagne's avatar
Don Gagne committed
233
  template<typename Rhs,typename Dest>
234
  void _solve_impl(const MatrixBase<Rhs>& b, Dest& x) const
Don Gagne's avatar
Don Gagne committed
235
  {
236
    x.setZero();
237
    _solve_with_guess_impl(b.derived(),x);
Don Gagne's avatar
Don Gagne committed
238 239 240 241 242 243 244 245 246
  }

protected:

};

} // end namespace Eigen

#endif // EIGEN_CONJUGATE_GRADIENT_H