ATLAS Offline Software
Loading...
Searching...
No Matches
CaloClusterMLGaussianMixture.h
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
3*/
4
5#ifndef CALOCLUSTERCORRECTION_CALOCLUSTERMLCALIBGAUSSIANMIXTURE_H
6#define CALOCLUSTERCORRECTION_CALOCLUSTERMLCALIBGAUSSIANMIXTURE_H
7
8#include <cmath>
9#include <vector>
10#include <numeric>
11#include <algorithm>
12#include <limits>
13
14namespace CaloClusterMLCalib
15{
16 constexpr float epsilon = 1e-9; // Introduced to avoid FPE DIVBYZERO warning in std::log()
17
18 // Helper function for logsumexp
19 float log_sum_exp(const std::vector<float> &vec)
20 {
21 if (vec.empty())
22 {
23 return -std::numeric_limits<float>::infinity();
24 }
25 float max_val = *std::max_element(vec.begin(), vec.end());
26 float sum = 0.0;
27 for (float val : vec)
28 {
29 sum += std::exp(val - max_val);
30 }
31 return max_val + std::log(sum);
32 }
33
34 float log_likelihood(float x, const std::vector<float> &mus, const std::vector<float> &log_sigma2s, const std::vector<float> &alphas)
35 {
36 // Ensure vectors have the correct size
37 assert(mus.size() == 3 && log_sigma2s.size() == 3 && alphas.size() == 3);
38
39 std::vector<float> log_likelihood_components(3);
40
41 for (int i = 0; i < 3; ++i)
42 {
43 // Calculate one-dimensional negative log-Gaussian
44 float neg_log_gauss = std::pow(mus[i] - x, 2.0) / (2.0 * std::exp(log_sigma2s[i])) + 0.5 * log_sigma2s[i];
45 neg_log_gauss += 0.5 * std::log(2.0 * M_PI); // M_PI is a common constant for pi
46
47 // log_prob_components = -neg_log_gauss_i + log(alpha_i)
48 log_likelihood_components[i] = -neg_log_gauss + std::log(alphas[i] + epsilon); // Added epsilon to avoid FPE DIVBYZERO warning
49 }
50
51 // log_prob = log(sum_i exp(log_prob_components_i))
52 return log_sum_exp(log_likelihood_components);
53 }
54
55 float modes(const std::vector<float> &mus, const std::vector<float> &log_sigma2s, const std::vector<float> &alphas)
56 {
57 // Select range to check for maxima
58 float x_min = 0.9 * (*std::min_element(mus.begin(), mus.end()));
59 float x_max = 1.1 * (*std::max_element(mus.begin(), mus.end()));
60
61 // Create array of ranges to check for maxima
62 const int num_points = 1000;
63 std::vector<float> x_test(num_points);
64 float step = (x_max - x_min) / (num_points - 1);
65 for (int i = 0; i < num_points; ++i)
66 {
67 x_test[i] = x_min + i * step;
68 }
69
70 float max_log_likelihood = -std::numeric_limits<float>::infinity();
71 float mode = x_test[0]; // Initialize to first test point instead of 0
72
73 // Find the x-point with the largest likelihood value
74 for (float x : x_test)
75 {
76 float ll = log_likelihood(x, mus, log_sigma2s, alphas);
77 if (ll > max_log_likelihood)
78 {
79 max_log_likelihood = ll;
80 mode = x;
81 }
82 }
83
84 return mode;
85 }
86
87 float sigma_stoch(const std::vector<float> &mus,
88 const std::vector<float> &log_sigma2s,
89 const std::vector<float> &alphas)
90 {
91 float sigma_stoch2 = 0.0;
92 float sum_alphas_mus = 0.0;
93
94 // This loop combines the first three lines of the Python function.
95 for (size_t i = 0; i < mus.size(); ++i)
96 {
97 // Corresponds to: np.sum(alphas * sigma2s, axis=-1)
98 sigma_stoch2 += alphas[i] * std::exp(log_sigma2s[i]);
99 // Corresponds to: np.sum(alphas * np.power(mus, 2), axis=-1)
100 sigma_stoch2 += alphas[i] * std::pow(mus[i], 2);
101 // Accumulates sum for the final term: np.sum(alphas * mus, axis=-1)
102 sum_alphas_mus += alphas[i] * mus[i];
103 }
104
105 // Corresponds to: sigma_stoch2 -= np.power(np.sum(alphas * mus, axis=-1), 2)
106 sigma_stoch2 -= std::pow(sum_alphas_mus, 2);
107
108 // Corresponds to: return np.sqrt(sigma_stoch2)
109 return std::sqrt(sigma_stoch2);
110 }
111}
112
113#endif // CALOCLUSTERCORRECTION_CALOCLUSTERMLCALIBGAUSSIANMIXTURE_H
#define M_PI
std::vector< size_t > vec
#define x
float modes(const std::vector< float > &mus, const std::vector< float > &log_sigma2s, const std::vector< float > &alphas)
float log_likelihood(float x, const std::vector< float > &mus, const std::vector< float > &log_sigma2s, const std::vector< float > &alphas)
float log_sum_exp(const std::vector< float > &vec)
float sigma_stoch(const std::vector< float > &mus, const std::vector< float > &log_sigma2s, const std::vector< float > &alphas)