Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
RHistData.hxx
Go to the documentation of this file.
1 /// \file ROOT/RHistData.h
2 /// \ingroup Hist ROOT7
3 /// \author Axel Naumann <axel@cern.ch>
4 /// \date 2015-06-14
5 /// \warning This is part of the ROOT 7 prototype! It will change without notice. It might trigger earthquakes. Feedback
6 /// is welcome!
7 
8 /*************************************************************************
9  * Copyright (C) 1995-2015, Rene Brun and Fons Rademakers. *
10  * All rights reserved. *
11  * *
12  * For the licensing terms see $ROOTSYS/LICENSE. *
13  * For the list of contributors see $ROOTSYS/README/CREDITS. *
14  *************************************************************************/
15 
16 #ifndef ROOT7_RHistData
17 #define ROOT7_RHistData
18 
19 #include <cmath>
20 #include <vector>
21 #include "ROOT/RSpan.hxx"
22 #include "ROOT/RHistUtils.hxx"
23 
24 namespace ROOT {
25 namespace Experimental {
26 
27 template <int DIMENSIONS, class PRECISION, template <int D_, class P_> class... STAT>
28 class RHist;
29 
30 /**
31  \class RHistStatContent
32  Basic histogram statistics, keeping track of the bin content and the total
33  number of calls to Fill().
34  */
35 template <int DIMENSIONS, class PRECISION>
36 class RHistStatContent {
37 public:
38  /// The type of a (possibly multi-dimensional) coordinate.
39  using CoordArray_t = Hist::CoordArray_t<DIMENSIONS>;
40  /// The type of the weight and the bin content.
41  using Weight_t = PRECISION;
42  /// Type of the bin content array.
43  using Content_t = std::vector<PRECISION>;
44 
45  /**
46  \class RConstBinStat
47  Const view on a RHistStatContent for a given bin.
48  */
49  class RConstBinStat {
50  public:
51  RConstBinStat(const RHistStatContent &stat, int index): fContent(stat.GetBinContent(index)) {}
52  PRECISION GetContent() const { return fContent; }
53 
54  private:
55  PRECISION fContent; ///< The content of this bin.
56  };
57 
58  /**
59  \class RBinStat
60  Modifying view on a RHistStatContent for a given bin.
61  */
62  class RBinStat {
63  public:
64  RBinStat(RHistStatContent &stat, int index): fContent(stat.GetBinContent(index)) {}
65  PRECISION &GetContent() const { return fContent; }
66 
67  private:
68  PRECISION &fContent; ///< The content of this bin.
69  };
70 
71  using ConstBinStat_t = RConstBinStat;
72  using BinStat_t = RBinStat;
73 
74 private:
75  /// Number of calls to Fill().
76  int64_t fEntries = 0;
77 
78  /// Bin content.
79  Content_t fBinContent;
80 
81 public:
82  RHistStatContent() = default;
83  RHistStatContent(size_t in_size): fBinContent(in_size) {}
84 
85  /// Add weight to the bin content at binidx.
86  void Fill(const CoordArray_t & /*x*/, int binidx, Weight_t weight = 1.)
87  {
88  fBinContent[binidx] += weight;
89  ++fEntries;
90  }
91 
92  /// Get the number of entries filled into the histogram - i.e. the number of
93  /// calls to Fill().
94  int64_t GetEntries() const { return fEntries; }
95 
96  /// Get the number of bins.
97  size_t size() const noexcept { return fBinContent.size(); }
98 
99  /// Get the bin content for the given bin.
100  Weight_t operator[](int idx) const { return fBinContent[idx]; }
101  /// Get the bin content for the given bin (non-const).
102  Weight_t &operator[](int idx) { return fBinContent[idx]; }
103 
104  /// Get the bin content for the given bin.
105  Weight_t GetBinContent(int idx) const { return fBinContent[idx]; }
106  /// Get the bin content for the given bin (non-const).
107  Weight_t &GetBinContent(int idx) { return fBinContent[idx]; }
108 
109  /// Retrieve the content array.
110  const Content_t &GetContentArray() const { return fBinContent; }
111  /// Retrieve the content array (non-const).
112  Content_t &GetContentArray() { return fBinContent; }
113 };
114 
115 /**
116  \class RHistStatTotalSumOfWeights
117  Keeps track of the histogram's total sum of weights.
118  */
119 template <int DIMENSIONS, class PRECISION>
120 class RHistStatTotalSumOfWeights {
121 public:
122  /// The type of a (possibly multi-dimensional) coordinate.
123  using CoordArray_t = Hist::CoordArray_t<DIMENSIONS>;
124  /// The type of the weight and the bin content.
125  using Weight_t = PRECISION;
126 
127  /**
128  \class RBinStat
129  No-op; this class does not provide per-bin statistics.
130  */
131  class RBinStat {
132  public:
133  RBinStat(const RHistStatTotalSumOfWeights &, int) {}
134  };
135 
136  using ConstBinStat_t = RBinStat;
137  using BinStat_t = RBinStat;
138 
139 private:
140  /// Sum of weights.
141  PRECISION fSumWeights = 0;
142 
143 public:
144  RHistStatTotalSumOfWeights() = default;
145  RHistStatTotalSumOfWeights(size_t) {}
146 
147  /// Add weight to the bin content at binidx.
148  void Fill(const CoordArray_t & /*x*/, int, Weight_t weight = 1.) { fSumWeights += weight; }
149 
150  /// Get the sum of weights.
151  Weight_t GetSumOfWeights() const { return fSumWeights; }
152 };
153 
154 /**
155  \class RHistStatTotalSumOfSquaredWeights
156  Keeps track of the histogram's total sum of squared weights.
157  */
158 template <int DIMENSIONS, class PRECISION>
159 class RHistStatTotalSumOfSquaredWeights {
160 public:
161  /// The type of a (possibly multi-dimensional) coordinate.
162  using CoordArray_t = Hist::CoordArray_t<DIMENSIONS>;
163  /// The type of the weight and the bin content.
164  using Weight_t = PRECISION;
165 
166  /**
167  \class RBinStat
168  No-op; this class does not provide per-bin statistics.
169  */
170  class RBinStat {
171  public:
172  RBinStat(const RHistStatTotalSumOfSquaredWeights &, int) {}
173  };
174 
175  using ConstBinStat_t = RBinStat;
176  using BinStat_t = RBinStat;
177 
178 private:
179  /// Sum of (weights^2).
180  PRECISION fSumWeights2 = 0;
181 
182 public:
183  RHistStatTotalSumOfSquaredWeights() = default;
184  RHistStatTotalSumOfSquaredWeights(size_t) {}
185 
186  /// Add weight to the bin content at binidx.
187  void Fill(const CoordArray_t & /*x*/, int /*binidx*/, Weight_t weight = 1.) { fSumWeights2 += weight * weight; }
188 
189  /// Get the sum of weights.
190  Weight_t GetSumOfSquaredWeights() const { return fSumWeights2; }
191 };
192 
193 /**
194  \class RHistStatUncertainty
195  Histogram statistics to keep track of the Poisson uncertainty per bin.
196  */
197 template <int DIMENSIONS, class PRECISION>
198 class RHistStatUncertainty {
199 
200 public:
201  /// The type of a (possibly multi-dimensional) coordinate.
202  using CoordArray_t = Hist::CoordArray_t<DIMENSIONS>;
203  /// The type of the weight and the bin content.
204  using Weight_t = PRECISION;
205  /// Type of the bin content array.
206  using Content_t = std::vector<PRECISION>;
207 
208  /**
209  \class RConstBinStat
210  Const view on a RHistStatUncertainty for a given bin.
211  */
212  class RConstBinStat {
213  public:
214  RConstBinStat(const RHistStatUncertainty &stat, int index): fSumW2(stat.GetSumOfSquaredWeights(index)) {}
215  PRECISION GetSumW2() const { return fSumW2; }
216 
217  double GetUncertaintyImpl() const { return std::sqrt(std::abs(fSumW2)); }
218 
219  private:
220  PRECISION fSumW2; ///< The bin's sum of square of weights.
221  };
222 
223  /**
224  \class RBinStat
225  Modifying view on a RHistStatUncertainty for a given bin.
226  */
227  class RBinStat {
228  public:
229  RBinStat(RHistStatUncertainty &stat, int index): fSumW2(stat.GetSumOfSquaredWeights(index)) {}
230  PRECISION &GetSumW2() const { return fSumW2; }
231  // Can never modify this. Set GetSumW2() instead.
232  double GetUncertaintyImpl() const { return std::sqrt(std::abs(fSumW2)); }
233 
234  private:
235  PRECISION &fSumW2; ///< The bin's sum of square of weights.
236  };
237 
238  using ConstBinStat_t = RConstBinStat;
239  using BinStat_t = RBinStat;
240 
241 private:
242  /// Uncertainty of the content for each bin.
243  Content_t fSumWeightsSquared; ///< Sum of squared weights
244 
245 public:
246  RHistStatUncertainty() = default;
247  RHistStatUncertainty(size_t size): fSumWeightsSquared(size) {}
248 
249  /// Add weight to the bin at binidx; the coordinate was x.
250  void Fill(const CoordArray_t & /*x*/, int binidx, Weight_t weight = 1.)
251  {
252  fSumWeightsSquared[binidx] += weight * weight;
253  }
254 
255  /// Calculate a bin's (Poisson) uncertainty of the bin content as the
256  /// square-root of the bin's sum of squared weights.
257  double GetBinUncertaintyImpl(int binidx) const { return std::sqrt(fSumWeightsSquared[binidx]); }
258 
259  /// Get a bin's sum of squared weights.
260  Weight_t GetSumOfSquaredWeights(int binidx) const { return fSumWeightsSquared[binidx]; }
261 
262  /// Get a bin's sum of squared weights.
263  Weight_t &GetSumOfSquaredWeights(int binidx) { return fSumWeightsSquared[binidx]; }
264 
265  /// Get the structure holding the sum of squares of weights.
266  const std::vector<double> &GetSumOfSquaredWeights() const { return fSumWeightsSquared; }
267  /// Get the structure holding the sum of squares of weights (non-const).
268  std::vector<double> &GetSumOfSquaredWeights() { return fSumWeightsSquared; }
269 };
270 
271 /** \class RHistDataMomentUncert
272  For now do as RH1: calculate first (xw) and second (x^2w) moment.
273 */
274 template <int DIMENSIONS, class PRECISION>
275 class RHistDataMomentUncert {
276 public:
277  /// The type of a (possibly multi-dimensional) coordinate.
278  using CoordArray_t = Hist::CoordArray_t<DIMENSIONS>;
279  /// The type of the weight and the bin content.
280  using Weight_t = PRECISION;
281  /// Type of the bin content array.
282  using Content_t = std::vector<PRECISION>;
283 
284  /**
285  \class RBinStat
286  No-op; this class does not provide per-bin statistics.
287  */
288  class RBinStat {
289  public:
290  RBinStat(const RHistDataMomentUncert &, int) {}
291  };
292 
293  using ConstBinStat_t = RBinStat;
294  using BinStat_t = RBinStat;
295 
296 private:
297  std::array<Weight_t, DIMENSIONS> fMomentXW;
298  std::array<Weight_t, DIMENSIONS> fMomentX2W;
299 
300 public:
301  RHistDataMomentUncert() = default;
302  RHistDataMomentUncert(size_t) {}
303 
304  /// Add weight to the bin at binidx; the coordinate was x.
305  void Fill(const CoordArray_t &x, int /*binidx*/, Weight_t weight = 1.)
306  {
307  for (int idim = 0; idim < DIMENSIONS; ++idim) {
308  const PRECISION xw = x[idim] * weight;
309  fMomentXW[idim] += xw;
310  fMomentX2W[idim] += x[idim] * xw;
311  }
312  }
313 };
314 
315 /** \class RHistStatRuntime
316  Interface implementing a pure virtual functions DoFill(), DoFillN().
317  */
318 template <int DIMENSIONS, class PRECISION>
319 class RHistStatRuntime {
320 public:
321  /// The type of a (possibly multi-dimensional) coordinate.
322  using CoordArray_t = Hist::CoordArray_t<DIMENSIONS>;
323  /// The type of the weight and the bin content.
324  using Weight_t = PRECISION;
325  /// Type of the bin content array.
326  using Content_t = std::vector<PRECISION>;
327 
328  /**
329  \class RBinStat
330  No-op; this class does not provide per-bin statistics.
331  */
332  class RBinStat {
333  public:
334  RBinStat(const RHistStatRuntime &, int) {}
335  };
336 
337  using ConstBinStat_t = RBinStat;
338  using BinStat_t = RBinStat;
339 
340  RHistStatRuntime() = default;
341  RHistStatRuntime(size_t) {}
342  virtual ~RHistStatRuntime() = default;
343 
344  virtual void DoFill(const CoordArray_t &x, int binidx, Weight_t weightN) = 0;
345  void Fill(const CoordArray_t &x, int binidx, Weight_t weight = 1.) { DoFill(x, binidx, weight); }
346 };
347 
348 namespace Detail {
349 
350 /** \class RHistBinStat
351  Const view on a bin's statistical data. Combines all STATs' BinStat_t views.
352  */
353 template <class DATA, class... BASES>
354 class RHistBinStat: public BASES... {
355 private:
356  /// Check whether `double T::GetBinUncertaintyImpl(int)` can be called.
357  template <class T>
358  static auto HaveUncertainty(const T *This) -> decltype(This->GetUncertaintyImpl());
359  /// Fall-back case for check whether `double T::GetBinUncertaintyImpl(int)` can be called.
360  template <class T>
361  static char HaveUncertainty(...);
362 
363 public:
364  RHistBinStat(DATA &data, int index): BASES(data, index)... {}
365 
366  /// Whether this provides storage for uncertainties, or whether uncertainties
367  /// are determined as poisson uncertainty of the content.
368  static constexpr bool HasBinUncertainty()
369  {
370  struct AllYourBaseAreBelongToUs: public BASES... {
371  };
372  return sizeof(HaveUncertainty<AllYourBaseAreBelongToUs>(nullptr)) == sizeof(double);
373  }
374  /// Calculate the bin content's uncertainty for the given bin, using base class information,
375  /// i.e. forwarding to a base's `GetUncertaintyImpl()`.
376  template <bool B = true, class = typename std::enable_if<B && HasBinUncertainty()>::type>
377  double GetUncertainty() const
378  {
379  return this->GetUncertaintyImpl();
380  }
381  /// Calculate the bin content's uncertainty for the given bin, using Poisson
382  /// statistics on the absolute bin content. Only available if no base provides
383  /// this functionality. Requires GetContent().
384  template <bool B = true, class = typename std::enable_if<B && !HasBinUncertainty()>::type>
385  double GetUncertainty(...) const
386  {
387  auto content = this->GetContent();
388  return std::sqrt(std::fabs(content));
389  }
390 };
391 
392 /** \class RHistData
393  A RHistImplBase's data, provides accessors to all its statistics.
394  */
395 template <int DIMENSIONS, class PRECISION, class STORAGE, template <int D_, class P_> class... STAT>
396 class RHistData: public STAT<DIMENSIONS, PRECISION>... {
397 private:
398  /// Check whether `double T::GetBinUncertaintyImpl(int)` can be called.
399  template <class T>
400  static auto HaveUncertainty(const T *This) -> decltype(This->GetBinUncertaintyImpl(12));
401  /// Fall-back case for check whether `double T::GetBinUncertaintyImpl(int)` can be called.
402  template <class T>
403  static char HaveUncertainty(...);
404 
405 public:
406  /// Matching RHist
407  using Hist_t = RHist<DIMENSIONS, PRECISION, STAT...>;
408 
409  /// The type of the weight and the bin content.
410  using Weight_t = PRECISION;
411 
412  /// The type of a (possibly multi-dimensional) coordinate.
413  using CoordArray_t = Hist::CoordArray_t<DIMENSIONS>;
414 
415  /// The type of a non-modifying view on a bin.
416  using ConstHistBinStat_t =
417  RHistBinStat<const RHistData, typename STAT<DIMENSIONS, PRECISION>::ConstBinStat_t...>;
418 
419  /// The type of a modifying view on a bin.
420  using HistBinStat_t = RHistBinStat<RHistData, typename STAT<DIMENSIONS, PRECISION>::BinStat_t...>;
421 
422  /// Number of dimensions of the coordinates
423  static constexpr int GetNDim() noexcept { return DIMENSIONS; }
424 
425  RHistData() = default;
426 
427  /// Constructor providing the number of bins (incl under, overflow) to the
428  /// base classes.
429  RHistData(size_t size): STAT<DIMENSIONS, PRECISION>(size)... {}
430 
431  /// Fill weight at x to the bin content at binidx.
432  void Fill(const CoordArray_t &x, int binidx, Weight_t weight = 1.)
433  {
434  // Call Fill() on all base classes.
435  // This combines a couple of C++ spells:
436  // - "STAT": is a template parameter pack of template template arguments. It
437  // has multiple (or one or no) elements; each is a template name
438  // that needs to be instantiated before it can be used.
439  // - "...": template parameter pack expansion; the expression is evaluated
440  // for each STAT. The expression is
441  // (STAT<DIMENSIONS, PRECISION>::Fill(x, binidx, weight), 0)
442  // - "trigger_base_fill{}":
443  // initialization, provides a context in which template parameter
444  // pack expansion happens.
445  // - ", 0": because Fill() returns void it cannot be used as initializer
446  // expression. The trailing ", 0" gives it the type of the trailing
447  // comma-separated expression - int.
448  using trigger_base_fill = int[];
449  (void)trigger_base_fill{(STAT<DIMENSIONS, PRECISION>::Fill(x, binidx, weight), 0)...};
450  }
451 
452  /// Whether this provides storage for uncertainties, or whether uncertainties
453  /// are determined as poisson uncertainty of the content.
454  static constexpr bool HasBinUncertainty()
455  {
456  struct AllYourBaseAreBelongToUs: public STAT<DIMENSIONS, PRECISION>... {
457  };
458  return sizeof(HaveUncertainty<AllYourBaseAreBelongToUs>(nullptr)) == sizeof(double);
459  }
460 
461  /// Calculate the bin content's uncertainty for the given bin, using base class information,
462  /// i.e. forwarding to a base's `GetBinUncertaintyImpl(binidx)`.
463  template <bool B = true, class = typename std::enable_if<B && HasBinUncertainty()>::type>
464  double GetBinUncertainty(int binidx) const
465  {
466  return this->GetBinUncertaintyImpl(binidx);
467  }
468  /// Calculate the bin content's uncertainty for the given bin, using Poisson
469  /// statistics on the absolute bin content. Only available if no base provides
470  /// this functionality. Requires GetContent().
471  template <bool B = true, class = typename std::enable_if<B && !HasBinUncertainty()>::type>
472  double GetBinUncertainty(int binidx, ...) const
473  {
474  auto content = this->GetBinContent(binidx);
475  return std::sqrt(std::fabs(content));
476  }
477 
478  /// Get a view on the statistics values of a bin.
479  ConstHistBinStat_t GetView(int idx) const { return ConstHistBinStat_t(*this, idx); }
480  /// Get a (non-const) view on the statistics values of a bin.
481  HistBinStat_t GetView(int idx) { return HistBinStat_t(*this, idx); }
482 };
483 } // namespace Detail
484 
485 } // namespace Experimental
486 } // namespace ROOT
487 
488 #endif