Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 22 additions & 8 deletions hist/histv7/inc/ROOT/RRegularAxis.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -83,9 +83,10 @@ public:

/// Compute the linarized index for a single argument.
///
/// The normal bins have indices \f$0\f$ to \f$fNNormalBins - 1\f$, the underflow bin has index
/// \f$fNNormalBins\f$, and the overflow bin has index \f$fNNormalBins + 1\f$. If the argument is outside the
/// interval \f$[fLow, fHigh)\f$ and the flow bins are disabled, the return value is invalid.
/// If flow bins are disabled, the normal bins have indices \f$0\f$ to \f$fNNormalBins - 1\f$. Otherwise the
/// underflow bin has index \f$0\$, the indices of all normal bins shift by one, and the overflow bin has index
/// \f$fNNormalBins + 1\f$. If the argument is outside the interval \f$[fLow, fHigh)\f$ and the flow bins are
/// disabled, the return value is invalid.
///
/// \param[in] x the argument
/// \return the linearized index that may be invalid
Expand All @@ -95,7 +96,7 @@ public:
// Put NaNs into overflow bin.
bool overflow = !(x < fHigh);
if (underflow) {
return {fNNormalBins, fEnableFlowBins};
return {0, fEnableFlowBins};
} else if (overflow) {
return {fNNormalBins + 1, fEnableFlowBins};
}
Expand All @@ -104,28 +105,41 @@ public:
if (bin >= fNNormalBins) {
bin = fNNormalBins - 1;
}
// If the underflow bin is enabled, shift the normal bins by one.
if (fEnableFlowBins) {
bin += 1;
}
return {bin, true};
}

/// Get the linearized index for an RBinIndex.
///
/// The normal bins have indices \f$0\f$ to \f$fNNormalBins - 1\f$, the underflow bin has index
/// \f$fNNormalBins\f$, and the overflow bin has index \f$fNNormalBins + 1\f$.
/// If flow bins are disabled, the normal bins have indices \f$0\f$ to \f$fNNormalBins - 1\f$. Otherwise the
/// underflow bin has index \f$0\$, the indices of all normal bins shift by one, and the overflow bin has index
/// \f$fNNormalBins + 1\f$.
///
/// \param[in] index the RBinIndex
/// \return the linearized index that may be invalid
RLinearizedIndex GetLinearizedIndex(RBinIndex index) const
{
if (index.IsUnderflow()) {
return {fNNormalBins, fEnableFlowBins};
return {0, fEnableFlowBins};
} else if (index.IsOverflow()) {
return {fNNormalBins + 1, fEnableFlowBins};
} else if (index.IsInvalid()) {
return {0, false};
}
assert(index.IsNormal());
std::uint64_t bin = index.GetIndex();
return {bin, bin < fNNormalBins};
if (bin >= fNNormalBins) {
// Index is out of range and invalid.
return {bin, false};
}
// If the underflow bin is enabled, shift the normal bins by one.
if (fEnableFlowBins) {
bin += 1;
}
return {bin, true};
Comment thread
hahnjo marked this conversation as resolved.
}

/// Get the range of all normal bins.
Expand Down
34 changes: 26 additions & 8 deletions hist/histv7/inc/ROOT/RVariableBinAxis.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -79,9 +79,10 @@ public:

/// Compute the linarized index for a single argument.
///
/// The normal bins have indices \f$0\f$ to \f$fBinEdges.size() - 2\f$, the underflow bin has index
/// \f$fBinEdges.size() - 1\f$, and the overflow bin has index \f$fBinEdges.size()\f$. If the argument is outside all
/// bin edges and the flow bins are disabled, the return value is invalid.
/// If flow bins are disabled, the normal bins have indices \f$0\f$ to \f$fBinEdges.size() - 2\f$. Otherwise the
/// underflow bin has index \f$0\$, the indices of all normal bins shift by one, and the overflow bin has index
/// \f$fBinEdges.size()\f$. If the argument is outside all bin edges and the flow bins are disabled, the return value
/// is invalid.
///
/// \param[in] x the argument
/// \return the linearized index that may be invalid
Expand All @@ -91,40 +92,57 @@ public:
// Put NaNs into overflow bin.
bool overflow = !(x < fBinEdges.back());
if (underflow) {
return {fBinEdges.size() - 1, fEnableFlowBins};
return {0, fEnableFlowBins};
} else if (overflow) {
return {fBinEdges.size(), fEnableFlowBins};
}

