DiSMEC++
histogram.cpp
Go to the documentation of this file.
1 // Copyright (c) 2021, Aalto University, developed by Erik Schultheis
2 // All rights reserved.
3 //
4 // SPDX-License-Identifier: MIT
5 
6 #include "histogram.h"
7 #include "collection.h"
8 #include "utils/conversion.h"
9 #include <nlohmann/json.hpp>
10 
11 using namespace dismec;
12 using namespace dismec::stats;
13 
14 #if DISMEC_STATS_SUPPORT_HISTOGRAM
15 using namespace boost::histogram;
16 
17 
18 namespace axis = boost::histogram::axis;
19 
20 using log_axis_t = axis::regular<real_t, axis::transform::log>;
21 using lin_axis_t = axis::regular<real_t>;
22 
23 namespace {
24  template<class T>
25  void combine_histograms(T& target, const T& source) {
26  auto index_s = indexed(source, coverage::all);
27  auto index_t = indexed(target, coverage::all);
28 
29  auto s_it = begin(index_s);
30  auto t_it = begin(index_t);
31  auto end_it = end(index_s);
32  while(s_it != end_it) {
33  **t_it += **s_it;
34  ++t_it;
35  ++s_it;
36  }
37  }
38 
39  template<class T, class U>
40  void combine_histograms(T& target, const U& source) {
41  throw std::logic_error("Trying to combine histograms of different type");
42  }
43 
44  template<class... Args>
45  nlohmann::json to_json(const histogram<Args...>& hist) {
46  nlohmann::json result;
47  nlohmann::json lower_bounds;
48  nlohmann::json upper_bounds;
49  nlohmann::json counts;
50 
51  for(auto&& b : indexed(hist, coverage::all)) {
52  lower_bounds.push_back(b.bin(0).lower());
53  upper_bounds.push_back(b.bin(0).upper());
54  counts.push_back(long(*b));
55  }
56 
57  result["Lower"] = std::move(lower_bounds);
58  result["Upper"] = std::move(upper_bounds);
59  result["Count"] = std::move(counts);
60  return result;
61  }
62 
63  template<class Axis>
64  std::string get_type();
65 
66  template<>
67  std::string get_type<lin_axis_t>() {
68  return "Hist1dLin";
69  }
70  template<>
71  std::string get_type<log_axis_t>() {
72  return "Hist1dLog";
73  }
74 
75  template<class Axis>
76  real_t transform(real_t value) {
77  return value;
78  }
79 
80  template<>
81  real_t transform<log_axis_t>(real_t value) {
82  return std::abs(value);
83  }
84 }
85 
86 
87 template<class Axis>
88 HistogramStat<Axis>::HistogramStat(int bins, real_t min, real_t max) :
89  m_Histogram(make_histogram(Axis(bins, min, max))),
90  m_Bins(bins), m_Min(min), m_Max(max) {
91 
92 }
93 
94 template<class Axis>
95 void HistogramStat<Axis>::record_int(long value) {
96  record_real(real_t(value));
97 }
98 
99 template<class Axis>
100 void HistogramStat<Axis>::record_real(real_t value) {
101  m_Histogram(value);
102 }
103 
104 template<class Axis>
105 void HistogramStat<Axis>::record_vec(const DenseRealVector& vector) {
106  for(int i = 0; i < vector.size(); ++i) {
107  m_Histogram(transform<Axis>(vector.coeff(i)));
108  }
109 }
110 
111 template<class Axis>
112 std::unique_ptr<Statistics> HistogramStat<Axis>::clone() const {
113  return std::make_unique<HistogramStat<Axis>>(m_Bins, m_Min, m_Max);
114 }
115 template<class Axis>
116 void HistogramStat<Axis>::merge_imp(const HistogramStat<Axis>& other) {
117  combine_histograms(m_Histogram, other.m_Histogram);
118 }
119 
120 template<class Axis>
121 nlohmann::json HistogramStat<Axis>::to_json() const {
122  auto temp = ::to_json(m_Histogram);
123  temp["Type"] = get_type<Axis>();
124  return temp;
125 }
126 
127 std::unique_ptr<Statistics> dismec::stats::make_linear_histogram(int bins, real_t min, real_t max) {
128  return std::make_unique<HistogramStat<lin_axis_t>>(bins, min, max);
129 }
130 
131 std::unique_ptr<Statistics> dismec::stats::make_logarithmic_histogram(int bins, real_t min, real_t max) {
132  return std::make_unique<HistogramStat<log_axis_t>>(bins, min, max);
133 }
134 
135 template<class Axis>
136 TaggedHistogramStat<Axis>::TaggedHistogramStat(std::string tag, int max_tag, int bins, real_t min, real_t max) :
137  m_Bins(bins), m_MaxTag(max_tag), m_Min(min), m_Max(max), m_Tag(TagContainer::create_empty_container(std::move(tag))) {
138 
139 }
140 
141 template<class Axis>
142 void TaggedHistogramStat<Axis>::record_int(long value) {
143  record_real(real_t(value));
144 }
145 
146 template<class Axis>
147 auto TaggedHistogramStat<Axis>::get_active_hist() -> histogram_t& {
148  int tag = m_Tag.get_value();
149  if(tag < 0)
150  throw std::logic_error("Missing tag!");
151  if(tag > m_MaxTag)
152  tag = m_MaxTag;
153 
154  while(tag >= ssize(m_Histograms)) {
155  m_Histograms.push_back(make_histogram(Axis(m_Bins, m_Min, m_Max)));
156  }
157  return m_Histograms[tag];
158 }
159 
160 template<class Axis>
161 void TaggedHistogramStat<Axis>::record_real(real_t value) {
162  get_active_hist()(value);
163 }
164 
165 template<class Axis>
166 void TaggedHistogramStat<Axis>::record_vec(const DenseRealVector& vector) {
167  auto& hist = get_active_hist();
168  for(int i = 0; i < vector.size(); ++i) {
169  hist(transform<Axis>(vector.coeff(i)));
170  }
171 }
172 
173 template<class Axis>
174 std::unique_ptr<Statistics> TaggedHistogramStat<Axis>::clone() const {
175  return std::make_unique<TaggedHistogramStat<Axis>>(m_Tag.get_name(), m_MaxTag, m_Bins, m_Min, m_Max);
176 }
177 
178 template<class Axis>
179 void TaggedHistogramStat<Axis>::merge_imp(const TaggedHistogramStat<Axis>& other) {
180  m_Histograms.reserve(other.m_Histograms.size());
181  while(other.m_Histograms.size() > m_Histograms.size()) {
182  m_Histograms.emplace_back(make_histogram(Axis(m_Bins, m_Min, m_Max)));
183  }
184 
185  for(int i = 0; i < ssize(other.m_Histograms); ++i) {
186  combine_histograms(m_Histograms[i], other.m_Histograms[i]);
187  }
188 }
189 
190 template<class Axis>
191 nlohmann::json TaggedHistogramStat<Axis>::to_json() const {
192  nlohmann::json result;
193  for(int i = 0; i < ssize(m_Histograms); ++i) {
194  auto temp = ::to_json(m_Histograms[i]);
195  result["Counts"].push_back(temp["Count"]);
196  if ( i == 0 ) {
197  result["Lower"] = std::move(temp["Lower"]);
198  result["Upper"] = std::move(temp["Upper"]);
199  }
200  }
201  result["Type"] = "Tagged" + get_type<Axis>();
202  return result;
203 }
204 
205 template<class Axis>
206 void TaggedHistogramStat<Axis>::setup(const StatisticsCollection& source) {
207  m_Tag = source.get_tag_by_name(m_Tag.get_name());
208 }
209 
210 std::unique_ptr<Statistics> dismec::stats::make_linear_histogram(std::string tag, int max_tag, int bins, real_t min, real_t max) {
211  return std::make_unique<TaggedHistogramStat<lin_axis_t>>(std::move(tag), max_tag, bins, min, max);
212 }
213 
214 std::unique_ptr<Statistics> dismec::stats::make_logarithmic_histogram(std::string tag, int max_tag, int bins, real_t min, real_t max) {
215  return std::make_unique<TaggedHistogramStat<log_axis_t>>(std::move(tag), max_tag, bins, min, max);
216 }
217 #else
218 std::unique_ptr<Statistics> dismec::stats::make_linear_histogram(int bins, real_t min, real_t max) {
219  throw std::runtime_error("Histogram statistics not supported in this binary");
220 }
221 
222 std::unique_ptr<Statistics> dismec::stats::make_logarithmic_histogram(int bins, real_t min, real_t max) {
223  throw std::runtime_error("Histogram statistics not supported in this binary");
224 }
225 std::unique_ptr<Statistics> dismec::stats::make_linear_histogram(std::string tag, int max_tag, int bins, real_t min, real_t max) {
226  throw std::runtime_error("Histogram statistics not supported in this binary");
227 }
228 
229 std::unique_ptr<Statistics> dismec::stats::make_logarithmic_histogram(std::string tag, int max_tag, int bins, real_t min, real_t max) {
230  throw std::runtime_error("Histogram statistics not supported in this binary");
231 }
232 #endif
This class manages a collection of named Statistics objects.
Definition: collection.h:47
TagContainer get_tag_by_name(const std::string &name) const
Gets the tag with the given name.
Definition: collection.cpp:105
A tag container combines a name with a shared pointer, which points to the tag value.
Definition: stats_base.h:30
nlohmann::json json
Definition: model-io.cpp:22
std::unique_ptr< Statistics > make_linear_histogram(int bins, real_t min, real_t max)
Definition: histogram.cpp:218
std::unique_ptr< Statistics > make_logarithmic_histogram(int bins, real_t min, real_t max)
Definition: histogram.cpp:222
Main namespace in which all types, classes, and functions are defined.
Definition: app.h:15
constexpr auto ssize(const C &c) -> std::common_type_t< std::ptrdiff_t, std::make_signed_t< decltype(c.size())>>
signed size free function. Taken from https://en.cppreference.com/w/cpp/iterator/size
Definition: conversion.h:42
types::DenseVector< real_t > DenseRealVector
Any dense, real values vector.
Definition: matrix_types.h:40
float real_t
The default type for floating point values.
Definition: config.h:17
float real_t
Definition: regularizers.h:11