Hyperiso
1.0.3
Modular flavour-physics calculations, Wilson coefficients and statistical inference
Loading...
Searching...
No Matches
test_contour_minuit2.cpp
Go to the documentation of this file.
1
// #include <algorithm>
2
// #include <chrono>
3
// #include <cmath>
4
// #include <fstream>
5
// #include <functional>
6
// #include <iomanip>
7
// #include <iostream>
8
// #include <limits>
9
// #include <memory>
10
// #include <sstream>
11
// #include <stdexcept>
12
// #include <string>
13
// #include <vector>
14
15
// #include "StatisticManager.h"
16
// #include "ObservableInterfaceProxy.h"
17
// #include "StatCorrelationProxy.h"
18
// #include "StatParameterProxy.h"
19
// #include "ObservableInterface.h"
20
// #include "StatParamSourcesProxy.h"
21
// #include "StatDependencyPruner.h"
22
23
// #include "Fit.h"
24
// #include "BaseLikelihood.h"
25
// #include "NuisanceReader.h"
26
// #include "DefaultNuisancePathsProvider.h"
27
28
// #include "minuit-cpp/FCNBase.hh"
29
// #include "minuit-cpp/FunctionMinimum.hh"
30
// #include "minuit-cpp/MnEigen.hh"
31
// #include "minuit-cpp/MnHesse.hh"
32
// #include "minuit-cpp/MnMigrad.hh"
33
// #include "minuit-cpp/MnUserCovariance.hh"
34
// #include "minuit-cpp/MnUserParameters.hh"
35
// #include "minuit-cpp/MnUserParameterState.hh"
36
37
// namespace M2 = MinuitCpp;
38
39
// // -----------------------------------------------------------------------------
40
// // Helpers
41
// // -----------------------------------------------------------------------------
42
43
// template <class T>
44
// static std::string stream_str(const T& x) {
45
// std::ostringstream oss;
46
// oss << x;
47
// return oss.str();
48
// }
49
50
// static void print_vec(const std::vector<double>& vec) {
51
// std::cout << "[ ";
52
// for (std::size_t i = 0; i < vec.size(); ++i) {
53
// std::cout << std::setprecision(17) << vec[i]
54
// << (i + 1 == vec.size() ? " " : ", ");
55
// }
56
// std::cout << "]\n";
57
// }
58
59
// static std::vector<double> linspace(double a, double b, std::size_t n) {
60
// std::vector<double> out(n);
61
// if (n == 0) return out;
62
// if (n == 1) {
63
// out[0] = a;
64
// return out;
65
// }
66
// for (std::size_t i = 0; i < n; ++i) {
67
// out[i] = a + (b - a) * double(i) / double(n - 1);
68
// }
69
// return out;
70
// }
71
72
// static double safe_step(double value, double scale_hint) {
73
// double a = std::fabs(value);
74
// double s = std::fabs(scale_hint);
75
76
// double step = 0.0;
77
// if (std::isfinite(s) && s > 0.0) step = 0.05 * s;
78
// if (std::isfinite(a) && a > 0.0) step = std::max(step, 0.01 * a);
79
// if (!std::isfinite(step) || step <= 0.0) step = 1e-3;
80
81
// return step;
82
// }
83
84
// static void save_bestfit_csv(const std::string& path,
85
// const std::vector<std::string>& names,
86
// const Vector& vals,
87
// const Vector& errs) {
88
// std::ofstream out(path);
89
// out << "name,value,error\n";
90
// for (std::size_t i = 0; i < vals.size(); ++i) {
91
// out << names[i] << ","
92
// << std::setprecision(17) << vals[i] << ","
93
// << errs[i] << "\n";
94
// }
95
// }
96
97
// static void save_grid_csv(const std::string& path,
98
// const std::string& xname,
99
// const std::string& yname,
100
// const std::vector<double>& xs,
101
// const std::vector<double>& ys,
102
// const std::vector<double>& z) {
103
// const std::size_t nx = xs.size();
104
// const std::size_t ny = ys.size();
105
106
// std::ofstream out(path);
107
// out << "# x=" << xname << "\n";
108
// out << "# y=" << yname << "\n";
109
// out << "x,y,delta_nll\n";
110
// out << std::setprecision(17);
111
112
// for (std::size_t iy = 0; iy < ny; ++iy) {
113
// for (std::size_t ix = 0; ix < nx; ++ix) {
114
// out << xs[ix] << "," << ys[iy] << "," << z[iy * nx + ix] << "\n";
115
// }
116
// }
117
// }
118
119
// // -----------------------------------------------------------------------------
120
// // Minuit wrappers
121
// // -----------------------------------------------------------------------------
122
123
// struct ParamLimit {
124
// std::size_t idx;
125
// double low;
126
// double high;
127
// };
128
129
// struct MinuitFitOptions {
130
// double up = 0.5; // NLL => 0.5 for 1D 1σ
131
// unsigned strategy = 2;
132
// unsigned max_fcn = 100000;
133
// double tolerance = 0.2; // Minuit "toler"
134
// bool run_hesse = true;
135
// unsigned hesse_maxcalls = 0;
136
// bool verbose = true;
137
// };
138
139
// struct MinuitJointFit {
140
// Vector x_hat; // full vector [p, eta]
141
// std::vector<double> x_err; // HESSE errors
142
// std::vector<double> cov_eigs; // covariance eigenvalues
143
// double cond_number = std::numeric_limits<double>::infinity();
144
145
// double fmin = std::numeric_limits<double>::quiet_NaN();
146
// double edm = std::numeric_limits<double>::quiet_NaN();
147
// int nfcn = -1;
148
149
// bool ok = false;
150
// bool has_valid_covar = false;
151
// bool has_posdef_covar = false;
152
// bool has_accurate_covar = false;
153
// bool made_posdef = false;
154
155
// RealMatrix cov;
156
// };
157
158
// class GenericFCN final : public M2::FCNBase {
159
// public:
160
// GenericFCN(std::function<double(const std::vector<double>&)> f, double up)
161
// : f_(std::move(f)), up_(up) {}
162
163
// double operator()(const std::vector<double>& x) const override {
164
// try {
165
// const double v = f_(x);
166
// return std::isfinite(v) ? v : 1e300;
167
// } catch (...) {
168
// return 1e300;
169
// }
170
// }
171
172
// double Up() const override { return up_; }
173
174
// private:
175
// std::function<double(const std::vector<double>&)> f_;
176
// double up_;
177
// };
178
179
// static void log_minuit_summary(const std::string& tag, const M2::FunctionMinimum& min) {
180
// std::cout << "\n=== [" << tag << "] FunctionMinimum ===\n";
181
// std::cout << "IsValid = " << min.IsValid() << "\n";
182
// std::cout << "HasValidParameters = " << min.HasValidParameters() << "\n";
183
// std::cout << "HasValidCovariance = " << min.HasValidCovariance() << "\n";
184
// std::cout << "HasAccurateCovar = " << min.HasAccurateCovar() << "\n";
185
// std::cout << "HasPosDefCovar = " << min.HasPosDefCovar() << "\n";
186
// std::cout << "HasMadePosDefCovar = " << min.HasMadePosDefCovar() << "\n";
187
// std::cout << "HesseFailed = " << min.HesseFailed() << "\n";
188
// std::cout << "Fval = " << std::setprecision(17) << min.Fval() << "\n";
189
// std::cout << "EDM = " << std::setprecision(17) << min.Edm() << "\n";
190
// std::cout << "NFcn = " << min.NFcn() << "\n";
191
// std::cout << "Up = " << min.Up() << "\n";
192
// }
193
194
// static MinuitJointFit minuit_migrad_hesse(
195
// const std::function<double(const std::vector<double>&)>& f,
196
// const std::vector<std::string>& names,
197
// const std::vector<double>& x0,
198
// const std::vector<double>& scale_hints,
199
// const std::vector<ParamLimit>& limits,
200
// const MinuitFitOptions& opt
201
// ) {
202
// if (x0.size() != names.size() || x0.size() != scale_hints.size()) {
203
// throw std::invalid_argument("minuit_migrad_hesse: names/x0/scale_hints size mismatch");
204
// }
205
206
// GenericFCN fcn(f, opt.up);
207
208
// M2::MnUserParameters upar;
209
// for (std::size_t i = 0; i < x0.size(); ++i) {
210
// const double step = safe_step(x0[i], scale_hints[i]);
211
// upar.Add(names[i].c_str(), x0[i], step);
212
// }
213
214
// for (const auto& lim : limits) {
215
// if (lim.idx < names.size()) {
216
// upar.SetLimits(names[lim.idx].c_str(), lim.low, lim.high);
217
// }
218
// }
219
220
// M2::MnMigrad migrad(fcn, upar, opt.strategy);
221
// M2::FunctionMinimum min = migrad(opt.max_fcn, opt.tolerance);
222
223
// if (opt.run_hesse) {
224
// M2::MnHesse hesse(opt.strategy);
225
// hesse(fcn, min, opt.hesse_maxcalls);
226
// }
227
228
// if (opt.verbose) {
229
// log_minuit_summary("MIGRAD+HESSE", min);
230
// }
231
232
// std::vector<double> eigs;
233
// double cond = std::numeric_limits<double>::infinity();
234
235
// if (min.HasValidCovariance()) {
236
// M2::MnEigen eigen;
237
// eigs = eigen(min.UserState().Covariance());
238
239
// double min_pos = std::numeric_limits<double>::infinity();
240
// double max_pos = 0.0;
241
// for (double e : eigs) {
242
// if (std::isfinite(e) && e > 0.0) {
243
// min_pos = std::min(min_pos, e);
244
// max_pos = std::max(max_pos, e);
245
// }
246
// }
247
// if (min_pos < std::numeric_limits<double>::infinity() && max_pos > 0.0) {
248
// cond = max_pos / min_pos;
249
// }
250
251
// if (opt.verbose) {
252
// if (!eigs.empty()) {
253
// std::cout << "Cov eigen min/max = "
254
// << std::setprecision(6) << eigs.front()
255
// << " / " << eigs.back()
256
// << " (cond ~ " << cond << ")\n";
257
// } else {
258
// std::cout << "Cov eigenvalues unavailable\n";
259
// }
260
// }
261
// }
262
263
// MinuitJointFit out;
264
// out.fmin = min.Fval();
265
// out.edm = min.Edm();
266
// out.nfcn = min.NFcn();
267
// out.ok = min.IsValid();
268
269
// out.has_valid_covar = min.HasValidCovariance();
270
// out.has_posdef_covar = min.HasPosDefCovar();
271
// out.has_accurate_covar = min.HasAccurateCovar();
272
// out.made_posdef = min.HasMadePosDefCovar();
273
274
// out.cov_eigs = std::move(eigs);
275
// out.cond_number = cond;
276
277
// const auto& st = min.UserState();
278
// const std::size_t n = x0.size();
279
280
// out.x_hat.resize(n);
281
// out.x_err.assign(n, 0.0);
282
// out.cov = RealMatrix(n, n);
283
284
// for (std::size_t i = 0; i < n; ++i) {
285
// out.x_hat[i] = st.Value(names[i].c_str());
286
// out.x_err[i] = st.Error(names[i].c_str());
287
// }
288
289
// if (min.HasValidCovariance()) {
290
// const auto& cov = st.Covariance();
291
// for (std::size_t i = 0; i < n; ++i) {
292
// for (std::size_t j = 0; j < n; ++j) {
293
// out.cov.at(i, j) = cov(i, j);
294
// }
295
// }
296
// }
297
298
// return out;
299
// }
300
301
// struct ProfileXYResult {
302
// double fmin = 1e300;
303
// std::vector<double> x_hat;
304
// bool ok = false;
305
// };
306
307
// static ProfileXYResult profiled_fit_at_fixed_xy(
308
// const std::function<double(const std::vector<double>&)>& f_joint,
309
// const std::vector<std::string>& names,
310
// const std::vector<double>& x_start,
311
// const std::vector<double>& scale_hints,
312
// const std::vector<ParamLimit>& limits,
313
// unsigned px,
314
// unsigned py,
315
// double xval,
316
// double yval,
317
// unsigned strategy,
318
// unsigned max_fcn,
319
// double tolerance
320
// ) {
321
// GenericFCN fcn(f_joint, 0.5);
322
323
// M2::MnUserParameters upar;
324
// for (std::size_t i = 0; i < x_start.size(); ++i) {
325
// upar.Add(names[i].c_str(), x_start[i], safe_step(x_start[i], scale_hints[i]));
326
// }
327
328
// for (const auto& lim : limits) {
329
// if (lim.idx < names.size()) {
330
// upar.SetLimits(names[lim.idx].c_str(), lim.low, lim.high);
331
// }
332
// }
333
334
// M2::MnMigrad migrad(fcn, upar, strategy);
335
// migrad.SetValue(px, xval);
336
// migrad.SetValue(py, yval);
337
// migrad.Fix(px);
338
// migrad.Fix(py);
339
340
// M2::FunctionMinimum min = migrad(max_fcn, tolerance);
341
342
// ProfileXYResult out;
343
// out.ok = min.IsValid();
344
// out.fmin = out.ok ? min.Fval() : 1e300;
345
// out.x_hat = x_start;
346
347
// if (out.ok) {
348
// const auto& st = min.UserState();
349
// for (std::size_t i = 0; i < x_start.size(); ++i) {
350
// out.x_hat[i] = st.Value(names[i].c_str());
351
// }
352
// } else {
353
// out.x_hat[px] = xval;
354
// out.x_hat[py] = yval;
355
// out.fmin = f_joint(out.x_hat);
356
// }
357
358
// return out;
359
// }
360
361
// // -----------------------------------------------------------------------------
362
// // Local estimator using Minuit
363
// // -----------------------------------------------------------------------------
364
365
// struct JointFitOutput {
366
// FitResult fr;
367
// MinuitJointFit mj;
368
// std::vector<std::string> names; // full order [p, eta]
369
// std::vector<double> scale_hints; // full order [p, eta]
370
// std::vector<ParamLimit> limits; // full order indices
371
// };
372
373
// class MinuitMLEstimatorLocal {
374
// public:
375
// // using ModelFn = ProfiledLikelihood::ModelFn;
376
377
// MinuitMLEstimatorLocal(LikelihoodContext ctx,
378
// ModelFn model,
379
// std::size_t max_fcn,
380
// double tolerance,
381
// unsigned strategy)
382
// : like_(std::move(ctx))
383
// , model_(std::move(model))
384
// , max_fcn_(max_fcn)
385
// , tolerance_(tolerance)
386
// , strategy_(strategy) {}
387
388
// std::function<double(const std::vector<double>&)> make_joint_f(std::size_t p_dim) const {
389
// return [this, p_dim](const std::vector<double>& x) -> double {
390
// Vector p(x.begin(), x.begin() + p_dim);
391
// Vector eta(x.begin() + p_dim, x.end());
392
// return nll(p, eta);
393
// };
394
// }
395
396
// JointFitOutput fit_joint_with_minuit(
397
// const std::vector<ParamId>& p_ids,
398
// const std::vector<ParamId>& eta_ids,
399
// const Vector& p0
400
// ) const {
401
// const std::size_t p_dim = p0.size();
402
403
// // Vector eta0 = like_.nuisance_central_values;
404
// Vector eta0;
405
// for (auto elem : like_.nuis_defs) {
406
// eta0.push_back(elem.value);
407
// }
408
// Vector eta_scales = like_.nuisance_dist->get_stds();
409
410
// if (eta0.size() != eta_scales.size()) {
411
// throw std::runtime_error("eta central values and eta stds do not have same size");
412
// }
413
414
// std::vector<double> x0;
415
// x0.reserve(p_dim + eta0.size());
416
// x0.insert(x0.end(), p0.begin(), p0.end());
417
// x0.insert(x0.end(), eta0.begin(), eta0.end());
418
419
// std::vector<double> scale_hints;
420
// scale_hints.reserve(x0.size());
421
422
// for (std::size_t i = 0; i < p_dim; ++i) {
423
// double hint = std::fabs(p0[i]);
424
// if (hint < 1e-3) hint = 0.01;
425
// scale_hints.push_back(hint);
426
// }
427
// for (double s : eta_scales) {
428
// scale_hints.push_back(std::max(1e-12, std::fabs(s)));
429
// }
430
431
// std::vector<std::string> names;
432
// names.reserve(x0.size());
433
// for (const auto& pid : p_ids) names.push_back(stream_str(pid));
434
// for (const auto& pid : eta_ids) names.push_back(stream_str(pid));
435
436
// std::vector<ParamLimit> limits;
437
438
// // bornes sur les paramètres de fit
439
// for (std::size_t i = 0; i < p_dim; ++i) {
440
// if (names[i].find("FCONST") != std::string::npos) {
441
// limits.push_back(ParamLimit{i, 0.05, 0.35});
442
// }
443
// }
444
445
// // bornes sur certains nuisances sensibles / positifs
446
// for (std::size_t i = p_dim; i < names.size(); ++i) {
447
// const std::string& nm = names[i];
448
// const double c = x0[i];
449
// const double s = std::max(1e-12, std::fabs(scale_hints[i]));
450
451
// if (nm.find("SMINPUTS:3") != std::string::npos) {
452
// limits.push_back(ParamLimit{i, 0.05, 0.30});
453
// } else if (nm.find("MASS:") != std::string::npos ||
454
// nm.find("FLIFE:") != std::string::npos ||
455
// nm.find("FCONST:") != std::string::npos ||
456
// nm.find("FMASS:") != std::string::npos ||
457
// nm.find("SMINPUTS:5") != std::string::npos ||
458
// nm.find("SMINPUTS:6") != std::string::npos) {
459
// limits.push_back(ParamLimit{i, std::max(1e-12, c - 5.0 * s), c + 5.0 * s});
460
// }
461
// }
462
463
// auto f_joint = make_joint_f(p_dim);
464
465
// MinuitFitOptions opt;
466
// opt.up = 0.5;
467
// opt.strategy = strategy_;
468
// opt.max_fcn = static_cast<unsigned>(max_fcn_);
469
// opt.tolerance = tolerance_;
470
// opt.run_hesse = true;
471
// opt.verbose = true;
472
473
// MinuitJointFit mj = minuit_migrad_hesse(
474
// f_joint, names, x0, scale_hints, limits, opt
475
// );
476
477
// FitResult fr;
478
// fr.ell_hat = mj.fmin;
479
480
// fr.p_hat.assign(mj.x_hat.begin(), mj.x_hat.begin() + p_dim);
481
// fr.eta_hat.assign(mj.x_hat.begin() + p_dim, mj.x_hat.end());
482
483
// fr.p_hat_std.assign(p_dim, 0.0);
484
// fr.p_hat_correlations = RealMatrix(p_dim, p_dim);
485
486
// if (mj.has_valid_covar) {
487
// for (std::size_t i = 0; i < p_dim; ++i) {
488
// fr.p_hat_std[i] = std::sqrt(std::max(0.0, mj.cov.at(i, i)));
489
// }
490
491
// for (std::size_t i = 0; i < p_dim; ++i) {
492
// for (std::size_t j = 0; j < p_dim; ++j) {
493
// const double di = std::sqrt(std::max(0.0, mj.cov.at(i, i)));
494
// const double dj = std::sqrt(std::max(0.0, mj.cov.at(j, j)));
495
// fr.p_hat_correlations.at(i, j) =
496
// (di > 0.0 && dj > 0.0) ? (mj.cov.at(i, j) / (di * dj)) : 0.0;
497
// }
498
// }
499
// } else {
500
// for (std::size_t i = 0; i < p_dim && i < mj.x_err.size(); ++i) {
501
// fr.p_hat_std[i] = mj.x_err[i];
502
// fr.p_hat_correlations.at(i, i) = 1.0;
503
// }
504
// }
505
506
// return JointFitOutput{fr, mj, names, scale_hints, limits};
507
// }
508
509
// private:
510
// double nll(const Vector& p, const Vector& eta) const {
511
// Vector pred = model_(p, eta);
512
513
// Vector r(pred.size());
514
// for (std::size_t i = 0; i < pred.size(); ++i) {
515
// r[i] = pred[i] - like_.exp_obs_values[i];
516
// }
517
518
// const double ell_obs = like_.exp_obs_dist->logpdf(r);
519
// const double ell_eta = like_.nuisance_dist->logpdf(eta);
520
521
// return -(ell_obs + ell_eta);
522
// }
523
524
// LikelihoodContext like_;
525
// ModelFn model_;
526
// std::size_t max_fcn_;
527
// double tolerance_;
528
// unsigned strategy_;
529
// };
530
531
// // -----------------------------------------------------------------------------
532
// // main
533
// // -----------------------------------------------------------------------------
534
535
int
main
(
int
argc,
char
** argv) {
536
// HyperisoMaster hyp;
537
// HyperisoConfig config_hyp;
538
// config_hyp.model = Model::SM;
539
// hyp.init("lha/si_input.flha", config_hyp);
540
541
// auto oint = std::make_shared<ObservableInterface>();
542
// oint->add_observable(ObservableMapper::to_id(Observables::BR_BS_MUMU_UNTAG), QCDOrder::LO, true)
543
// .add_observable(ObservableMapper::to_id(Observables::BR_BD_MUMU), QCDOrder::LO, true);
544
545
// StatisticConfig config;
546
// config.MC_draws = 100;
547
548
// // Ici ces valeurs pilotent Minuit
549
// config.MLE_max_iter = 120000;
550
// config.MLE_tol = 0.2;
551
552
// std::vector<ParamId> p_specs = {
553
// ParamId{ParameterType::FLAVOR, "FCONST", {511, 1}},
554
// ParamId{ParameterType::FLAVOR, "FCONST", {531, 1}}
555
// };
556
557
// std::shared_ptr<IStatParamOptimizerProxy> spop = std::make_shared<StatParamOptimizerProxy>();
558
// auto model = std::make_shared<ObservableInterfaceProxy>(oint, spop);
559
560
// std::shared_ptr<INuisancePathsProvider> npp = std::make_shared<DefaultNuisancePathsProvider>();
561
562
// StatisticManager stat(
563
// config,
564
// model,
565
// std::make_shared<StatCorrelationProxy>(),
566
// std::make_shared<StatParameterProxy>(),
567
// std::make_shared<StatParamSourcesProxy>(),
568
// std::make_shared<StatDependencyPruner>(),
569
// std::make_shared<NuisanceReader>(npp),
570
// spop
571
// );
572
573
// LOG_INFO("fill_cache #1");
574
// // stat.fill_cache();
575
576
// auto start_u = std::chrono::steady_clock::now();
577
// stat.compute_uncertainties();
578
// auto stop_u = std::chrono::steady_clock::now();
579
580
// auto us_u = std::chrono::duration_cast<std::chrono::microseconds>(stop_u - start_u).count();
581
// std::cout << "Uncertainty estimation time: " << us_u << " us\n";
582
583
// LOG_INFO("fill_cache #2");
584
// // stat.fill_cache();
585
586
// auto p_specs_map = stat.get_p_specs(p_specs);
587
// auto eta_specs_real = stat.get_all_obss_deps();
588
// for (const auto& [pid, _] : p_specs_map) eta_specs_real.erase(pid);
589
// auto exp_obs_map = stat.get_obs_exp();
590
591
// auto unz_p = unzip(p_specs_map);
592
// auto unz_eta = unzip(eta_specs_real);
593
// auto unz_obs = unzip(exp_obs_map);
594
595
// std::vector<ParamId> p_ids = unz_p.ids;
596
// std::vector<ParamId> eta_ids = unz_eta.ids;
597
// std::vector<ExperimentObs> obs_ids = unz_obs.ids;
598
599
// auto nuisance_dist = stat.build_nuisance_distribution();
600
// auto exp_obs_dist = stat.build_exp_data_distribution();
601
602
// if (nuisance_dist->get_stds().size() != unz_eta.vals.size()) {
603
// std::cerr << "[ERROR] nuisance std size = " << nuisance_dist->get_stds().size()
604
// << " but eta central size = " << unz_eta.vals.size() << "\n";
605
// return 3;
606
// }
607
608
// if (exp_obs_dist->dim() != unz_obs.vals.size()) {
609
// std::cerr << "[ERROR] exp obs dim = " << exp_obs_dist->dim()
610
// << " but values size = " << unz_obs.vals.size() << "\n";
611
// return 4;
612
// }
613
614
// LikelihoodContext ctx;
615
// ctx.nuisance_dist = std::move(nuisance_dist);
616
// ctx.exp_obs_dist = std::move(exp_obs_dist);
617
// // ctx.nuisance_central_values = unz_eta.vals;
618
// ctx.exp_obs_values = unz_obs.vals;
619
620
// auto model_fn = [model, obs_ids, p_ids, eta_ids](const Vec& p_vec, const Vec& eta_vec) -> Vec {
621
// auto pred_map = model->predict_optimized(zip(p_ids, p_vec), zip(eta_ids, eta_vec));
622
623
// Vec out;
624
// out.reserve(obs_ids.size());
625
626
// for (const auto& bid : obs_ids) {
627
// const auto& vec = pred_map.at(bid.obs.s);
628
629
// auto it = std::find_if(vec.begin(), vec.end(), [&](const ObservableValue& ov) {
630
// auto bin = ov.bin.value_or(std::pair<double, double>{0., 0.});
631
// return bin == bid.obs.p;
632
// });
633
634
// if (it == vec.end()) {
635
// throw std::runtime_error("Missing predicted observable/bin");
636
// }
637
638
// out.push_back(it->value);
639
// }
640
641
// return out;
642
// };
643
644
// auto start_m = std::chrono::steady_clock::now();
645
// MinuitMLEstimatorLocal est(std::move(ctx), model_fn, config.MLE_max_iter, config.MLE_tol, 2);
646
// JointFitOutput fit_out = est.fit_joint_with_minuit(p_ids, eta_ids, unz_p.vals);
647
// auto stop_m = std::chrono::steady_clock::now();
648
649
// const auto& fr = fit_out.fr;
650
// const auto& mj = fit_out.mj;
651
652
// auto us_m = std::chrono::duration_cast<std::chrono::microseconds>(stop_m - start_m).count();
653
// std::cout << "\nMLE (Minuit) fitting time: " << us_m << " us\n";
654
655
// std::cout << "ell_hat = " << std::setprecision(17) << fr.ell_hat << "\n";
656
// std::cout << "p_hat = "; print_vec(fr.p_hat);
657
// std::cout << "p_hat_std = "; print_vec(fr.p_hat_std);
658
// std::cout << "p_hat_correlations:\n" << fr.p_hat_correlations << "\n";
659
660
// if (!mj.ok) {
661
// std::cerr << "[ERROR] Minuit fit invalid.\n";
662
// return 5;
663
// }
664
665
// if (!mj.has_valid_covar || !mj.has_posdef_covar) {
666
// std::cerr << "[WARN] Covariance is not fully healthy."
667
// << " valid=" << mj.has_valid_covar
668
// << " posdef=" << mj.has_posdef_covar
669
// << " accurate=" << mj.has_accurate_covar
670
// << " cond=" << mj.cond_number << "\n";
671
// }
672
673
// {
674
// std::vector<std::string> p_names;
675
// for (const auto& pid : p_ids) p_names.push_back(stream_str(pid));
676
// save_bestfit_csv("bestfit.csv", p_names, fr.p_hat, fr.p_hat_std);
677
// std::cout << "[INFO] Wrote bestfit.csv\n";
678
// }
679
680
// // -------------------------------------------------------------------------
681
// // Contour 2D uniquement par grille profilée
682
// // -------------------------------------------------------------------------
683
// if (p_ids.size() == 2) {
684
// const std::string xname = stream_str(p_ids[0]);
685
// const std::string yname = stream_str(p_ids[1]);
686
687
// const unsigned px = 0;
688
// const unsigned py = 1;
689
690
// double x0 = fr.p_hat[0];
691
// double y0 = fr.p_hat[1];
692
// double sx = std::max(0.01, fr.p_hat_std[0]);
693
// double sy = std::max(0.01, fr.p_hat_std[1]);
694
695
// double xlo = std::max(0.05, x0 - 4.0 * sx);
696
// double xhi = std::min(0.35, x0 + 4.0 * sx);
697
// double ylo = std::max(0.05, y0 - 4.0 * sy);
698
// double yhi = std::min(0.35, y0 + 4.0 * sy);
699
700
// if (!(xhi > xlo)) { xlo = 0.10; xhi = 0.30; }
701
// if (!(yhi > ylo)) { ylo = 0.10; yhi = 0.30; }
702
703
// // Grille raisonnable et profilage léger
704
// const std::size_t nx = 31;
705
// const std::size_t ny = 31;
706
// const unsigned profile_strategy = 1;
707
// const unsigned profile_max_fcn = 1200;
708
// const double profile_tol = 0.5;
709
710
// std::vector<double> xs = linspace(xlo, xhi, nx);
711
// std::vector<double> ys = linspace(ylo, yhi, ny);
712
// std::vector<double> z(nx * ny, 1e300);
713
714
// auto f_joint = est.make_joint_f(/*p_dim=*/2);
715
716
// // warm-start : on repart du best-fit global
717
// std::vector<double> seed = mj.x_hat;
718
719
// for (std::size_t iy = 0; iy < ny; ++iy) {
720
// bool reverse = (iy % 2 == 1);
721
722
// if (!reverse) {
723
// for (std::size_t ix = 0; ix < nx; ++ix) {
724
// auto pr = profiled_fit_at_fixed_xy(
725
// f_joint,
726
// fit_out.names,
727
// seed,
728
// fit_out.scale_hints,
729
// fit_out.limits,
730
// px, py,
731
// xs[ix], ys[iy],
732
// profile_strategy,
733
// profile_max_fcn,
734
// profile_tol
735
// );
736
737
// z[iy * nx + ix] = pr.fmin - fr.ell_hat;
738
// seed = pr.x_hat;
739
// }
740
// } else {
741
// for (std::size_t k = 0; k < nx; ++k) {
742
// std::size_t ix = nx - 1 - k;
743
744
// auto pr = profiled_fit_at_fixed_xy(
745
// f_joint,
746
// fit_out.names,
747
// seed,
748
// fit_out.scale_hints,
749
// fit_out.limits,
750
// px, py,
751
// xs[ix], ys[iy],
752
// profile_strategy,
753
// profile_max_fcn,
754
// profile_tol
755
// );
756
757
// z[iy * nx + ix] = pr.fmin - fr.ell_hat;
758
// seed = pr.x_hat;
759
// }
760
// }
761
762
// std::cout << "[INFO] grid row " << (iy + 1) << "/" << ny << " done\n";
763
// }
764
765
// save_grid_csv("grid.csv", xname, yname, xs, ys, z);
766
// std::cout << "[INFO] Wrote grid.csv\n";
767
768
// // diagnostic : minimum trouvé sur la grille
769
// double best_grid = 1e300;
770
// std::size_t best_ix = 0;
771
// std::size_t best_iy = 0;
772
773
// for (std::size_t iy = 0; iy < ny; ++iy) {
774
// for (std::size_t ix = 0; ix < nx; ++ix) {
775
// double val = z[iy * nx + ix];
776
// if (val < best_grid) {
777
// best_grid = val;
778
// best_ix = ix;
779
// best_iy = iy;
780
// }
781
// }
782
// }
783
784
// std::cout << "[INFO] grid min delta_nll = " << best_grid
785
// << " at (" << xs[best_ix] << ", " << ys[best_iy] << ")\n";
786
// std::cout << "[INFO] best-fit = (" << fr.p_hat[0] << ", " << fr.p_hat[1] << ")\n";
787
// }
788
789
return
0;
790
}
main
int main()
Definition
test_dynamic_registry.cpp:12
Hyperiso
core
src
Statistic
app
test_contour_minuit2.cpp
Generated by
1.9.8