Skip to content

Commit 3885717

Browse files
committed
Binning policy changes minimized, backward compatible
1 parent 78e2f6a commit 3885717

2 files changed

Lines changed: 142 additions & 51 deletions

File tree

Framework/Core/include/Framework/ASoAHelpers.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -125,9 +125,8 @@ std::vector<BinningIndex> groupTable(const T& table, const BP<Cs...>& binningPol
125125
selInd = selectedRows[ind];
126126
}
127127

128-
auto rowData = o2::soa::row_helpers::getRowData<decltype(rowIterator), Cs...>(arrowTable, rowIterator, ci, ai, ind);
129-
130-
int val = binningPolicy.getBin(rowData);
128+
auto values = binningPolicy.getBinningValues(rowIterator, arrowTable, ci, ai, ind);
129+
auto val = binningPolicy.getBin(values);
131130
if (val != outsider) {
132131
groupedIndices.emplace_back(val, ind);
133132
}

Framework/Core/include/Framework/BinningPolicy.h

Lines changed: 140 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -13,39 +13,57 @@
1313
#define FRAMEWORK_BINNINGPOLICY_H
1414

1515
#include "Framework/HistogramSpec.h" // only for VARIABLE_WIDTH
16-
#include "Framework/ASoAHelpers.h"
1716
#include "Framework/Pack.h"
1817
#include "Framework/ArrowTypes.h"
1918
#include <optional>
2019

