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):171177, 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 Comparator> 55 class lexicographic 56 : public std::binary_function<std::pair<T1, T2>, std::pair<T1, T2>, bool> 57 { 58 private: 59 Comparator& comp; 60 61 public: 62 lexicographic(Comparator& _comp) : comp(_comp) { } 63 64 bool 65 operator()(const std::pair<T1, T2>& p1, 66 const std::pair<T1, T2>& p2) const 67 { 68 if (comp(p1.first, p2.first)) 69 return true; 70 71 if (comp(p2.first, p1.first)) 72 return false; 73 74 // Firsts are equal. 75 return p1.second < p2.second; 76 } 77 }; 78 79 /** @brief Compare a pair of types lexicographically, descending. */ 80 template<typename T1, typename T2, typename Comparator> 81 class lexicographic_reverse : public std::binary_function<T1, T2, bool> 82 { 83 private: 84 Comparator& comp; 85 86 public: 87 lexicographic_reverse(Comparator& _comp) : comp(_comp) { } 88 89 bool 90 operator()(const std::pair<T1, T2>& p1, 91 const std::pair<T1, T2>& p2) const 92 { 93 if (comp(p2.first, p1.first)) 94 return true; 95 96 if (comp(p1.first, p2.first)) 97 return false; 98 99 // Firsts are equal. 100 return p2.second < p1.second; 101 } 102 }; 103 104 /** 105 * @brief Splits several sorted sequences at a certain global rank, 106 * resulting in a splitting point for each sequence. 107 * The sequences are passed via a sequence of random-access 108 * iterator pairs, none of the sequences may be empty. If there 109 * are several equal elements across the split, the ones on the 110 * left side will be chosen from sequences with smaller number. 111 * @param begin_seqs Begin of the sequence of iterator pairs. 112 * @param end_seqs End of the sequence of iterator pairs. 113 * @param rank The global rank to partition at. 114 * @param begin_offsets A random-access sequence begin where the 115 * result will be stored in. Each element of the sequence is an 116 * iterator that points to the first element on the greater part of 117 * the respective sequence. 118 * @param comp The ordering functor, defaults to std::less<T>. 119 */ 120 template<typename RanSeqs, typename RankType, typename RankIterator, 121 typename Comparator> 122 void 123 multiseq_partition(RanSeqs begin_seqs, RanSeqs end_seqs, 124 RankType rank, 125 RankIterator begin_offsets, 126 Comparator comp = std::less< 127 typename std::iterator_traits<typename 128 std::iterator_traits<RanSeqs>::value_type:: 129 first_type>::value_type>()) // std::less<T> 130 { 131 _GLIBCXX_CALL(end_seqs - begin_seqs) 132 133 typedef typename std::iterator_traits<RanSeqs>::value_type::first_type 134 It; 135 typedef typename std::iterator_traits<It>::difference_type 136 difference_type; 137 typedef typename std::iterator_traits<It>::value_type value_type; 138 139 lexicographic<value_type, int, Comparator> lcomp(comp); 140 lexicographic_reverse<value_type, int, Comparator> lrcomp(comp); 141 142 // Number of sequences, number of elements in total (possibly 143 // including padding). 144 difference_type m = std::distance(begin_seqs, end_seqs), N = 0, 145 nmax, n, r; 146 147 for (int i = 0; i < m; i++) 148 { 149 N += std::distance(begin_seqs[i].first, begin_seqs[i].second); 150 _GLIBCXX_PARALLEL_ASSERT( 151 std::distance(begin_seqs[i].first, begin_seqs[i].second) > 0); 152 } 153 154 if (rank == N) 155 { 156 for (int i = 0; i < m; i++) 157 begin_offsets[i] = begin_seqs[i].second; // Very end. 158 // Return m - 1; 159 return; 160 } 161 162 _GLIBCXX_PARALLEL_ASSERT(m != 0); 163 _GLIBCXX_PARALLEL_ASSERT(N != 0); 164 _GLIBCXX_PARALLEL_ASSERT(rank >= 0); 165 _GLIBCXX_PARALLEL_ASSERT(rank < N); 166 167 difference_type* ns = new difference_type[m]; 168 difference_type* a = new difference_type[m]; 169 difference_type* b = new difference_type[m]; 170 difference_type l; 171 172 ns[0] = std::distance(begin_seqs[0].first, begin_seqs[0].second); 173 nmax = ns[0]; 174 for (int i = 0; i < m; i++) 175 { 176 ns[i] = std::distance(begin_seqs[i].first, begin_seqs[i].second); 177 nmax = std::max(nmax, ns[i]); 178 } 179 180 r = __log2(nmax) + 1; 181 182 // Pad all lists to this length, at least as long as any ns[i], 183 // equality iff nmax = 2^k - 1. 184 l = (1ULL << r) - 1; 185 186 for (int i = 0; i < m; i++) 187 { 188 a[i] = 0; 189 b[i] = l; 190 } 191 n = l / 2; 192 193 // Invariants: 194 // 0 <= a[i] <= ns[i], 0 <= b[i] <= l 195 196 #define S(i) (begin_seqs[i].first) 197 198 // Initial partition. 199 std::vector<std::pair<value_type, int> > sample; 200 201 for (int i = 0; i < m; i++) 202 if (n < ns[i]) //sequence long enough 203 sample.push_back(std::make_pair(S(i)[n], i)); 204 __gnu_sequential::sort(sample.begin(), sample.end(), lcomp); 205 206 for (int i = 0; i < m; i++) //conceptual infinity 207 if (n >= ns[i]) //sequence too short, conceptual infinity 208 sample.push_back(std::make_pair(S(i)[0] /*dummy element*/, i)); 209 210 difference_type localrank = rank / l; 211 212 int j; 213 for (j = 0; j < localrank && ((n + 1) <= ns[sample[j].second]); ++j) 214 a[sample[j].second] += n + 1; 215 for (; j < m; j++) 216 b[sample[j].second] -= n + 1; 217 218 // Further refinement. 219 while (n > 0) 220 { 221 n /= 2; 222 223 int lmax_seq = -1; // to avoid warning 224 const value_type* lmax = NULL; // impossible to avoid the warning? 225 for (int i = 0; i < m; i++) 226 { 227 if (a[i] > 0) 228 { 229 if (!lmax) 230 { 231 lmax = &(S(i)[a[i] - 1]); 232 lmax_seq = i; 233 } 234 else 235 { 236 // Max, favor rear sequences. 237 if (!comp(S(i)[a[i] - 1], *lmax)) 238 { 239 lmax = &(S(i)[a[i] - 1]); 240 lmax_seq = i; 241 } 242 } 243 } 244 } 245 246 int i; 247 for (i = 0; i < m; i++) 248 { 249 difference_type middle = (b[i] + a[i]) / 2; 250 if (lmax && middle < ns[i] && 251 lcomp(std::make_pair(S(i)[middle], i), 252 std::make_pair(*lmax, lmax_seq))) 253 a[i] = std::min(a[i] + n + 1, ns[i]); 254 else 255 b[i] -= n + 1; 256 } 257 258 difference_type leftsize = 0; 259 for (int i = 0; i < m; i++) 260 leftsize += a[i] / (n + 1); 261 262 difference_type skew = rank / (n + 1) - leftsize; 263 264 if (skew > 0) 265 { 266 // Move to the left, find smallest. 267 std::priority_queue<std::pair<value_type, int>, 268 std::vector<std::pair<value_type, int> >, 269 lexicographic_reverse<value_type, int, Comparator> > 270 pq(lrcomp); 271 272 for (int i = 0; i < m; i++) 273 if (b[i] < ns[i]) 274 pq.push(std::make_pair(S(i)[b[i]], i)); 275 276 for (; skew != 0 && !pq.empty(); --skew) 277 { 278 int source = pq.top().second; 279 pq.pop(); 280 281 a[source] = std::min(a[source] + n + 1, ns[source]); 282 b[source] += n + 1; 283 284 if (b[source] < ns[source]) 285 pq.push(std::make_pair(S(source)[b[source]], source)); 286 } 287 } 288 else if (skew < 0) 289 { 290 // Move to the right, find greatest. 291 std::priority_queue<std::pair<value_type, int>, 292 std::vector<std::pair<value_type, int> >, 293 lexicographic<value_type, int, Comparator> > pq(lcomp); 294 295 for (int i = 0; i < m; i++) 296 if (a[i] > 0) 297 pq.push(std::make_pair(S(i)[a[i] - 1], i)); 298 299 for (; skew != 0; ++skew) 300 { 301 int source = pq.top().second; 302 pq.pop(); 303 304 a[source] -= n + 1; 305 b[source] -= n + 1; 306 307 if (a[source] > 0) 308 pq.push(std::make_pair(S(source)[a[source] - 1], source)); 309 } 310 } 311 } 312 313 // Postconditions: 314 // a[i] == b[i] in most cases, except when a[i] has been clamped 315 // because of having reached the boundary 316 317 // Now return the result, calculate the offset. 318 319 // Compare the keys on both edges of the border. 320 321 // Maximum of left edge, minimum of right edge. 322 value_type* maxleft = NULL; 323 value_type* minright = NULL; 324 for (int i = 0; i < m; i++) 325 { 326 if (a[i] > 0) 327 { 328 if (!maxleft) 329 maxleft = &(S(i)[a[i] - 1]); 330 else 331 { 332 // Max, favor rear sequences. 333 if (!comp(S(i)[a[i] - 1], *maxleft)) 334 maxleft = &(S(i)[a[i] - 1]); 335 } 336 } 337 if (b[i] < ns[i]) 338 { 339 if (!minright) 340 minright = &(S(i)[b[i]]); 341 else 342 { 343 // Min, favor fore sequences. 344 if (comp(S(i)[b[i]], *minright)) 345 minright = &(S(i)[b[i]]); 346 } 347 } 348 } 349 350 int seq = 0; 351 for (int i = 0; i < m; i++) 352 begin_offsets[i] = S(i) + a[i]; 353 354 delete[] ns; 355 delete[] a; 356 delete[] b; 357 } 358 359 360 /** 361 * @brief Selects the element at a certain global rank from several 362 * sorted sequences. 363 * 364 * The sequences are passed via a sequence of random-access 365 * iterator pairs, none of the sequences may be empty. 366 * @param begin_seqs Begin of the sequence of iterator pairs. 367 * @param end_seqs End of the sequence of iterator pairs. 368 * @param rank The global rank to partition at. 369 * @param offset The rank of the selected element in the global 370 * subsequence of elements equal to the selected element. If the 371 * selected element is unique, this number is 0. 372 * @param comp The ordering functor, defaults to std::less. 373 */ 374 template<typename T, typename RanSeqs, typename RankType, 375 typename Comparator> 376 T 377 multiseq_selection(RanSeqs begin_seqs, RanSeqs end_seqs, RankType rank, 378 RankType& offset, Comparator comp = std::less<T>()) 379 { 380 _GLIBCXX_CALL(end_seqs - begin_seqs) 381 382 typedef typename std::iterator_traits<RanSeqs>::value_type::first_type 383 It; 384 typedef typename std::iterator_traits<It>::difference_type 385 difference_type; 386 387 lexicographic<T, int, Comparator> lcomp(comp); 388 lexicographic_reverse<T, int, Comparator> lrcomp(comp); 389 390 // Number of sequences, number of elements in total (possibly 391 // including padding). 392 difference_type m = std::distance(begin_seqs, end_seqs); 393 difference_type N = 0; 394 difference_type nmax, n, r; 395 396 for (int i = 0; i < m; i++) 397 N += std::distance(begin_seqs[i].first, begin_seqs[i].second); 398 399 if (m == 0 || N == 0 || rank < 0 || rank >= N) 400 { 401 // Result undefined when there is no data or rank is outside bounds. 402 throw std::exception(); 403 } 404 405 406 difference_type* ns = new difference_type[m]; 407 difference_type* a = new difference_type[m]; 408 difference_type* b = new difference_type[m]; 409 difference_type l; 410 411 ns[0] = std::distance(begin_seqs[0].first, begin_seqs[0].second); 412 nmax = ns[0]; 413 for (int i = 0; i < m; ++i) 414 { 415 ns[i] = std::distance(begin_seqs[i].first, begin_seqs[i].second); 416 nmax = std::max(nmax, ns[i]); 417 } 418 419 r = __log2(nmax) + 1; 420 421 // Pad all lists to this length, at least as long as any ns[i], 422 // equality iff nmax = 2^k - 1 423 l = pow2(r) - 1; 424 425 for (int i = 0; i < m; ++i) 426 { 427 a[i] = 0; 428 b[i] = l; 429 } 430 n = l / 2; 431 432 // Invariants: 433 // 0 <= a[i] <= ns[i], 0 <= b[i] <= l 434 435 #define S(i) (begin_seqs[i].first) 436 437 // Initial partition. 438 std::vector<std::pair<T, int> > sample; 439 440 for (int i = 0; i < m; i++) 441 if (n < ns[i]) 442 sample.push_back(std::make_pair(S(i)[n], i)); 443 __gnu_sequential::sort(sample.begin(), sample.end(), 444 lcomp, sequential_tag()); 445 446 // Conceptual infinity. 447 for (int i = 0; i < m; i++) 448 if (n >= ns[i]) 449 sample.push_back(std::make_pair(S(i)[0] /*dummy element*/, i)); 450 451 difference_type localrank = rank / l; 452 453 int j; 454 for (j = 0; j < localrank && ((n + 1) <= ns[sample[j].second]); ++j) 455 a[sample[j].second] += n + 1; 456 for (; j < m; ++j) 457 b[sample[j].second] -= n + 1; 458 459 // Further refinement. 460 while (n > 0) 461 { 462 n /= 2; 463 464 const T* lmax = NULL; 465 for (int i = 0; i < m; ++i) 466 { 467 if (a[i] > 0) 468 { 469 if (!lmax) 470 lmax = &(S(i)[a[i] - 1]); 471 else 472 { 473 if (comp(*lmax, S(i)[a[i] - 1])) //max 474 lmax = &(S(i)[a[i] - 1]); 475 } 476 } 477 } 478 479 int i; 480 for (i = 0; i < m; i++) 481 { 482 difference_type middle = (b[i] + a[i]) / 2; 483 if (lmax && middle < ns[i] && comp(S(i)[middle], *lmax)) 484 a[i] = std::min(a[i] + n + 1, ns[i]); 485 else 486 b[i] -= n + 1; 487 } 488 489 difference_type leftsize = 0; 490 for (int i = 0; i < m; ++i) 491 leftsize += a[i] / (n + 1); 492 493 difference_type skew = rank / (n + 1) - leftsize; 494 495 if (skew > 0) 496 { 497 // Move to the left, find smallest. 498 std::priority_queue<std::pair<T, int>, 499 std::vector<std::pair<T, int> >, 500 lexicographic_reverse<T, int, Comparator> > pq(lrcomp); 501 502 for (int i = 0; i < m; ++i) 503 if (b[i] < ns[i]) 504 pq.push(std::make_pair(S(i)[b[i]], i)); 505 506 for (; skew != 0 && !pq.empty(); --skew) 507 { 508 int source = pq.top().second; 509 pq.pop(); 510 511 a[source] = std::min(a[source] + n + 1, ns[source]); 512 b[source] += n + 1; 513 514 if (b[source] < ns[source]) 515 pq.push(std::make_pair(S(source)[b[source]], source)); 516 } 517 } 518 else if (skew < 0) 519 { 520 // Move to the right, find greatest. 521 std::priority_queue<std::pair<T, int>, 522 std::vector<std::pair<T, int> >, 523 lexicographic<T, int, Comparator> > pq(lcomp); 524 525 for (int i = 0; i < m; ++i) 526 if (a[i] > 0) 527 pq.push(std::make_pair(S(i)[a[i] - 1], i)); 528 529 for (; skew != 0; ++skew) 530 { 531 int source = pq.top().second; 532 pq.pop(); 533 534 a[source] -= n + 1; 535 b[source] -= n + 1; 536 537 if (a[source] > 0) 538 pq.push(std::make_pair(S(source)[a[source] - 1], source)); 539 } 540 } 541 } 542 543 // Postconditions: 544 // a[i] == b[i] in most cases, except when a[i] has been clamped 545 // because of having reached the boundary 546 547 // Now return the result, calculate the offset. 548 549 // Compare the keys on both edges of the border. 550 551 // Maximum of left edge, minimum of right edge. 552 bool maxleftset = false, minrightset = false; 553 554 // Impossible to avoid the warning? 555 T maxleft, minright; 556 for (int i = 0; i < m; ++i) 557 { 558 if (a[i] > 0) 559 { 560 if (!maxleftset) 561 { 562 maxleft = S(i)[a[i] - 1]; 563 maxleftset = true; 564 } 565 else 566 { 567 // Max. 568 if (comp(maxleft, S(i)[a[i] - 1])) 569 maxleft = S(i)[a[i] - 1]; 570 } 571 } 572 if (b[i] < ns[i]) 573 { 574 if (!minrightset) 575 { 576 minright = S(i)[b[i]]; 577 minrightset = true; 578 } 579 else 580 { 581 // Min. 582 if (comp(S(i)[b[i]], minright)) 583 minright = S(i)[b[i]]; 584 } 585 } 586 } 587 588 // Minright is the splitter, in any case. 589 590 if (!maxleftset || comp(minright, maxleft)) 591 { 592 // Good luck, everything is split unambiguously. 593 offset = 0; 594 } 595 else 596 { 597 // We have to calculate an offset. 598 offset = 0; 599 600 for (int i = 0; i < m; ++i) 601 { 602 difference_type lb = std::lower_bound(S(i), S(i) + ns[i], 603 minright, 604 comp) - S(i); 605 offset += a[i] - lb; 606 } 607 } 608 609 delete[] ns; 610 delete[] a; 611 delete[] b; 612 613 return minright; 614 } 615 } 616 617 #undef S 618 619 #endif /* _GLIBCXX_PARALLEL_MULTISEQ_SELECTION_H */ 620