Skip to content

Commit e111d60

Browse files
committed
[hist] Implement Get{Normal,Full}Range of axis
1 parent 78d03e6 commit e111d60

File tree

5 files changed

+251
-0
lines changed

5 files changed

+251
-0
lines changed

hist/histv7/inc/ROOT/RBinIndexRange.hxx

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,16 @@ A range of bin indices \f$[fBegin, fEnd)\f$.
2626
The interface allows convenient iteration over RBinIndex. If included, RBinIndex::Underflow() is encountered before the
2727
normal bins and RBinIndex::Overflow() is the last value.
2828
29+
~~~ {.cxx}
30+
ROOT::Experimental::RRegularAxis axis(10, 0, 1);
31+
for (auto index : axis.GetNormalRange(2, 5)) {
32+
// Will iterate over [2, 3, 4]
33+
}
34+
for (auto index : axis.GetFullRange()) {
35+
// Will iterate over all bins, starting with the underflow and ending with the overflow bin
36+
}
37+
~~~
38+
2939
\warning This is part of the ROOT 7 prototype! It will change without notice. It might trigger earthquakes. Feedback is
3040
welcome!
3141
*/
@@ -121,6 +131,9 @@ namespace Internal {
121131

122132
/// Internal function to create RBinIndexRange.
123133
///
134+
/// Users are strongly advised to create bin index ranges via the respective axis types, for example with
135+
/// RRegularAxis::GetNormalRange(RBinIndex, RBinIndex) or RRegularAxis::GetFullRange().
136+
///
124137
/// \param[in] begin the begin of the bin index range (inclusive)
125138
/// \param[in] end the end of the bin index range (exclusive)
126139
/// \param[in] nNormalBins the number of normal bins, after which iteration advances to RBinIndex::Overflow()

hist/histv7/inc/ROOT/RRegularAxis.hxx

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#define ROOT_RRegularAxis
77

88
#include "RBinIndex.hxx"
9+
#include "RBinIndexRange.hxx"
910
#include "RLinearizedIndex.hxx"
1011

1112
#include <cassert>
@@ -120,6 +121,50 @@ public:
120121
return {bin, bin < fNNormalBins};
121122
}
122123

124+
/// Get the range of all normal bins.
125+
///
126+
/// \return the bin index range from the first to the last bin, inclusive
127+
RBinIndexRange GetNormalRange() const
128+
{
129+
return Internal::CreateBinIndexRange(RBinIndex(0), RBinIndex(fNNormalBins), 0);
130+
}
131+
132+
/// Get a range of normal bins.
133+
///
134+
/// \param[in] begin the begin of the bin index range (inclusive), must be normal
135+
/// \param[in] end the end of the bin index range (exclusive), must be normal and >= begin
136+
/// \return a bin index range \f$[begin, end)\f$
137+
RBinIndexRange GetNormalRange(RBinIndex begin, RBinIndex end) const
138+
{
139+
if (!begin.IsNormal()) {
140+
throw std::invalid_argument("begin must be a normal bin");
141+
}
142+
if (begin.GetIndex() >= fNNormalBins) {
143+
throw std::invalid_argument("begin must be inside the axis");
144+
}
145+
if (!end.IsNormal()) {
146+
throw std::invalid_argument("end must be a normal bin");
147+
}
148+
if (end.GetIndex() > fNNormalBins) {
149+
throw std::invalid_argument("end must be inside or past the axis");
150+
}
151+
if (!(end >= begin)) {
152+
throw std::invalid_argument("end must be >= begin");
153+
}
154+
return Internal::CreateBinIndexRange(begin, end, 0);
155+
}
156+
157+
/// Get the full range of all bins.
158+
///
159+
/// This includes underflow and overflow bins, if enabled.
160+
///
161+
/// \return the bin index range of all bins
162+
RBinIndexRange GetFullRange() const
163+
{
164+
return fEnableFlowBins ? Internal::CreateBinIndexRange(RBinIndex::Underflow(), RBinIndex(), fNNormalBins)
165+
: GetNormalRange();
166+
}
167+
123168
/// ROOT Streamer function to throw when trying to store an object of this class.
124169
void Streamer(TBuffer &) { throw std::runtime_error("unable to store RRegularAxis"); }
125170
};

hist/histv7/inc/ROOT/RVariableBinAxis.hxx

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#define ROOT_RVariableBinAxis
77

88
#include "RBinIndex.hxx"
9+
#include "RBinIndexRange.hxx"
910
#include "RLinearizedIndex.hxx"
1011

1112
#include <cassert>
@@ -121,6 +122,49 @@ public:
121122
return {bin, bin < fBinEdges.size() - 1};
122123
}
123124

