b2api
B2000++ API Reference Manual, VERSION 4.6
 
Loading...
Searching...
No Matches
b2nonlinear_system_solver.H
1//------------------------------------------------------------------------
2// b2simple_nonlinear_system_solver.H --
3//
4//
5// written by Mathias Doreille
6//
7// Copyright (c) 2009 SMR Engineering & Development SA
8// 2502 Bienne, Switzerland
9//
10// All Rights Reserved. Proprietary source code. The contents of
11// this file may not be disclosed to third parties, copied or
12// duplicated in any form, in whole or in part, without the prior
13// written permission of SMR.
14//------------------------------------------------------------------------
15
16#ifndef B2SIMPLE_NONLINEAR_SYSTEM_SOLVER_H_
17#define B2SIMPLE_NONLINEAR_SYSTEM_SOLVER_H_
18
19#include <cmath>
20#include <iostream>
21#include <limits>
22
23#include "b2blaslapack.H"
24#include "b2line_search.H"
25#include "b2logging.H"
26#include "linear_algebra/b2linear_algebra_utils.H"
27
28namespace b2000 {
29
30/* Solve a nonlinear system using Newton-Raphson method
31 *
32 * struct SYSTEM {
33 * typename value_type;
34 * static const int size;
35 * void value(const value_type[size] x, value_type[size] y, value_type[size * size] jacobien);
36 * };
37 */
38template <typename SYSTEM>
39bool solve_newton_raphson(
40 SYSTEM& system, typename SYSTEM::value_type x[SYSTEM::size], double tol = 1e-5,
41 int maxiter = 50) {
42 typename SYSTEM::value_type y[SYSTEM::size];
43 int ipiv[SYSTEM::size];
44 typename SYSTEM::value_type jacobien[SYSTEM::size * SYSTEM::size];
45 int info;
46 tol = tol * tol;
47 while (--maxiter) {
48 system.value(x, y, jacobien);
49 double norm = 0;
50 for (int i = 0; i != SYSTEM::size; ++i) { norm += y[i] * y[i]; }
51 if (norm < tol) { return true; }
52 lapack::gesv(SYSTEM::size, 1, jacobien, SYSTEM::size, ipiv, y, SYSTEM::size, info);
53 if (info) { return false; }
54 for (int i = 0; i != SYSTEM::size; ++i) { x[i] -= y[i]; }
55 }
56 return false;
57}
58
59/* Line search using the Wolfe-Powell Rule using the transformed problem
60 * f = 0.5 * g * g
61 * g: R^n -> R^n
62 * f: R^n -> R
63 */
64template <typename g_t>
65struct f_line_search_t {
66 typedef typename g_t::x_type x_t;
67 typedef typename g_t::r_type g_x_t;
68
69 f_line_search_t(g_t& g_, x_t& xv_, x_t& dv_) : g(g_), xv(xv_), dv(dv_) {}
70
71 double search(double rho, double sigma, double min_f, unsigned long max_iter) {
72 double der0;
73 double f0 = (*this)(0, der0);
74 return line_search<f_line_search_t>(*this, f0, der0, rho, sigma, min_f, max_iter);
75
76 /*
77 double xmin;
78 double rmin = std::numeric_limits<double>::max();
79 for (double x = 1; x >= -1; x -= 0.001) {
80 double r = (*this)(x);
81 if (r < rmin) {
82 rmin = r;
83 xmin = x;
84 }
85 }
86 std::cout << "x min = " << xmin << std::endl;
87 return xmin;
88 */
89 }
90
91 double operator()(double x) const {
92 x_t v = xv;
93 v += x * dv;
94 g_x_t rv;
95 g(v, rv);
96 return 0.5 * (rv * rv);
97 }
98
99 double operator()(double x, double& der) const {
100 x_t v = xv;
101 if (x != 0) { v += x * dv; }
102 g_x_t rv, drv;
103 g(v, rv, dv, drv);
104 der = rv * drv;
105 // std::cout << " " << x << " " << 0.5 * (rv * rv) << " " << der
106 // << std::endl;
107 return 0.5 * (rv * rv);
108 }
109 g_t& g;
110 x_t& xv;
111 x_t& dv;
112};
113
120public:
122 logging::Logger& logger_ = logging::get_logger("solver.nonlinear_system.sha1"))
123 : logger(logger_) {
124 // termination test
125 conv_epsilon = 1e-6;
126
127 // Sha parameter
128 alpha = 0.9;
129 epsilon = 0.1;
130
131 // Wolf-Powell rule
132 wp_rho = 0.001;
133 wp_sigma = 0.9;
134 max_iter_line_search = 10;
135 }
136
137 template <typename g_t, typename x_t>
138 bool solve(g_t& g, x_t& xk) {
139 typedef typename g_t::r_type g_x_t;
140
141 g_x_t g_xk;
142 g_x_t g_xk1;
143 x_t d1;
144 x_t d2;
145 x_t xk1;
146 g(xk, g_xk, true);
147 double f_xk = 0.5 * g_xk * g_xk;
148 for (int iter = 0;; ++iter) {
149 {
150 double norm_g_xk = std::sqrt(2 * f_xk);
151 logger << logging::debug << "iteration " << iter + 1 << ", norm = " << norm_g_xk
152 << ", termination = " << conv_epsilon << logging::LOGFLUSH;
153 if (norm_g_xk < conv_epsilon) { break; }
154 }
155 bool inv_h = g.nd(xk, g_xk, d1);
156 if (inv_h) {
157 xk1 = xk;
158 xk1 += d1;
159 g(xk1, g_xk1, true);
160 double f_xk1 = 0.5 * (g_xk1 * g_xk1);
161 if (f_xk1 <= alpha * f_xk) {
162 xk = xk1;
163 g_xk = g_xk1;
164 f_xk = f_xk1;
165 continue;
166 }
167 }
168
169 logger << logging::debug << "need line search procedure" << logging::LOGFLUSH;
170 g.gd(xk, g_xk, d2);
171 if (inv_h) {
172 double d1d1 = d1 * d1;
173 double d2d2 = d2 * d2;
174 double d1d2 = d1 * d2;
175 if (d1d2 < epsilon * std::sqrt(d1d1 * d2d2)) {
176 double beta = get_beta(d1d1, d1d2, d2d2);
177 // std::cout << "beta=" << beta << std::endl;
178 d1 *= (1 - beta);
179 d1 += beta * d2;
180 }
181 } else {
182 d1 = d2;
183 }
184 double lambda =
185 f_line_search_t<g_t>(g, xk, d1).search(wp_rho, wp_sigma, 0, max_iter_line_search);
186 if (lambda == 0) { return false; }
187 xk += lambda * d1;
188 g(xk, g_xk, true);
189 f_xk = 0.5 * g_xk * g_xk;
190 }
191 return true;
192 }
193
194protected:
195 double get_beta(double d1d1, double d1d2, double d2d2) {
196 const double a[2] = {d2d2 - d1d2, d1d2};
197 const double b[3] = {
198 d2d2 * (d2d2 - 2 * d1d2 + d1d1), d2d2 * 2 * (d1d2 - d1d1), d2d2 * d1d1};
199 double r = 0;
200 while (r < 1 && (a[0] * r + a[1]) / std::sqrt(b[0] * r * r + b[1] * r + b[2]) < epsilon) {
201 r += 0.001;
202 }
203
204 return std::min(r, 1.0);
205 }
206
207 logging::Logger logger;
208 double conv_epsilon;
209 double alpha;
210 double epsilon;
211 double wp_rho;
212 double wp_sigma;
213 int max_iter_line_search;
214};
215
222public:
224 int _n, logging::Logger& logger_ = logging::get_logger("solver.nonlinear_system.sha2"))
225 : Sha1NonlinearSolver(logger_) {
226 n = _n;
227 nu = 0.1;
228 }
229
230 template <typename g_t, typename x_t>
231 bool solve(g_t& g, x_t& xk) {
232 typedef typename g_t::r_type g_x_t;
233
234 g_x_t g_xk;
235 g_x_t g_xk1;
236 x_t d1;
237 x_t d2;
238 x_t xk1;
239 int flag = 0;
240 double omega = 0;
241 std::vector<double> f_xl(n, std::numeric_limits<double>::max());
242 g(xk, g_xk, true);
243 double f_xk = 0.5 * g_xk * g_xk;
244 for (int iter = 0;; ++iter) {
245 {
246 {
247 size_t s = g_xk.size();
248 b2linalg::Interval a(0, s / 2);
249 b2linalg::Interval b(s / 2, s - 1);
250 std::cout << "rrrrr " << g_xk(b2linalg::Interval(0, s / 2)).norm2() << " "
251 << g_xk(b2linalg::Interval(s / 2, s - 1)).norm2() << " "
252 << g_xk[s - 1] << std::endl;
253 }
254 double norm_g_xk = std::sqrt(2 * f_xk);
255 logger << logging::debug << "iteration " << iter + 1 << ", norm = " << norm_g_xk
256 << ", termination = " << conv_epsilon << logging::LOGFLUSH;
257 if (norm_g_xk < conv_epsilon) { break; }
258 }
259 double f_min = f_xk;
260 for (size_t i = n - 1; i > 0; --i) {
261 f_xl[i] = f_xl[i - 1];
262 f_min = std::min(f_xl[i], f_min);
263 }
264 f_xl[0] = f_xk;
265 bool inv_h = g.nd(xk, g_xk, d1);
266 if (inv_h) {
267 xk1 = xk;
268 xk1 += d1;
269 g(xk1, g_xk1, true);
270 double f_xk1 = 0.5 * (g_xk1 * g_xk1);
271 if (f_xk1 <= alpha * (omega == 0 ? f_min : f_xk)) {
272 xk = xk1;
273 g_xk = g_xk1;
274 f_xk = f_xk1;
275 flag = 0;
276 if (f_xk <= alpha * omega) { omega = 0; }
277 continue;
278 }
279 if (omega == 0 && flag < n && f_xk1 <= (1 + nu) * f_xk) {
280 xk = xk1;
281 g_xk = g_xk1;
282 f_xk = f_xk1;
283 ++flag;
284 continue;
285 }
286 }
287
288 logger << logging::debug << "need line search procedure" << logging::LOGFLUSH;
289 if (omega == 0) {
290 if (flag == n) {
291 omega = f_min;
292 } else if (flag > 0) {
293 ++flag;
294 }
295 }
296
297 g.gd(xk, g_xk, d2);
298 if (inv_h) {
299 double d1d1 = d1 * d1;
300 double d2d2 = d2 * d2;
301 double d1d2 = d1 * d2;
302 if (d1d2 < epsilon * std::sqrt(d1d1 * d2d2)) {
303 double beta = get_beta(d1d1, d1d2, d2d2);
304 beta = 0;
305 // std::cout << "beta=" << beta << std::endl;
306 d1 *= (1 - beta);
307 d1 += beta * d2;
308 }
309 } else {
310 d1 = d2;
311 }
312 double lambda =
313 f_line_search_t<g_t>(g, xk, d1).search(wp_rho, wp_sigma, 0, max_iter_line_search);
314 std::cout << "lambda = " << lambda << std::endl;
315 if (lambda == 0) { lambda = 0.1; }
316 xk += lambda * d1;
317 g(xk, g_xk, true);
318 f_xk = 0.5 * g_xk * g_xk;
319 }
320 return true;
321 }
322
323protected:
324 int n;
325 double nu;
326};
327
334public:
336 epsilon = 1e-6;
337 delta0 = 0.001;
338 Delta0 = 1;
339 nu = 0.99;
340 rho = 0.001;
341 sigma = 0.9;
342 gamma1 = gamma2 = 10000;
343 max_iter_line_search = 10;
344 beta1 = 0.01;
345 beta2 = 1 / beta1;
346 beta3 = 1.1;
347 tau = 1e-10;
348 Tau = 1e10;
349 norm_g_xk_1 = -1;
350 }
351
352 template <typename g_t, typename x_t>
353 bool next(const g_t& g, int k, x_t& xk) {
354 // typedef typename g_t::x_type x_t;
355 typedef typename g_t::r_type g_x_t;
356
357 double delta = delta0;
358 double Delta = Delta0;
359 double alphak;
360
361 g_x_t d1;
362 g_x_t d2;
363 x_t xk_sk;
364 g_x_t sk;
365
366 // l1_and_l2:
367 double norm_g_xk;
368 const bool has_h = g(xk, d2, norm_g_xk, epsilon, d1);
369 std::cout << k << " " << xk[0] << " " << norm_g_xk << std::endl;
370 if (norm_g_xk < epsilon) { return true; }
371
372 double f_xk = 0.5 * norm_g_xk * norm_g_xk;
373 const double f_xk_1 = norm_g_xk_1 < 0 ? f_xk : 0.5 * norm_g_xk_1 * norm_g_xk_1;
374
375 g_x_t d_xi;
376
377 // l3:
378 if (!has_h) { goto l8; }
379
380 // l4:
381 if (std::abs(f_xk - f_xk_1) > gamma1 && norm_g_xk > gamma2) {
382 delta = beta2 * delta0;
383 goto l7;
384 }
385
386 // l5:
387 if (k == 1 || norm_g_xk < norm_g_xk_1) {
388 x_t xbar;
389 xbar = xk + d1;
390 // l6:
391 g_x_t g_xbar;
392 g(xbar, g_xbar);
393 double norm_g_xbar = g_xbar.norm2();
394 double f_xbar = 0.5 * g_xbar * g_xbar;
395 if (f_xbar < f_xk && norm_g_xbar <= nu * norm_g_xk) { delta = beta1 * delta0; }
396 }
397
398 l7:
399 if (d1 * d2 >= 0) { goto l9; }
400
401 l8:
402 alphak = f_line_search_t<g_t>(g, xk, d2).search(rho, sigma, 0, max_iter_line_search);
403 sk = alphak * d2;
404 goto l12;
405
406 l9 : {
407 double xi = 1 / (Delta + std::abs(f_xk - f_xk_1));
408 d_xi = (1 - xi) * d2;
409 d_xi += xi * d1;
410
411 // l10:
412 if (d_xi * d2 < delta * d_xi.norm2() * d2.norm2()) {
413 Delta = beta3 * Delta;
414 goto l9;
415 }
416
417 // l11:
418#define USEA
419#ifdef USEA
420 alphak = f_line_search_t<g_t>(g, xk, d2).search(rho, sigma, 0, max_iter_line_search);
421 if (alphak * d2.norm2() < Tau * d1.norm2()) {
422 sk = (alphak * (1 - xi)) * d2 + xi * d1;
423 xk_sk = xk + sk;
424 g_x_t g_xk_sk;
425 g(xk_sk, g_xk_sk);
426 double norm_g_xk_sk = g_xk_sk.norm2();
427 if (0.5 * norm_g_xk_sk * norm_g_xk_sk <= f_xk - tau * sk.norm2()) {
428 xk = xk_sk;
429 return false;
430 }
431 }
432#else
433 alphak = f_line_search_t<g_t>(g, xk, d_xi).search(rho, sigma, 0, max_iter_line_search);
434 xk += alphak * d_xi;
435 return false;
436#endif
437 }
438
439 l12:
440 xk += alphak * d2;
441
442 return false;
443 }
444
445 template <typename g_t, typename x_t>
446 void solve(const g_t& g, x_t& x0) {
447 for (int k = 1; !next(g, k, x0); ++k) { ; }
448 }
449
450 double epsilon;
451 double delta0;
452 double Delta0;
453 double nu;
454 double rho;
455 double sigma;
456 int max_iter_line_search;
457 double gamma1;
458 double gamma2;
459 double beta1;
460 double beta2;
461 double beta3;
462 double tau;
463 double Tau;
464 double norm_g_xk_1;
465};
466
467} // namespace b2000
468
469#endif /* B2SIMPLE_NONLINEAR_SYSTEM_SOLVER_H_ */
csda< T > norm(const csda< T > &a)
Definition b2csda.H:343
Definition b2nonlinear_system_solver.H:333
Definition b2nonlinear_system_solver.H:119
Definition b2nonlinear_system_solver.H:221
Definition b2logging.H:495
Logger & get_logger(const std::string &logger_name="")
Definition b2logging.H:829
Contains the base classes for implementing Finite Elements.
Definition b2boundary_condition.H:32