Hyperiso 1.0.3
Modular flavour-physics calculations, Wilson coefficients and statistical inference
Loading...
Searching...
No Matches
LikelihoodMarginal.cpp
Go to the documentation of this file.
2
3LikelihoodMarginal::LikelihoodMarginal(std::vector<double> values,
4 std::vector<double> weights,
5 unsigned int seed,
6 bool standardize)
7 : eng_(seed), u01_(0.0, 1.0), values_(std::move(values)), standardize_(standardize)
8{
9 if (values_.empty()) throw std::invalid_argument("LikelihoodDiscrete: empty values.");
10 if (weights.size() != values_.size()) throw std::invalid_argument("LikelihoodDiscrete: weights size mismatch.");
11
12 // compute mean/std if standardize requested (using normalized weights)
13 double wsum = 0.0;
14 for (double w : weights) {
15 if (!(w >= 0.0) || !std::isfinite(w)) throw std::invalid_argument("LikelihoodDiscrete: invalid weight (must be finite >=0).");
16 wsum += w;
17 }
18 if (wsum <= 0.0) throw std::invalid_argument("LikelihoodDiscrete: sum(weights) must be > 0.");
19
20 if (standardize_) {
21 // normalize weights for moments
22 double m = 0.0;
23 for (std::size_t i = 0; i < values_.size(); ++i) m += values_[i] * (weights[i] / wsum);
24
25 double v = 0.0;
26 for (std::size_t i = 0; i < values_.size(); ++i) {
27 double d = values_[i] - m;
28 v += d * d * (weights[i] / wsum);
29 }
30 mean_ = m;
31 std_ = (v > 0.0) ? std::sqrt(v) : 1.0;
32 }
33
34 build_alias_tables(std::move(weights));
35}
36
37void LikelihoodMarginal::build_alias_tables(std::vector<double> weights) {
38 const std::size_t n = values_.size();
39 prob_.assign(n, 0.0);
40 alias_.assign(n, 0);
41
42 // Normalize weights to average 1 (scaled by n)
43 double sumw = std::accumulate(weights.begin(), weights.end(), 0.0);
44 if (sumw <= 0.0) throw std::invalid_argument("LikelihoodDiscrete: sum(weights) must be > 0.");
45
46 std::vector<double> scaled(n);
47 for (std::size_t i = 0; i < n; ++i) scaled[i] = (weights[i] * n) / sumw;
48
49 std::vector<std::size_t> small;
50 std::vector<std::size_t> large;
51 small.reserve(n);
52 large.reserve(n);
53
54 for (std::size_t i = 0; i < n; ++i) {
55 if (scaled[i] < 1.0) small.push_back(i);
56 else large.push_back(i);
57 }
58
59 while (!small.empty() && !large.empty()) {
60 const std::size_t s = small.back(); small.pop_back();
61 const std::size_t l = large.back(); large.pop_back();
62
63 prob_[s] = scaled[s];
64 alias_[s] = l;
65
66 scaled[l] = (scaled[l] + scaled[s]) - 1.0;
67 if (scaled[l] < 1.0) small.push_back(l);
68 else large.push_back(l);
69 }
70
71 for (std::size_t i : large) {
72 prob_[i] = 1.0;
73 alias_[i] = i;
74 }
75 for (std::size_t i : small) {
76 prob_[i] = 1.0;
77 alias_[i] = i;
78 }
79}
80
81std::vector<double> LikelihoodMarginal::rvs(std::size_t n) {
82 std::vector<double> out(n);
83 const std::size_t m = values_.size();
84 std::uniform_int_distribution<std::size_t> uid(0, m - 1);
85
86 for (std::size_t k = 0; k < n; ++k) {
87 const std::size_t i = uid(eng_);
88 const double r = u01_(eng_);
89 const std::size_t idx = (r < prob_[i]) ? i : alias_[i];
90 double x = values_[idx];
91 if (standardize_) x = (x - mean_) / std_;
92 out[k] = x;
93 }
94 return out;
95}
std::vector< double > rvs(std::size_t n) override
Draws random samples from the marginal distribution.
LikelihoodMarginal(std::vector< double > values, std::vector< double > weights, unsigned int seed=std::random_device{}(), bool standardize=false)
Constructs a discrete likelihood marginal.
Hash specialization for SymbolId<Tag>.
Definition BlockName.h:353