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);