R3BROOT
R3B analysis software
Loading...
Searching...
No Matches
R3BHuberRegression.cxx
Go to the documentation of this file.
2#include <Math/Functor.h>
3#include <Math/Minimizer.h>
4#include <Math/ProbFuncMathCore.h>
5#include <algorithm>
6#include <cstdlib>
7#include <functional>
8#include <memory>
9#include <ranges>
10#include <span>
11#include <utility>
12#include <vector>
13
14namespace R3B
15{
16 HuberRegressor::HuberRegressor(Config config, std::unique_ptr<ROOT::Math::Minimizer> minimizer)
17 : config_{ config }
18 , minimizer_{ std::move(minimizer) }
19 {
20 minimizer_->SetTolerance(config.tolerance);
21 minimizer_->SetPrintLevel(-1);
23 }
24
25 auto HuberRegressor::train_from_data(const std::vector<double>& x_vals, const std::vector<double>& y_vals) -> bool
26 {
27 // auto loss_functor =
28 auto functor = ROOT::Math::Functor{ [&](const double* raw_pars) -> double { return calculate_loss(raw_pars); },
30 minimizer_->SetFunction(functor);
31 x_vals_ = std::span{ x_vals };
32 y_vals_ = std::span{ y_vals };
33 auto is_ok = minimizer_->Minimize();
34
35 const auto errors = std::span(minimizer_->Errors(), HuberRegressor::n_pars);
37 set_par_errors(minimizer_->Errors());
38 result_.iteration = static_cast<int>(minimizer_->NIterations());
39 result_.n_data = x_vals_.size();
40 if (not is_ok)
41 {
42 result_.is_success = false;
43 return false;
44 }
45
46 result_.is_success = true;
47 return true;
48 }
49
50 void HuberRegressor::set_par_values(const double* raw_pars_ptr)
51 {
52 const auto vals = std::span(raw_pars_ptr, HuberRegressor::n_pars);
53 result_.weight.value = vals[0];
54 result_.bias.value = vals[1];
55 }
56
57 void HuberRegressor::set_par_errors(const double* raw_error_ptr)
58 {
59 const auto vals = std::span(raw_error_ptr, HuberRegressor::n_pars);
60 result_.weight.error = vals[0];
61 result_.bias.error = vals[1];
62 }
63
65 {
66 minimizer_->SetVariable(0, "weight", config_.weight.init, config_.weight.learning_rate);
67 minimizer_->SetVariable(1, "bias", config_.bias.init, config_.bias.learning_rate);
68 }
69
70 auto HuberRegressor::calculate_p_value(const std::vector<double>& y_errs, double scale) -> double
71 {
72 auto chi_square_view = std::views::zip_transform(
73 [&](auto x_val, auto y_val, auto y_err) -> double
74 {
75 auto [is_outlier, residual] = check_outlier(x_val, y_val);
76
77 if (is_outlier)
78 {
79 return 0.;
80 }
81 return residual * residual / y_err / scale;
82 },
83 x_vals_,
84 y_vals_,
85 y_errs);
86 const auto chi_square = std::ranges::fold_left(chi_square_view, 0., std::plus{});
87 return ROOT::Math::chisquared_cdf_c(chi_square, static_cast<double>(y_errs.size() - 1));
88 }
89
90 auto HuberRegressor::check_outlier(double x_val, double y_val, const std::pair<double, double>& weight_bias) const
91 -> std::pair<bool, double>
92 {
93 const auto residual = std::abs(y_val - (x_val * weight_bias.first) - weight_bias.second);
94 return std::make_pair(residual > sigma_, residual);
95 }
96
97 auto HuberRegressor::check_outlier(double x_val, double y_val) const -> std::pair<bool, double>
98 {
99 return check_outlier(x_val, y_val, std::make_pair(result_.weight.value, result_.bias.value));
100 }
101
102 auto HuberRegressor::calculate_loss(const double* raw_pars) -> double
103 {
104 set_par_values(raw_pars);
105 const auto weight = result_.weight.value;
106 const auto bias = result_.bias.value;
107
108 return std::ranges::fold_left(std::views::zip_transform(
109 [&](auto x_val, auto y_val) -> double
110 {
111 const auto residual = std::abs(y_val - (x_val * weight) - bias);
112 if (residual > sigma_)
113 {
114 return sigma_ * (residual - sigma_ / 2.);
115 }
116 return residual * residual / 2;
117 },
118 x_vals_,
119 y_vals_),
120 0.,
121 std::plus{});
122 }
123} // namespace R3B
HuberRegressor(Config config=Config{}, std::unique_ptr< ROOT::Math::Minimizer > minimizer=std::unique_ptr< ROOT::Math::Minimizer >{ ROOT::Math::Factory::CreateMinimizer("Minuit2") })
std::unique_ptr< ROOT::Math::Minimizer > minimizer_
auto train_from_data(const std::vector< double > &x_vals, const std::vector< double > &y_vals) -> bool
std::span< const double > x_vals_
static constexpr auto n_pars
std::span< const double > y_vals_
void set_par_errors(const double *raw_error_ptr)
auto check_outlier(double x_val, double y_val) const -> std::pair< bool, double >
auto calculate_p_value(const std::vector< double > &y_errs, double scale=1.) -> double
void set_par_values(const double *raw_pars_ptr)
auto calculate_loss(const double *raw_pars) -> double
HuberRegressorConfig Config