Alien  1.3.0
User documentation
Loading...
Searching...
No Matches
ChebyshevPreconditioner.h
1/*
2 * Copyright 2020 IFPEN-CEA
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *
16 * SPDX-License-Identifier: Apache-2.0
17 */
18#pragma once
19
20#include <random>
21#include <iostream>
22
23/**
24 *
25 * G = (I-omega*A)
26 * A-1 =omega*(I-G)-1=omega*(I+G+G2+...)
27 */
28namespace Alien
29{
30
31template <typename AlgebraT, bool saad = false>
32class ChebyshevPreconditioner
33{
34 public:
35 // clang-format off
36 static const bool m_use_saad_algo = saad;
37 typedef AlgebraT AlgebraType;
38 typedef typename AlgebraType::Matrix MatrixType;
39 typedef typename AlgebraType::Vector VectorType;
40 typedef typename MatrixType::ValueType ValueType;
41 // clang-format on
42
43 ChebyshevPreconditioner(AlgebraType& algebra,
44 MatrixType const& matrix,
45 ValueType factor,
46 int polynome_order,
47 int factor_max_iter,
48 ITraceMng* trace_mng = nullptr)
49 : m_algebra(algebra)
50 , m_matrix(matrix)
51 , m_factor(factor)
52 , m_polynome_order(polynome_order)
53 , m_factor_max_iter(factor_max_iter)
54 , m_trace_mng(trace_mng)
55 {}
56
57 virtual ~ChebyshevPreconditioner()
58 {
59 m_algebra.free(m_inv_diag, m_y, m_r);
60 if (m_use_saad_algo) {
61 m_algebra.free(m_w);
62 }
63 else {
64 m_algebra.free(m_p, m_z);
65 }
66 };
67
68 void setOutputLevel(int level)
69 {
70 m_output_level = level;
71 }
72
73 void init()
74 {
75 m_algebra.allocate(AlgebraType::resource(m_matrix), m_y, m_r);
76 m_algebra.assign(m_y, 0.);
77 m_algebra.assign(m_r, 0.);
78 if (m_use_saad_algo) {
79 m_algebra.allocate(AlgebraType::resource(m_matrix), m_w);
80 m_algebra.assign(m_w, 0.);
81 }
82 else {
83 m_algebra.allocate(AlgebraType::resource(m_matrix), m_p, m_z);
84 m_algebra.assign(m_p, 0.);
85 m_algebra.assign(m_z, 0.);
86 }
87
88 m_algebra.allocate(AlgebraType::resource(m_matrix), m_inv_diag);
89 m_algebra.assign(m_inv_diag, 1.);
90 m_algebra.computeInvDiag(m_matrix, m_inv_diag);
91
92 if (m_beta == 0) {
93 computeBeta();
94 }
95
96 if (m_alpha == 0) {
97 computeAlpha();
98 }
99 if (m_factor != 0.)
100 m_alpha = m_beta / m_factor;
101
102 m_delta = (m_beta - m_alpha) / 2;
103 m_theta = (m_beta + m_alpha) / 2;
104
105 if (m_trace_mng) {
106 m_trace_mng->info() << "CHEBYSHEV PRECONDITIONER";
107 m_trace_mng->info() << "Polynome Degree : " << m_polynome_order;
108 m_trace_mng->info() << "User EigenValue Ratio : " << m_factor;
109 m_trace_mng->info() << "Power Method Max Iter : " << m_factor_max_iter;
110 m_trace_mng->info() << "ALPHA : " << m_alpha;
111 m_trace_mng->info() << "BETA : " << m_beta;
112 m_trace_mng->info() << "EigenValue Ratio : " << m_beta / m_alpha;
113 m_trace_mng->info() << "THETA : " << m_theta;
114 m_trace_mng->info() << "DELTA : " << m_delta;
115 }
116 }
117
118 void computeBeta()
119 {
120 VectorType x;
121 m_algebra.allocate(AlgebraType::resource(m_matrix), x);
122 std::random_device rd;
123 //std::mt19937 gen(rd());
124 std::mt19937 gen;
125 std::uniform_real_distribution<> dis(-1., 1.);
126
127 m_algebra.assign(x, [&]([[maybe_unused]] std::size_t i) {
128 return dis(gen);
129 });
130 /*
131 for (std::size_t i = 0; i < x.getAllocSize(); ++i)
132 {
133 x[i] =dis(gen);
134 }*/
135
136 //m_algebra.assign(x,1.) ;
137 ValueType norm = m_algebra.norm2(x);
138 m_algebra.scal(1 / norm, x);
139
140 for (int i = 0; i < m_factor_max_iter; ++i) {
141 m_algebra.mult(m_matrix, x, m_y);
142 m_algebra.pointwiseMult(m_inv_diag, m_y, m_y);
143 ValueType xAx = m_algebra.dot(m_y, x);
144 ValueType xdx = m_algebra.dot(x, x);
145 ValueType norme = m_algebra.norm2(m_y);
146 m_algebra.scal(1 / norme, m_y);
147 m_algebra.copy(m_y, x);
148 m_beta = xAx / xdx;
149 if (m_trace_mng && m_output_level > 1)
150 m_trace_mng->info() << "Iter(" << i << ") : beta ratio=" << m_beta;
151 }
152 if (m_trace_mng)
153 m_trace_mng->info() << "Max eigen value : " << m_beta;
154
155 m_algebra.free(x);
156 }
157
158 void computeAlpha()
159 {
160
161 VectorType x;
162 m_algebra.allocate(AlgebraType::resource(m_matrix), x);
163
164 std::random_device rd;
165 //std::mt19937 gen(rd());
166 std::mt19937 gen;
167 std::uniform_real_distribution<> dis(-1., 1.);
168 /*
169 for (std::size_t i = 0; i < x.getAllocSize(); ++i)
170 {
171 x[i] =dis(gen);
172 }*/
173
174 m_algebra.assign(x, [&]([[maybe_unused]] std::size_t i) {
175 return dis(gen);
176 });
177 //m_algebra.assign(x,1.) ;
178
179 ValueType norm = m_algebra.norm2(x);
180 m_algebra.scal(1 / norm, x);
181
182 for (int i = 0; i < m_factor_max_iter; ++i) {
183 m_algebra.mult(m_matrix, x, m_y);
184 m_algebra.pointwiseMult(m_inv_diag, m_y, m_y);
185 m_algebra.axpy(-m_beta, x, m_y);
186
187 ValueType xAx = m_algebra.dot(m_y, x);
188 ValueType xdx = m_algebra.dot(x, x);
189 m_alpha = xAx / xdx;
190 if (m_trace_mng && m_output_level > 1)
191 m_trace_mng->info() << "Iter(" << i << ") : alpha ratio=" << m_alpha;
192
193 ValueType norme = m_algebra.norm2(m_y);
194 m_algebra.scal(1 / norme, m_y);
195 m_algebra.copy(m_y, x);
196 }
197 m_alpha += m_beta;
198 if (m_trace_mng)
199 m_trace_mng->info() << "Min eigen value : " << m_alpha;
200
201 m_algebra.free(x);
202 }
203
204 void solve1(const VectorType& x, //! input
205 VectorType& y //! output
206 ) const
207 {
208 /*
209 * r = invD(b - Ax)
210 * s = theta/delta
211 * rho_old = 1/sigma
212 * d = 1/theta * r
213 * do k=0,k<degree
214 * y = y + d
215 * r = r - invD.A.d
216 * rho = (2*sigma -rho_old)^-1
217 * d = rho*rho_old d + 2*rho/delta r
218 * rho_old = rho
219 * enddo
220 */
221 //m_algebra.copy(x,y) ;
222 //m_algebra.mult(m_matrix,x,m_y) ;
223 //m_algebra.axpy(-1.,m_y,m_r) ;
224 //m_algebra.copy(x,m_r) ;
225 m_algebra.xyz(m_inv_diag, x, m_r);
226 m_trace_mng->info() << "||R||" << m_algebra.norm2(m_r);
227
228 ValueType sigma = m_theta / m_delta;
229 ValueType rho_old = 1. / sigma;
230 ValueType rho = rho_old;
231 m_algebra.copy(m_r, m_w);
232 m_algebra.scal(1 / m_theta, m_w);
233 m_algebra.copy(m_w, y);
234
235 for (int k = 1; k < m_polynome_order; ++k) {
236 // R = R +invD*A.W
237 m_algebra.mult(m_matrix, m_w, m_y);
238 m_algebra.xyz(m_inv_diag, m_y, m_y);
239 m_algebra.axpy(-1., m_y, m_r);
240 m_trace_mng->info() << k << " "
241 << "||R||" << m_algebra.norm2(m_r);
242
243 rho = 1. / (2 * sigma - rho_old);
244
245 m_algebra.scal(rho * rho_old, m_w);
246 m_algebra.axpy(2 * rho / m_delta, m_r, m_w);
247 rho_old = rho;
248
249 m_algebra.axpy(1., m_w, y);
250 }
251 }
252
253 void solve2(VectorType const& x, //! input
254 VectorType& y //! output
255 ) const
256 {
257
258 const ValueType d = (m_beta + m_alpha) / 2; // Ifpack2 calls this theta
259 const ValueType c = (m_beta - m_alpha) / 2; // Ifpack2 calls this 1/delta
260
261 m_algebra.copy(x, y);
262
263 m_algebra.mult(m_matrix, y, m_y);
264 m_algebra.copy(x, m_r);
265 m_algebra.axpy(-1., m_y, m_r);
266
267 //solve (Z, D_inv, R); // z = D_inv * R, that is, D \ R.
268 //m_algebra.copy(m_r,m_z) ;
269 m_algebra.xyz(m_inv_diag, m_r, m_z);
270
271 m_algebra.copy(m_z, m_p);
272 ValueType alpha = 2 / d;
273
274 //X.update (alpha, P, one); // X = X + alpha*P
275 m_algebra.axpy(alpha, m_p, y);
276
277 for (int i = 1; i < m_polynome_order; ++i) {
278 //computeResidual (R, B, A, X); // R = B - A*X
279 m_algebra.mult(m_matrix, y, m_y);
280 m_algebra.copy(x, m_r);
281 m_algebra.axpy(-1., m_y, m_r);
282
283 m_trace_mng->info() << i << " "
284 << "||R||" << m_algebra.norm2(m_r);
285
286 //solve (Z, D_inv, R); // z = D_inv * R, that is, D \ R.
287 //m_algebra.copy(m_r,m_z) ;
288 m_algebra.xyz(m_inv_diag, m_r, m_z);
289
290 //beta = (c * alpha / two)^2;
291 //const ST sqrtBeta = c * alpha / two;
292 //beta = sqrtBeta * sqrtBeta;
293 ValueType beta = alpha * (c / 2.) * (c / 2.);
294 alpha = 1. / (d - beta);
295
296 //P.update (one, Z, beta); // P = Z + beta*P
297 m_algebra.scal(beta, m_p);
298 m_algebra.axpy(1., m_z, m_p);
299
300 //X.update (alpha, P, one); // X = X + alpha*P
301 m_algebra.axpy(alpha, m_p, y);
302 // If we compute the residual here, we could either do R = B -
303 // A*X, or R = R - alpha*A*P. Since we choose the former, we
304 // can move the computeResidual call to the top of the loop.
305 }
306 }
307
308 void solve(const VectorType& x, //! input
309 VectorType& y //! output
310 ) const
311 {
312 if (m_use_saad_algo)
313 solve1(x, y);
314 else
315 solve2(x, y);
316 }
317
318 void _algo1([[maybe_unused]] AlgebraType& algebra,
319 VectorType const& x,
320 VectorType& y) const
321 {
322 /*
323 * r = b -Ax
324 * s = theta/delta
325 * rho_old = 1/sigma
326 * d = 1/theta * r
327 * do k=0,k<degree
328 * y = y + d
329 * r = r - Ad
330 * rho = (2sigma1 -rho_old)^-1
331 * d = rho*rho_old d + 2*rho/delta r
332 * rho_old = rho
333 * enddo
334 *
335 *
336 *
337 *
338 alpha = lambdaMax / eigRatio;
339 beta = boostFactor_ * lambdaMax;
340 delta = two / (beta - alpha);
341 theta = (beta + alpha) / two;
342 s1 = theta * delta;
343
344 // W := (1/theta)*D_inv*B and X := 0 + W.
345
346 // The rest of the iterations.
347 ST rhok = one / s1;
348 ST rhokp1, dtemp1, dtemp2;
349 for (int deg = 1; deg < numIters; ++deg)
350 {
351 rhokp1 = one / (two * s1 - rhok);
352 dtemp1 = rhokp1 * rhok;
353 dtemp2 = two * rhokp1 * delta;
354 rhok = rhokp1;
355 // W := dtemp2*D_inv*(B - A*X) + dtemp1*W.
356 // X := X + W
357 }
358 *
359 *
360 */
361
362 //m_algebra.copy(x,m_r) ;
363 m_algebra.pointwiseMult(m_inv_diag, x, m_r);
364
365 ValueType sigma = m_theta / m_delta;
366 ValueType rho_old = 1. / sigma;
367 ValueType rho = rho_old;
368 m_algebra.copy(m_r, m_w);
369 m_algebra.scal(1 / m_theta, m_w);
370 m_algebra.copy(m_w, y);
371
372 m_trace_mng->info() << "sigma =" << sigma;
373 m_trace_mng->info() << "rho =" << rho;
374 m_trace_mng->info() << "theta =" << m_theta;
375
376 for (int k = 1; k < m_polynome_order; ++k) {
377 m_algebra.mult(m_matrix, m_w, m_y);
378 m_algebra.pointwiseMult(m_inv_diag, m_y, m_y);
379 m_algebra.axpy(-1., m_y, m_r);
380
381 rho = 1. / (2 * sigma - rho_old);
382 m_algebra.scal(rho * rho_old, m_w);
383 m_algebra.axpy(2 * rho / m_delta, m_r, m_w);
384
385 //m_algebra.barrier(0,y) ;
386 m_algebra.axpy(1., m_w, y);
387
388 rho_old = rho;
389 }
390 }
391
392 void _algo2([[maybe_unused]] AlgebraType& algebra,
393 VectorType const& x,
394 VectorType& y) const
395 {
396 const ValueType d = (m_beta + m_alpha) / 2;
397 const ValueType c = (m_beta - m_alpha) / 2;
398
399 m_algebra.copy(x, y);
400
401 m_algebra.mult(m_matrix, y, m_y);
402 m_algebra.copy(x, m_r);
403 m_algebra.axpy(-1., m_y, m_r);
404
405 m_algebra.pointwiseMult(m_inv_diag, m_r, m_z); // z = D_inv * R, that is, D \ R.
406
407 m_algebra.copy(m_z, m_p);
408
409 ValueType alpha = 2 / d;
410 m_algebra.axpy(alpha, m_p, y); // X = X + alpha*P
411
412 for (int i = 1; i < m_polynome_order; ++i) {
413 // R = B - A*X
414 m_algebra.mult(m_matrix, y, m_y);
415 m_algebra.copy(x, m_r);
416 m_algebra.axpy(-1., m_y, m_r);
417
418 // z = D_inv * R, that is, D \ R.
419 m_algebra.pointwiseMult(m_inv_diag, m_r, m_z);
420
421 //beta = (c * alpha / two)^2;
422 //const ST sqrtBeta = c * alpha / two;
423 //beta = sqrtBeta * sqrtBeta;
424 ValueType beta = alpha * (c / 2.) * (c / 2.);
425 alpha = 1. / (d - beta);
426
427 // P = Z + beta*P
428 m_algebra.scal(beta, m_p);
429 m_algebra.axpy(1., m_z, m_p);
430
431 // X = X + alpha*P
432 m_algebra.axpy(alpha, m_p, y);
433 }
434 }
435
436 void solve(AlgebraType& algebra,
437 VectorType const& x,
438 VectorType& y) const
439 {
440 if (m_use_saad_algo)
441 _algo1(algebra, x, y);
442 else
443 _algo2(algebra, x, y);
444 }
445
446 private:
447 AlgebraType& m_algebra;
448
449 //! matrix a preconditioner
450 MatrixType const& m_matrix;
451
452 //! facteur d'acceleration
453 // clang-format off
454 ValueType m_factor = 0.;
455 ValueType m_alpha = 0.;
456 ValueType m_beta = 0.;
457 ValueType m_theta = 0.;
458 ValueType m_delta = 0.;
459 // clang-format on
460
461 int m_polynome_order;
462
463 int m_factor_max_iter;
464
465 VectorType m_inv_diag;
466
467 mutable VectorType m_y;
468 mutable VectorType m_r;
469 mutable VectorType m_w;
470 mutable VectorType m_p;
471 mutable VectorType m_z;
472
473 ITraceMng* m_trace_mng = nullptr;
474 int m_output_level = 0;
475};
476
477} // namespace Alien
void solve2(VectorType const &x, VectorType &y) const
void solve1(const VectorType &x, VectorType &y) const
void solve(const VectorType &x, VectorType &y) const
-- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature --
Definition BackEnd.h:17