IDRS.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) 2020 Chris Schoutrop <c.e.m.schoutrop@tue.nl>
5 // Copyright (C) 2020 Jens Wehner <j.wehner@esciencecenter.nl>
6 // Copyright (C) 2020 Jan van Dijk <j.v.dijk@tue.nl>
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 #ifndef EIGEN_IDRS_H
13 #define EIGEN_IDRS_H
14 
15 // IWYU pragma: private
16 #include "./InternalHeaderCheck.h"
17 
18 namespace Eigen {
19 
20 namespace internal {
35 template <typename Vector, typename RealScalar>
36 typename Vector::Scalar omega(const Vector& t, const Vector& s, RealScalar angle) {
37  using numext::abs;
38  typedef typename Vector::Scalar Scalar;
39  const RealScalar ns = s.stableNorm();
40  const RealScalar nt = t.stableNorm();
41  const Scalar ts = t.dot(s);
42  const RealScalar rho = abs(ts / (nt * ns));
43 
44  if (rho < angle) {
45  if (ts == Scalar(0)) {
46  return Scalar(0);
47  }
48  // Original relation for om is given by
49  // om = om * angle / rho;
50  // To alleviate potential (near) division by zero this can be rewritten as
51  // om = angle * (ns / nt) * (ts / abs(ts)) = angle * (ns / nt) * sgn(ts)
52  return angle * (ns / nt) * (ts / abs(ts));
53  }
54  return ts / (nt * nt);
55 }
56 
57 template <typename MatrixType, typename Rhs, typename Dest, typename Preconditioner>
58 bool idrs(const MatrixType& A, const Rhs& b, Dest& x, const Preconditioner& precond, Index& iter,
59  typename Dest::RealScalar& relres, Index S, bool smoothing, typename Dest::RealScalar angle,
60  bool replacement) {
61  typedef typename Dest::RealScalar RealScalar;
62  typedef typename Dest::Scalar Scalar;
64  typedef Matrix<Scalar, Dynamic, Dynamic, ColMajor> DenseMatrixType;
65  const Index N = b.size();
66  S = S < x.rows() ? S : x.rows();
67  const RealScalar tol = relres;
68  const Index maxit = iter;
69 
70  bool trueres = false;
71 
73 
74  DenseMatrixType P;
75  {
76  HouseholderQR<DenseMatrixType> qr(DenseMatrixType::Random(N, S));
77  P = (qr.householderQ() * DenseMatrixType::Identity(N, S));
78  }
79 
80  const RealScalar normb = b.stableNorm();
81 
82  if (internal::isApprox(normb, RealScalar(0))) {
83  // Solution is the zero vector
84  x.setZero();
85  iter = 0;
86  relres = 0;
87  return true;
88  }
89  // from http://homepage.tudelft.nl/1w5b5/IDRS/manual.pdf
90  // A peak in the residual is considered dangerously high if‖ri‖/‖b‖> C(tol/epsilon).
91  // With epsilon the relative machine precision. The factor tol/epsilon corresponds
92  // to the size of a finite precision number that is so large that the absolute
93  // round-off error in this number, when propagated through the process, makes it
94  // impossible to achieve the required accuracy. The factor C accounts for the
95  // accumulation of round-off errors. This parameter has been set to 10^{-3}.
96  // mp is epsilon/C 10^3 * eps is very conservative, so normally no residual
97  // replacements will take place. It only happens if things go very wrong. Too many
98  // restarts may ruin the convergence.
100 
101  // Compute initial residual
102  const RealScalar tolb = tol * normb; // Relative tolerance
103  VectorType r = b - A * x;
104 
105  VectorType x_s, r_s;
106 
107  if (smoothing) {
108  x_s = x;
109  r_s = r;
110  }
111 
112  RealScalar normr = r.stableNorm();
113 
114  if (normr <= tolb) {
115  // Initial guess is a good enough solution
116  iter = 0;
117  relres = normr / normb;
118  return true;
119  }
120 
121  DenseMatrixType G = DenseMatrixType::Zero(N, S);
122  DenseMatrixType U = DenseMatrixType::Zero(N, S);
123  DenseMatrixType M = DenseMatrixType::Identity(S, S);
124  VectorType t(N), v(N);
125  Scalar om = 1.;
126 
127  // Main iteration loop, guild G-spaces:
128  iter = 0;
129 
130  while (normr > tolb && iter < maxit) {
131  // New right hand size for small system:
132  VectorType f = (r.adjoint() * P).adjoint();
133 
134  for (Index k = 0; k < S; ++k) {
135  // Solve small system and make v orthogonal to P:
136  // c = M(k:s,k:s)\f(k:s);
137  lu_solver.compute(M.block(k, k, S - k, S - k));
138  VectorType c = lu_solver.solve(f.segment(k, S - k));
139  // v = r - G(:,k:s)*c;
140  v = r - G.rightCols(S - k) * c;
141  // Preconditioning
142  v = precond.solve(v);
143 
144  // Compute new U(:,k) and G(:,k), G(:,k) is in space G_j
145  U.col(k) = U.rightCols(S - k) * c + om * v;
146  G.col(k) = A * U.col(k);
147 
148  // Bi-Orthogonalise the new basis vectors:
149  for (Index i = 0; i < k - 1; ++i) {
150  // alpha = ( P(:,i)'*G(:,k) )/M(i,i);
151  Scalar alpha = P.col(i).dot(G.col(k)) / M(i, i);
152  G.col(k) = G.col(k) - alpha * G.col(i);
153  U.col(k) = U.col(k) - alpha * U.col(i);
154  }
155 
156  // New column of M = P'*G (first k-1 entries are zero)
157  // M(k:s,k) = (G(:,k)'*P(:,k:s))';
158  M.block(k, k, S - k, 1) = (G.col(k).adjoint() * P.rightCols(S - k)).adjoint();
159 
160  if (internal::isApprox(M(k, k), Scalar(0))) {
161  return false;
162  }
163 
164  // Make r orthogonal to q_i, i = 0..k-1
165  Scalar beta = f(k) / M(k, k);
166  r = r - beta * G.col(k);
167  x = x + beta * U.col(k);
168  normr = r.stableNorm();
169 
170  if (replacement && normr > tolb / mp) {
171  trueres = true;
172  }
173 
174  // Smoothing:
175  if (smoothing) {
176  t = r_s - r;
177  // gamma is a Scalar, but the conversion is not allowed
178  Scalar gamma = t.dot(r_s) / t.stableNorm();
179  r_s = r_s - gamma * t;
180  x_s = x_s - gamma * (x_s - x);
181  normr = r_s.stableNorm();
182  }
183 
184  if (normr < tolb || iter == maxit) {
185  break;
186  }
187 
188  // New f = P'*r (first k components are zero)
189  if (k < S - 1) {
190  f.segment(k + 1, S - (k + 1)) = f.segment(k + 1, S - (k + 1)) - beta * M.block(k + 1, k, S - (k + 1), 1);
191  }
192  } // end for
193 
194  if (normr < tolb || iter == maxit) {
195  break;
196  }
197 
198  // Now we have sufficient vectors in G_j to compute residual in G_j+1
199  // Note: r is already perpendicular to P so v = r
200  // Preconditioning
201  v = r;
202  v = precond.solve(v);
203 
204  // Matrix-vector multiplication:
205  t = A * v;
206 
207  // Computation of a new omega
208  om = internal::omega(t, r, angle);
209 
210  if (om == RealScalar(0.0)) {
211  return false;
212  }
213 
214  r = r - om * t;
215  x = x + om * v;
216  normr = r.stableNorm();
217 
218  if (replacement && normr > tolb / mp) {
219  trueres = true;
220  }
221 
222  // Residual replacement?
223  if (trueres && normr < normb) {
224  r = b - A * x;
225  trueres = false;
226  }
227 
228  // Smoothing:
229  if (smoothing) {
230  t = r_s - r;
231  Scalar gamma = t.dot(r_s) / t.stableNorm();
232  r_s = r_s - gamma * t;
233  x_s = x_s - gamma * (x_s - x);
234  normr = r_s.stableNorm();
235  }
236 
237  iter++;
238 
239  } // end while
240 
241  if (smoothing) {
242  x = x_s;
243  }
244  relres = normr / normb;
245  return true;
246 }
247 
248 } // namespace internal
249 
250 template <typename MatrixType_, typename Preconditioner_ = DiagonalPreconditioner<typename MatrixType_::Scalar> >
251 class IDRS;
252 
253 namespace internal {
254 
255 template <typename MatrixType_, typename Preconditioner_>
256 struct traits<Eigen::IDRS<MatrixType_, Preconditioner_> > {
257  typedef MatrixType_ MatrixType;
258  typedef Preconditioner_ Preconditioner;
259 };
260 
261 } // namespace internal
262 
304 template <typename MatrixType_, typename Preconditioner_>
305 class IDRS : public IterativeSolverBase<IDRS<MatrixType_, Preconditioner_> > {
306  public:
307  typedef MatrixType_ MatrixType;
308  typedef typename MatrixType::Scalar Scalar;
310  typedef Preconditioner_ Preconditioner;
311 
312  private:
314  using Base::m_error;
315  using Base::m_info;
316  using Base::m_isInitialized;
317  using Base::m_iterations;
318  using Base::matrix;
323 
324  public:
326  IDRS() : m_S(4), m_smoothing(false), m_angle(RealScalar(0.7)), m_residual(false) {}
327 
338  template <typename MatrixDerived>
339  explicit IDRS(const EigenBase<MatrixDerived>& A)
340  : Base(A.derived()), m_S(4), m_smoothing(false), m_angle(RealScalar(0.7)), m_residual(false) {}
341 
347  template <typename Rhs, typename Dest>
348  void _solve_vector_with_guess_impl(const Rhs& b, Dest& x) const {
351 
353  m_residual);
354 
356  }
357 
359  void setS(Index S) {
360  if (S < 1) {
361  S = 4;
362  }
363 
364  m_S = S;
365  }
366 
373  void setSmoothing(bool smoothing) { m_smoothing = smoothing; }
374 
386 
390  void setResidualUpdate(bool update) { m_residual = update; }
391 };
392 
393 } // namespace Eigen
394 
395 #endif /* EIGEN_IDRS_H */
AnnoyingScalar abs(const AnnoyingScalar &x)
Definition: AnnoyingScalar.h:135
Array< int, Dynamic, 1 > v
Definition: Array_initializer_list_vector_cxx11.cpp:1
int i
Definition: BiCGSTAB_step_by_step.cpp:9
HouseholderQR< MatrixXf > qr(A)
JacobiRotation< float > G
Definition: Jacobi_makeGivens.cpp:2
void adjoint(const MatrixType &m)
Definition: adjoint.cpp:85
Scalar * b
Definition: benchVecAdd.cpp:17
SCALAR Scalar
Definition: bench_gemm.cpp:45
Matrix< RealScalar, Dynamic, Dynamic > M
Definition: bench_gemm.cpp:50
NumTraits< Scalar >::Real RealScalar
Definition: bench_gemm.cpp:46
MatrixXf MatrixType
Definition: benchmark-blocking-sizes.cpp:52
LU decomposition of a matrix with complete pivoting, and related features.
Definition: FullPivLU.h:63
FullPivLU & compute(const EigenBase< InputType > &matrix)
Definition: FullPivLU.h:123
Householder QR decomposition of a matrix.
Definition: HouseholderQR.h:59
The Induced Dimension Reduction method (IDR(s)) is a short-recurrences Krylov method for sparse squar...
Definition: IDRS.h:305
void setResidualUpdate(bool update)
Definition: IDRS.h:390
IDRS()
Definition: IDRS.h:326
ComputationInfo m_info
Definition: IterativeSolverBase.h:389
IDRS(const EigenBase< MatrixDerived > &A)
Definition: IDRS.h:339
MatrixType::Scalar Scalar
Definition: IDRS.h:308
Preconditioner_ Preconditioner
Definition: IDRS.h:310
IterativeSolverBase< IDRS > Base
Definition: IDRS.h:313
RealScalar m_error
Definition: IterativeSolverBase.h:387
bool m_residual
Definition: IDRS.h:322
Index m_iterations
Definition: IterativeSolverBase.h:388
void _solve_vector_with_guess_impl(const Rhs &b, Dest &x) const
Definition: IDRS.h:348
MatrixType_ MatrixType
Definition: IDRS.h:307
void setSmoothing(bool smoothing)
Definition: IDRS.h:373
MatrixType::RealScalar RealScalar
Definition: IDRS.h:309
void setS(Index S)
Definition: IDRS.h:359
bool m_smoothing
Definition: IDRS.h:320
const ActualMatrixType & matrix() const
Definition: IterativeSolverBase.h:374
void setAngle(RealScalar angle)
Definition: IDRS.h:385
Index m_S
Definition: IDRS.h:319
RealScalar m_angle
Definition: IDRS.h:321
Base class for linear iterative solvers.
Definition: IterativeSolverBase.h:124
Index maxIterations() const
Definition: IterativeSolverBase.h:251
ComputationInfo m_info
Definition: IterativeSolverBase.h:389
RealScalar m_error
Definition: IterativeSolverBase.h:387
Preconditioner m_preconditioner
Definition: IterativeSolverBase.h:382
Index m_iterations
Definition: IterativeSolverBase.h:388
bool m_isInitialized
Definition: SparseSolverBase.h:110
RealScalar m_tolerance
Definition: IterativeSolverBase.h:385
IDRS< MatrixType_, Preconditioner_ > & derived()
Definition: SparseSolverBase.h:76
const ActualMatrixType & matrix() const
Definition: IterativeSolverBase.h:374
The matrix class, also used for vectors and row-vectors.
Definition: Eigen/Eigen/src/Core/Matrix.h:186
internal::traits< Matrix< Scalar_, Rows_, Cols_, Options_, MaxRows_, MaxCols_ > >::Scalar Scalar
Definition: PlainObjectBase.h:127
const Solve< Derived, Rhs > solve(const MatrixBase< Rhs > &b) const
Definition: SolverBase.h:106
@ N
Definition: constructor.cpp:22
static int f(const TensorMap< Tensor< int, 3 > > &tensor)
Definition: cxx11_tensor_map.cpp:237
@ NumericalIssue
Definition: Constants.h:442
@ Success
Definition: Constants.h:440
@ NoConvergence
Definition: Constants.h:444
RealScalar s
Definition: level1_cplx_impl.h:130
Eigen::DenseIndex ret
Definition: level1_cplx_impl.h:43
RealScalar alpha
Definition: level1_cplx_impl.h:151
Scalar beta
Definition: level2_cplx_impl.h:36
char char char int int * k
Definition: level2_impl.h:374
@ Rhs
Definition: TensorContractionMapper.h:20
bool idrs(const MatrixType &A, const Rhs &b, Dest &x, const Preconditioner &precond, Index &iter, typename Dest::RealScalar &relres, Index S, bool smoothing, typename Dest::RealScalar angle, bool replacement)
Definition: IDRS.h:58
EIGEN_DEVICE_FUNC bool isApprox(const Scalar &x, const Scalar &y, const typename NumTraits< Scalar >::Real &precision=NumTraits< Scalar >::dummy_precision())
Definition: MathFunctions.h:1923
Vector::Scalar omega(const Vector &t, const Vector &s, RealScalar angle)
Definition: IDRS.h:36
EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE std::enable_if_t< NumTraits< T >::IsSigned||NumTraits< T >::IsComplex, typename NumTraits< T >::Real > abs(const T &x)
Definition: MathFunctions.h:1355
Namespace containing all symbols from the Eigen library.
Definition: bench_norm.cpp:70
EIGEN_DEFAULT_DENSE_INDEX_TYPE Index
The Index type as used for the API.
Definition: Meta.h:83
unsigned Preconditioner
----------------------—Domain Properties------------------------—
Definition: space_time_oscillating_cylinder.cc:725
double P
Uniform pressure.
Definition: TwenteMeshGluing.cpp:77
double angle(const double &t)
Angular position as a function of time t.
Definition: jeffery_orbit.cc:98
double U
Swimming speed.
Definition: two_d_variable_diff_adapt.cc:53
r
Definition: UniformPSDSelfTest.py:20
int c
Definition: calibrate.py:100
Definition: Eigen_Colamd.h:49
Mdouble gamma(Mdouble gamma_in)
This is the gamma function returns the true value for the half integer value.
Definition: ExtendedMath.cc:116
double Zero
Definition: pseudosolid_node_update_elements.cc:35
@ S
Definition: quadtree.h:62
double epsilon
Definition: osc_ring_sarah_asymptotics.h:43
list x
Definition: plotDoE.py:28
t
Definition: plotPSD.py:36
Definition: EigenBase.h:33
Definition: ForwardDeclarations.h:21
Definition: fft_test_shared.h:66