File indexing completed on 2025-04-19 09:13:39
0001
0002
0003
0004
0005
0006 #ifndef YODA_BinnedStorage_H
0007 #define YODA_BinnedStorage_H
0008
0009 #include "YODA/BinnedAxis.h"
0010 #include "YODA/Binning.h"
0011 #include "YODA/Bin.h"
0012
0013 #include <memory>
0014 #include <vector>
0015
0016 namespace YODA {
0017
0018
0019
0020 template <class VecT>
0021 class BinsVecWrapper {
0022 public:
0023
0024 class myIt;
0025
0026 using BinType = std::decay_t<decltype(*std::declval<VecT>().begin())>;
0027
0028 BinsVecWrapper() = delete;
0029
0030 BinsVecWrapper(VecT& bins, const std::vector<size_t>& hiddenBins)
0031 : _bins(bins), _hiddenBins(hiddenBins) {}
0032
0033 BinsVecWrapper(BinsVecWrapper&& other)
0034 : _bins(std::move(other._bins)), _hiddenBins(std::move(other._hiddenBins)) {}
0035
0036 myIt begin() const { return myIt(_bins, _hiddenBins); }
0037 myIt end() const { return myIt(_bins); }
0038
0039 size_t size() const { return _bins.size() - _hiddenBins.size(); }
0040
0041 const BinType& operator[](size_t index) const { return _bins[index]; }
0042
0043 BinType& operator[](size_t index) { return _bins[index]; }
0044
0045 private:
0046
0047 VecT& _bins;
0048 std::vector<size_t> _hiddenBins;
0049 };
0050
0051 template<typename VecT>
0052 class BinsVecWrapper<VecT>::myIt {
0053 private:
0054 using IterT = std::conditional_t<std::is_const<VecT>::value,
0055 typename VecT::const_iterator,
0056 typename VecT::iterator>;
0057 public:
0058
0059 myIt(VecT& bins,
0060 const std::vector<size_t>& hiddenBins)
0061 : _ptr(bins.begin()),
0062 hiddenCurrPtr(hiddenBins.begin()),
0063 hiddenEndPtr(hiddenBins.end()),
0064 binsEndPtr(bins.end()) {
0065
0066 if (hiddenCurrPtr != hiddenEndPtr && 0 == *hiddenCurrPtr){
0067
0068 ++hiddenCurrPtr;
0069 ++(*this);
0070
0071 }
0072 }
0073
0074 myIt(VecT& bins)
0075 : _ptr(bins.end()),
0076
0077
0078 binsEndPtr(bins.end()) {}
0079
0080 myIt operator++() noexcept {
0081
0082
0083 ++_ptr;
0084 ++currBinIdx;
0085
0086 while (_ptr != binsEndPtr &&
0087 hiddenCurrPtr != hiddenEndPtr &&
0088 currBinIdx == *hiddenCurrPtr) {
0089
0090 ++currBinIdx;
0091 ++hiddenCurrPtr;
0092 ++_ptr;
0093 }
0094 return *this;
0095 }
0096
0097 bool operator!=(const myIt& other) const noexcept {
0098 return _ptr != other._ptr;
0099 }
0100
0101 typename std::iterator_traits<IterT>::reference operator*() noexcept { return *_ptr; }
0102
0103 private:
0104 IterT _ptr;
0105 std::vector<size_t>::const_iterator hiddenCurrPtr;
0106 std::vector<size_t>::const_iterator hiddenEndPtr;
0107 IterT binsEndPtr;
0108 size_t currBinIdx = 0;
0109 };
0110
0111
0112
0113 template <typename BinContentT, typename... AxisT>
0114 class BinnedStorage {
0115 protected:
0116
0117
0118 using BinningT = Binning<std::decay_t<decltype(std::declval<Axis<AxisT>>())>...>;
0119 using BinT = Bin<sizeof...(AxisT), BinContentT, BinningT>;
0120 using BinsVecT = std::vector<BinT>;
0121 using BaseT = BinnedStorage<BinContentT, AxisT...>;
0122
0123 public:
0124
0125 using BinningType = BinningT;
0126 using BinType = BinT;
0127 using BinDimension = std::integral_constant<size_t, sizeof...(AxisT)>;
0128
0129
0130
0131
0132
0133
0134 BinnedStorage() : _binning(std::vector<AxisT>{}...) {
0135 fillBins();
0136 }
0137
0138
0139 BinnedStorage(const BinningT& binning) : _binning(binning) {
0140 fillBins();
0141 }
0142
0143
0144 BinnedStorage(BinningT&& binning) : _binning(std::move(binning)) {
0145 fillBins();
0146 }
0147
0148
0149 BinnedStorage(const std::vector<AxisT>&... edges) : _binning(edges...) {
0150 fillBins();
0151 }
0152
0153
0154 BinnedStorage(std::vector<AxisT>&&... edges) : _binning(std::move(edges)...) {
0155 fillBins();
0156 }
0157
0158
0159 BinnedStorage(std::initializer_list<AxisT>&&... edges) : _binning(std::vector<AxisT>{edges}...) {
0160 fillBins();
0161 }
0162
0163
0164 BinnedStorage(const Axis<AxisT>&... axes) : _binning(axes...) {
0165 fillBins();
0166 }
0167
0168
0169 BinnedStorage(Axis<AxisT>&&... axes) : _binning(std::move(axes)...) {
0170 fillBins();
0171 }
0172
0173
0174 BinnedStorage(const BinnedStorage& other) : _binning(other._binning) {
0175 fillBins(other._bins);
0176 }
0177
0178
0179 BinnedStorage(BinnedStorage&& other) : _binning(std::move(other._binning)) {
0180 fillBins(std::move(other._bins));
0181 }
0182
0183
0184
0185
0186
0187
0188
0189 size_t dim() const noexcept {
0190 return sizeof...(AxisT) + 1;
0191 }
0192
0193
0194
0195
0196
0197
0198
0199
0200 BinT& bin(size_t idx) noexcept {
0201 return _bins.at(idx);
0202 }
0203
0204
0205 const BinT& bin(size_t idx) const noexcept {
0206 return _bins.at(idx);
0207 }
0208
0209
0210 BinT& bin(const std::array<size_t, sizeof...(AxisT)>& idxLocal) noexcept {
0211 return bin( _binning.localToGlobalIndex(idxLocal) );
0212 }
0213
0214
0215 const BinT& bin(const std::array<size_t, sizeof...(AxisT)>& idxLocal) const noexcept {
0216 return bin( _binning.localToGlobalIndex(idxLocal) );
0217 }
0218
0219
0220 BinT& binAt(typename BinningT::EdgeTypesTuple&& coords) noexcept {
0221 const size_t binIdx = _binning.globalIndexAt(coords);
0222 return bin(binIdx);
0223 }
0224
0225
0226 const BinT& binAt(typename BinningT::EdgeTypesTuple&& coords) const noexcept {
0227 const size_t binIdx = _binning.globalIndexAt(coords);
0228 return bin(binIdx);
0229 }
0230
0231
0232
0233
0234 void set(typename BinningT::EdgeTypesTuple&& coords, BinContentT&& content) noexcept {
0235 const size_t binIdx = _binning.globalIndexAt(coords);
0236 _bins[binIdx] = std::move(content);
0237 }
0238
0239
0240 void set(typename BinningT::EdgeTypesTuple&& coords, const BinContentT& content) noexcept {
0241 const size_t binIdx = _binning.globalIndexAt(coords);
0242 _bins[binIdx] = content;
0243 }
0244
0245
0246
0247
0248 void set(const size_t binIdx, BinContentT&& content) noexcept {
0249 _bins[binIdx] = std::move(content);
0250 }
0251
0252
0253 void set(const size_t binIdx, const BinContentT& content) noexcept {
0254 _bins[binIdx] = content;
0255 }
0256
0257
0258
0259 std::vector<size_t> calcIndicesToSkip(const bool includeOverflows, const bool includeMaskedBins) const noexcept {
0260
0261
0262 if (!_binning.numBins(!includeOverflows, !includeMaskedBins)) return {};
0263
0264 std::vector<size_t> indicesToSkip;
0265
0266
0267 auto appendIndicesVec = [&indicesToSkip](std::vector<size_t>&& indicesVec) {
0268 indicesToSkip.insert(std::end(indicesToSkip),
0269 std::make_move_iterator(std::begin(indicesVec)),
0270 std::make_move_iterator(std::end(indicesVec)));
0271 };
0272
0273
0274
0275 if(!includeOverflows) {
0276 appendIndicesVec(_binning.calcOverflowBinsIndices());
0277 }
0278
0279 if (!includeMaskedBins) {
0280 appendIndicesVec(_binning.maskedBins());
0281 }
0282
0283
0284 std::sort(indicesToSkip.begin(), indicesToSkip.end());
0285 indicesToSkip.erase( std::unique(indicesToSkip.begin(), indicesToSkip.end()),
0286 indicesToSkip.end() );
0287
0288 return indicesToSkip;
0289 }
0290
0291
0292
0293
0294
0295
0296
0297
0298 BinsVecWrapper<BinsVecT> bins(const bool includeOverflows = false,
0299 const bool includeMaskedBins = false) noexcept {
0300 return BinsVecWrapper<BinsVecT>(_bins,
0301 calcIndicesToSkip(includeOverflows, includeMaskedBins));
0302 }
0303
0304
0305
0306
0307
0308
0309 const BinsVecWrapper<const BinsVecT> bins(const bool includeOverflows = false,
0310 const bool includeMaskedBins = false) const noexcept {
0311 return BinsVecWrapper<const BinsVecT>(_bins,
0312 calcIndicesToSkip(includeOverflows, includeMaskedBins));
0313 }
0314
0315
0316
0317
0318
0319
0320
0321 const BinningT& binning() const noexcept {
0322 return _binning;
0323 }
0324
0325
0326 size_t binDim() const noexcept {
0327 return _binning.dim();
0328 }
0329
0330
0331 size_t numBins(const bool includeOverflows = false, const bool includeMaskedBins = false) const noexcept {
0332 return _binning.numBins(includeOverflows, includeMaskedBins);
0333 }
0334
0335
0336
0337
0338
0339 size_t numBinsAt(const size_t axisN, const bool includeOverflows = false) const noexcept {
0340 size_t nOverflows = includeOverflows? 0 : _binning.countOverflowBins(axisN);
0341 return _binning.numBinsAt(axisN) - nOverflows;
0342 }
0343
0344
0345 void reset() noexcept { clearBins(); }
0346
0347
0348
0349
0350 void clearBins() noexcept {
0351 _bins.clear();
0352 fillBins();
0353 }
0354
0355
0356 void maskBins(const std::vector<size_t>& indicesToMask, const bool status = true) noexcept {
0357 _binning.maskBins(indicesToMask, status);
0358 }
0359
0360
0361 void maskBin(const size_t indexToMask, const bool status = true) noexcept {
0362 _binning.maskBin(indexToMask, status);
0363 }
0364
0365
0366 void maskSlice(const size_t dim, const size_t idx, const bool status = true) {
0367 _binning.maskSlice(dim, idx, status);
0368 }
0369
0370
0371 void maskBinAt(typename BinningT::EdgeTypesTuple&& coords, const bool status = true) noexcept {
0372 _binning.maskBinAt(coords, status);
0373 }
0374
0375 bool isMasked(const size_t binIndex) const noexcept {
0376 return _binning.isMasked(binIndex);
0377 }
0378
0379 std::vector<size_t> maskedBins() const noexcept {
0380 return _binning.maskedBins();
0381 }
0382
0383 bool isVisible(const size_t binIndex) const noexcept {
0384 return _binning.isVisible(binIndex);
0385 }
0386
0387
0388
0389
0390
0391
0392
0393
0394
0395
0396
0397
0398 template <size_t... AxisNs, class RetT = void>
0399 auto mergeBins(
0400 std::decay_t<decltype(AxisNs, std::declval<std::pair<size_t, size_t>>())>... mergeRanges)
0401 noexcept -> std::enable_if_t<MetaUtils::is_detected_v<MetaUtils::operatorTraits::addition_assignment_t, BinContentT>, RetT>
0402 {
0403 auto mergeStorageBins =
0404 [&binning = BaseT::_binning, &binStorage = BaseT::_bins](auto I, const auto& mergeRangePair){
0405 assert(mergeRangePair.first < mergeRangePair.second);
0406
0407 auto append = [&binStorage](const auto& pivotBinsIndices, const auto& binsIndicesToMerge){
0408 assert(pivotBinsIndices.size() == binsIndicesToMerge.size());
0409
0410
0411
0412
0413
0414
0415
0416 for (size_t i = 0; i < pivotBinsIndices.size(); ++i) {
0417 auto& pivotBin = binStorage[pivotBinsIndices[i]];
0418 pivotBin += std::move(binStorage[binsIndicesToMerge[i]]);
0419 }
0420
0421 binStorage.erase(
0422 std::remove_if(binStorage.begin(), binStorage.end(), [&](const auto& b) {
0423 return std::find(binsIndicesToMerge.begin(), binsIndicesToMerge.end(), b.index()) != binsIndicesToMerge.end();
0424 }), binStorage.end());
0425 };
0426
0427 ssize_t nBinRowsToBeMerged = mergeRangePair.second - mergeRangePair.first;
0428
0429 size_t currBinRowIdx = mergeRangePair.first;
0430 size_t nextBinRowIdx = mergeRangePair.first + 1;
0431
0432
0433 while (nBinRowsToBeMerged--) {
0434
0435
0436 append(binning.sliceIndices(I, mergeRangePair.first), binning.sliceIndices(I, nextBinRowIdx));
0437 binning.template mergeBins<I>({currBinRowIdx, nextBinRowIdx});
0438 }
0439 };
0440
0441 ((void)mergeStorageBins(std::integral_constant<size_t, AxisNs>(), mergeRanges), ...);
0442
0443 }
0444
0445
0446
0447
0448
0449
0450 template<size_t axisN, template<typename...> typename BinnedT, typename Func,
0451 typename = std::enable_if_t< (axisN < sizeof...(AxisT) && sizeof...(AxisT)>=2) >>
0452 auto mkBinnedSlices(Func&& how2add, const bool includeOverflows=false) const {
0453
0454 size_t vecN = BaseT::numBinsAt(axisN, includeOverflows);
0455 auto binnedSlice = _mkBinnedT<BinnedT>(_binning.template _getAxesExcept<axisN>());
0456 std::vector<decltype(binnedSlice)> rtn(vecN, binnedSlice);
0457 for (size_t i = 0; i < vecN; ++i) {
0458
0459 auto mkSlice = [&oldBins = _bins, &how2add, &binnedSlice = rtn[i]](const auto& indicesToCopy) {
0460 assert(binnedSlice.numBins(true) == indicesToCopy.size());
0461
0462
0463
0464 for (size_t i = 0; i < binnedSlice.numBins(true); ++i) {
0465 auto& pivotBin = binnedSlice.bin(i);
0466 auto& binToCopy = oldBins[indicesToCopy[i]];
0467 how2add(pivotBin, binToCopy);
0468 }
0469 };
0470
0471
0472
0473 mkSlice(_binning.sliceIndices(axisN, i + !includeOverflows));
0474
0475 }
0476 return rtn;
0477 }
0478
0479
0480
0481 BinnedStorage& operator = (const BinnedStorage& other) noexcept {
0482 if (this != &other) {
0483 _binning = other._binning;
0484 fillBins(other._bins);
0485 }
0486 return *this;
0487 }
0488
0489
0490 BinnedStorage& operator = (BinnedStorage&& other) noexcept {
0491 if (this != &other) {
0492 _binning = std::move(other._binning);
0493 fillBins(std::move(other._bins));
0494 }
0495 return *this;
0496 }
0497
0498
0499
0500
0501
0502 bool operator == (const BinnedStorage& other) const noexcept {
0503 return _binning.isCompatible(other._binning);
0504 }
0505
0506
0507
0508
0509 bool operator != (const BinnedStorage& other) const noexcept {
0510 return ! operator == (other);
0511 }
0512
0513
0514 std::vector<size_t> _global2local(size_t idx) const noexcept {
0515 const auto& indices = _binning.globalToLocalIndices(idx);
0516 return std::vector<size_t>(indices.begin(), indices.end());
0517 }
0518
0519
0520 size_t _local2global(const std::vector<size_t>& indices) const {
0521 assert(indices.size() == sizeof...(AxisT));
0522 std::array<size_t, sizeof...(AxisT)> arr;
0523 std::copy_n(std::make_move_iterator(indices.begin()), sizeof...(AxisT), arr.begin());
0524 return _binning.localToGlobalIndex(arr);
0525 }
0526
0527
0528
0529
0530 protected:
0531
0532
0533
0534
0535
0536 void fillBins() noexcept {
0537 _bins.reserve(_binning.numBins());
0538
0539 for (size_t i = 0; i < _binning.numBins(); ++i) {
0540 _bins.emplace_back(i, _binning);
0541 }
0542 }
0543
0544 void fillBins(const BinsVecT& bins) noexcept {
0545 _bins.clear();
0546 _bins.reserve(_binning.numBins());
0547 for (const auto& b : bins) {
0548 _bins.emplace_back(b, _binning);
0549 }
0550 }
0551
0552 void fillBins(BinsVecT&& bins) noexcept {
0553 _bins.clear();
0554 _bins.reserve(_binning.numBins());
0555 for (auto&& b : bins) {
0556 _bins.emplace_back(std::move(b), _binning);
0557 }
0558 }
0559
0560
0561 template<template<typename...> typename BinnedT, class... newAxes, size_t... As>
0562 auto _mkBinnedT_aux(const std::tuple<newAxes...>& t, std::index_sequence<As...>) const {
0563 return BinnedT<typename newAxes::EdgeT...>(std::get<As>(t)...);
0564 }
0565
0566
0567 template <template<typename...> typename BinnedT, class... newAxes>
0568 auto _mkBinnedT(const std::tuple<newAxes...>& t) const {
0569 return _mkBinnedT_aux<BinnedT>(t, std::make_index_sequence<sizeof...(newAxes)>{});
0570 }
0571
0572
0573
0574
0575
0576 BinsVecT _bins;
0577
0578 BinningT _binning;
0579
0580 };
0581
0582 }
0583
0584 #endif