-
Notifications
You must be signed in to change notification settings - Fork 1.5k
[hist] Implement RSliceSpec and Internal::RSliceBinIndexMapper
#21323
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
f6add28
[hist] Implement RBinIndexRange::IsInvalid
hahnjo d7da593
[hist] Implement RSliceSpec
hahnjo 75c2505
[hist] Implement outline of RSliceBinIndexMapper
hahnjo 75e694a
[hist] Implement mapping for slice with range
hahnjo e9baf53
[hist] Implement mapping for rebin operation
hahnjo 320e65a
[hist] Implement mapping for sum operation
hahnjo d23f2e4
[hist] Implement mapping for slice + sum
hahnjo File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,131 @@ | ||
| /// \file | ||
| /// \warning This is part of the %ROOT 7 prototype! It will change without notice. It might trigger earthquakes. | ||
| /// Feedback is welcome! | ||
|
|
||
| #ifndef ROOT_RSliceBinIndexMapper | ||
| #define ROOT_RSliceBinIndexMapper | ||
|
|
||
| #include "RBinIndex.hxx" | ||
| #include "RBinIndexRange.hxx" | ||
| #include "RSliceSpec.hxx" | ||
|
|
||
| #include <cstdint> | ||
| #include <stdexcept> | ||
| #include <utility> | ||
| #include <vector> | ||
|
|
||
| namespace ROOT { | ||
| namespace Experimental { | ||
| namespace Internal { | ||
|
|
||
| /** | ||
| Mapper of bin indices for slice operations. | ||
| */ | ||
| class RSliceBinIndexMapper final { | ||
| /// The requested slice specifications | ||
| std::vector<RSliceSpec> fSliceSpecs; | ||
| /// The expected dimensionality of the mapped indices | ||
| std::size_t fMappedDimensionality; | ||
|
|
||
| static std::size_t ComputeMappedDimensionality(const std::vector<RSliceSpec> &sliceSpecs) | ||
| { | ||
| std::size_t dimensionality = 0; | ||
| for (auto &&spec : sliceSpecs) { | ||
| // A sum operation makes the dimension disappear. | ||
| if (spec.GetOperationSum() == nullptr) { | ||
| dimensionality++; | ||
| } | ||
| } | ||
| return dimensionality; | ||
| } | ||
|
|
||
| public: | ||
| /// \param[in] sliceSpecs the slice specifications, must have size > 0 | ||
| explicit RSliceBinIndexMapper(std::vector<RSliceSpec> sliceSpecs) | ||
| : fSliceSpecs(std::move(sliceSpecs)), fMappedDimensionality(ComputeMappedDimensionality(fSliceSpecs)) | ||
| { | ||
| if (fSliceSpecs.empty()) { | ||
| throw std::invalid_argument("must have at least 1 slice specification"); | ||
| } | ||
| } | ||
|
|
||
| const std::vector<RSliceSpec> &GetSliceSpecs() const { return fSliceSpecs; } | ||
| std::size_t GetMappedDimensionality() const { return fMappedDimensionality; } | ||
|
|
||
| /// Map a vector of RBinIndex according to the slice specifications. | ||
| /// | ||
| /// \param[in] original the original bin indices | ||
| /// \param[out] mapped the mapped bin indices | ||
| /// \return whether the mapping was successful or the bin content should be discarded | ||
| bool Map(const std::vector<RBinIndex> &original, std::vector<RBinIndex> &mapped) const | ||
| { | ||
| if (original.size() != fSliceSpecs.size()) { | ||
| throw std::invalid_argument("invalid number of original indices passed to RSliceBinIndexMapper::Map"); | ||
| } | ||
| if (mapped.size() != fMappedDimensionality) { | ||
| throw std::invalid_argument("invalid size of mapped indices passed to RSliceBinIndexMapper::Map"); | ||
| } | ||
|
|
||
| std::size_t mappedPos = 0; | ||
| for (std::size_t i = 0; i < original.size(); i++) { | ||
| RBinIndex index = original[i]; | ||
| if (index.IsInvalid()) { | ||
| throw std::invalid_argument("invalid bin index passed to RSliceBinIndexMapper::Map"); | ||
| } | ||
|
|
||
| const RSliceSpec &sliceSpec = fSliceSpecs[i]; | ||
| const auto &range = sliceSpec.GetRange(); | ||
| bool contained = true; | ||
| if (!range.IsInvalid()) { | ||
| // Underflow and overflow indices map to themselves, but they may not actually be contained in the range. | ||
| // This is important for the sum operation below. | ||
| if (index.IsUnderflow()) { | ||
| contained = range.GetBegin().IsUnderflow(); | ||
| } else if (index.IsOverflow()) { | ||
| contained = range.GetEnd().IsInvalid(); | ||
| } else if (index.IsNormal()) { | ||
| const auto &begin = range.GetBegin(); | ||
| const auto &end = range.GetEnd(); | ||
| if (begin.IsNormal() && index < begin) { | ||
| index = RBinIndex::Underflow(); | ||
| contained = false; | ||
| } else if (end.IsNormal() && index >= end) { | ||
| index = RBinIndex::Overflow(); | ||
| contained = false; | ||
| } else if (begin.IsNormal()) { | ||
| // This normal bin is contained in the range. Its index must be shifted according to the begin of the | ||
| // range. | ||
| index -= begin.GetIndex(); | ||
| assert(!index.IsInvalid()); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| if (auto *opRebin = sliceSpec.GetOperationRebin()) { | ||
| if (index.IsNormal()) { | ||
| index = RBinIndex(index.GetIndex() / opRebin->GetNGroup()); | ||
| } | ||
| } else if (sliceSpec.GetOperationSum() != nullptr) { | ||
|
hageboeck marked this conversation as resolved.
|
||
| // This dimension disappears. If there is a range and the index is not contained, discard it. | ||
| if (!contained) { | ||
| return false; | ||
| } | ||
| // Otherwise got to the next dimension. | ||
| continue; | ||
| } | ||
|
|
||
| mapped[mappedPos] = index; | ||
| mappedPos++; | ||
| } | ||
|
|
||
| // If we got here, the loop should have filled all mapped indices. | ||
| assert(mappedPos == mapped.size()); | ||
| return true; | ||
|
hageboeck marked this conversation as resolved.
|
||
| } | ||
| }; | ||
|
|
||
| } // namespace Internal | ||
| } // namespace Experimental | ||
| } // namespace ROOT | ||
|
|
||
| #endif | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,99 @@ | ||
| /// \file | ||
| /// \warning This is part of the %ROOT 7 prototype! It will change without notice. It might trigger earthquakes. | ||
| /// Feedback is welcome! | ||
|
|
||
| #ifndef ROOT_RSliceSpec | ||
| #define ROOT_RSliceSpec | ||
|
|
||
| #include "RBinIndexRange.hxx" | ||
|
|
||
| #include <cstdint> | ||
| #include <stdexcept> | ||
| #include <utility> | ||
| #include <variant> | ||
|
|
||
| namespace ROOT { | ||
| namespace Experimental { | ||
|
|
||
| /** | ||
| Specification of a slice operation along one dimension. | ||
|
|
||
| \code | ||
|
hahnjo marked this conversation as resolved.
|
||
| using ROOT::Experimental::RSliceSpec; | ||
| // When not specifying a range, the slice will include all bins. | ||
| RSliceSpec full; | ||
| // In the following, assuming range is an RBinIndexRange. | ||
| RSliceSpec slice(range); | ||
|
|
||
| // Operations are specified with parameters. | ||
| RSliceSpec rebin(RSliceSpec::ROperationRebin(2)); | ||
| RSliceSpec sum(RSliceSpec::ROperationSum{}); | ||
|
|
||
| // Finally, it is possible to combine a range and an operation. | ||
| RSliceSpec sliceRebin(range, RSliceSpec::ROperationRebin(2)); | ||
| RSliceSpec sliceSum(range, RSliceSpec::ROperationSum{}); | ||
| \endcode | ||
|
|
||
| \warning This is part of the %ROOT 7 prototype! It will change without notice. It might trigger earthquakes. | ||
| Feedback is welcome! | ||
| */ | ||
| class RSliceSpec final { | ||
|
hahnjo marked this conversation as resolved.
|
||
| public: | ||
| /// Rebin the dimension, grouping a number of original bins into a new one. | ||
| class ROperationRebin final { | ||
| std::uint64_t fNGroup = 1; | ||
|
|
||
| public: | ||
| /// \param[in] nGroup the number of bins to group, must be > 0 | ||
| ROperationRebin(std::uint64_t nGroup) : fNGroup(nGroup) | ||
| { | ||
| if (nGroup == 0) { | ||
| throw std::invalid_argument("nGroup must be > 0"); | ||
| } | ||
| } | ||
|
|
||
| std::uint64_t GetNGroup() const { return fNGroup; } | ||
| }; | ||
|
|
||
| /// Sum bins along this dimension, effectively resulting in a projection. | ||
| class ROperationSum final { | ||
| // empty, no parameters at the moment | ||
| }; | ||
|
|
||
| private: | ||
| /// The range of the slice; can be invalid to signify the full range | ||
| RBinIndexRange fRange; | ||
| /// The operation to perform, if any | ||
| std::variant<std::monostate, ROperationRebin, ROperationSum> fOperation; | ||
|
|
||
| public: | ||
| /// A default slice operation that keeps the dimension untouched. | ||
| RSliceSpec() = default; | ||
|
|
||
| /// A slice of a dimension. | ||
| /// | ||
| /// \param[in] range the range of the slice | ||
| RSliceSpec(RBinIndexRange range) : fRange(std::move(range)) {} | ||
|
|
||
| /// A rebin operation of a dimension. | ||
| RSliceSpec(ROperationRebin rebin) : fOperation(std::move(rebin)) {} | ||
|
|
||
| /// A sum operation of a dimension. | ||
| RSliceSpec(ROperationSum sum) : fOperation(std::move(sum)) {} | ||
|
|
||
| /// A rebin operation of a slice of the dimension. | ||
| RSliceSpec(RBinIndexRange range, ROperationRebin rebin) : fRange(std::move(range)), fOperation(std::move(rebin)) {} | ||
|
|
||
| /// A sum operation of a slice of the dimension. | ||
| RSliceSpec(RBinIndexRange range, ROperationSum sum) : fRange(std::move(range)), fOperation(std::move(sum)) {} | ||
|
|
||
| const RBinIndexRange &GetRange() const { return fRange; } | ||
| bool HasOperation() const { return !std::holds_alternative<std::monostate>(fOperation); } | ||
| const ROperationRebin *GetOperationRebin() const { return std::get_if<ROperationRebin>(&fOperation); } | ||
| const ROperationSum *GetOperationSum() const { return std::get_if<ROperationSum>(&fOperation); } | ||
| }; | ||
|
|
||
| } // namespace Experimental | ||
| } // namespace ROOT | ||
|
|
||
| #endif | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.