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
7 changes: 7 additions & 0 deletions hist/histv7/inc/ROOT/RBinWithError.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,13 @@ struct RBinWithError final {
return *this;
}

RBinWithError &operator*=(double factor)
{
fSum *= factor;
fSum2 *= factor * factor;
return *this;
}

void AtomicInc()
{
Internal::AtomicInc(&fSum);
Expand Down
11 changes: 11 additions & 0 deletions hist/histv7/inc/ROOT/RHist.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,17 @@ public:
fStats.Fill(args...);
}

/// Scale all histogram bin contents and statistics.
///
/// This method is not available for integral bin content types.
///
/// \param[in] factor the scale factor
void Scale(double factor)
{
fEngine.Scale(factor);
fStats.Scale(factor);
}

/// %ROOT Streamer function to throw when trying to store an object of this class.
void Streamer(TBuffer &) { throw std::runtime_error("unable to store RHist"); }
};
Expand Down
13 changes: 13 additions & 0 deletions hist/histv7/inc/ROOT/RHistEngine.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -405,6 +405,19 @@ public:
}
}

/// Scale all histogram bin contents.
///
/// This method is not available for integral bin content types.
///
/// \param[in] factor the scale factor
void Scale(double factor)
{
static_assert(!std::is_integral_v<BinContentType>, "scaling is not supported for integral bin content types");
for (std::size_t i = 0; i < fBinContents.size(); i++) {
fBinContents[i] *= factor;
}
}

/// %ROOT Streamer function to throw when trying to store an object of this class.
void Streamer(TBuffer &) { throw std::runtime_error("unable to store RHistEngine"); }
};
Expand Down
20 changes: 20 additions & 0 deletions hist/histv7/inc/ROOT/RHistStats.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,14 @@ public:
fSumWX3 = 0.0;
fSumWX4 = 0.0;
}

void Scale(double factor)
{
fSumWX *= factor;
fSumWX2 *= factor;
fSumWX3 *= factor;
fSumWX4 *= factor;
}
};

private:
Expand Down Expand Up @@ -393,6 +401,18 @@ public:
}
}

/// Scale the histogram statistics.
///
/// \param[in] factor the scale factor
void Scale(double factor)
{
fSumW *= factor;
fSumW2 *= factor * factor;
for (std::size_t i = 0; i < fDimensionStats.size(); i++) {
fDimensionStats[i].Scale(factor);
}
}

/// %ROOT Streamer function to throw when trying to store an object of this class.
void Streamer(TBuffer &) { throw std::runtime_error("unable to store RHistStats"); }
};
Expand Down
43 changes: 43 additions & 0 deletions hist/histv7/test/hist_engine.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -358,6 +358,28 @@ TEST(RHistEngine, FillTupleWeightInvalidNumberOfArguments)
EXPECT_THROW(engine2.Fill(std::make_tuple(1, 2, 3), RWeight(1)), std::invalid_argument);
}

TEST(RHistEngine, Scale)
{
static constexpr std::size_t Bins = 20;
const RRegularAxis axis(Bins, {0, Bins});
RHistEngine<float> engine({axis});

engine.Fill(-100, RWeight(0.25));
for (std::size_t i = 0; i < Bins; i++) {
engine.Fill(i, RWeight(0.1 + i * 0.03));
}
engine.Fill(100, RWeight(0.75));

static constexpr double Factor = 0.8;
engine.Scale(Factor);

EXPECT_FLOAT_EQ(engine.GetBinContent(RBinIndex::Underflow()), Factor * 0.25);
for (auto index : axis.GetNormalRange()) {
EXPECT_FLOAT_EQ(engine.GetBinContent(index), Factor * (0.1 + index.GetIndex() * 0.03));
}
EXPECT_FLOAT_EQ(engine.GetBinContent(RBinIndex::Overflow()), Factor * 0.75);
}

TEST(RHistEngine_RBinWithError, Add)
{
static constexpr std::size_t Bins = 20;
Expand Down Expand Up @@ -415,3 +437,24 @@ TEST(RHistEngine_RBinWithError, FillWeight)
EXPECT_FLOAT_EQ(bin.fSum2, weight * weight);
}
}

