MINRES.h
Go to the documentation of this file.
1 // This file is part of Eigen, a lightweight C++ template library
2 // for linear algebra.
3 //
4 // Copyright (C) 2012 Giacomo Po <gpo@ucla.edu>
5 // Copyright (C) 2011-2014 Gael Guennebaud <gael.guennebaud@inria.fr>
6 // Copyright (C) 2018 David Hyde <dabh@stanford.edu>
7 //
8 // This Source Code Form is subject to the terms of the Mozilla
9 // Public License v. 2.0. If a copy of the MPL was not distributed
10 // with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
11 
12 
13 #ifndef EIGEN_MINRES_H
14 #define EIGEN_MINRES_H
15 
16 
17 #include "./InternalHeaderCheck.h"
18 
19 namespace Eigen {
20 
21  namespace internal {
22 
32  template<typename MatrixType, typename Rhs, typename Dest, typename Preconditioner>
34  void minres(const MatrixType& mat, const Rhs& rhs, Dest& x,
35  const Preconditioner& precond, Index& iters,
36  typename Dest::RealScalar& tol_error)
37  {
38  using std::sqrt;
39  typedef typename Dest::RealScalar RealScalar;
40  typedef typename Dest::Scalar Scalar;
41  typedef Matrix<Scalar,Dynamic,1> VectorType;
42 
43  // Check for zero rhs
44  const RealScalar rhsNorm2(rhs.squaredNorm());
45  if(rhsNorm2 == 0)
46  {
47  x.setZero();
48  iters = 0;
49  tol_error = 0;
50  return;
51  }
52 
53  // initialize
54  const Index maxIters(iters); // initialize maxIters to iters
55  const Index N(mat.cols()); // the size of the matrix
56  const RealScalar threshold2(tol_error*tol_error*rhsNorm2); // convergence threshold (compared to residualNorm2)
57 
58  // Initialize preconditioned Lanczos
59  VectorType v_old(N); // will be initialized inside loop
60  VectorType v( VectorType::Zero(N) ); //initialize v
61  VectorType v_new(rhs-mat*x); //initialize v_new
62  RealScalar residualNorm2(v_new.squaredNorm());
63  VectorType w(N); // will be initialized inside loop
64  VectorType w_new(precond.solve(v_new)); // initialize w_new
65 // RealScalar beta; // will be initialized inside loop
66  RealScalar beta_new2(v_new.dot(w_new));
67  eigen_assert(beta_new2 >= 0.0 && "PRECONDITIONER IS NOT POSITIVE DEFINITE");
68  RealScalar beta_new(sqrt(beta_new2));
69  const RealScalar beta_one(beta_new);
70  // Initialize other variables
71  RealScalar c(1.0); // the cosine of the Givens rotation
72  RealScalar c_old(1.0);
73  RealScalar s(0.0); // the sine of the Givens rotation
74  RealScalar s_old(0.0); // the sine of the Givens rotation
75  VectorType p_oold(N); // will be initialized in loop
76  VectorType p_old(VectorType::Zero(N)); // initialize p_old=0
77  VectorType p(p_old); // initialize p=0
78  RealScalar eta(1.0);
79 
80  iters = 0; // reset iters
81  while ( iters < maxIters )
82  {
83  // Preconditioned Lanczos
84  /* Note that there are 4 variants on the Lanczos algorithm. These are
85  * described in Paige, C. C. (1972). Computational variants of
86  * the Lanczos method for the eigenproblem. IMA Journal of Applied
87  * Mathematics, 10(3), 373-381. The current implementation corresponds
88  * to the case A(2,7) in the paper. It also corresponds to
89  * algorithm 6.14 in Y. Saad, Iterative Methods for Sparse Linear
90  * Systems, 2003 p.173. For the preconditioned version see
91  * A. Greenbaum, Iterative Methods for Solving Linear Systems, SIAM (1987).
92  */
93  const RealScalar beta(beta_new);
94  v_old = v; // update: at first time step, this makes v_old = 0 so value of beta doesn't matter
95  v_new /= beta_new; // overwrite v_new for next iteration
96  w_new /= beta_new; // overwrite w_new for next iteration
97  v = v_new; // update
98  w = w_new; // update
99  v_new.noalias() = mat*w - beta*v_old; // compute v_new
100  const RealScalar alpha = v_new.dot(w);
101  v_new -= alpha*v; // overwrite v_new
102  w_new = precond.solve(v_new); // overwrite w_new
103  beta_new2 = v_new.dot(w_new); // compute beta_new
104  eigen_assert(beta_new2 >= 0.0 && "PRECONDITIONER IS NOT POSITIVE DEFINITE");
105  beta_new = sqrt(beta_new2); // compute beta_new
106 
107  // Givens rotation
108  const RealScalar r2 =s*alpha+c*c_old*beta; // s, s_old, c and c_old are still from previous iteration
109  const RealScalar r3 =s_old*beta; // s, s_old, c and c_old are still from previous iteration
110  const RealScalar r1_hat=c*alpha-c_old*s*beta;
111  const RealScalar r1 =sqrt( std::pow(r1_hat,2) + std::pow(beta_new,2) );
112  c_old = c; // store for next iteration
113  s_old = s; // store for next iteration
114  c=r1_hat/r1; // new cosine
115  s=beta_new/r1; // new sine
116 
117  // Update solution
118  p_oold = p_old;
119  p_old = p;
120  p.noalias()=(w-r2*p_old-r3*p_oold) /r1; // IS NOALIAS REQUIRED?
121  x += beta_one*c*eta*p;
122 
123  /* Update the squared residual. Note that this is the estimated residual.
124  The real residual |Ax-b|^2 may be slightly larger */
125  residualNorm2 *= s*s;
126 
127  if ( residualNorm2 < threshold2)
128  {
129  break;
130  }
131 
132  eta=-s*eta; // update eta
133  iters++; // increment iteration number (for output purposes)
134  }
135 
136  /* Compute error. Note that this is the estimated error. The real
137  error |Ax-b|/|b| may be slightly larger */
138  tol_error = std::sqrt(residualNorm2 / rhsNorm2);
139  }
140 
141  }
142 
143  template< typename MatrixType_, int UpLo_=Lower,
144  typename Preconditioner_ = IdentityPreconditioner>
145  class MINRES;
146 
147  namespace internal {
148 
149  template< typename MatrixType_, int UpLo_, typename Preconditioner_>
150  struct traits<MINRES<MatrixType_,UpLo_,Preconditioner_> >
151  {
152  typedef MatrixType_ MatrixType;
153  typedef Preconditioner_ Preconditioner;
154  };
155 
156  }
157 
196  template< typename MatrixType_, int UpLo_, typename Preconditioner_>
197  class MINRES : public IterativeSolverBase<MINRES<MatrixType_,UpLo_,Preconditioner_> >
198  {
199 
201  using Base::matrix;
202  using Base::m_error;
203  using Base::m_iterations;
204  using Base::m_info;
205  using Base::m_isInitialized;
206  public:
207  using Base::_solve_impl;
208  typedef MatrixType_ MatrixType;
209  typedef typename MatrixType::Scalar Scalar;
210  typedef typename MatrixType::RealScalar RealScalar;
211  typedef Preconditioner_ Preconditioner;
212 
213  enum {UpLo = UpLo_};
214 
215  public:
216 
218  MINRES() : Base() {}
219 
230  template<typename MatrixDerived>
231  explicit MINRES(const EigenBase<MatrixDerived>& A) : Base(A.derived()) {}
232 
235 
237  template<typename Rhs,typename Dest>
238  void _solve_vector_with_guess_impl(const Rhs& b, Dest& x) const
239  {
240  typedef typename Base::MatrixWrapper MatrixWrapper;
241  typedef typename Base::ActualMatrixType ActualMatrixType;
242  enum {
243  TransposeInput = (!MatrixWrapper::MatrixFree)
244  && (UpLo==(Lower|Upper))
245  && (!MatrixType::IsRowMajor)
247  };
248  typedef std::conditional_t<TransposeInput,Transpose<const ActualMatrixType>, ActualMatrixType const&> RowMajorWrapper;
249  EIGEN_STATIC_ASSERT(internal::check_implication(MatrixWrapper::MatrixFree, UpLo==(Lower|Upper)),MATRIX_FREE_CONJUGATE_GRADIENT_IS_COMPATIBLE_WITH_UPPER_UNION_LOWER_MODE_ONLY);
250  typedef std::conditional_t<UpLo==(Lower|Upper),
251  RowMajorWrapper,
252  typename MatrixWrapper::template ConstSelfAdjointViewReturnType<UpLo>::Type
253  > SelfAdjointWrapper;
254 
257  RowMajorWrapper row_mat(matrix());
258  internal::minres(SelfAdjointWrapper(row_mat), b, x,
261  }
262 
263  protected:
264 
265  };
266 
267 } // end namespace Eigen
268 
269 #endif // EIGEN_MINRES_H
Array< int, Dynamic, 1 > v
SparseMatrix< double > A(n, n)
Array33i c
#define EIGEN_DONT_INLINE
#define eigen_assert(x)
RowVector3d w
#define EIGEN_STATIC_ASSERT(X, MSG)
MatrixXf mat
float * p
Matrix< float, 1, Dynamic > MatrixType
internal::generic_matrix_wrapper< MatrixType > MatrixWrapper
MatrixWrapper::ActualMatrixType ActualMatrixType
void _solve_impl(const Rhs &b, Dest &x) const
Preconditioner m_preconditioner
const ActualMatrixType & matrix() const
A minimal residual solver for sparse symmetric problems.
Definition: MINRES.h:198
RealScalar m_error
const ActualMatrixType & matrix() const
ComputationInfo m_info
Preconditioner_ Preconditioner
Definition: MINRES.h:211
MatrixType::RealScalar RealScalar
Definition: MINRES.h:210
void _solve_vector_with_guess_impl(const Rhs &b, Dest &x) const
Definition: MINRES.h:238
MatrixType_ MatrixType
Definition: MINRES.h:208
MINRES(const EigenBase< MatrixDerived > &A)
Definition: MINRES.h:231
Index m_iterations
MatrixType::Scalar Scalar
Definition: MINRES.h:209
IterativeSolverBase< MINRES > Base
Definition: MINRES.h:200
constexpr bool check_implication(bool a, bool b)
EIGEN_DONT_INLINE void minres(const MatrixType &mat, const Rhs &rhs, Dest &x, const Preconditioner &precond, Index &iters, typename Dest::RealScalar &tol_error)
Definition: MINRES.h:34
: TensorContractionSycl.h, provides various tensor contraction kernel for SYCL backend
Eigen::AutoDiffScalar< EIGEN_EXPR_BINARYOP_SCALAR_RETURN_TYPE(Eigen::internal::remove_all_t< DerType >, typename Eigen::internal::traits< Eigen::internal::remove_all_t< DerType >>::Scalar, product) > sqrt(const Eigen::AutoDiffScalar< DerType > &x)
EIGEN_DEFAULT_DENSE_INDEX_TYPE Index
Eigen::AutoDiffScalar< EIGEN_EXPR_BINARYOP_SCALAR_RETURN_TYPE(internal::remove_all_t< DerType >, typename internal::traits< internal::remove_all_t< DerType >>::Scalar, product) > pow(const Eigen::AutoDiffScalar< DerType > &x, const typename internal::traits< internal::remove_all_t< DerType >>::Scalar &y)
const Eigen::CwiseUnaryOp< Eigen::internal::scalar_sqrt_op< typename Derived::Scalar >, const Derived > sqrt(const Eigen::ArrayBase< Derived > &x)