Logo ROOT  
Reference Guide
RHistImpl.hxx
Go to the documentation of this file.
1/// \file ROOT/RHistImpl.h
2/// \ingroup Hist ROOT7
3/// \author Axel Naumann <axel@cern.ch>
4/// \date 2015-03-23
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_RHistImpl
17#define ROOT7_RHistImpl
18
19#include <cassert>
20#include <cctype>
21#include <functional>
22#include "ROOT/RSpan.hxx"
23#include "ROOT/RTupleApply.hxx"
24
25#include "ROOT/RAxis.hxx"
26#include "ROOT/RHistBinIter.hxx"
27#include "ROOT/RHistUtils.hxx"
28
29class TRootIOCtor;
30
31namespace ROOT {
32namespace Experimental {
33
34template <int DIMENSIONS, class PRECISION, template <int D_, class P_> class... STAT>
35class RHist;
36
37namespace Hist {
38/// Iterator over n dimensional axes - an array of n axis iterators.
39template <int NDIMS>
40using AxisIter_t = std::array<RAxisBase::const_iterator, NDIMS>;
41/// Range over n dimensional axes - a pair of arrays of n axis iterators.
42template <int NDIMS>
43using AxisIterRange_t = std::array<AxisIter_t<NDIMS>, 2>;
44
45/// Kinds of under- and overflow handling.
46enum class EOverflow {
47 kNoOverflow = 0x0, ///< Exclude under- and overflows
48 kUnderflow = 0x1, ///< Include underflows
49 kOverflow = 0x2, ///< Include overflows
50 kUnderOver = 0x3, ///< Include both under- and overflows
51};
52
54{
55 return static_cast<int>(a) & static_cast<int>(b);
56}
57} // namespace Hist
58
59namespace Detail {
60
61/**
62 \class RHistImplPrecisionAgnosticBase
63 Base class for `RHistImplBase` that abstracts out the histogram's `PRECISION`.
64
65 For operations such as painting a histogram, the `PRECISION` (type of the bin
66 content) is not relevant; painting will cast the underlying bin type to double.
67 To facilitate this, `RHistImplBase` itself inherits from the
68 `RHistImplPrecisionAgnosticBase` interface.
69 */
70template <int DIMENSIONS>
72public:
73 /// Type of the coordinates.
75 /// Type of the local per-axis bin indices.
76 using BinArray_t = std::array<int, DIMENSIONS>;
77 /// Range type.
79
85
86 /// Number of dimensions of the coordinates.
87 static constexpr int GetNDim() { return DIMENSIONS; }
88 /// Number of bins of this histogram, including all overflow and underflow
89 /// bins. Simply the product of all axes' total number of bins.
90 virtual int GetNBins() const noexcept = 0;
91 /// Number of bins of this histogram, excluding all overflow and underflow
92 /// bins. Simply the product of all axes' number of regular bins.
93 virtual int GetNBinsNoOver() const noexcept = 0;
94 /// Number of under- and overflow bins of this histogram, excluding all
95 /// regular bins.
96 virtual int GetNOverflowBins() const noexcept = 0;
97
98 /// Get the histogram title.
99 const std::string &GetTitle() const { return fTitle; }
100
101 /// Given the coordinate `x`, determine the index of the bin.
102 virtual int GetBinIndex(const CoordArray_t &x) const = 0;
103 /// Given the coordinate `x`, determine the index of the bin, possibly
104 /// growing axes for which `x` is out of range.
105 virtual int GetBinIndexAndGrow(const CoordArray_t &x) const = 0;
106
107 /// Given the local per-axis bins `x`, determine the index of the bin.
108 virtual int GetBinIndexFromLocalBins(const BinArray_t &x) const = 0;
109 /// Given the index of the bin, determine the local per-axis bins `x`.
110 virtual BinArray_t GetLocalBins(int binidx) const = 0;
111
112 /// Get the center in all dimensions of the bin with index `binidx`.
113 virtual CoordArray_t GetBinCenter(int binidx) const = 0;
114 /// Get the lower edge in all dimensions of the bin with index `binidx`.
115 virtual CoordArray_t GetBinFrom(int binidx) const = 0;
116 /// Get the upper edge in all dimensions of the bin with index `binidx`.
117 virtual CoordArray_t GetBinTo(int binidx) const = 0;
118
119 /// Get the uncertainty of the bin with index `binidx`.
120 virtual double GetBinUncertainty(int binidx) const = 0;
121
122 /// Whether this histogram's statistics provide storage for uncertainties, or
123 /// whether uncertainties are determined as poisson uncertainty of the content.
124 virtual bool HasBinUncertainty() const = 0;
125
126 /// The bin content, cast to double.
127 virtual double GetBinContentAsDouble(int binidx) const = 0;
128
129 /// Get a base-class view on axis with index `iAxis`.
130 ///
131 /// \param iAxis - index of the axis, must be `0 <= iAxis < DIMENSION`.
132 virtual const RAxisBase &GetAxis(int iAxis) const = 0;
133
134 /// Get an `AxisIterRange_t` for the whole histogram,
135 /// excluding under- and overflow.
136 virtual AxisIterRange_t GetRange() const = 0;
137
138private:
139 std::string fTitle; ///< The histogram's title.
140};
141
142/**
143 \class RHistImplBase
144 Interface class for `RHistImpl`.
145
146 `RHistImpl` is templated for a specific configuration of axes. To enable access
147 through `RHist`, `RHistImpl` inherits from `RHistImplBase`, exposing only dimension
148 (`DIMENSION`) and bin type (`PRECISION`).
149 */
150template <class DATA>
151class RHistImplBase: public RHistImplPrecisionAgnosticBase<DATA::GetNDim()> {
152public:
153 /// Type of the statistics (bin content, uncertainties etc).
154 using Stat_t = DATA;
155 /// Type of the coordinates.
156 using CoordArray_t = Hist::CoordArray_t<DATA::GetNDim()>;
157 /// Type of the local per-axis bin indices.
158 using BinArray_t = std::array<int, DATA::GetNDim()>;
159 /// Type of the bin content (and thus weights).
160 using Weight_t = typename DATA::Weight_t;
161
162 /// Type of the `Fill(x, w)` function
164
165private:
166 /// The histogram's bin content, uncertainties etc.
168
169public:
170 RHistImplBase() = default;
171 RHistImplBase(size_t numBins, size_t numOverflowBins): fStatistics(numBins, numOverflowBins) {}
172 RHistImplBase(std::string_view title, size_t numBins, size_t numOverflowBins)
173 : RHistImplPrecisionAgnosticBase<DATA::GetNDim()>(title), fStatistics(numBins, numOverflowBins)
174 {}
175 RHistImplBase(const RHistImplBase &) = default;
177
178 virtual std::unique_ptr<RHistImplBase> Clone() const = 0;
179
180 /// Interface function to fill a vector or array of coordinates with
181 /// corresponding weights.
182 /// \note the size of `xN` and `weightN` must be the same!
183 virtual void FillN(const std::span<const CoordArray_t> xN, const std::span<const Weight_t> weightN) = 0;
184
185 /// Interface function to fill a vector or array of coordinates.
186 virtual void FillN(const std::span<const CoordArray_t> xN) = 0;
187
188 /// Retrieve the pointer to the overridden `Fill(x, w)` function.
189 virtual FillFunc_t GetFillFunc() const = 0;
190
191 /// Get the bin content (sum of weights) for the bin at coordinate `x`.
192 virtual Weight_t GetBinContent(const CoordArray_t &x) const = 0;
193
195
196 /// Get the bin uncertainty for the bin at coordinate x.
197 virtual double GetBinUncertainty(const CoordArray_t &x) const = 0;
198
199 /// Get the number of bins in this histogram, including possible under- and
200 /// overflow bins.
201 int GetNBins() const noexcept final { return fStatistics.size(); }
202
203 /// Get the number of bins in this histogram, excluding possible under- and
204 /// overflow bins.
205 int GetNBinsNoOver() const noexcept final { return fStatistics.sizeNoOver(); }
206
207 /// Get the number of under- and overflow bins of this histogram, excluding all
208 /// regular bins.
209 int GetNOverflowBins() const noexcept final { return fStatistics.sizeUnderOver(); }
210
211 /// Get the bin content (sum of weights) for bin index `binidx`.
212 Weight_t GetBinContent(int binidx) const
213 {
214 assert(binidx != 0);
215 return fStatistics[binidx];
216 }
217
218 /// Get the bin content (sum of weights) for bin index `binidx` (non-const).
220 {
221 assert(binidx != 0);
222 return fStatistics[binidx];
223 }
224
225 /// Const access to statistics.
226 const Stat_t &GetStat() const noexcept { return fStatistics; }
227
228 /// Non-const access to statistics.
229 Stat_t &GetStat() noexcept { return fStatistics; }
230
231 /// Get the bin content (sum of weights) for bin index `binidx`, cast to
232 /// `double`.
233 double GetBinContentAsDouble(int binidx) const final { return (double)GetBinContent(binidx); }
234
235 /// Add `w` to the bin at index `bin`.
236 void AddBinContent(int binidx, Weight_t w)
237 {
238 assert(binidx != 0);
239 fStatistics[binidx] += w;
240 }
241};
242} // namespace Detail
243
244namespace Internal {
245/** \name Histogram traits
246 Helper traits for histogram operations.
247 */
248///\{
249
250/// Specifies if the wanted result is the bin's lower edge, center or higher edge.
251enum class EBinCoord {
252 kBinFrom, ///< Get the lower bin edge
253 kBinCenter, ///< Get the bin center
254 kBinTo ///< Get the bin high edge
255};
256
257/// Status of FindBin(x) and FindAdjustedBin(x)
258enum class EFindStatus {
259 kCanGrow, ///< The coordinate could fit after growing the axis
260 kValid ///< The returned bin index is valid
261};
262
263/// \name Axis tuple operations
264/// Template operations on axis tuple.
265///@{
266
267/// Recursively gets the total number of bins in whole hist, excluding under- and overflow.
268/// Each call gets the current axis' number of bins (excluding under- and overflow) multiplied
269/// by that of the next axis.
270template <int IDX, class AXISTUPLE>
271struct RGetNBinsNoOverCount;
272
273template <class AXES>
274struct RGetNBinsNoOverCount<0, AXES> {
275 int operator()(const AXES &axes) const { return std::get<0>(axes).GetNBinsNoOver(); }
276};
277
278template <int I, class AXES>
280 int operator()(const AXES &axes) const { return std::get<I>(axes).GetNBinsNoOver() * RGetNBinsNoOverCount<I - 1, AXES>()(axes); }
281};
282
283/// Get the number of bins in whole hist, excluding under- and overflow.
284template <class... AXISCONFIG>
285int GetNBinsNoOverFromAxes(AXISCONFIG... axisArgs)
286{
287 using axesTuple = std::tuple<AXISCONFIG...>;
288 return RGetNBinsNoOverCount<sizeof...(AXISCONFIG) - 1, axesTuple>()(axesTuple{axisArgs...});
289}
290
291/// Recursively gets the total number of bins in whole hist, including under- and overflow.
292/// Each call gets the current axis' number of bins (including under- and overflow) multiplied
293/// by that of the next axis.
294template <int IDX, class AXISTUPLE>
295struct RGetNBinsCount;
296
297template <class AXES>
298struct RGetNBinsCount<0, AXES> {
299 int operator()(const AXES &axes) const { return std::get<0>(axes).GetNBins(); }
300};
301
302template <int I, class AXES>
304 int operator()(const AXES &axes) const { return std::get<I>(axes).GetNBins() * RGetNBinsCount<I - 1, AXES>()(axes); }
305};
306
307/// Get the number of bins in whole hist, including under- and overflow.
308template <class... AXISCONFIG>
309int GetNBinsFromAxes(AXISCONFIG... axisArgs)
310{
311 using axesTuple = std::tuple<AXISCONFIG...>;
312 return RGetNBinsCount<sizeof...(AXISCONFIG) - 1, axesTuple>()(axesTuple{axisArgs...});
313}
314
315/// Get the number of under- and overflow bins in whole hist, excluding regular bins.
316template <class... AXISCONFIG>
317int GetNOverflowBinsFromAxes(AXISCONFIG... axisArgs)
318{
319 using axesTuple = std::tuple<AXISCONFIG...>;
320 return RGetNBinsCount<sizeof...(AXISCONFIG) - 1, axesTuple>()(axesTuple{axisArgs...}) - RGetNBinsNoOverCount<sizeof...(AXISCONFIG) - 1, axesTuple>()(axesTuple{axisArgs...});
321}
322
323/// Recursively fills the ranges of all axes, excluding under- and overflow.
324/// Each call fills `range` with `begin()` and `end()` of the current axis, excluding
325/// under- and overflow.
326template <int I, class AXES>
327struct RFillIterRange;
328
329template <class AXES>
330struct RFillIterRange<-1, AXES> {
331 void operator()(Hist::AxisIterRange_t<std::tuple_size<AXES>::value> & /*range*/, const AXES & /*axes*/) const
332 {}
333};
334
335template <int I, class AXES>
337 void operator()(Hist::AxisIterRange_t<std::tuple_size<AXES>::value> &range, const AXES &axes) const
338 {
339 range[0][I] = std::get<I>(axes).begin();
340 range[1][I] = std::get<I>(axes).end();
341 RFillIterRange<I - 1, AXES>()(range, axes);
342 }
343};
344
345/// Recursively gets the number of regular bins just before the current dimension.
346/// Each call gets the previous axis' number of regular bins multiplied
347/// by the number of regular bins before the previous axis.
348template <int I, int NDIMS, typename BINS, class AXES>
349struct RGetNRegularBinsBefore;
350
351template <int NDIMS, typename BINS, class AXES>
352struct RGetNRegularBinsBefore<-1, NDIMS, BINS, AXES> {
353 void operator()(BINS &/*binSizes*/, const AXES &/*axes*/) const
354 {}
355};
356
357template <int I, int NDIMS, typename BINS, class AXES>
359 void operator()(BINS &binSizes, const AXES &axes) const
360 {
361 constexpr const int thisAxis = NDIMS - I - 1;
362 binSizes[thisAxis] = binSizes[thisAxis-1] * std::get<thisAxis-1>(axes).GetNBinsNoOver();
363 RGetNRegularBinsBefore<I - 1, NDIMS, BINS, AXES>()(binSizes, axes);
364 }
365};
366
367/// Recursively gets the total number of regular bins before the current dimension,
368/// when computing a global bin that is in under- or overflow in at least one
369/// dimension. That global bin's local per-axis bin indices are passed through
370/// the `localBins` parameter. These `localBins` were translated to 0-based bins,
371/// which is more convenient for some operations and which are the `virtualBins`
372/// parameter.
373/// Each call gets the current axis' number of regular bins before the global_bin
374/// in the current dimension multiplied by the number of regular bins before the
375/// current axis.
376/// If the global_bin is in under- or overflow in the current dimension (local bin),
377/// there is no need to process further.
378
379// - We want to know how many regular bins lie before the current overflow bin in the
380// histogram's global binning order (which so far I thought was row-major, but now I'm
381// not sure, maybe it's actually column-major... it doesn't matter, we don't need to spell out what is the global binning order anyway).
382
383template <int I, int NDIMS, typename BINS, class AXES>
384struct RComputeGlobalBin;
385
386template <int NDIMS, typename BINS, class AXES>
387struct RComputeGlobalBin<-1, NDIMS, BINS, AXES> {
388 int operator()(int total_regular_bins_before, const AXES &/*axes*/, const BINS &/*virtualBins*/, const BINS &/*binSizes*/, const BINS &/*localBins*/) const
389 {
390 return total_regular_bins_before;
391 }
392};
393
394template <int I, int NDIMS, typename BINS, class AXES>
396 int operator()(int total_regular_bins_before, const AXES &axes, const BINS &virtualBins, const BINS &binSizes, const BINS &localBins) const
397 {
398 // We can tell how many regular bins lie before us on this axis,
399 // accounting for the underflow bin of this axis if it has one.
400 const int num_underflow_bins = static_cast<int>(!std::get<I>(axes).CanGrow());
401 const int num_regular_bins_before =
402 std::max(virtualBins[I] - num_underflow_bins, 0);
403 total_regular_bins_before += num_regular_bins_before * binSizes[I];
404
405 // If we are on an overflow or underflow bin on this axis, we know that
406 // we don't need to look at the remaining axes. Projecting on those
407 // dimensions would only take us into an hyperplane of over/underflow
408 // bins for the current axis, and we know that by construction there
409 // will be no regular bins in there.
410 if (localBins[I] < 1)
411 return total_regular_bins_before;
412
413 return RComputeGlobalBin<I - 1, NDIMS, BINS, AXES>()(total_regular_bins_before, axes, virtualBins, binSizes, localBins);
414 }
415};
416
417/// Recursively compute some quantities needed for `ComputeLocalBins`, namely
418/// the total number of bins per hyperplane (overflow and regular) and the
419/// number of regular bins per hyperplane on the hyperplanes that have them.
420template <int I, int NDIMS, class AXES>
421struct RComputeLocalBinsInitialisation;
422
423template <int NDIMS, class AXES>
424struct RComputeLocalBinsInitialisation<0, NDIMS, AXES> {
425 void operator()(std::array<int, NDIMS-1> /* bins_per_hyperplane */, std::array<int, NDIMS-1> /* regular_bins_per_hyperplane */, const AXES & /*axes*/) const
426 {}
427};
428
429template <int I, int NDIMS, class AXES>
431 void operator()(std::array<int, NDIMS-1>& bins_per_hyperplane, std::array<int, NDIMS-1>& regular_bins_per_hyperplane, const AXES &axes) const
432 {
433 constexpr const int thisAxis = NDIMS - I - 1;
434 bins_per_hyperplane[thisAxis] = Internal::RGetNBinsCount<thisAxis, AXES>()(axes);
435 regular_bins_per_hyperplane[thisAxis] = Internal::RGetNBinsNoOverCount<thisAxis, AXES>()(axes);
436 RComputeLocalBinsInitialisation<I - 1, NDIMS, AXES>()(bins_per_hyperplane, regular_bins_per_hyperplane, axes);
437 }
438};
439
440/// Recursively computes the number of regular bins before the current dimension,
441/// as well as the number of under- and overflow bins left to account for, after
442/// the current dimension. If the latter is equal to 0, there is no need to process
443/// further.
444/// It is computing local bins that are in under- or overflow in at least one
445/// dimension.
446/// Starting at the highest dimension, it examines how many full hyperplanes of
447/// regular bins lie before, then projects on the remaining dimensions.
448
449template <int I, int NDIMS, class AXES>
450struct RComputeLocalBins;
451
452template <int NDIMS, class AXES>
453struct RComputeLocalBins<0, NDIMS, AXES> {
454 void operator()(const AXES &/*axes*/, int &/*unprocessed_previous_overflow_bin*/,
455 int &/*num_regular_bins_before*/, std::array<int, NDIMS-1> /* bins_per_hyperplane */,
456 std::array<int, NDIMS-1> /* regular_bins_per_hyperplane */, int /* curr_bins_per_hyperplane */,
457 int /* curr_regular_bins_per_hyperplane */) const
458 {}
459};
460
461template <int I, int NDIMS, class AXES>
463 void operator()(const AXES &axes, int &unprocessed_previous_overflow_bin,
464 int &num_regular_bins_before, std::array<int, NDIMS-1> bins_per_hyperplane,
465 std::array<int, NDIMS-1> regular_bins_per_hyperplane, int curr_bins_per_hyperplane,
466 int curr_regular_bins_per_hyperplane) const
467 {
468 // Let's start by computing the contribution of the underflow
469 // hyperplane (if any), in which we know there will be no regular bins
470 const int num_underflow_hyperplanes =
471 static_cast<int>(!std::get<I>(axes).CanGrow());
472 const int bins_in_underflow_hyperplane =
473 num_underflow_hyperplanes * bins_per_hyperplane[I-1];
474
475 // Next, from the total number of bins per hyperplane and the number of
476 // regular bins per hyperplane that has them, we deduce the number of
477 // overflow bins per hyperplane that has regular bins.
478 const int overflow_bins_per_regular_hyperplane =
479 bins_per_hyperplane[I-1] - regular_bins_per_hyperplane[I-1];
480
481 // This allows us to answer a key question: are there any under/overflow
482 // bins on the hyperplanes that have regular bins? It may not be the
483 // case if all of their axes are growable, and thus don't have overflow bins.
484 if (overflow_bins_per_regular_hyperplane != 0) {
485 // If so, we start by cutting off the contribution of the underflow
486 // and overflow hyperplanes, to focus specifically on regular bins.
487 const int overflow_bins_in_regular_hyperplanes =
488 std::min(
489 std::max(
490 unprocessed_previous_overflow_bin
491 - bins_in_underflow_hyperplane,
492 0
493 ),
494 overflow_bins_per_regular_hyperplane
495 * std::get<I>(axes).GetNBinsNoOver()
496 );
497
498 // We count how many _complete_ "regular" hyperplanes that leaves
499 // before us, and account for those in our regular bin count.
500 const int num_regular_hyperplanes_before =
501 overflow_bins_in_regular_hyperplanes
502 / overflow_bins_per_regular_hyperplane;
503 num_regular_bins_before +=
504 num_regular_hyperplanes_before
505 * regular_bins_per_hyperplane[I-1];
506
507 // This only leaves the _current_ hyperplane as a possible source of
508 // more regular bins that we haven't accounted for yet. We'll take
509 // those into account while processing previous dimensions.
510 unprocessed_previous_overflow_bin =
511 overflow_bins_in_regular_hyperplanes
512 % overflow_bins_per_regular_hyperplane;
513 } else {
514 // If there are no overflow bins in regular hyperplane, then the
515 // rule changes: observing _one_ overflow bin after the underflow
516 // hyperplane means that _all_ regular hyperplanes on this axis are
517 // already before us.
518 if (unprocessed_previous_overflow_bin >= bins_in_underflow_hyperplane) {
519 num_regular_bins_before +=
520 std::get<I>(axes).GetNBinsNoOver()
521 * regular_bins_per_hyperplane[I-1];
522 }
523
524 // In this case, we're done, because the current bin may only lie
525 // in the underflow or underflow hyperplane of this axis. Which
526 // means that there are no further regular bins to be accounted for
527 // in the current hyperplane.
528 unprocessed_previous_overflow_bin = 0;
529 }
530
531 // No need to continue this loop if we've taken into account all
532 // overflow bins that were associated with regular bins.
533 if (unprocessed_previous_overflow_bin == 0)
534 return;
535
536 return Internal::RComputeLocalBins<I - 1, NDIMS, AXES>()
537 (axes, unprocessed_previous_overflow_bin, num_regular_bins_before, bins_per_hyperplane,
538 regular_bins_per_hyperplane, curr_bins_per_hyperplane, curr_regular_bins_per_hyperplane);
539 }
540};
541
542/// Recursively computes zero-based local bin indices, given...
543///
544/// - A zero-based global bin index
545/// - The number of considered bins on each axis (can be either `GetNBinsNoOver`
546/// or `GetNBins` depending on what you are trying to do)
547/// - A policy of treating all bins as regular (i.e. no negative indices)
548template <int I, int NDIMS, typename BINS, class AXES, class BINTYPE>
549struct RComputeLocalBinsRaw;
550
551template <int NDIMS, typename BINS, class AXES, class BINTYPE>
552struct RComputeLocalBinsRaw<-1, NDIMS, BINS, AXES, BINTYPE> {
553 void operator()(BINS & /*virtualBins*/, const AXES & /*axes*/, int /*zeroBasedGlobalBin*/, BINTYPE /*GetNBinType*/) const
554 {}
555};
556
557template <int I, int NDIMS, typename BINS, class AXES, class BINTYPE>
559 void operator()(BINS &virtualBins, const AXES &axes, int zeroBasedGlobalBin, BINTYPE GetNBinType) const
560 {
561 constexpr const int thisAxis = NDIMS - I - 1;
562 virtualBins[thisAxis] = zeroBasedGlobalBin % (std::get<thisAxis>(axes).*GetNBinType)();
563 RComputeLocalBinsRaw<I - 1, NDIMS, BINS, AXES, BINTYPE>()(virtualBins, axes, zeroBasedGlobalBin / (std::get<thisAxis>(axes).*GetNBinType)(), GetNBinType);
564 }
565};
566
567/// Recursively computes a zero-based global bin index, given...
568///
569/// - A set of zero-based per-axis bin indices
570/// - The number of considered bins on each axis (can be either `GetNBinsNoOver`
571/// or `GetNBins` depending on what you are trying to do)
572/// - A policy of treating all bins qs regular (i.e. no negative indices)
573template <int I, int NDIMS, typename BINS, class AXES, class BINTYPE>
574struct RComputeGlobalBinRaw;
575
576template <int NDIMS, typename BINS, class AXES, class BINTYPE>
577struct RComputeGlobalBinRaw<-1, NDIMS, BINS, AXES, BINTYPE> {
578 int operator()(int globalVirtualBin, const AXES & /*axes*/, const BINS & /*zeroBasedLocalBins*/, int /*binSize*/, BINTYPE /*GetNBinType*/) const
579 {
580 return globalVirtualBin;
581 }
582};
583
584template <int I, int NDIMS, typename BINS, class AXES, class BINTYPE>
586 int operator()(int globalVirtualBin, const AXES &axes, const BINS &zeroBasedLocalBins, int binSize, BINTYPE GetNBinType) const
587 {
588 constexpr const int thisAxis = NDIMS - I - 1;
589 globalVirtualBin += zeroBasedLocalBins[thisAxis] * binSize;
590 binSize *= (std::get<thisAxis>(axes).*GetNBinType)();
591 return Internal::RComputeGlobalBinRaw<I - 1, NDIMS, BINS, AXES, BINTYPE>()(globalVirtualBin, axes, zeroBasedLocalBins, binSize, GetNBinType);
592 }
593};
594
595/// Recursively converts zero-based virtual bins where the underflow bin
596/// has index `0` and the overflow bin has index `N+1` where `N` is the axis'
597/// number of regular bins, to the standard `kUnderflowBin`/`kOverflowBin` for under/overflow
598/// bin indexing convention.
599///
600/// For growable axes, must add 1 to go back to standard indices as their virtual
601/// indexing convention is also 0-based, with zero designating the first regular bin.
602template <int I, int NDIMS, typename BINS, class AXES>
603struct RVirtualBinsToLocalBins;
604
605template <int NDIMS, typename BINS, class AXES>
606struct RVirtualBinsToLocalBins<-1, NDIMS, BINS, AXES> {
607 void operator()(BINS & /*localBins*/, const AXES & /*axes*/, const BINS & /*virtualBins*/) const
608 {}
609};
610
611template <int I, int NDIMS, typename BINS, class AXES>
613 void operator()(BINS &localBins, const AXES &axes, const BINS &virtualBins) const
614 {
615 constexpr const int thisAxis = NDIMS - I - 1;
616 if ((!std::get<thisAxis>(axes).CanGrow()) && (virtualBins[thisAxis] == 0)) {
617 localBins[thisAxis] = RAxisBase::kUnderflowBin;
618 } else if ((!std::get<thisAxis>(axes).CanGrow()) && (virtualBins[thisAxis] == (std::get<thisAxis>(axes).GetNBins() - 1))) {
619 localBins[thisAxis] = RAxisBase::kOverflowBin;
620 } else {
621 const int regular_bin_offset = -static_cast<int>(std::get<thisAxis>(axes).CanGrow());
622 localBins[thisAxis] = virtualBins[thisAxis] - regular_bin_offset;
623 }
624 RVirtualBinsToLocalBins<I - 1, NDIMS, BINS, AXES>()(localBins, axes, virtualBins);
625 }
626};
627
628/// Recursively converts local axis bins from the standard `kUnderflowBin`/`kOverflowBin` for under/overflow
629/// bin indexing convention, to a "virtual bin" convention where the underflow bin
630/// has index `0` and the overflow bin has index `N+1` where `N` is the axis'
631/// number of regular bins.
632///
633/// For growable axes, subtract 1 from regular indices so that the indexing
634/// convention remains zero-based (this means that there will be no "holes" in
635/// global binning, which matters more than the choice of regular index base)
636template <int I, int NDIMS, typename BINS, class AXES>
637struct RLocalBinsToVirtualBins;
638
639template <int NDIMS, typename BINS, class AXES>
640struct RLocalBinsToVirtualBins<-1, NDIMS, BINS, AXES> {
641 void operator()(BINS & /*virtualBins*/, const AXES & /*axes*/, const BINS & /*localBins*/) const
642 {}
643};
644
645template <int I, int NDIMS, typename BINS, class AXES>
647 void operator()(BINS &virtualBins, const AXES &axes, const BINS &localBins) const
648 {
649 constexpr const int thisAxis = NDIMS - I - 1;
650 switch (localBins[thisAxis]) {
652 virtualBins[thisAxis] = 0; break;
654 virtualBins[thisAxis] = std::get<thisAxis>(axes).GetNBins() - 1; break;
655 default:
656 virtualBins[thisAxis] = localBins[thisAxis] - static_cast<int>(std::get<thisAxis>(axes).CanGrow());
657 }
658 RLocalBinsToVirtualBins<I - 1, NDIMS, BINS, AXES>()(virtualBins, axes, localBins);
659 }
660};
661
662/// Find the per-axis local bin indices associated with a certain set of coordinates.
663template <int I, int NDIMS, typename BINS, typename COORD, class AXES>
664struct RFindLocalBins;
665
666template <int NDIMS, typename BINS, typename COORD, class AXES>
667struct RFindLocalBins<-1, NDIMS, BINS, COORD, AXES> {
668 void operator()(BINS & /*localBins*/, const AXES & /*axes*/, const COORD & /*coords*/) const
669 {}
670};
671
672template <int I, int NDIMS, typename BINS, typename COORD, class AXES>
674 void operator()(BINS &localBins, const AXES &axes, const COORD &coords) const
675 {
676 constexpr const int thisAxis = NDIMS - I - 1;
677 localBins[thisAxis] = std::get<thisAxis>(axes).FindBin(coords[thisAxis]);
678 RFindLocalBins<I - 1, NDIMS, BINS, COORD, AXES>()(localBins, axes, coords);
679 }
680};
681
682/// Recursively converts local axis bins from the standard `kUnderflowBin`/`kOverflowBin` for
683/// under/overflow bin indexing convention, to the corresponding bin coordinates.
684template <int I, int NDIMS, typename BINS, typename COORD, class AXES>
685struct RLocalBinsToCoords;
686
687template <int NDIMS, typename BINS, typename COORD, class AXES>
688struct RLocalBinsToCoords<-1, NDIMS, BINS, COORD, AXES> {
689 void operator()(COORD & /*coords*/, const AXES & /*axes*/, const BINS & /*localBins*/, EBinCoord /*kind*/) const
690 {}
691};
692
693template <int I, int NDIMS, typename BINS, typename COORD, class AXES>
695 void operator()(COORD &coords, const AXES &axes, const BINS &localBins, EBinCoord kind) const
696 {
697 constexpr const int thisAxis = NDIMS - I - 1;
698 int axisbin = localBins[thisAxis];
699 switch (kind) {
700 case EBinCoord::kBinFrom: coords[thisAxis] = std::get<thisAxis>(axes).GetBinFrom(axisbin); break;
701 case EBinCoord::kBinCenter: coords[thisAxis] = std::get<thisAxis>(axes).GetBinCenter(axisbin); break;
702 case EBinCoord::kBinTo: coords[thisAxis] = std::get<thisAxis>(axes).GetBinTo(axisbin); break;
703 }
704 RLocalBinsToCoords<I - 1, NDIMS, BINS, COORD, AXES>()(coords, axes, localBins, kind);
705 }
706};
707
708template <class... AXISCONFIG>
709static std::array<const RAxisBase *, sizeof...(AXISCONFIG)> GetAxisView(const AXISCONFIG &... axes) noexcept
710{
711 std::array<const RAxisBase *, sizeof...(AXISCONFIG)> axisViews{{&axes...}};
712 return axisViews;
713}
714
715///\}
716} // namespace Internal
717
718namespace Detail {
719
720template <class DATA, class... AXISCONFIG>
721class RHistImpl final: public RHistImplBase<DATA> {
722 static_assert(sizeof...(AXISCONFIG) == DATA::GetNDim(), "Number of axes must equal histogram dimension");
723
724 friend typename DATA::Hist_t;
725
726public:
731 using typename ImplBase_t::FillFunc_t;
732 template <int NDIMS = DATA::GetNDim()>
734
735private:
736 std::tuple<AXISCONFIG...> fAxes; ///< The histogram's axes
737
738public:
740 RHistImpl(AXISCONFIG... axisArgs);
741 RHistImpl(std::string_view title, AXISCONFIG... axisArgs);
742
743 std::unique_ptr<ImplBase_t> Clone() const override {
744 return std::unique_ptr<ImplBase_t>(new RHistImpl(*this));
745 }
746
747 /// Retrieve the fill function for this histogram implementation, to prevent
748 /// the virtual function call for high-frequency fills.
749 FillFunc_t GetFillFunc() const final {
750 return (FillFunc_t)&RHistImpl::Fill;
751 }
752
753 /// Get the axes of this histogram.
754 const std::tuple<AXISCONFIG...> &GetAxes() const { return fAxes; }
755
756 /// Normalized axes access, converting from actual axis type to base class.
757 const RAxisBase &GetAxis(int iAxis) const final { return *std::apply(Internal::GetAxisView<AXISCONFIG...>, fAxes)[iAxis]; }
758
759 /// Computes a zero-based global bin index, given...
760 ///
761 /// - A set of zero-based per-axis bin indices
762 /// - The number of considered bins on each axis (can be either `GetNBinsNoOver`
763 /// or `GetNBins` depending on what you are trying to do)
764 /// - A policy of treating all bins qs regular (i.e. no negative indices)
765 template <int NDIMS, typename BINTYPE>
766 int ComputeGlobalBinRaw(const BinArray_t& zeroBasedLocalBins, BINTYPE GetNBinType) const {
767 int result = 0;
768 int binSize = 1;
769 return Internal::RComputeGlobalBinRaw<NDIMS - 1, NDIMS, BinArray_t, decltype(fAxes), BINTYPE>()(result, fAxes, zeroBasedLocalBins, binSize, GetNBinType);
770 }
771
772 /// Computes zero-based local bin indices, given...
773 ///
774 /// - A zero-based global bin index
775 /// - The number of considered bins on each axis (can be either `GetNBinsNoOver`
776 /// or `GetNBins` depending on what you are trying to do)
777 /// - A policy of treating all bins as regular (i.e. no negative indices)
778 template <int NDIMS, typename BINTYPE>
779 BinArray_t ComputeLocalBinsRaw(int zeroBasedGlobalBin, BINTYPE GetNBinType) const {
780 BinArray_t result;
781 Internal::RComputeLocalBinsRaw<NDIMS - 1, NDIMS, BinArray_t, decltype(fAxes), BINTYPE>()(result, fAxes, zeroBasedGlobalBin, GetNBinType);
782 return result;
783 }
784
785 /// Converts local axis bins from the standard `kUnderflowBin`/`kOverflowBin` for under/overflow
786 /// bin indexing convention, to a "virtual bin" convention where the underflow bin
787 /// has index `0` and the overflow bin has index `N+1` where `N` is the axis'
788 /// number of regular bins.
789 template <int NDIMS>
791 BinArray_t virtualBins;
792 Internal::RLocalBinsToVirtualBins<NDIMS - 1, NDIMS, BinArray_t, decltype(fAxes)>()(virtualBins, fAxes, localBins);
793 return virtualBins;
794 }
795
796 /// Converts zero-based virtual bins where the underflow bin has
797 /// index `0` and the overflow bin has index `N+1` where `N` is the axis'
798 /// number of regular bins, to the standard `kUnderflowBin`/`kOverflowBin` for under/overflow
799 /// bin indexing convention.
800 template <int NDIMS>
801 BinArray_t VirtualBinsToLocalBins(const BinArray_t& virtualBins) const {
802 BinArray_t localBins = {};
803 Internal::RVirtualBinsToLocalBins<NDIMS - 1, NDIMS, BinArray_t, decltype(fAxes)>()(localBins, fAxes, virtualBins);
804 return localBins;
805 }
806
807 /// Computes the global index of a certain bin on an `NDIMS`-dimensional histogram,
808 /// knowing the local per-axis bin indices as returned by calling `FindBin()` on each axis.
809 template <int NDIMS>
810 int ComputeGlobalBin(BinArray_t& local_bins) const {
811 // Get regular bins out of the way
812 if (std::all_of(local_bins.cbegin(), local_bins.cend(),
813 [](int bin) { return bin >= 1; })) {
814 for (int bin = 0; bin < NDIMS; bin++)
815 local_bins[bin] -= 1;
816 return ComputeGlobalBinRaw<NDIMS>(local_bins, &ROOT::Experimental::RAxisBase::GetNBinsNoOver) + 1;
817 }
818
819 // Convert bin indices to a zero-based coordinate system where the underflow
820 // bin (if any) has coordinate 0 and the overflow bin (if any) has
821 // coordinate N-1, where N is the axis' total number of bins.
822 BinArray_t virtual_bins = LocalBinsToVirtualBins<NDIMS>(local_bins);
823
824 // Deduce what the global bin index would be in this coordinate system that
825 // unifies regular and overflow bins.
826 const int global_virtual_bin = ComputeGlobalBinRaw<NDIMS>(virtual_bins, &ROOT::Experimental::RAxisBase::GetNBins);
827
828 // Move to 1-based and negative indexing
829 const int neg_1based_virtual_bin = -global_virtual_bin - 1;
830
831 // At this point, we have an index that represents a count of all bins, both
832 // regular and overflow, that are located before the current bin when
833 // enumerating histogram bins in row-major order.
834 //
835 // We will next count the number of _regular_ bins which are located before
836 // the current bin, and by removing this offset from the above index, we
837 // will get a count of overflow bins that are located before the current bin
838 // in row-major order. Which is what we want as our overflow bin index.
839 //
840 int total_regular_bins_before = 0;
841
842 // First, we need to know how many regular bins we leave behind us for each
843 // step on each axis, assuming that the bin from which we come was regular.
844 //
845 // If mathematically inclined, you can also think of this as the size of an
846 // hyperplane of regular bins when projecting on lower-numbered dimensions.
847 // See the docs of ComputeLocalBins for more on this worldview.
848 //
849 BinArray_t bin_sizes;
850 bin_sizes[0] = 1;
851 Internal::RGetNRegularBinsBefore<NDIMS - 2, NDIMS, BinArray_t, decltype(fAxes)>()(bin_sizes, fAxes);
852
853 // With that, we can deduce how many regular bins lie before us.
854 total_regular_bins_before = Internal::RComputeGlobalBin<NDIMS - 1, NDIMS, BinArray_t, decltype(fAxes)>()
855 (total_regular_bins_before, fAxes, virtual_bins, bin_sizes, local_bins);
856
857 // Now that we know how many bins lie before us, and how many of those are
858 // regular bins, we can trivially deduce how many overflow bins lie before
859 // us, and emit that as our global overflow bin index.
860 return neg_1based_virtual_bin + total_regular_bins_before;
861 }
862
863 /// Computes the local per-axis bin indices of a certain bin on an `NDIMS`-dimensional histogram,
864 /// knowing the global histogram bin index.
865 template <int NDIMS>
866 BinArray_t ComputeLocalBins(int global_bin) const {
867 // Get regular bins out of the way
868 if (global_bin >= 1) {
869 BinArray_t computed_bins = ComputeLocalBinsRaw<NDIMS>(global_bin - 1, &ROOT::Experimental::RAxisBase::GetNBinsNoOver);
870 for (int bin = 0; bin < NDIMS; ++bin)
871 computed_bins[bin] += 1;
872 return computed_bins;
873 }
874
875 // Convert our negative index to something positive and 0-based, as that is
876 // more convenient to work with. Note, however, that this is _not_
877 // equivalent to the virtual_bin that we had before, because what we have
878 // here is a count of overflow bins, not of all bins...
879 const int corrected_virtual_overflow_bin = -global_bin - 1;
880
881 // ...so we need to retrieve and bring back the regular bin count, and this
882 // is where the fun begins.
883 //
884 // The main difficulty is that the number of regular bins is not fixed as
885 // one slides along a histogram axis. Using a 2D binning case as a simple
886 // motivating example...
887 //
888 // -1 -2 -3 -4 <- No regular bins on the underflow line of axis 1
889 // -5 1 2 -6 <- Some of them on middle lines of axis 1
890 // -7 3 4 -8
891 // -9 -10 -11 -12 <- No regular bins on the overflow line of axis 1
892 //
893 // As we go to higher dimensions, the geometry becomes more complex, but
894 // if we replace "line" with "plane", we get a similar picture in 3D when we
895 // slide along axis 2:
896 //
897 // No regular bins on the Some of them on the No regular bins again
898 // UF plane of axis 2 regular planes of ax.2 on the OF plane of ax.2
899 //
900 // -1 -2 -3 -4 -17 -18 -19 -20 -29 -30 -31 -32
901 // -5 -6 -7 -8 -21 1 2 -22 -33 -34 -35 -36
902 // -9 -10 -11 -12 -23 3 4 -24 -37 -37 -39 -40
903 // -13 -14 -15 -16 -25 -26 -27 -28 -41 -42 -43 -44
904 //
905 // We can generalize this to N dimensions by saying that as we slide along
906 // the last axis of an N-d histogram, we see an hyperplane full of overflow
907 // bins, then some hyperplanes with regular bins in the "middle" surrounded
908 // by overflow bins, then a last hyperplane full of overflow bins.
909 //
910 // From this, we can devise a recursive algorithm to recover the number of
911 // regular bins before the overflow bin we're currently looking at:
912 //
913 // - Start by processing the last histogram axis.
914 // - Ignore the first and last hyperplane on this axis, which only contain
915 // underflow and overflow bins respectively.
916 // - Count how many complete hyperplanes of regular bins lie before us on
917 // this axis, which we can do indirectly in our overflow bin based
918 // reasoning by computing the perimeter of the regular region and dividing
919 // our "regular" overflow bin count by that amount.
920 // - Now we counted previous hyperplanes on this last histogram axis, but
921 // we need to process the hyperplane that our bin is located in, if any.
922 // * For this, we reduce our overflow bin count to a count of
923 // _unaccounted_ overflow bins in the current hyperplane...
924 // * ...which allows us to recursively continue the computation by
925 // processing the next (well, previous) histogram axis in the context
926 // of this hyperplane, in the same manner as above.
927 //
928 // Alright, now that the general plan is sorted out, let's compute some
929 // quantities that we are going to need, namely the total number of bins per
930 // hyperplane (overflow and regular) and the number of regular bins per
931 // hyperplane on the hyperplanes that have them.
932 //
933 std::array<int, NDIMS - 1> bins_per_hyperplane;
934 std::array<int, NDIMS - 1> regular_bins_per_hyperplane;
935 Internal::RComputeLocalBinsInitialisation<NDIMS - 1, NDIMS, decltype(fAxes)>()(bins_per_hyperplane, regular_bins_per_hyperplane, fAxes);
936
937 int curr_bins_per_hyperplane = Internal::RGetNBinsCount<NDIMS - 1, decltype(fAxes)>()(fAxes);
938 int curr_regular_bins_per_hyperplane = Internal::RGetNBinsNoOverCount<NDIMS - 1, decltype(fAxes)>()(fAxes);
939
940 // Given that, we examine each axis, starting from the last one.
941 int unprocessed_previous_overflow_bin = corrected_virtual_overflow_bin;
942 int num_regular_bins_before = 0;
943 Internal::RComputeLocalBins<NDIMS - 1, NDIMS, decltype(fAxes)>()
944 (fAxes, unprocessed_previous_overflow_bin, num_regular_bins_before, bins_per_hyperplane,
945 regular_bins_per_hyperplane, curr_bins_per_hyperplane, curr_regular_bins_per_hyperplane);
946
947 // By the time we reach the first axis, there should only be at most one
948 // full row of regular bins before us:
949 //
950 // -1 1 2 3 -2
951 // ^ ^
952 // | |
953 // | Option 2: one overflow bin before us
954 // |
955 // Option 1: no overflow bin before us
956 //
957 num_regular_bins_before +=
958 unprocessed_previous_overflow_bin * std::get<0>(fAxes).GetNBinsNoOver();
959
960 // Now that we know the number of regular bins before us, we can add this to
961 // to the zero-based overflow bin index that we started with to get a global
962 // zero-based bin index accounting for both under/overflow bins and regular
963 // bins, just like what we had in the ComputeGlobalBin<DATA::GetNDim()>() implementation.
964 const int global_virtual_bin =
965 corrected_virtual_overflow_bin + num_regular_bins_before;
966
967 // We can then easily go back to zero-based "virtual" bin indices...
968 const BinArray_t virtual_bins = ComputeLocalBinsRaw<NDIMS>(global_virtual_bin, &ROOT::Experimental::RAxisBase::GetNBins);
969
970 // ...and from that go back to the -1/-2 overflow bin indexing convention.
971 return VirtualBinsToLocalBins<NDIMS>(virtual_bins);
972 }
973
974 /// Get the bin index for the given coordinates `x`. The use of `RFindLocalBins`
975 /// allows to convert the coordinates to local per-axis bin indices before using
976 /// `ComputeGlobalBin()`.
977 int GetBinIndex(const CoordArray_t &x) const final
978 {
979 BinArray_t localBins = {};
980 Internal::RFindLocalBins<DATA::GetNDim() - 1, DATA::GetNDim(), BinArray_t, CoordArray_t, decltype(fAxes)>()(localBins, fAxes, x);
981 int result = ComputeGlobalBin<DATA::GetNDim()>(localBins);
982 return result;
983 }
984
985 /// Get the bin index for the given coordinates `x`, growing the axes as needed.
986 /// The use of `RFindLocalBins` allows to convert the coordinates to local
987 /// per-axis bin indices before using `ComputeGlobalBin()`.
988 ///
989 /// TODO: implement growable behavior
990 int GetBinIndexAndGrow(const CoordArray_t &x) const final
991 {
993 int ret = 0;
994 BinArray_t localBins = {};
995 while (status == Internal::EFindStatus::kCanGrow) {
996 Internal::RFindLocalBins<DATA::GetNDim() - 1, DATA::GetNDim(), BinArray_t, CoordArray_t, decltype(fAxes)>()(localBins, fAxes, x);
997 ret = ComputeGlobalBin<DATA::GetNDim()>(localBins);
999 }
1000 return ret;
1001 }
1002
1003 /// Get the bin index for the given local per-axis bin indices `x`, using
1004 /// `ComputeGlobalBin()`.
1005 int GetBinIndexFromLocalBins(const BinArray_t &x) const final
1006 {
1007 BinArray_t localBins = x;
1008 int result = ComputeGlobalBin<DATA::GetNDim()>(localBins);
1009 return result;
1010 }
1011
1012 /// Get the local per-axis bin indices `x` for the given bin index, using
1013 /// `ComputeLocalBins()`.
1014 BinArray_t GetLocalBins(int binidx) const final
1015 {
1016 BinArray_t localBins = ComputeLocalBins<DATA::GetNDim()>(binidx);
1017 return localBins;
1018 }
1019
1020 /// Get the center coordinates of the bin with index `binidx`.
1021 CoordArray_t GetBinCenter(int binidx) const final
1022 {
1023 BinArray_t localBins = ComputeLocalBins<DATA::GetNDim()>(binidx);
1024 CoordArray_t coords;
1025 Internal::RLocalBinsToCoords<DATA::GetNDim() - 1, DATA::GetNDim(), BinArray_t, CoordArray_t, decltype(fAxes)>()(coords, fAxes, localBins, Internal::EBinCoord::kBinCenter);
1026 return coords;
1027 }
1028
1029 /// Get the coordinates of the low limit of the bin with index `binidx`.
1030 CoordArray_t GetBinFrom(int binidx) const final
1031 {
1032 BinArray_t localBins = ComputeLocalBins<DATA::GetNDim()>(binidx);
1033 CoordArray_t coords;
1034 Internal::RLocalBinsToCoords<DATA::GetNDim() - 1, DATA::GetNDim(), BinArray_t, CoordArray_t, decltype(fAxes)>()(coords, fAxes, localBins, Internal::EBinCoord::kBinFrom);
1035 return coords;
1036 }
1037
1038 /// Get the coordinates of the high limit of the bin with index `binidx`.
1039 CoordArray_t GetBinTo(int binidx) const final
1040 {
1041 BinArray_t localBins = ComputeLocalBins<DATA::GetNDim()>(binidx);
1042 CoordArray_t coords;
1043 Internal::RLocalBinsToCoords<DATA::GetNDim() - 1, DATA::GetNDim(), BinArray_t, CoordArray_t, decltype(fAxes)>()(coords, fAxes, localBins, Internal::EBinCoord::kBinTo);
1044 return coords;
1045 }
1046
1047 /// Fill an array of `weightN` to the bins specified by coordinates `xN`.
1048 /// For each element `i`, the weight `weightN[i]` will be added to the bin
1049 /// at the coordinate `xN[i]`
1050 /// \note `xN` and `weightN` must have the same size!
1051 void FillN(const std::span<const CoordArray_t> xN, const std::span<const Weight_t> weightN) final
1052 {
1053#ifndef NDEBUG
1054 if (xN.size() != weightN.size()) {
1055 R__ERROR_HERE("HIST") << "Not the same number of points and weights!";
1056 return;
1057 }
1058#endif
1059
1060 for (size_t i = 0; i < xN.size(); ++i) {
1061 Fill(xN[i], weightN[i]);
1062 }
1063 }
1064
1065 /// Fill an array of `weightN` to the bins specified by coordinates `xN`.
1066 /// For each element `i`, the weight `weightN[i]` will be added to the bin
1067 /// at the coordinate `xN[i]`
1068 void FillN(const std::span<const CoordArray_t> xN) final
1069 {
1070 for (auto &&x: xN) {
1071 Fill(x);
1072 }
1073 }
1074
1075 /// Add a single weight `w` to the bin at coordinate `x`.
1076 void Fill(const CoordArray_t &x, Weight_t w = 1.)
1077 {
1078 int bin = GetBinIndexAndGrow(x);
1079 this->GetStat().Fill(x, bin, w);
1080 }
1081
1082 /// Get the content of the bin at position `x`.
1084 {
1085 int bin = GetBinIndex(x);
1086 return ImplBase_t::GetBinContent(bin);
1087 }
1088
1089 /// Return the uncertainties for the given bin index.
1090 double GetBinUncertainty(int binidx) const final { return this->GetStat().GetBinUncertainty(binidx); }
1091
1092 /// Get the bin uncertainty for the bin at coordinate `x`.
1093 double GetBinUncertainty(const CoordArray_t &x) const final
1094 {
1095 const int bin = GetBinIndex(x);
1096 return this->GetBinUncertainty(bin);
1097 }
1098
1099 /// Whether this histogram's statistics provide storage for uncertainties, or
1100 /// whether uncertainties are determined as poisson uncertainty of the content.
1101 bool HasBinUncertainty() const final { return this->GetStat().HasBinUncertainty(); }
1102
1103 /// Get the begin() and end() for each axis.
1104 AxisIterRange_t<DATA::GetNDim()>
1105 GetRange() const final
1106 {
1107 std::array<std::array<RAxisBase::const_iterator, DATA::GetNDim()>, 2> ret;
1108 Internal::RFillIterRange<DATA::GetNDim() - 1, decltype(fAxes)>()(ret, fAxes);
1109 return ret;
1110 }
1111
1112 /// Grow the axis number `iAxis` to fit the coordinate `x`.
1113 ///
1114 /// The histogram (conceptually) combines pairs of bins along this axis until
1115 /// `x` is within the range of the axis.
1116 /// The axis must support growing for this to work (e.g. a `RAxisGrow`).
1117 void GrowAxis(int /*iAxis*/, double /*x*/)
1118 {
1119 // TODO: Implement GrowAxis()
1120 }
1121
1122 /// \{
1123 /// \name Iterator interface
1126 iterator begin() noexcept { return iterator(*this); }
1127 const_iterator begin() const noexcept { return const_iterator(*this); }
1128 iterator end() noexcept { return iterator(*this, this->GetNBinsNoOver()); }
1129 const_iterator end() const noexcept { return const_iterator(*this, this->GetNBinsNoOver()); }
1130 /// \}
1131};
1132
1133template <class DATA, class... AXISCONFIG>
1135{}
1136
1137template <class DATA, class... AXISCONFIG>
1139 : ImplBase_t(Internal::GetNBinsNoOverFromAxes(axisArgs...), Internal::GetNOverflowBinsFromAxes(axisArgs...)), fAxes{axisArgs...}
1140{}
1141
1142template <class DATA, class... AXISCONFIG>
1144 : ImplBase_t(title, Internal::GetNBinsNoOverFromAxes(axisArgs...), Internal::GetNOverflowBinsFromAxes(axisArgs...)), fAxes{axisArgs...}
1145{}
1146
1147#if 0
1148// In principle we can also have a runtime version of RHistImpl, that does not
1149// contain a tuple of concrete axis types but a vector of `RAxisConfig`.
1150template <class DATA>
1151class RHistImplRuntime: public RHistImplBase<DATA> {
1152public:
1153 RHistImplRuntime(std::array<RAxisConfig, DATA::GetNDim()>&& axisCfg);
1154};
1155#endif
1156
1157} // namespace Detail
1158
1159} // namespace Experimental
1160} // namespace ROOT
1161
1162#endif
#define R__ERROR_HERE(GROUP)
Definition: RLogger.hxx:183
#define b(i)
Definition: RSha256.hxx:100
typedef void((*Func_t)())
@ kUnderflow
Definition: TSystem.h:81
@ kOverflow
Definition: TSystem.h:80
Iterates over the bins of a RHist or RHistImpl.
Interface class for RHistImpl.
Definition: RHistImpl.hxx:151
Weight_t & GetBinContent(int binidx)
Get the bin content (sum of weights) for bin index binidx (non-const).
Definition: RHistImpl.hxx:219
int GetNOverflowBins() const noexcept final
Get the number of under- and overflow bins of this histogram, excluding all regular bins.
Definition: RHistImpl.hxx:209
RHistImplBase(const RHistImplBase &)=default
void(RHistImplBase::*)(const CoordArray_t &x, Weight_t w) FillFunc_t
Type of the Fill(x, w) function.
Definition: RHistImpl.hxx:163
virtual double GetBinUncertainty(const CoordArray_t &x) const =0
Get the bin uncertainty for the bin at coordinate x.
void AddBinContent(int binidx, Weight_t w)
Add w to the bin at index bin.
Definition: RHistImpl.hxx:236
int GetNBinsNoOver() const noexcept final
Get the number of bins in this histogram, excluding possible under- and overflow bins.
Definition: RHistImpl.hxx:205
RHistImplBase(RHistImplBase &&)=default
Hist::CoordArray_t< DATA::GetNDim()> CoordArray_t
Type of the coordinates.
Definition: RHistImpl.hxx:156
virtual std::unique_ptr< RHistImplBase > Clone() const =0
DATA Stat_t
Type of the statistics (bin content, uncertainties etc).
Definition: RHistImpl.hxx:154
Stat_t & GetStat() noexcept
Non-const access to statistics.
Definition: RHistImpl.hxx:229
virtual void FillN(const std::span< const CoordArray_t > xN)=0
Interface function to fill a vector or array of coordinates.
Weight_t GetBinContent(int binidx) const
Get the bin content (sum of weights) for bin index binidx.
Definition: RHistImpl.hxx:212
const Stat_t & GetStat() const noexcept
Const access to statistics.
Definition: RHistImpl.hxx:226
Stat_t fStatistics
The histogram's bin content, uncertainties etc.
Definition: RHistImpl.hxx:167
virtual void FillN(const std::span< const CoordArray_t > xN, const std::span< const Weight_t > weightN)=0
Interface function to fill a vector or array of coordinates with corresponding weights.
virtual Weight_t GetBinContent(const CoordArray_t &x) const =0
Get the bin content (sum of weights) for the bin at coordinate x.
std::array< int, DATA::GetNDim()> BinArray_t
Type of the local per-axis bin indices.
Definition: RHistImpl.hxx:158
RHistImplBase(std::string_view title, size_t numBins, size_t numOverflowBins)
Definition: RHistImpl.hxx:172
double GetBinContentAsDouble(int binidx) const final
Get the bin content (sum of weights) for bin index binidx, cast to double.
Definition: RHistImpl.hxx:233
int GetNBins() const noexcept final
Get the number of bins in this histogram, including possible under- and overflow bins.
Definition: RHistImpl.hxx:201
typename DATA::Weight_t Weight_t
Type of the bin content (and thus weights).
Definition: RHistImpl.hxx:160
RHistImplBase(size_t numBins, size_t numOverflowBins)
Definition: RHistImpl.hxx:171
virtual FillFunc_t GetFillFunc() const =0
Retrieve the pointer to the overridden Fill(x, w) function.
Base class for RHistImplBase that abstracts out the histogram's PRECISION.
Definition: RHistImpl.hxx:71
virtual int GetNOverflowBins() const noexcept=0
Number of under- and overflow bins of this histogram, excluding all regular bins.
virtual int GetBinIndex(const CoordArray_t &x) const =0
Given the coordinate x, determine the index of the bin.
std::array< int, DIMENSIONS > BinArray_t
Type of the local per-axis bin indices.
Definition: RHistImpl.hxx:76
RHistImplPrecisionAgnosticBase(RHistImplPrecisionAgnosticBase &&)=default
virtual int GetNBins() const noexcept=0
Number of bins of this histogram, including all overflow and underflow bins.
virtual bool HasBinUncertainty() const =0
Whether this histogram's statistics provide storage for uncertainties, or whether uncertainties are d...
virtual int GetNBinsNoOver() const noexcept=0
Number of bins of this histogram, excluding all overflow and underflow bins.
virtual CoordArray_t GetBinTo(int binidx) const =0
Get the upper edge in all dimensions of the bin with index binidx.
virtual BinArray_t GetLocalBins(int binidx) const =0
Given the index of the bin, determine the local per-axis bins x.
RHistImplPrecisionAgnosticBase(const RHistImplPrecisionAgnosticBase &)=default
const std::string & GetTitle() const
Get the histogram title.
Definition: RHistImpl.hxx:99
Hist::AxisIterRange_t< DIMENSIONS > AxisIterRange_t
Range type.
Definition: RHistImpl.hxx:78
static constexpr int GetNDim()
Number of dimensions of the coordinates.
Definition: RHistImpl.hxx:87
virtual int GetBinIndexAndGrow(const CoordArray_t &x) const =0
Given the coordinate x, determine the index of the bin, possibly growing axes for which x is out of r...
virtual int GetBinIndexFromLocalBins(const BinArray_t &x) const =0
Given the local per-axis bins x, determine the index of the bin.
virtual double GetBinUncertainty(int binidx) const =0
Get the uncertainty of the bin with index binidx.
virtual double GetBinContentAsDouble(int binidx) const =0
The bin content, cast to double.
virtual const RAxisBase & GetAxis(int iAxis) const =0
Get a base-class view on axis with index iAxis.
virtual CoordArray_t GetBinCenter(int binidx) const =0
Get the center in all dimensions of the bin with index binidx.
virtual AxisIterRange_t GetRange() const =0
Get an AxisIterRange_t for the whole histogram, excluding under- and overflow.
virtual CoordArray_t GetBinFrom(int binidx) const =0
Get the lower edge in all dimensions of the bin with index binidx.
void Fill(const CoordArray_t &x, Weight_t w=1.)
Add a single weight w to the bin at coordinate x.
Definition: RHistImpl.hxx:1076
BinArray_t GetLocalBins(int binidx) const final
Get the local per-axis bin indices x for the given bin index, using ComputeLocalBins().
Definition: RHistImpl.hxx:1014
int GetBinIndexAndGrow(const CoordArray_t &x) const final
Get the bin index for the given coordinates x, growing the axes as needed.
Definition: RHistImpl.hxx:990
int ComputeGlobalBinRaw(const BinArray_t &zeroBasedLocalBins, BINTYPE GetNBinType) const
Computes a zero-based global bin index, given...
Definition: RHistImpl.hxx:766
const_iterator end() const noexcept
Definition: RHistImpl.hxx:1129
AxisIterRange_t< DATA::GetNDim()> GetRange() const final
Get the begin() and end() for each axis.
Definition: RHistImpl.hxx:1105
BinArray_t ComputeLocalBins(int global_bin) const
Computes the local per-axis bin indices of a certain bin on an NDIMS-dimensional histogram,...
Definition: RHistImpl.hxx:866
double GetBinUncertainty(const CoordArray_t &x) const final
Get the bin uncertainty for the bin at coordinate x.
Definition: RHistImpl.hxx:1093
const_iterator begin() const noexcept
Definition: RHistImpl.hxx:1127
CoordArray_t GetBinCenter(int binidx) const final
Get the center coordinates of the bin with index binidx.
Definition: RHistImpl.hxx:1021
int GetBinIndexFromLocalBins(const BinArray_t &x) const final
Get the bin index for the given local per-axis bin indices x, using ComputeGlobalBin().
Definition: RHistImpl.hxx:1005
FillFunc_t GetFillFunc() const final
Retrieve the fill function for this histogram implementation, to prevent the virtual function call fo...
Definition: RHistImpl.hxx:749
std::tuple< AXISCONFIG... > fAxes
The histogram's axes.
Definition: RHistImpl.hxx:736
void GrowAxis(int, double)
Grow the axis number iAxis to fit the coordinate x.
Definition: RHistImpl.hxx:1117
Weight_t GetBinContent(const CoordArray_t &x) const final
Get the content of the bin at position x.
Definition: RHistImpl.hxx:1083
int GetBinIndex(const CoordArray_t &x) const final
Get the bin index for the given coordinates x.
Definition: RHistImpl.hxx:977
BinArray_t VirtualBinsToLocalBins(const BinArray_t &virtualBins) const
Converts zero-based virtual bins where the underflow bin has index 0 and the overflow bin has index N...
Definition: RHistImpl.hxx:801
const RAxisBase & GetAxis(int iAxis) const final
Normalized axes access, converting from actual axis type to base class.
Definition: RHistImpl.hxx:757
typename Hist::AxisIterRange_t< NDIMS > AxisIterRange_t
Definition: RHistImpl.hxx:733
int ComputeGlobalBin(BinArray_t &local_bins) const
Computes the global index of a certain bin on an NDIMS-dimensional histogram, knowing the local per-a...
Definition: RHistImpl.hxx:810
typename ImplBase_t::BinArray_t BinArray_t
Definition: RHistImpl.hxx:729
double GetBinUncertainty(int binidx) const final
Return the uncertainties for the given bin index.
Definition: RHistImpl.hxx:1090
bool HasBinUncertainty() const final
Whether this histogram's statistics provide storage for uncertainties, or whether uncertainties are d...
Definition: RHistImpl.hxx:1101
std::unique_ptr< ImplBase_t > Clone() const override
Definition: RHistImpl.hxx:743
RHistBinIter< ImplBase_t > iterator
Definition: RHistImpl.hxx:1125
void FillN(const std::span< const CoordArray_t > xN, const std::span< const Weight_t > weightN) final
Fill an array of weightN to the bins specified by coordinates xN.
Definition: RHistImpl.hxx:1051
BinArray_t ComputeLocalBinsRaw(int zeroBasedGlobalBin, BINTYPE GetNBinType) const
Computes zero-based local bin indices, given...
Definition: RHistImpl.hxx:779
const std::tuple< AXISCONFIG... > & GetAxes() const
Get the axes of this histogram.
Definition: RHistImpl.hxx:754
CoordArray_t GetBinTo(int binidx) const final
Get the coordinates of the high limit of the bin with index binidx.
Definition: RHistImpl.hxx:1039
void FillN(const std::span< const CoordArray_t > xN) final
Fill an array of weightN to the bins specified by coordinates xN.
Definition: RHistImpl.hxx:1068
CoordArray_t GetBinFrom(int binidx) const final
Get the coordinates of the low limit of the bin with index binidx.
Definition: RHistImpl.hxx:1030
BinArray_t LocalBinsToVirtualBins(const BinArray_t &localBins) const
Converts local axis bins from the standard kUnderflowBin/kOverflowBin for under/overflow bin indexing...
Definition: RHistImpl.hxx:790
RHistBinIter< const ImplBase_t > const_iterator
Definition: RHistImpl.hxx:1124
typename ImplBase_t::CoordArray_t CoordArray_t
Definition: RHistImpl.hxx:728
Random const_iterator through bins.
Definition: RAxis.hxx:127
Histogram axis base class.
Definition: RAxis.hxx:44
virtual int GetNBinsNoOver() const noexcept=0
Get the number of bins, excluding under- and overflow.
static constexpr const int kUnderflowBin
Index of the underflow bin, if any.
Definition: RAxis.hxx:229
static constexpr const int kOverflowBin
Index of the overflow bin, if any.
Definition: RAxis.hxx:232
int GetNBins() const noexcept
Get the number of bins, including under- and overflow.
Definition: RAxis.hxx:244
Objects used to configure the different axis types.
Definition: RAxisConfig.hxx:35
Double_t x[n]
Definition: legend1.C:17
basic_string_view< char > string_view
#define I(x, y, z)
EOverflow
Kinds of under- and overflow handling.
Definition: RHistImpl.hxx:46
@ kNoOverflow
Exclude under- and overflows.
@ kUnderOver
Include both under- and overflows.
std::array< AxisIter_t< NDIMS >, 2 > AxisIterRange_t
Range over n dimensional axes - a pair of arrays of n axis iterators.
Definition: RHistImpl.hxx:43
bool operator&(EOverflow a, EOverflow b)
Definition: RHistImpl.hxx:53
std::array< RAxisBase::const_iterator, NDIMS > AxisIter_t
Iterator over n dimensional axes - an array of n axis iterators.
Definition: RHistImpl.hxx:40
EFindStatus
Status of FindBin(x) and FindAdjustedBin(x)
Definition: RHistImpl.hxx:258
@ kValid
The returned bin index is valid.
@ kCanGrow
The coordinate could fit after growing the axis.
int GetNBinsFromAxes(AXISCONFIG... axisArgs)
Get the number of bins in whole hist, including under- and overflow.
Definition: RHistImpl.hxx:309
EBinCoord
Specifies if the wanted result is the bin's lower edge, center or higher edge.
Definition: RHistImpl.hxx:251
@ kBinFrom
Get the lower bin edge.
int GetNOverflowBinsFromAxes(AXISCONFIG... axisArgs)
Get the number of under- and overflow bins in whole hist, excluding regular bins.
Definition: RHistImpl.hxx:317
int GetNBinsNoOverFromAxes(AXISCONFIG... axisArgs)
Get the number of bins in whole hist, excluding under- and overflow.
Definition: RHistImpl.hxx:285
static std::array< const RAxisBase *, sizeof...(AXISCONFIG)> GetAxisView(const AXISCONFIG &... axes) noexcept
Definition: RHistImpl.hxx:709
tbb::task_arena is an alias of tbb::interface7::task_arena, which doesn't allow to forward declare tb...
Definition: StringConv.hxx:21
int operator()(int globalVirtualBin, const AXES &, const BINS &, int, BINTYPE) const
Definition: RHistImpl.hxx:578
Recursively computes a zero-based global bin index, given...
Definition: RHistImpl.hxx:585
int operator()(int globalVirtualBin, const AXES &axes, const BINS &zeroBasedLocalBins, int binSize, BINTYPE GetNBinType) const
Definition: RHistImpl.hxx:586
int operator()(int total_regular_bins_before, const AXES &, const BINS &, const BINS &, const BINS &) const
Definition: RHistImpl.hxx:388
Recursively gets the total number of regular bins before the current dimension, when computing a glob...
Definition: RHistImpl.hxx:395
int operator()(int total_regular_bins_before, const AXES &axes, const BINS &virtualBins, const BINS &binSizes, const BINS &localBins) const
Definition: RHistImpl.hxx:396
void operator()(std::array< int, NDIMS-1 >, std::array< int, NDIMS-1 >, const AXES &) const
Definition: RHistImpl.hxx:425
Recursively compute some quantities needed for ComputeLocalBins, namely the total number of bins per ...
Definition: RHistImpl.hxx:430
void operator()(std::array< int, NDIMS-1 > &bins_per_hyperplane, std::array< int, NDIMS-1 > &regular_bins_per_hyperplane, const AXES &axes) const
Definition: RHistImpl.hxx:431
Recursively computes zero-based local bin indices, given...
Definition: RHistImpl.hxx:558
void operator()(BINS &virtualBins, const AXES &axes, int zeroBasedGlobalBin, BINTYPE GetNBinType) const
Definition: RHistImpl.hxx:559
void operator()(const AXES &, int &, int &, std::array< int, NDIMS-1 >, std::array< int, NDIMS-1 >, int, int) const
Definition: RHistImpl.hxx:454
Recursively computes the number of regular bins before the current dimension, as well as the number o...
Definition: RHistImpl.hxx:462
void operator()(const AXES &axes, int &unprocessed_previous_overflow_bin, int &num_regular_bins_before, std::array< int, NDIMS-1 > bins_per_hyperplane, std::array< int, NDIMS-1 > regular_bins_per_hyperplane, int curr_bins_per_hyperplane, int curr_regular_bins_per_hyperplane) const
Definition: RHistImpl.hxx:463
void operator()(Hist::AxisIterRange_t< std::tuple_size< AXES >::value > &, const AXES &) const
Definition: RHistImpl.hxx:331
Recursively fills the ranges of all axes, excluding under- and overflow.
Definition: RHistImpl.hxx:336
void operator()(Hist::AxisIterRange_t< std::tuple_size< AXES >::value > &range, const AXES &axes) const
Definition: RHistImpl.hxx:337
void operator()(BINS &, const AXES &, const COORD &) const
Definition: RHistImpl.hxx:668
Find the per-axis local bin indices associated with a certain set of coordinates.
Definition: RHistImpl.hxx:673
void operator()(BINS &localBins, const AXES &axes, const COORD &coords) const
Definition: RHistImpl.hxx:674
Recursively gets the total number of bins in whole hist, including under- and overflow.
Definition: RHistImpl.hxx:303
int operator()(const AXES &axes) const
Definition: RHistImpl.hxx:304
Recursively gets the total number of bins in whole hist, excluding under- and overflow.
Definition: RHistImpl.hxx:279
Recursively gets the number of regular bins just before the current dimension.
Definition: RHistImpl.hxx:358
void operator()(BINS &binSizes, const AXES &axes) const
Definition: RHistImpl.hxx:359
void operator()(COORD &, const AXES &, const BINS &, EBinCoord) const
Definition: RHistImpl.hxx:689
Recursively converts local axis bins from the standard kUnderflowBin/kOverflowBin for under/overflow ...
Definition: RHistImpl.hxx:694
void operator()(COORD &coords, const AXES &axes, const BINS &localBins, EBinCoord kind) const
Definition: RHistImpl.hxx:695
Recursively converts local axis bins from the standard kUnderflowBin/kOverflowBin for under/overflow ...
Definition: RHistImpl.hxx:646
void operator()(BINS &virtualBins, const AXES &axes, const BINS &localBins) const
Definition: RHistImpl.hxx:647
Recursively converts zero-based virtual bins where the underflow bin has index 0 and the overflow bin...
Definition: RHistImpl.hxx:612
void operator()(BINS &localBins, const AXES &axes, const BINS &virtualBins) const
Definition: RHistImpl.hxx:613
auto * a
Definition: textangle.C:12