MyraMath
gmres


Source: tests/iterative/gmres.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.
39 
40 // Reporting.
42 #include <tests/myratest.h>
43 
44 using namespace myra;
45 using namespace myra_stlprint;
46 
47 namespace {
48 
49 // Action that solves by the L factor of an ILUSolver.
50 template<class InstantiatedNumber> class solveL_Action
51  {
52  public:
53  typedef InstantiatedNumber Number;
54  solveL_Action(const ILUSolver<Number>& in_solver)
55  : solver(in_solver) { }
56  std::pair<int,int> size() const
57  { int N = solver.size(); return std::pair<int,int>(N,N); }
58  void multiply(const CMatrixRange<Number>& B, const MatrixRange<Number>& X) const
59  { X.assign(B); solver.solveL(X,'L','N'); }
60  private:
61  const ILUSolver<Number>& solver;
62  };
63 
64 // Action that solves by the U factor of an ILUSolver.
65 template<class InstantiatedNumber> class solveU_Action
66  {
67  public:
68  typedef InstantiatedNumber Number;
69  solveU_Action(const ILUSolver<Number>& in_solver)
70  : solver(in_solver) { }
71  std::pair<int,int> size() const
72  { int N = solver.size(); return std::pair<int,int>(N,N); }
73  void multiply(const CMatrixRange<Number>& B, const MatrixRange<Number>& X) const
74  { X.assign(B); solver.solveU(X,'L','N'); }
75  private:
76  const ILUSolver<Number>& solver;
77  };
78 
79 template<class Number> void test(int X, int Y, typename ReflectPrecision<Number>::type tolerance)
80  {
81  typedef typename ReflectPrecision<Number>::type Precision;
82  myra::out() << typestring<Number>() << std::endl;
83  // Construct 2D stencil with random values.
84  auto A = SparseMatrix<Number>::random(stencil2(X,Y));
85  // Add some mass to it, to make it a little better conditioned.
86  int N = X*Y;
87  Precision sigma = 2.0;
88  for (int n = 0; n < N; ++n)
89  A(n,n) += sigma;
90  A /= frobenius(A);
91  // Construct random x/b vectors.
92  auto x = Vector<Number>::random(N);
93  auto b = A*x;
94  // Solve using gmres() - no preconditioner.
95  {
96  auto m = make_IdentityAction<Number>(N);
97  auto a = make_GemmAction(A);
98  x = Vector<Number>::zeros(N);
99  auto result = gmres(m,a,b,x,tolerance);
100  Precision error = euclidean(A*x-b) / euclidean(b);
101  myra::out() << " No preconditioner:" << std::endl;
102  myra::out() << " |Ax-b| = " << error << std::endl;
103  myra::out() << " iteration count = " << result.history.size() << std::endl;
104  //myra::out() << " history = " << result.history << std::endl;
105  myra::out() << std::endl;
106  REQUIRE(error < tolerance*100);
107  }
108  // Solve using gmres() - incomplete LU preconditioner for M1.
109  {
110  ILUSolver<Number> M1(A);
111  auto m1 = make_SolveAction(M1);
112  auto m2 = make_IdentityAction<Number>(N);
113  auto a = make_GemmAction(A);
114  x = Vector<Number>::zeros(N);
115  auto result = gmres(m1,a,m2,b,x,tolerance);
116  Precision error = euclidean(A*x-b) / euclidean(b);
117  myra::out() << " ILU preconditioner (left):" << std::endl;
118  myra::out() << " |Ax-b| = " << error << std::endl;
119  myra::out() << " iteration count = " << result.history.size() << std::endl;
120  //myra::out() << " history = " << result.history << std::endl;
121  myra::out() << std::endl;
122  REQUIRE(error < tolerance*100);
123  }
124 
125  // Solve using gmres() - incomplete LU preconditioner for M2.
126  {
127  ILUSolver<Number> M2(A);
128  auto m1 = make_IdentityAction<Number>(N);
129  auto m2 = make_SolveAction(M2);
130  auto a = make_GemmAction(A);
131  x = Vector<Number>::zeros(N);
132  auto result = gmres(m1,a,m2,b,x,tolerance);
133  Precision error = euclidean(A*x-b) / euclidean(b);
134  myra::out() << " ILU preconditioner (right):" << std::endl;
135  myra::out() << " |Ax-b| = " << error << std::endl;
136  myra::out() << " iteration count = " << result.history.size() << std::endl;
137  //myra::out() << " history = " << result.history << std::endl;
138  myra::out() << std::endl;
139  REQUIRE(error < tolerance*100);
140  }
141 
142  // Solve using gmres() - incomplete LU preconditioner split into M1 (L) and M2 (U).
143  {
144  ILUSolver<Number> M(A);
145  auto m1 = make_UserAction( solveL_Action<Number>(M) );
146  auto m2 = make_UserAction( solveU_Action<Number>(M) );
147  auto a = make_GemmAction(A);
148  x = Vector<Number>::zeros(N);
149  auto result = gmres(m1,a,m2,b,x,tolerance);
150  Precision error = euclidean(A*x-b) / euclidean(b);
151  myra::out() << " ILU preconditioner (split):" << std::endl;
152  myra::out() << " |Ax-b| = " << error << std::endl;
153  myra::out() << " iteration count = " << result.history.size() << std::endl;
154  myra::out() << std::endl;
155  REQUIRE(error < tolerance*100);
156  }
157 
158  }
159 
160 } // namespace
161 
162 ADD_TEST("gmres","[iterative]")
163  {
164  test<NumberS>(20,20,1.0e-3f);
165  test<NumberD>(20,20,1.0e-6);
166  test<NumberC>(20,20,1.0e-3f);
167  test<NumberZ>(20,20,1.0e-6);
168  }
169 
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)
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
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
General purpose dense matrix container, O(i*j) storage.
Range/Iterator types associated with Pattern.
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.
Incomplete LU preconditioner. Presents a solve() function, but it&#39;s only approximate.
Returns cumulative sum of a std::vector<T>. Reversible by diff()
Helper routines for reordering/filling 2D structured grids. Used by many unit tests.
Range/Iterator types associated with SparseMatrix.


Results: [PASS]

float
No preconditioner:
|Ax-b| = 0.000987093
iteration count = 19
ILU preconditioner (left):
|Ax-b| = 3.03245e-05
iteration count = 10
ILU preconditioner (right):
|Ax-b| = 0.000284022
iteration count = 8
ILU preconditioner (split):
|Ax-b| = 0.000290397
iteration count = 8
double
No preconditioner:
|Ax-b| = 9.12586e-07
iteration count = 52
ILU preconditioner (left):
|Ax-b| = 2.34349e-08
iteration count = 17
ILU preconditioner (right):
|Ax-b| = 3.40748e-07
iteration count = 14
ILU preconditioner (split):
|Ax-b| = 3.59676e-07
iteration count = 14
std::complex<float>
No preconditioner:
|Ax-b| = 0.000951256
iteration count = 51
ILU preconditioner (left):
|Ax-b| = 1.71785e-05
iteration count = 18
ILU preconditioner (right):
|Ax-b| = 0.00082377
iteration count = 12
ILU preconditioner (split):
|Ax-b| = 0.000461446
iteration count = 13
std::complex<double>
No preconditioner:
|Ax-b| = 9.06458e-07
iteration count = 89
ILU preconditioner (left):
|Ax-b| = 1.55762e-08
iteration count = 23
ILU preconditioner (right):
|Ax-b| = 8.95171e-07
iteration count = 18
ILU preconditioner (split):
|Ax-b| = 4.33058e-07
iteration count = 19


Go back to Summary of /test programs.