21 #include <initializer_list>
23 #include <unordered_map>
30 namespace Experimental {
45 enum class EFindStatus {
55 RAxisBase(
const RAxisBase &) =
default;
56 RAxisBase(RAxisBase &&) =
default;
57 RAxisBase &operator=(
const RAxisBase &) =
default;
58 RAxisBase &operator=(RAxisBase &&) =
default;
62 RAxisBase() =
default;
72 int AdjustOverflowBinNumber(
double rawbin)
const
79 if (rawbin >= GetNBins())
80 return GetNBins() - 1;
91 class const_iterator:
public std::iterator<std::random_access_iterator_tag, int , int ,
92 const int * , const int & > {
96 const_iterator() =
default;
99 explicit const_iterator(
int cursor) noexcept: fCursor(cursor) {}
102 const_iterator &operator++() noexcept
110 const_iterator &operator--() noexcept
118 const_iterator operator++(
int)noexcept
120 const_iterator old(*
this);
126 const_iterator operator--(
int)noexcept
128 const_iterator old(*
this);
134 const_iterator &operator+=(
int d) noexcept
141 const_iterator &operator-=(
int d) noexcept
148 const_iterator operator+(
int d) noexcept
150 const_iterator ret(*
this);
156 const_iterator operator-(
int d) noexcept
158 const_iterator ret(*
this);
164 const int *operator*() const noexcept {
return &fCursor; }
167 int operator->() const noexcept {
return fCursor; }
169 friend bool operator<(const_iterator lhs, const_iterator rhs) noexcept;
170 friend bool operator>(const_iterator lhs, const_iterator rhs) noexcept;
171 friend bool operator<=(const_iterator lhs, const_iterator rhs) noexcept;
172 friend bool operator>=(const_iterator lhs, const_iterator rhs) noexcept;
173 friend bool operator==(const_iterator lhs, const_iterator rhs) noexcept;
174 friend bool operator!=(const_iterator lhs, const_iterator rhs) noexcept;
178 constexpr
static const int kIgnoreBin = -1;
181 constexpr
static const int kNOverflowBins[4] = {0, 1, 1, 2};
189 RAxisBase(std::string_view title,
int nbinsNoOver,
bool canGrow) noexcept
190 : fNBins(nbinsNoOver + (canGrow ? 0 : 2)), fTitle(title), fCanGrow(canGrow)
198 RAxisBase(
int nbinsNoOver,
bool canGrow) noexcept: RAxisBase(
"", nbinsNoOver, canGrow) {}
200 const std::string &GetTitle()
const {
return fTitle; }
203 int GetNBinsNoOver() const noexcept {
return fNBins - GetNOverflowBins(); }
206 int GetNBins() const noexcept {
return fNBins; }
209 int GetNOverflowBins() const noexcept
218 int GetUnderflowBin() const noexcept {
return 0; }
222 int GetOverflowBin() const noexcept {
return GetNBinsNoOver() + 1; }
225 bool IsUnderflowBin(
int bin)
const noexcept {
return bin <= GetUnderflowBin(); }
228 bool IsOverflowBin(
int bin)
const noexcept {
return bin >= GetOverflowBin(); }
234 const_iterator begin() const noexcept {
return const_iterator{1}; }
237 const_iterator begin_with_underflow() const noexcept {
return const_iterator{0}; }
241 const_iterator end() const noexcept {
return const_iterator{GetOverflowBin()}; }
244 const_iterator end_with_overflow() const noexcept {
return const_iterator{GetOverflowBin() + 1}; }
250 bool fCanGrow =
false;
257 inline bool operator<(RAxisBase::const_iterator lhs, RAxisBase::const_iterator rhs) noexcept
259 return lhs.fCursor < rhs.fCursor;
263 inline bool operator>(RAxisBase::const_iterator lhs, RAxisBase::const_iterator rhs) noexcept
265 return lhs.fCursor > rhs.fCursor;
269 inline bool operator<=(RAxisBase::const_iterator lhs, RAxisBase::const_iterator rhs) noexcept
271 return lhs.fCursor <= rhs.fCursor;
275 inline bool operator>=(RAxisBase::const_iterator lhs, RAxisBase::const_iterator rhs) noexcept
277 return lhs.fCursor >= rhs.fCursor;
281 inline bool operator==(RAxisBase::const_iterator lhs, RAxisBase::const_iterator rhs) noexcept
283 return lhs.fCursor == rhs.fCursor;
287 inline bool operator!=(RAxisBase::const_iterator lhs, RAxisBase::const_iterator rhs) noexcept
289 return lhs.fCursor != rhs.fCursor;
300 class RAxisConfig:
public RAxisBase {
312 std::vector<double> fBinBorders;
313 std::vector<std::string> fLabels;
317 explicit RAxisConfig(std::string_view title,
int nbins,
double from,
double to, EKind kind)
318 : RAxisBase(title, nbins, kind == kGrow), fKind(kind), fBinBorders(2)
323 fBinBorders[0] = from;
335 constexpr
static const Grow_t Grow{};
339 RAxisConfig(std::string_view title,
int nbins,
double from,
double to)
340 : RAxisConfig(title, nbins, from, to, kEquidistant)
344 RAxisConfig(
int nbins,
double from,
double to): RAxisConfig(
"", nbins, from, to, kEquidistant) {}
347 RAxisConfig(std::string_view title, Grow_t,
int nbins,
double from,
double to)
348 : RAxisConfig(title, nbins, from, to, kGrow)
352 RAxisConfig(Grow_t,
int nbins,
double from,
double to): RAxisConfig(
"", nbins, from, to, kGrow) {}
355 RAxisConfig(std::string_view title,
const std::vector<double> &binborders)
356 : RAxisBase(title, binborders.size() - 1, false ), fKind(kIrregular), fBinBorders(binborders)
360 RAxisConfig(
const std::vector<double> &binborders): RAxisConfig(
"", binborders) {}
363 RAxisConfig(std::string_view title, std::vector<double> &&binborders) noexcept
364 : RAxisBase(title, binborders.size() - 1, false ), fKind(kIrregular),
365 fBinBorders(std::move(binborders))
369 RAxisConfig(std::vector<double> &&binborders) noexcept: RAxisConfig("", std::move(binborders)) {}
372 RAxisConfig(std::string_view title,
const std::vector<std::string_view> &labels)
373 : RAxisBase(title, labels.size(), true ), fKind(kLabels), fLabels(labels.begin(), labels.end())
377 RAxisConfig(
const std::vector<std::string_view> &labels): RAxisConfig(
"", labels) {}
380 RAxisConfig(std::string_view title, std::vector<std::string> &&labels)
381 : RAxisBase(title, labels.size(), true ), fKind(kLabels), fLabels(std::move(labels))
385 RAxisConfig(std::vector<std::string> &&labels): RAxisConfig(
"", std::move(labels)) {}
388 EKind GetKind() const noexcept {
return fKind; }
391 const std::vector<double> &GetBinBorders() const noexcept {
return fBinBorders; }
394 const std::vector<std::string> &GetBinLabels() const noexcept {
return fLabels; }
403 class RAxisEquidistant:
public RAxisBase {
406 double fInvBinWidth = 0.;
412 static double GetInvBinWidth(
int nbinsNoOver,
double lowOrHigh,
double highOrLow)
414 return nbinsNoOver / std::abs(highOrLow - lowOrHigh);
425 explicit RAxisEquidistant(std::string_view title,
int nbinsNoOver,
double low,
double high,
bool canGrow) noexcept
426 : RAxisBase(title, nbinsNoOver, canGrow), fLow(low), fInvBinWidth(GetInvBinWidth(nbinsNoOver, low, high))
436 explicit RAxisEquidistant(
int nbinsNoOver,
double low,
double high,
bool canGrow) noexcept
437 : RAxisEquidistant(
"", nbinsNoOver, low, high, canGrow)
441 RAxisEquidistant() =
default;
451 explicit RAxisEquidistant(
int nbinsNoOver,
double low,
double high) noexcept
452 : RAxisEquidistant(nbinsNoOver, low, high,
false )
463 explicit RAxisEquidistant(std::string_view title,
int nbinsNoOver,
double low,
double high) noexcept
464 : RAxisEquidistant(title, nbinsNoOver, low, high,
false )
468 operator RAxisConfig()
const {
return RAxisConfig(GetNBinsNoOver(), GetMinimum(), GetMaximum()); }
473 int FindBin(
double x)
const noexcept
475 double rawbin = (x - fLow) * fInvBinWidth;
476 return AdjustOverflowBinNumber(rawbin);
480 static bool CanGrow() noexcept {
return false; }
483 double GetMinimum() const noexcept {
return fLow; }
486 double GetMaximum() const noexcept {
return fLow + GetNBinsNoOver() / fInvBinWidth; }
489 double GetBinWidth() const noexcept {
return 1. / fInvBinWidth; }
492 double GetInverseBinWidth() const noexcept {
return fInvBinWidth; }
497 double GetBinCenter(
int bin)
const noexcept {
return fLow + (bin - 0.5) / fInvBinWidth; }
502 double GetBinFrom(
int bin)
const noexcept {
return fLow + (bin - 1) / fInvBinWidth; }
507 double GetBinTo(
int bin)
const noexcept {
return GetBinFrom(bin + 1); }
509 int GetBinIndexForLowEdge(
double x)
const noexcept;
513 inline bool operator==(
const RAxisEquidistant &lhs,
const RAxisEquidistant &rhs) noexcept
515 return lhs.GetNBins() == rhs.GetNBins() && lhs.GetMinimum() == rhs.GetMinimum() &&
516 lhs.GetInverseBinWidth() == rhs.GetInverseBinWidth();
523 class RAxisGrow:
public RAxisEquidistant {
534 explicit RAxisGrow(std::string_view title,
int nbins,
double low,
double high) noexcept
535 : RAxisEquidistant(title, nbins, low, high, CanGrow())
548 explicit RAxisGrow(
int nbins,
double low,
double high) noexcept: RAxisEquidistant(nbins, low, high, CanGrow()) {}
551 operator RAxisConfig()
const {
return RAxisConfig(RAxisConfig::Grow, GetNBinsNoOver(), GetMinimum(), GetMaximum()); }
580 bool CanGrow()
const {
return true; }
595 class RAxisIrregular:
public RAxisBase {
598 std::vector<double> fBinBorders;
601 RAxisIrregular() =
default;
605 explicit RAxisIrregular(
const std::vector<double> &binborders)
606 : RAxisBase(binborders.size() - 1, CanGrow()), fBinBorders(binborders)
608 #ifdef R__DO_RANGE_CHECKS
609 if (!std::is_sorted(fBinBorders.begin(), fBinBorders.end()))
610 R__ERROR_HERE(
"HIST") <<
"Bin borders must be sorted!";
611 #endif // R__DO_RANGE_CHECKS
618 explicit RAxisIrregular(std::vector<double> &&binborders) noexcept
619 : RAxisBase(binborders.size() - 1, CanGrow()), fBinBorders(std::move(binborders))
621 #ifdef R__DO_RANGE_CHECKS
622 if (!std::is_sorted(fBinBorders.begin(), fBinBorders.end()))
623 R__ERROR_HERE(
"HIST") <<
"Bin borders must be sorted!";
624 #endif // R__DO_RANGE_CHECKS
629 explicit RAxisIrregular(std::string_view title,
const std::vector<double> &binborders)
630 : RAxisBase(title, binborders.size() - 1, CanGrow()), fBinBorders(binborders)
632 #ifdef R__DO_RANGE_CHECKS
633 if (!std::is_sorted(fBinBorders.begin(), fBinBorders.end()))
634 R__ERROR_HERE(
"HIST") <<
"Bin borders must be sorted!";
635 #endif // R__DO_RANGE_CHECKS
642 explicit RAxisIrregular(std::string_view title, std::vector<double> &&binborders) noexcept
643 : RAxisBase(title, binborders.size() - 1, CanGrow()), fBinBorders(std::move(binborders))
645 #ifdef R__DO_RANGE_CHECKS
646 if (!std::is_sorted(fBinBorders.begin(), fBinBorders.end()))
647 R__ERROR_HERE(
"HIST") <<
"Bin borders must be sorted!";
648 #endif // R__DO_RANGE_CHECKS
652 operator RAxisConfig()
const {
return RAxisConfig(GetBinBorders()); }
657 int FindBin(
double x)
const noexcept
659 const auto bBegin = fBinBorders.begin();
660 const auto bEnd = fBinBorders.end();
662 auto iNotLess = std::lower_bound(bBegin, bEnd, x);
663 int rawbin = iNotLess - bBegin;
677 double GetBinCenter(
int bin)
const noexcept
679 if (IsUnderflowBin(bin))
680 return std::numeric_limits<double>::min();
681 if (IsOverflowBin(bin))
682 return std::numeric_limits<double>::max();
683 return 0.5 * (fBinBorders[bin - 1] + fBinBorders[bin]);
691 double GetBinFrom(
int bin)
const noexcept
693 if (IsUnderflowBin(bin))
694 return std::numeric_limits<double>::min();
697 return fBinBorders[bin - 1];
705 double GetBinTo(
int bin)
const noexcept
707 if (IsOverflowBin(bin))
708 return std::numeric_limits<double>::max();
709 return GetBinFrom(bin + 1);
713 static bool CanGrow() noexcept {
return false; }
716 const std::vector<double> &GetBinBorders() const noexcept {
return fBinBorders; }
736 class RAxisLabels:
public RAxisGrow {
739 std::unordered_map<std::string,
int > fLabelsIndex;
743 explicit RAxisLabels(std::string_view title,
const std::vector<std::string_view> &labels)
744 : RAxisGrow(title, labels.size(), 0., static_cast<double>(labels.size()))
746 for (
size_t i = 0, n = labels.size(); i < n; ++i)
747 fLabelsIndex[std::string(labels[i])] = i;
751 explicit RAxisLabels(std::string_view title,
const std::vector<std::string> &labels)
752 : RAxisGrow(title, labels.size(), 0., static_cast<double>(labels.size()))
754 for (
size_t i = 0, n = labels.size(); i < n; ++i)
755 fLabelsIndex[labels[i]] = i;
759 explicit RAxisLabels(
const std::vector<std::string_view> &labels): RAxisLabels(
"", labels) {}
762 explicit RAxisLabels(
const std::vector<std::string> &labels): RAxisLabels(
"", labels) {}
765 int GetBinIndex(
const std::string &label)
767 auto insertResult = fLabelsIndex.insert({label, -1});
768 if (insertResult.second) {
770 int idx = fLabelsIndex.size() - 1;
771 insertResult.first->second = idx;
774 return insertResult.first->second;
778 double GetBinCenter(
const std::string &label)
780 return GetBinIndex(label) - 0.5;
784 std::vector<std::string_view> GetBinLabels()
const
786 std::vector<std::string_view> vec(fLabelsIndex.size());
787 for (
const auto &kv: fLabelsIndex)
788 vec.at(kv.second) = kv.first;
797 template <RAxisConfig::EKind>
798 struct AxisConfigToType;
801 struct AxisConfigToType<RAxisConfig::kEquidistant> {
802 using Axis_t = RAxisEquidistant;
804 Axis_t operator()(
const RAxisConfig &cfg) noexcept
806 return RAxisEquidistant(cfg.GetTitle(), cfg.GetNBinsNoOver(), cfg.GetBinBorders()[0], cfg.GetBinBorders()[1]);
811 struct AxisConfigToType<RAxisConfig::kGrow> {
812 using Axis_t = RAxisGrow;
814 Axis_t operator()(
const RAxisConfig &cfg) noexcept
816 return RAxisGrow(cfg.GetTitle(), cfg.GetNBinsNoOver(), cfg.GetBinBorders()[0], cfg.GetBinBorders()[1]);
820 struct AxisConfigToType<RAxisConfig::kIrregular> {
821 using Axis_t = RAxisIrregular;
823 Axis_t operator()(
const RAxisConfig &cfg) {
return RAxisIrregular(cfg.GetTitle(), cfg.GetBinBorders()); }
827 struct AxisConfigToType<RAxisConfig::kLabels> {
828 using Axis_t = RAxisLabels;
830 Axis_t operator()(
const RAxisConfig &cfg) {
return RAxisLabels(cfg.GetTitle(), cfg.GetBinLabels()); }
838 const RAxisEquidistant *fEqui =
nullptr;
840 const RAxisIrregular *fIrr =
nullptr;
843 RAxisView() =
default;
846 RAxisView(
const RAxisEquidistant &equi): fEqui(&equi) {}
849 RAxisView(
const RAxisIrregular &irr): fIrr(&irr) {}
851 const std::string &GetTitle()
const {
return fEqui ? fEqui->GetTitle() : fIrr->GetTitle(); }
854 int FindBin(
double x)
const noexcept
857 return fEqui->FindBin(x);
858 return fIrr->FindBin(x);
862 int GetNBins() const noexcept
865 return fEqui->GetNBins();
866 return fIrr->GetNBins();
870 double GetFrom()
const {
return GetBinFrom(1); }
872 double GetTo()
const {
return GetBinTo(GetNBins() - 2); }
875 double GetBinCenter(
int i)
const noexcept
878 return fEqui->GetBinCenter(i);
879 return fIrr->GetBinCenter(i);
883 double GetBinFrom(
int i)
const noexcept
886 return fEqui->GetBinFrom(i);
887 return fIrr->GetBinFrom(i);
891 double GetBinTo(
int i)
const noexcept
894 return fEqui->GetBinTo(i);
895 return fIrr->GetBinTo(i);
899 const RAxisEquidistant *GetAsEquidistant()
const {
return fEqui; }
901 const RAxisIrregular *GetAsIrregular()
const {
return fIrr; }
906 enum class EAxisCompatibility {
923 EAxisCompatibility CanMap(RAxisEquidistant &target, RAxisEquidistant &source) noexcept;