6#ifndef __B2LINE_SEARCH_H__
7#define __B2LINE_SEARCH_H__
15inline double put_in_range(
double min,
double max,
double v) {
16 if (v < min) {
return min; }
17 if (v > max) {
return max; }
21inline double poly_min_extrap(
double f0,
double d0,
double f1) {
22 const double temp = 2 * (f1 - f0 - d0);
23 if (std::abs(temp) <= d0 * std::numeric_limits<double>::epsilon()) {
return 0.5; }
25 const double alpha = -d0 / temp;
28 return put_in_range(0, 1, alpha);
31inline double poly_min_extrap(
double f0,
double d0,
double f1,
double d1) {
32 const double n = 3 * (f1 - f0) - 2 * d0 - d1;
33 const double e = d0 + d1 - 2 * (f1 - f0);
37 double temp = std::max(n * n - 3 * e * d0, 0.0);
39 if (temp < 0) {
return 0.5; }
41 temp = std::sqrt(temp);
43 if (std::abs(e) <= std::numeric_limits<double>::epsilon()) {
return 0.5; }
46 double x1 = (temp - n) / (3 * e);
47 double x2 = -(temp + n) / (3 * e);
50 double y1 = f0 + d0 * x1 + n * x1 * x1 + e * x1 * x1 * x1;
51 double y2 = f0 + d0 * x2 + n * x2 * x2 + e * x2 * x2 * x2;
62 return put_in_range(0, 1, x);
65inline double poly_min_extrap(
66 double f0,
double d0,
double x1,
double f_x1,
double x2,
double f_x2) {
67 assert(0 < x1 && x1 < x2);
71 const double aa2 = x2 * x2;
72 const double aa1 = x1 * x1;
73 const double m[2][2] = {{aa2, -aa2 * x2}, {-aa1, aa1 * x1}};
74 const double v[2] = {f_x1 - f0 - d0 * x1, f_x2 - f0 - d0 * x2};
75 double temp = aa2 * aa1 * (x1 - x2);
78 if (temp == 0) {
return x1 / 2.0; }
80 const double inv_temp = 1 / temp;
81 const double a = inv_temp * (m[0][0] * v[0] + m[1][0] * v[1]);
82 const double b = inv_temp * (m[0][1] * v[0] + m[1][1] * v[1]);
84 temp = b * b - 3 * a * d0;
85 if (temp < 0 || a == 0) {
93 temp = (-b + std::sqrt(temp)) / (3 * a);
94 return put_in_range(0, x2, temp);
97template <
typename funct>
99 const funct& f,
const double f0,
const double d0,
double rho,
double sigma,
double min_f,
100 unsigned long max_iter) {
101 assert(0 < rho && rho < sigma && sigma < 1 && max_iter > 0);
108 const double tau1 = 9;
112 const double tau2 = 1.0 / 10.0;
113 const double tau3 = 1.0 / 2.0;
116 if (std::abs(d0) < std::numeric_limits<double>::epsilon()) {
return 0; }
119 if (f0 <= min_f) {
return 0; }
122 const double mu = (min_f - f0) / (rho * d0);
125 if (mu < 0) { alpha = -alpha; }
126 alpha = put_in_range(0, 0.65 * mu, alpha);
128 double last_alpha = 0;
129 double last_val = f0;
130 double last_val_der = d0;
137 double a_val, b_val, a_val_der, b_val_der;
140 const double thresh = std::abs(sigma * d0);
142 unsigned long itr = 0;
147 const double val = f(alpha, val_der);
151 if (val <= min_f) {
return alpha; }
153 if (val > f0 + rho * alpha * d0 || val >= last_val) {
155 a_val_der = last_val_der;
164 if (std::abs(val_der) <= thresh) {
return alpha; }
167 if (last_alpha == alpha || itr >= max_iter) {
return alpha; }
173 b_val_der = last_val_der;
180 if (mu <= 2 * alpha - last_alpha) {
184 const double temp = alpha;
186 double first = 2 * alpha - last_alpha;
189 last = std::min(mu, alpha + tau1 * (alpha - last_alpha));
191 last = std::max(mu, alpha + tau1 * (alpha - last_alpha));
195 if (last_alpha < alpha) {
197 + (alpha - last_alpha)
198 * poly_min_extrap(last_val, last_val_der, val, val_der);
201 + (last_alpha - alpha)
202 * poly_min_extrap(val, val_der, last_val, last_val_der);
205 alpha = put_in_range(first, last, alpha);
211 last_val_der = val_der;
217 double first = a + tau2 * (b - a);
218 double last = b - tau3 * (b - a);
221 alpha = a + (b - a) * poly_min_extrap(a_val, a_val_der, b_val, b_val_der);
222 alpha = put_in_range(first, last, alpha);
225 const double val = f(alpha, val_der);
229 if (val <= min_f || itr >= max_iter) {
return alpha; }
232 if (a == first || b == last) {
return b; }
234 if (val > f0 + rho * alpha * d0 || val >= a_val) {
239 if (std::abs(val_der) <= thresh) {
return alpha; }
241 if ((b - a) * val_der >= 0) {
244 b_val_der = a_val_der;
254template <
typename funct>
255double backtracking_line_search(
256 const funct& f,
double f0,
double d0,
double alpha,
double rho,
unsigned long max_iter) {
257 assert(0 < rho && rho < 1 && max_iter > 0);
261 if ((d0 > 0 && alpha > 0) || (d0 < 0 && alpha < 0)) { alpha *= -1; }
263 bool have_prev_alpha =
false;
264 double prev_alpha = 0;
266 unsigned long iter = 0;
269 const double val = f(alpha);
270 if (val <= f0 + alpha * rho * d0 || iter >= max_iter) {
276 if (!have_prev_alpha) {
278 step = alpha * put_in_range(0.1, 0.9, poly_min_extrap(f0, d0, val));
280 step = alpha * put_in_range(0.1, 0.9, poly_min_extrap(f0, -d0, val));
282 have_prev_alpha =
true;
286 0.1 * alpha, 0.9 * alpha,
287 poly_min_extrap(f0, d0, alpha, val, prev_alpha, prev_val));
290 0.1 * alpha, 0.9 * alpha,
291 -poly_min_extrap(f0, -d0, -alpha, val, -prev_alpha, prev_val));
Contains the base classes for implementing Finite Elements.
Definition b2boundary_condition.H:32