MyraMath
fgmres


Source: tests/iterative/fgmres.cpp

1 // ========================================================================= //
2 // This file is part of MyraMath, copyright (c) 2014-2019 by Ryan A Chilton //
3 // and distributed by MyraCore, LLC. See LICENSE.txt for license terms. //
4 // ========================================================================= //
5 
11 // Containers.
13 #include <myramath/dense/Matrix.h>
15 #include <myramath/dense/Vector.h>
22 
23 // Algorithms.
25 #include <myramath/dense/inverse.h>
27 #include <myramath/sparse/gemm.h>
28 #include <myramath/sparse/gemv.h>
31 
32 // Iterative solve/action stuff.
42 
43 // Reporting.
44 #include <myramath/utility/Timer.h>
46 #include <tests/myratest.h>
47 
48 using namespace myra;
49 using namespace myra_stlprint;
50 
51 namespace {
52 
53 // Action that solves by the L factor of an ILUSolver.
54 template<class InstantiatedNumber> class solveL_Action
55  {
56  public:
57  typedef InstantiatedNumber Number;
58  solveL_Action(const ILUSolver<Number>& in_solver)
59  : solver(in_solver) { }
60  std::pair<int,int> size() const
61  { int N = solver.size(); return std::pair<int,int>(N,N); }
62  void multiply(const CMatrixRange<Number>& B, const MatrixRange<Number>& X) const
63  { X.assign(B); solver.solveL(X,'L','N'); }
64  private:
65  const ILUSolver<Number>& solver;
66  };
67 
68 // Action that solves by the U factor of an ILUSolver.
69 template<class InstantiatedNumber> class solveU_Action
70  {
71  public:
72  typedef InstantiatedNumber Number;
73  solveU_Action(const ILUSolver<Number>& in_solver)
74  : solver(in_solver) { }
75  std::pair<int,int> size() const
76  { int N = solver.size(); return std::pair<int,int>(N,N); }
77  void multiply(const CMatrixRange<Number>& B, const MatrixRange<Number>& X) const
78  { X.assign(B); solver.solveU(X,'L','N'); }
79  private:
80  const ILUSolver<Number>& solver;
81  };
82 
83 // Action that applies gmres()
84 template<class InstantiatedNumber> class gmres_Action
85  {
86  public:
87 
88  // Required typedef.
89  typedef InstantiatedNumber Number;
90  typedef typename ReflectPrecision<Number>::type Precision;
91 
93  gmres_Action(const Action<Number>& in_A, Precision in_tol, int in_iter)
94  : A(in_A), tol(in_tol), iter(in_iter) { M = make_IdentityAction<Number>(A.size().first); }
95 
97  std::pair<int,int> size() const
98  { return A.size(); }
99 
101  void multiply (const CMatrixRange<Number>& B, const MatrixRange<Number>& X) const
102  { X.zero(); auto output = gmres(M,A,B,X,tol,iter); }
103 
104  private:
105 
106  // Captured environment for inner gmres()
107  Action<Number> M;
108  Action<Number> A;
109  Precision tol;
110  int iter;
111 
112  };
113 
114 template<class Number> void test(int I, int J, typename ReflectPrecision<Number>::type tolerance)
115  {
116  typedef typename ReflectPrecision<Number>::type Precision;
117  myra::out() << typestring<Number>() << std::endl;
118  int N = I*J;
119  auto A = SparseMatrix<Number>::random(stencil2(I,J));
120  Precision sigma = 2.0;
121  for (int n = 0; n < N; ++n)
122  A(n,n) += sigma;
123  auto y = Vector<Number>::random(N);
124  auto b = A*y;
125  ILUSolver<Number> solver(A);
126 
127  // Instantiate actions for subsequent test cases.
128  auto a = make_GemmAction(A);
129  auto i = make_IdentityAction<Number>(N);
130  auto z = make_SolveAction(solver);
131  auto l = make_UserAction(solveL_Action<Number>(solver));
132  auto u = make_UserAction(solveU_Action<Number>(solver));
133  auto g = make_UserAction(gmres_Action<Number>(z*a,1.0e-2,20));
134 
135  // Solve using gmres(), left ILU.
136  {
137  auto x = Vector<Number>::zeros(N);
138  auto result = gmres(z,a,b,x,tolerance,500);
139  Precision error = euclidean(A*x-b) / euclidean(b);
140  myra::out() << "gmres, left ILU:" << std::endl;
141  myra::out() << " |Ax-b| = " << error << std::endl;
142  myra::out() << " iteration count = " << result.history.size() << std::endl;
143  myra::out() << std::endl;
144  REQUIRE(error < tolerance*100);
145  }
146 
147  // Solve using fgmres(), left ILU.
148  {
149  auto x = Vector<Number>::zeros(N);
150  auto result = fgmres(z,a,i,b,x,tolerance,500);
151  Precision error = euclidean(A*x-b) / euclidean(b);
152  myra::out() << "fgmres, left ILU:" << std::endl;
153  myra::out() << " |Ax-b| = " << error << std::endl;
154  myra::out() << " iteration count = " << result.history.size() << std::endl;
155  myra::out() << std::endl;
156  REQUIRE(error < tolerance*100);
157  }
158 
159  // Solve using fgmres(), right ILU.
160  {
161  auto x = Vector<Number>::zeros(N);
162  auto result = fgmres(i,a,z,b,x,tolerance,500);
163  Precision error = euclidean(A*x-b) / euclidean(b);
164  myra::out() << "fgmres, right ILU:" << std::endl;
165  myra::out() << " |Ax-b| = " << error << std::endl;
166  myra::out() << " iteration count = " << result.history.size() << std::endl;
167  myra::out() << std::endl;
168  REQUIRE(error < tolerance*100);
169  }
170 
171  // Solve using fgmres(), split ILU.
172  {
173  auto x = Vector<Number>::zeros(N);
174  auto result = fgmres(l,a,u,b,x,tolerance,500);
175  Precision error = euclidean(A*x-b) / euclidean(b);
176  myra::out() << "fgmres, split ILU:" << std::endl;
177  myra::out() << " |Ax-b| = " << error << std::endl;
178  myra::out() << " iteration count = " << result.history.size() << std::endl;
179  myra::out() << std::endl;
180  REQUIRE(error < tolerance*100);
181  }
182 
183  // Solve using restarted gmres(), left ILU. Expected to fail, restarts impede convergence.
184  {
185  auto x = Vector<Number>::zeros(N);
186  auto result = gmres(z,a,b,x,tolerance,20,20);
187  Precision error = euclidean(A*x-b) / euclidean(b);
188  myra::out() << "restarted gmres, left ILU:" << std::endl;
189  myra::out() << " |Ax-b| = " << error << std::endl;
190  myra::out() << " iteration count = " << result.history.size() << std::endl;
191  myra::out() << std::endl;
192  // REQUIRE(error < tolerance*100); // will be big
193  }
194 
195  // Solve using fgmres() with M1=ILUSolver and M2=inaccurate gmres(M1*A). Expected to work.
196  {
197  auto x = Vector<Number>::zeros(N);
198  auto result = fgmres(z,a,g,b,x,tolerance,500);
199  Precision error = euclidean(A*x-b) / euclidean(b);
200  myra::out() << "fgmres, left ILU and right inner gmres:" << std::endl;
201  myra::out() << " |Ax-b| = " << error << std::endl;
202  myra::out() << " iteration count = " << result.history.size() << std::endl;
203  myra::out() << std::endl;
204  REQUIRE(error < tolerance*100);
205  }
206 
207  // Solve using gmres() with M1=ILUSolver and M2=inaccurate gmres(M1*A). This is not
208  // expected to work, because the preconditioner is effectively changing from one outer
209  // gmres() iteration to the next, due to the limits imposed on inner gmres() tolerance
210  // and iteration count. It will converge, but the final solution will not be correct.
211  {
212  auto x = Vector<Number>::zeros(N);
213  auto result = gmres(z,a,g,b,x,tolerance,500);
214  Precision error = euclidean(A*x-b) / euclidean(b);
215  myra::out() << "gmres, left ILU and right inner gmres:" << std::endl;
216  myra::out() << " |Ax-b| = " << error << std::endl;
217  myra::out() << " iteration count = " << result.history.size() << std::endl;
218  myra::out() << std::endl;
219  // REQUIRE(error < tolerance*100); // will be big
220  }
221 
222  }
223 
224 } // namespace
225 
226 ADD_TEST("fgmres","[iterative]")
227  {
228  test<NumberD>(20,20,1.0e-8);
229  test<NumberZ>(20,20,1.0e-8);
230  }
231 
232 ADD_TEST("fgmres_big","[iterative][.]")
233  {
234  test<NumberD>(100,50,1.0e-8);
235  test<NumberZ>(100,50,1.0e-8);
236  }
237 
Routines for computing euclidean norm of a Vector/VectorRange, or normalizing a Vector/VectorRange to...
Action< typename UserClass::Number > make_UserAction(const UserClass &u)
Helper function to adapt some user code (encapsulated in a class) into an Action. ...
Definition: UserAction.h:61
Incompletely factors A ~= L*U, presents approximate solve() method.
Definition: ILUSolver.h:28
Interface class for representing subranges of dense Matrix&#39;s.
Interface class for representing subranges of dense Vector&#39;s.
Applies the "Action" of a linear operator, b := A*x, used in iterative solution algorithms.
Variety of routines for mixed dense*sparse or dense*sparse matrix multiplies. The dense*dense case is...
void assign(const CMatrixRange< Number > &that) const
Assigns the values in *this with the values in that.
Definition: MatrixRange.cpp:268
Linear system solution via gmres (for invertible action A)
Simplistic timing class, might dispatch to platform specific timers depending upon environment...
static SparseMatrix< Number > random(int I, int J, int N)
Generates a random SparseMatrix with size IxJ and (approximately) N nonzeros.
Definition: SparseMatrix.cpp:493
Linear system solution via (flexible) fgmres (for invertible action A)
General purpose compressed-sparse-column (CSC) container.
static Vector< Number > random(int N)
Generates a random Vector of specified size.
Definition: Vector.cpp:276
Definition: syntax.dox:1
Represents a const MatrixRange.
Definition: bothcat.h:22
An Action that is just the identity operator.
Definition: stlprint.h:32
Adapts user code (encapsulated in a class) into an Action.
Action< typename ReflectNumber< Solver >::type > make_SolveAction(const Solver &solver, char op='N')
Free function for making SolveAction&#39;s.
Definition: SolveAction.h:67
Routines for printing the contents of various std::container&#39;s to a std::ostream using operator <<...
Various utility functions/classes related to scalar Number types.
Signatures for sparse matrix * dense vector multiplies. All delegate to gemm() under the hood...
Represents a mutable MatrixRange.
Definition: conjugate.h:26
static Vector< Number > zeros(int N)
Generates a zeros Vector of specified size.
Definition: Vector.cpp:280
Composes two Action&#39;s A and B, yielding an Action that cascades A*(B*X)
General purpose dense matrix container, O(i*j) storage.
Range/Iterator types associated with Pattern.
Applies the "Action" of a linear operator, b := A*x.
Definition: Action.h:29
Container for either a column vector or row vector (depends upon the usage context) ...
Reflects Precision trait for a Number, scalar Number types should specialize it.
Definition: Number.h:33
Container class for a sparse nonzero pattern, used in reordering/symbolic analysis.
Overwrites a LowerMatrix, DiagonalMatrix, or square Matrix with its own inverse. Or, returns it as a copy.
Adapts a class with a .solve() method into an Action.
An Action for multiplying by a dense Matrix or SparseMatrix using gemm().
Returns frobenius norm of a SparseMatrix.
std::pair< int, int > size() const
Size inspector.
Definition: Matrix.cpp:116
Incomplete LU preconditioner. Presents a solve() function, but it&#39;s only approximate.
Returns cumulative sum of a std::vector<T>. Reversible by diff()
void zero() const
Assigns zero to every entry.
Definition: MatrixRange.cpp:362
Helper routines for reordering/filling 2D structured grids. Used by many unit tests.
Range/Iterator types associated with SparseMatrix.