// TODO (for later): The following can be optimized with binary search...
for (std::size_t bin = 0; bin < fBinEdges.size() - 2; bin++) {
if (x < fBinEdges[bin + 1]) {
// If the underflow bin is enabled, shift the normal bins by one.
if (fEnableFlowBins) {
bin += 1;
}
return {bin, true};
}
}
std::size_t bin = fBinEdges.size() - 2;
// If the underflow bin is enabled, shift the normal bins by one.
if (fEnableFlowBins) {
bin += 1;
}
return {bin, true};
}

/// Get the linearized index for an RBinIndex.
///
/// The normal bins have indices \f$0\f$ to \f$fBinEdges.size() - 2\f$, the underflow bin has index
/// \f$fBinEdges.size() - 1\f$, and the overflow bin has index \f$fBinEdges.size()\f$.
/// If flow bins are disabled, the normal bins have indices \f$0\f$ to \f$fBinEdges.size() - 2\f$. Otherwise the
/// underflow bin has index \f$0\$, the indices of all normal bins shift by one, and the overflow bin has index
/// \f$fBinEdges.size()\f$.
///
/// \param[in] index the RBinIndex
/// \return the linearized index that may be invalid
RLinearizedIndex GetLinearizedIndex(RBinIndex index) const
{
if (index.IsUnderflow()) {
return {fBinEdges.size() - 1, fEnableFlowBins};
return {0, fEnableFlowBins};
} else if (index.IsOverflow()) {
return {fBinEdges.size(), fEnableFlowBins};
} else if (index.IsInvalid()) {
return {0, false};
}
assert(index.IsNormal());
std::uint64_t bin = index.GetIndex();
return {bin, bin < fBinEdges.size() - 1};
if (bin >= fBinEdges.size() - 1) {
// Index is out of range and invalid.
return {bin, false};
}
// If the underflow bin is enabled, shift the normal bins by one.
if (fEnableFlowBins) {
bin += 1;
}
return {bin, true};
}

/// Get the range of all normal bins.
Expand Down
25 changes: 15 additions & 10 deletions hist/histv7/test/hist_axes.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -110,45 +110,49 @@ TEST(RAxes, ComputeGlobalIndex)
const RAxes axes({regularAxis, variableBinAxis, categoricalAxis});

{
const std::uint64_t Expected = (2 * (BinsY + 2) + 3) * (categories.size() + 1) + 2;
auto globalIndex = axes.ComputeGlobalIndex(std::make_tuple(1.5, 2.5, "c"));
EXPECT_EQ(globalIndex.fIndex, (1 * (BinsY + 2) + 2) * (categories.size() + 1) + 2);
EXPECT_EQ(globalIndex.fIndex, Expected);
EXPECT_TRUE(globalIndex.fValid);
const std::array<RBinIndex, 3> indices = {1, 2, 2};
globalIndex = axes.ComputeGlobalIndex(indices);
EXPECT_EQ(globalIndex.fIndex, (1 * (BinsY + 2) + 2) * (categories.size() + 1) + 2);
EXPECT_EQ(globalIndex.fIndex, Expected);
EXPECT_TRUE(globalIndex.fValid);
}

{
// Underflow bin of the first axis.
const std::uint64_t Expected = (0 * (BinsY + 2) + 3) * (categories.size() + 1) + 2;
auto globalIndex = axes.ComputeGlobalIndex(std::make_tuple(-1, 2.5, "c"));
EXPECT_EQ(globalIndex.fIndex, (BinsX * (BinsY + 2) + 2) * (categories.size() + 1) + 2);
EXPECT_EQ(globalIndex.fIndex, Expected);
EXPECT_TRUE(globalIndex.fValid);
const std::array<RBinIndex, 3> indices = {RBinIndex::Underflow(), 2, 2};
globalIndex = axes.ComputeGlobalIndex(indices);
EXPECT_EQ(globalIndex.fIndex, (BinsX * (BinsY + 2) + 2) * (categories.size() + 1) + 2);
EXPECT_EQ(globalIndex.fIndex, Expected);
EXPECT_TRUE(globalIndex.fValid);
}