125+
/// Get the range of all normal bins.
126+
///
127+
/// \return the bin index range from the first to the last bin, inclusive
128+
RBinIndexRange GetNormalRange() const
129+
{
130+
return Internal::CreateBinIndexRange(RBinIndex(0), RBinIndex(fBinEdges.size() - 1), 0);
131+
}
132+
133+
/// Get a range of normal bins.
134+
///
135+
/// \param[in] begin the begin of the bin index range (inclusive), must be normal
136+
/// \param[in] end the end of the bin index range (exclusive), must be normal and >= begin
137+
/// \return a bin index range \f$[begin, end)\f$
138+
RBinIndexRange GetNormalRange(RBinIndex begin, RBinIndex end) const
139+
{
140+
if (!begin.IsNormal()) {
141+
throw std::invalid_argument("begin must be a normal bin");
142+
}
143+
if (begin.GetIndex() >= fBinEdges.size() - 1) {
144+
throw std::invalid_argument("begin must be inside the axis");
145+
}
146+
if (!end.IsNormal()) {
147+
throw std::invalid_argument("end must be a normal bin");
148+
}
149+
if (end.GetIndex() > fBinEdges.size() - 1) {
150+
throw std::invalid_argument("end must be inside or past the axis");
151+
}
152+
if (!(end >= begin)) {
153+
throw std::invalid_argument("end must be >= begin");
154+
}
155+
return Internal::CreateBinIndexRange(begin, end, 0);
156+
}
157+
158+
/// Get the full range of all bins.
159+
///
160+
/// This includes underflow and overflow bins, if enabled.
161+
///
162+
/// \return the bin index range of all bins
163+
RBinIndexRange GetFullRange() const
164+
{
165+
return fEnableFlowBins ? Internal::CreateBinIndexRange(RBinIndex::Underflow(), RBinIndex(), fBinEdges.size() - 1)
166+
: GetNormalRange();
167+
}
124168
/// ROOT Streamer function to throw when trying to store an object of this class.
125169
void Streamer(TBuffer &) { throw std::runtime_error("unable to store RVariableBinAxis"); }
126170
};

hist/histv7/test/hist_regular.cxx

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
#include "hist_test.hxx"
22

3+
#include <iterator>
34
#include <limits>
5+
#include <stdexcept>
46

57
TEST(RRegularAxis, Constructor)
68
{
@@ -163,3 +165,70 @@ TEST(RRegularAxis, GetLinearizedIndex)
163165
EXPECT_FALSE(linIndex.fValid);
164166
}
165167
}
168+
169+
TEST(RRegularAxis, GetNormalRange)
170+
{
171+
static constexpr std::size_t Bins = 20;
172+
const RRegularAxis axis(Bins, 0, Bins);
173+
const auto index0 = RBinIndex(0);
174+
const auto indexBins = RBinIndex(Bins);
175+
176+
{
177+
const auto normal = axis.GetNormalRange();
178+
EXPECT_EQ(normal.GetBegin(), index0);
179+
EXPECT_EQ(normal.GetEnd(), indexBins);
180+
EXPECT_EQ(std::distance(normal.begin(), normal.end()), Bins);
181+
}
182+
183+
{
184+
const auto normal = axis.GetNormalRange(index0, indexBins);
185+
EXPECT_EQ(normal.GetBegin(), index0);
186+
EXPECT_EQ(normal.GetEnd(), indexBins);
187+
EXPECT_EQ(std::distance(normal.begin(), normal.end()), Bins);
188+
}
189+
190+
{
191+
const auto index1 = RBinIndex(1);
192+
const auto index5 = RBinIndex(5);
193+
const auto normal = axis.GetNormalRange(index1, index5);
194+
EXPECT_EQ(normal.GetBegin(), index1);
195+
EXPECT_EQ(normal.GetEnd(), index5);
196+
EXPECT_EQ(std::distance(normal.begin(), normal.end()), 4);
197+
}
198+
199+
{
200+
const auto index1 = RBinIndex(1);
201+
const auto empty = axis.GetNormalRange(index1, index1);
202+
EXPECT_EQ(empty.GetBegin(), index1);
203+
EXPECT_EQ(empty.GetEnd(), index1);
204+
EXPECT_EQ(empty.begin(), empty.end());
205+
}
206+
207+
const auto underflow = RBinIndex::Underflow();
208+
const auto overflow = RBinIndex::Overflow();
209+
EXPECT_THROW(axis.GetNormalRange(underflow, index0), std::invalid_argument);
210+
EXPECT_THROW(axis.GetNormalRange(indexBins, indexBins), std::invalid_argument);
211+
EXPECT_THROW(axis.GetNormalRange(index0, overflow), std::invalid_argument);
212+
EXPECT_THROW(axis.GetNormalRange(index0, indexBins + 1), std::invalid_argument);
213+
}
214+
215+
TEST(RRegularAxis, FullRange)
216+
{
217+
static constexpr std::size_t Bins = 20;
218+
219+
{
220+
const RRegularAxis axis(Bins, 0, Bins);
221+
const auto full = axis.GetFullRange();
222+
EXPECT_EQ(full.GetBegin(), RBinIndex::Underflow());
223+
EXPECT_EQ(full.GetEnd(), RBinIndex());
224+
EXPECT_EQ(std::distance(full.begin(), full.end()), Bins + 2);
225+
}
226+
227+
{
228+
const RRegularAxis axisNoFlowBins(Bins, 0, Bins, /*enableFlowBins=*/false);
229+
const auto full = axisNoFlowBins.GetFullRange();
230+
EXPECT_EQ(full.GetBegin(), RBinIndex(0));
231+
EXPECT_EQ(full.GetEnd(), RBinIndex(Bins));
232+
EXPECT_EQ(std::distance(full.begin(), full.end()), Bins);
233+
}
234+
}

