diff --git a/hist/histv7/inc/ROOT/RHist.hxx b/hist/histv7/inc/ROOT/RHist.hxx index 10fa9cc679782..05e67ee08a60d 100644 --- a/hist/histv7/inc/ROOT/RHist.hxx +++ b/hist/histv7/inc/ROOT/RHist.hxx @@ -146,6 +146,9 @@ public: ~RHist() = default; + /// \name Accessors + /// \{ + const RHistEngine &GetEngine() const { return fEngine; } const RHistStats &GetStats() const { return fStats; } @@ -154,6 +157,11 @@ public: std::uint64_t GetTotalNBins() const { return fEngine.GetTotalNBins(); } std::uint64_t GetNEntries() const { return fStats.GetNEntries(); } + + /// \} + /// \name Computations + /// \{ + /// \copydoc RHistStats::ComputeNEffectiveEntries() double ComputeNEffectiveEntries() const { return fStats.ComputeNEffectiveEntries(); } /// \copydoc RHistStats::ComputeMean() @@ -161,6 +169,10 @@ public: /// \copydoc RHistStats::ComputeStdDev() double ComputeStdDev(std::size_t dim = 0) const { return fStats.ComputeStdDev(dim); } + /// \} + /// \name Accessors + /// \{ + /// Get the content of a single bin. /// /// \code @@ -258,8 +270,7 @@ public: /// \param[in] indices the array of indices for each axis /// \param[in] value the new value of the bin content /// \par See also - /// the \ref SetBinContent(const A &... args) const "variadic function template overload" accepting arguments - /// directly + /// the \ref SetBinContent(const A &... args) "variadic function template overload" accepting arguments directly template void SetBinContent(const std::array &indices, const V &value) { @@ -287,8 +298,8 @@ public: /// /// \param[in] args the arguments for each axis and the new value of the bin content /// \par See also - /// the \ref SetBinContent(const std::array &indices, const V &value) const "function overload" - /// accepting `std::array` + /// the \ref SetBinContent(const std::array &indices, const V &value) "function overload" accepting + /// `std::array` template void SetBinContent(const A &...args) { @@ -296,62 +307,9 @@ public: fStats.Taint(); } - /// Add all bin contents and statistics of another histogram. - /// - /// Throws an exception if the axes configurations are not identical. - /// - /// \param[in] other another histogram - void Add(const RHist &other) - { - fEngine.Add(other.fEngine); - fStats.Add(other.fStats); - } - - /// Add all bin contents and statistics of another histogram using atomic instructions. - /// - /// Throws an exception if the axes configurations are not identical. - /// - /// \param[in] other another histogram that must not be modified during the operation - void AddAtomic(const RHist &other) - { - fEngine.AddAtomic(other.fEngine); - fStats.AddAtomic(other.fStats); - } - - /// Clear all bin contents and statistics. - void Clear() - { - fEngine.Clear(); - fStats.Clear(); - } - - /// Clone this histogram. - /// - /// Copying all bin contents can be an expensive operation, depending on the number of bins. - /// - /// \return the cloned object - RHist Clone() const - { - RHist h(fEngine.Clone()); - h.fStats = fStats; - return h; - } - - /// Convert this histogram to a different bin content type. - /// - /// There is no bounds checking to make sure that the converted values can be represented. Note that it is not - /// possible to convert to RBinWithError since the information about individual weights has been lost since filling. - /// - /// Converting all bin contents can be an expensive operation, depending on the number of bins. - /// - /// \return the converted object - template - RHist Convert() const - { - RHist h(fEngine.template Convert()); - h.fStats = fStats; - return h; - } + /// \} + /// \name Filling + /// \{ /// Fill an entry into the histogram. /// @@ -440,6 +398,67 @@ public: } } + /// \} + /// \name Operations + /// \{ + + /// Add all bin contents and statistics of another histogram. + /// + /// Throws an exception if the axes configurations are not identical. + /// + /// \param[in] other another histogram + void Add(const RHist &other) + { + fEngine.Add(other.fEngine); + fStats.Add(other.fStats); + } + + /// Add all bin contents and statistics of another histogram using atomic instructions. + /// + /// Throws an exception if the axes configurations are not identical. + /// + /// \param[in] other another histogram that must not be modified during the operation + void AddAtomic(const RHist &other) + { + fEngine.AddAtomic(other.fEngine); + fStats.AddAtomic(other.fStats); + } + + /// Clear all bin contents and statistics. + void Clear() + { + fEngine.Clear(); + fStats.Clear(); + } + + /// Clone this histogram. + /// + /// Copying all bin contents can be an expensive operation, depending on the number of bins. + /// + /// \return the cloned object + RHist Clone() const + { + RHist h(fEngine.Clone()); + h.fStats = fStats; + return h; + } + + /// Convert this histogram to a different bin content type. + /// + /// There is no bounds checking to make sure that the converted values can be represented. Note that it is not + /// possible to convert to RBinWithError since the information about individual weights has been lost since filling. + /// + /// Converting all bin contents can be an expensive operation, depending on the number of bins. + /// + /// \return the converted object + template + RHist Convert() const + { + RHist h(fEngine.template Convert()); + h.fStats = fStats; + return h; + } + /// Scale all histogram bin contents and statistics. /// /// This method is not available for integral bin content types. @@ -560,6 +579,8 @@ public: return Slice(sliceSpecs); } + /// \} + /// %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"); } }; diff --git a/hist/histv7/inc/ROOT/RHistEngine.hxx b/hist/histv7/inc/ROOT/RHistEngine.hxx index f04fd03304be8..4a6003445083d 100644 --- a/hist/histv7/inc/ROOT/RHistEngine.hxx +++ b/hist/histv7/inc/ROOT/RHistEngine.hxx @@ -143,6 +143,9 @@ public: ~RHistEngine() = default; + /// \name Accessors + /// \{ + const std::vector &GetAxes() const { return fAxes.Get(); } std::size_t GetNDimensions() const { return fAxes.GetNDimensions(); } std::uint64_t GetTotalNBins() const { return fBinContents.size(); } @@ -262,8 +265,7 @@ public: /// \param[in] indices the array of indices for each axis /// \param[in] value the new value of the bin content /// \par See also - /// the \ref SetBinContent(const A &... args) const "variadic function template overload" accepting arguments - /// directly + /// the \ref SetBinContent(const A &... args) "variadic function template overload" accepting arguments directly template void SetBinContent(const std::array &indices, const V &value) { @@ -282,6 +284,9 @@ public: fBinContents[index.fIndex] = value; } + /// \} + // End the group to ensure that all contained member functions are public. + private: template void SetBinContentImpl(const std::tuple &args, std::index_sequence) @@ -291,6 +296,9 @@ private: } public: + /// \name Accessors + /// \{ + /// Set the content of a single bin. /// /// \code @@ -308,8 +316,8 @@ public: /// /// \param[in] args the arguments for each axis and the new value of the bin content /// \par See also - /// the \ref SetBinContent(const std::array &indices, const V &value) const "function overload" - /// accepting `std::array` + /// the \ref SetBinContent(const std::array &indices, const V &value) "function overload" accepting + /// `std::array` template void SetBinContent(const A &...args) { @@ -317,79 +325,16 @@ public: SetBinContentImpl(t, std::make_index_sequence()); } - /// Add all bin contents of another histogram. - /// - /// Throws an exception if the axes configurations are not identical. - /// - /// \param[in] other another histogram - void Add(const RHistEngine &other) - { - if (fAxes != other.fAxes) { - throw std::invalid_argument("axes configurations not identical in Add"); - } - for (std::size_t i = 0; i < fBinContents.size(); i++) { - fBinContents[i] += other.fBinContents[i]; - } - } - - /// Add all bin contents of another histogram using atomic instructions. - /// - /// Throws an exception if the axes configurations are not identical. - /// - /// \param[in] other another histogram that must not be modified during the operation - void AddAtomic(const RHistEngine &other) - { - if (fAxes != other.fAxes) { - throw std::invalid_argument("axes configurations not identical in AddAtomic"); - } - for (std::size_t i = 0; i < fBinContents.size(); i++) { - Internal::AtomicAdd(&fBinContents[i], other.fBinContents[i]); - } - } - - /// Clear all bin contents. - void Clear() - { - for (std::size_t i = 0; i < fBinContents.size(); i++) { - fBinContents[i] = {}; - } - } - - /// Clone this histogram engine. - /// - /// Copying all bin contents can be an expensive operation, depending on the number of bins. - /// - /// \return the cloned object - RHistEngine Clone() const - { - RHistEngine h(fAxes.Get()); - for (std::size_t i = 0; i < fBinContents.size(); i++) { - h.fBinContents[i] = fBinContents[i]; - } - return h; - } - - /// Convert this histogram engine to a different bin content type. - /// - /// There is no bounds checking to make sure that the converted values can be represented. Note that it is not - /// possible to convert to RBinWithError since the information about individual weights has been lost since filling. - /// - /// Converting all bin contents can be an expensive operation, depending on the number of bins. - /// - /// \return the converted object - template - RHistEngine Convert() const - { - RHistEngine h(fAxes.Get()); - for (std::size_t i = 0; i < fBinContents.size(); i++) { - h.fBinContents[i] = static_cast(fBinContents[i]); - } - return h; - } + /// \} /// Whether this histogram engine type supports weighted filling. static constexpr bool SupportsWeightedFilling = !std::is_integral_v; + // SupportsWeightedFilling is not included because it is static, which would mess up the subgrouping below "Public + // Member Functions". + /// \name Filling + /// \{ + /// Fill an entry into the histogram. /// /// \code @@ -635,6 +580,80 @@ public: } } + /// \} + /// \name Operations + /// \{ + + /// Add all bin contents of another histogram. + /// + /// Throws an exception if the axes configurations are not identical. + /// + /// \param[in] other another histogram + void Add(const RHistEngine &other) + { + if (fAxes != other.fAxes) { + throw std::invalid_argument("axes configurations not identical in Add"); + } + for (std::size_t i = 0; i < fBinContents.size(); i++) { + fBinContents[i] += other.fBinContents[i]; + } + } + + /// Add all bin contents of another histogram using atomic instructions. + /// + /// Throws an exception if the axes configurations are not identical. + /// + /// \param[in] other another histogram that must not be modified during the operation + void AddAtomic(const RHistEngine &other) + { + if (fAxes != other.fAxes) { + throw std::invalid_argument("axes configurations not identical in AddAtomic"); + } + for (std::size_t i = 0; i < fBinContents.size(); i++) { + Internal::AtomicAdd(&fBinContents[i], other.fBinContents[i]); + } + } + + /// Clear all bin contents. + void Clear() + { + for (std::size_t i = 0; i < fBinContents.size(); i++) { + fBinContents[i] = {}; + } + } + + /// Clone this histogram engine. + /// + /// Copying all bin contents can be an expensive operation, depending on the number of bins. + /// + /// \return the cloned object + RHistEngine Clone() const + { + RHistEngine h(fAxes.Get()); + for (std::size_t i = 0; i < fBinContents.size(); i++) { + h.fBinContents[i] = fBinContents[i]; + } + return h; + } + + /// Convert this histogram engine to a different bin content type. + /// + /// There is no bounds checking to make sure that the converted values can be represented. Note that it is not + /// possible to convert to RBinWithError since the information about individual weights has been lost since filling. + /// + /// Converting all bin contents can be an expensive operation, depending on the number of bins. + /// + /// \return the converted object + template + RHistEngine Convert() const + { + RHistEngine h(fAxes.Get()); + for (std::size_t i = 0; i < fBinContents.size(); i++) { + h.fBinContents[i] = static_cast(fBinContents[i]); + } + return h; + } + /// Scale all histogram bin contents. /// /// This method is not available for integral bin content types. @@ -648,6 +667,9 @@ public: } } + /// \} + // End the group to ensure that all contained member functions are public. + private: RHistEngine SliceImpl(const std::vector &sliceSpecs, bool &dropped) const { @@ -701,6 +723,9 @@ private: } public: + /// \name Operations + /// \{ + /// Slice this histogram with an RSliceSpec per dimension. /// /// With a range, only the specified bins are retained. All other bin contents are transferred to the underflow and @@ -786,6 +811,8 @@ public: return Slice(sliceSpecs); } + /// \} + /// %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"); } }; diff --git a/hist/histv7/inc/ROOT/RHistStats.hxx b/hist/histv7/inc/ROOT/RHistStats.hxx index fad20f9054777..6d0d4035b6b30 100644 --- a/hist/histv7/inc/ROOT/RHistStats.hxx +++ b/hist/histv7/inc/ROOT/RHistStats.hxx @@ -144,6 +144,9 @@ public: fDimensionStats.resize(nDimensions); } + /// \name Accessors + /// \{ + std::size_t GetNDimensions() const { return fDimensionStats.size(); } std::uint64_t GetNEntries() const @@ -195,77 +198,9 @@ public: bool IsTainted() const { return fTainted; } - /// Add all entries from another statistics object. - /// - /// Throws an exception if the number of dimensions are not identical. - /// - /// \param[in] other another statistics object - void Add(const RHistStats &other) - { - // NB: this method does *not* call ThrowIfTainted() to allow adding RHist which may contain a tainted statistics - // object. - if (fDimensionStats.size() != other.fDimensionStats.size()) { - throw std::invalid_argument("number of dimensions not identical in Add"); - } - // For exception safety, first check all dimensions before modifying the object. - for (std::size_t i = 0; i < fDimensionStats.size(); i++) { - if (fDimensionStats[i].fEnabled != other.fDimensionStats[i].fEnabled) { - throw std::invalid_argument("the same dimensions must be enabled to combine statistics with Add"); - } - } - - fNEntries += other.fNEntries; - fSumW += other.fSumW; - fSumW2 += other.fSumW2; - for (std::size_t i = 0; i < fDimensionStats.size(); i++) { - if (fDimensionStats[i].fEnabled) { - fDimensionStats[i].Add(other.fDimensionStats[i]); - } - } - fTainted |= other.fTainted; - } - - /// Add all entries from another statistics object using atomic instructions. - /// - /// Throws an exception if the number of dimensions are not identical. - /// - /// \param[in] other another statistics object that must not be modified during the operation - void AddAtomic(const RHistStats &other) - { - // NB: this method does *not* call ThrowIfTainted() to allow adding RHist which may contain a tainted statistics - // object. - if (fDimensionStats.size() != other.fDimensionStats.size()) { - throw std::invalid_argument("number of dimensions not identical in AddAtomic"); - } - // For exception safety, first check all dimensions before modifying the object. - for (std::size_t i = 0; i < fDimensionStats.size(); i++) { - if (fDimensionStats[i].fEnabled != other.fDimensionStats[i].fEnabled) { - throw std::invalid_argument("the same dimensions must be enabled to combine statistics with AddAtomic"); - } - } - - Internal::AtomicAdd(&fNEntries, other.fNEntries); - Internal::AtomicAdd(&fSumW, other.fSumW); - Internal::AtomicAdd(&fSumW2, other.fSumW2); - for (std::size_t i = 0; i < fDimensionStats.size(); i++) { - if (fDimensionStats[i].fEnabled) { - fDimensionStats[i].AddAtomic(other.fDimensionStats[i]); - } - } - fTainted |= other.fTainted; - } - - /// Clear this statistics object. - void Clear() - { - fNEntries = 0; - fSumW = 0; - fSumW2 = 0; - for (std::size_t i = 0; i < fDimensionStats.size(); i++) { - fDimensionStats[i].Clear(); - } - fTainted = false; - } + /// \} + /// \name Computations + /// \{ /// Compute the number of effective entries. /// @@ -416,6 +351,8 @@ public: return (EWX4 - 4 * EWX3 * mean + 6 * EWX2 * mean * mean - 3 * mean * mean * mean * mean) / (var * var) - 3; } + /// \} + private: template void CheckArguments(const std::tuple &args) const @@ -468,6 +405,9 @@ private: } public: + /// \name Filling + /// \{ + /// Fill an entry into this statistics object. /// /// \code @@ -569,6 +509,82 @@ public: } } + /// \} + /// \name Operations + /// \{ + + /// Add all entries from another statistics object. + /// + /// Throws an exception if the number of dimensions are not identical. + /// + /// \param[in] other another statistics object + void Add(const RHistStats &other) + { + // NB: this method does *not* call ThrowIfTainted() to allow adding RHist which may contain a tainted statistics + // object. + if (fDimensionStats.size() != other.fDimensionStats.size()) { + throw std::invalid_argument("number of dimensions not identical in Add"); + } + // For exception safety, first check all dimensions before modifying the object. + for (std::size_t i = 0; i < fDimensionStats.size(); i++) { + if (fDimensionStats[i].fEnabled != other.fDimensionStats[i].fEnabled) { + throw std::invalid_argument("the same dimensions must be enabled to combine statistics with Add"); + } + } + + fNEntries += other.fNEntries; + fSumW += other.fSumW; + fSumW2 += other.fSumW2; + for (std::size_t i = 0; i < fDimensionStats.size(); i++) { + if (fDimensionStats[i].fEnabled) { + fDimensionStats[i].Add(other.fDimensionStats[i]); + } + } + fTainted |= other.fTainted; + } + + /// Add all entries from another statistics object using atomic instructions. + /// + /// Throws an exception if the number of dimensions are not identical. + /// + /// \param[in] other another statistics object that must not be modified during the operation + void AddAtomic(const RHistStats &other) + { + // NB: this method does *not* call ThrowIfTainted() to allow adding RHist which may contain a tainted statistics + // object. + if (fDimensionStats.size() != other.fDimensionStats.size()) { + throw std::invalid_argument("number of dimensions not identical in AddAtomic"); + } + // For exception safety, first check all dimensions before modifying the object. + for (std::size_t i = 0; i < fDimensionStats.size(); i++) { + if (fDimensionStats[i].fEnabled != other.fDimensionStats[i].fEnabled) { + throw std::invalid_argument("the same dimensions must be enabled to combine statistics with AddAtomic"); + } + } + + Internal::AtomicAdd(&fNEntries, other.fNEntries); + Internal::AtomicAdd(&fSumW, other.fSumW); + Internal::AtomicAdd(&fSumW2, other.fSumW2); + for (std::size_t i = 0; i < fDimensionStats.size(); i++) { + if (fDimensionStats[i].fEnabled) { + fDimensionStats[i].AddAtomic(other.fDimensionStats[i]); + } + } + fTainted |= other.fTainted; + } + + /// Clear this statistics object. + void Clear() + { + fNEntries = 0; + fSumW = 0; + fSumW2 = 0; + for (std::size_t i = 0; i < fDimensionStats.size(); i++) { + fDimensionStats[i].Clear(); + } + fTainted = false; + } + /// Scale the histogram statistics. /// /// \param[in] factor the scale factor @@ -585,6 +601,8 @@ public: } } + /// \} + /// %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"); } };