{
// Overflow bin of the second axis.
const std::uint64_t Expected = (2 * (BinsY + 2) + BinsY + 1) * (categories.size() + 1) + 2;
auto globalIndex = axes.ComputeGlobalIndex(std::make_tuple(1.5, 42, "c"));
EXPECT_EQ(globalIndex.fIndex, (1 * (BinsY + 2) + BinsY + 1) * (categories.size() + 1) + 2);
EXPECT_EQ(globalIndex.fIndex, Expected);
EXPECT_TRUE(globalIndex.fValid);
const std::array<RBinIndex, 3> indices = {1, RBinIndex::Overflow(), 2};
globalIndex = axes.ComputeGlobalIndex(indices);
EXPECT_EQ(globalIndex.fIndex, (1 * (BinsY + 2) + BinsY + 1) * (categories.size() + 1) + 2);
EXPECT_EQ(globalIndex.fIndex, Expected);
EXPECT_TRUE(globalIndex.fValid);
}

{
// Overflow bin of the third axis.
const std::uint64_t Expected = (2 * (BinsY + 2) + 3) * (categories.size() + 1) + categories.size();
auto globalIndex = axes.ComputeGlobalIndex(std::make_tuple(1.5, 2.5, "d"));
EXPECT_EQ(globalIndex.fIndex, (1 * (BinsY + 2) + 2) * (categories.size() + 1) + categories.size());
EXPECT_EQ(globalIndex.fIndex, Expected);
EXPECT_TRUE(globalIndex.fValid);
const std::array<RBinIndex, 3> indices = {1, 2, RBinIndex::Overflow()};
globalIndex = axes.ComputeGlobalIndex(indices);
EXPECT_EQ(globalIndex.fIndex, (1 * (BinsY + 2) + 2) * (categories.size() + 1) + categories.size());
EXPECT_EQ(globalIndex.fIndex, Expected);
EXPECT_TRUE(globalIndex.fValid);
}
}
Expand All @@ -170,12 +174,13 @@ TEST(RAxes, ComputeGlobalIndexNoFlowBins)
ASSERT_EQ(axes.ComputeTotalNBins(), BinsX * BinsY * categories.size());

{
const std::uint64_t Expected = (1 * BinsY + 2) * categories.size() + 2;
auto globalIndex = axes.ComputeGlobalIndex(std::make_tuple(1.5, 2.5, "c"));
EXPECT_EQ(globalIndex.fIndex, (1 * BinsY + 2) * categories.size() + 2);
EXPECT_EQ(globalIndex.fIndex, Expected);
EXPECT_TRUE(globalIndex.fValid);
const std::array<RBinIndex, 3> indices = {1, 2, 2};
globalIndex = axes.ComputeGlobalIndex(indices);
EXPECT_EQ(globalIndex.fIndex, (1 * BinsY + 2) * categories.size() + 2);
EXPECT_EQ(globalIndex.fIndex, Expected);
EXPECT_TRUE(globalIndex.fValid);
}

Expand Down
16 changes: 8 additions & 8 deletions hist/histv7/test/hist_regular.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -62,17 +62,17 @@ TEST(RRegularAxis, ComputeLinearizedIndex)
static constexpr double UnderflowSmall = -0.1;
for (double underflow : {NegativeInfinity, UnderflowLarge, UnderflowSmall}) {
auto linIndex = axis.ComputeLinearizedIndex(underflow);
EXPECT_EQ(linIndex.fIndex, Bins);
EXPECT_EQ(linIndex.fIndex, 0);
EXPECT_TRUE(linIndex.fValid);
linIndex = axisNoFlowBins.ComputeLinearizedIndex(underflow);
EXPECT_EQ(linIndex.fIndex, Bins);
EXPECT_EQ(linIndex.fIndex, 0);
EXPECT_FALSE(linIndex.fValid);
}

