Project
Loading...
Searching...
No Matches
ASoAHelpers.h
Go to the documentation of this file.
1// Copyright 2019-2020 CERN and copyright holders of ALICE O2.
2// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
3// All rights not expressly granted are reserved.
4//
5// This software is distributed under the terms of the GNU General Public
6// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
7//
8// In applying this license CERN does not waive the privileges and immunities
9// granted to it by virtue of its status as an Intergovernmental Organization
10// or submit itself to any jurisdiction.
11
12#ifndef O2_FRAMEWORK_ASOAHELPERS_H_
13#define O2_FRAMEWORK_ASOAHELPERS_H_
14
15#include "Framework/ASoA.h"
17#include <arrow/table.h>
18
19#include <iterator>
20#include <tuple>
21#include <utility>
22
23namespace o2::soa
24{
25// Functions to enable looping over tuples
26template <std::size_t V>
27struct Num {
28 static const constexpr auto value = V;
29};
30
31template <class F, std::size_t... Is>
32void for_(F func, std::index_sequence<Is...>)
33{
34 using expander = int[];
35 (void)expander{0, ((void)func(Num<Is>{}), 0)...};
36}
37
38template <std::size_t N, typename F>
39void for_(F func)
40{
41 for_(func, std::make_index_sequence<N>());
42}
43
44// Creating tuple of given size and type
45template <typename T, unsigned N, typename... REST>
46struct NTupleType {
47 using type = typename NTupleType<T, N - 1, T, REST...>::type;
48};
49
50template <typename T, typename... REST>
51struct NTupleType<T, 0, REST...> {
52 using type = std::tuple<REST...>;
53};
54
56 BinningIndex(int bin_, uint64_t index_) : bin(bin_), index(index_) {}
57
58 bool operator<(const BinningIndex& rhs) const { return std::tie(bin, index) < std::tie(rhs.bin, rhs.index); }
59
60 int bin;
61 uint64_t index;
62};
63
64// Group table (C++ vector of indices)
65inline bool sameCategory(BinningIndex const& a, BinningIndex const& b)
66{
67 return a.bin < b.bin;
68}
69inline bool diffCategory(BinningIndex const& a, BinningIndex const& b)
70{
71 return a.bin >= b.bin;
72}
73
75
76template <template <typename... Cs> typename BP, typename T, typename... Cs>
77std::vector<BinningIndex> groupTable(const T& table, const BP<Cs...>& binningPolicy, int minCatSize, int outsider)
78{
79 std::vector<BinningIndex> groupedIndices;
80
81 for (auto rowIterator : table) {
82 auto values = binningPolicy.getBinningValues(rowIterator);
83 auto val = binningPolicy.getBin(values);
84 if (val != outsider) {
85 groupedIndices.emplace_back(val, *std::get<1>(rowIterator.getIndices()));
86 }
87 }
88
89 // Do a stable sort so that same categories entries are
90 // grouped together.
91 std::stable_sort(groupedIndices.begin(), groupedIndices.end());
92
93 // Remove categories of too small size
94 if (minCatSize > 1) {
95 auto catBegin = groupedIndices.begin();
96 while (catBegin != groupedIndices.end()) {
97 auto catEnd = std::upper_bound(catBegin, groupedIndices.end(), *catBegin, sameCategory);
98 if (std::distance(catBegin, catEnd) < minCatSize) {
99 catEnd = groupedIndices.erase(catBegin, catEnd);
100 }
101 catBegin = catEnd;
102 }
103 }
104
105 return groupedIndices;
106}
107
108// Synchronize categories so as groupedIndices contain elements only of categories common to all tables
109template <std::size_t K>
110void syncCategories(std::array<std::vector<BinningIndex>, K>& groupedIndices)
111{
112 std::vector<BinningIndex> firstCategories;
113 std::vector<BinningIndex> commonCategories;
114 std::unique_copy(groupedIndices[0].begin(), groupedIndices[0].end(), std::back_inserter(firstCategories), diffCategory);
115
116 for (auto& cat : firstCategories) {
117 bool isCommon = true;
118 for (int i = 1; i < K; i++) {
119 if (!std::binary_search(groupedIndices[i].begin(), groupedIndices[i].end(), cat, sameCategory)) {
120 isCommon = false;
121 break;
122 }
123 }
124 if (isCommon) {
125 commonCategories.push_back(cat);
126 }
127 }
128
129 for (int i = 0; i < K; i++) {
130 auto nonCatBegin = groupedIndices[i].begin();
131 for (auto& cat : commonCategories) {
132 auto nonCatEnd = std::lower_bound(nonCatBegin, groupedIndices[i].end(), cat, sameCategory);
133 nonCatEnd = groupedIndices[i].erase(nonCatBegin, nonCatEnd);
134 nonCatBegin = std::upper_bound(nonCatEnd, groupedIndices[i].end(), cat, sameCategory);
135 }
136 }
137}
138
139template <typename... Ts>
141 using CombinationType = std::tuple<typename Ts::iterator...>;
142 using IndicesType = typename NTupleType<uint64_t, sizeof...(Ts)>::type;
143
145 template <typename... Tss>
146 CombinationsIndexPolicyBase(const Tss&... tables) : mIsEnd(false),
147 mMaxOffset(tables.end().index...),
148 mCurrent(tables.begin()...)
149 {
150 if (((tables.size() == 0) || ...)) {
151 this->mIsEnd = true;
152 }
153 }
154 template <typename... Tss>
155 CombinationsIndexPolicyBase(Tss&&... tables) : mTables(std::make_shared<std::tuple<Tss...>>(std::make_tuple(std::move(tables)...))),
156 mIsEnd(false)
157 {
158 std::apply([&](auto&&... x) mutable { mMaxOffset = IndicesType{x.end().index...}; mCurrent = CombinationType{x.begin()...}; }, *mTables);
159 if (
160 std::apply([](auto&&... x) -> bool { return ((x.size() == 0) || ...); }, *mTables)) {
161 this->mIsEnd = true;
162 }
163 }
164
165 void setTables(const Ts&... tables)
166 {
167 mIsEnd = false;
168 mMaxOffset = IndicesType(tables.end().index...);
169 mCurrent = CombinationType(tables.begin()...);
170 if (((tables.size() == 0) || ...)) {
171 this->mIsEnd = true;
172 }
173 }
174 template <typename... Tss>
175 void setTables(Tss&&... tables)
176 {
177 mIsEnd = false;
178 mTables = std::make_shared<std::tuple<Tss...>>(std::make_tuple(std::move(tables)...));
179 std::apply([&](auto&&... x) mutable { mMaxOffset = IndicesType{x.end().index...}; mCurrent = CombinationType{x.begin()...}; }, *mTables);
180 if (
181 std::apply([](auto&&... x) -> bool { return ((x.size() == 0) || ...); }, *mTables)) {
182 this->mIsEnd = true;
183 }
184 }
185
187 {
188 constexpr auto k = sizeof...(Ts);
189 for_<k>([&, this](auto i) {
190 std::get<i.value>(this->mCurrent).moveToEnd();
191 });
192 this->mIsEnd = true;
193 }
194
195 void addOne() {}
196
197 std::shared_ptr<std::tuple<Ts...>> mTables;
199 IndicesType mMaxOffset; // one position past maximum acceptable position for each element of combination
200 bool mIsEnd; // whether there are any more tuples available
201};
202
203template <typename... Ts>
205
206template <typename... Ts>
208
209template <typename... Ts>
212
214 CombinationsUpperIndexPolicy(const Ts&... tables) : CombinationsIndexPolicyBase<Ts...>(tables...) {}
215 CombinationsUpperIndexPolicy(Ts&&... tables) : CombinationsIndexPolicyBase<Ts...>(std::forward<Ts>(tables)...) {}
216
217 void addOne()
218 {
219 constexpr auto k = sizeof...(Ts);
220 bool modify = true;
221 for_<k>([&, this](auto i) {
222 if (modify) {
223 constexpr auto curInd = k - i.value - 1;
224 std::get<curInd>(this->mCurrent)++;
225 if (*std::get<1>(std::get<curInd>(this->mCurrent).getIndices()) != std::get<curInd>(this->mMaxOffset)) {
226 modify = false;
227 for_<i.value>([&, this](auto j) {
228 constexpr auto curJ = k - i.value + j.value;
229 int64_t nextInd = *std::get<1>(std::get<curJ - 1>(this->mCurrent).getIndices());
230 if (nextInd < std::get<curJ>(this->mMaxOffset)) {
231 std::get<curJ>(this->mCurrent).setCursor(nextInd);
232 } else {
233 modify = true;
234 }
235 });
236 }
237 }
238 });
239 this->mIsEnd = modify;
240 }
241};
242
243template <typename... Ts>
246
249 {
250 if (!this->mIsEnd) {
251 setRanges(tables...);
252 }
253 }
255 {
256 if (!this->mIsEnd) {
257 setRanges();
258 }
259 }
260
261 void setTables(const Ts&... tables)
262 {
264 setRanges(tables...);
265 }
266 void setTables(Ts&&... tables)
267 {
268 CombinationsIndexPolicyBase<Ts...>::setTables(std::forward<Ts>(tables)...);
269 setRanges(tables...);
270 }
271
272 void setRanges(const Ts&... tables)
273 {
274 constexpr auto k = sizeof...(Ts);
275 if (((tables.size() < k) || ...)) {
276 this->mIsEnd = true;
277 return;
278 }
279 for_<k>([&, this](auto i) {
280 std::get<i.value>(this->mMaxOffset) += i.value + 1 - k;
281 std::get<i.value>(this->mCurrent).moveByIndex(i.value);
282 });
283 }
285 {
286 constexpr auto k = sizeof...(Ts);
287 if (
288 std::apply([](auto&&... x) -> bool { return ((x.size() < k) || ...); }, *this->mTables)) {
289 this->mIsEnd = true;
290 return;
291 }
292 for_<k>([&, this](auto i) {
293 std::get<i.value>(this->mMaxOffset) += i.value + 1 - k;
294 std::get<i.value>(this->mCurrent).moveByIndex(i.value);
295 });
296 }
297
298 void addOne()
299 {
300 constexpr auto k = sizeof...(Ts);
301 bool modify = true;
302 for_<k>([&, this](auto i) {
303 if (modify) {
304 constexpr auto curInd = k - i.value - 1;
305 std::get<curInd>(this->mCurrent)++;
306 if (*std::get<1>(std::get<curInd>(this->mCurrent).getIndices()) != std::get<curInd>(this->mMaxOffset)) {
307 modify = false;
308 for_<i.value>([&, this](auto j) {
309 constexpr auto curJ = k - i.value + j.value;
310 int64_t nextInd = *std::get<1>(std::get<curJ - 1>(this->mCurrent).getIndices()) + 1;
311 if (nextInd < std::get<curJ>(this->mMaxOffset)) {
312 std::get<curJ>(this->mCurrent).setCursor(nextInd);
313 } else {
314 modify = true;
315 }
316 });
317 }
318 }
319 });
320 this->mIsEnd = modify;
321 }
322};
323
324template <typename... Ts>
327
329 CombinationsFullIndexPolicy(const Ts&... tables) : CombinationsIndexPolicyBase<Ts...>(tables...) {}
330 CombinationsFullIndexPolicy(Ts&&... tables) : CombinationsIndexPolicyBase<Ts...>(std::forward<Ts>(tables)...) {}
331
332 void addOne()
333 {
334 constexpr auto k = sizeof...(Ts);
335 bool modify = true;
336 for_<k>([&, this](auto i) {
337 if (modify) {
338 constexpr auto curInd = k - i.value - 1;
339 std::get<curInd>(this->mCurrent)++;
340 if (*std::get<1>(std::get<curInd>(this->mCurrent).getIndices()) != std::get<curInd>(this->mMaxOffset)) {
341 for_<i.value>([&, this](auto j) {
342 constexpr auto curJ = k - i.value + j.value;
343 std::get<curJ>(this->mCurrent).setCursor(0);
344 });
345 modify = false;
346 }
347 }
348 });
349 this->mIsEnd = modify;
350 }
351};
352
353// For upper and full only
354template <typename BP, typename T, typename... Ts>
357 using IndicesType = typename NTupleType<uint64_t, sizeof...(Ts)>::type;
358
359 CombinationsBlockIndexPolicyBase(const BP& binningPolicy, int categoryNeighbours, const T& outsider) : CombinationsIndexPolicyBase<Ts...>(), mSlidingWindowSize(categoryNeighbours + 1), mBP(binningPolicy), mCategoryNeighbours(categoryNeighbours), mOutsider(outsider), mIsNewWindow(true) {}
360 CombinationsBlockIndexPolicyBase(const BP& binningPolicy, int categoryNeighbours, const T& outsider, const Ts&... tables) : CombinationsIndexPolicyBase<Ts...>(tables...), mSlidingWindowSize(categoryNeighbours + 1), mBP(binningPolicy), mCategoryNeighbours(categoryNeighbours), mOutsider(outsider), mIsNewWindow(true)
361 {
362 if (!this->mIsEnd) {
363 setRanges(tables...);
364 }
365 }
366 CombinationsBlockIndexPolicyBase(const BP& binningPolicy, int categoryNeighbours, const T& outsider, Ts&&... tables) : CombinationsIndexPolicyBase<Ts...>(std::forward<Ts>(tables)...), mSlidingWindowSize(categoryNeighbours + 1), mBP(binningPolicy), mCategoryNeighbours(categoryNeighbours), mOutsider(outsider), mIsNewWindow(true)
367 {
368 if (!this->mIsEnd) {
369 setRanges();
370 }
371 }
372
373 void setTables(const Ts&... tables)
374 {
376 setRanges(tables...);
377 }
378 void setTables(Ts&&... tables)
379 {
380 CombinationsIndexPolicyBase<Ts...>::setTables(std::forward<Ts>(tables)...);
381 setRanges();
382 }
383
384 void setRanges(const Ts&... tables)
385 {
386 constexpr auto k = sizeof...(Ts);
387 if (mSlidingWindowSize < 1) {
388 this->mIsEnd = true;
389 return;
390 }
391
392 int tableIndex = 0;
393 ((this->mGroupedIndices[tableIndex++] = groupTable(tables, this->mBP, 1, this->mOutsider)), ...);
394
395 // Synchronize categories across tables
397
398 for (int i = 0; i < k; i++) {
399 if (this->mGroupedIndices[i].size() == 0) {
400 this->mIsEnd = true;
401 return;
402 }
403 }
404
405 for_<k>([this](auto i) {
406 std::get<i.value>(this->mCurrentIndices) = 0;
407 });
408 }
409 void setRanges(Ts&&... tables)
410 {
411 constexpr auto k = sizeof...(Ts);
412 if (this->mIsEnd) {
413 return;
414 }
415 if (mSlidingWindowSize < 1) {
416 this->mIsEnd = true;
417 return;
418 }
419
420 int tableIndex = 0;
421 std::apply([&, this](auto&&... x) mutable {
422 ((this->mGroupedIndices[tableIndex++] = groupTable(x, this->mBP, 1, this->mOutsider)), ...);
423 },
424 *this->mTables);
425
426 // Synchronize categories across tables
428
429 for (int i = 0; i < k; i++) {
430 if (this->mGroupedIndices[i].size() == 0) {
431 this->mIsEnd = true;
432 return;
433 }
434 }
435
436 for_<k>([this](auto i) {
437 std::get<i.value>(this->mCurrentIndices) = 0;
438 });
439 }
440
442 {
443 // NOTE: The same number of currentWindowNeighbours is returned for all kinds of block combinations.
444 // Strictly upper: the first element will is paired with exactly currentWindowNeighbours other elements.
445 // Upper: the first element is paired with (currentWindowNeighbours + 1) elements, including itself.
446 // Full: (currentWindowNeighbours + 1) pairs with the first element in the first position (c1)
447 // + there are other combinations with the first element at other positions.
448 if (this->mIsEnd) {
449 return 0;
450 }
451 uint64_t maxForWindow = std::get<0>(this->mBeginIndices) + this->mSlidingWindowSize - 1;
452 uint64_t maxForTable = std::get<0>(this->mMaxOffset);
453 uint64_t currentMax = maxForWindow < maxForTable ? maxForWindow : maxForTable;
454 return currentMax - std::get<0>(mCurrentIndices);
455 }
456
458 {
459 return mIsNewWindow;
460 }
461
462 std::array<std::vector<BinningIndex>, sizeof...(Ts)> mGroupedIndices;
466 const BP mBP;
468 const T mOutsider;
470};
471
472template <typename BP, typename T, typename... Ts>
475
476 CombinationsBlockUpperIndexPolicy(const BP& binningPolicy, int categoryNeighbours, const T& outsider) : CombinationsBlockIndexPolicyBase<BP, T, Ts...>(binningPolicy, categoryNeighbours, outsider) {}
477 CombinationsBlockUpperIndexPolicy(const BP& binningPolicy, int categoryNeighbours, const T& outsider, const Ts&... tables) : CombinationsBlockIndexPolicyBase<BP, T, Ts...>(binningPolicy, categoryNeighbours, outsider, tables...)
478 {
479 if (!this->mIsEnd) {
480 setRanges();
481 }
482 }
483 CombinationsBlockUpperIndexPolicy(const BP& binningPolicy, int categoryNeighbours, const T& outsider, Ts&&... tables) : CombinationsBlockIndexPolicyBase<BP, T, Ts...>(binningPolicy, categoryNeighbours, outsider, std::forward<Ts>(tables)...)
484 {
485 if (!this->mIsEnd) {
486 setRanges();
487 }
488 }
489
490 void setTables(const Ts&... tables)
491 {
493 setRanges();
494 }
495 void setTables(Ts&&... tables)
496 {
498 setRanges();
499 }
500
502 {
503 constexpr auto k = sizeof...(Ts);
504 for_<k>([&, this](auto i) {
505 auto catBegin = this->mGroupedIndices[i.value].begin() + std::get<i.value>(this->mCurrentIndices);
506 auto range = std::equal_range(catBegin, this->mGroupedIndices[i.value].end(), *catBegin, sameCategory);
507 std::get<i.value>(this->mBeginIndices) = std::distance(this->mGroupedIndices[i.value].begin(), range.first);
508 std::get<i.value>(this->mCurrent).setCursor(range.first->index);
509 std::get<i.value>(this->mMaxOffset) = std::distance(this->mGroupedIndices[i.value].begin(), range.second);
510 });
511 }
512
513 void addOne()
514 {
515 constexpr auto k = sizeof...(Ts);
516 bool modify = true;
517 bool nextCatAvailable = true;
518 for_<k - 1>([&, this](auto i) {
519 if (modify) {
520 constexpr auto curInd = k - i.value - 1;
521 std::get<curInd>(this->mCurrentIndices)++;
522 uint64_t curGroupedInd = std::get<curInd>(this->mCurrentIndices);
523 uint64_t maxForWindow = std::get<curInd>(this->mBeginIndices) + this->mSlidingWindowSize;
524
525 // If we remain within the same sliding window
526 if (curGroupedInd < maxForWindow && curGroupedInd < std::get<curInd>(this->mMaxOffset)) {
527 std::get<curInd>(this->mCurrent).setCursor(this->mGroupedIndices[curInd][curGroupedInd].index);
528 modify = false;
529 for_<i.value>([&, this](auto j) {
530 constexpr auto curJ = k - i.value + j.value;
531 if (std::get<curJ - 1>(this->mCurrentIndices) < std::get<curJ>(this->mMaxOffset)) {
532 std::get<curJ>(this->mCurrentIndices) = std::get<curJ - 1>(this->mCurrentIndices);
533 uint64_t curGroupedJ = std::get<curJ>(this->mCurrentIndices);
534 std::get<curJ>(this->mCurrent).setCursor(this->mGroupedIndices[curJ][curGroupedJ].index);
535 } else {
536 modify = true;
537 }
538 });
539 }
540 }
541 });
542
543 this->mIsNewWindow = modify;
544
545 // First iterator processed separately
546 if (modify) {
547 std::get<0>(this->mCurrentIndices)++;
548 std::get<0>(this->mBeginIndices)++;
549 uint64_t curGroupedInd = std::get<0>(this->mCurrentIndices);
550
551 // If we remain within the same category - slide window
552 if (curGroupedInd < std::get<0>(this->mMaxOffset)) {
553 std::get<0>(this->mCurrent).setCursor(this->mGroupedIndices[0][curGroupedInd].index);
554 modify = false;
555 for_<k - 1>([&, this](auto j) {
556 constexpr auto curJ = j.value + 1;
557 std::get<curJ>(this->mBeginIndices)++;
558 if (std::get<curJ>(this->mBeginIndices) < std::get<curJ>(this->mMaxOffset)) {
559 std::get<curJ>(this->mCurrentIndices) = std::get<curJ>(this->mBeginIndices);
560 uint64_t curGroupedJ = std::get<curJ>(this->mCurrentIndices);
561 std::get<curJ>(this->mCurrent).setCursor(this->mGroupedIndices[curJ][curGroupedJ].index);
562 } else {
563 modify = true;
564 }
565 });
566 }
567 }
568
569 // No more combinations within this category - move to the next category, if possible
570 if (modify) {
571 for_<k>([&, this](auto m) {
572 std::get<m.value>(this->mCurrentIndices) = std::get<m.value>(this->mMaxOffset);
573 if (std::get<m.value>(this->mCurrentIndices) == this->mGroupedIndices[m.value].size()) {
574 nextCatAvailable = false;
575 }
576 });
577 if (nextCatAvailable) {
578 setRanges();
579 }
580 }
581
582 this->mIsEnd = modify && !nextCatAvailable;
583 }
584};
585
586template <typename BP, typename T, typename... Ts>
589 using IndicesType = typename NTupleType<uint64_t, sizeof...(Ts)>::type;
590
591 CombinationsBlockFullIndexPolicy(const BP& binningPolicy, int categoryNeighbours, const T& outsider) : CombinationsBlockIndexPolicyBase<BP, T, Ts...>(binningPolicy, categoryNeighbours, outsider), mCurrentlyFixed(0) {}
592 CombinationsBlockFullIndexPolicy(const BP& binningPolicy, int categoryNeighbours, const T& outsider, const Ts&... tables) : CombinationsBlockIndexPolicyBase<BP, T, Ts...>(binningPolicy, categoryNeighbours, outsider, tables...), mCurrentlyFixed(0)
593 {
594 if (!this->mIsEnd) {
595 setRanges();
596 }
597 }
598 CombinationsBlockFullIndexPolicy(const BP& binningPolicy, int categoryNeighbours, const T& outsider, Ts&&... tables) : CombinationsBlockIndexPolicyBase<BP, T, Ts...>(binningPolicy, categoryNeighbours, outsider, std::forward<Ts>(tables)...), mCurrentlyFixed(0)
599 {
600 if (!this->mIsEnd) {
601 setRanges();
602 }
603 }
604
605 void setTables(const Ts&... tables)
606 {
608 setRanges();
609 }
610 void setTables(Ts&&... tables)
611 {
613 setRanges();
614 }
615
617 {
618 constexpr auto k = sizeof...(Ts);
619 for_<k>([&, this](auto i) {
620 auto catBegin = this->mGroupedIndices[i.value].begin() + std::get<i.value>(this->mCurrentIndices);
621 auto range = std::equal_range(catBegin, this->mGroupedIndices[i.value].end(), *catBegin, sameCategory);
622 std::get<i.value>(this->mBeginIndices) = std::distance(this->mGroupedIndices[i.value].begin(), range.first);
623 std::get<i.value>(this->mMaxOffset) = std::distance(this->mGroupedIndices[i.value].begin(), range.second);
624 std::get<i.value>(this->mCurrent).setCursor(range.first->index);
625 });
626 }
627
628 void addOne()
629 {
630 constexpr auto k = sizeof...(Ts);
631 bool modify = true;
632 bool nextCatAvailable = true;
633 for_<k>([&, this](auto i) {
634 if (modify) {
635 constexpr auto curInd = k - i.value - 1;
636 std::get<curInd>(this->mCurrentIndices)++;
637 uint64_t curGroupedInd = std::get<curInd>(this->mCurrentIndices);
638 uint64_t windowOffset = curInd == this->mCurrentlyFixed ? 1 : this->mSlidingWindowSize;
639 uint64_t maxForWindow = std::get<curInd>(this->mBeginIndices) + windowOffset;
640
641 // If we remain within the same sliding window and fixed index
642 if (curGroupedInd < maxForWindow && curGroupedInd < std::get<curInd>(this->mMaxOffset)) {
643 std::get<curInd>(this->mCurrent).setCursor(this->mGroupedIndices[curInd][curGroupedInd].index);
644 for_<i.value>([&, this](auto j) {
645 constexpr auto curJ = k - i.value + j.value;
646 if (curJ < this->mCurrentlyFixed) { // To assure no repetitions
647 std::get<curJ>(this->mCurrentIndices) = std::get<curJ>(this->mBeginIndices) + 1;
648 } else {
649 std::get<curJ>(this->mCurrentIndices) = std::get<curJ>(this->mBeginIndices);
650 }
651 uint64_t curGroupedJ = std::get<curJ>(this->mCurrentIndices);
652 std::get<curJ>(this->mCurrent).setCursor(this->mGroupedIndices[curJ][curGroupedJ].index);
653 });
654 modify = false;
655 }
656 }
657 });
658
659 this->mIsNewWindow = modify;
660
661 // Currently fixed iterator processed separately
662 if (modify) {
663 // If we haven't finished with window starting element
664 if (this->mCurrentlyFixed < k - 1 && std::get<0>(this->mBeginIndices) < std::get<0>(this->mMaxOffset) - 1) {
665 this->mCurrentlyFixed++;
666 for_<k>([&, this](auto s) {
667 if (s.value < this->mCurrentlyFixed) { // To assure no repetitions
668 std::get<s.value>(this->mCurrentIndices) = std::get<s.value>(this->mBeginIndices) + 1;
669 } else {
670 std::get<s.value>(this->mCurrentIndices) = std::get<s.value>(this->mBeginIndices);
671 }
672 uint64_t curGroupedI = std::get<s.value>(this->mCurrentIndices);
673 std::get<s.value>(this->mCurrent).setCursor(this->mGroupedIndices[s.value][curGroupedI].index);
674 });
675 modify = false;
676 } else {
677 this->mCurrentlyFixed = 0;
678 std::get<0>(this->mBeginIndices)++;
679 std::get<0>(this->mCurrentIndices) = std::get<0>(this->mBeginIndices);
680
681 // If we remain within the same category - slide window
682 if (std::get<0>(this->mBeginIndices) < std::get<0>(this->mMaxOffset)) {
683 uint64_t curGroupedInd = std::get<0>(this->mCurrentIndices);
684 std::get<0>(this->mCurrent).setCursor(this->mGroupedIndices[0][curGroupedInd].index);
685 modify = false;
686 for_<k - 1>([&, this](auto j) {
687 constexpr auto curJ = j.value + 1;
688 std::get<curJ>(this->mBeginIndices)++;
689 if (std::get<curJ>(this->mBeginIndices) < std::get<curJ>(this->mMaxOffset)) {
690 std::get<curJ>(this->mCurrentIndices) = std::get<curJ>(this->mBeginIndices);
691 uint64_t curGroupedJ = std::get<curJ>(this->mCurrentIndices);
692 std::get<curJ>(this->mCurrent).setCursor(this->mGroupedIndices[curJ][curGroupedJ].index);
693 } else {
694 modify = true;
695 }
696 });
697 }
698 }
699 }
700
701 // No more combinations within this category - move to the next category, if possible
702 if (modify) {
703 for_<k>([&, this](auto m) {
704 std::get<m.value>(this->mCurrentIndices) = std::get<m.value>(this->mMaxOffset);
705 if (std::get<m.value>(this->mCurrentIndices) == this->mGroupedIndices[m.value].size()) {
706 nextCatAvailable = false;
707 }
708 });
709 if (nextCatAvailable) {
710 setRanges();
711 }
712 }
713
714 this->mIsEnd = modify && !nextCatAvailable;
715 }
716
718};
719
720template <typename BP, typename T1, typename T, typename... Ts>
723 using IndicesType = typename NTupleType<uint64_t, sizeof...(Ts) + 1>::type;
724
725 CombinationsBlockSameIndexPolicyBase(const BP& binningPolicy, int categoryNeighbours, const T1& outsider, int minWindowSize) : CombinationsIndexPolicyBase<T, Ts...>(), mSlidingWindowSize(categoryNeighbours + 1), mBP(binningPolicy), mCategoryNeighbours(categoryNeighbours), mOutsider(outsider), mMinWindowSize(minWindowSize), mIsNewWindow(true) {}
726 CombinationsBlockSameIndexPolicyBase(const BP& binningPolicy, int categoryNeighbours, const T1& outsider, int minWindowSize, const T& table, const Ts&... tables) : CombinationsIndexPolicyBase<T, Ts...>(table, tables...), mSlidingWindowSize(categoryNeighbours + 1), mBP(binningPolicy), mCategoryNeighbours(categoryNeighbours), mOutsider(outsider), mMinWindowSize(minWindowSize), mIsNewWindow(true)
727 {
728 if (!this->mIsEnd) {
729 setRanges(table);
730 }
731 }
732 CombinationsBlockSameIndexPolicyBase(const BP& binningPolicy, int categoryNeighbours, const T1& outsider, int minWindowSize, T&& table, Ts&&... tables) : CombinationsIndexPolicyBase<T, Ts...>(std::forward<T>(table), std::forward<Ts>(tables)...), mSlidingWindowSize(categoryNeighbours + 1), mBP(binningPolicy), mCategoryNeighbours(categoryNeighbours), mOutsider(outsider), mMinWindowSize(minWindowSize), mIsNewWindow(true)
733 {
734 if (!this->mIsEnd) {
735 setRanges();
736 }
737 }
738
739 void setTables(const T& table, const Ts&... tables)
740 {
742 if (!this->mIsEnd) {
743 setRanges(table);
744 }
745 }
746 void setTables(T&& table, Ts&&... tables)
747 {
748 CombinationsIndexPolicyBase<T, Ts...>::setTables(std::forward<T>(table), std::forward<Ts>(tables)...);
749 if (!this->mIsEnd) {
750 setRanges();
751 }
752 }
753
754 void setRanges(const T& table)
755 {
756 constexpr auto k = sizeof...(Ts) + 1;
757 // minWindowSize == 1 for upper and full, and k for strictly upper k-combination
759 this->mIsEnd = true;
760 return;
761 }
762
764
765 if (this->mGroupedIndices.size() == 0) {
766 this->mIsEnd = true;
767 return;
768 }
769
770 std::get<0>(this->mCurrentIndices) = 0;
771 }
773 {
774 constexpr auto k = sizeof...(Ts) + 1;
775 // minWindowSize == 1 for upper and full, and k for strictly upper k-combination
777 this->mIsEnd = true;
778 return;
779 }
780
781 this->mGroupedIndices = groupTable(std::get<0>(*this->mTables), mBP, mMinWindowSize, mOutsider);
782
783 if (this->mGroupedIndices.size() == 0) {
784 this->mIsEnd = true;
785 return;
786 }
787
788 std::get<0>(this->mCurrentIndices) = 0;
789 }
790
792 {
793 // NOTE: The same number of currentWindowNeighbours is returned for all kinds of block combinations.
794 // Strictly upper: the first element will is paired with exactly currentWindowNeighbours other elements.
795 // Upper: the first element is paired with (currentWindowNeighbours + 1) elements, including itself.
796 // Full: (currentWindowNeighbours + 1) pairs with the first element in the first position (c1)
797 // + there are other combinations with the first element at other positions.
798 if (this->mIsEnd) {
799 return 0;
800 }
801 uint64_t maxForWindow = std::get<0>(this->mCurrentIndices) + this->mSlidingWindowSize - 1;
802 uint64_t maxForTable = std::get<0>(this->mMaxOffset);
803 uint64_t currentMax = maxForWindow < maxForTable ? maxForWindow : maxForTable;
804 return currentMax - std::get<0>(mCurrentIndices);
805 }
806
808 {
809 return mIsNewWindow;
810 }
811
812 std::vector<BinningIndex> mGroupedIndices;
814 const uint64_t mSlidingWindowSize;
815 const int mMinWindowSize;
816 const BP mBP;
818 const T1 mOutsider;
820};
821
822template <typename BP, typename T1, typename... Ts>
825
826 CombinationsBlockUpperSameIndexPolicy(const BP& binningPolicy, int categoryNeighbours, const T1& outsider) : CombinationsBlockSameIndexPolicyBase<BP, T1, Ts...>(binningPolicy, categoryNeighbours, outsider, 1) {}
827 CombinationsBlockUpperSameIndexPolicy(const BP& binningPolicy, int categoryNeighbours, const T1& outsider, const Ts&... tables) : CombinationsBlockSameIndexPolicyBase<BP, T1, Ts...>(binningPolicy, categoryNeighbours, outsider, 1, tables...)
828 {
829 if (!this->mIsEnd) {
830 setRanges();
831 }
832 }
833 CombinationsBlockUpperSameIndexPolicy(const BP& binningPolicy, int categoryNeighbours, const T1& outsider, Ts&&... tables) : CombinationsBlockSameIndexPolicyBase<BP, T1, Ts...>(binningPolicy, categoryNeighbours, outsider, 1, std::forward<Ts>(tables)...)
834 {
835 if (!this->mIsEnd) {
836 setRanges();
837 }
838 }
839
840 void setTables(const Ts&... tables)
841 {
843 setRanges();
844 }
845 void setTables(Ts&&... tables)
846 {
848 setRanges();
849 }
850
852 {
853 constexpr auto k = sizeof...(Ts);
854 auto catBegin = this->mGroupedIndices.begin() + std::get<0>(this->mCurrentIndices);
855 auto range = std::equal_range(catBegin, this->mGroupedIndices.end(), *catBegin, sameCategory);
856 uint64_t offset = std::distance(this->mGroupedIndices.begin(), range.second);
857
858 for_<k>([&, this](auto i) {
859 std::get<i.value>(this->mCurrentIndices) = std::get<0>(this->mCurrentIndices);
860 std::get<i.value>(this->mMaxOffset) = offset;
861 std::get<i.value>(this->mCurrent).setCursor(range.first->index);
862 });
863 }
864
865 void addOne()
866 {
867 constexpr auto k = sizeof...(Ts);
868 bool modify = true;
869 for_<k - 1>([&, this](auto i) {
870 if (modify) {
871 constexpr auto curInd = k - i.value - 1;
872 std::get<curInd>(this->mCurrentIndices)++;
873 uint64_t curGroupedInd = std::get<curInd>(this->mCurrentIndices);
874 uint64_t maxForWindow = std::get<0>(this->mCurrentIndices) + this->mSlidingWindowSize;
875
876 // If we remain within the same sliding window
877 if (curGroupedInd < maxForWindow && curGroupedInd < std::get<curInd>(this->mMaxOffset)) {
878 std::get<curInd>(this->mCurrent).setCursor(this->mGroupedIndices[curGroupedInd].index);
879 for_<i.value>([&, this](auto j) {
880 constexpr auto curJ = k - i.value + j.value;
881 std::get<curJ>(this->mCurrentIndices) = std::get<curJ - 1>(this->mCurrentIndices);
882 uint64_t curGroupedJ = std::get<curJ>(this->mCurrentIndices);
883 std::get<curJ>(this->mCurrent).setCursor(this->mGroupedIndices[curGroupedJ].index);
884 });
885 modify = false;
886 }
887 }
888 });
889
890 this->mIsNewWindow = modify;
891
892 // First iterator processed separately
893 if (modify) {
894 std::get<0>(this->mCurrentIndices)++;
895 uint64_t curGroupedInd = std::get<0>(this->mCurrentIndices);
896
897 // If we remain within the same category - slide window
898 if (curGroupedInd < std::get<0>(this->mMaxOffset)) {
899 std::get<0>(this->mCurrent).setCursor(this->mGroupedIndices[curGroupedInd].index);
900 for_<k - 1>([&, this](auto j) {
901 constexpr auto curJ = j.value + 1;
902 std::get<curJ>(this->mCurrentIndices) = std::get<curJ - 1>(this->mCurrentIndices);
903 uint64_t curGroupedJ = std::get<curJ>(this->mCurrentIndices);
904 std::get<curJ>(this->mCurrent).setCursor(this->mGroupedIndices[curGroupedJ].index);
905 });
906 modify = false;
907 }
908 }
909
910 // No more combinations within this category - move to the next category, if possible
911 if (modify && std::get<0>(this->mCurrentIndices) < this->mGroupedIndices.size()) {
912 setRanges();
913 return;
914 }
915
916 this->mIsEnd = modify;
917 }
918};
919
920template <typename BP, typename T1, typename... Ts>
923
924 CombinationsBlockStrictlyUpperSameIndexPolicy(const BP& binningPolicy, int categoryNeighbours, const T1& outsider) : CombinationsBlockSameIndexPolicyBase<BP, T1, Ts...>(binningPolicy, categoryNeighbours, outsider, sizeof...(Ts)) {}
925 CombinationsBlockStrictlyUpperSameIndexPolicy(const BP& binningPolicy, int categoryNeighbours, const T1& outsider, const Ts&... tables) : CombinationsBlockSameIndexPolicyBase<BP, T1, Ts...>(binningPolicy, categoryNeighbours, outsider, sizeof...(Ts), tables...)
926 {
927 if (!this->mIsEnd) {
928 setRanges();
929 }
930 }
931
932 CombinationsBlockStrictlyUpperSameIndexPolicy(const BP& binningPolicy, int categoryNeighbours, const T1& outsider, Ts&&... tables) : CombinationsBlockSameIndexPolicyBase<BP, T1, Ts...>(binningPolicy, categoryNeighbours, outsider, sizeof...(Ts), std::forward<Ts>(tables)...)
933 {
934 if (!this->mIsEnd) {
935 setRanges();
936 }
937 }
938
939 void setTables(const Ts&... tables)
940 {
942 if (!this->mIsEnd) {
943 setRanges();
944 }
945 }
946 void setTables(Ts&&... tables)
947 {
949 if (!this->mIsEnd) {
950 setRanges();
951 }
952 }
953
955 {
956 constexpr auto k = sizeof...(Ts);
957 auto catBegin = this->mGroupedIndices.begin() + std::get<0>(this->mCurrentIndices);
958 auto lastIt = std::upper_bound(catBegin, this->mGroupedIndices.end(), *catBegin, sameCategory);
959 uint64_t lastOffset = std::distance(this->mGroupedIndices.begin(), lastIt);
960
961 for_<k>([&, this](auto i) {
962 std::get<i.value>(this->mCurrentIndices) = std::get<0>(this->mCurrentIndices) + i.value;
963 std::get<i.value>(this->mCurrent).setCursor(this->mGroupedIndices[std::get<i.value>(this->mCurrentIndices)].index);
964 std::get<i.value>(this->mMaxOffset) = lastOffset - k + i.value + 1;
965 });
966 }
967
968 void addOne()
969 {
970 constexpr auto k = sizeof...(Ts);
971 bool modify = true;
972 for_<k - 1>([&, this](auto i) {
973 if (modify) {
974 constexpr auto curInd = k - i.value - 1;
975 std::get<curInd>(this->mCurrentIndices)++;
976 uint64_t curGroupedInd = std::get<curInd>(this->mCurrentIndices);
977 uint64_t maxForWindow = std::get<0>(this->mCurrentIndices) + this->mSlidingWindowSize - i.value;
978
979 // If we remain within the same sliding window
980 if (curGroupedInd < maxForWindow && curGroupedInd < std::get<curInd>(this->mMaxOffset)) {
981 std::get<curInd>(this->mCurrent).setCursor(this->mGroupedIndices[curGroupedInd].index);
982 for_<i.value>([&, this](auto j) {
983 constexpr auto curJ = k - i.value + j.value;
984 std::get<curJ>(this->mCurrentIndices) = std::get<curJ - 1>(this->mCurrentIndices) + 1;
985 uint64_t curGroupedJ = std::get<curJ>(this->mCurrentIndices);
986 std::get<curJ>(this->mCurrent).setCursor(this->mGroupedIndices[curGroupedJ].index);
987 });
988 modify = false;
989 }
990 }
991 });
992
993 this->mIsNewWindow = modify;
994
995 // First iterator processed separately
996 if (modify) {
997 std::get<0>(this->mCurrentIndices)++;
998 uint64_t curGroupedInd = std::get<0>(this->mCurrentIndices);
999
1000 // If we remain within the same category - slide window
1001 if (curGroupedInd < std::get<0>(this->mMaxOffset)) {
1002 std::get<0>(this->mCurrent).setCursor(this->mGroupedIndices[curGroupedInd].index);
1003 for_<k - 1>([&, this](auto j) {
1004 constexpr auto curJ = j.value + 1;
1005 std::get<curJ>(this->mCurrentIndices) = std::get<curJ - 1>(this->mCurrentIndices) + 1;
1006 uint64_t curGroupedJ = std::get<curJ>(this->mCurrentIndices);
1007 std::get<curJ>(this->mCurrent).setCursor(this->mGroupedIndices[curGroupedJ].index);
1008 });
1009 modify = false;
1010 }
1011 }
1012
1013 // No more combinations within this category - move to the next category, if possible
1014 if (modify && std::get<k - 1>(this->mCurrentIndices) < this->mGroupedIndices.size()) {
1015 for_<k>([&, this](auto m) {
1016 std::get<m.value>(this->mCurrentIndices) = std::get<m.value>(this->mMaxOffset) + k - 1;
1017 });
1018 setRanges();
1019 return;
1020 }
1021
1022 this->mIsEnd = modify;
1023 }
1024};
1025
1026template <typename BP, typename T1, typename... Ts>
1029
1030 CombinationsBlockFullSameIndexPolicy(const BP& binningPolicy, int categoryNeighbours, const T1& outsider) : CombinationsBlockSameIndexPolicyBase<BP, T1, Ts...>(binningPolicy, categoryNeighbours, outsider, 1), mCurrentlyFixed(0) {}
1031 CombinationsBlockFullSameIndexPolicy(const BP& binningPolicy, int categoryNeighbours, const T1& outsider, const Ts&... tables) : CombinationsBlockSameIndexPolicyBase<BP, T1, Ts...>(binningPolicy, categoryNeighbours, outsider, 1, tables...), mCurrentlyFixed(0)
1032 {
1033 if (!this->mIsEnd) {
1034 setRanges();
1035 }
1036 }
1037 CombinationsBlockFullSameIndexPolicy(const BP& binningPolicy, int categoryNeighbours, const T1& outsider, Ts&&... tables) : CombinationsBlockSameIndexPolicyBase<BP, T1, Ts...>(binningPolicy, categoryNeighbours, outsider, 1, std::forward<Ts>(tables)...), mCurrentlyFixed(0)
1038 {
1039 if (!this->mIsEnd) {
1040 setRanges();
1041 }
1042 }
1043
1044 void setTables(const Ts&... tables)
1045 {
1047 setRanges();
1048 }
1049 void setTables(Ts&&... tables)
1050 {
1052 setRanges();
1053 }
1054
1056 {
1057 constexpr auto k = sizeof...(Ts);
1058 auto catBegin = this->mGroupedIndices.begin() + std::get<0>(this->mCurrentIndices);
1059 auto range = std::equal_range(catBegin, this->mGroupedIndices.end(), *catBegin, sameCategory);
1060 this->mBeginIndex = std::get<0>(this->mCurrentIndices);
1061 uint64_t offset = std::distance(this->mGroupedIndices.begin(), range.second);
1062
1063 for_<k>([&, this](auto i) {
1064 std::get<i.value>(this->mMaxOffset) = offset;
1065 std::get<i.value>(this->mCurrentIndices) = this->mBeginIndex;
1066 std::get<i.value>(this->mCurrent).setCursor(range.first->index);
1067 });
1068 }
1069
1070 void addOne()
1071 {
1072 constexpr auto k = sizeof...(Ts);
1073 bool modify = true;
1074 for_<k>([&, this](auto i) {
1075 if (modify) {
1076 constexpr auto curInd = k - i.value - 1;
1077 std::get<curInd>(this->mCurrentIndices)++;
1078 uint64_t curGroupedInd = std::get<curInd>(this->mCurrentIndices);
1079 uint64_t windowOffset = curInd == this->mCurrentlyFixed ? 1 : this->mSlidingWindowSize;
1080 uint64_t maxForWindow = this->mBeginIndex + windowOffset;
1081
1082 // If we remain within the same sliding window and fixed index
1083 if (curGroupedInd < maxForWindow && curGroupedInd < std::get<curInd>(this->mMaxOffset)) {
1084 std::get<curInd>(this->mCurrent).setCursor(this->mGroupedIndices[curGroupedInd].index);
1085 for_<i.value>([&, this](auto j) {
1086 constexpr auto curJ = k - i.value + j.value;
1087 if (curJ < this->mCurrentlyFixed) { // To assure no repetitions
1088 std::get<curJ>(this->mCurrentIndices) = this->mBeginIndex + 1;
1089 } else {
1090 std::get<curJ>(this->mCurrentIndices) = this->mBeginIndex;
1091 }
1092 uint64_t curGroupedJ = std::get<curJ>(this->mCurrentIndices);
1093 std::get<curJ>(this->mCurrent).setCursor(this->mGroupedIndices[curGroupedJ].index);
1094 });
1095 modify = false;
1096 }
1097 }
1098 });
1099
1100 // Currently fixed iterator processed separately
1101 if (modify) {
1102 // If we haven't finished with window starting element
1103 if (this->mCurrentlyFixed < k - 1 && this->mBeginIndex < std::get<0>(this->mMaxOffset) - 1) {
1104 this->mCurrentlyFixed++;
1105 for_<k>([&, this](auto s) {
1106 if (s.value < this->mCurrentlyFixed) { // To assure no repetitions
1107 std::get<s.value>(this->mCurrentIndices) = this->mBeginIndex + 1;
1108 } else {
1109 std::get<s.value>(this->mCurrentIndices) = this->mBeginIndex;
1110 }
1111 uint64_t curGroupedI = std::get<s.value>(this->mCurrentIndices);
1112 std::get<s.value>(this->mCurrent).setCursor(this->mGroupedIndices[curGroupedI].index);
1113 });
1114 modify = false;
1115 } else {
1116 this->mCurrentlyFixed = 0;
1117 this->mBeginIndex++;
1118 std::get<0>(this->mCurrentIndices) = this->mBeginIndex;
1119
1120 // If we remain within the same category - slide window
1121 if (this->mBeginIndex < std::get<0>(this->mMaxOffset)) {
1122 uint64_t curGroupedInd = std::get<0>(this->mCurrentIndices);
1123 std::get<0>(this->mCurrent).setCursor(this->mGroupedIndices[curGroupedInd].index);
1124 for_<k - 1>([&, this](auto j) {
1125 constexpr auto curJ = j.value + 1;
1126 std::get<curJ>(this->mCurrentIndices) = this->mBeginIndex;
1127 uint64_t curGroupedJ = std::get<curJ>(this->mCurrentIndices);
1128 std::get<curJ>(this->mCurrent).setCursor(this->mGroupedIndices[curGroupedJ].index);
1129 });
1130 modify = false;
1131 } else {
1132 for_<k>([&, this](auto j) {
1133 std::get<j.value>(this->mCurrentIndices) = std::get<j.value>(this->mMaxOffset);
1134 });
1135 }
1136 }
1137 }
1138
1139 // No more combinations within this category - move to the next category, if possible
1140 if (modify && std::get<0>(this->mCurrentIndices) < this->mGroupedIndices.size()) {
1141 setRanges();
1142 return;
1143 }
1144
1145 this->mIsEnd = modify;
1146 }
1147
1148 uint64_t mBeginIndex;
1150};
1151
1154template <typename P>
1156 using CombinationType = typename P::CombinationType;
1157
1158 public:
1159 struct CombinationsIterator : public P {
1160 public:
1164 using iterator_category = std::forward_iterator_tag;
1165
1167
1168 CombinationsIterator(const P& policy) : P(policy) {}
1169
1173
1174 // prefix increment
1176 {
1177 if (!this->mIsEnd) {
1178 this->addOne();
1179 }
1180 return *this;
1181 }
1182 // postfix increment
1184 {
1185 CombinationsIterator copy(*this);
1186 operator++();
1187 return copy;
1188 }
1189 // return reference
1191 {
1192 return this->mCurrent;
1193 }
1194 friend bool operator==(const CombinationsIterator& lh, const CombinationsIterator& rh)
1195 {
1196 return (lh.mIsEnd && rh.mIsEnd) || (lh.mCurrent == rh.mCurrent);
1197 }
1198 };
1199
1202
1204 {
1205 return iterator(mBegin);
1206 }
1207 inline iterator end()
1208 {
1209 return iterator(mEnd);
1210 }
1211 inline const_iterator begin() const
1212 {
1213 return iterator(mBegin);
1214 }
1215 inline const_iterator end() const
1216 {
1217 return iterator(mEnd);
1218 }
1219
1221 CombinationsGenerator(const P& policy) : mBegin(policy), mEnd(policy)
1222 {
1223 mEnd.moveToEnd();
1224 }
1226
1227 private:
1228 iterator mBegin;
1229 iterator mEnd;
1230};
1231
1232template <typename T2, typename... T2s>
1233constexpr bool isSameType()
1234{
1235 return (std::same_as<T2, T2s> && ...);
1236}
1237
1238template <typename BP, typename T1, typename... T2s>
1239auto selfCombinations(const BP& binningPolicy, int categoryNeighbours, const T1& outsider, const T2s&... tables)
1240{
1241 static_assert(isSameType<T2s...>(), "Tables must have the same type for self combinations");
1242 return CombinationsGenerator<CombinationsBlockStrictlyUpperSameIndexPolicy<BP, T1, T2s...>>(CombinationsBlockStrictlyUpperSameIndexPolicy<BP, T1, T2s...>(binningPolicy, categoryNeighbours, outsider, tables...));
1243}
1244
1245template <typename BP, typename T1, typename T2>
1246auto selfPairCombinations(const BP& binningPolicy, int categoryNeighbours, const T1& outsider)
1247{
1249}
1250
1251template <typename BP, typename T1, typename T2>
1252auto selfPairCombinations(const BP& binningPolicy, int categoryNeighbours, const T1& outsider, const T2& table)
1253{
1255}
1256
1257template <typename BP, typename T1, typename T2>
1258auto selfTripleCombinations(const BP& binningPolicy, int categoryNeighbours, const T1& outsider)
1259{
1261}
1262
1263template <typename BP, typename T1, typename T2>
1264auto selfTripleCombinations(const BP& binningPolicy, int categoryNeighbours, const T1& outsider, const T2& table)
1265{
1267}
1268
1269template <typename BP, typename T1, typename... T2s>
1270auto combinations(const BP& binningPolicy, int categoryNeighbours, const T1& outsider, const T2s&... tables)
1271{
1272 if constexpr (isSameType<T2s...>()) {
1273 return CombinationsGenerator<CombinationsBlockStrictlyUpperSameIndexPolicy<BP, T1, T2s...>>(CombinationsBlockStrictlyUpperSameIndexPolicy<BP, T1, T2s...>(binningPolicy, categoryNeighbours, outsider, tables...));
1274 } else {
1275 return CombinationsGenerator<CombinationsBlockUpperIndexPolicy<BP, T1, T2s...>>(CombinationsBlockUpperIndexPolicy<BP, T1, T2s...>(binningPolicy, categoryNeighbours, outsider, tables...));
1276 }
1277}
1278
1279template <typename BP, typename T1, typename... T2s>
1280auto combinations(const BP& binningPolicy, int categoryNeighbours, const T1& outsider, const o2::framework::expressions::Filter& filter, const T2s&... tables)
1281{
1282 if constexpr (isSameType<T2s...>()) {
1284 } else {
1285 return CombinationsGenerator<CombinationsBlockUpperIndexPolicy<BP, T1, Filtered<T2s>...>>(CombinationsBlockUpperIndexPolicy(binningPolicy, categoryNeighbours, outsider, tables.select(filter)...));
1286 }
1287}
1288
1289template <soa::is_table... T2s>
1291{
1292 if constexpr (isSameType<T2s...>()) {
1294 } else {
1296 }
1297}
1298
1299// This shortened version cannot be used for Filtered
1300// (unless users create filtered tables themselves before policy creation)
1301template <template <typename...> typename P2, typename... T2s>
1302CombinationsGenerator<P2<T2s...>> combinations(const P2<T2s...>& policy)
1303{
1304 return CombinationsGenerator<P2<T2s...>>(policy);
1305}
1306
1307template <template <typename...> typename P2, soa::is_table... T2s>
1309{
1310 return CombinationsGenerator<P2<Filtered<T2s>...>>(P2<Filtered<T2s>...>(tables.select(filter)...));
1311}
1312
1313template <typename... T2s>
1314auto combinations(const T2s&... tables)
1315{
1316 if constexpr (isSameType<T2s...>()) {
1318 } else {
1320 }
1321}
1322
1323template <typename T2>
1328
1329template <typename T2>
1334
1335template <typename T2>
1340
1341template <typename T2>
1346
1347} // namespace o2::soa
1348
1349#endif // O2_FRAMEWORK_ASOAHELPERS_H_
int32_t i
uint32_t j
Definition RawData.h:0
GLint GLenum GLint x
Definition glcorearb.h:403
const GLfloat * m
Definition glcorearb.h:4066
GLenum func
Definition glcorearb.h:778
GLsizeiptr size
Definition glcorearb.h:659
GLuint GLuint end
Definition glcorearb.h:469
GLuint index
Definition glcorearb.h:781
GLboolean GLboolean GLboolean b
Definition glcorearb.h:1233
GLenum GLint * range
Definition glcorearb.h:1899
GLsizei const GLfloat * value
Definition glcorearb.h:819
GLint GLint GLsizei GLint GLenum GLenum type
Definition glcorearb.h:275
GLenum GLsizei GLsizei GLint * values
Definition glcorearb.h:1576
GLintptr offset
Definition glcorearb.h:660
typedef void(APIENTRYP PFNGLCULLFACEPROC)(GLenum mode)
GLuint GLfloat * val
Definition glcorearb.h:1582
GLint GLint GLint GLint GLint GLint GLint GLbitfield GLenum filter
Definition glcorearb.h:1308
GLboolean GLboolean GLboolean GLboolean a
Definition glcorearb.h:1233
constexpr bool isSameType()
bool diffCategory(BinningIndex const &a, BinningIndex const &b)
Definition ASoAHelpers.h:69
void syncCategories(std::array< std::vector< BinningIndex >, K > &groupedIndices)
auto pairCombinations()
auto selfTripleCombinations(const BP &binningPolicy, int categoryNeighbours, const T1 &outsider)
auto tripleCombinations()
std::vector< BinningIndex > groupTable(const T &table, const BP< Cs... > &binningPolicy, int minCatSize, int outsider)
Definition ASoAHelpers.h:77
auto combinations(const BP &binningPolicy, int categoryNeighbours, const T1 &outsider, const T2s &... tables)
auto selfCombinations(const BP &binningPolicy, int categoryNeighbours, const T1 &outsider, const T2s &... tables)
void for_(F func, std::index_sequence< Is... >)
Definition ASoAHelpers.h:32
auto selfPairCombinations(const BP &binningPolicy, int categoryNeighbours, const T1 &outsider)
void dataSizeVariesBetweenColumns()
bool sameCategory(BinningIndex const &a, BinningIndex const &b)
Definition ASoAHelpers.h:65
Defining DataPointCompositeObject explicitly as copiable.
A struct, containing the root of the expression tree.
bool operator<(const BinningIndex &rhs) const
Definition ASoAHelpers.h:58
BinningIndex(int bin_, uint64_t index_)
Definition ASoAHelpers.h:56
CombinationsBlockFullIndexPolicy(const BP &binningPolicy, int categoryNeighbours, const T &outsider, Ts &&... tables)
typename CombinationsBlockIndexPolicyBase< BP, T, Ts... >::CombinationType CombinationType
CombinationsBlockFullIndexPolicy(const BP &binningPolicy, int categoryNeighbours, const T &outsider, const Ts &... tables)
void setTables(const Ts &... tables)
CombinationsBlockFullIndexPolicy(const BP &binningPolicy, int categoryNeighbours, const T &outsider)
typename NTupleType< uint64_t, sizeof...(Ts)>::type IndicesType
CombinationsBlockFullSameIndexPolicy(const BP &binningPolicy, int categoryNeighbours, const T1 &outsider, Ts &&... tables)
CombinationsBlockFullSameIndexPolicy(const BP &binningPolicy, int categoryNeighbours, const T1 &outsider)
CombinationsBlockFullSameIndexPolicy(const BP &binningPolicy, int categoryNeighbours, const T1 &outsider, const Ts &... tables)
typename CombinationsBlockSameIndexPolicyBase< BP, T1, Ts... >::CombinationType CombinationType
std::array< std::vector< BinningIndex >, sizeof...(Ts)> mGroupedIndices
void setRanges(const Ts &... tables)
typename CombinationsIndexPolicyBase< Ts... >::CombinationType CombinationType
CombinationsBlockIndexPolicyBase(const BP &binningPolicy, int categoryNeighbours, const T &outsider, const Ts &... tables)
CombinationsBlockIndexPolicyBase(const BP &binningPolicy, int categoryNeighbours, const T &outsider)
void setTables(const Ts &... tables)
typename NTupleType< uint64_t, sizeof...(Ts)>::type IndicesType
CombinationsBlockIndexPolicyBase(const BP &binningPolicy, int categoryNeighbours, const T &outsider, Ts &&... tables)
CombinationsBlockSameIndexPolicyBase(const BP &binningPolicy, int categoryNeighbours, const T1 &outsider, int minWindowSize)
void setTables(T &&table, Ts &&... tables)
CombinationsBlockSameIndexPolicyBase(const BP &binningPolicy, int categoryNeighbours, const T1 &outsider, int minWindowSize, const T &table, const Ts &... tables)
void setTables(const T &table, const Ts &... tables)
CombinationsBlockSameIndexPolicyBase(const BP &binningPolicy, int categoryNeighbours, const T1 &outsider, int minWindowSize, T &&table, Ts &&... tables)
std::vector< BinningIndex > mGroupedIndices
typename CombinationsIndexPolicyBase< T, Ts... >::CombinationType CombinationType
typename NTupleType< uint64_t, sizeof...(Ts)+1 >::type IndicesType
CombinationsBlockStrictlyUpperSameIndexPolicy(const BP &binningPolicy, int categoryNeighbours, const T1 &outsider, Ts &&... tables)
CombinationsBlockStrictlyUpperSameIndexPolicy(const BP &binningPolicy, int categoryNeighbours, const T1 &outsider, const Ts &... tables)
CombinationsBlockStrictlyUpperSameIndexPolicy(const BP &binningPolicy, int categoryNeighbours, const T1 &outsider)
typename CombinationsBlockSameIndexPolicyBase< BP, T1, Ts... >::CombinationType CombinationType
CombinationsBlockUpperIndexPolicy(const BP &binningPolicy, int categoryNeighbours, const T &outsider, Ts &&... tables)
CombinationsBlockUpperIndexPolicy(const BP &binningPolicy, int categoryNeighbours, const T &outsider, const Ts &... tables)
void setTables(const Ts &... tables)
typename CombinationsBlockIndexPolicyBase< BP, T, Ts... >::CombinationType CombinationType
CombinationsBlockUpperIndexPolicy(const BP &binningPolicy, int categoryNeighbours, const T &outsider)
CombinationsBlockUpperSameIndexPolicy(const BP &binningPolicy, int categoryNeighbours, const T1 &outsider, Ts &&... tables)
CombinationsBlockUpperSameIndexPolicy(const BP &binningPolicy, int categoryNeighbours, const T1 &outsider, const Ts &... tables)
CombinationsBlockUpperSameIndexPolicy(const BP &binningPolicy, int categoryNeighbours, const T1 &outsider)
typename CombinationsBlockSameIndexPolicyBase< BP, T1, Ts... >::CombinationType CombinationType
CombinationsFullIndexPolicy(Ts &&... tables)
typename CombinationsIndexPolicyBase< Ts... >::CombinationType CombinationType
CombinationsFullIndexPolicy(const Ts &... tables)
CombinationsIterator(CombinationsIterator const &)=default
CombinationsIterator & operator=(CombinationsIterator const &)=default
friend bool operator==(const CombinationsIterator &lh, const CombinationsIterator &rh)
const_iterator begin() const
const_iterator end() const
CombinationsGenerator(const P &policy)
CombinationsIterator iterator
typename P::CombinationType CombinationType
std::shared_ptr< std::tuple< Ts... > > mTables
CombinationsIndexPolicyBase(Tss &&... tables)
void setTables(const Ts &... tables)
typename NTupleType< uint64_t, sizeof...(Ts)>::type IndicesType
void setTables(Tss &&... tables)
CombinationsIndexPolicyBase(const Tss &... tables)
std::tuple< typename Ts::iterator... > CombinationType
typename CombinationsIndexPolicyBase< Ts... >::CombinationType CombinationType
CombinationsStrictlyUpperIndexPolicy(const Ts &... tables)
typename CombinationsIndexPolicyBase< Ts... >::CombinationType CombinationType
CombinationsUpperIndexPolicy(Ts &&... tables)
CombinationsUpperIndexPolicy(const Ts &... tables)
typename NTupleType< T, N - 1, T, REST... >::type type
Definition ASoAHelpers.h:47