TEST(RHistEngine_RBinWithError, Scale)
{
static constexpr std::size_t Bins = 20;
const RRegularAxis axis(Bins, {0, Bins});
RHistEngine<RBinWithError> engine({axis});

for (std::size_t i = 0; i < Bins; i++) {
engine.Fill(i, RWeight(0.1 + i * 0.03));
}

static constexpr double Factor = 0.8;
engine.Scale(Factor);

for (auto index : axis.GetNormalRange()) {
auto &bin = engine.GetBinContent(index);
double weight = Factor * (0.1 + index.GetIndex() * 0.03);
EXPECT_FLOAT_EQ(bin.fSum, weight);
EXPECT_FLOAT_EQ(bin.fSum2, weight * weight);
}
}
42 changes: 34 additions & 8 deletions hist/histv7/test/hist_hist.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -105,10 +105,10 @@ TEST(RHist, Fill)
std::array<RBinIndex, 1> indices = {9};
EXPECT_EQ(hist.GetBinContent(indices), 1);

EXPECT_EQ(hist.GetStats().GetNEntries(), 2);
EXPECT_FLOAT_EQ(hist.GetStats().ComputeNEffectiveEntries(), 2);
EXPECT_FLOAT_EQ(hist.GetStats().ComputeMean(), 9);
EXPECT_FLOAT_EQ(hist.GetStats().ComputeStdDev(), 0.5);
EXPECT_EQ(hist.GetNEntries(), 2);
EXPECT_FLOAT_EQ(hist.ComputeNEffectiveEntries(), 2);
EXPECT_FLOAT_EQ(hist.ComputeMean(), 9);
EXPECT_FLOAT_EQ(hist.ComputeStdDev(), 0.5);
}

TEST(RHist, FillWeight)
Expand All @@ -124,9 +124,35 @@ TEST(RHist, FillWeight)
std::array<RBinIndex, 1> indices = {9};
EXPECT_FLOAT_EQ(hist.GetBinContent(indices), 0.9);

EXPECT_EQ(hist.GetStats().GetNEntries(), 2);
EXPECT_EQ(hist.GetNEntries(), 2);
EXPECT_FLOAT_EQ(hist.GetStats().GetSumW(), 1.7);
EXPECT_FLOAT_EQ(hist.GetStats().GetSumW2(), 1.45);
// Cross-checked with TH1
EXPECT_FLOAT_EQ(hist.GetStats().ComputeNEffectiveEntries(), 1.9931034);
EXPECT_FLOAT_EQ(hist.GetStats().ComputeMean(), 9.0294118);
EXPECT_FLOAT_EQ(hist.GetStats().ComputeStdDev(), 0.49913420);
EXPECT_FLOAT_EQ(hist.ComputeNEffectiveEntries(), 1.9931034);
EXPECT_FLOAT_EQ(hist.ComputeMean(), 9.0294118);
EXPECT_FLOAT_EQ(hist.ComputeStdDev(), 0.49913420);
}

TEST(RHist, Scale)
{
static constexpr std::size_t Bins = 20;
const RRegularAxis axis(Bins, {0, Bins});
RHist<float> hist({axis});

hist.Fill(8.5, RWeight(0.8));
hist.Fill(9.5, RWeight(0.9));

static constexpr double Factor = 0.8;
hist.Scale(Factor);

EXPECT_FLOAT_EQ(hist.GetBinContent(8), Factor * 0.8);
EXPECT_FLOAT_EQ(hist.GetBinContent(9), Factor * 0.9);

EXPECT_EQ(hist.GetNEntries(), 2);
EXPECT_FLOAT_EQ(hist.GetStats().GetSumW(), Factor * 1.7);
EXPECT_FLOAT_EQ(hist.GetStats().GetSumW2(), Factor * Factor * 1.45);
// Cross-checked with TH1 - unchanged compared to FillWeight because the factor cancels out.
EXPECT_FLOAT_EQ(hist.ComputeNEffectiveEntries(), 1.9931034);
EXPECT_FLOAT_EQ(hist.ComputeMean(), 9.0294118);
EXPECT_FLOAT_EQ(hist.ComputeStdDev(), 0.49913420);
}
41 changes: 41 additions & 0 deletions hist/histv7/test/hist_stats.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -455,3 +455,44 @@ TEST(RHistStats, FillTupleWeightInvalidNumberOfArguments)
EXPECT_NO_THROW(stats2.Fill(std::make_tuple(1, 2), RWeight(1)));
EXPECT_THROW(stats2.Fill(std::make_tuple(1, 2, 3), RWeight(1)), std::invalid_argument);
}