hist/histv7/test/hist_variable.cxx

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
#include "hist_test.hxx"
22

3+
#include <iterator>
34
#include <limits>
5+
#include <stdexcept>
46
#include <vector>
57

68
TEST(RVariableBinAxis, Constructor)
@@ -194,3 +196,81 @@ TEST(RVariableBinAxis, GetLinearizedIndex)
194196
EXPECT_FALSE(linIndex.fValid);
195197
}
196198
}
199+
200+
TEST(RVariableBinAxis, GetNormalRange)
201+
{
202+
static constexpr std::size_t Bins = 20;
203+
std::vector<double> bins;
204+
for (std::size_t i = 0; i < Bins; i++) {
205+
bins.push_back(i);
206+
}
207+
bins.push_back(Bins);
208+
209+
const RVariableBinAxis axis(bins);
210+
const auto index0 = RBinIndex(0);
211+
const auto indexBins = RBinIndex(Bins);
212+
213+
{
214+
const auto normal = axis.GetNormalRange();
215+
EXPECT_EQ(normal.GetBegin(), index0);
216+
EXPECT_EQ(normal.GetEnd(), indexBins);
217+
EXPECT_EQ(std::distance(normal.begin(), normal.end()), Bins);
218+
}
219+
220+
{
221+
const auto normal = axis.GetNormalRange(index0, indexBins);
222+
EXPECT_EQ(normal.GetBegin(), index0);
223+
EXPECT_EQ(normal.GetEnd(), indexBins);
224+
EXPECT_EQ(std::distance(normal.begin(), normal.end()), Bins);
225+
}
226+
227+
{
228+
const auto index1 = RBinIndex(1);
229+
const auto index5 = RBinIndex(5);
230+
const auto normal = axis.GetNormalRange(index1, index5);
231+
EXPECT_EQ(normal.GetBegin(), index1);
232+
EXPECT_EQ(normal.GetEnd(), index5);
233+
EXPECT_EQ(std::distance(normal.begin(), normal.end()), 4);
234+
}
235+
236+
{
237+
const auto index1 = RBinIndex(1);
238+
const auto empty = axis.GetNormalRange(index1, index1);
239+
EXPECT_EQ(empty.GetBegin(), index1);
240+
EXPECT_EQ(empty.GetEnd(), index1);
241+
EXPECT_EQ(empty.begin(), empty.end());
242+
}
243+
244+
const auto underflow = RBinIndex::Underflow();
245+
const auto overflow = RBinIndex::Overflow();
246+
EXPECT_THROW(axis.GetNormalRange(underflow, index0), std::invalid_argument);
247+
EXPECT_THROW(axis.GetNormalRange(indexBins, indexBins), std::invalid_argument);
248+
EXPECT_THROW(axis.GetNormalRange(index0, overflow), std::invalid_argument);
249+
EXPECT_THROW(axis.GetNormalRange(index0, indexBins + 1), std::invalid_argument);
250+
}
251+
252+
TEST(RVariableBinAxis, FullRange)
253+
{
254+
static constexpr std::size_t Bins = 20;
255+
std::vector<double> bins;
256+
for (std::size_t i = 0; i < Bins; i++) {
257+
bins.push_back(i);
258+
}
259+
bins.push_back(Bins);
260+
261+
{
262+
const RVariableBinAxis axis(bins);
263+
const auto full = axis.GetFullRange();
264+
EXPECT_EQ(full.GetBegin(), RBinIndex::Underflow());
265+
EXPECT_EQ(full.GetEnd(), RBinIndex());
266+
EXPECT_EQ(std::distance(full.begin(), full.end()), Bins + 2);
267+
}
268+
269+
{
270+
const RVariableBinAxis axisNoFlowBins(bins, /*enableFlowBins=*/false);
271+
const auto full = axisNoFlowBins.GetFullRange();
272+
EXPECT_EQ(full.GetBegin(), RBinIndex(0));
273+
EXPECT_EQ(full.GetEnd(), RBinIndex(Bins));
274+
EXPECT_EQ(std::distance(full.begin(), full.end()), Bins);
275+
}
276+
}

0 commit comments

Comments
 (0)