Multiscale Universal Interface  2.0
A Concurrent Framework for Coupling Heterogeneous Solvers
solver_cg.h
Go to the documentation of this file.
1 /*****************************************************************************
2 * Multiscale Universal Interface Code Coupling Library *
3 * *
4 * Copyright (C) 2023 W. Liu *
5 * *
6 * This software is jointly licensed under the Apache License, Version 2.0 *
7 * and the GNU General Public License version 3, you may use it according *
8 * to either. *
9 * *
10 * ** Apache License, version 2.0 ** *
11 * *
12 * Licensed under the Apache License, Version 2.0 (the "License"); *
13 * you may not use this file except in compliance with the License. *
14 * You may obtain a copy of the License at *
15 * *
16 * http://www.apache.org/licenses/LICENSE-2.0 *
17 * *
18 * Unless required by applicable law or agreed to in writing, software *
19 * distributed under the License is distributed on an "AS IS" BASIS, *
20 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
21 * See the License for the specific language governing permissions and *
22 * limitations under the License. *
23 * *
24 * ** GNU General Public License, version 3 ** *
25 * *
26 * This program is free software: you can redistribute it and/or modify *
27 * it under the terms of the GNU General Public License as published by *
28 * the Free Software Foundation, either version 3 of the License, or *
29 * (at your option) any later version. *
30 * *
31 * This program is distributed in the hope that it will be useful, *
32 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
33 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
34 * GNU General Public License for more details. *
35 * *
36 * You should have received a copy of the GNU General Public License *
37 * along with this program. If not, see <http://www.gnu.org/licenses/>. *
38 *****************************************************************************/
39 
50 #ifndef MUI_CONJUGATE_GRADIENT_H_
51 #define MUI_CONJUGATE_GRADIENT_H_
52 
53 #include <cmath>
54 
55 namespace mui {
56 namespace linalg {
57 
58 // Constructor for one-dimensional Conjugate Gradient solver
59 template<typename ITYPE, typename VTYPE>
61  : A_(A),
62  b_(b),
63  cg_solve_tol_(cg_solve_tol),
64  cg_max_iter_(cg_max_iter),
65  M_(M){
66  assert(b_.get_cols() == 1 &&
67  "MUI Error [solver_cg.h]: Number of column of b matrix must be 1");
68  x_.resize(A_.get_rows(),1);
69  r_.resize(A_.get_rows(),1);
70  z_.resize(A_.get_rows(),1);
71  p_.resize(A_.get_rows(),1);
72 }
73 
74 // Constructor for multidimensional Conjugate Gradient solver
75 template<typename ITYPE, typename VTYPE>
77  : A_(A),
78  b_(b),
79  cg_solve_tol_(cg_solve_tol),
80  cg_max_iter_(cg_max_iter),
81  M_(M){
82  assert(A_.get_rows() == b_.get_rows() &&
83  "MUI Error [solver_cg.h]: Number of rows of A matrix must be the same as the number of rows of b matrix");
84  b_column_.resize(b_.get_rows(),1);
85  x_.resize(b_.get_rows(),b_.get_cols());
86  x_init_column_.resize(b_.get_rows(),1);
87 }
88 
89 // Destructor for one-dimensional Conjugate Gradient solver
90 template<typename ITYPE, typename VTYPE>
92  // Deallocate the memory for matrices
93  A_.set_zero();
94  x_.set_zero();
95  b_.set_zero();
96  r_.set_zero();
97  z_.set_zero();
98  p_.set_zero();
99  // Set properties to null
100  cg_solve_tol_ = 0;
101  cg_max_iter_ = 0;
102  // Deallocate the memory for preconditioner pointer
103  if(M_!=nullptr) {
104  M_ = nullptr;
105  delete[] M_;
106  }
107 }
108 
109 // Destructor for multidimensional Conjugate Gradient solver
110 template<typename ITYPE, typename VTYPE>
112  // Deallocate the memory for matrices
113  A_.set_zero();
114  x_.set_zero();
115  b_.set_zero();
116  b_column_.set_zero();
117  x_init_column_.set_zero();
118  // Set properties to null
119  cg_solve_tol_ = 0;
120  cg_max_iter_ = 0;
121  // Deallocate the memory for preconditioner pointer
122  if(M_!=nullptr) {
123  M_ = nullptr;
124  delete[] M_;
125  }
126 }
127 
128 // Member function for one-dimensional Conjugate Gradient solver to solve
129 template<typename ITYPE, typename VTYPE>
131  if (!x_init.empty()){
132  assert(((x_init.get_rows() == x_.get_rows()) && (x_init.get_cols() == x_.get_cols())) &&
133  "MUI Error [solver_cg.h]: Size of x_init matrix mismatch with size of x_ matrix");
134  // Initialize x_ with x_init
135  x_.copy(x_init);
136  // Initialise r_ with b-Ax0
137  sparse_matrix<ITYPE,VTYPE> Ax0 = A_* x_init;
138  r_.copy(b_-Ax0);
139  } else {
140  // Initialise r_ with b
141  r_.copy(b_);
142  }
143 
144  // Initialise z_ with r_
145  z_.copy(r_);
146 
147  if (M_) {
148  sparse_matrix<ITYPE,VTYPE> tempZ(z_.get_rows(), z_.get_cols());
149  tempZ = M_->apply(z_);
150  z_.set_zero();
151  z_.copy(tempZ);
152  }
153 
154  // Initialise p_ with z_
155  p_.copy(z_);
156 
157  VTYPE r_norm0 = r_.dot_product(z_);
158  assert(std::abs(r_norm0) >= std::numeric_limits<VTYPE>::min() &&
159  "MUI Error [solver_cg.h]: Divide by zero assert for r_norm0");
160  VTYPE r_norm = r_norm0;
161  VTYPE r_norm_rel = std::sqrt(r_norm/r_norm0);
162 
163  ITYPE kIter;
164  if(cg_max_iter_ == 0) {
166  } else {
167  kIter = cg_max_iter_;
168  }
169 
170  ITYPE acturalKIterCount = 0;
171 
172  for (ITYPE k = 0; k < kIter; ++k) {
173  ++acturalKIterCount;
174  sparse_matrix<ITYPE,VTYPE> Ap = A_*p_;
175  VTYPE p_dot_Ap = p_.dot_product(Ap);
176  assert(std::abs(p_dot_Ap) >= std::numeric_limits<VTYPE>::min() &&
177  "MUI Error [solver_cg.h]: Divide by zero assert for p_dot_Ap");
178  VTYPE alpha = r_norm / p_dot_Ap;
179  for (ITYPE j = 0; j < A_.get_rows(); ++j) {
180  x_.add_scalar(j, 0, (alpha * (p_.get_value(j,0))));
181  r_.subtract_scalar(j, 0, (alpha * (Ap.get_value(j,0))));
182  }
183 
184  z_.set_zero();
185  z_.copy(r_);
186 
187  if (M_) {
188  sparse_matrix<ITYPE,VTYPE> tempZ(z_.get_rows(), z_.get_cols());
189  tempZ = M_->apply(z_);
190  z_.set_zero();
191  z_.copy(tempZ);
192  }
193 
194  VTYPE updated_r_norm = r_.dot_product(z_);
195  assert(std::abs(r_norm) >= std::numeric_limits<VTYPE>::min() &&
196  "MUI Error [solver_cg.h]: Divide by zero assert for r_norm");
197  VTYPE beta = updated_r_norm / r_norm;
198  r_norm = updated_r_norm;
199  for (ITYPE j = 0; j < A_.get_rows(); ++j) {
200  p_.set_value(j, 0, (z_.get_value(j,0)+(beta*p_.get_value(j,0))));
201  }
202 
203  r_norm_rel = std::sqrt(r_norm/r_norm0);
204  if (r_norm_rel <= cg_solve_tol_) {
205  break;
206  }
207  }
208  return std::make_pair(acturalKIterCount,r_norm_rel);
209 }
210 
211 // Member function for multidimensional Conjugate Gradient solver to solve
212 template<typename ITYPE, typename VTYPE>
214  if (!x_init.empty()){
215  assert(((x_init.get_rows() == b_.get_rows()) && (x_init.get_cols() == b_.get_cols())) &&
216  "MUI Error [solver_cg.h]: Size of x_init matrix mismatch with size of b_ matrix");
217  }
218 
219  std::pair<ITYPE, VTYPE> cgReturn;
220  for (ITYPE j = 0; j < b_.get_cols(); ++j) {
221  b_column_.set_zero();
222  b_column_ = b_.segment(0,(b_.get_rows()-1),j,j);
223  conjugate_gradient_1d<ITYPE, VTYPE> cg(A_, b_column_, cg_solve_tol_, cg_max_iter_, M_);
224  if (!x_init.empty()) {
225  x_init_column_.set_zero();
226  x_init_column_ = x_init.segment(0,(x_init.get_rows()-1),j,j);
227  }
228  std::pair<ITYPE, VTYPE> cgReturnTemp = cg.solve(x_init_column_);
229  if (cgReturn.first < cgReturnTemp.first)
230  cgReturn.first = cgReturnTemp.first;
231  cgReturn.second += cgReturnTemp.second;
232  sparse_matrix<ITYPE,VTYPE> x_column(b_.get_rows(),1);
233  x_column = cg.getSolution();
234  for (ITYPE i = 0; i < x_column.get_rows(); ++i) {
235  x_.set_value(i, j, x_column.get_value(i,0));
236  }
237  }
238  cgReturn.second /= b_.get_cols();
239 
240  return cgReturn;
241 }
242 
243 // Member function for one-dimensional Conjugate Gradient solver to get the solution
244 template<typename ITYPE, typename VTYPE>
246  return x_;
247 }
248 
249 // Member function for multidimensional Conjugate Gradient solver to get the solution
250 template<typename ITYPE, typename VTYPE>
252  return x_;
253 }
254 
255 } // linalg
256 } // mui
257 
258 #endif /* MUI_CONJUGATE_GRADIENT_H_ */
Definition: solver.h:75
std::pair< ITYPE, VTYPE > solve(sparse_matrix< ITYPE, VTYPE >=sparse_matrix< ITYPE, VTYPE >())
Definition: solver_cg.h:130
sparse_matrix< ITYPE, VTYPE > getSolution()
Definition: solver_cg.h:245
~conjugate_gradient_1d()
Definition: solver_cg.h:91
conjugate_gradient_1d(sparse_matrix< ITYPE, VTYPE >, sparse_matrix< ITYPE, VTYPE >, VTYPE=1e-6, ITYPE=0, preconditioner< ITYPE, VTYPE > *=nullptr)
Definition: solver_cg.h:60
sparse_matrix< ITYPE, VTYPE > getSolution()
Definition: solver_cg.h:251
std::pair< ITYPE, VTYPE > solve(sparse_matrix< ITYPE, VTYPE >=sparse_matrix< ITYPE, VTYPE >())
Definition: solver_cg.h:213
conjugate_gradient(sparse_matrix< ITYPE, VTYPE >, sparse_matrix< ITYPE, VTYPE >, VTYPE=1e-6, ITYPE=0, preconditioner< ITYPE, VTYPE > *=nullptr)
Definition: solver_cg.h:76
~conjugate_gradient()
Definition: solver_cg.h:111
Definition: preconditioner.h:55
Definition: matrix.h:61
ITYPE get_rows() const
Definition: matrix_io_info.h:579
VTYPE dot_product(sparse_matrix< ITYPE, VTYPE > &) const
Definition: matrix_arithmetic.h:759
void set_zero()
Definition: matrix_manipulation.h:418
VTYPE get_value(ITYPE, ITYPE) const
Definition: matrix_io_info.h:523
sparse_matrix< ITYPE, VTYPE > segment(ITYPE, ITYPE, ITYPE, ITYPE, bool=true)
Definition: matrix_manipulation.h:153
ITYPE get_cols() const
Definition: matrix_io_info.h:585
void copy(const sparse_matrix< ITYPE, VTYPE > &)
Definition: matrix_manipulation.h:79
bool empty() const
Definition: matrix_io_info.h:665
u u u u u u min
Definition: dim.h:289
Definition: comm.h:54
SCALAR max(vexpr< E, SCALAR, D > const &u)
Definition: point.h:350