TEST(RHistStats, Scale)
{
RHistStats stats(3);
ASSERT_EQ(stats.GetNEntries(), 0);

static constexpr std::size_t Entries = 20;
for (std::size_t i = 0; i < Entries; i++) {
stats.Fill(i, 2 * i, i * i, RWeight(0.1 + 0.03 * i));
}

static constexpr double Factor = 0.8;
stats.Scale(Factor);

// The number of entries should not have changed.
EXPECT_EQ(stats.GetNEntries(), Entries);
EXPECT_DOUBLE_EQ(stats.GetSumW(), Factor * 7.7);
EXPECT_DOUBLE_EQ(stats.GetSumW2(), Factor * Factor * 3.563);

{
const auto &dimensionStats = stats.GetDimensionStats(/*=0*/);
EXPECT_DOUBLE_EQ(dimensionStats.fSumWX, Factor * 93.1);
EXPECT_DOUBLE_EQ(dimensionStats.fSumWX2, Factor * 1330.0);
EXPECT_DOUBLE_EQ(dimensionStats.fSumWX3, Factor * 20489.98);
EXPECT_DOUBLE_EQ(dimensionStats.fSumWX4, Factor * 330265.6);
}
{
const auto &dimensionStats = stats.GetDimensionStats(1);
EXPECT_DOUBLE_EQ(dimensionStats.fSumWX, Factor * 2 * 93.1);
EXPECT_DOUBLE_EQ(dimensionStats.fSumWX2, Factor * 4 * 1330.0);
EXPECT_DOUBLE_EQ(dimensionStats.fSumWX3, Factor * 8 * 20489.98);
EXPECT_DOUBLE_EQ(dimensionStats.fSumWX4, Factor * 16 * 330265.6);
}
{
const auto &dimensionStats = stats.GetDimensionStats(2);
EXPECT_DOUBLE_EQ(dimensionStats.fSumWX, Factor * 1330.0);
EXPECT_DOUBLE_EQ(dimensionStats.fSumWX2, Factor * 330265.6);
EXPECT_DOUBLE_EQ(dimensionStats.fSumWX3, Factor * 93164182.0);
EXPECT_DOUBLE_EQ(dimensionStats.fSumWX4, Factor * 28108731464.8);
}
}
23 changes: 23 additions & 0 deletions hist/histv7/test/hist_user.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,12 @@ struct User {
return *this;
}

User &operator*=(double factor)
{
fValue *= factor;
return *this;
}

void AtomicInc() { ROOT::Experimental::Internal::AtomicInc(&fValue); }

void AtomicAdd(double w) { ROOT::Experimental::Internal::AtomicAdd(&fValue, w); }
Expand Down Expand Up @@ -153,3 +159,20 @@ TEST(RHistEngineUser, FillAtomicWeight)
std::array<RBinIndex, 1> indices = {9};
EXPECT_EQ(engine.GetBinContent(indices).fValue, 0.9);
}

TEST(RHistEngineUser, Scale)
{
// Scaling uses operator+=(double)
static constexpr std::size_t Bins = 20;
const RRegularAxis axis(Bins, {0, Bins});
RHistEngine<User> engine({axis});

engine.Fill(8.5, RWeight(0.8));
engine.Fill(9.5, RWeight(0.9));

static constexpr double Factor = 0.8;
engine.Scale(Factor);

EXPECT_EQ(engine.GetBinContent(8).fValue, Factor * 0.8);
EXPECT_EQ(engine.GetBinContent(9).fValue, Factor * 0.9);
}
Loading