Results: [PASS]

double
gmres, left ILU:
|Ax-b| = 4.37427e-09
iteration count = 19
fgmres, left ILU:
|Ax-b| = 4.37427e-09
iteration count = 19
fgmres, right ILU:
|Ax-b| = 4.0265e-09
iteration count = 19
fgmres, split ILU:
|Ax-b| = 4.14965e-09
iteration count = 19
restarted gmres, left ILU:
|Ax-b| = 4.37427e-09
iteration count = 19
fgmres, left ILU and right inner gmres:
|Ax-b| = 1.76921e-09
iteration count = 5
gmres, left ILU and right inner gmres:
|Ax-b| = 0.00393714
iteration count = 5
std::complex<double>
gmres, left ILU:
|Ax-b| = 7.80565e-09
iteration count = 27
fgmres, left ILU:
|Ax-b| = 7.80565e-09
iteration count = 27
fgmres, right ILU:
|Ax-b| = 7.10404e-09
iteration count = 27
fgmres, split ILU:
|Ax-b| = 7.75107e-09
iteration count = 27
restarted gmres, left ILU:
|Ax-b| = 1.02763e-08
iteration count = 30
fgmres, left ILU and right inner gmres:
|Ax-b| = 2.47425e-09
iteration count = 5
gmres, left ILU and right inner gmres:
|Ax-b| = 0.00028365
iteration count = 5


Go back to Summary of /test programs.