GetFEM  5.5
gmm_precond_ilutp.h
Go to the documentation of this file.
1 /* -*- c++ -*- (enables emacs c++ mode) */
2 /*===========================================================================
3 
4  Copyright (C) 2004-2026 Yves Renard
5 
6  This file is a part of GetFEM
7 
8  GetFEM is free software; you can redistribute it and/or modify it
9  under the terms of the GNU Lesser General Public License as published
10  by the Free Software Foundation; either version 3 of the License, or
11  (at your option) any later version along with the GCC Runtime Library
12  Exception either version 3.1 or (at your option) any later version.
13  This program is distributed in the hope that it will be useful, but
14  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
16  License and GCC Runtime Library Exception for more details.
17  You should have received a copy of the GNU Lesser General Public License
18  along with this program. If not, see https://www.gnu.org/licenses/.
19 
20  As a special exception, you may use this file as it is a part of a free
21  software library without restriction. Specifically, if other files
22  instantiate templates or use macros or inline functions from this file,
23  or you compile this file and link it with other files to produce an
24  executable, this file does not by itself cause the resulting executable
25  to be covered by the GNU Lesser General Public License. This exception
26  does not however invalidate any other reasons why the executable file
27  might be covered by the GNU Lesser General Public License.
28 
29 ===========================================================================*/
30 
31 /**@file gmm_precond_ilutp.h
32  @author Yves Renard <[email protected]>
33  @date October 14, 2004.
34  @brief ILUTP: Incomplete LU with threshold and K fill-in Preconditioner and
35  column pivoting.
36 
37 
38 */
39 #ifndef GMM_PRECOND_ILUTP_H
40 #define GMM_PRECOND_ILUTP_H
41 
42 #include "gmm_precond_ilut.h"
43 
44 namespace gmm {
45 
46  /**
47  ILUTP: Incomplete LU with threshold and K fill-in Preconditioner and
48  column pivoting.
49 
50  See Yousef Saad, Iterative Methods for
51  sparse linear systems, PWS Publishing Company, section 10.4.4
52 
53  TODO : store the permutation by cycles to avoid the temporary vector
54  */
55  template <typename Matrix>
56  class ilutp_precond {
57  public :
58  typedef typename linalg_traits<Matrix>::value_type value_type;
61  typedef row_matrix<_rsvector> LU_Matrix;
62  typedef col_matrix<_wsvector> CLU_Matrix;
63 
64  bool invert;
65  LU_Matrix L, U;
66  gmm::unsorted_sub_index indperm;
67  gmm::unsorted_sub_index indperminv;
68  mutable std::vector<value_type> temporary;
69 
70  protected:
71  size_type K;
72  double eps;
73 
74  template<typename M> void do_ilutp(const M&, row_major);
75  void do_ilutp(const Matrix&, col_major);
76 
77  public:
78  void build_with(const Matrix& A, int k_ = -1, double eps_ = double(-1)) {
79  if (k_ >= 0) K = k_;
80  if (eps_ >= double(0)) eps = eps_;
81  invert = false;
82  gmm::resize(L, mat_nrows(A), mat_ncols(A));
83  gmm::resize(U, mat_nrows(A), mat_ncols(A));
84  do_ilutp(A, typename principal_orientation_type<typename
85  linalg_traits<Matrix>::sub_orientation>::potype());
86  }
87  ilutp_precond(const Matrix& A, size_type k_, double eps_)
88  : L(mat_nrows(A), mat_ncols(A)), U(mat_nrows(A), mat_ncols(A)),
89  K(k_), eps(eps_) { build_with(A); }
90  ilutp_precond(int k_, double eps_) : K(k_), eps(eps_) {}
91  ilutp_precond(void) { K = 10; eps = 1E-7; }
92  size_type memsize() const {
93  return sizeof(*this) + (nnz(U)+nnz(L))*sizeof(value_type);
94  }
95  };
96 
97 
98  template<typename Matrix> template<typename M>
99  void ilutp_precond<Matrix>::do_ilutp(const M& A, row_major) {
100  typedef value_type T;
101  typedef typename number_traits<T>::magnitude_type R;
102 
103  size_type n = mat_nrows(A);
104  CLU_Matrix CU(n,n);
105  if (n == 0) return;
106  std::vector<T> indiag(n);
107  temporary.resize(n);
108  std::vector<size_type> ipvt(n), ipvtinv(n);
109  for (size_type i = 0; i < n; ++i) ipvt[i] = ipvtinv[i] = i;
110  indperm = unsorted_sub_index(ipvt);
111  indperminv = unsorted_sub_index(ipvtinv);
112  _wsvector w(mat_ncols(A));
113  _rsvector ww(mat_ncols(A));
114 
115  T tmp = T(0);
116  gmm::clear(L); gmm::clear(U);
117  R prec = default_tol(R());
118  R max_pivot = gmm::abs(A(0,0)) * prec;
119 
120  for (size_type i = 0; i < n; ++i) {
121 
122  copy(sub_vector(mat_const_row(A, i), indperm), w);
123  double norm_row = gmm::vect_norm2(mat_const_row(A, i));
124 
125  typename _wsvector::iterator wkold = w.end();
126  for (typename _wsvector::iterator wk = w.begin();
127  wk != w.end() && wk->first < i; ) {
128  size_type k = wk->first;
129  tmp = (wk->second) * indiag[k];
130  if (gmm::abs(tmp) < eps * norm_row) w.erase(k);
131  else { wk->second += tmp; gmm::add(scaled(mat_row(U, k), -tmp), w); }
132  if (wkold == w.end()) wk = w.begin(); else { wk = wkold; ++wk; }
133  if (wk != w.end() && wk->first == k)
134  { if (wkold == w.end()) wkold = w.begin(); else ++wkold; ++wk; }
135  }
136 
137  gmm::clean(w, eps * norm_row);
138  gmm::copy(w, ww);
139 
140  std::sort(ww.begin(), ww.end(), elt_rsvector_value_less_<T>());
141  typename _rsvector::const_iterator wit = ww.begin(), wite = ww.end();
142  size_type ip = size_type(-1);
143 
144  for (; wit != wite; ++wit)
145  if (wit->c >= i) { ip = wit->c; tmp = wit->e; break; }
146  if (ip == size_type(-1) || gmm::abs(tmp) <= max_pivot)
147  { GMM_WARNING2("pivot " << i << " too small"); ip=i; ww[i]=tmp=T(1); }
148  max_pivot = std::max(max_pivot, std::min(gmm::abs(tmp) * prec, R(1)));
149  indiag[i] = T(1) / tmp;
150  wit = ww.begin();
151 
152  size_type nnl = 0, nnu = 0;
153  L[i].base_resize(K); U[i].base_resize(K+1);
154  typename _rsvector::iterator witL = L[i].begin(), witU = U[i].begin();
155  for (; wit != wite; ++wit) {
156  if (wit->c < i) { if (nnl < K) { *witL++ = *wit; ++nnl; } }
157  else if (nnu < K || wit->c == i)
158  { CU(i, wit->c) = wit->e; *witU++ = *wit; ++nnu; }
159  }
160  L[i].base_resize(nnl); U[i].base_resize(nnu);
161  std::sort(L[i].begin(), L[i].end());
162  std::sort(U[i].begin(), U[i].end());
163 
164  if (ip != i) {
165  typename _wsvector::const_iterator iti = CU.col(i).begin();
166  typename _wsvector::const_iterator itie = CU.col(i).end();
167  typename _wsvector::const_iterator itp = CU.col(ip).begin();
168  typename _wsvector::const_iterator itpe = CU.col(ip).end();
169 
170  while (iti != itie && itp != itpe) {
171  if (iti->first < itp->first)
172  { U.row(iti->first).swap_indices(i, ip); ++iti; }
173  else if (iti->first > itp->first)
174  { U.row(itp->first).swap_indices(i,ip);++itp; }
175  else
176  { U.row(iti->first).swap_indices(i, ip); ++iti; ++itp; }
177  }
178 
179  for( ; iti != itie; ++iti) U.row(iti->first).swap_indices(i, ip);
180  for( ; itp != itpe; ++itp) U.row(itp->first).swap_indices(i, ip);
181 
182  CU.swap_col(i, ip);
183 
184  indperm.swap(i, ip);
185  indperminv.swap(ipvt[i], ipvt[ip]);
186  std::swap(ipvtinv[ipvt[i]], ipvtinv[ipvt[ip]]);
187  std::swap(ipvt[i], ipvt[ip]);
188  }
189  }
190  }
191 
192  template<typename Matrix>
193  void ilutp_precond<Matrix>::do_ilutp(const Matrix& A, col_major) {
194  do_ilutp(gmm::transposed(A), row_major());
195  invert = true;
196  }
197 
198  template <typename Matrix, typename V1, typename V2> inline
199  void mult(const ilutp_precond<Matrix>& P, const V1 &v1, V2 &v2) {
200  if (P.invert) {
201  gmm::copy(gmm::sub_vector(v1, P.indperm), v2);
202  gmm::lower_tri_solve(gmm::transposed(P.U), v2, false);
203  gmm::upper_tri_solve(gmm::transposed(P.L), v2, true);
204  }
205  else {
206  gmm::copy(v1, P.temporary);
207  gmm::lower_tri_solve(P.L, P.temporary, true);
208  gmm::upper_tri_solve(P.U, P.temporary, false);
209  gmm::copy(gmm::sub_vector(P.temporary, P.indperminv), v2);
210  }
211  }
212 
213  template <typename Matrix, typename V1, typename V2> inline
214  void transposed_mult(const ilutp_precond<Matrix>& P,const V1 &v1,V2 &v2) {
215  if (P.invert) {
216  gmm::copy(v1, P.temporary);
217  gmm::lower_tri_solve(P.L, P.temporary, true);
218  gmm::upper_tri_solve(P.U, P.temporary, false);
219  gmm::copy(gmm::sub_vector(P.temporary, P.indperminv), v2);
220  }
221  else {
222  gmm::copy(gmm::sub_vector(v1, P.indperm), v2);
223  gmm::lower_tri_solve(gmm::transposed(P.U), v2, false);
224  gmm::upper_tri_solve(gmm::transposed(P.L), v2, true);
225  }
226  }
227 
228  template <typename Matrix, typename V1, typename V2> inline
229  void left_mult(const ilutp_precond<Matrix>& P, const V1 &v1, V2 &v2) {
230  if (P.invert) {
231  gmm::copy(gmm::sub_vector(v1, P.indperm), v2);
232  gmm::lower_tri_solve(gmm::transposed(P.U), v2, false);
233  }
234  else {
235  copy(v1, v2);
236  gmm::lower_tri_solve(P.L, v2, true);
237  }
238  }
239 
240  template <typename Matrix, typename V1, typename V2> inline
241  void right_mult(const ilutp_precond<Matrix>& P, const V1 &v1, V2 &v2) {
242  if (P.invert) {
243  copy(v1, v2);
244  gmm::upper_tri_solve(gmm::transposed(P.L), v2, true);
245  }
246  else {
247  copy(v1, P.temporary);
248  gmm::upper_tri_solve(P.U, P.temporary, false);
249  gmm::copy(gmm::sub_vector(P.temporary, P.indperminv), v2);
250  }
251  }
252 
253  template <typename Matrix, typename V1, typename V2> inline
254  void transposed_left_mult(const ilutp_precond<Matrix>& P, const V1 &v1,
255  V2 &v2) {
256  if (P.invert) {
257  copy(v1, P.temporary);
258  gmm::upper_tri_solve(P.U, P.temporary, false);
259  gmm::copy(gmm::sub_vector(P.temporary, P.indperminv), v2);
260  }
261  else {
262  copy(v1, v2);
263  gmm::upper_tri_solve(gmm::transposed(P.L), v2, true);
264  }
265  }
266 
267  template <typename Matrix, typename V1, typename V2> inline
268  void transposed_right_mult(const ilutp_precond<Matrix>& P, const V1 &v1,
269  V2 &v2) {
270  if (P.invert) {
271  copy(v1, v2);
272  gmm::lower_tri_solve(P.L, v2, true);
273  }
274  else {
275  gmm::copy(gmm::sub_vector(v1, P.indperm), v2);
276  gmm::lower_tri_solve(gmm::transposed(P.U), v2, false);
277  }
278  }
279 
280 }
281 
282 #endif
283 
ILUTP: Incomplete LU with threshold and K fill-in Preconditioner and column pivoting.
sparse vector built upon std::vector.
Definition: gmm_vector.h:995
sparse vector built upon std::map.
Definition: gmm_vector.h:752
size_type nnz(const L &l)
count the number of non-zero entries of a vector or matrix.
Definition: gmm_blas.h:68
void copy(const L1 &l1, L2 &l2)
*‍/
Definition: gmm_blas.h:976
number_traits< typename linalg_traits< V >::value_type >::magnitude_type vect_norm2(const V &v)
Euclidean norm of a vector.
Definition: gmm_blas.h:556
void clear(L &l)
clear (fill with zeros) a vector or matrix.
Definition: gmm_blas.h:58
void resize(V &v, size_type n)
*‍/
Definition: gmm_blas.h:209
void clean(L &l, double threshold)
Clean a vector or matrix (replace near-zero entries with zeroes).
void mult(const L1 &l1, const L2 &l2, L3 &l3)
*‍/
Definition: gmm_blas.h:1663
void add(const L1 &l1, L2 &l2)
*‍/
Definition: gmm_blas.h:1275
ILUT: Incomplete LU with threshold and K fill-in Preconditioner.
size_t size_type
used as the common size type in the library
Definition: bgeot_poly.h:48