OGLplus  (0.59.0) a C++ wrapper for rendering APIs

sorting_network.hpp
Go to the documentation of this file.
1 
9 #ifndef EAGINE_SORTING_NETWORK_HPP
10 #define EAGINE_SORTING_NETWORK_HPP
11 
12 #include "types.hpp"
13 #include <array>
14 #include <cstdint>
15 #include <type_traits>
16 
17 namespace eagine {
18 
19 class bitonic_sorting_network_base {
20 protected:
21  static constexpr auto _next_log(std::size_t n, std::size_t pot = 1) noexcept
22  -> std::size_t {
23  return (n > pot) ? 1U + _next_log(n, pot << 1U) : 0U;
24  }
25 
26  static constexpr auto _hlp(std::size_t n) noexcept -> std::size_t {
27  return (n == 0) ? 0 : n + _hlp(n - 1);
28  }
29 
30  template <std::size_t N>
31  static void _fill_idx(std::array<std::size_t, N>* idx) noexcept {
32  std::size_t r = 0;
33  for(std::size_t k = 0, l = _next_log(N); k < l; ++k) {
34  for(std::size_t m = 0; m <= k; ++m, ++r) {
35  std::size_t d = 1U << (k - m);
36  std::array<std::size_t, N>& row = idx[r];
37 
38  for(std::size_t i = 0; i < N; ++i) {
39  std::size_t inv = ((i >> k) & 2U) >> 1U;
40  std::size_t j = i + ((i & d) == 0 ? d : -d);
41 
42  if(j >= N) {
43  j = i;
44  }
45  row[i] = (j << 1U) | inv;
46  }
47  }
48  }
49  }
50 
51 public:
52  static constexpr auto num_rounds_for(span_size_t n) noexcept
53  -> span_size_t {
54  return span_size(_hlp(_next_log(std_size(n))));
55  }
56 };
57 
58 template <span_size_t N>
59 class bitonic_sorting_network : public bitonic_sorting_network_base {
60 private:
61  using _base = bitonic_sorting_network_base;
62  using _idx_t =
63  std::array<std::array<std::size_t, N>, _base::num_rounds_for(N)>;
64 
65  static auto _make_idx() {
66  _idx_t result;
67  _base::_fill_idx(result.data());
68  return result;
69  }
70 
71  static auto _get_idx() -> _idx_t& {
72  static _idx_t idx = _make_idx();
73  return idx;
74  }
75 
76  static auto _c(span_size_t r, span_size_t i) -> std::size_t& {
77  return _get_idx()[std_size(r)][std_size(i)];
78  }
79 
80 public:
81  static constexpr auto size() noexcept -> span_size_t {
82  return N;
83  }
84 
85  static constexpr auto rounds() noexcept -> span_size_t {
86  return _base::num_rounds_for(N);
87  }
88 
89  static auto index(span_size_t r, span_size_t i) -> span_size_t {
90  return span_size(_c(r, i) >> 1U);
91  }
92 
93  static auto inv(span_size_t r, span_size_t i) -> bool {
94  return (_c(r, i) & 1U) == 1U;
95  }
96 
97  static auto min(span_size_t r, span_size_t i, span_size_t j) -> bool {
98  return inv(r, i) ? (i > j) : (i < j);
99  }
100 
101  static auto max(span_size_t r, span_size_t i, span_size_t j) -> bool {
102  return inv(r, i) ? (i < j) : (i > j);
103  }
104 };
105 
106 template <span_size_t N>
107 struct manual_sorting_network_base {
108  static constexpr bool is_specialized = false;
109 };
110 
111 template <span_size_t N>
112 struct manual_sorting_network : manual_sorting_network_base<N> {
113 private:
114  using _base = manual_sorting_network_base<N>;
115 
116 public:
117  static constexpr auto size() noexcept -> span_size_t {
118  return N;
119  }
120 
121  static constexpr auto
122  min(span_size_t /*round*/, span_size_t i, span_size_t j) noexcept -> bool {
123  return i < j;
124  }
125 
126  static constexpr auto
127  max(span_size_t /*round*/, span_size_t i, span_size_t j) noexcept -> bool {
128  return i > j;
129  }
130 };
131 
132 template <>
133 struct manual_sorting_network_base<1> {
134  static constexpr bool is_specialized = true;
135 
136  static constexpr auto rounds() noexcept -> span_size_t {
137  return 1;
138  }
139 
140  static constexpr auto
141  index(span_size_t /*round*/, span_size_t /*elem*/) noexcept -> span_size_t {
142  return 0;
143  }
144 };
145 
146 template <>
147 struct manual_sorting_network_base<2> {
148  static constexpr bool is_specialized = true;
149 
150  static constexpr auto rounds() noexcept -> span_size_t {
151  return 1;
152  }
153 
154  static constexpr auto
155  index(span_size_t /*round*/, span_size_t elem) noexcept -> span_size_t {
156  return elem == 0 ? 1 : 0;
157  }
158 };
159 
160 template <>
161 struct manual_sorting_network_base<3> {
162  static constexpr bool is_specialized = true;
163 
164  static constexpr auto rounds() noexcept -> span_size_t {
165  return 3;
166  }
167 
168  static constexpr span_size_t idx[3][3] = {{1, 0, 2}, {0, 2, 1}, {1, 0, 2}};
169 
170  static constexpr auto index(span_size_t round, span_size_t elem) noexcept
171  -> span_size_t {
172  return idx[round][elem];
173  }
174 };
175 
176 constexpr span_size_t manual_sorting_network_base<3>::idx[3][3];
177 
178 template <>
179 struct manual_sorting_network_base<4> {
180  static constexpr bool is_specialized = true;
181 
182  static constexpr auto size() noexcept -> span_size_t {
183  return 4;
184  }
185 
186  static constexpr auto rounds() noexcept -> span_size_t {
187  return 3;
188  }
189 
190  static constexpr span_size_t idx[3][4] = {
191  {1, 0, 3, 2},
192  {2, 3, 0, 1},
193  {0, 2, 1, 3}};
194 
195  static constexpr auto index(span_size_t round, span_size_t elem) noexcept
196  -> span_size_t {
197  return idx[round][elem];
198  }
199 };
200 
201 constexpr span_size_t manual_sorting_network_base<4>::idx[3][4];
202 
203 template <>
204 struct manual_sorting_network_base<5> {
205  static constexpr bool is_specialized = true;
206 
207  static constexpr auto size() noexcept -> span_size_t {
208  return 5;
209  }
210 
211  static constexpr auto rounds() noexcept -> span_size_t {
212  return 5;
213  }
214 
215  static constexpr span_size_t idx[5][5] = {
216  {1, 0, 3, 2, 4},
217  {0, 3, 4, 1, 2},
218  {2, 4, 0, 3, 1},
219  {0, 2, 1, 4, 3},
220  {0, 1, 3, 2, 4}};
221 
222  static constexpr auto index(span_size_t round, span_size_t elem) noexcept
223  -> span_size_t {
224  return idx[round][elem];
225  }
226 };
227 
228 constexpr span_size_t manual_sorting_network_base<5>::idx[5][5];
229 
230 template <>
231 struct manual_sorting_network_base<6> {
232  static constexpr bool is_specialized = true;
233 
234  static constexpr auto size() noexcept -> span_size_t {
235  return 6;
236  }
237 
238  static constexpr auto rounds() noexcept -> span_size_t {
239  return 5;
240  }
241 
242  static constexpr span_size_t idx[5][6] = {
243  {1, 0, 3, 2, 5, 4},
244  {2, 4, 0, 5, 1, 3},
245  {1, 0, 3, 2, 5, 4},
246  {0, 2, 1, 4, 3, 5},
247  {0, 1, 3, 2, 4, 5}};
248 
249  static constexpr auto index(span_size_t round, span_size_t elem) noexcept
250  -> span_size_t {
251  return idx[round][elem];
252  }
253 };
254 
255 constexpr span_size_t manual_sorting_network_base<6>::idx[5][6];
256 
257 template <>
258 struct manual_sorting_network_base<7> {
259  static constexpr bool is_specialized = true;
260 
261  static constexpr auto size() noexcept -> span_size_t {
262  return 7;
263  }
264 
265  static constexpr auto rounds() noexcept -> span_size_t {
266  return 6;
267  }
268 
269  static constexpr span_size_t idx[6][7] = {
270  {1, 0, 3, 2, 5, 4, 6},
271  {2, 3, 0, 1, 6, 5, 4},
272  {4, 5, 6, 3, 0, 1, 2},
273  {0, 4, 2, 6, 1, 5, 3},
274  {0, 1, 4, 5, 2, 3, 6},
275  {0, 2, 1, 4, 3, 6, 5}};
276 
277  static constexpr auto index(span_size_t round, span_size_t elem) noexcept
278  -> span_size_t {
279  return idx[round][elem];
280  }
281 };
282 
283 constexpr span_size_t manual_sorting_network_base<7>::idx[6][7];
284 
285 template <>
286 struct manual_sorting_network_base<8> {
287  static constexpr bool is_specialized = true;
288 
289  static constexpr auto size() noexcept -> span_size_t {
290  return 8;
291  }
292 
293  static constexpr auto rounds() noexcept -> span_size_t {
294  return 6;
295  }
296 
297  static constexpr span_size_t idx[6][8] = {
298  {1, 0, 3, 2, 5, 4, 7, 6},
299  {2, 3, 0, 1, 6, 7, 4, 5},
300  {4, 2, 1, 7, 0, 6, 5, 3},
301  {0, 5, 6, 3, 4, 1, 2, 7},
302  {0, 1, 4, 5, 2, 3, 6, 7},
303  {0, 2, 1, 4, 3, 6, 5, 7}};
304 
305  static constexpr auto index(span_size_t round, span_size_t elem) noexcept
306  -> span_size_t {
307  return idx[round][elem];
308  }
309 };
310 
311 constexpr span_size_t manual_sorting_network_base<8>::idx[6][8];
312 
313 template <>
314 struct manual_sorting_network_base<9> {
315  static constexpr bool is_specialized = true;
316 
317  static constexpr auto size() noexcept -> span_size_t {
318  return 9;
319  }
320 
321  static constexpr auto rounds() noexcept -> span_size_t {
322  return 7;
323  }
324 
325  static constexpr span_size_t idx[7][9] = {
326  {7, 6, 5, 4, 3, 2, 1, 0, 8},
327  {3, 2, 1, 0, 7, 5, 8, 4, 6},
328  {1, 0, 6, 4, 3, 8, 2, 7, 5},
329  {0, 2, 1, 5, 6, 3, 4, 8, 7},
330  {0, 3, 4, 1, 2, 7, 6, 5, 8},
331  {1, 0, 3, 2, 5, 4, 7, 6, 8},
332  {0, 1, 2, 4, 3, 6, 5, 7, 8}};
333 
334  static constexpr auto index(span_size_t round, span_size_t elem) noexcept
335  -> span_size_t {
336  return idx[round][elem];
337  }
338 };
339 
340 constexpr span_size_t manual_sorting_network_base<9>::idx[7][9];
341 
342 template <>
343 struct manual_sorting_network_base<10> {
344  static constexpr bool is_specialized = true;
345 
346  static constexpr auto size() noexcept -> span_size_t {
347  return 10;
348  }
349 
350  static constexpr auto rounds() noexcept -> span_size_t {
351  return 7;
352  }
353 
354  static constexpr span_size_t idx[7][10] = {
355  {1, 0, 3, 2, 5, 4, 7, 6, 9, 8},
356  {5, 8, 6, 7, 9, 0, 2, 3, 1, 4},
357  {2, 4, 0, 6, 1, 8, 3, 9, 5, 7},
358  {1, 0, 7, 5, 6, 3, 4, 2, 9, 8},
359  {0, 3, 4, 1, 2, 7, 8, 5, 6, 9},
360  {0, 2, 1, 4, 3, 6, 5, 8, 7, 9},
361  {0, 1, 3, 2, 5, 4, 7, 6, 8, 9},
362  };
363 
364  static constexpr auto index(span_size_t round, span_size_t elem) noexcept
365  -> span_size_t {
366  return idx[round][elem];
367  }
368 };
369 
370 constexpr span_size_t manual_sorting_network_base<10>::idx[7][10];
371 
372 template <>
373 struct manual_sorting_network_base<11> {
374  static constexpr bool is_specialized = true;
375 
376  static constexpr auto size() noexcept -> span_size_t {
377  return 11;
378  }
379 
380  static constexpr auto rounds() noexcept -> span_size_t {
381  return 8;
382  }
383 
384  static constexpr span_size_t idx[8][11] = {
385  {0, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1},
386  {6, 4, 3, 2, 1, 5, 0, 10, 9, 8, 7},
387  {1, 0, 5, 4, 3, 2, 6, 8, 7, 10, 9},
388  {2, 5, 0, 3, 6, 1, 4, 7, 9, 8, 10},
389  {0, 8, 3, 2, 7, 9, 10, 4, 1, 5, 6},
390  {0, 4, 2, 5, 1, 3, 9, 8, 7, 6, 10},
391  {0, 2, 1, 4, 3, 7, 8, 5, 6, 9, 10},
392  {0, 1, 3, 2, 5, 4, 7, 6, 8, 9, 10},
393  };
394 
395  static constexpr auto index(span_size_t round, span_size_t elem) noexcept
396  -> span_size_t {
397  return idx[round][elem];
398  }
399 };
400 
401 constexpr span_size_t manual_sorting_network_base<11>::idx[8][11];
402 
403 template <>
404 struct manual_sorting_network_base<12> {
405  static constexpr bool is_specialized = true;
406 
407  static constexpr auto size() noexcept -> span_size_t {
408  return 12;
409  }
410 
411  static constexpr auto rounds() noexcept -> span_size_t {
412  return 8;
413  }
414 
415  static constexpr span_size_t idx[8][12] = {
416  {6, 7, 8, 9, 10, 11, 0, 1, 2, 3, 4, 5},
417  {3, 4, 5, 0, 1, 2, 9, 10, 11, 6, 7, 8},
418  {1, 0, 2, 6, 5, 4, 3, 8, 7, 9, 11, 10},
419  {0, 2, 1, 4, 3, 8, 7, 6, 5, 10, 9, 11},
420  {1, 0, 9, 6, 5, 4, 3, 8, 7, 2, 11, 10},
421  {0, 3, 6, 1, 7, 9, 2, 4, 10, 5, 8, 11},
422  {0, 1, 3, 2, 6, 7, 4, 5, 9, 8, 10, 11},
423  {0, 1, 2, 4, 3, 6, 5, 8, 7, 9, 10, 11}};
424 
425  static constexpr auto index(span_size_t round, span_size_t elem) noexcept
426  -> span_size_t {
427  return idx[round][elem];
428  }
429 };
430 
431 constexpr span_size_t manual_sorting_network_base<12>::idx[8][12];
432 
433 template <>
434 struct manual_sorting_network_base<14> {
435  static constexpr bool is_specialized = true;
436 
437  static constexpr auto size() noexcept -> span_size_t {
438  return 14;
439  }
440 
441  static constexpr auto rounds() noexcept -> span_size_t {
442  return 9;
443  }
444 
445  static constexpr span_size_t idx[9][14] = {
446  {13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0},
447  {5, 4, 3, 2, 1, 0, 6, 7, 13, 12, 11, 10, 9, 8},
448  {1, 0, 2, 6, 5, 4, 3, 10, 9, 8, 7, 11, 13, 12},
449  {0, 7, 8, 4, 3, 11, 12, 1, 2, 10, 9, 5, 6, 13},
450  {3, 2, 1, 0, 9, 8, 7, 6, 5, 4, 13, 12, 11, 10},
451  {1, 0, 3, 2, 8, 7, 9, 5, 4, 6, 11, 10, 13, 12},
452  {0, 2, 1, 5, 6, 3, 4, 9, 10, 7, 8, 12, 11, 13},
453  {0, 1, 2, 4, 3, 6, 5, 8, 7, 10, 9, 11, 12, 13},
454  {0, 1, 3, 2, 5, 4, 7, 6, 9, 8, 11, 10, 12, 13}};
455 
456  static constexpr auto index(span_size_t round, span_size_t elem) noexcept
457  -> span_size_t {
458  return idx[round][elem];
459  }
460 };
461 
462 constexpr span_size_t manual_sorting_network_base<14>::idx[9][14];
463 
464 template <>
465 struct manual_sorting_network_base<16> {
466  static constexpr bool is_specialized = true;
467 
468  static constexpr auto size() noexcept -> span_size_t {
469  return 16;
470  }
471 
472  static constexpr auto rounds() noexcept -> span_size_t {
473  return 9;
474  }
475 
476  static constexpr span_size_t idx[9][16] = {
477  {15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0},
478  {7, 6, 5, 4, 3, 2, 1, 0, 15, 14, 13, 12, 11, 10, 9, 8},
479  {3, 2, 1, 0, 7, 6, 5, 4, 11, 10, 9, 8, 15, 14, 13, 12},
480  {1, 0, 8, 9, 5, 4, 12, 13, 2, 3, 11, 10, 6, 7, 15, 14},
481  {0, 4, 3, 2, 1, 10, 9, 8, 7, 6, 5, 14, 13, 12, 11, 15},
482  {0, 2, 1, 4, 3, 9, 8, 10, 6, 5, 7, 12, 11, 14, 13, 15},
483  {0, 1, 3, 2, 6, 7, 4, 5, 10, 11, 8, 9, 13, 12, 14, 15},
484  {0, 1, 2, 3, 5, 4, 7, 6, 9, 8, 11, 10, 12, 13, 14, 15},
485  {0, 1, 2, 4, 3, 6, 5, 8, 7, 11, 9, 12, 11, 13, 14, 15}};
486 
487  static constexpr auto index(span_size_t round, span_size_t elem) noexcept
488  -> span_size_t {
489  return idx[round][elem];
490  }
491 };
492 
493 constexpr span_size_t manual_sorting_network_base<16>::idx[9][16];
494 
495 template <span_size_t N>
496 struct sorting_network
497  : std::conditional_t<
498  manual_sorting_network<N>::is_specialized,
499  manual_sorting_network<N>,
500  bitonic_sorting_network<N>> {};
501 
502 } // namespace eagine
503 
504 #endif // EAGINE_SORTING_NETWORK_HPP
std::ptrdiff_t span_size_t
Signed span size type used by eagine.
Definition: types.hpp:36
static constexpr auto span_size(T v) noexcept
Converts argument to span size type.
Definition: types.hpp:59
Common code is placed in this namespace.
Definition: eagine.hpp:21
static constexpr auto std_size(T v) noexcept
Converts argument to std size type.
Definition: types.hpp:52
static constexpr auto row(const matrix< T, C, R, true, V > &m) noexcept -> vector< T, C, V >
Returns the I-th row vector of a matrix. Row-major implementation.
Definition: matrix.hpp:381

Copyright © 2015-2021 Matúš Chochlík.
<chochlik -at -gmail.com>
Documentation generated on Tue Apr 13 2021 by Doxygen (version 1.8.17).