CMS 3D CMS Logo

 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
binnor.h
Go to the documentation of this file.
1 #ifndef RecoTracker_MkFitCore_interface_binnor_h
2 #define RecoTracker_MkFitCore_interface_binnor_h
3 
4 #include <algorithm>
5 #include <cmath>
6 #include <numeric>
7 #include <vector>
8 #include <cassert>
9 #include <cstdio>
10 
11 namespace mkfit {
12 
13  // For all axis types:
14  //--------------------
15  // R - real type
16  // I - bin index type
17  // M and N - number of bits for fine and normal binning
18 
19  // axis_base
20  //----------
21  template <typename R, typename I, unsigned M, unsigned N>
22  struct axis_base {
23  static_assert(M >= N);
24 
25  typedef R real_t;
26  typedef I index_t;
27 
28  static constexpr unsigned c_M = M;
29  static constexpr unsigned c_N = N;
30  static constexpr unsigned c_M2N_shift = M - N;
31 
32  const R m_R_min, m_R_max;
33  const R m_M_fac, m_N_fac;
35 
36  struct I_pair {
38  I end;
39 
40  I_pair() : begin(0), end(0) {}
41  I_pair(I b, I e) : begin(b), end(e) {}
42  };
43 
44  axis_base(R min, R max, unsigned M_size, unsigned N_size)
45  : m_R_min(min),
46  m_R_max(max),
47  m_M_fac(M_size / (max - min)),
48  m_N_fac(N_size / (max - min)),
49  m_last_M_bin(M_size - 1),
50  m_last_N_bin(N_size - 1) {
51  // Requested number of bins must fit within the intended bit-field (declared by binnor, later).
52  assert(N_size <= (1 << N));
53  }
54 
55  I from_R_to_M_bin(R r) const { return (r - m_R_min) * m_M_fac; }
56  I from_R_to_N_bin(R r) const { return (r - m_R_min) * m_N_fac; }
57 
58  I from_R_to_M_bin_safe(R r) const { return r <= m_R_min ? 0 : (r >= m_R_max ? m_last_M_bin : from_R_to_M_bin(r)); }
59  I from_R_to_N_bin_safe(R r) const { return r <= m_R_min ? 0 : (r >= m_R_max ? m_last_N_bin : from_R_to_N_bin(r)); }
60 
61  I from_M_bin_to_N_bin(I m) const { return m >> c_M2N_shift; }
62 
63  I_pair from_R_minmax_to_N_bins(R rmin, R rmax) const {
64  return I_pair(from_R_to_N_bin_safe(rmin), from_R_to_N_bin_safe(rmax) + I{1});
65  }
66 
67  I_pair from_R_rdr_to_N_bins(R r, R dr) const { return from_R_minmax_to_N_bins(r - dr, r + dr); }
68  I next_N_bin(I bin) const { return bin + 1; }
69  };
70 
71  // axis_pow2_base
72  //---------------
73  // Assumes the numbers of fine/normal bins are powers of 2 that are inferred directly from the number of bits.
74  template <typename R, typename I, unsigned M, unsigned N>
75  struct axis_pow2_base : public axis_base<R, I, M, N> {
76  static constexpr unsigned c_M_end = 1 << M;
77  static constexpr unsigned c_N_end = 1 << N;
78 
79  axis_pow2_base(R min, R max) : axis_base<R, I, M, N>(min, max, c_M_end, c_N_end) {}
80 
81  unsigned size_of_M() const { return c_M_end; }
82  unsigned size_of_N() const { return c_N_end; }
83  };
84 
85  // axis_pow2_u1
86  //-------------
87  // Specialization of axis_pow2 for the "U(1)" case where the coordinate is periodic with period (Rmax - Rmin).
88  // In the "safe" methods below, bit masking serves as the modulo operator for out-of-range bin numbers.
89  template <typename R, typename I, unsigned M, unsigned N>
90  struct axis_pow2_u1 : public axis_pow2_base<R, I, M, N> {
91  static constexpr I c_M_mask = (1 << M) - 1;
92  static constexpr I c_N_mask = (1 << N) - 1;
93 
94  axis_pow2_u1(R min, R max) : axis_pow2_base<R, I, M, N>(min, max) {}
95 
96  I from_R_to_M_bin_safe(R r) const { return this->from_R_to_M_bin(r) & c_M_mask; }
97  I from_R_to_N_bin_safe(R r) const { return this->from_R_to_N_bin(r) & c_N_mask; }
98 
101  (this->from_R_to_N_bin(rmax) + I{1}) & c_N_mask);
102  }
103 
105  return from_R_minmax_to_N_bins(r - dr, r + dr);
106  }
107  I next_N_bin(I bin) const { return (bin + 1) & c_N_mask; }
108  };
109 
110  // axis_pow2
111  //----------
112  template <typename R, typename I, unsigned M, unsigned N>
113  struct axis_pow2 : public axis_pow2_base<R, I, M, N> {
114  axis_pow2(R min, R max) : axis_pow2_base<R, I, M, N>(min, max) {}
115  };
116 
117  // axis
118  //-----
119  template <typename R, typename I, unsigned M = 8 * sizeof(I), unsigned N = 8 * sizeof(I)>
120  struct axis : public axis_base<R, I, M, N> {
121  const unsigned m_num_M_bins, m_num_N_bins;
122 
123  axis(R min, R max, unsigned n_bins)
124  : axis_base<R, I, M, N>(min, max, n_bins << this->c_M2N_shift, n_bins),
125  m_num_M_bins(n_bins << this->c_M2N_shift),
126  m_num_N_bins(n_bins) {}
127 
128  axis(R min, R max, R bin_width) {
129  R extent = max - min;
130  unsigned n_bins = std::ceil(extent / bin_width);
131  R extra = (n_bins * bin_width - extent) / 2;
132 
133  axis(min - extra, max + extra, n_bins);
134  }
135 
136  unsigned size_of_M() const { return m_num_M_bins; }
137  unsigned size_of_N() const { return m_num_N_bins; }
138  };
139 
140  // binnor
141  //---------------
142  // To build and populate bins, do the following:
143  // 1. Construct two axis objects, giving numbers of bits and bins, and extents.
144  // 2. Construct a binnor from the axis objects, and begin_registration on it.
145  // 3. Loop register_entry (optional: _safe) over pairs of coordinates, to fill
146  // m_cons with the corresponding pairs of bin indices (B_pairs).
147  // 4. Call finalize_registration, which sorts m_ranks based on m_cons, making
148  // m_ranks into an in-order map into m_cons (as well as the inputs that were
149  // used to fill it). Final counts for all the bins, as well as starting
150  // indices for the bins (within m_ranks), are computed and stored in packed
151  // form (i.e., bit-fields) in m_bins.
152  //
153  // C - bin content type, to hold "bin population coordinates" in packed form (bit-fields)
154  // A1, A2 - axis types
155  // NB_first, NB_count - number of bits for storage of { first, count } pairs
156 
157  template <typename C, typename A1, typename A2, unsigned NB_first = 8 * sizeof(C), unsigned NB_count = 8 * sizeof(C)>
158  struct binnor {
159  static_assert(std::is_same<typename A1::real_t, typename A2::real_t>());
160  static_assert(A1::c_M + A2::c_M <= 32);
161 
162  static constexpr unsigned int c_A1_mask = (1 << A1::c_M) - 1;
163  static constexpr unsigned int c_A2_Mout_mask = ~(((1 << A2::c_M2N_shift) - 1) << A1::c_M);
164 
165  // Pair of axis bin indices packed into unsigned.
166  struct B_pair {
167  unsigned int packed_value; // bin1 in A1::c_M lower bits, bin2 above
168 
170  B_pair(typename A1::index_t i1, typename A2::index_t i2) : packed_value(i2 << A1::c_M | i1) {}
171 
172  typename A1::index_t bin1() const { return packed_value & c_A1_mask; }
173  typename A2::index_t bin2() const { return packed_value >> A1::c_M; }
174 
175  unsigned int mask_A2_M_bins() const { return packed_value & c_A2_Mout_mask; }
176  };
177 
178  // Bin content pair (bit-fields).
179  struct C_pair {
180  C first : NB_first;
181  C count : NB_count;
182 
183  C_pair() : first(0), count(0) {}
184  C_pair(C f, C c) : first(f), count(c) {}
185 
186  C end() const { return first + count; }
187  };
188 
189  const A1 &m_a1;
190  const A2 &m_a2;
191  std::vector<B_pair> m_cons;
192  std::vector<C_pair> m_bins;
193  std::vector<C> m_ranks;
194 
195  binnor(const A1 &a1, const A2 &a2) : m_a1(a1), m_a2(a2), m_bins(m_a1.size_of_N() * m_a2.size_of_N()) {}
196 
197  // Access
198 
200  return {m_a1.from_M_bin_to_N_bin(m_bin.bin1()), m_a2.from_M_bin_to_N_bin(m_bin.bin2())};
201  }
202 
203  B_pair get_n_bin(typename A1::index_t n1, typename A2::index_t n2) const { return {n1, n2}; }
204 
205  B_pair get_n_bin(typename A1::real_t r1, typename A2::real_t r2) const {
206  return {m_a1.from_R_to_N_bin(r1), m_a2.from_R_to_N_bin(r2)};
207  }
208 
209  C_pair &ref_content(B_pair n_bin) { return m_bins[n_bin.bin2() * m_a1.size_of_N() + n_bin.bin1()]; }
210 
211  C_pair get_content(B_pair n_bin) const { return m_bins[n_bin.bin2() * m_a1.size_of_N() + n_bin.bin1()]; }
212 
213  C_pair get_content(typename A1::index_t n1, typename A2::index_t n2) const {
214  return m_bins[n2 * m_a1.size_of_N() + n1];
215  }
216 
217  C_pair get_content(typename A1::real_t r1, typename A2::real_t r2) const {
218  return get_content(m_a1.from_R_to_N_bin(r1), m_a2.from_R_to_N_bin(r2));
219  }
220 
221  // Filling
222 
223  void reset_contents() {
224  m_bins.assign(m_bins.size(), C_pair());
225  m_ranks.clear();
226  m_ranks.shrink_to_fit();
227  }
228 
229  void begin_registration(C n_items) { m_cons.reserve(n_items); }
230 
231  void register_entry(typename A1::real_t r1, typename A2::real_t r2) {
232  m_cons.push_back({m_a1.from_R_to_M_bin(r1), m_a2.from_R_to_M_bin(r2)});
233  }
234 
235  void register_entry_safe(typename A1::real_t r1, typename A2::real_t r2) {
236  m_cons.push_back({m_a1.from_R_to_M_bin_safe(r1), m_a2.from_R_to_M_bin_safe(r2)});
237  }
238 
239  // Do M-binning outside, potentially using R_to_M_bin_safe().
240  void register_m_bins(typename A1::index_t m1, typename A2::index_t m2) { m_cons.push_back({m1, m2}); }
241 
243  // call internal sort, bin building from icc where template instantiation has to be made.
244 
245  m_ranks.resize(m_cons.size());
246  std::iota(m_ranks.begin(), m_ranks.end(), 0);
247 
248  std::sort(m_ranks.begin(), m_ranks.end(), [&](auto &a, auto &b) {
249  return m_cons[a].mask_A2_M_bins() < m_cons[b].mask_A2_M_bins();
250  });
251 
252  for (C i = 0; i < m_ranks.size(); ++i) {
253  C j = m_ranks[i];
254  C_pair &c_bin = ref_content(m_bin_to_n_bin(m_cons[j]));
255  if (c_bin.count == 0)
256  c_bin.first = i;
257  ++c_bin.count;
258 
259 #ifdef DEBUG
260  B_pair n_pair = m_bin_to_n_bin(m_cons[j]);
261  printf("i=%4u j=%4u %u %u %u %u\n", i, j, n_pair.bin1, n_pair.bin2, c_bin.first, c_bin.count);
262 #endif
263  }
264 
265  // Those could be kept to do preselection when determining search ranges.
266  // Especially since additional precision on Axis2 is screened out during sorting.
267  m_cons.clear();
268  m_cons.shrink_to_fit();
269  }
270  };
271 
272 } // namespace mkfit
273 
274 #endif
constexpr int32_t ceil(float num)
I from_R_to_M_bin(R r) const
Definition: binnor.h:55
const unsigned m_num_M_bins
Definition: binnor.h:121
C_pair get_content(typename A1::real_t r1, typename A2::real_t r2) const
Definition: binnor.h:217
axis(R min, R max, R bin_width)
Definition: binnor.h:128
const edm::EventSetup & c
static constexpr unsigned c_M_end
Definition: binnor.h:76
const A2 & m_a2
Definition: binnor.h:190
A1::index_t bin1() const
Definition: binnor.h:172
I from_R_to_N_bin_safe(R r) const
Definition: binnor.h:97
I from_M_bin_to_N_bin(I m) const
Definition: binnor.h:61
C_pair get_content(typename A1::index_t n1, typename A2::index_t n2) const
Definition: binnor.h:213
static constexpr unsigned c_M
Definition: binnor.h:28
unsigned size_of_M() const
Definition: binnor.h:136
I next_N_bin(I bin) const
Definition: binnor.h:107
axis_base(R min, R max, unsigned M_size, unsigned N_size)
Definition: binnor.h:44
C_pair(C f, C c)
Definition: binnor.h:184
I_pair from_R_minmax_to_N_bins(R rmin, R rmax) const
Definition: binnor.h:63
axis_pow2(R min, R max)
Definition: binnor.h:114
unsigned size_of_M() const
Definition: binnor.h:81
axis_base< R, I, M, N >::I_pair from_R_rdr_to_N_bins(R r, R dr) const
Definition: binnor.h:104
axis_pow2_base(R min, R max)
Definition: binnor.h:79
std::vector< B_pair > m_cons
Definition: binnor.h:191
std::vector< C_pair > m_bins
Definition: binnor.h:192
unsigned int mask_A2_M_bins() const
Definition: binnor.h:175
assert(be >=bs)
unsigned size_of_N() const
Definition: binnor.h:137
void finalize_registration()
Definition: binnor.h:242
tuple m2
Definition: callgraph.py:57
void register_entry(typename A1::real_t r1, typename A2::real_t r2)
Definition: binnor.h:231
axis_pow2_u1(R min, R max)
Definition: binnor.h:94
std::vector< C > m_ranks
Definition: binnor.h:193
axis_base< R, I, M, N >::I_pair from_R_minmax_to_N_bins(R rmin, R rmax) const
Definition: binnor.h:99
I_pair from_R_rdr_to_N_bins(R r, R dr) const
Definition: binnor.h:67
binnor(const A1 &a1, const A2 &a2)
Definition: binnor.h:195
const R m_R_max
Definition: binnor.h:32
static constexpr unsigned c_N_end
Definition: binnor.h:77
const I m_last_M_bin
Definition: binnor.h:34
void register_entry_safe(typename A1::real_t r1, typename A2::real_t r2)
Definition: binnor.h:235
printf("params %d %f %f %f\n", minT, eps, errmax, chi2max)
C_pair get_content(B_pair n_bin) const
Definition: binnor.h:211
const std::complex< double > I
Definition: I.h:8
void register_m_bins(typename A1::index_t m1, typename A2::index_t m2)
Definition: binnor.h:240
void begin_registration(C n_items)
Definition: binnor.h:229
void reset_contents()
Definition: binnor.h:223
B_pair get_n_bin(typename A1::index_t n1, typename A2::index_t n2) const
Definition: binnor.h:203
const A1 & m_a1
Definition: binnor.h:189
axis(R min, R max, unsigned n_bins)
Definition: binnor.h:123
static constexpr unsigned c_M2N_shift
Definition: binnor.h:30
static constexpr unsigned int c_A2_Mout_mask
Definition: binnor.h:163
B_pair(typename A1::index_t i1, typename A2::index_t i2)
Definition: binnor.h:170
static constexpr unsigned int c_A1_mask
Definition: binnor.h:162
#define N
Definition: blowfish.cc:9
static constexpr I c_M_mask
Definition: binnor.h:91
unsigned int packed_value
Definition: binnor.h:167
const R m_M_fac
Definition: binnor.h:33
double b
Definition: hdecay.h:118
const unsigned m_num_N_bins
Definition: binnor.h:121
I from_R_to_M_bin_safe(R r) const
Definition: binnor.h:96
I from_R_to_M_bin_safe(R r) const
Definition: binnor.h:58
const I m_last_N_bin
Definition: binnor.h:34
static constexpr unsigned c_N
Definition: binnor.h:29
static constexpr I c_N_mask
Definition: binnor.h:92
double a
Definition: hdecay.h:119
I from_R_to_N_bin(R r) const
Definition: binnor.h:56
B_pair get_n_bin(typename A1::real_t r1, typename A2::real_t r2) const
Definition: binnor.h:205
A2::index_t bin2() const
Definition: binnor.h:173
I from_R_to_N_bin_safe(R r) const
Definition: binnor.h:59
I next_N_bin(I bin) const
Definition: binnor.h:68
unsigned size_of_N() const
Definition: binnor.h:82
C end() const
Definition: binnor.h:186
B_pair m_bin_to_n_bin(B_pair m_bin)
Definition: binnor.h:199
C_pair & ref_content(B_pair n_bin)
Definition: binnor.h:209
const R m_N_fac
Definition: binnor.h:33
const R m_R_min
Definition: binnor.h:32