// Exactly the lower end of the axis interval
{
auto linIndex = axis.ComputeLinearizedIndex(0);
EXPECT_EQ(linIndex.fIndex, 0);
EXPECT_EQ(linIndex.fIndex, 1);
EXPECT_TRUE(linIndex.fValid);
linIndex = axisNoFlowBins.ComputeLinearizedIndex(0);
EXPECT_EQ(linIndex.fIndex, 0);
Expand All @@ -81,7 +81,7 @@ TEST(RRegularAxis, ComputeLinearizedIndex)

for (std::size_t i = 0; i < Bins; i++) {
auto linIndex = axis.ComputeLinearizedIndex(i + 0.5);
EXPECT_EQ(linIndex.fIndex, i);
EXPECT_EQ(linIndex.fIndex, i + 1);
EXPECT_TRUE(linIndex.fValid);
linIndex = axisNoFlowBins.ComputeLinearizedIndex(i + 0.5);
EXPECT_EQ(linIndex.fIndex, i);
Expand Down Expand Up @@ -119,7 +119,7 @@ TEST(RRegularAxis, ComputeLinearizedIndexMin)
const RRegularAxis axis(Bins, {-1, std::numeric_limits<double>::min()});

auto linIndex = axis.ComputeLinearizedIndex(0);
EXPECT_EQ(linIndex.fIndex, Bins - 1);
EXPECT_EQ(linIndex.fIndex, Bins); // the last normal bin
EXPECT_TRUE(linIndex.fValid);
}

Expand All @@ -132,16 +132,16 @@ TEST(RRegularAxis, GetLinearizedIndex)
{
const auto underflow = RBinIndex::Underflow();
auto linIndex = axis.GetLinearizedIndex(underflow);
EXPECT_EQ(linIndex.fIndex, Bins);
EXPECT_EQ(linIndex.fIndex, 0);
EXPECT_TRUE(linIndex.fValid);
linIndex = axisNoFlowBins.GetLinearizedIndex(underflow);
EXPECT_EQ(linIndex.fIndex, Bins);
EXPECT_EQ(linIndex.fIndex, 0);
EXPECT_FALSE(linIndex.fValid);
}

for (std::size_t i = 0; i < Bins; i++) {
auto linIndex = axis.GetLinearizedIndex(i);
EXPECT_EQ(linIndex.fIndex, i);
EXPECT_EQ(linIndex.fIndex, i + 1);
EXPECT_TRUE(linIndex.fValid);
linIndex = axisNoFlowBins.GetLinearizedIndex(i);
EXPECT_EQ(linIndex.fIndex, i);
Expand Down
14 changes: 7 additions & 7 deletions hist/histv7/test/hist_variable.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -87,16 +87,16 @@ TEST(RVariableBinAxis, ComputeLinearizedIndex)
static constexpr double UnderflowSmall = -0.1;
for (double underflow : {NegativeInfinity, UnderflowLarge, UnderflowSmall}) {
auto linIndex = axis.ComputeLinearizedIndex(underflow);
EXPECT_EQ(linIndex.fIndex, Bins);
EXPECT_EQ(linIndex.fIndex, 0);
EXPECT_TRUE(linIndex.fValid);
linIndex = axisNoFlowBins.ComputeLinearizedIndex(underflow);
EXPECT_EQ(linIndex.fIndex, Bins);
EXPECT_EQ(linIndex.fIndex, 0);
EXPECT_FALSE(linIndex.fValid);
}

for (std::size_t i = 0; i < Bins; i++) {
auto linIndex = axis.ComputeLinearizedIndex(i + 0.5);
EXPECT_EQ(linIndex.fIndex, i);
EXPECT_EQ(linIndex.fIndex, i + 1);
EXPECT_TRUE(linIndex.fValid);
linIndex = axisNoFlowBins.ComputeLinearizedIndex(i + 0.5);
EXPECT_EQ(linIndex.fIndex, i);
Expand All @@ -106,7 +106,7 @@ TEST(RVariableBinAxis, ComputeLinearizedIndex)
// Exactly on the bin edges
for (std::size_t i = 0; i < Bins; i++) {
auto linIndex = axis.ComputeLinearizedIndex(i);
EXPECT_EQ(linIndex.fIndex, i);
EXPECT_EQ(linIndex.fIndex, i + 1);
EXPECT_TRUE(linIndex.fValid);
linIndex = axisNoFlowBins.ComputeLinearizedIndex(i);
EXPECT_EQ(linIndex.fIndex, i);
Expand Down Expand Up @@ -153,16 +153,16 @@ TEST(RVariableBinAxis, GetLinearizedIndex)
{
const auto underflow = RBinIndex::Underflow();
auto linIndex = axis.GetLinearizedIndex(underflow);
EXPECT_EQ(linIndex.fIndex, Bins);
EXPECT_EQ(linIndex.fIndex, 0);
EXPECT_TRUE(linIndex.fValid);
linIndex = axisNoFlowBins.GetLinearizedIndex(underflow);
EXPECT_EQ(linIndex.fIndex, Bins);
EXPECT_EQ(linIndex.fIndex, 0);
EXPECT_FALSE(linIndex.fValid);
}

for (std::size_t i = 0; i < Bins; i++) {
auto linIndex = axis.GetLinearizedIndex(i);
EXPECT_EQ(linIndex.fIndex, i);
EXPECT_EQ(linIndex.fIndex, i + 1);
EXPECT_TRUE(linIndex.fValid);
linIndex = axisNoFlowBins.GetLinearizedIndex(i);
EXPECT_EQ(linIndex.fIndex, i);
Expand Down
Loading