Hyperiso 1.0.3
Modular flavour-physics calculations, Wilson coefficients and statistical inference
Loading...
Searching...
No Matches
optimization.cpp
Go to the documentation of this file.
1#include "optimization.h"
2
4 double x_min, double x_max,
5 double &a, double &b,
6 int n_samples)
7{
8 if (!(x_min < x_max)) throw std::invalid_argument("x_min < x_max required");
9 std::vector<double> xs;
10 xs.reserve(n_samples+1);
11 for (int i = 0; i <= n_samples; ++i) {
12 double t = double(i) / double(n_samples);
13 xs.push_back(x_min + t * (x_max - x_min));
14 }
15 double fa = f(xs.front());
16 if (!std::isfinite(fa)) return false;
17 if (std::fabs(fa) == 0.0) { a = b = xs.front(); return true; }
18 for (size_t i = 1; i < xs.size(); ++i) {
19 double fb = f(xs[i]);
20 if (!std::isfinite(fb)) return false;
21 if (fb == 0.0) { a = b = xs[i]; return true; }
22 if (fa * fb < 0.0) { a = xs[i-1]; b = xs[i]; return true; }
23 fa = fb;
24 }
25 return false;
26}
27
29 double a, double b,
30 double xtol,
31 double ftol,
32 int max_it)
33{
34 double fa = f(a);
35 double fb = f(b);
36 if (!std::isfinite(fa) || !std::isfinite(fb))
37 throw std::runtime_error("Function not finite at bracket endpoints.");
38 if (fa == 0.0) return a;
39 if (fb == 0.0) return b;
40 if (fa * fb > 0.0)
41 throw std::invalid_argument("Root is not bracketed (f(a) and f(b) must have opposite signs).");
42
43 double c = a;
44 double fc = fa;
45 double d = b - a;
46 double e = d;
47
48 for (int iter = 0; iter < max_it; ++iter) {
49 if (std::fabs(fc) < std::fabs(fb)) {
50 a = b; fa = fb;
51 b = c; fb = fc;
52 c = a; fc = fa;
53 }
54
55 double tol = 2.0 * std::numeric_limits<double>::epsilon() * std::fabs(b) + xtol;
56 double m = 0.5 * (c - b);
57 if (std::fabs(m) <= tol || std::fabs(fb) <= ftol) {
58 return b;
59 }
60
61 if (std::fabs(e) >= tol && std::fabs(fa) > std::fabs(fb)) {
62 double s = fb / fa;
63 double p, q;
64 if (a == c) {
65 p = 2.0 * m * s;
66 q = 1.0 - s;
67 } else {
68 double r = fb / fc;
69 double s2 = fa / fc;
70 p = s * (2.0 * m * s2 * (s2 - r) - (b - a) * (r - 1.0));
71 q = (s2 - 1.0) * (r - 1.0) * (s - 1.0);
72 }
73 if (p > 0) q = -q; else p = -p;
74 if ( (2.0 * p) < (3.0 * m * q - std::fabs(tol * q)) && p < std::fabs(0.5 * e * q) ) {
75 e = d;
76 d = p / q;
77 } else {
78 d = m;
79 e = m;
80 }
81 } else {
82 d = m;
83 e = m;
84 }
85
86 a = b; fa = fb;
87 if (std::fabs(d) > tol)
88 b += d;
89 else
90 b += (m > 0 ? tol : -tol);
91 fb = f(b);
92 if (!std::isfinite(fb)) throw std::runtime_error("Function returned non-finite value during iteration.");
93 if ((fb > 0 && fc > 0) || (fb < 0 && fc < 0)) {
94 c = a; fc = fa;
95 d = b - a;
96 e = d;
97 }
98 }
99
100 throw std::runtime_error("brent_root: maximum iterations exceeded");
101}
102
104 gsl_function gsl_f;
105 gsl_f.function = &unwrap_lambda_unidim;
106 gsl_f.params = &f;
107
108 std::unique_ptr<gsl_min_fminimizer, void(*)(gsl_min_fminimizer*)>
109 s(gsl_min_fminimizer_alloc(gsl_min_fminimizer_quad_golden),
110 gsl_min_fminimizer_free);
111
112 int st = gsl_min_fminimizer_set(s.get(), &gsl_f, context.start, context.bracket[0], context.bracket[1]);
113
114 if (st)
115 throw std::runtime_error(std::string("gsl_min_fminimizer_set: ") + gsl_strerror(st));
116
117 double a, b, m;
118
119 std::size_t iter=0; int status; double size;
120 do {
121 ++iter; status = gsl_min_fminimizer_iterate(s.get());
122 if (status) break;
123
124 a = gsl_min_fminimizer_x_lower(s.get());
125 b = gsl_min_fminimizer_x_upper(s.get());
126 m = gsl_min_fminimizer_x_minimum(s.get());
127
128 status = gsl_min_test_interval(a, b, context.tol, 0.0);
129 } while (status == GSL_CONTINUE && iter < context.max_iter);
130
132 mr.status = status;
133 mr.argmin = a;
134 mr.min = m;
135
136 return mr;
137}
138
139MinimizationResult minimize_NM(RealValuedForm f, const std::vector<double>& x0, const std::vector<double>& scales, const MinimizationContext& context) {
140 ScaledForm f_scaled(f, x0, scales);
141 MinimizationResult mr_scaled = minimize_NM(f_scaled, std::vector<double>(x0.size(), 0.0), context);
142
143 for (std::size_t i = 0; i < x0.size(); ++i)
144 mr_scaled.argmin[i] = f_scaled.x0[i] + f_scaled.s[i] * mr_scaled.argmin[i];
145
146 return mr_scaled;
147}
148
149MinimizationResult minimize_BFGS(RealValuedForm f, const std::vector<double> &x0, const std::vector<double>& scales, const MinimizationContext &context) {
150 ScaledForm f_scaled(f, x0, scales);
151 MinimizationResult mr_scaled = minimize_BFGS(f_scaled, std::vector<double>(x0.size(), 0.0), context);
152
153 for (std::size_t i = 0; i < x0.size(); ++i)
154 mr_scaled.argmin[i] = f_scaled.x0[i] + f_scaled.s[i] * mr_scaled.argmin[i];
155
156 return mr_scaled;
157}
158
159MinimizationResult minimize_NM(ScaledForm f, const std::vector<double>& t0, const MinimizationContext &context) {
160 std::size_t d = t0.size();
161
162 gsl_multimin_function gsl_f;
163 gsl_f.n = d;
164 gsl_f.f = &unwrap_lambda_multidim;
165 gsl_f.params = &f;
166
167 std::unique_ptr<gsl_multimin_fminimizer, void(*)(gsl_multimin_fminimizer*)>
168 s(gsl_multimin_fminimizer_alloc(gsl_multimin_fminimizer_nmsimplex2, d),
169 gsl_multimin_fminimizer_free);
170
171 gsl_vector* x = gsl_vector_alloc(d);
172 gsl_vector* step = gsl_vector_alloc(d);
173 for (size_t i = 0; i < d; i++)
174 gsl_vector_set(x, i, t0[i]);
175 gsl_vector_set_all(step, context.simplex_initial_step_size);
176
177 int st = gsl_multimin_fminimizer_set(s.get(), &gsl_f, x, step);
178
179 if (st)
180 throw std::runtime_error(std::string("gsl_multimin_fminimizer_set: ") + gsl_strerror(st));
181
182 std::size_t iter=0; int status; double size;
183 do {
184 ++iter; status = gsl_multimin_fminimizer_iterate(s.get());
185 if (status) break;
186 size = gsl_multimin_fminimizer_size(s.get());
187 status = gsl_multimin_test_size(size, context.switch_tol);
188 // std::cout << "[minimize] iter=" << iter << " status=" << gsl_strerror(status) << " size=" << size << std::endl;
189 } while (status == GSL_CONTINUE && iter < context.simplex_max_iter);
190
191 std::cout << "NM minimization converged in " << iter << " iterations." << std::endl;
192 gsl_vector* gsl_argmin = gsl_multimin_fminimizer_x(s.get());
193 std::vector<double> argmin(d);
194 for (std::size_t i = 0; i < d; ++i)
195 argmin[i] = gsl_vector_get(gsl_argmin, i);
196
198 mr.status = status;
199 mr.argmin = argmin;
200 mr.min = gsl_multimin_fminimizer_minimum(s.get());
201
202 gsl_vector_free(x);
203 gsl_vector_free(step);
204
205 return mr;
206}
207
208MinimizationResult minimize_BFGS(ScaledForm f, const std::vector<double> &t0, const MinimizationContext &context) {
209 std::size_t d = t0.size();
210 gsl_multimin_function_fdf gsl_f;
211
212 gsl_f.n = d;
213 gsl_f.f = &unwrap_lambda_multidim;
214 gsl_f.df = &unwrap_lambda_gradient;
216 gsl_f.params = &f;
217
218 std::unique_ptr<gsl_multimin_fdfminimizer, void(*)(gsl_multimin_fdfminimizer*)>
219 s(gsl_multimin_fdfminimizer_alloc(gsl_multimin_fdfminimizer_vector_bfgs2, d),
220 gsl_multimin_fdfminimizer_free);
221
222 gsl_vector* x = gsl_vector_alloc(d);
223 for (size_t i = 0; i < d; i++)
224 gsl_vector_set(x, i, t0[i]);
225 int st = gsl_multimin_fdfminimizer_set(s.get(), &gsl_f, x, context.bfgs_initial_step_size, context.bfgs_line_search_tol);
226
227 if (st)
228 throw std::runtime_error(std::string("gsl_multimin_fminimizer_set: ") + gsl_strerror(st));
229
230 std::size_t iter = 0; int status; gsl_vector* g;
231 double f_cur = f(t0);
232 bool converged = false;
233 bool iterate = true;
234 do {
235 ++iter; status = gsl_multimin_fdfminimizer_iterate(s.get());
236 if (status) break; // cannot improve
237 g = gsl_multimin_fdfminimizer_gradient(s.get());
238 status = gsl_multimin_test_gradient(g, context.final_tol);
239 double f_new = gsl_multimin_fdfminimizer_minimum(s.get());
240 double df = std::abs(f_new - f_cur);
241 converged = (status == GSL_SUCCESS) && (df < 1e-8 * (1.0 + std::abs(f_cur)));
242 iterate = !converged && (iter < context.bfgs_max_iter);
243 f_cur = f_new;
244 } while (iterate);
245 std::cout << "BFGS minimization converged in " << iter << " iterations." << std::endl;
246 gsl_vector* gsl_argmin = gsl_multimin_fdfminimizer_x(s.get());
247 std::vector<double> argmin(d);
248 for (std::size_t i = 0; i < d; ++i)
249 argmin[i] = gsl_vector_get(gsl_argmin, i);
250
252 mr.status = status;
253 mr.argmin = argmin;
254 mr.min = gsl_multimin_fdfminimizer_minimum(s.get());
255
256 gsl_vector_free(x);
257
258 return mr;
259}
260
261MinimizationResult minimize_combined(RealValuedForm f, const std::vector<double> &x0, const std::vector<double> &scales, const MinimizationContext &context) {
262 ScaledForm f_scaled(f, x0, scales);
263 MinimizationResult interm = minimize_NM(f_scaled, std::vector<double>(x0.size(), 0.0), context);
264
265 if (interm.status != GSL_SUCCESS)
266 return interm;
267
268 MinimizationResult mr_final = minimize_BFGS(f_scaled, interm.argmin, context);
269
270 for (std::size_t i = 0; i < x0.size(); ++i)
271 mr_final.argmin[i] = f_scaled.x0[i] + f_scaled.s[i] * mr_final.argmin[i];
272
273 return mr_final;
274}
constexpr double g
std::function< double(double)> RealValuedFunction
Definition functions.h:10
std::function< double(std::vector< double >)> RealValuedForm
Definition functions.h:11
double unwrap_lambda_multidim(const gsl_vector *t, void *params)
void unwrap_lambda_gradient(const gsl_vector *t, void *params, gsl_vector *g)
double unwrap_lambda_unidim(double x, void *p)
void unwrap_lambda_func_and_gradient(const gsl_vector *t, void *params, double *f, gsl_vector *g)
MinimizationResult minimize_NM(RealValuedForm f, const std::vector< double > &x0, const std::vector< double > &scales, const MinimizationContext &context)
MinimizationResult minimize_BFGS(RealValuedForm f, const std::vector< double > &x0, const std::vector< double > &scales, const MinimizationContext &context)
ScalarMinimizationResult minimize_scalar(RealValuedFunction f, const ScalarMinimizationContext &context)
MinimizationResult minimize_combined(RealValuedForm f, const std::vector< double > &x0, const std::vector< double > &scales, const MinimizationContext &context)
bool find_bracket(const RealValuedFunction &f, double x_min, double x_max, double &a, double &b, int n_samples)
double brent_root(const RealValuedFunction &f, double a, double b, double xtol, double ftol, int max_it)
double f(double x)
Wilson special function f depending on x.
std::vector< double > argmin
std::vector< double > s
Definition functions.h:17
std::vector< double > x0
Definition functions.h:16