2120
namespace o2::framework
2221
{
2322

24-
template <typename C, typename... Cs>
25-
struct BinningPolicy {
26-
BinningPolicy(std::array<std::vector<double>, sizeof...(Cs) + 1> bins, bool ignoreOverflows = true) : mBins(bins), mIgnoreOverflows(ignoreOverflows)
23+
namespace binning_helpers
24+
{
25+
void expandConstantBinning(std::vector<double> const& bins, std::vector<double>& expanded)
26+
{
27+
if (bins[0] != VARIABLE_WIDTH) {
28+
int nBins = static_cast<int>(bins[0]);
29+
expanded.clear();
30+
expanded.resize(nBins + 2);
31+
expanded[0] = VARIABLE_WIDTH;
32+
for (int i = 0; i <= nBins; i++) {
33+
expanded[i + 1] = bins[1] + i * (bins[2] - bins[1]) / nBins;
34+
}
35+
}
36+
}
37+
} // namespace binning_helpers
38+
39+
template <std::size_t N>
40+
struct BinningPolicyBase {
41+
BinningPolicyBase(std::array<std::vector<double>, N> bins, bool ignoreOverflows = true) : mBins(bins), mIgnoreOverflows(ignoreOverflows)
2742
{
28-
static_assert(sizeof...(Cs) < 3, "No default binning for more than 3 columns, you need to implement a binning class yourself");
29-
for (int i = 0; i < sizeof...(Cs) + 1; i++) {
30-
expandConstantBinning(bins[i], i);
43+
static_assert(N <= 3, "No default binning for more than 3 columns, you need to implement a binning class yourself");
44+
for (int i = 0; i < N; i++) {
45+
binning_helpers::expandConstantBinning(bins[i], mBins[i]);
3146
}
3247
}
3348

34-
int getBin(std::tuple<typename C::type, typename Cs::type...> const& data) const
49+
template <typename... Ts>
50+
int getBin(std::tuple<Ts...> const& data) const
3551
{
52+
static_assert(sizeof...(Ts) == N, "There must be the same number of binning axes and data values/columns");
53+
3654
unsigned int i = 2, j = 2, k = 2;
3755
if (this->mIgnoreOverflows) {
3856
// underflow
39-
if (std::get<0>(data) < this->mBins[0][1]) { // xBins[0] is a dummy VARIABLE_WIDTH
57+
if (std::get<0>(data) < this->mBins[0][1]) { // mBins[0][0] is a dummy VARIABLE_WIDTH
4058
return -1;
4159
}
42-
if constexpr (sizeof...(Cs) > 0) {
43-
if (std::get<1>(data) < this->mBins[1][1]) { // this->mBins[1][0] is a dummy VARIABLE_WIDTH
60+
if constexpr (N > 1) {
61+
if (std::get<1>(data) < this->mBins[1][1]) { // mBins[1][0] is a dummy VARIABLE_WIDTH
4462
return -1;
4563
}
4664
}
47-
if constexpr (sizeof...(Cs) > 1) {
48-
if (std::get<2>(data) < this->mBins[2][1]) { // this->mBins[2][0] is a dummy VARIABLE_WIDTH
65+
if constexpr (N > 2) {
66+
if (std::get<2>(data) < this->mBins[2][1]) { // mBins[2][0] is a dummy VARIABLE_WIDTH
4967
return -1;
5068
}
5169
}
@@ -58,11 +76,11 @@ struct BinningPolicy {
5876
for (; i < this->mBins[0].size(); i++) {
5977
if (std::get<0>(data) < this->mBins[0][i]) {
6078

61-
if constexpr (sizeof...(Cs) > 0) {
79+
if constexpr (N > 1) {
6280
for (; j < this->mBins[1].size(); j++) {
6381
if (std::get<1>(data) < this->mBins[1][j]) {
6482

65-
if constexpr (sizeof...(Cs) > 1) {
83+
if constexpr (N > 2) {
6684
for (; k < this->mBins[2].size(); k++) {
6785
if (std::get<2>(data) < this->mBins[2][k]) {
6886
return getBinAt(i, j, k);
@@ -73,7 +91,7 @@ struct BinningPolicy {
7391
}
7492
}
7593

76-
// overflow for this->mBins[2] only
94+
// overflow for mBins[2] only
7795
return getBinAt(i, j, k);
7896
}
7997
}
@@ -82,8 +100,8 @@ struct BinningPolicy {
82100
return -1;
83101
}
84102

85-
// overflow for this->mBins[1] only
86-
if constexpr (sizeof...(Cs) > 1) {
103+
// overflow for mBins[1] only
104+
if constexpr (N > 2) {
87105
for (k = 2; k < this->mBins[2].size(); k++) {
88106
if (std::get<2>(data) < this->mBins[2][k]) {
89107
return getBinAt(i, j, k);
@@ -92,7 +110,7 @@ struct BinningPolicy {
92110
}
93111
}
94112

95-
// overflow for this->mBins[2] and this->mBins[1]
113+
// overflow for mBins[2] and mBins[1]
96114
return getBinAt(i, j, k);
97115
}
98116
}
@@ -102,27 +120,27 @@ struct BinningPolicy {
102120
return -1;
103121
}
104122

105-
// overflow for this->mBins[0] only
106-
if constexpr (sizeof...(Cs) > 0) {
123+
// overflow for mBins[0] only
124+
if constexpr (N > 1) {
107125
for (j = 2; j < this->mBins[1].size(); j++) {
108126
if (std::get<1>(data) < this->mBins[1][j]) {
109127

110-
if constexpr (sizeof...(Cs) > 1) {
128+
if constexpr (N > 2) {
111129
for (k = 2; k < this->mBins[2].size(); k++) {
112130
if (std::get<2>(data) < this->mBins[2][k]) {
113131
return getBinAt(i, j, k);
114132
}
115133
}
116134
}
117135

118-
// overflow for this->mBins[0] and this->mBins[2]
136+
// overflow for mBins[0] and mBins[2]
119137
return getBinAt(i, j, k);
120138
}
121139
}
122140
}
123141

124-
// overflow for this->mBins[0] and this->mBins[1]
125-
if constexpr (sizeof...(Cs) > 1) {
142+
// overflow for mBins[0] and mBins[1]
143+
if constexpr (N > 2) {
126144
for (k = 2; k < this->mBins[2].size(); k++) {
127145
if (std::get<2>(data) < this->mBins[2][k]) {
128146
return getBinAt(i, j, k);
@@ -137,43 +155,44 @@ struct BinningPolicy {
137155
// Note: Overflow / underflow bin -1 is not included
138156
int getXBinsCount() const
139157
{
140-
return this->mBins[0].size() - 1 - getOverflowShift();
158+
return getBinsCount(mBins[0]);
141159
}
142160

143161
// Note: Overflow / underflow bin -1 is not included
144162
int getYBinsCount() const
145163
{
146-
if constexpr (sizeof...(Cs) == 0) {
164+
if constexpr (N == 1) {
147165
return 0;
148166
}
149-
return this->mBins[1].size() - 1 - getOverflowShift();
167+
return getBinsCount(mBins[1]);
150168
}
151169

152170
// Note: Overflow / underflow bin -1 is not included
153171
int getZBinsCount() const
154172
{
155-
if constexpr (sizeof...(Cs) < 2) {
173+
if constexpr (N < 3) {
156174
return 0;
157175
}
158-
return this->mBins[2].size() - 1 - getOverflowShift();
176+
return getBinsCount(mBins[2]);
159177
}
160178

161179
// Note: Overflow / underflow bin -1 is not included
162180
int getAllBinsCount() const
163181
{
164-
if constexpr (sizeof...(Cs) == 0) {
182+
if constexpr (N == 1) {
165183
return getXBinsCount();
166184
}
167-
if constexpr (sizeof...(Cs) == 1) {
185+
if constexpr (N == 2) {
168186
return getXBinsCount() * getYBinsCount();
169187
}
170-
if constexpr (sizeof...(Cs) == 2) {
188+
if constexpr (N == 2) {
171189
return getXBinsCount() * getYBinsCount() * getZBinsCount();
172190
}
173191
return -1;
174192
}
175193

176-
using persistent_columns_t = framework::selected_pack<o2::soa::is_persistent_t, C, Cs...>;
194+
std::array<std::vector<double>, N> mBins;
195+
bool mIgnoreOverflows;
177196

178197
private:
179198
// We substract 1 to account for VARIABLE_WIDTH in the bins vector
@@ -186,12 +205,12 @@ struct BinningPolicy {
186205
unsigned int j = jRaw - 1 - shiftBinsWithoutOverflow;
187206
unsigned int k = kRaw - 1 - shiftBinsWithoutOverflow;
188207
auto xBinsCount = getXBinsCount();
189-
if constexpr (sizeof...(Cs) == 0) {
208+
if constexpr (N == 1) {
190209
return i;
191-
} else if constexpr (sizeof...(Cs) == 1) {
210+
} else if constexpr (N == 2) {
192211
return i + j * xBinsCount;
193-
} else if constexpr (sizeof...(Cs) == 2) {
194-
return i + j * xBinsCount + k * xBinsCount * (this->mBins[1].size() - 1 - shiftBinsWithoutOverflow);
212+
} else if constexpr (N == 3) {
213+
return i + j * xBinsCount + k * xBinsCount * getYBinsCount();
195214
} else {
196215
return -1;
197216
}
@@ -202,28 +221,101 @@ struct BinningPolicy {
202221
return mIgnoreOverflows ? 1 : -1;
203222
}
204223

205-
void expandConstantBinning(std::vector<double> const& bins, int ind)
224+
// Note: Overflow / underflow bin -1 is not included
225+
int getBinsCount(std::vector<double> const& bins) const
206226
{
207-
if (bins[0] != VARIABLE_WIDTH) {
208-
int nBins = static_cast<int>(bins[0]);
209-
this->mBins[ind].clear();
210-
this->mBins[ind].resize(nBins + 2);
211-
this->mBins[ind][0] = VARIABLE_WIDTH;
212-
for (int i = 0; i <= nBins; i++) {
213-
this->mBins[ind][i + 1] = bins[1] + i * (bins[2] - bins[1]) / nBins;
227+
return bins.size() - 1 - getOverflowShift();
228+
}
229+
};
230+
231+
template <typename, typename...>
232+
struct FlexibleBinningPolicy;
233+
234+
template <typename... Ts, typename... Ls>
235+
struct FlexibleBinningPolicy<std::tuple<Ls...>, Ts...> : BinningPolicyBase<sizeof...(Ts)> {
236+
FlexibleBinningPolicy(std::tuple<Ls...> const& lambdaPtrs, std::array<std::vector<double>, sizeof...(Ts)> bins, bool ignoreOverflows = true) : BinningPolicyBase<sizeof...(Ts)>(bins, ignoreOverflows), mBinningFunctions{lambdaPtrs}
237+
{
238+
}
239+
240+
template <typename T, typename T2>
241+
auto getBinningValue(T& rowIterator, arrow::Table* table, uint64_t globalIndex = -1, uint64_t ci = -1, uint64_t ai = -1) const
242+
{
243+
using decayed = std::decay_t<T2>;
244+
if (globalIndex == -1) {
245+
globalIndex = *(std::get<0>(rowIterator.getIndices()));
246+
}
247+
248+
if constexpr (has_type_v<T2, pack<Ls...>>) {
249+
rowIterator.setCursor(globalIndex);
250+
return std::get<T2>(mBinningFunctions)(rowIterator);
251+
} else {
252+
if (ci == -1 && ai == -1) {
253+
auto colIterator = static_cast<decayed>(rowIterator).mColumnIterator;
254+
ci = colIterator.mCurrentChunk;
255+
ai = *(colIterator.mCurrentPos) - colIterator.mFirstIndex;
214256
}
257+
return soa::row_helpers::getSingleRowData<T, T2>(table, rowIterator, ci, ai, globalIndex);
215258
}
216259
}
217260

218-
std::array<std::vector<double>, sizeof...(Cs) + 1> mBins;
219-
bool mIgnoreOverflows;
261+
template <typename T>
262+
auto getBinningValues(T& rowIterator, arrow::Table* table, uint64_t globalIndex = -1, uint64_t ci = -1, uint64_t ai = -1) const
263+
{
264+
return std::make_tuple(getBinningValue<T, Ts>(rowIterator, table, globalIndex, ci, ai)...);
265+
}
266+
267+
template <typename T>
268+
auto getBinningValues(typename T::iterator rowIterator, T& table, uint64_t globalIndex = -1, uint64_t ci = -1, uint64_t ai = -1) const
269+
{
270+
return getBinningValues(rowIterator, table.asArrowTable().get(), globalIndex, ci, ai);
271+
}
272+
273+
template <typename... T2s>
274+
int getBin(std::tuple<T2s...> const& data) const
275+
{
276+
return BinningPolicyBase<sizeof...(Ts)>::template getBin<T2s...>(data);
277+
}
278+
279+
using persistent_columns_t = framework::selected_pack<o2::soa::is_persistent_t, Ts...>;
280+
281+
private:
282+
std::tuple<Ls...> mBinningFunctions;
220283
};
221284

285+
template <typename... Ts>
286+
struct ColumnBinningPolicy : BinningPolicyBase<sizeof...(Ts)> {
287+
ColumnBinningPolicy(std::array<std::vector<double>, sizeof...(Ts)> bins, bool ignoreOverflows = true) : BinningPolicyBase<sizeof...(Ts)>(bins, ignoreOverflows)
288+
{
289+
}
290+
291+
template <typename T>
292+
auto getBinningValues(T& rowIterator, arrow::Table* table, uint64_t ci, uint64_t ai, uint64_t globalIndex) const
293+
{
294+
return std::make_tuple(soa::row_helpers::getSingleRowData<T, Ts>(table, rowIterator, ci, ai, globalIndex)...);
295+
}
296+
297+
int getBin(std::tuple<typename Ts::type...> const& data) const
298+
{
299+
return BinningPolicyBase<sizeof...(Ts)>::template getBin<typename Ts::type...>(data);
300+
}
301+
302+
using persistent_columns_t = framework::selected_pack<o2::soa::is_persistent_t, Ts...>;
303+
};
304+
305+
template <typename... Ts>
306+
using BinningPolicy = ColumnBinningPolicy<Ts...>;
307+
222308
template <typename C>
223309
struct NoBinningPolicy {
224310
// Just take the bin number from the column data
225311
NoBinningPolicy() = default;
226312

313+
template <typename T>
314+
auto getBinningValues(T& rowIterator, arrow::Table* table, uint64_t ci, uint64_t ai, uint64_t globalIndex) const
315+
{
316+
return std::make_tuple(soa::row_helpers::getSingleRowData<T, C>(table, rowIterator, ci, ai, globalIndex));
317+
}
318+
227319
int getBin(std::tuple<typename C::type> const& data) const
228320
{
229321
return std::get<0>(data);

0 commit comments

Comments
 (0)