1 // -*- C++ -*- 2 3 // Copyright (C) 2007-2020 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 namespace __gnu_parallel 50 { 51 /** @brief Compare __a pair of types lexicographically, ascending. */ 52 template<typename _T1, typename _T2, typename _Compare> 53 class _Lexicographic 54 : public std::binary_function<std::pair<_T1, _T2>, 55 std::pair<_T1, _T2>, bool> 56 { 57 private: 58 _Compare& _M_comp; 59 60 public: _Lexicographic(_Compare & __comp)61 _Lexicographic(_Compare& __comp) : _M_comp(__comp) { } 62 63 bool operator()64 operator()(const std::pair<_T1, _T2>& __p1, 65 const std::pair<_T1, _T2>& __p2) const 66 { 67 if (_M_comp(__p1.first, __p2.first)) 68 return true; 69 70 if (_M_comp(__p2.first, __p1.first)) 71 return false; 72 73 // Firsts are equal. 74 return __p1.second < __p2.second; 75 } 76 }; 77 78 /** @brief Compare __a pair of types lexicographically, descending. */ 79 template<typename _T1, typename _T2, typename _Compare> 80 class _LexicographicReverse : public std::binary_function<_T1, _T2, bool> 81 { 82 private: 83 _Compare& _M_comp; 84 85 public: _LexicographicReverse(_Compare & __comp)86 _LexicographicReverse(_Compare& __comp) : _M_comp(__comp) { } 87 88 bool operator()89 operator()(const std::pair<_T1, _T2>& __p1, 90 const std::pair<_T1, _T2>& __p2) const 91 { 92 if (_M_comp(__p2.first, __p1.first)) 93 return true; 94 95 if (_M_comp(__p1.first, __p2.first)) 96 return false; 97 98 // Firsts are equal. 99 return __p2.second < __p1.second; 100 } 101 }; 102 103 /** 104 * @brief Splits several sorted sequences at a certain global __rank, 105 * resulting in a splitting point for each sequence. 106 * The sequences are passed via a sequence of random-access 107 * iterator pairs, none of the sequences may be empty. If there 108 * are several equal elements across the split, the ones on the 109 * __left side will be chosen from sequences with smaller number. 110 * @param __begin_seqs Begin of the sequence of iterator pairs. 111 * @param __end_seqs End of the sequence of iterator pairs. 112 * @param __rank The global rank to partition at. 113 * @param __begin_offsets A random-access __sequence __begin where the 114 * __result will be stored in. Each element of the sequence is an 115 * iterator that points to the first element on the greater part of 116 * the respective __sequence. 117 * @param __comp The ordering functor, defaults to std::less<_Tp>. 118 */ 119 template<typename _RanSeqs, typename _RankType, typename _RankIterator, 120 typename _Compare> 121 void 122 multiseq_partition(_RanSeqs __begin_seqs, _RanSeqs __end_seqs, 123 _RankType __rank, 124 _RankIterator __begin_offsets, 125 _Compare __comp = std::less< 126 typename std::iterator_traits<typename 127 std::iterator_traits<_RanSeqs>::value_type:: 128 first_type>::value_type>()) // std::less<_Tp> 129 { 130 _GLIBCXX_CALL(__end_seqs - __begin_seqs) 131 132 typedef typename std::iterator_traits<_RanSeqs>::value_type::first_type 133 _It; 134 typedef typename std::iterator_traits<_RanSeqs>::difference_type 135 _SeqNumber; 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, _SeqNumber, _Compare> __lcomp(__comp); 141 _LexicographicReverse<_ValueType, _SeqNumber, _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), __nn = 0, 146 __nmax, __n, __r; 147 148 for (_SeqNumber __i = 0; __i < __m; __i++) 149 { 150 __nn += 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 == __nn) 158 { 159 for (_SeqNumber __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(__nn != 0); 167 _GLIBCXX_PARALLEL_ASSERT(__rank >= 0); 168 _GLIBCXX_PARALLEL_ASSERT(__rank < __nn); 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 (_SeqNumber __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 = __rd_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 for (_SeqNumber __i = 0; __i < __m; __i++) 191 { 192 __a[__i] = 0; 193 __b[__i] = __l; 194 } 195 __n = __l / 2; 196 197 // Invariants: 198 // 0 <= __a[__i] <= __ns[__i], 0 <= __b[__i] <= __l 199 200 #define __S(__i) (__begin_seqs[__i].first) 201 202 // Initial partition. 203 std::vector<std::pair<_ValueType, _SeqNumber> > __sample; 204 205 for (_SeqNumber __i = 0; __i < __m; __i++) 206 if (__n < __ns[__i]) //__sequence long enough 207 __sample.push_back(std::make_pair(__S(__i)[__n], __i)); 208 __gnu_sequential::sort(__sample.begin(), __sample.end(), __lcomp); 209 210 for (_SeqNumber __i = 0; __i < __m; __i++) //conceptual infinity 211 if (__n >= __ns[__i]) //__sequence too short, conceptual infinity 212 __sample.push_back( 213 std::make_pair(__S(__i)[0] /*__dummy element*/, __i)); 214 215 _DifferenceType __localrank = __rank / __l; 216 217 _SeqNumber __j; 218 for (__j = 0; 219 __j < __localrank && ((__n + 1) <= __ns[__sample[__j].second]); 220 ++__j) 221 __a[__sample[__j].second] += __n + 1; 222 for (; __j < __m; __j++) 223 __b[__sample[__j].second] -= __n + 1; 224 225 // Further refinement. 226 while (__n > 0) 227 { 228 __n /= 2; 229 230 _SeqNumber __lmax_seq = -1; // to avoid warning 231 const _ValueType* __lmax = 0; // impossible to avoid the warning? 232 for (_SeqNumber __i = 0; __i < __m; __i++) 233 { 234 if (__a[__i] > 0) 235 { 236 if (!__lmax) 237 { 238 __lmax = &(__S(__i)[__a[__i] - 1]); 239 __lmax_seq = __i; 240 } 241 else 242 { 243 // Max, favor rear sequences. 244 if (!__comp(__S(__i)[__a[__i] - 1], *__lmax)) 245 { 246 __lmax = &(__S(__i)[__a[__i] - 1]); 247 __lmax_seq = __i; 248 } 249 } 250 } 251 } 252 253 _SeqNumber __i; 254 for (__i = 0; __i < __m; __i++) 255 { 256 _DifferenceType __middle = (__b[__i] + __a[__i]) / 2; 257 if (__lmax && __middle < __ns[__i] && 258 __lcomp(std::make_pair(__S(__i)[__middle], __i), 259 std::make_pair(*__lmax, __lmax_seq))) 260 __a[__i] = std::min(__a[__i] + __n + 1, __ns[__i]); 261 else 262 __b[__i] -= __n + 1; 263 } 264 265 _DifferenceType __leftsize = 0; 266 for (_SeqNumber __i = 0; __i < __m; __i++) 267 __leftsize += __a[__i] / (__n + 1); 268 269 _DifferenceType __skew = __rank / (__n + 1) - __leftsize; 270 271 if (__skew > 0) 272 { 273 // Move to the left, find smallest. 274 std::priority_queue<std::pair<_ValueType, _SeqNumber>, 275 std::vector<std::pair<_ValueType, _SeqNumber> >, 276 _LexicographicReverse<_ValueType, _SeqNumber, _Compare> > 277 __pq(__lrcomp); 278 279 for (_SeqNumber __i = 0; __i < __m; __i++) 280 if (__b[__i] < __ns[__i]) 281 __pq.push(std::make_pair(__S(__i)[__b[__i]], __i)); 282 283 for (; __skew != 0 && !__pq.empty(); --__skew) 284 { 285 _SeqNumber __source = __pq.top().second; 286 __pq.pop(); 287 288 __a[__source] 289 = std::min(__a[__source] + __n + 1, __ns[__source]); 290 __b[__source] += __n + 1; 291 292 if (__b[__source] < __ns[__source]) 293 __pq.push( 294 std::make_pair(__S(__source)[__b[__source]], __source)); 295 } 296 } 297 else if (__skew < 0) 298 { 299 // Move to the right, find greatest. 300 std::priority_queue<std::pair<_ValueType, _SeqNumber>, 301 std::vector<std::pair<_ValueType, _SeqNumber> >, 302 _Lexicographic<_ValueType, _SeqNumber, _Compare> > 303 __pq(__lcomp); 304 305 for (_SeqNumber __i = 0; __i < __m; __i++) 306 if (__a[__i] > 0) 307 __pq.push(std::make_pair(__S(__i)[__a[__i] - 1], __i)); 308 309 for (; __skew != 0; ++__skew) 310 { 311 _SeqNumber __source = __pq.top().second; 312 __pq.pop(); 313 314 __a[__source] -= __n + 1; 315 __b[__source] -= __n + 1; 316 317 if (__a[__source] > 0) 318 __pq.push(std::make_pair( 319 __S(__source)[__a[__source] - 1], __source)); 320 } 321 } 322 } 323 324 // Postconditions: 325 // __a[__i] == __b[__i] in most cases, except when __a[__i] has been 326 // clamped because of having reached the boundary 327 328 // Now return the result, calculate the offset. 329 330 // Compare the keys on both edges of the border. 331 332 // Maximum of left edge, minimum of right edge. 333 _ValueType* __maxleft = 0; 334 _ValueType* __minright = 0; 335 for (_SeqNumber __i = 0; __i < __m; __i++) 336 { 337 if (__a[__i] > 0) 338 { 339 if (!__maxleft) 340 __maxleft = &(__S(__i)[__a[__i] - 1]); 341 else 342 { 343 // Max, favor rear sequences. 344 if (!__comp(__S(__i)[__a[__i] - 1], *__maxleft)) 345 __maxleft = &(__S(__i)[__a[__i] - 1]); 346 } 347 } 348 if (__b[__i] < __ns[__i]) 349 { 350 if (!__minright) 351 __minright = &(__S(__i)[__b[__i]]); 352 else 353 { 354 // Min, favor fore sequences. 355 if (__comp(__S(__i)[__b[__i]], *__minright)) 356 __minright = &(__S(__i)[__b[__i]]); 357 } 358 } 359 } 360 361 _SeqNumber __seq = 0; 362 for (_SeqNumber __i = 0; __i < __m; __i++) 363 __begin_offsets[__i] = __S(__i) + __a[__i]; 364 365 delete[] __ns; 366 delete[] __a; 367 delete[] __b; 368 } 369 370 371 /** 372 * @brief Selects the element at a certain global __rank from several 373 * sorted sequences. 374 * 375 * The sequences are passed via a sequence of random-access 376 * iterator pairs, none of the sequences may be empty. 377 * @param __begin_seqs Begin of the sequence of iterator pairs. 378 * @param __end_seqs End of the sequence of iterator pairs. 379 * @param __rank The global rank to partition at. 380 * @param __offset The rank of the selected element in the global 381 * subsequence of elements equal to the selected element. If the 382 * selected element is unique, this number is 0. 383 * @param __comp The ordering functor, defaults to std::less. 384 */ 385 template<typename _Tp, typename _RanSeqs, typename _RankType, 386 typename _Compare> 387 _Tp 388 multiseq_selection(_RanSeqs __begin_seqs, _RanSeqs __end_seqs, 389 _RankType __rank, 390 _RankType& __offset, _Compare __comp = std::less<_Tp>()) 391 { 392 _GLIBCXX_CALL(__end_seqs - __begin_seqs) 393 394 typedef typename std::iterator_traits<_RanSeqs>::value_type::first_type 395 _It; 396 typedef typename std::iterator_traits<_RanSeqs>::difference_type 397 _SeqNumber; 398 typedef typename std::iterator_traits<_It>::difference_type 399 _DifferenceType; 400 401 _Lexicographic<_Tp, _SeqNumber, _Compare> __lcomp(__comp); 402 _LexicographicReverse<_Tp, _SeqNumber, _Compare> __lrcomp(__comp); 403 404 // Number of sequences, number of elements in total (possibly 405 // including padding). 406 _DifferenceType __m = std::distance(__begin_seqs, __end_seqs); 407 _DifferenceType __nn = 0; 408 _DifferenceType __nmax, __n, __r; 409 410 for (_SeqNumber __i = 0; __i < __m; __i++) 411 __nn += std::distance(__begin_seqs[__i].first, 412 __begin_seqs[__i].second); 413 414 if (__m == 0 || __nn == 0 || __rank < 0 || __rank >= __nn) 415 { 416 // result undefined if there is no data or __rank is outside bounds 417 throw std::exception(); 418 } 419 420 421 _DifferenceType* __ns = new _DifferenceType[__m]; 422 _DifferenceType* __a = new _DifferenceType[__m]; 423 _DifferenceType* __b = new _DifferenceType[__m]; 424 _DifferenceType __l; 425 426 __ns[0] = std::distance(__begin_seqs[0].first, __begin_seqs[0].second); 427 __nmax = __ns[0]; 428 for (_SeqNumber __i = 0; __i < __m; ++__i) 429 { 430 __ns[__i] = std::distance(__begin_seqs[__i].first, 431 __begin_seqs[__i].second); 432 __nmax = std::max(__nmax, __ns[__i]); 433 } 434 435 __r = __rd_log2(__nmax) + 1; 436 437 // Pad all lists to this length, at least as long as any ns[__i], 438 // equality iff __nmax = 2^__k - 1 439 __l = __round_up_to_pow2(__r) - 1; 440 441 for (_SeqNumber __i = 0; __i < __m; ++__i) 442 { 443 __a[__i] = 0; 444 __b[__i] = __l; 445 } 446 __n = __l / 2; 447 448 // Invariants: 449 // 0 <= __a[__i] <= __ns[__i], 0 <= __b[__i] <= __l 450 451 #define __S(__i) (__begin_seqs[__i].first) 452 453 // Initial partition. 454 std::vector<std::pair<_Tp, _SeqNumber> > __sample; 455 456 for (_SeqNumber __i = 0; __i < __m; __i++) 457 if (__n < __ns[__i]) 458 __sample.push_back(std::make_pair(__S(__i)[__n], __i)); 459 __gnu_sequential::sort(__sample.begin(), __sample.end(), 460 __lcomp, sequential_tag()); 461 462 // Conceptual infinity. 463 for (_SeqNumber __i = 0; __i < __m; __i++) 464 if (__n >= __ns[__i]) 465 __sample.push_back( 466 std::make_pair(__S(__i)[0] /*__dummy element*/, __i)); 467 468 _DifferenceType __localrank = __rank / __l; 469 470 _SeqNumber __j; 471 for (__j = 0; 472 __j < __localrank && ((__n + 1) <= __ns[__sample[__j].second]); 473 ++__j) 474 __a[__sample[__j].second] += __n + 1; 475 for (; __j < __m; ++__j) 476 __b[__sample[__j].second] -= __n + 1; 477 478 // Further refinement. 479 while (__n > 0) 480 { 481 __n /= 2; 482 483 const _Tp* __lmax = 0; 484 for (_SeqNumber __i = 0; __i < __m; ++__i) 485 { 486 if (__a[__i] > 0) 487 { 488 if (!__lmax) 489 __lmax = &(__S(__i)[__a[__i] - 1]); 490 else 491 { 492 if (__comp(*__lmax, __S(__i)[__a[__i] - 1])) //max 493 __lmax = &(__S(__i)[__a[__i] - 1]); 494 } 495 } 496 } 497 498 _SeqNumber __i; 499 for (__i = 0; __i < __m; __i++) 500 { 501 _DifferenceType __middle = (__b[__i] + __a[__i]) / 2; 502 if (__lmax && __middle < __ns[__i] 503 && __comp(__S(__i)[__middle], *__lmax)) 504 __a[__i] = std::min(__a[__i] + __n + 1, __ns[__i]); 505 else 506 __b[__i] -= __n + 1; 507 } 508 509 _DifferenceType __leftsize = 0; 510 for (_SeqNumber __i = 0; __i < __m; ++__i) 511 __leftsize += __a[__i] / (__n + 1); 512 513 _DifferenceType __skew = __rank / (__n + 1) - __leftsize; 514 515 if (__skew > 0) 516 { 517 // Move to the left, find smallest. 518 std::priority_queue<std::pair<_Tp, _SeqNumber>, 519 std::vector<std::pair<_Tp, _SeqNumber> >, 520 _LexicographicReverse<_Tp, _SeqNumber, _Compare> > 521 __pq(__lrcomp); 522 523 for (_SeqNumber __i = 0; __i < __m; ++__i) 524 if (__b[__i] < __ns[__i]) 525 __pq.push(std::make_pair(__S(__i)[__b[__i]], __i)); 526 527 for (; __skew != 0 && !__pq.empty(); --__skew) 528 { 529 _SeqNumber __source = __pq.top().second; 530 __pq.pop(); 531 532 __a[__source] 533 = std::min(__a[__source] + __n + 1, __ns[__source]); 534 __b[__source] += __n + 1; 535 536 if (__b[__source] < __ns[__source]) 537 __pq.push( 538 std::make_pair(__S(__source)[__b[__source]], __source)); 539 } 540 } 541 else if (__skew < 0) 542 { 543 // Move to the right, find greatest. 544 std::priority_queue<std::pair<_Tp, _SeqNumber>, 545 std::vector<std::pair<_Tp, _SeqNumber> >, 546 _Lexicographic<_Tp, _SeqNumber, _Compare> > __pq(__lcomp); 547 548 for (_SeqNumber __i = 0; __i < __m; ++__i) 549 if (__a[__i] > 0) 550 __pq.push(std::make_pair(__S(__i)[__a[__i] - 1], __i)); 551 552 for (; __skew != 0; ++__skew) 553 { 554 _SeqNumber __source = __pq.top().second; 555 __pq.pop(); 556 557 __a[__source] -= __n + 1; 558 __b[__source] -= __n + 1; 559 560 if (__a[__source] > 0) 561 __pq.push(std::make_pair( 562 __S(__source)[__a[__source] - 1], __source)); 563 } 564 } 565 } 566 567 // Postconditions: 568 // __a[__i] == __b[__i] in most cases, except when __a[__i] has been 569 // clamped because of having reached the boundary 570 571 // Now return the result, calculate the offset. 572 573 // Compare the keys on both edges of the border. 574 575 // Maximum of left edge, minimum of right edge. 576 bool __maxleftset = false, __minrightset = false; 577 578 // Impossible to avoid the warning? 579 _Tp __maxleft, __minright; 580 for (_SeqNumber __i = 0; __i < __m; ++__i) 581 { 582 if (__a[__i] > 0) 583 { 584 if (!__maxleftset) 585 { 586 __maxleft = __S(__i)[__a[__i] - 1]; 587 __maxleftset = true; 588 } 589 else 590 { 591 // Max. 592 if (__comp(__maxleft, __S(__i)[__a[__i] - 1])) 593 __maxleft = __S(__i)[__a[__i] - 1]; 594 } 595 } 596 if (__b[__i] < __ns[__i]) 597 { 598 if (!__minrightset) 599 { 600 __minright = __S(__i)[__b[__i]]; 601 __minrightset = true; 602 } 603 else 604 { 605 // Min. 606 if (__comp(__S(__i)[__b[__i]], __minright)) 607 __minright = __S(__i)[__b[__i]]; 608 } 609 } 610 } 611 612 // Minright is the __splitter, in any case. 613 614 if (!__maxleftset || __comp(__minright, __maxleft)) 615 { 616 // Good luck, everything is split unambiguously. 617 __offset = 0; 618 } 619 else 620 { 621 // We have to calculate an offset. 622 __offset = 0; 623 624 for (_SeqNumber __i = 0; __i < __m; ++__i) 625 { 626 _DifferenceType lb 627 = std::lower_bound(__S(__i), __S(__i) + __ns[__i], 628 __minright, 629 __comp) - __S(__i); 630 __offset += __a[__i] - lb; 631 } 632 } 633 634 delete[] __ns; 635 delete[] __a; 636 delete[] __b; 637 638 return __minright; 639 } 640 } 641 642 #undef __S 643 644 #endif /* _GLIBCXX_PARALLEL_MULTISEQ_SELECTION_H */ 645