]> git.ipfire.org Git - thirdparty/gcc.git/blob - libstdc++-v3/include/parallel/multiseq_selection.h
algobase.h: Replace tabs by spaces; correct line breaks.
[thirdparty/gcc.git] / libstdc++-v3 / include / parallel / multiseq_selection.h
1 // -*- C++ -*-
2
3 // Copyright (C) 2007, 2008, 2009 Free Software Foundation, Inc.
4 //
5 // This file is part of the GNU ISO C++ Library. This library is free
6 // software; you can redistribute it and/or modify it under the terms
7 // of the GNU General Public License as published by the Free Software
8 // Foundation; either version 3, or (at your option) any later
9 // version.
10
11 // This library is distributed in the hope that it will be useful, but
12 // WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 // General Public License for more details.
15
16 // Under Section 7 of GPL version 3, you are granted additional
17 // permissions described in the GCC Runtime Library Exception, version
18 // 3.1, as published by the Free Software Foundation.
19
20 // You should have received a copy of the GNU General Public License and
21 // a copy of the GCC Runtime Library Exception along with this program;
22 // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
23 // <http://www.gnu.org/licenses/>.
24
25 /** @file parallel/multiseq_selection.h
26 * @brief Functions to find elements of a certain global __rank in
27 * multiple sorted sequences. Also serves for splitting such
28 * sequence sets.
29 *
30 * The algorithm description can be found in
31 *
32 * P. J. Varman, S. D. Scheufler, B. R. Iyer, and G. R. Ricard.
33 * Merging Multiple Lists on Hierarchical-Memory Multiprocessors.
34 * Journal of Parallel and Distributed Computing, 12(2):171–177, 1991.
35 *
36 * This file is a GNU parallel extension to the Standard C++ Library.
37 */
38
39 // Written by Johannes Singler.
40
41 #ifndef _GLIBCXX_PARALLEL_MULTISEQ_SELECTION_H
42 #define _GLIBCXX_PARALLEL_MULTISEQ_SELECTION_H 1
43
44 #include <vector>
45 #include <queue>
46
47 #include <bits/stl_algo.h>
48
49 #include <parallel/sort.h>
50
51 namespace __gnu_parallel
52 {
53 /** @brief Compare __a pair of types lexicographically, ascending. */
54 template<typename _T1, typename _T2, typename _Compare>
55 class _Lexicographic
56 : public std::binary_function<
57 std::pair<_T1, _T2>, std::pair<_T1, _T2>, bool>
58 {
59 private:
60 _Compare& _M_comp;
61
62 public:
63 _Lexicographic(_Compare& __comp) : _M_comp(__comp) { }
64
65 bool
66 operator()(const std::pair<_T1, _T2>& __p1,
67 const std::pair<_T1, _T2>& __p2) const
68 {
69 if (_M_comp(__p1.first, __p2.first))
70 return true;
71
72 if (_M_comp(__p2.first, __p1.first))
73 return false;
74
75 // Firsts are equal.
76 return __p1.second < __p2.second;
77 }
78 };
79
80 /** @brief Compare __a pair of types lexicographically, descending. */
81 template<typename _T1, typename _T2, typename _Compare>
82 class _LexicographicReverse : public std::binary_function<_T1, _T2, bool>
83 {
84 private:
85 _Compare& _M_comp;
86
87 public:
88 _LexicographicReverse(_Compare& __comp) : _M_comp(__comp) { }
89
90 bool
91 operator()(const std::pair<_T1, _T2>& __p1,
92 const std::pair<_T1, _T2>& __p2) const
93 {
94 if (_M_comp(__p2.first, __p1.first))
95 return true;
96
97 if (_M_comp(__p1.first, __p2.first))
98 return false;
99
100 // Firsts are equal.
101 return __p2.second < __p1.second;
102 }
103 };
104
105 /**
106 * @brief Splits several sorted sequences at __a certain global __rank,
107 * resulting in a splitting point for each sequence.
108 * The sequences are passed via __a __sequence of random-access
109 * iterator pairs, none of the sequences may be empty. If there
110 * are several equal elements across the split, the ones on the
111 * __left side will be chosen from sequences with smaller number.
112 * @param __begin_seqs Begin of the sequence of iterator pairs.
113 * @param __end_seqs End of the sequence of iterator pairs.
114 * @param __rank The global __rank to partition at.
115 * @param __begin_offsets A random-access __sequence __begin where the
116 * __result will be stored in. Each element of the sequence is an
117 * iterator that points to the first element on the greater part of
118 * the respective __sequence.
119 * @param __comp The ordering functor, defaults to std::less<_Tp>.
120 */
121 template<typename _RanSeqs, typename _RankType, typename _RankIterator,
122 typename _Compare>
123 void
124 multiseq_partition(_RanSeqs __begin_seqs, _RanSeqs __end_seqs,
125 _RankType __rank,
126 _RankIterator __begin_offsets,
127 _Compare __comp = std::less<
128 typename std::iterator_traits<typename
129 std::iterator_traits<_RanSeqs>::value_type::
130 first_type>::value_type>()) // std::less<_Tp>
131 {
132 _GLIBCXX_CALL(__end_seqs - __begin_seqs)
133
134 typedef typename std::iterator_traits<_RanSeqs>::value_type::first_type
135 _It;
136 typedef typename std::iterator_traits<_It>::difference_type
137 _DifferenceType;
138 typedef typename std::iterator_traits<_It>::value_type _ValueType;
139
140 _Lexicographic<_ValueType, int, _Compare> __lcomp(__comp);
141 _LexicographicReverse<_ValueType, int, _Compare> __lrcomp(__comp);
142
143 // Number of sequences, number of elements in total (possibly
144 // including padding).
145 _DifferenceType __m = std::distance(__begin_seqs, __end_seqs), __N = 0,
146 __nmax, __n, __r;
147
148 for (int __i = 0; __i < __m; __i++)
149 {
150 __N += std::distance(__begin_seqs[__i].first,
151 __begin_seqs[__i].second);
152 _GLIBCXX_PARALLEL_ASSERT(
153 std::distance(__begin_seqs[__i].first,
154 __begin_seqs[__i].second) > 0);
155 }
156
157 if (__rank == __N)
158 {
159 for (int __i = 0; __i < __m; __i++)
160 __begin_offsets[__i] = __begin_seqs[__i].second; // Very end.
161 // Return __m - 1;
162 return;
163 }
164
165 _GLIBCXX_PARALLEL_ASSERT(__m != 0);
166 _GLIBCXX_PARALLEL_ASSERT(__N != 0);
167 _GLIBCXX_PARALLEL_ASSERT(__rank >= 0);
168 _GLIBCXX_PARALLEL_ASSERT(__rank < __N);
169
170 _DifferenceType* __ns = new _DifferenceType[__m];
171 _DifferenceType* __a = new _DifferenceType[__m];
172 _DifferenceType* __b = new _DifferenceType[__m];
173 _DifferenceType __l;
174
175 __ns[0] = std::distance(__begin_seqs[0].first, __begin_seqs[0].second);
176 __nmax = __ns[0];
177 for (int __i = 0; __i < __m; __i++)
178 {
179 __ns[__i] = std::distance(__begin_seqs[__i].first,
180 __begin_seqs[__i].second);
181 __nmax = std::max(__nmax, __ns[__i]);
182 }
183
184 __r = __log2(__nmax) + 1;
185
186 // Pad all lists to this length, at least as long as any ns[__i],
187 // equality iff __nmax = 2^__k - 1.
188 __l = (1ULL << __r) - 1;
189
190 // From now on, including padding.
191 __N = __l * __m;
192
193 for (int __i = 0; __i < __m; __i++)
194 {
195 __a[__i] = 0;
196 __b[__i] = __l;
197 }
198 __n = __l / 2;
199
200 // Invariants:
201 // 0 <= __a[__i] <= __ns[__i], 0 <= __b[__i] <= __l
202
203 #define __S(__i) (__begin_seqs[__i].first)
204
205 // Initial partition.
206 std::vector<std::pair<_ValueType, int> > __sample;
207
208 for (int __i = 0; __i < __m; __i++)
209 if (__n < __ns[__i]) //__sequence long enough
210 __sample.push_back(std::make_pair(__S(__i)[__n], __i));
211 __gnu_sequential::sort(__sample.begin(), __sample.end(), __lcomp);
212
213 for (int __i = 0; __i < __m; __i++) //conceptual infinity
214 if (__n >= __ns[__i]) //__sequence too short, conceptual infinity
215 __sample.push_back(
216 std::make_pair(__S(__i)[0] /*__dummy element*/, __i));
217
218 _DifferenceType localrank = __rank * __m / __N ;
219
220 int __j;
221 for (__j = 0;
222 __j < localrank && ((__n + 1) <= __ns[__sample[__j].second]); ++__j)
223 __a[__sample[__j].second] += __n + 1;
224 for (; __j < __m; __j++)
225 __b[__sample[__j].second] -= __n + 1;
226
227 // Further refinement.
228 while (__n > 0)
229 {
230 __n /= 2;
231
232 int __lmax_seq = -1; // to avoid warning
233 const _ValueType* __lmax = NULL; // impossible to avoid the warning?
234 for (int __i = 0; __i < __m; __i++)
235 {
236 if (__a[__i] > 0)
237 {
238 if (!__lmax)
239 {
240 __lmax = &(__S(__i)[__a[__i] - 1]);
241 __lmax_seq = __i;
242 }
243 else
244 {
245 // Max, favor rear sequences.
246 if (!__comp(__S(__i)[__a[__i] - 1], *__lmax))
247 {
248 __lmax = &(__S(__i)[__a[__i] - 1]);
249 __lmax_seq = __i;
250 }
251 }
252 }
253 }
254
255 int __i;
256 for (__i = 0; __i < __m; __i++)
257 {
258 _DifferenceType __middle = (__b[__i] + __a[__i]) / 2;
259 if (__lmax && __middle < __ns[__i] &&
260 __lcomp(std::make_pair(__S(__i)[__middle], __i),
261 std::make_pair(*__lmax, __lmax_seq)))
262 __a[__i] = std::min(__a[__i] + __n + 1, __ns[__i]);
263 else
264 __b[__i] -= __n + 1;
265 }
266
267 _DifferenceType __leftsize = 0, __total = 0;
268 for (int __i = 0; __i < __m; __i++)
269 {
270 __leftsize += __a[__i] / (__n + 1);
271 __total += __l / (__n + 1);
272 }
273
274 _DifferenceType __skew = static_cast<_DifferenceType>
275 (static_cast<uint64>(__total) * __rank / __N - __leftsize);
276
277 if (__skew > 0)
278 {
279 // Move to the left, find smallest.
280 std::priority_queue<std::pair<_ValueType, int>,
281 std::vector<std::pair<_ValueType, int> >,
282 _LexicographicReverse<_ValueType, int, _Compare> >
283 __pq(__lrcomp);
284
285 for (int __i = 0; __i < __m; __i++)
286 if (__b[__i] < __ns[__i])
287 __pq.push(std::make_pair(__S(__i)[__b[__i]], __i));
288
289 for (; __skew != 0 && !__pq.empty(); --__skew)
290 {
291 int source = __pq.top().second;
292 __pq.pop();
293
294 __a[source] = std::min(__a[source] + __n + 1, __ns[source]);
295 __b[source] += __n + 1;
296
297 if (__b[source] < __ns[source])
298 __pq.push(
299 std::make_pair(__S(source)[__b[source]], source));
300 }
301 }
302 else if (__skew < 0)
303 {
304 // Move to the right, find greatest.
305 std::priority_queue<std::pair<_ValueType, int>,
306 std::vector<std::pair<_ValueType, int> >,
307 _Lexicographic<_ValueType, int, _Compare> > __pq(__lcomp);
308
309 for (int __i = 0; __i < __m; __i++)
310 if (__a[__i] > 0)
311 __pq.push(std::make_pair(__S(__i)[__a[__i] - 1], __i));
312
313 for (; __skew != 0; ++__skew)
314 {
315 int source = __pq.top().second;
316 __pq.pop();
317
318 __a[source] -= __n + 1;
319 __b[source] -= __n + 1;
320
321 if (__a[source] > 0)
322 __pq.push(
323 std::make_pair(__S(source)[__a[source] - 1], source));
324 }
325 }
326 }
327
328 // Postconditions:
329 // __a[__i] == __b[__i] in most cases, except when __a[__i] has been
330 // clamped because of having reached the boundary
331
332 // Now return the result, calculate the offset.
333
334 // Compare the keys on both edges of the border.
335
336 // Maximum of left edge, minimum of right edge.
337 _ValueType* __maxleft = NULL;
338 _ValueType* __minright = NULL;
339 for (int __i = 0; __i < __m; __i++)
340 {
341 if (__a[__i] > 0)
342 {
343 if (!__maxleft)
344 __maxleft = &(__S(__i)[__a[__i] - 1]);
345 else
346 {
347 // Max, favor rear sequences.
348 if (!__comp(__S(__i)[__a[__i] - 1], *__maxleft))
349 __maxleft = &(__S(__i)[__a[__i] - 1]);
350 }
351 }
352 if (__b[__i] < __ns[__i])
353 {
354 if (!__minright)
355 __minright = &(__S(__i)[__b[__i]]);
356 else
357 {
358 // Min, favor fore sequences.
359 if (__comp(__S(__i)[__b[__i]], *__minright))
360 __minright = &(__S(__i)[__b[__i]]);
361 }
362 }
363 }
364
365 int __seq = 0;
366 for (int __i = 0; __i < __m; __i++)
367 __begin_offsets[__i] = __S(__i) + __a[__i];
368
369 delete[] __ns;
370 delete[] __a;
371 delete[] __b;
372 }
373
374
375 /**
376 * @brief Selects the element at __a certain global __rank from several
377 * sorted sequences.
378 *
379 * The sequences are passed via __a __sequence of random-access
380 * iterator pairs, none of the sequences may be empty.
381 * @param __begin_seqs Begin of the sequence of iterator pairs.
382 * @param __end_seqs End of the sequence of iterator pairs.
383 * @param __rank The global __rank to partition at.
384 * @param __offset The rank of the selected element in the global
385 * subsequence of elements equal to the selected element. If the
386 * selected element is unique, this number is 0.
387 * @param __comp The ordering functor, defaults to std::less.
388 */
389 template<typename _Tp, typename _RanSeqs, typename _RankType,
390 typename _Compare>
391 _Tp
392 multiseq_selection(_RanSeqs __begin_seqs, _RanSeqs __end_seqs,
393 _RankType __rank,
394 _RankType& __offset, _Compare __comp = std::less<_Tp>())
395 {
396 _GLIBCXX_CALL(__end_seqs - __begin_seqs)
397
398 typedef typename std::iterator_traits<_RanSeqs>::value_type::first_type
399 _It;
400 typedef typename std::iterator_traits<_It>::difference_type
401 _DifferenceType;
402
403 _Lexicographic<_Tp, int, _Compare> __lcomp(__comp);
404 _LexicographicReverse<_Tp, int, _Compare> __lrcomp(__comp);
405
406 // Number of sequences, number of elements in total (possibly
407 // including padding).
408 _DifferenceType __m = std::distance(__begin_seqs, __end_seqs);
409 _DifferenceType __N = 0;
410 _DifferenceType __nmax, __n, __r;
411
412 for (int __i = 0; __i < __m; __i++)
413 __N += std::distance(__begin_seqs[__i].first,
414 __begin_seqs[__i].second);
415
416 if (__m == 0 || __N == 0 || __rank < 0 || __rank >= __N)
417 {
418 // result undefined if there is no data or __rank is outside bounds
419 throw std::exception();
420 }
421
422
423 _DifferenceType* __ns = new _DifferenceType[__m];
424 _DifferenceType* __a = new _DifferenceType[__m];
425 _DifferenceType* __b = new _DifferenceType[__m];
426 _DifferenceType __l;
427
428 __ns[0] = std::distance(__begin_seqs[0].first, __begin_seqs[0].second);
429 __nmax = __ns[0];
430 for (int __i = 0; __i < __m; ++__i)
431 {
432 __ns[__i] = std::distance(__begin_seqs[__i].first,
433 __begin_seqs[__i].second);
434 __nmax = std::max(__nmax, __ns[__i]);
435 }
436
437 __r = __log2(__nmax) + 1;
438
439 // Pad all lists to this length, at least as long as any ns[__i],
440 // equality iff __nmax = 2^__k - 1
441 __l = pow2(__r) - 1;
442
443 // From now on, including padding.
444 __N = __l * __m;
445
446 for (int __i = 0; __i < __m; ++__i)
447 {
448 __a[__i] = 0;
449 __b[__i] = __l;
450 }
451 __n = __l / 2;
452
453 // Invariants:
454 // 0 <= __a[__i] <= __ns[__i], 0 <= __b[__i] <= __l
455
456 #define __S(__i) (__begin_seqs[__i].first)
457
458 // Initial partition.
459 std::vector<std::pair<_Tp, int> > __sample;
460
461 for (int __i = 0; __i < __m; __i++)
462 if (__n < __ns[__i])
463 __sample.push_back(std::make_pair(__S(__i)[__n], __i));
464 __gnu_sequential::sort(__sample.begin(), __sample.end(),
465 __lcomp, sequential_tag());
466
467 // Conceptual infinity.
468 for (int __i = 0; __i < __m; __i++)
469 if (__n >= __ns[__i])
470 __sample.push_back(
471 std::make_pair(__S(__i)[0] /*__dummy element*/, __i));
472
473 _DifferenceType localrank = __rank * __m / __N ;
474
475 int __j;
476 for (__j = 0;
477 __j < localrank && ((__n + 1) <= __ns[__sample[__j].second]); ++__j)
478 __a[__sample[__j].second] += __n + 1;
479 for (; __j < __m; ++__j)
480 __b[__sample[__j].second] -= __n + 1;
481
482 // Further refinement.
483 while (__n > 0)
484 {
485 __n /= 2;
486
487 const _Tp* __lmax = NULL;
488 for (int __i = 0; __i < __m; ++__i)
489 {
490 if (__a[__i] > 0)
491 {
492 if (!__lmax)
493 __lmax = &(__S(__i)[__a[__i] - 1]);
494 else
495 {
496 if (__comp(*__lmax, __S(__i)[__a[__i] - 1])) //max
497 __lmax = &(__S(__i)[__a[__i] - 1]);
498 }
499 }
500 }
501
502 int __i;
503 for (__i = 0; __i < __m; __i++)
504 {
505 _DifferenceType __middle = (__b[__i] + __a[__i]) / 2;
506 if (__lmax && __middle < __ns[__i]
507 && __comp(__S(__i)[__middle], *__lmax))
508 __a[__i] = std::min(__a[__i] + __n + 1, __ns[__i]);
509 else
510 __b[__i] -= __n + 1;
511 }
512
513 _DifferenceType __leftsize = 0, __total = 0;
514 for (int __i = 0; __i < __m; ++__i)
515 {
516 __leftsize += __a[__i] / (__n + 1);
517 __total += __l / (__n + 1);
518 }
519
520 _DifferenceType __skew = ((unsigned long long)__total * __rank / __N
521 - __leftsize);
522
523 if (__skew > 0)
524 {
525 // Move to the left, find smallest.
526 std::priority_queue<std::pair<_Tp, int>,
527 std::vector<std::pair<_Tp, int> >,
528 _LexicographicReverse<_Tp, int, _Compare> > __pq(__lrcomp);
529
530 for (int __i = 0; __i < __m; ++__i)
531 if (__b[__i] < __ns[__i])
532 __pq.push(std::make_pair(__S(__i)[__b[__i]], __i));
533
534 for (; __skew != 0 && !__pq.empty(); --__skew)
535 {
536 int source = __pq.top().second;
537 __pq.pop();
538
539 __a[source] = std::min(__a[source] + __n + 1, __ns[source]);
540 __b[source] += __n + 1;
541
542 if (__b[source] < __ns[source])
543 __pq.push(
544 std::make_pair(__S(source)[__b[source]], source));
545 }
546 }
547 else if (__skew < 0)
548 {
549 // Move to the right, find greatest.
550 std::priority_queue<std::pair<_Tp, int>,
551 std::vector<std::pair<_Tp, int> >,
552 _Lexicographic<_Tp, int, _Compare> > __pq(__lcomp);
553
554 for (int __i = 0; __i < __m; ++__i)
555 if (__a[__i] > 0)
556 __pq.push(std::make_pair(__S(__i)[__a[__i] - 1], __i));
557
558 for (; __skew != 0; ++__skew)
559 {
560 int source = __pq.top().second;
561 __pq.pop();
562
563 __a[source] -= __n + 1;
564 __b[source] -= __n + 1;
565
566 if (__a[source] > 0)
567 __pq.push(
568 std::make_pair(__S(source)[__a[source] - 1], source));
569 }
570 }
571 }
572
573 // Postconditions:
574 // __a[__i] == __b[__i] in most cases, except when __a[__i] has been
575 // clamped because of having reached the boundary
576
577 // Now return the result, calculate the offset.
578
579 // Compare the keys on both edges of the border.
580
581 // Maximum of left edge, minimum of right edge.
582 bool __maxleftset = false, __minrightset = false;
583
584 // Impossible to avoid the warning?
585 _Tp __maxleft, __minright;
586 for (int __i = 0; __i < __m; ++__i)
587 {
588 if (__a[__i] > 0)
589 {
590 if (!__maxleftset)
591 {
592 __maxleft = __S(__i)[__a[__i] - 1];
593 __maxleftset = true;
594 }
595 else
596 {
597 // Max.
598 if (__comp(__maxleft, __S(__i)[__a[__i] - 1]))
599 __maxleft = __S(__i)[__a[__i] - 1];
600 }
601 }
602 if (__b[__i] < __ns[__i])
603 {
604 if (!__minrightset)
605 {
606 __minright = __S(__i)[__b[__i]];
607 __minrightset = true;
608 }
609 else
610 {
611 // Min.
612 if (__comp(__S(__i)[__b[__i]], __minright))
613 __minright = __S(__i)[__b[__i]];
614 }
615 }
616 }
617
618 // Minright is the splitter, in any case.
619
620 if (!__maxleftset || __comp(__minright, __maxleft))
621 {
622 // Good luck, everything is split unambiguously.
623 __offset = 0;
624 }
625 else
626 {
627 // We have to calculate an offset.
628 __offset = 0;
629
630 for (int __i = 0; __i < __m; ++__i)
631 {
632 _DifferenceType lb
633 = std::lower_bound(__S(__i), __S(__i) + __ns[__i],
634 __minright,
635 __comp) - __S(__i);
636 __offset += __a[__i] - lb;
637 }
638 }
639
640 delete[] __ns;
641 delete[] __a;
642 delete[] __b;
643
644 return __minright;
645 }
646 }
647
648 #undef __S
649
650 #endif /* _GLIBCXX_PARALLEL_MULTISEQ_SELECTION_H */