16 #ifndef ROOT7_RHistImpl
17 #define ROOT7_RHistImpl
31 namespace Experimental {
33 template <
int DIMENSIONS,
class PRECISION,
template <
int D_,
class P_>
class... STAT>
39 using AxisIter_t = std::array<RAxisBase::const_iterator, NDIM>;
42 using AxisIterRange_t = std::array<AxisIter_t<NDIM>, 2>;
45 enum class EOverflow {
52 inline bool operator&(EOverflow a, EOverflow b)
54 return static_cast<int>(a) & static_cast<int>(b);
69 template <
int DIMENSIONS>
70 class RHistImplPrecisionAgnosticBase {
73 using CoordArray_t = Hist::CoordArray_t<DIMENSIONS>;
75 using AxisIterRange_t = Hist::AxisIterRange_t<DIMENSIONS>;
77 RHistImplPrecisionAgnosticBase() =
default;
78 RHistImplPrecisionAgnosticBase(
const RHistImplPrecisionAgnosticBase &) =
default;
79 RHistImplPrecisionAgnosticBase(RHistImplPrecisionAgnosticBase &&) =
default;
80 RHistImplPrecisionAgnosticBase(std::string_view title): fTitle(title) {}
81 virtual ~RHistImplPrecisionAgnosticBase() {}
84 static constexpr
int GetNDim() {
return DIMENSIONS; }
87 virtual int GetNBins() const noexcept = 0;
90 const std::
string &GetTitle()
const {
return fTitle; }
93 virtual int GetBinIndex(
const CoordArray_t &x)
const = 0;
96 virtual int GetBinIndexAndGrow(
const CoordArray_t &x) = 0;
99 virtual CoordArray_t GetBinCenter(
int binidx)
const = 0;
101 virtual CoordArray_t GetBinFrom(
int binidx)
const = 0;
103 virtual CoordArray_t GetBinTo(
int binidx)
const = 0;
107 virtual double GetBinUncertainty(
int binidx)
const = 0;
111 virtual bool HasBinUncertainty()
const = 0;
114 virtual double GetBinContentAsDouble(
int binidx)
const = 0;
119 virtual RAxisView GetAxis(
int iAxis)
const = 0;
126 virtual AxisIterRange_t GetRange(
const std::array<Hist::EOverflow, DIMENSIONS> &withOverUnder)
const = 0;
140 template <
class DATA>
141 class RHistImplBase:
public RHistImplPrecisionAgnosticBase<DATA::GetNDim()> {
146 using CoordArray_t = Hist::CoordArray_t<DATA::GetNDim()>;
148 using Weight_t =
typename DATA::Weight_t;
151 using FillFunc_t = void (RHistImplBase::*)(
const CoordArray_t &x, Weight_t w);
158 RHistImplBase() =
default;
159 RHistImplBase(
size_t numBins): fStatistics(numBins) {}
160 RHistImplBase(std::string_view title,
size_t numBins)
161 : RHistImplPrecisionAgnosticBase<DATA::GetNDim()>(title), fStatistics(numBins)
163 RHistImplBase(
const RHistImplBase &) =
default;
164 RHistImplBase(RHistImplBase &&) =
default;
166 virtual std::unique_ptr<RHistImplBase> Clone()
const = 0;
171 virtual void FillN(
const std::span<const CoordArray_t> xN,
const std::span<const Weight_t> weightN) = 0;
174 virtual void FillN(
const std::span<const CoordArray_t> xN) = 0;
177 virtual FillFunc_t GetFillFunc()
const = 0;
181 virtual void Apply(std::function<
void(RHistBinRef<const RHistImplBase>)>)
const = 0;
185 virtual void ApplyXC(std::function<
void(
const CoordArray_t &, Weight_t)>)
const = 0;
189 virtual void ApplyXCE(std::function<
void(
const CoordArray_t &, Weight_t,
double)>)
const = 0;
192 virtual Weight_t GetBinContent(
const CoordArray_t &x)
const = 0;
194 using RHistImplPrecisionAgnosticBase<DATA::GetNDim()>::GetBinUncertainty;
197 virtual double GetBinUncertainty(
const CoordArray_t &x)
const = 0;
201 int GetNBins() const noexcept final {
return fStatistics.size(); }
204 Weight_t GetBinContent(
int binidx)
const {
return fStatistics[binidx]; }
207 Weight_t &GetBinContent(
int binidx) {
return fStatistics[binidx]; }
210 const Stat_t &GetStat() const noexcept {
return fStatistics; }
213 Stat_t &GetStat() noexcept {
return fStatistics; }
217 double GetBinContentAsDouble(
int binidx)
const final {
return (
double)GetBinContent(binidx); }
220 void AddBinContent(
int binidx, Weight_t w) { fStatistics[binidx] += w; }
233 template <
int IDX,
class AXISTUPLE>
236 template <
class AXES>
237 struct RGetBinCount<0, AXES> {
238 int operator()(
const AXES &axes)
const {
return std::get<0>(axes).GetNBins(); }
241 template <
int I,
class AXES>
242 struct RGetBinCount {
243 int operator()(
const AXES &axes)
const {
return std::get<I>(axes).GetNBins() * RGetBinCount<I - 1, AXES>()(axes); }
246 template <
class... AXISCONFIG>
247 int GetNBinsFromAxes(AXISCONFIG... axisArgs)
249 using axesTuple = std::tuple<AXISCONFIG...>;
250 return RGetBinCount<
sizeof...(AXISCONFIG) - 1, axesTuple>()(axesTuple{axisArgs...});
253 template <
int IDX,
class HISTIMPL,
class AXES,
bool GROW>
257 template <
class HISTIMPL,
class AXES,
bool GROW>
258 struct RGetBinIndex<-1, HISTIMPL, AXES, GROW> {
259 int operator()(HISTIMPL *,
const AXES &,
const typename HISTIMPL::CoordArray_t &,
260 RAxisBase::EFindStatus &status)
const
262 status = RAxisBase::EFindStatus::kValid;
267 template <
int I,
class HISTIMPL,
class AXES,
bool GROW>
268 struct RGetBinIndex {
269 int operator()(HISTIMPL *hist,
const AXES &axes,
const typename HISTIMPL::CoordArray_t &x,
270 RAxisBase::EFindStatus &status)
const
272 constexpr
const int thisAxis = HISTIMPL::GetNDim() - I - 1;
273 int bin = std::get<thisAxis>(axes).FindBin(x[thisAxis]);
274 if (GROW && std::get<thisAxis>(axes).CanGrow() && (bin < 0 || bin >= std::get<thisAxis>(axes).GetNBinsNoOver())) {
275 hist->GrowAxis(thisAxis, x[thisAxis]);
276 status = RAxisBase::EFindStatus::kCanGrow;
282 RGetBinIndex<I - 1, HISTIMPL, AXES, GROW>()(hist, axes, x, status) * std::get<thisAxis>(axes).GetNBins();
286 template <
int I,
class AXES>
287 struct RFillIterRange;
290 template <
class AXES>
291 struct RFillIterRange<-1, AXES> {
292 void operator()(Hist::AxisIterRange_t<std::tuple_size<AXES>::value> & ,
const AXES & ,
293 const std::array<Hist::EOverflow, std::tuple_size<AXES>::value> & )
const
300 template <
int I,
class AXES>
301 struct RFillIterRange {
302 void operator()(Hist::AxisIterRange_t<std::tuple_size<AXES>::value> &range,
const AXES &axes,
303 const std::array<Hist::EOverflow, std::tuple_size<AXES>::value> &over)
const
305 if (over[I] & Hist::EOverflow::kUnderflow)
306 range[0][I] = std::get<I>(axes).begin_with_underflow();
308 range[0][I] = std::get<I>(axes).begin();
309 if (over[I] & Hist::EOverflow::kOverflow)
310 range[1][I] = std::get<I>(axes).end_with_overflow();
312 range[1][I] = std::get<I>(axes).end();
313 RFillIterRange<I - 1, AXES>()(range, axes, over);
317 enum class EBinCoord {
323 template <
int I,
int NDIM,
class COORD,
class AXES>
324 struct RFillBinCoord;
327 template <
int NDIM,
class COORD,
class AXES>
328 struct RFillBinCoord<-1, NDIM, COORD, AXES> {
329 void operator()(COORD & ,
const AXES & , EBinCoord ,
int )
const {}
334 template <
int I,
int NDIM,
class COORD,
class AXES>
335 struct RFillBinCoord {
336 void operator()(COORD &coord,
const AXES &axes, EBinCoord kind,
int binidx)
const
338 constexpr
const int thisAxis = NDIM - I - 1;
339 int axisbin = binidx % std::get<thisAxis>(axes).GetNBins();
341 case EBinCoord::kBinFrom: coord[thisAxis] = std::get<thisAxis>(axes).GetBinFrom(axisbin);
break;
342 case EBinCoord::kBinCenter: coord[thisAxis] = std::get<thisAxis>(axes).GetBinCenter(axisbin);
break;
343 case EBinCoord::kBinTo: coord[thisAxis] = std::get<thisAxis>(axes).GetBinTo(axisbin);
break;
345 RFillBinCoord<I - 1, NDIM, COORD, AXES>()(coord, axes, kind, binidx / std::get<thisAxis>(axes).GetNBins());
349 template <
class... AXISCONFIG>
350 static std::array<RAxisView,
sizeof...(AXISCONFIG)> GetAxisView(
const AXISCONFIG &... axes) noexcept
352 std::array<RAxisView,
sizeof...(AXISCONFIG)> axisViews = {{RAxisView(axes)...}};
361 template <
class DATA,
class... AXISCONFIG>
362 class RHistImpl final:
public RHistImplBase<DATA> {
363 static_assert(
sizeof...(AXISCONFIG) == DATA::GetNDim(),
"Number of axes must equal histogram dimension");
365 friend typename DATA::Hist_t;
368 using ImplBase_t = RHistImplBase<DATA>;
369 using CoordArray_t =
typename ImplBase_t::CoordArray_t;
370 using Weight_t =
typename ImplBase_t::Weight_t;
371 using typename ImplBase_t::FillFunc_t;
372 template <
int NDIM = DATA::GetNDim()>
373 using AxisIterRange_t =
typename Hist::AxisIterRange_t<NDIM>;
376 std::tuple<AXISCONFIG...> fAxes;
379 RHistImpl(TRootIOCtor *);
380 RHistImpl(AXISCONFIG... axisArgs);
381 RHistImpl(std::string_view title, AXISCONFIG... axisArgs);
383 std::unique_ptr<ImplBase_t> Clone()
const override {
384 return std::unique_ptr<ImplBase_t>(
new RHistImpl(*
this));
389 FillFunc_t GetFillFunc() const final {
return (FillFunc_t)&RHistImpl::Fill; }
393 void Apply(std::function<
void(RHistBinRef<const ImplBase_t>)> op) const final
395 for (RHistBinRef<const ImplBase_t> binref: *
this)
401 void ApplyXC(std::function<
void(
const CoordArray_t &, Weight_t)> op) const final
403 for (
auto binref: *
this)
404 op(binref.GetCenter(), binref.GetContent());
409 virtual void ApplyXCE(std::function<
void(
const CoordArray_t &, Weight_t,
double)> op) const final
411 for (
auto binref: *
this)
412 op(binref.GetCenter(), binref.GetContent(), binref.GetUncertainty());
416 const std::tuple<AXISCONFIG...> &GetAxes()
const {
return fAxes; }
419 RAxisView GetAxis(
int iAxis)
const final {
return std::apply(Internal::GetAxisView<AXISCONFIG...>, fAxes)[iAxis]; }
423 int GetBinIndex(
const CoordArray_t &x)
const final
425 RAxisBase::EFindStatus status = RAxisBase::EFindStatus::kValid;
427 Internal::RGetBinIndex<DATA::GetNDim() - 1, RHistImpl, decltype(fAxes),
false>()(
nullptr, fAxes, x, status);
428 if (status != RAxisBase::EFindStatus::kValid)
436 int GetBinIndexAndGrow(
const CoordArray_t &x)
final
438 RAxisBase::EFindStatus status = RAxisBase::EFindStatus::kCanGrow;
440 while (status == RAxisBase::EFindStatus::kCanGrow) {
441 ret = Internal::RGetBinIndex<DATA::GetNDim() - 1, RHistImpl, decltype(fAxes),
true>()(
this, fAxes, x, status);
447 CoordArray_t GetBinCenter(
int binidx)
const final
449 using RFillBinCoord = Internal::RFillBinCoord<DATA::GetNDim() - 1, DATA::GetNDim(), CoordArray_t, decltype(fAxes)>;
451 RFillBinCoord()(coord, fAxes, Internal::EBinCoord::kBinCenter, binidx);
456 CoordArray_t GetBinFrom(
int binidx)
const final
458 using RFillBinCoord = Internal::RFillBinCoord<DATA::GetNDim() - 1, DATA::GetNDim(), CoordArray_t, decltype(fAxes)>;
460 RFillBinCoord()(coord, fAxes, Internal::EBinCoord::kBinFrom, binidx);
465 CoordArray_t GetBinTo(
int binidx)
const final
467 using RFillBinCoord = Internal::RFillBinCoord<DATA::GetNDim() - 1, DATA::GetNDim(), CoordArray_t, decltype(fAxes)>;
469 RFillBinCoord()(coord, fAxes, Internal::EBinCoord::kBinTo, binidx);
477 void FillN(
const std::span<const CoordArray_t> xN,
const std::span<const Weight_t> weightN)
final
480 if (xN.size() != weightN.size()) {
481 R__ERROR_HERE(
"HIST") <<
"Not the same number of points and weights!";
486 for (
size_t i = 0; i < xN.size(); ++i) {
487 Fill(xN[i], weightN[i]);
494 void FillN(
const std::span<const CoordArray_t> xN)
final
502 void Fill(
const CoordArray_t &x, Weight_t w = 1.)
504 int bin = GetBinIndexAndGrow(x);
505 this->GetStat().Fill(x, bin, w);
509 Weight_t GetBinContent(
const CoordArray_t &x)
const final
511 int bin = GetBinIndex(x);
513 return ImplBase_t::GetBinContent(bin);
518 double GetBinUncertainty(
int binidx)
const final {
return this->GetStat().GetBinUncertainty(binidx); }
521 double GetBinUncertainty(
const CoordArray_t &x)
const final
523 const int bin = GetBinIndex(x);
524 return this->GetBinUncertainty(bin);
529 bool HasBinUncertainty() const final {
return this->GetStat().HasBinUncertainty(); }
535 AxisIterRange_t<DATA::GetNDim()>
536 GetRange(
const std::array<Hist::EOverflow, DATA::GetNDim()> &withOverUnder) const final
538 std::array<std::array<RAxisBase::const_iterator, DATA::GetNDim()>, 2> ret;
539 Internal::RFillIterRange<DATA::GetNDim() - 1, decltype(fAxes)>()(ret, fAxes, withOverUnder);
548 void GrowAxis(
int ,
double )
555 using const_iterator = RHistBinIter<const ImplBase_t>;
556 using iterator = RHistBinIter<ImplBase_t>;
557 iterator begin() noexcept {
return iterator(*
this); }
558 const_iterator begin() const noexcept {
return const_iterator(*
this); }
559 iterator end() noexcept {
return iterator(*
this, this->GetNBins()); }
560 const_iterator end() const noexcept {
return const_iterator(*
this, this->GetNBins()); }
564 template <
class DATA,
class... AXISCONFIG>
565 RHistImpl<DATA, AXISCONFIG...>::RHistImpl(TRootIOCtor *)
568 template <
class DATA,
class... AXISCONFIG>
569 RHistImpl<DATA, AXISCONFIG...>::RHistImpl(AXISCONFIG... axisArgs)
570 : ImplBase_t(Internal::GetNBinsFromAxes(axisArgs...)), fAxes{axisArgs...}
573 template <
class DATA,
class... AXISCONFIG>
574 RHistImpl<DATA, AXISCONFIG...>::RHistImpl(std::string_view title, AXISCONFIG... axisArgs)
575 : ImplBase_t(title, Internal::GetNBinsFromAxes(axisArgs...)), fAxes{axisArgs...}
581 template <
class DATA>
582 class RHistImplRuntime:
public RHistImplBase<DATA> {
584 RHistImplRuntime(std::array<RAxisConfig, DATA::GetNDim()>&& axisCfg);