yoda is hosted by Hepforge, IPPP Durham
YODA - Yet more Objects for Data Analysis 2.0.0
BinnedStorage.h
Go to the documentation of this file.
1// -*- C++ -*-
2//
3// This file is part of YODA -- Yet more Objects for Data Analysis
4// Copyright (C) 2008-2023 The YODA collaboration (see AUTHORS for details)
5//
6#ifndef YODA_BinnedStorage_H
7#define YODA_BinnedStorage_H
8
9#include "YODA/BinnedAxis.h"
10#include "YODA/Binning.h"
11#include "YODA/Bin.h"
12
13#include <memory>
14#include <vector>
15
16namespace YODA {
17
20 template <class VecT>
22 public:
24 class myIt;
25
26 using BinType = std::decay_t<decltype(*std::declval<VecT>().begin())>;
27
28 BinsVecWrapper() = delete;
30 BinsVecWrapper(VecT& bins, const std::vector<size_t>& hiddenBins)
31 : _bins(bins), _hiddenBins(hiddenBins) {}
32
34 : _bins(std::move(other._bins)), _hiddenBins(std::move(other._hiddenBins)) {}
35
36 myIt begin() const { return myIt(_bins, _hiddenBins); }
37 myIt end() const { return myIt(_bins); }
38
39 size_t size() const { return _bins.size() - _hiddenBins.size(); }
40
41 const BinType& operator[](size_t index) const { return _bins[index]; }
42
43 BinType& operator[](size_t index) { return _bins[index]; }
44
45 private:
46
47 VecT& _bins;
48 std::vector<size_t> _hiddenBins;
49 };
50
51 template<typename VecT>
52 class BinsVecWrapper<VecT>::myIt {
53 private:
54 using IterT = std::conditional_t<std::is_const<VecT>::value,
55 typename VecT::const_iterator,
56 typename VecT::iterator>;
57 public:
58
59 myIt(VecT& bins,
60 const std::vector<size_t>& hiddenBins)
61 : _ptr(bins.begin()),
62 hiddenCurrPtr(hiddenBins.begin()),
63 hiddenEndPtr(hiddenBins.end()),
64 binsEndPtr(bins.end()) {
65
66 if (hiddenCurrPtr != hiddenEndPtr && 0 == *hiddenCurrPtr){
67
68 ++hiddenCurrPtr;
69 ++(*this);
70
71 }
72 }
73
74 myIt(VecT& bins)
75 : _ptr(bins.end()),
76 //hiddenCurrPtr(std::vector<size_t>::const_iterator()),
77 //hiddenEndPtr(std::vector<size_t>::const_iterator()),
78 binsEndPtr(bins.end()) {}
79
80 myIt operator++() noexcept {
83 ++_ptr;
84 ++currBinIdx;
85
86 while (_ptr != binsEndPtr &&
87 hiddenCurrPtr != hiddenEndPtr &&
88 currBinIdx == *hiddenCurrPtr) {
89
90 ++currBinIdx;
91 ++hiddenCurrPtr;
92 ++_ptr;
93 }
94 return *this;
95 }
96
97 bool operator!=(const myIt& other) const noexcept {
98 return _ptr != other._ptr;
99 }
100
101 typename std::iterator_traits<IterT>::reference operator*() noexcept { return *_ptr; }
102
103 private:
104 IterT _ptr;
105 std::vector<size_t>::const_iterator hiddenCurrPtr;
106 std::vector<size_t>::const_iterator hiddenEndPtr;
107 IterT binsEndPtr;
108 size_t currBinIdx = 0;
109 };
110
111
113 template <typename BinContentT, typename... AxisT>
115 protected:
116
118 using BinningT = Binning<std::decay_t<decltype(std::declval<Axis<AxisT>>())>...>;
119 using BinT = Bin<sizeof...(AxisT), BinContentT, BinningT>;
120 using BinsVecT = std::vector<BinT>;
121 using BaseT = BinnedStorage<BinContentT, AxisT...>;
122
123 public:
124
126 using BinType = BinT;
127 using BinDimension = std::integral_constant<size_t, sizeof...(AxisT)>;
128
129
131 // @{
132
134 BinnedStorage() : _binning(std::vector<AxisT>{}...) {
135 fillBins();
136 }
137
139 BinnedStorage(const BinningT& binning) : _binning(binning) {
140 fillBins();
141 }
142
144 BinnedStorage(BinningT&& binning) : _binning(std::move(binning)) {
145 fillBins();
146 }
147
149 BinnedStorage(const std::vector<AxisT>&... edges) : _binning(edges...) {
150 fillBins();
151 }
152
154 BinnedStorage(std::vector<AxisT>&&... edges) : _binning(std::move(edges)...) {
155 fillBins();
156 }
157
159 BinnedStorage(std::initializer_list<AxisT>&&... edges) : _binning(std::vector<AxisT>{edges}...) {
160 fillBins();
161 }
162
164 BinnedStorage(const Axis<AxisT>&... axes) : _binning(axes...) {
165 fillBins();
166 }
167
169 BinnedStorage(Axis<AxisT>&&... axes) : _binning(std::move(axes)...) {
170 fillBins();
171 }
172
174 BinnedStorage(const BinnedStorage& other) : _binning(other._binning) {
175 fillBins(other._bins);
176 }
177
179 BinnedStorage(BinnedStorage&& other) : _binning(std::move(other._binning)) {
180 fillBins(std::move(other._bins));
181 }
182
183 // @}
184
186 // @{
187
189 size_t dim() const noexcept {
190 return sizeof...(AxisT) + 1;
191 }
192
200 BinT& bin(size_t idx) noexcept {
201 return _bins.at(idx);
202 }
203
205 const BinT& bin(size_t idx) const noexcept {
206 return _bins.at(idx);
207 }
208
210 BinT& bin(const std::array<size_t, sizeof...(AxisT)>& idxLocal) noexcept {
211 return bin( _binning.localToGlobalIndex(idxLocal) );
212 }
213
215 const BinT& bin(const std::array<size_t, sizeof...(AxisT)>& idxLocal) const noexcept {
216 return bin( _binning.localToGlobalIndex(idxLocal) );
217 }
218
220 BinT& binAt(typename BinningT::EdgeTypesTuple&& coords) noexcept {
221 const size_t binIdx = _binning.globalIndexAt(coords);
222 return bin(binIdx);
223 }
224
226 const BinT& binAt(typename BinningT::EdgeTypesTuple&& coords) const noexcept {
227 const size_t binIdx = _binning.globalIndexAt(coords);
228 return bin(binIdx);
229 }
230
234 void set(typename BinningT::EdgeTypesTuple&& coords, BinContentT&& content) noexcept {
235 const size_t binIdx = _binning.globalIndexAt(coords);
236 _bins[binIdx] = std::move(content);
237 }
238
240 void set(typename BinningT::EdgeTypesTuple&& coords, const BinContentT& content) noexcept {
241 const size_t binIdx = _binning.globalIndexAt(coords);
242 _bins[binIdx] = content;
243 }
244
248 void set(const size_t binIdx, BinContentT&& content) noexcept {
249 _bins[binIdx] = std::move(content);
250 }
251
253 void set(const size_t binIdx, const BinContentT& content) noexcept {
254 _bins[binIdx] = content;
255 }
256
259 std::vector<size_t> calcIndicesToSkip(const bool includeOverflows, const bool includeMaskedBins) const noexcept {
260
261 // if there are no bins, exit early
262 if (!_binning.numBins(!includeOverflows, !includeMaskedBins)) return {};
263
264 std::vector<size_t> indicesToSkip;
265
266 // define a lambda
267 auto appendIndicesVec = [&indicesToSkip](std::vector<size_t>&& indicesVec) {
268 indicesToSkip.insert(std::end(indicesToSkip),
269 std::make_move_iterator(std::begin(indicesVec)),
270 std::make_move_iterator(std::end(indicesVec)));
271 };
272
273 // only calculate the masked indices when
274 // the masked bins are to be skipped over
275 if(!includeOverflows) {
276 appendIndicesVec(_binning.calcOverflowBinsIndices());
277 }
278
279 if (!includeMaskedBins) {
280 appendIndicesVec(_binning.maskedBins());
281 }
282
283 // sort and remove duplicates
284 std::sort(indicesToSkip.begin(), indicesToSkip.end());
285 indicesToSkip.erase( std::unique(indicesToSkip.begin(), indicesToSkip.end()),
286 indicesToSkip.end() );
287
288 return indicesToSkip;
289 }
290
291
298 BinsVecWrapper<BinsVecT> bins(const bool includeOverflows = false,
299 const bool includeMaskedBins = false) noexcept {
300 return BinsVecWrapper<BinsVecT>(_bins,
301 calcIndicesToSkip(includeOverflows, includeMaskedBins));
302 }
303
309 const BinsVecWrapper<const BinsVecT> bins(const bool includeOverflows = false,
310 const bool includeMaskedBins = false) const noexcept {
312 calcIndicesToSkip(includeOverflows, includeMaskedBins));
313 }
314
315 // @}
316
318 // @{
319
321 const BinningT& binning() const noexcept {
322 return _binning;
323 }
324
326 size_t binDim() const noexcept {
327 return _binning.dim();
328 }
329
331 size_t numBins(const bool includeOverflows = false, const bool includeMaskedBins = false) const noexcept {
332 return _binning.numBins(includeOverflows, includeMaskedBins);
333 }
334
339 size_t numBinsAt(const size_t axisN, const bool includeOverflows = false) const noexcept {
340 size_t nOverflows = includeOverflows? 0 : _binning.countOverflowBins(axisN);
341 return _binning.numBinsAt(axisN) - nOverflows;
342 }
343
345 void reset() noexcept { clearBins(); }
346
350 void clearBins() noexcept {
351 _bins.clear();
352 fillBins();
353 }
354
356 void maskBins(const std::vector<size_t>& indicesToMask, const bool status = true) noexcept {
357 _binning.maskBins(indicesToMask, status);
358 }
359
361 void maskBin(const size_t indexToMask, const bool status = true) noexcept {
362 _binning.maskBin(indexToMask, status);
363 }
364
366 void maskSlice(const size_t dim, const size_t idx, const bool status = true) {
367 _binning.maskSlice(dim, idx, status);
368 }
369
371 void maskBinAt(typename BinningT::EdgeTypesTuple&& coords, const bool status = true) noexcept {
372 _binning.maskBinAt(coords, status);
373 }
374
375 bool isMasked(const size_t binIndex) const noexcept {
376 return _binning.isMasked(binIndex);
377 }
378
379 std::vector<size_t> maskedBins() const noexcept {
380 return _binning.maskedBins();
381 }
382
383 bool isVisible(const size_t binIndex) const noexcept {
384 return _binning.isVisible(binIndex);
385 }
386
398 template <size_t... AxisNs, class RetT = void>
400 std::decay_t<decltype(AxisNs, std::declval<std::pair<size_t, size_t>>())>... mergeRanges)
401 noexcept -> std::enable_if_t<MetaUtils::is_detected_v<MetaUtils::operatorTraits::addition_assignment_t, BinContentT>, RetT>
402 {
403 auto mergeStorageBins =
404 [&binning = BaseT::_binning, &binStorage = BaseT::_bins](auto I, const auto& mergeRangePair){
405 assert(mergeRangePair.first < mergeRangePair.second);
406 const auto& pivotBinsIndices = binning.sliceIndices(I, mergeRangePair.first);
407
408 auto append = [&binStorage, &pivotBinsIndices](const auto& binsIndicesToMerge){
409 assert(pivotBinsIndices.size() == binsIndicesToMerge.size());
410 //for (const auto& k : binsIndicesToMerge) std::cout << k << std::endl;
411 //for (const auto& k : pivotBinsIndices) std::cout << k << std::endl;
412
413 // first merge the bins based on old set of indices
414 // unless the bins are masked
415 for (size_t i = 0; i < pivotBinsIndices.size(); i++) {
416 auto& pivotBin = binStorage[pivotBinsIndices[i]];
417 auto& binToAppend = binStorage[binsIndicesToMerge[i]];
418 pivotBin += binToAppend;
419 }
420 // then erase the bins (which will change the set of indices)
421 binStorage.erase(
422 std::remove_if(binStorage.begin(), binStorage.end(), [&](const auto& b) {
423 return std::find(binsIndicesToMerge.begin(), binsIndicesToMerge.end(), b.index()) != binsIndicesToMerge.end();
424 }), binStorage.end());
425 };
426
427 ssize_t nBinRowsToBeMerged = mergeRangePair.second - mergeRangePair.first;
428
429 size_t currBinRowIdx = mergeRangePair.first;
430 size_t nextBinRowIdx = mergeRangePair.first + 1;
431 //std::cout << nBinRowsToBeMerged << " " << currBinRowIdx << " " << nextBinRowIdx << std::endl;
432
433 while(nBinRowsToBeMerged--) {
436 append(binning.sliceIndices(I, nextBinRowIdx));
437 binning.template mergeBins<I>({currBinRowIdx, nextBinRowIdx});
438 }
439 };
440
441 ((void)mergeStorageBins(std::integral_constant<std::size_t, AxisNs>(), mergeRanges), ...);
442
443 }
444
445
450 template<size_t axisN, template<typename...> typename BinnedT, typename Func,
451 typename = std::enable_if_t< (axisN < sizeof...(AxisT) && sizeof...(AxisT)>=2) >>
452 auto mkBinnedSlices(Func&& how2add, const bool includeOverflows=false) const {
453
454 size_t vecN = BaseT::numBinsAt(axisN, includeOverflows);
455 auto binnedSlice = _mkBinnedT<BinnedT>(_binning.template _getAxesExcept<axisN>());
456 std::vector<decltype(binnedSlice)> rtn(vecN, binnedSlice);
457 for (size_t i = 0; i < vecN; ++i) {
458
459 auto mkSlice = [&oldBins = _bins, &how2add, &binnedSlice = rtn[i]](const auto& indicesToCopy) {
460 assert(binnedSlice.numBins(true) == indicesToCopy.size());
461
462 // for any given pivot, add the content
463 // from the old slice to the new slice
464 for (size_t i = 0; i < binnedSlice.numBins(true); ++i) {
465 auto& pivotBin = binnedSlice.bin(i);
466 auto& binToCopy = oldBins[indicesToCopy[i]];
467 how2add(pivotBin, binToCopy);
468 }
469 };
470
471 // get bin slice for any given bin i along the axis that is to be
472 // sliced, then make the estimates for the new binning
473 mkSlice(_binning.sliceIndices(axisN, i + !includeOverflows));
474
475 }
476 return rtn;
477 }
478
479
481 BinnedStorage& operator = (const BinnedStorage& other) noexcept {
482 if (this != &other) {
483 _binning = other._binning;
484 fillBins(other._bins);
485 }
486 return *this;
487 }
488
491 if (this != &other) {
492 _binning = std::move(other._binning);
493 fillBins(std::move(other._bins));
494 }
495 return *this;
496 }
497
502 bool operator == (const BinnedStorage& other) const noexcept {
503 return _binning.isCompatible(other._binning);
504 }
505
509 bool operator != (const BinnedStorage& other) const noexcept {
510 return ! operator == (other);
511 }
512
514 std::vector<size_t> _global2local(size_t idx) const noexcept {
515 const auto& indices = _binning.globalToLocalIndices(idx);
516 return std::vector<size_t>(indices.begin(), indices.end());
517 }
518
520 size_t _local2global(const std::vector<size_t>& indices) const {
521 assert(indices.size() == sizeof...(AxisT));
522 std::array<size_t, sizeof...(AxisT)> arr;
523 std::copy_n(std::make_move_iterator(indices.begin()), sizeof...(AxisT), arr.begin());
524 return _binning.localToGlobalIndex(arr);
525 }
526
528
529
530 protected:
531
533 // @{
534
536 void fillBins() noexcept {
537 _bins.reserve(_binning.numBins());
538
539 for (size_t i = 0; i < _binning.numBins(); ++i) {
540 _bins.emplace_back(i, _binning);
541 }
542 }
543
544 void fillBins(const BinsVecT& bins) noexcept {
545 _bins.clear();
546 _bins.reserve(_binning.numBins());
547 for (const auto& b : bins) {
548 _bins.emplace_back(b, _binning);
549 }
550 }
551
552 void fillBins(BinsVecT&& bins) noexcept {
553 _bins.clear();
554 _bins.reserve(_binning.numBins());
555 for (auto&& b : bins) {
556 _bins.emplace_back(std::move(b), _binning);
557 }
558 }
559
561 template<template<typename...> typename BinnedT, class... newAxes, size_t... As>
562 auto _mkBinnedT_aux(const std::tuple<newAxes...>& t, std::index_sequence<As...>) const {
563 return BinnedT<typename newAxes::EdgeT...>(std::get<As>(t)...);
564 }
565
567 template <template<typename...> typename BinnedT, class... newAxes>
568 auto _mkBinnedT(const std::tuple<newAxes...>& t) const {
569 return _mkBinnedT_aux<BinnedT>(t, std::make_index_sequence<sizeof...(newAxes)>{});
570 }
571
572 // @}
573
576 BinsVecT _bins;
577
578 BinningT _binning;
579
580 };
581
582} // namespace YODA
583
584#endif
Discrete axis with edges of non-floating-point-type.
Definition BinnedAxis.h:91
generic Bin version that derives from BinBase
Definition Bin.h:265
BinnedStorage, stores the bins and coordinates access to them.
void maskBin(const size_t indexToMask, const bool status=true) noexcept
Mask a bin at a given index.
BinT & bin(size_t idx) noexcept
Returns reference to the bin at idx.
std::vector< BinT > BinsVecT
BinnedStorage(std::initializer_list< AxisT > &&... edges)
Constructs binning from an adapter and Rvalue initializer lists of axes' edges.
void maskBinAt(typename BinningT::EdgeTypesTuple &&coords, const bool status=true) noexcept
Mask a bin at a given set of corrdinates.
void maskBins(const std::vector< size_t > &indicesToMask, const bool status=true) noexcept
Mask a range of bins.
size_t numBinsAt(const size_t axisN, const bool includeOverflows=false) const noexcept
Number of bins in the BinnedStorage.
const BinsVecWrapper< const BinsVecT > bins(const bool includeOverflows=false, const bool includeMaskedBins=false) const noexcept
Const version.
auto mkBinnedSlices(Func &&how2add, const bool includeOverflows=false) const
Split this BinnedStorage into a vector of BinnedStorages along axisN.
void set(const size_t binIdx, const BinContentT &content) noexcept
Sets the bin corresponding to binIndex with content.
size_t numBins(const bool includeOverflows=false, const bool includeMaskedBins=false) const noexcept
Number of bins in the BinnedStorage.
Binning< std::decay_t< decltype(std::declval< Axis< AxisT > >())>... > BinningT
Convenience alias to be used in constructor.
void set(typename BinningT::EdgeTypesTuple &&coords, const BinContentT &content) noexcept
Sets the bin corresponding to coords with content.
BinnedStorage(const BinningT &binning)
Constructs BinnedStorage from Binning.
bool operator==(const BinnedStorage &other) const noexcept
Compares BinnedStorages for equality, e.g. dimensions of underlying binnings and all axes edges are e...
void set(typename BinningT::EdgeTypesTuple &&coords, BinContentT &&content) noexcept
Sets the bin corresponding to coords with an rvalue content.
BinnedStorage(const Axis< AxisT > &... axes)
Constructs binning from an adapter and a sequence of axes.
BinnedStorage(std::vector< AxisT > &&... edges)
Constructs binning from an adapter and Rvalue vectors of axes' edges.
const BinT & bin(const std::array< size_t, sizeof...(AxisT)> &idxLocal) const noexcept
Bin access using local bin indices.
void fillBins() noexcept
Fills bins with wrapped BinContent objects.
BinnedStorage(const std::vector< AxisT > &... edges)
Constructs binning from an adapter and vectors of axes' edges.
BinnedStorage & operator=(const BinnedStorage &other) noexcept
Copy assignment.
size_t binDim() const noexcept
Returns dimension of binning.
bool isMasked(const size_t binIndex) const noexcept
BinnedStorage(BinningT &&binning)
Constructs BinnedStorage from Binning. Rvalue.
const BinT & binAt(typename BinningT::EdgeTypesTuple &&coords) const noexcept
Returns reference to the bin at coordinates (const version).
void maskSlice(const size_t dim, const size_t idx, const bool status=true)
Mask a slice of the binning at local bin index idx along axis dimesnion dim.
Bin< sizeof...(AxisT), BinContentT, BinningT > BinT
BinnedStorage(const BinnedStorage &other)
Copy constructor.
BinnedStorage(Axis< AxisT > &&... axes)
Constructs binning from an adapter and a sequence of Rvalue axes.
void clearBins() noexcept
Deletes all bins and creates empty new ones.
BinsVecWrapper< BinsVecT > bins(const bool includeOverflows=false, const bool includeMaskedBins=false) noexcept
Returns bins vector wrapper, which skips masked elements when iterated over.
const BinT & bin(size_t idx) const noexcept
Returns Bin at idx.
void reset() noexcept
Reset the BinnedStorage.
auto mergeBins(std::decay_t< decltype(AxisNs, std::declval< std::pair< size_t, size_t > >())>... mergeRanges) noexcept -> std::enable_if_t< MetaUtils::is_detected_v< MetaUtils::operatorTraits::addition_assignment_t, BinContentT >, RetT >
Merge bins from A to B at G axis.
void fillBins(const BinsVecT &bins) noexcept
size_t dim() const noexcept
Total dimension of the object ( = number of axes + content)
BinnedStorage()
Nullary constructor for unique pointers etc.
BinnedStorage(BinnedStorage &&other)
Move constructor.
BinT & bin(const std::array< size_t, sizeof...(AxisT)> &idxLocal) noexcept
Bin access using local bin indices.
const BinningT & binning() const noexcept
Returns dimension underlying binning object reference.
std::vector< size_t > maskedBins() const noexcept
BinT & binAt(typename BinningT::EdgeTypesTuple &&coords) noexcept
Returns reference to the bin at coordinates.
bool isVisible(const size_t binIndex) const noexcept
void fillBins(BinsVecT &&bins) noexcept
std::vector< size_t > calcIndicesToSkip(const bool includeOverflows, const bool includeMaskedBins) const noexcept
Calculates indices of bins which are marked or located in the overflow.
void set(const size_t binIdx, BinContentT &&content) noexcept
Sets the bin corresponding to binIndex with an rvalue content.
bool operator!=(const BinnedStorage &other) const noexcept
Compares BinnedStorages for inequality.
std::integral_constant< size_t, sizeof...(AxisT)> BinDimension
decltype(std::tuple_cat(std::declval< std::tuple< typename Axes::EdgeT > >()...)) EdgeTypesTuple
Definition Binning.h:85
std::vector< size_t > sliceIndices(std::vector< std::pair< size_t, std::vector< size_t > > >) const noexcept
Calculates indices of bins located in the specified slices.
Definition Binning.h:574
myIt(VecT &bins, const std::vector< size_t > &hiddenBins)
std::iterator_traits< IterT >::reference operator*() noexcept
bool operator!=(const myIt &other) const noexcept
Vector wrapper used to interact with bins vectors. Able to hide overflow and hidden bins.
size_t size() const
BinsVecWrapper(BinsVecWrapper &&other)
std::decay_t< decltype(*std::declval< VecT >().begin())> BinType
BinType & operator[](size_t index)
BinsVecWrapper(VecT &bins, const std::vector< size_t > &hiddenBins)
HiddenBins std::vector<size_t> must be sorted.
const BinType & operator[](size_t index) const
Anonymous namespace to limit visibility.