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 arrow::Table* arrowTable = table.asArrowTable().get();
80 auto rowIterator = table.begin();
81
82 uint64_t ind = 0;
83 uint64_t selInd = 0;
84 gsl::span<int64_t const> selectedRows;
85 std::vector<BinningIndex> groupedIndices;
86
87 // Separate check to account for Filtered size different from arrow table
88 if (table.size() == 0) {
89 return groupedIndices;
90 }
91
92 if constexpr (soa::is_filtered_table<T>) {
93 selectedRows = table.getSelectedRows(); // vector<int64_t>
94 }
95
96 auto persistentColumns = typename BP<Cs...>::persistent_columns_t{};
97 constexpr auto persistentColumnsCount = pack_size(persistentColumns);
98 auto arrowColumns = o2::soa::row_helpers::getArrowColumns(arrowTable, persistentColumns);
99 auto chunksCount = arrowColumns[0]->num_chunks();
100 for (int i = 1; i < persistentColumnsCount; i++) {
101 if (arrowColumns[i]->num_chunks() != chunksCount) {
103 }
104 }
105
106 for (uint64_t ci = 0; ci < chunksCount; ++ci) {
107 auto chunks = o2::soa::row_helpers::getChunks(arrowTable, persistentColumns, ci);
108 auto chunkLength = std::get<0>(chunks)->length();
109 for_<persistentColumnsCount - 1>([&chunks, &chunkLength](auto i) {
110 if (std::get<i.value + 1>(chunks)->length() != chunkLength) {
112 }
113 });
114
115 if constexpr (soa::is_filtered_table<T>) {
116 if (selectedRows[ind] >= selInd + chunkLength) {
117 selInd += chunkLength;
118 continue; // Go to the next chunk, no value selected in this chunk
119 }
120 }
121
122 uint64_t ai = 0;
123 while (ai < chunkLength) {
124 if constexpr (soa::is_filtered_table<T>) {
125 ai += selectedRows[ind] - selInd;
126 selInd = selectedRows[ind];
127 }
128
129 auto values = binningPolicy.getBinningValues(rowIterator, arrowTable, ci, ai, ind);
130 auto val = binningPolicy.getBin(values);
131 if (val != outsider) {
132 groupedIndices.emplace_back(val, ind);
133 }
134 ind++;
135
136 if constexpr (soa::is_filtered_table<T>) {
137 if (ind >= selectedRows.size()) {
138 break;
139 }
140 } else {
141 ai++;
142 }
143 }
144
145 if constexpr (soa::is_filtered_table<T>) {
146 if (ind == selectedRows.size()) {
147 break;
148 }
149 }
150 }
151
152 // Do a stable sort so that same categories entries are
153 // grouped together.
154 std::stable_sort(groupedIndices.begin(), groupedIndices.end());
155
156 // Remove categories of too small size
157 if (minCatSize > 1) {
158 auto catBegin = groupedIndices.begin();
159 while (catBegin != groupedIndices.end()) {
160 auto catEnd = std::upper_bound(catBegin, groupedIndices.end(), *catBegin, sameCategory);
161 if (std::distance(catBegin, catEnd) < minCatSize) {
162 catEnd = groupedIndices.erase(catBegin, catEnd);
163 }
164 catBegin = catEnd;
165 }
166 }
167
168 return groupedIndices;
169}
170
171// Synchronize categories so as groupedIndices contain elements only of categories common to all tables
172template <std::size_t K>
173void syncCategories(std::array<std::vector<BinningIndex>, K>& groupedIndices)
174{
175 std::vector<BinningIndex> firstCategories;
176 std::vector<BinningIndex> commonCategories;
177 std::unique_copy(groupedIndices[0].begin(), groupedIndices[0].end(), std::back_inserter(firstCategories), diffCategory);
178
179 for (auto& cat : firstCategories) {
180 bool isCommon = true;
181 for (int i = 1; i < K; i++) {
182 if (!std::binary_search(groupedIndices[i].begin(), groupedIndices[i].end(), cat, sameCategory)) {
183 isCommon = false;
184 break;
185 }
186 }
187 if (isCommon) {
188 commonCategories.push_back(cat);
189 }
190 }
191
192 for (int i = 0; i < K; i++) {
193 auto nonCatBegin = groupedIndices[i].begin();
194 for (auto& cat : commonCategories) {
195 auto nonCatEnd = std::lower_bound(nonCatBegin, groupedIndices[i].end(), cat, sameCategory);
196 nonCatEnd = groupedIndices[i].erase(nonCatBegin, nonCatEnd);
197 nonCatBegin = std::upper_bound(nonCatEnd, groupedIndices[i].end(), cat, sameCategory);
198 }
199 }
200}
201
202template <typename... Ts>
204 using CombinationType = std::tuple<typename Ts::iterator...>;
205 using IndicesType = typename NTupleType<uint64_t, sizeof...(Ts)>::type;
206
208 template <typename... Tss>
209 CombinationsIndexPolicyBase(const Tss&... tables) : mIsEnd(false),
210 mMaxOffset(tables.end().index...),
211 mCurrent(tables.begin()...)
212 {
213 if (((tables.size() == 0) || ...)) {
214 this->mIsEnd = true;
215 }
216 }
217 template <typename... Tss>
218 CombinationsIndexPolicyBase(Tss&&... tables) : mTables(std::make_shared<std::tuple<Tss...>>(std::make_tuple(std::move(tables)...))),
219 mIsEnd(false)
220 {
221 std::apply([&](auto&&... x) mutable { mMaxOffset = IndicesType{x.end().index...}; mCurrent = CombinationType{x.begin()...}; }, *mTables);
222 if (
223 std::apply([](auto&&... x) -> bool { return ((x.size() == 0) || ...); }, *mTables)) {
224 this->mIsEnd = true;
225 }
226 }
227
228 void setTables(const Ts&... tables)
229 {
230 mIsEnd = false;
231 mMaxOffset = IndicesType(tables.end().index...);
232 mCurrent = CombinationType(tables.begin()...);
233 if (((tables.size() == 0) || ...)) {
234 this->mIsEnd = true;
235 }
236 }
237 template <typename... Tss>
238 void setTables(Tss&&... tables)
239 {
240 mIsEnd = false;
241 mTables = std::make_shared<std::tuple<Tss...>>(std::make_tuple(std::move(tables)...));
242 std::apply([&](auto&&... x) mutable { mMaxOffset = IndicesType{x.end().index...}; mCurrent = CombinationType{x.begin()...}; }, *mTables);
243 if (
244 std::apply([](auto&&... x) -> bool { return ((x.size() == 0) || ...); }, *mTables)) {
245 this->mIsEnd = true;
246 }
247 }
248
250 {
251 constexpr auto k = sizeof...(Ts);
252 for_<k>([&, this](auto i) {
253 std::get<i.value>(this->mCurrent).moveToEnd();
254 });
255 this->mIsEnd = true;
256 }
257
258 void addOne() {}
259
260 std::shared_ptr<std::tuple<Ts...>> mTables;
262 IndicesType mMaxOffset; // one position past maximum acceptable position for each element of combination
263 bool mIsEnd; // whether there are any more tuples available
264};
265
266template <typename... Ts>
268
269template <typename... Ts>
271
272template <typename... Ts>
275
277 CombinationsUpperIndexPolicy(const Ts&... tables) : CombinationsIndexPolicyBase<Ts...>(tables...) {}
278 CombinationsUpperIndexPolicy(Ts&&... tables) : CombinationsIndexPolicyBase<Ts...>(std::forward<Ts>(tables)...) {}
279
280 void addOne()
281 {
282 constexpr auto k = sizeof...(Ts);
283 bool modify = true;
284 for_<k>([&, this](auto i) {
285 if (modify) {
286 constexpr auto curInd = k - i.value - 1;
287 std::get<curInd>(this->mCurrent)++;
288 if (*std::get<1>(std::get<curInd>(this->mCurrent).getIndices()) != std::get<curInd>(this->mMaxOffset)) {
289 modify = false;
290 for_<i.value>([&, this](auto j) {
291 constexpr auto curJ = k - i.value + j.value;
292 int64_t nextInd = *std::get<1>(std::get<curJ - 1>(this->mCurrent).getIndices());
293 if (nextInd < std::get<curJ>(this->mMaxOffset)) {
294 std::get<curJ>(this->mCurrent).setCursor(nextInd);
295 } else {
296 modify = true;
297 }
298 });
299 }
300 }
301 });
302 this->mIsEnd = modify;
303 }
304};
305
306template <typename... Ts>
309
312 {
313 if (!this->mIsEnd) {
314 setRanges(tables...);
315 }
316 }
318 {
319 if (!this->mIsEnd) {
320 setRanges();
321 }
322 }
323
324 void setTables(const Ts&... tables)
325 {
327 setRanges(tables...);
328 }
329 void setTables(Ts&&... tables)
330 {
331 CombinationsIndexPolicyBase<Ts...>::setTables(std::forward<Ts>(tables)...);
332 setRanges(tables...);
333 }
334
335 void setRanges(const Ts&... tables)
336 {
337 constexpr auto k = sizeof...(Ts);
338 if (((tables.size() < k) || ...)) {
339 this->mIsEnd = true;
340 return;
341 }
342 for_<k>([&, this](auto i) {
343 std::get<i.value>(this->mMaxOffset) += i.value + 1 - k;
344 std::get<i.value>(this->mCurrent).moveByIndex(i.value);
345 });
346 }
348 {
349 constexpr auto k = sizeof...(Ts);
350 if (
351 std::apply([](auto&&... x) -> bool { return ((x.size() < k) || ...); }, *this->mTables)) {
352 this->mIsEnd = true;
353 return;
354 }
355 for_<k>([&, this](auto i) {
356 std::get<i.value>(this->mMaxOffset) += i.value + 1 - k;
357 std::get<i.value>(this->mCurrent).moveByIndex(i.value);
358 });
359 }
360
361 void addOne()
362 {
363 constexpr auto k = sizeof...(Ts);
364 bool modify = true;
365 for_<k>([&, this](auto i) {
366 if (modify) {
367 constexpr auto curInd = k - i.value - 1;
368 std::get<curInd>(this->mCurrent)++;
369 if (*std::get<1>(std::get<curInd>(this->mCurrent).getIndices()) != std::get<curInd>(this->mMaxOffset)) {
370 modify = false;
371 for_<i.value>([&, this](auto j) {
372 constexpr auto curJ = k - i.value + j.value;
373 int64_t nextInd = *std::get<1>(std::get<curJ - 1>(this->mCurrent).getIndices()) + 1;
374 if (nextInd < std::get<curJ>(this->mMaxOffset)) {
375 std::get<curJ>(this->mCurrent).setCursor(nextInd);
376 } else {
377 modify = true;
378 }
379 });
380 }
381 }
382 });
383 this->mIsEnd = modify;
384 }
385};
386
387template <typename... Ts>
390
392 CombinationsFullIndexPolicy(const Ts&... tables) : CombinationsIndexPolicyBase<Ts...>(tables...) {}
393 CombinationsFullIndexPolicy(Ts&&... tables) : CombinationsIndexPolicyBase<Ts...>(std::forward<Ts>(tables)...) {}
394
395 void addOne()
396 {
397 constexpr auto k = sizeof...(Ts);
398 bool modify = true;
399 for_<k>([&, this](auto i) {
400 if (modify) {
401 constexpr auto curInd = k - i.value - 1;
402 std::get<curInd>(this->mCurrent)++;
403 if (*std::get<1>(std::get<curInd>(this->mCurrent).getIndices()) != std::get<curInd>(this->mMaxOffset)) {
404 for_<i.value>([&, this](auto j) {
405 constexpr auto curJ = k - i.value + j.value;
406 std::get<curJ>(this->mCurrent).setCursor(0);
407 });
408 modify = false;
409 }
410 }
411 });
412 this->mIsEnd = modify;
413 }
414};
415
416// For upper and full only
417template <typename BP, typename T, typename... Ts>
420 using IndicesType = typename NTupleType<uint64_t, sizeof...(Ts)>::type;
421
422 CombinationsBlockIndexPolicyBase(const BP& binningPolicy, int categoryNeighbours, const T& outsider) : CombinationsIndexPolicyBase<Ts...>(), mSlidingWindowSize(categoryNeighbours + 1), mBP(binningPolicy), mCategoryNeighbours(categoryNeighbours), mOutsider(outsider), mIsNewWindow(true) {}
423 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)
424 {
425 if (!this->mIsEnd) {
426 setRanges(tables...);
427 }
428 }
429 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)
430 {
431 if (!this->mIsEnd) {
432 setRanges();
433 }
434 }
435
436 void setTables(const Ts&... tables)
437 {
439 setRanges(tables...);
440 }
441 void setTables(Ts&&... tables)
442 {
443 CombinationsIndexPolicyBase<Ts...>::setTables(std::forward<Ts>(tables)...);
444 setRanges();
445 }
446
447 void setRanges(const Ts&... tables)
448 {
449 constexpr auto k = sizeof...(Ts);
450 if (mSlidingWindowSize < 1) {
451 this->mIsEnd = true;
452 return;
453 }
454
455 int tableIndex = 0;
456 ((this->mGroupedIndices[tableIndex++] = groupTable(tables, this->mBP, 1, this->mOutsider)), ...);
457
458 // Synchronize categories across tables
460
461 for (int i = 0; i < k; i++) {
462 if (this->mGroupedIndices[i].size() == 0) {
463 this->mIsEnd = true;
464 return;
465 }
466 }
467
468 for_<k>([this](auto i) {
469 std::get<i.value>(this->mCurrentIndices) = 0;
470 });
471 }
472 void setRanges(Ts&&... tables)
473 {
474 constexpr auto k = sizeof...(Ts);
475 if (this->mIsEnd) {
476 return;
477 }
478 if (mSlidingWindowSize < 1) {
479 this->mIsEnd = true;
480 return;
481 }
482
483 int tableIndex = 0;
484 std::apply([&, this](auto&&... x) mutable {
485 ((this->mGroupedIndices[tableIndex++] = groupTable(x, this->mBP, 1, this->mOutsider)), ...);
486 },
487 *this->mTables);
488
489 // Synchronize categories across tables
491
492 for (int i = 0; i < k; i++) {
493 if (this->mGroupedIndices[i].size() == 0) {
494 this->mIsEnd = true;
495 return;
496 }
497 }
498
499 for_<k>([this](auto i) {
500 std::get<i.value>(this->mCurrentIndices) = 0;
501 });
502 }
503
505 {
506 // NOTE: The same number of currentWindowNeighbours is returned for all kinds of block combinations.
507 // Strictly upper: the first element will is paired with exactly currentWindowNeighbours other elements.
508 // Upper: the first element is paired with (currentWindowNeighbours + 1) elements, including itself.
509 // Full: (currentWindowNeighbours + 1) pairs with the first element in the first position (c1)
510 // + there are other combinations with the first element at other positions.
511 if (this->mIsEnd) {
512 return 0;
513 }
514 uint64_t maxForWindow = std::get<0>(this->mBeginIndices) + this->mSlidingWindowSize - 1;
515 uint64_t maxForTable = std::get<0>(this->mMaxOffset);
516 uint64_t currentMax = maxForWindow < maxForTable ? maxForWindow : maxForTable;
517 return currentMax - std::get<0>(mCurrentIndices);
518 }
519
521 {
522 return mIsNewWindow;
523 }
524
525 std::array<std::vector<BinningIndex>, sizeof...(Ts)> mGroupedIndices;
529 const BP mBP;
531 const T mOutsider;
533};
534
535template <typename BP, typename T, typename... Ts>
538
539 CombinationsBlockUpperIndexPolicy(const BP& binningPolicy, int categoryNeighbours, const T& outsider) : CombinationsBlockIndexPolicyBase<BP, T, Ts...>(binningPolicy, categoryNeighbours, outsider) {}
540 CombinationsBlockUpperIndexPolicy(const BP& binningPolicy, int categoryNeighbours, const T& outsider, const Ts&... tables) : CombinationsBlockIndexPolicyBase<BP, T, Ts...>(binningPolicy, categoryNeighbours, outsider, tables...)
541 {
542 if (!this->mIsEnd) {
543 setRanges();
544 }
545 }
546 CombinationsBlockUpperIndexPolicy(const BP& binningPolicy, int categoryNeighbours, const T& outsider, Ts&&... tables) : CombinationsBlockIndexPolicyBase<BP, T, Ts...>(binningPolicy, categoryNeighbours, outsider, std::forward<Ts>(tables)...)
547 {
548 if (!this->mIsEnd) {
549 setRanges();
550 }
551 }
552
553 void setTables(const Ts&... tables)
554 {
556 setRanges();
557 }
558 void setTables(Ts&&... tables)
559 {
561 setRanges();
562 }
563
565 {
566 constexpr auto k = sizeof...(Ts);
567 for_<k>([&, this](auto i) {
568 auto catBegin = this->mGroupedIndices[i.value].begin() + std::get<i.value>(this->mCurrentIndices);
569 auto range = std::equal_range(catBegin, this->mGroupedIndices[i.value].end(), *catBegin, sameCategory);
570 std::get<i.value>(this->mBeginIndices) = std::distance(this->mGroupedIndices[i.value].begin(), range.first);
571 std::get<i.value>(this->mCurrent).setCursor(range.first->index);
572 std::get<i.value>(this->mMaxOffset) = std::distance(this->mGroupedIndices[i.value].begin(), range.second);
573 });
574 }
575
576 void addOne()
577 {
578 constexpr auto k = sizeof...(Ts);
579 bool modify = true;
580 bool nextCatAvailable = true;
581 for_<k - 1>([&, this](auto i) {
582 if (modify) {
583 constexpr auto curInd = k - i.value - 1;
584 std::get<curInd>(this->mCurrentIndices)++;
585 uint64_t curGroupedInd = std::get<curInd>(this->mCurrentIndices);
586 uint64_t maxForWindow = std::get<curInd>(this->mBeginIndices) + this->mSlidingWindowSize;
587
588 // If we remain within the same sliding window
589 if (curGroupedInd < maxForWindow && curGroupedInd < std::get<curInd>(this->mMaxOffset)) {
590 std::get<curInd>(this->mCurrent).setCursor(this->mGroupedIndices[curInd][curGroupedInd].index);
591 modify = false;
592 for_<i.value>([&, this](auto j) {
593 constexpr auto curJ = k - i.value + j.value;
594 if (std::get<curJ - 1>(this->mCurrentIndices) < std::get<curJ>(this->mMaxOffset)) {
595 std::get<curJ>(this->mCurrentIndices) = std::get<curJ - 1>(this->mCurrentIndices);
596 uint64_t curGroupedJ = std::get<curJ>(this->mCurrentIndices);
597 std::get<curJ>(this->mCurrent).setCursor(this->mGroupedIndices[curJ][curGroupedJ].index);
598 } else {
599 modify = true;
600 }
601 });
602 }
603 }
604 });
605
606 this->mIsNewWindow = modify;
607
608 // First iterator processed separately
609 if (modify) {
610 std::get<0>(this->mCurrentIndices)++;
611 std::get<0>(this->mBeginIndices)++;
612 uint64_t curGroupedInd = std::get<0>(this->mCurrentIndices);
613
614 // If we remain within the same category - slide window
615 if (curGroupedInd < std::get<0>(this->mMaxOffset)) {
616 std::get<0>(this->mCurrent).setCursor(this->mGroupedIndices[0][curGroupedInd].index);
617 modify = false;
618 for_<k - 1>([&, this](auto j) {
619 constexpr auto curJ = j.value + 1;
620 std::get<curJ>(this->mBeginIndices)++;
621 if (std::get<curJ>(this->mBeginIndices) < std::get<curJ>(this->mMaxOffset)) {
622 std::get<curJ>(this->mCurrentIndices) = std::get<curJ>(this->mBeginIndices);
623 uint64_t curGroupedJ = std::get<curJ>(this->mCurrentIndices);
624 std::get<curJ>(this->mCurrent).setCursor(this->mGroupedIndices[curJ][curGroupedJ].index);
625 } else {
626 modify = true;
627 }
628 });
629 }
630 }
631
632 // No more combinations within this category - move to the next category, if possible
633 if (modify) {
634 for_<k>([&, this](auto m) {
635 std::get<m.value>(this->mCurrentIndices) = std::get<m.value>(this->mMaxOffset);
636 if (std::get<m.value>(this->mCurrentIndices) == this->mGroupedIndices[m.value].size()) {
637 nextCatAvailable = false;
638 }
639 });
640 if (nextCatAvailable) {
641 setRanges();
642 }
643 }
644
645 this->mIsEnd = modify && !nextCatAvailable;
646 }
647};
648
649template <typename BP, typename T, typename... Ts>
652 using IndicesType = typename NTupleType<uint64_t, sizeof...(Ts)>::type;
653
654 CombinationsBlockFullIndexPolicy(const BP& binningPolicy, int categoryNeighbours, const T& outsider) : CombinationsBlockIndexPolicyBase<BP, T, Ts...>(binningPolicy, categoryNeighbours, outsider), mCurrentlyFixed(0) {}
655 CombinationsBlockFullIndexPolicy(const BP& binningPolicy, int categoryNeighbours, const T& outsider, const Ts&... tables) : CombinationsBlockIndexPolicyBase<BP, T, Ts...>(binningPolicy, categoryNeighbours, outsider, tables...), mCurrentlyFixed(0)
656 {
657 if (!this->mIsEnd) {
658 setRanges();
659 }
660 }
661 CombinationsBlockFullIndexPolicy(const BP& binningPolicy, int categoryNeighbours, const T& outsider, Ts&&... tables) : CombinationsBlockIndexPolicyBase<BP, T, Ts...>(binningPolicy, categoryNeighbours, outsider, std::forward<Ts>(tables)...), mCurrentlyFixed(0)
662 {
663 if (!this->mIsEnd) {
664 setRanges();
665 }
666 }
667
668 void setTables(const Ts&... tables)
669 {
671 setRanges();
672 }
673 void setTables(Ts&&... tables)
674 {
676 setRanges();
677 }
678
680 {
681 constexpr auto k = sizeof...(Ts);
682 for_<k>([&, this](auto i) {
683 auto catBegin = this->mGroupedIndices[i.value].begin() + std::get<i.value>(this->mCurrentIndices);
684 auto range = std::equal_range(catBegin, this->mGroupedIndices[i.value].end(), *catBegin, sameCategory);
685 std::get<i.value>(this->mBeginIndices) = std::distance(this->mGroupedIndices[i.value].begin(), range.first);
686 std::get<i.value>(this->mMaxOffset) = std::distance(this->mGroupedIndices[i.value].begin(), range.second);
687 std::get<i.value>(this->mCurrent).setCursor(range.first->index);
688 });
689 }
690
691 void addOne()
692 {
693 constexpr auto k = sizeof...(Ts);
694 bool modify = true;
695 bool nextCatAvailable = true;
696 for_<k>([&, this](auto i) {
697 if (modify) {
698 constexpr auto curInd = k - i.value - 1;
699 std::get<curInd>(this->mCurrentIndices)++;
700 uint64_t curGroupedInd = std::get<curInd>(this->mCurrentIndices);
701 uint64_t windowOffset = curInd == this->mCurrentlyFixed ? 1 : this->mSlidingWindowSize;
702 uint64_t maxForWindow = std::get<curInd>(this->mBeginIndices) + windowOffset;
703
704 // If we remain within the same sliding window and fixed index
705 if (curGroupedInd < maxForWindow && curGroupedInd < std::get<curInd>(this->mMaxOffset)) {
706 std::get<curInd>(this->mCurrent).setCursor(this->mGroupedIndices[curInd][curGroupedInd].index);
707 for_<i.value>([&, this](auto j) {
708 constexpr auto curJ = k - i.value + j.value;
709 if (curJ < this->mCurrentlyFixed) { // To assure no repetitions
710 std::get<curJ>(this->mCurrentIndices) = std::get<curJ>(this->mBeginIndices) + 1;
711 } else {
712 std::get<curJ>(this->mCurrentIndices) = std::get<curJ>(this->mBeginIndices);
713 }
714 uint64_t curGroupedJ = std::get<curJ>(this->mCurrentIndices);
715 std::get<curJ>(this->mCurrent).setCursor(this->mGroupedIndices[curJ][curGroupedJ].index);
716 });
717 modify = false;
718 }
719 }
720 });
721
722 this->mIsNewWindow = modify;
723
724 // Currently fixed iterator processed separately
725 if (modify) {
726 // If we haven't finished with window starting element
727 if (this->mCurrentlyFixed < k - 1 && std::get<0>(this->mBeginIndices) < std::get<0>(this->mMaxOffset) - 1) {
728 this->mCurrentlyFixed++;
729 for_<k>([&, this](auto s) {
730 if (s.value < this->mCurrentlyFixed) { // To assure no repetitions
731 std::get<s.value>(this->mCurrentIndices) = std::get<s.value>(this->mBeginIndices) + 1;
732 } else {
733 std::get<s.value>(this->mCurrentIndices) = std::get<s.value>(this->mBeginIndices);
734 }
735 uint64_t curGroupedI = std::get<s.value>(this->mCurrentIndices);
736 std::get<s.value>(this->mCurrent).setCursor(this->mGroupedIndices[s.value][curGroupedI].index);
737 });
738 modify = false;
739 } else {
740 this->mCurrentlyFixed = 0;
741 std::get<0>(this->mBeginIndices)++;
742 std::get<0>(this->mCurrentIndices) = std::get<0>(this->mBeginIndices);
743
744 // If we remain within the same category - slide window
745 if (std::get<0>(this->mBeginIndices) < std::get<0>(this->mMaxOffset)) {
746 uint64_t curGroupedInd = std::get<0>(this->mCurrentIndices);
747 std::get<0>(this->mCurrent).setCursor(this->mGroupedIndices[0][curGroupedInd].index);
748 modify = false;
749 for_<k - 1>([&, this](auto j) {
750 constexpr auto curJ = j.value + 1;
751 std::get<curJ>(this->mBeginIndices)++;
752 if (std::get<curJ>(this->mBeginIndices) < std::get<curJ>(this->mMaxOffset)) {
753 std::get<curJ>(this->mCurrentIndices) = std::get<curJ>(this->mBeginIndices);
754 uint64_t curGroupedJ = std::get<curJ>(this->mCurrentIndices);
755 std::get<curJ>(this->mCurrent).setCursor(this->mGroupedIndices[curJ][curGroupedJ].index);
756 } else {
757 modify = true;
758 }
759 });
760 }
761 }
762 }
763
764 // No more combinations within this category - move to the next category, if possible
765 if (modify) {
766 for_<k>([&, this](auto m) {
767 std::get<m.value>(this->mCurrentIndices) = std::get<m.value>(this->mMaxOffset);
768 if (std::get<m.value>(this->mCurrentIndices) == this->mGroupedIndices[m.value].size()) {
769 nextCatAvailable = false;
770 }
771 });
772 if (nextCatAvailable) {
773 setRanges();
774 }
775 }
776
777 this->mIsEnd = modify && !nextCatAvailable;
778 }
779
781};
782
783template <typename BP, typename T1, typename T, typename... Ts>
786 using IndicesType = typename NTupleType<uint64_t, sizeof...(Ts) + 1>::type;
787
788 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) {}
789 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)
790 {
791 if (!this->mIsEnd) {
792 setRanges(table);
793 }
794 }
795 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)
796 {
797 if (!this->mIsEnd) {
798 setRanges();
799 }
800 }
801
802 void setTables(const T& table, const Ts&... tables)
803 {
805 if (!this->mIsEnd) {
806 setRanges(table);
807 }
808 }
809 void setTables(T&& table, Ts&&... tables)
810 {
811 CombinationsIndexPolicyBase<T, Ts...>::setTables(std::forward<T>(table), std::forward<Ts>(tables)...);
812 if (!this->mIsEnd) {
813 setRanges();
814 }
815 }
816
817 void setRanges(const T& table)
818 {
819 constexpr auto k = sizeof...(Ts) + 1;
820 // minWindowSize == 1 for upper and full, and k for strictly upper k-combination
822 this->mIsEnd = true;
823 return;
824 }
825
827
828 if (this->mGroupedIndices.size() == 0) {
829 this->mIsEnd = true;
830 return;
831 }
832
833 std::get<0>(this->mCurrentIndices) = 0;
834 }
836 {
837 constexpr auto k = sizeof...(Ts) + 1;
838 // minWindowSize == 1 for upper and full, and k for strictly upper k-combination
840 this->mIsEnd = true;
841 return;
842 }
843
844 this->mGroupedIndices = groupTable(std::get<0>(*this->mTables), mBP, mMinWindowSize, mOutsider);
845
846 if (this->mGroupedIndices.size() == 0) {
847 this->mIsEnd = true;
848 return;
849 }
850
851 std::get<0>(this->mCurrentIndices) = 0;
852 }
853
855 {
856 // NOTE: The same number of currentWindowNeighbours is returned for all kinds of block combinations.
857 // Strictly upper: the first element will is paired with exactly currentWindowNeighbours other elements.
858 // Upper: the first element is paired with (currentWindowNeighbours + 1) elements, including itself.
859 // Full: (currentWindowNeighbours + 1) pairs with the first element in the first position (c1)
860 // + there are other combinations with the first element at other positions.
861 if (this->mIsEnd) {
862 return 0;
863 }
864 uint64_t maxForWindow = std::get<0>(this->mCurrentIndices) + this->mSlidingWindowSize - 1;
865 uint64_t maxForTable = std::get<0>(this->mMaxOffset);
866 uint64_t currentMax = maxForWindow < maxForTable ? maxForWindow : maxForTable;
867 return currentMax - std::get<0>(mCurrentIndices);
868 }
869
871 {
872 return mIsNewWindow;
873 }
874
875 std::vector<BinningIndex> mGroupedIndices;
877 const uint64_t mSlidingWindowSize;
878 const int mMinWindowSize;
879 const BP mBP;
881 const T1 mOutsider;
883};
884
885template <typename BP, typename T1, typename... Ts>
888
889 CombinationsBlockUpperSameIndexPolicy(const BP& binningPolicy, int categoryNeighbours, const T1& outsider) : CombinationsBlockSameIndexPolicyBase<BP, T1, Ts...>(binningPolicy, categoryNeighbours, outsider, 1) {}
890 CombinationsBlockUpperSameIndexPolicy(const BP& binningPolicy, int categoryNeighbours, const T1& outsider, const Ts&... tables) : CombinationsBlockSameIndexPolicyBase<BP, T1, Ts...>(binningPolicy, categoryNeighbours, outsider, 1, tables...)
891 {
892 if (!this->mIsEnd) {
893 setRanges();
894 }
895 }
896 CombinationsBlockUpperSameIndexPolicy(const BP& binningPolicy, int categoryNeighbours, const T1& outsider, Ts&&... tables) : CombinationsBlockSameIndexPolicyBase<BP, T1, Ts...>(binningPolicy, categoryNeighbours, outsider, 1, std::forward<Ts>(tables)...)
897 {
898 if (!this->mIsEnd) {
899 setRanges();
900 }
901 }
902
903 void setTables(const Ts&... tables)
904 {
906 setRanges();
907 }
908 void setTables(Ts&&... tables)
909 {
911 setRanges();
912 }
913
915 {
916 constexpr auto k = sizeof...(Ts);
917 auto catBegin = this->mGroupedIndices.begin() + std::get<0>(this->mCurrentIndices);
918 auto range = std::equal_range(catBegin, this->mGroupedIndices.end(), *catBegin, sameCategory);
919 uint64_t offset = std::distance(this->mGroupedIndices.begin(), range.second);
920
921 for_<k>([&, this](auto i) {
922 std::get<i.value>(this->mCurrentIndices) = std::get<0>(this->mCurrentIndices);
923 std::get<i.value>(this->mMaxOffset) = offset;
924 std::get<i.value>(this->mCurrent).setCursor(range.first->index);
925 });
926 }
927
928 void addOne()
929 {
930 constexpr auto k = sizeof...(Ts);
931 bool modify = true;
932 for_<k - 1>([&, this](auto i) {
933 if (modify) {
934 constexpr auto curInd = k - i.value - 1;
935 std::get<curInd>(this->mCurrentIndices)++;
936 uint64_t curGroupedInd = std::get<curInd>(this->mCurrentIndices);
937 uint64_t maxForWindow = std::get<0>(this->mCurrentIndices) + this->mSlidingWindowSize;
938
939 // If we remain within the same sliding window
940 if (curGroupedInd < maxForWindow && curGroupedInd < std::get<curInd>(this->mMaxOffset)) {
941 std::get<curInd>(this->mCurrent).setCursor(this->mGroupedIndices[curGroupedInd].index);
942 for_<i.value>([&, this](auto j) {
943 constexpr auto curJ = k - i.value + j.value;
944 std::get<curJ>(this->mCurrentIndices) = std::get<curJ - 1>(this->mCurrentIndices);
945 uint64_t curGroupedJ = std::get<curJ>(this->mCurrentIndices);
946 std::get<curJ>(this->mCurrent).setCursor(this->mGroupedIndices[curGroupedJ].index);
947 });
948 modify = false;
949 }
950 }
951 });
952
953 this->mIsNewWindow = modify;
954
955 // First iterator processed separately
956 if (modify) {
957 std::get<0>(this->mCurrentIndices)++;
958 uint64_t curGroupedInd = std::get<0>(this->mCurrentIndices);
959
960 // If we remain within the same category - slide window
961 if (curGroupedInd < std::get<0>(this->mMaxOffset)) {
962 std::get<0>(this->mCurrent).setCursor(this->mGroupedIndices[curGroupedInd].index);
963 for_<k - 1>([&, this](auto j) {
964 constexpr auto curJ = j.value + 1;
965 std::get<curJ>(this->mCurrentIndices) = std::get<curJ - 1>(this->mCurrentIndices);
966 uint64_t curGroupedJ = std::get<curJ>(this->mCurrentIndices);
967 std::get<curJ>(this->mCurrent).setCursor(this->mGroupedIndices[curGroupedJ].index);
968 });
969 modify = false;
970 }
971 }
972
973 // No more combinations within this category - move to the next category, if possible
974 if (modify && std::get<0>(this->mCurrentIndices) < this->mGroupedIndices.size()) {
975 setRanges();
976 return;
977 }
978
979 this->mIsEnd = modify;
980 }
981};
982
983template <typename BP, typename T1, typename... Ts>
986
987 CombinationsBlockStrictlyUpperSameIndexPolicy(const BP& binningPolicy, int categoryNeighbours, const T1& outsider) : CombinationsBlockSameIndexPolicyBase<BP, T1, Ts...>(binningPolicy, categoryNeighbours, outsider, sizeof...(Ts)) {}
988 CombinationsBlockStrictlyUpperSameIndexPolicy(const BP& binningPolicy, int categoryNeighbours, const T1& outsider, const Ts&... tables) : CombinationsBlockSameIndexPolicyBase<BP, T1, Ts...>(binningPolicy, categoryNeighbours, outsider, sizeof...(Ts), tables...)
989 {
990 if (!this->mIsEnd) {
991 setRanges();
992 }
993 }
994
995 CombinationsBlockStrictlyUpperSameIndexPolicy(const BP& binningPolicy, int categoryNeighbours, const T1& outsider, Ts&&... tables) : CombinationsBlockSameIndexPolicyBase<BP, T1, Ts...>(binningPolicy, categoryNeighbours, outsider, sizeof...(Ts), std::forward<Ts>(tables)...)
996 {
997 if (!this->mIsEnd) {
998 setRanges();
999 }
1000 }
1001
1002 void setTables(const Ts&... tables)
1003 {
1005 if (!this->mIsEnd) {
1006 setRanges();
1007 }
1008 }
1009 void setTables(Ts&&... tables)
1010 {
1012 if (!this->mIsEnd) {
1013 setRanges();
1014 }
1015 }
1016
1018 {
1019 constexpr auto k = sizeof...(Ts);
1020 auto catBegin = this->mGroupedIndices.begin() + std::get<0>(this->mCurrentIndices);
1021 auto lastIt = std::upper_bound(catBegin, this->mGroupedIndices.end(), *catBegin, sameCategory);
1022 uint64_t lastOffset = std::distance(this->mGroupedIndices.begin(), lastIt);
1023
1024 for_<k>([&, this](auto i) {
1025 std::get<i.value>(this->mCurrentIndices) = std::get<0>(this->mCurrentIndices) + i.value;
1026 std::get<i.value>(this->mCurrent).setCursor(this->mGroupedIndices[std::get<i.value>(this->mCurrentIndices)].index);
1027 std::get<i.value>(this->mMaxOffset) = lastOffset - k + i.value + 1;
1028 });
1029 }
1030
1031 void addOne()
1032 {
1033 constexpr auto k = sizeof...(Ts);
1034 bool modify = true;
1035 for_<k - 1>([&, this](auto i) {
1036 if (modify) {
1037 constexpr auto curInd = k - i.value - 1;
1038 std::get<curInd>(this->mCurrentIndices)++;
1039 uint64_t curGroupedInd = std::get<curInd>(this->mCurrentIndices);
1040 uint64_t maxForWindow = std::get<0>(this->mCurrentIndices) + this->mSlidingWindowSize - i.value;
1041
1042 // If we remain within the same sliding window
1043 if (curGroupedInd < maxForWindow && curGroupedInd < std::get<curInd>(this->mMaxOffset)) {
1044 std::get<curInd>(this->mCurrent).setCursor(this->mGroupedIndices[curGroupedInd].index);
1045 for_<i.value>([&, this](auto j) {
1046 constexpr auto curJ = k - i.value + j.value;
1047 std::get<curJ>(this->mCurrentIndices) = std::get<curJ - 1>(this->mCurrentIndices) + 1;
1048 uint64_t curGroupedJ = std::get<curJ>(this->mCurrentIndices);
1049 std::get<curJ>(this->mCurrent).setCursor(this->mGroupedIndices[curGroupedJ].index);
1050 });
1051 modify = false;
1052 }
1053 }
1054 });
1055
1056 this->mIsNewWindow = modify;
1057
1058 // First iterator processed separately
1059 if (modify) {
1060 std::get<0>(this->mCurrentIndices)++;
1061 uint64_t curGroupedInd = std::get<0>(this->mCurrentIndices);
1062
1063 // If we remain within the same category - slide window
1064 if (curGroupedInd < std::get<0>(this->mMaxOffset)) {
1065 std::get<0>(this->mCurrent).setCursor(this->mGroupedIndices[curGroupedInd].index);
1066 for_<k - 1>([&, this](auto j) {
1067 constexpr auto curJ = j.value + 1;
1068 std::get<curJ>(this->mCurrentIndices) = std::get<curJ - 1>(this->mCurrentIndices) + 1;
1069 uint64_t curGroupedJ = std::get<curJ>(this->mCurrentIndices);
1070 std::get<curJ>(this->mCurrent).setCursor(this->mGroupedIndices[curGroupedJ].index);
1071 });
1072 modify = false;
1073 }
1074 }
1075
1076 // No more combinations within this category - move to the next category, if possible
1077 if (modify && std::get<k - 1>(this->mCurrentIndices) < this->mGroupedIndices.size()) {
1078 for_<k>([&, this](auto m) {
1079 std::get<m.value>(this->mCurrentIndices) = std::get<m.value>(this->mMaxOffset) + k - 1;
1080 });
1081 setRanges();
1082 return;
1083 }
1084
1085 this->mIsEnd = modify;
1086 }
1087};
1088
1089template <typename BP, typename T1, typename... Ts>
1092
1093 CombinationsBlockFullSameIndexPolicy(const BP& binningPolicy, int categoryNeighbours, const T1& outsider) : CombinationsBlockSameIndexPolicyBase<BP, T1, Ts...>(binningPolicy, categoryNeighbours, outsider, 1), mCurrentlyFixed(0) {}
1094 CombinationsBlockFullSameIndexPolicy(const BP& binningPolicy, int categoryNeighbours, const T1& outsider, const Ts&... tables) : CombinationsBlockSameIndexPolicyBase<BP, T1, Ts...>(binningPolicy, categoryNeighbours, outsider, 1, tables...), mCurrentlyFixed(0)
1095 {
1096 if (!this->mIsEnd) {
1097 setRanges();
1098 }
1099 }
1100 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)
1101 {
1102 if (!this->mIsEnd) {
1103 setRanges();
1104 }
1105 }
1106
1107 void setTables(const Ts&... tables)
1108 {
1110 setRanges();
1111 }
1112 void setTables(Ts&&... tables)
1113 {
1115 setRanges();
1116 }
1117
1119 {
1120 constexpr auto k = sizeof...(Ts);
1121 auto catBegin = this->mGroupedIndices.begin() + std::get<0>(this->mCurrentIndices);
1122 auto range = std::equal_range(catBegin, this->mGroupedIndices.end(), *catBegin, sameCategory);
1123 this->mBeginIndex = std::get<0>(this->mCurrentIndices);
1124 uint64_t offset = std::distance(this->mGroupedIndices.begin(), range.second);
1125
1126 for_<k>([&, this](auto i) {
1127 std::get<i.value>(this->mMaxOffset) = offset;
1128 std::get<i.value>(this->mCurrentIndices) = this->mBeginIndex;
1129 std::get<i.value>(this->mCurrent).setCursor(range.first->index);
1130 });
1131 }
1132
1133 void addOne()
1134 {
1135 constexpr auto k = sizeof...(Ts);
1136 bool modify = true;
1137 for_<k>([&, this](auto i) {
1138 if (modify) {
1139 constexpr auto curInd = k - i.value - 1;
1140 std::get<curInd>(this->mCurrentIndices)++;
1141 uint64_t curGroupedInd = std::get<curInd>(this->mCurrentIndices);
1142 uint64_t windowOffset = curInd == this->mCurrentlyFixed ? 1 : this->mSlidingWindowSize;
1143 uint64_t maxForWindow = this->mBeginIndex + windowOffset;
1144
1145 // If we remain within the same sliding window and fixed index
1146 if (curGroupedInd < maxForWindow && curGroupedInd < std::get<curInd>(this->mMaxOffset)) {
1147 std::get<curInd>(this->mCurrent).setCursor(this->mGroupedIndices[curGroupedInd].index);
1148 for_<i.value>([&, this](auto j) {
1149 constexpr auto curJ = k - i.value + j.value;
1150 if (curJ < this->mCurrentlyFixed) { // To assure no repetitions
1151 std::get<curJ>(this->mCurrentIndices) = this->mBeginIndex + 1;
1152 } else {
1153 std::get<curJ>(this->mCurrentIndices) = this->mBeginIndex;
1154 }
1155 uint64_t curGroupedJ = std::get<curJ>(this->mCurrentIndices);
1156 std::get<curJ>(this->mCurrent).setCursor(this->mGroupedIndices[curGroupedJ].index);
1157 });
1158 modify = false;
1159 }
1160 }
1161 });
1162
1163 // Currently fixed iterator processed separately
1164 if (modify) {
1165 // If we haven't finished with window starting element
1166 if (this->mCurrentlyFixed < k - 1 && this->mBeginIndex < std::get<0>(this->mMaxOffset) - 1) {
1167 this->mCurrentlyFixed++;
1168 for_<k>([&, this](auto s) {
1169 if (s.value < this->mCurrentlyFixed) { // To assure no repetitions
1170 std::get<s.value>(this->mCurrentIndices) = this->mBeginIndex + 1;
1171 } else {
1172 std::get<s.value>(this->mCurrentIndices) = this->mBeginIndex;
1173 }
1174 uint64_t curGroupedI = std::get<s.value>(this->mCurrentIndices);
1175 std::get<s.value>(this->mCurrent).setCursor(this->mGroupedIndices[curGroupedI].index);
1176 });
1177 modify = false;
1178 } else {
1179 this->mCurrentlyFixed = 0;
1180 this->mBeginIndex++;
1181 std::get<0>(this->mCurrentIndices) = this->mBeginIndex;
1182
1183 // If we remain within the same category - slide window
1184 if (this->mBeginIndex < std::get<0>(this->mMaxOffset)) {
1185 uint64_t curGroupedInd = std::get<0>(this->mCurrentIndices);
1186 std::get<0>(this->mCurrent).setCursor(this->mGroupedIndices[curGroupedInd].index);
1187 for_<k - 1>([&, this](auto j) {
1188 constexpr auto curJ = j.value + 1;
1189 std::get<curJ>(this->mCurrentIndices) = this->mBeginIndex;
1190 uint64_t curGroupedJ = std::get<curJ>(this->mCurrentIndices);
1191 std::get<curJ>(this->mCurrent).setCursor(this->mGroupedIndices[curGroupedJ].index);
1192 });
1193 modify = false;
1194 } else {
1195 for_<k>([&, this](auto j) {
1196 std::get<j.value>(this->mCurrentIndices) = std::get<j.value>(this->mMaxOffset);
1197 });
1198 }
1199 }
1200 }
1201
1202 // No more combinations within this category - move to the next category, if possible
1203 if (modify && std::get<0>(this->mCurrentIndices) < this->mGroupedIndices.size()) {
1204 setRanges();
1205 return;
1206 }
1207
1208 this->mIsEnd = modify;
1209 }
1210
1211 uint64_t mBeginIndex;
1213};
1214
1217template <typename P>
1219 using CombinationType = typename P::CombinationType;
1220
1221 public:
1222 struct CombinationsIterator : public P {
1223 public:
1227 using iterator_category = std::forward_iterator_tag;
1228
1230
1231 CombinationsIterator(const P& policy) : P(policy) {}
1232
1236
1237 // prefix increment
1239 {
1240 if (!this->mIsEnd) {
1241 this->addOne();
1242 }
1243 return *this;
1244 }
1245 // postfix increment
1247 {
1248 CombinationsIterator copy(*this);
1249 operator++();
1250 return copy;
1251 }
1252 // return reference
1254 {
1255 return this->mCurrent;
1256 }
1257 friend bool operator==(const CombinationsIterator& lh, const CombinationsIterator& rh)
1258 {
1259 return (lh.mIsEnd && rh.mIsEnd) || (lh.mCurrent == rh.mCurrent);
1260 }
1261 };
1262
1265
1267 {
1268 return iterator(mBegin);
1269 }
1270 inline iterator end()
1271 {
1272 return iterator(mEnd);
1273 }
1274 inline const_iterator begin() const
1275 {
1276 return iterator(mBegin);
1277 }
1278 inline const_iterator end() const
1279 {
1280 return iterator(mEnd);
1281 }
1282
1284 CombinationsGenerator(const P& policy) : mBegin(policy), mEnd(policy)
1285 {
1286 mEnd.moveToEnd();
1287 }
1289
1290 private:
1291 iterator mBegin;
1292 iterator mEnd;
1293};
1294
1295template <typename T2, typename... T2s>
1296constexpr bool isSameType()
1297{
1298 return (std::same_as<T2, T2s> && ...);
1299}
1300
1301template <typename BP, typename T1, typename... T2s>
1302auto selfCombinations(const BP& binningPolicy, int categoryNeighbours, const T1& outsider, const T2s&... tables)
1303{
1304 static_assert(isSameType<T2s...>(), "Tables must have the same type for self combinations");
1305 return CombinationsGenerator<CombinationsBlockStrictlyUpperSameIndexPolicy<BP, T1, T2s...>>(CombinationsBlockStrictlyUpperSameIndexPolicy<BP, T1, T2s...>(binningPolicy, categoryNeighbours, outsider, tables...));
1306}
1307
1308template <typename BP, typename T1, typename T2>
1309auto selfPairCombinations(const BP& binningPolicy, int categoryNeighbours, const T1& outsider)
1310{
1312}
1313
1314template <typename BP, typename T1, typename T2>
1315auto selfPairCombinations(const BP& binningPolicy, int categoryNeighbours, const T1& outsider, const T2& table)
1316{
1318}
1319
1320template <typename BP, typename T1, typename T2>
1321auto selfTripleCombinations(const BP& binningPolicy, int categoryNeighbours, const T1& outsider)
1322{
1324}
1325
1326template <typename BP, typename T1, typename T2>
1327auto selfTripleCombinations(const BP& binningPolicy, int categoryNeighbours, const T1& outsider, const T2& table)
1328{
1330}
1331
1332template <typename BP, typename T1, typename... T2s>
1333auto combinations(const BP& binningPolicy, int categoryNeighbours, const T1& outsider, const T2s&... tables)
1334{
1335 if constexpr (isSameType<T2s...>()) {
1336 return CombinationsGenerator<CombinationsBlockStrictlyUpperSameIndexPolicy<BP, T1, T2s...>>(CombinationsBlockStrictlyUpperSameIndexPolicy<BP, T1, T2s...>(binningPolicy, categoryNeighbours, outsider, tables...));
1337 } else {
1338 return CombinationsGenerator<CombinationsBlockUpperIndexPolicy<BP, T1, T2s...>>(CombinationsBlockUpperIndexPolicy<BP, T1, T2s...>(binningPolicy, categoryNeighbours, outsider, tables...));
1339 }
1340}
1341
1342template <typename BP, typename T1, typename... T2s>
1343auto combinations(const BP& binningPolicy, int categoryNeighbours, const T1& outsider, const o2::framework::expressions::Filter& filter, const T2s&... tables)
1344{
1345 if constexpr (isSameType<T2s...>()) {
1347 } else {
1348 return CombinationsGenerator<CombinationsBlockUpperIndexPolicy<BP, T1, Filtered<T2s>...>>(CombinationsBlockUpperIndexPolicy(binningPolicy, categoryNeighbours, outsider, tables.select(filter)...));
1349 }
1350}
1351
1352template <soa::is_table... T2s>
1354{
1355 if constexpr (isSameType<T2s...>()) {
1357 } else {
1359 }
1360}
1361
1362// This shortened version cannot be used for Filtered
1363// (unless users create filtered tables themselves before policy creation)
1364template <template <typename...> typename P2, typename... T2s>
1365CombinationsGenerator<P2<T2s...>> combinations(const P2<T2s...>& policy)
1366{
1367 return CombinationsGenerator<P2<T2s...>>(policy);
1368}
1369
1370template <template <typename...> typename P2, soa::is_table... T2s>
1372{
1373 return CombinationsGenerator<P2<Filtered<T2s>...>>(P2<Filtered<T2s>...>(tables.select(filter)...));
1374}
1375
1376template <typename... T2s>
1377auto combinations(const T2s&... tables)
1378{
1379 if constexpr (isSameType<T2s...>()) {
1381 } else {
1383 }
1384}
1385
1386template <typename T2>
1391
1392template <typename T2>
1397
1398template <typename T2>
1403
1404template <typename T2>
1409
1410} // namespace o2::soa
1411
1412#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 std::size_t pack_size(pack< Ts... > const &)
template function to determine number of types in a pack
Definition Pack.h:28
std::array< std::shared_ptr< arrow::Array >, sizeof...(Cs)> getChunks(arrow::Table *table, framework::pack< Cs... >, uint64_t ci)
Definition ASoA.h:2137
std::array< arrow::ChunkedArray *, sizeof...(Cs)> getArrowColumns(arrow::Table *table, framework::pack< Cs... >)
Definition ASoA.h:2131
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