2007-09-11 22:32:51 +00:00
|
|
|
|
// -*- C++ -*-
|
|
|
|
|
|
2009-04-09 17:00:19 +02:00
|
|
|
|
// Copyright (C) 2007, 2008, 2009 Free Software Foundation, Inc.
|
2007-09-11 22:32:51 +00:00
|
|
|
|
//
|
|
|
|
|
// This file is part of the GNU ISO C++ Library. This library is free
|
|
|
|
|
// software; you can redistribute it and/or modify it under the terms
|
|
|
|
|
// of the GNU General Public License as published by the Free Software
|
2009-04-09 17:00:19 +02:00
|
|
|
|
// Foundation; either version 3, or (at your option) any later
|
2007-09-11 22:32:51 +00:00
|
|
|
|
// version.
|
|
|
|
|
|
|
|
|
|
// This library is distributed in the hope that it will be useful, but
|
|
|
|
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
|
// General Public License for more details.
|
|
|
|
|
|
2009-04-09 17:00:19 +02:00
|
|
|
|
// Under Section 7 of GPL version 3, you are granted additional
|
|
|
|
|
// permissions described in the GCC Runtime Library Exception, version
|
|
|
|
|
// 3.1, as published by the Free Software Foundation.
|
2007-09-11 22:32:51 +00:00
|
|
|
|
|
2009-04-09 17:00:19 +02:00
|
|
|
|
// You should have received a copy of the GNU General Public License and
|
|
|
|
|
// a copy of the GCC Runtime Library Exception along with this program;
|
|
|
|
|
// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
|
|
|
|
|
// <http://www.gnu.org/licenses/>.
|
2007-09-11 22:32:51 +00:00
|
|
|
|
|
|
|
|
|
/** @file parallel/multiseq_selection.h
|
|
|
|
|
* @brief Functions to find elements of a certain global rank in
|
|
|
|
|
* multiple sorted sequences. Also serves for splitting such
|
|
|
|
|
* sequence sets.
|
2007-10-08 15:17:28 +00:00
|
|
|
|
*
|
|
|
|
|
* The algorithm description can be found in
|
|
|
|
|
*
|
|
|
|
|
* P. J. Varman, S. D. Scheufler, B. R. Iyer, and G. R. Ricard.
|
|
|
|
|
* Merging Multiple Lists on Hierarchical-Memory Multiprocessors.
|
|
|
|
|
* Journal of Parallel and Distributed Computing, 12(2):171–177, 1991.
|
|
|
|
|
*
|
2007-09-11 22:32:51 +00:00
|
|
|
|
* This file is a GNU parallel extension to the Standard C++ Library.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
// Written by Johannes Singler.
|
|
|
|
|
|
|
|
|
|
#ifndef _GLIBCXX_PARALLEL_MULTISEQ_SELECTION_H
|
|
|
|
|
#define _GLIBCXX_PARALLEL_MULTISEQ_SELECTION_H 1
|
|
|
|
|
|
|
|
|
|
#include <vector>
|
|
|
|
|
#include <queue>
|
|
|
|
|
|
|
|
|
|
#include <bits/stl_algo.h>
|
|
|
|
|
|
|
|
|
|
#include <parallel/sort.h>
|
|
|
|
|
|
|
|
|
|
namespace __gnu_parallel
|
|
|
|
|
{
|
|
|
|
|
/** @brief Compare a pair of types lexicographically, ascending. */
|
|
|
|
|
template<typename T1, typename T2, typename Comparator>
|
2008-01-09 18:27:27 +00:00
|
|
|
|
class lexicographic
|
|
|
|
|
: public std::binary_function<std::pair<T1, T2>, std::pair<T1, T2>, bool>
|
|
|
|
|
{
|
|
|
|
|
private:
|
|
|
|
|
Comparator& comp;
|
2007-09-11 22:32:51 +00:00
|
|
|
|
|
2008-01-09 18:27:27 +00:00
|
|
|
|
public:
|
|
|
|
|
lexicographic(Comparator& _comp) : comp(_comp) { }
|
2007-09-11 22:32:51 +00:00
|
|
|
|
|
2008-01-09 18:27:27 +00:00
|
|
|
|
bool
|
|
|
|
|
operator()(const std::pair<T1, T2>& p1,
|
|
|
|
|
const std::pair<T1, T2>& p2) const
|
|
|
|
|
{
|
|
|
|
|
if (comp(p1.first, p2.first))
|
|
|
|
|
return true;
|
2007-09-11 22:32:51 +00:00
|
|
|
|
|
2008-01-09 18:27:27 +00:00
|
|
|
|
if (comp(p2.first, p1.first))
|
|
|
|
|
return false;
|
2007-09-11 22:32:51 +00:00
|
|
|
|
|
2008-01-09 18:27:27 +00:00
|
|
|
|
// Firsts are equal.
|
|
|
|
|
return p1.second < p2.second;
|
|
|
|
|
}
|
|
|
|
|
};
|
2007-09-11 22:32:51 +00:00
|
|
|
|
|
|
|
|
|
/** @brief Compare a pair of types lexicographically, descending. */
|
|
|
|
|
template<typename T1, typename T2, typename Comparator>
|
2008-01-09 18:27:27 +00:00
|
|
|
|
class lexicographic_reverse : public std::binary_function<T1, T2, bool>
|
|
|
|
|
{
|
|
|
|
|
private:
|
|
|
|
|
Comparator& comp;
|
2007-09-11 22:32:51 +00:00
|
|
|
|
|
2008-01-09 18:27:27 +00:00
|
|
|
|
public:
|
|
|
|
|
lexicographic_reverse(Comparator& _comp) : comp(_comp) { }
|
2007-09-11 22:32:51 +00:00
|
|
|
|
|
2008-01-09 18:27:27 +00:00
|
|
|
|
bool
|
|
|
|
|
operator()(const std::pair<T1, T2>& p1,
|
|
|
|
|
const std::pair<T1, T2>& p2) const
|
|
|
|
|
{
|
|
|
|
|
if (comp(p2.first, p1.first))
|
|
|
|
|
return true;
|
2007-09-11 22:32:51 +00:00
|
|
|
|
|
2008-01-09 18:27:27 +00:00
|
|
|
|
if (comp(p1.first, p2.first))
|
|
|
|
|
return false;
|
2007-09-11 22:32:51 +00:00
|
|
|
|
|
2008-01-09 18:27:27 +00:00
|
|
|
|
// Firsts are equal.
|
|
|
|
|
return p2.second < p1.second;
|
|
|
|
|
}
|
|
|
|
|
};
|
2007-09-11 22:32:51 +00:00
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Splits several sorted sequences at a certain global rank,
|
|
|
|
|
* resulting in a splitting point for each sequence.
|
|
|
|
|
* The sequences are passed via a sequence of random-access
|
|
|
|
|
* iterator pairs, none of the sequences may be empty. If there
|
|
|
|
|
* are several equal elements across the split, the ones on the
|
|
|
|
|
* left side will be chosen from sequences with smaller number.
|
|
|
|
|
* @param begin_seqs Begin of the sequence of iterator pairs.
|
|
|
|
|
* @param end_seqs End of the sequence of iterator pairs.
|
|
|
|
|
* @param rank The global rank to partition at.
|
|
|
|
|
* @param begin_offsets A random-access sequence begin where the
|
|
|
|
|
* result will be stored in. Each element of the sequence is an
|
|
|
|
|
* iterator that points to the first element on the greater part of
|
|
|
|
|
* the respective sequence.
|
|
|
|
|
* @param comp The ordering functor, defaults to std::less<T>.
|
|
|
|
|
*/
|
2008-01-09 18:27:27 +00:00
|
|
|
|
template<typename RanSeqs, typename RankType, typename RankIterator,
|
2008-04-23 07:20:58 +00:00
|
|
|
|
typename Comparator>
|
2008-01-09 18:27:27 +00:00
|
|
|
|
void
|
|
|
|
|
multiseq_partition(RanSeqs begin_seqs, RanSeqs end_seqs,
|
2008-04-23 07:20:58 +00:00
|
|
|
|
RankType rank,
|
|
|
|
|
RankIterator begin_offsets,
|
|
|
|
|
Comparator comp = std::less<
|
|
|
|
|
typename std::iterator_traits<typename
|
|
|
|
|
std::iterator_traits<RanSeqs>::value_type::
|
|
|
|
|
first_type>::value_type>()) // std::less<T>
|
2008-01-09 18:27:27 +00:00
|
|
|
|
{
|
|
|
|
|
_GLIBCXX_CALL(end_seqs - begin_seqs)
|
|
|
|
|
|
|
|
|
|
typedef typename std::iterator_traits<RanSeqs>::value_type::first_type
|
2008-04-23 07:20:58 +00:00
|
|
|
|
It;
|
2008-01-09 18:27:27 +00:00
|
|
|
|
typedef typename std::iterator_traits<It>::difference_type
|
2008-04-23 07:20:58 +00:00
|
|
|
|
difference_type;
|
2008-01-09 18:27:27 +00:00
|
|
|
|
typedef typename std::iterator_traits<It>::value_type value_type;
|
|
|
|
|
|
|
|
|
|
lexicographic<value_type, int, Comparator> lcomp(comp);
|
|
|
|
|
lexicographic_reverse<value_type, int, Comparator> lrcomp(comp);
|
|
|
|
|
|
|
|
|
|
// Number of sequences, number of elements in total (possibly
|
|
|
|
|
// including padding).
|
|
|
|
|
difference_type m = std::distance(begin_seqs, end_seqs), N = 0,
|
2008-04-23 07:20:58 +00:00
|
|
|
|
nmax, n, r;
|
2008-01-09 18:27:27 +00:00
|
|
|
|
|
|
|
|
|
for (int i = 0; i < m; i++)
|
2008-04-23 07:20:58 +00:00
|
|
|
|
{
|
|
|
|
|
N += std::distance(begin_seqs[i].first, begin_seqs[i].second);
|
|
|
|
|
_GLIBCXX_PARALLEL_ASSERT(
|
|
|
|
|
std::distance(begin_seqs[i].first, begin_seqs[i].second) > 0);
|
|
|
|
|
}
|
2008-01-09 18:27:27 +00:00
|
|
|
|
|
|
|
|
|
if (rank == N)
|
2008-04-23 07:20:58 +00:00
|
|
|
|
{
|
|
|
|
|
for (int i = 0; i < m; i++)
|
|
|
|
|
begin_offsets[i] = begin_seqs[i].second; // Very end.
|
|
|
|
|
// Return m - 1;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_GLIBCXX_PARALLEL_ASSERT(m != 0);
|
|
|
|
|
_GLIBCXX_PARALLEL_ASSERT(N != 0);
|
|
|
|
|
_GLIBCXX_PARALLEL_ASSERT(rank >= 0);
|
|
|
|
|
_GLIBCXX_PARALLEL_ASSERT(rank < N);
|
2008-01-09 18:27:27 +00:00
|
|
|
|
|
|
|
|
|
difference_type* ns = new difference_type[m];
|
|
|
|
|
difference_type* a = new difference_type[m];
|
|
|
|
|
difference_type* b = new difference_type[m];
|
|
|
|
|
difference_type l;
|
|
|
|
|
|
|
|
|
|
ns[0] = std::distance(begin_seqs[0].first, begin_seqs[0].second);
|
|
|
|
|
nmax = ns[0];
|
|
|
|
|
for (int i = 0; i < m; i++)
|
|
|
|
|
{
|
|
|
|
|
ns[i] = std::distance(begin_seqs[i].first, begin_seqs[i].second);
|
|
|
|
|
nmax = std::max(nmax, ns[i]);
|
|
|
|
|
}
|
|
|
|
|
|
2008-09-19 11:37:16 +00:00
|
|
|
|
r = __log2(nmax) + 1;
|
2008-01-09 18:27:27 +00:00
|
|
|
|
|
|
|
|
|
// Pad all lists to this length, at least as long as any ns[i],
|
|
|
|
|
// equality iff nmax = 2^k - 1.
|
|
|
|
|
l = (1ULL << r) - 1;
|
|
|
|
|
|
|
|
|
|
// From now on, including padding.
|
|
|
|
|
N = l * m;
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < m; i++)
|
|
|
|
|
{
|
|
|
|
|
a[i] = 0;
|
|
|
|
|
b[i] = l;
|
|
|
|
|
}
|
|
|
|
|
n = l / 2;
|
|
|
|
|
|
|
|
|
|
// Invariants:
|
|
|
|
|
// 0 <= a[i] <= ns[i], 0 <= b[i] <= l
|
2007-09-11 22:32:51 +00:00
|
|
|
|
|
|
|
|
|
#define S(i) (begin_seqs[i].first)
|
|
|
|
|
|
2008-01-09 18:27:27 +00:00
|
|
|
|
// Initial partition.
|
|
|
|
|
std::vector<std::pair<value_type, int> > sample;
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < m; i++)
|
|
|
|
|
if (n < ns[i]) //sequence long enough
|
|
|
|
|
sample.push_back(std::make_pair(S(i)[n], i));
|
|
|
|
|
__gnu_sequential::sort(sample.begin(), sample.end(), lcomp);
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < m; i++) //conceptual infinity
|
|
|
|
|
if (n >= ns[i]) //sequence too short, conceptual infinity
|
|
|
|
|
sample.push_back(std::make_pair(S(i)[0] /*dummy element*/, i));
|
|
|
|
|
|
|
|
|
|
difference_type localrank = rank * m / N ;
|
|
|
|
|
|
|
|
|
|
int j;
|
2008-01-10 02:07:41 +00:00
|
|
|
|
for (j = 0; j < localrank && ((n + 1) <= ns[sample[j].second]); ++j)
|
2008-01-09 18:27:27 +00:00
|
|
|
|
a[sample[j].second] += n + 1;
|
|
|
|
|
for (; j < m; j++)
|
|
|
|
|
b[sample[j].second] -= n + 1;
|
|
|
|
|
|
|
|
|
|
// Further refinement.
|
|
|
|
|
while (n > 0)
|
|
|
|
|
{
|
|
|
|
|
n /= 2;
|
|
|
|
|
|
|
|
|
|
int lmax_seq = -1; // to avoid warning
|
|
|
|
|
const value_type* lmax = NULL; // impossible to avoid the warning?
|
|
|
|
|
for (int i = 0; i < m; i++)
|
|
|
|
|
{
|
2007-09-11 22:32:51 +00:00
|
|
|
|
if (a[i] > 0)
|
2008-01-09 18:27:27 +00:00
|
|
|
|
{
|
|
|
|
|
if (!lmax)
|
|
|
|
|
{
|
|
|
|
|
lmax = &(S(i)[a[i] - 1]);
|
|
|
|
|
lmax_seq = i;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// Max, favor rear sequences.
|
|
|
|
|
if (!comp(S(i)[a[i] - 1], *lmax))
|
|
|
|
|
{
|
|
|
|
|
lmax = &(S(i)[a[i] - 1]);
|
|
|
|
|
lmax_seq = i;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int i;
|
|
|
|
|
for (i = 0; i < m; i++)
|
|
|
|
|
{
|
|
|
|
|
difference_type middle = (b[i] + a[i]) / 2;
|
|
|
|
|
if (lmax && middle < ns[i] &&
|
|
|
|
|
lcomp(std::make_pair(S(i)[middle], i),
|
|
|
|
|
std::make_pair(*lmax, lmax_seq)))
|
|
|
|
|
a[i] = std::min(a[i] + n + 1, ns[i]);
|
|
|
|
|
else
|
|
|
|
|
b[i] -= n + 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
difference_type leftsize = 0, total = 0;
|
|
|
|
|
for (int i = 0; i < m; i++)
|
|
|
|
|
{
|
|
|
|
|
leftsize += a[i] / (n + 1);
|
|
|
|
|
total += l / (n + 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
difference_type skew = static_cast<difference_type>
|
2008-02-17 15:46:30 +00:00
|
|
|
|
(static_cast<uint64>(total) * rank / N - leftsize);
|
2008-01-09 18:27:27 +00:00
|
|
|
|
|
|
|
|
|
if (skew > 0)
|
|
|
|
|
{
|
|
|
|
|
// Move to the left, find smallest.
|
|
|
|
|
std::priority_queue<std::pair<value_type, int>,
|
|
|
|
|
std::vector<std::pair<value_type, int> >,
|
|
|
|
|
lexicographic_reverse<value_type, int, Comparator> >
|
|
|
|
|
pq(lrcomp);
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < m; i++)
|
|
|
|
|
if (b[i] < ns[i])
|
|
|
|
|
pq.push(std::make_pair(S(i)[b[i]], i));
|
|
|
|
|
|
2008-01-10 02:07:41 +00:00
|
|
|
|
for (; skew != 0 && !pq.empty(); --skew)
|
2008-01-09 18:27:27 +00:00
|
|
|
|
{
|
|
|
|
|
int source = pq.top().second;
|
|
|
|
|
pq.pop();
|
|
|
|
|
|
|
|
|
|
a[source] = std::min(a[source] + n + 1, ns[source]);
|
|
|
|
|
b[source] += n + 1;
|
|
|
|
|
|
|
|
|
|
if (b[source] < ns[source])
|
|
|
|
|
pq.push(std::make_pair(S(source)[b[source]], source));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (skew < 0)
|
|
|
|
|
{
|
|
|
|
|
// Move to the right, find greatest.
|
|
|
|
|
std::priority_queue<std::pair<value_type, int>,
|
|
|
|
|
std::vector<std::pair<value_type, int> >,
|
|
|
|
|
lexicographic<value_type, int, Comparator> > pq(lcomp);
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < m; i++)
|
|
|
|
|
if (a[i] > 0)
|
|
|
|
|
pq.push(std::make_pair(S(i)[a[i] - 1], i));
|
|
|
|
|
|
2008-01-10 02:07:41 +00:00
|
|
|
|
for (; skew != 0; ++skew)
|
2008-01-09 18:27:27 +00:00
|
|
|
|
{
|
|
|
|
|
int source = pq.top().second;
|
|
|
|
|
pq.pop();
|
|
|
|
|
|
|
|
|
|
a[source] -= n + 1;
|
|
|
|
|
b[source] -= n + 1;
|
|
|
|
|
|
|
|
|
|
if (a[source] > 0)
|
|
|
|
|
pq.push(std::make_pair(S(source)[a[source] - 1], source));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Postconditions:
|
|
|
|
|
// a[i] == b[i] in most cases, except when a[i] has been clamped
|
|
|
|
|
// because of having reached the boundary
|
|
|
|
|
|
|
|
|
|
// Now return the result, calculate the offset.
|
|
|
|
|
|
|
|
|
|
// Compare the keys on both edges of the border.
|
|
|
|
|
|
|
|
|
|
// Maximum of left edge, minimum of right edge.
|
|
|
|
|
value_type* maxleft = NULL;
|
|
|
|
|
value_type* minright = NULL;
|
|
|
|
|
for (int i = 0; i < m; i++)
|
|
|
|
|
{
|
|
|
|
|
if (a[i] > 0)
|
|
|
|
|
{
|
|
|
|
|
if (!maxleft)
|
|
|
|
|
maxleft = &(S(i)[a[i] - 1]);
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// Max, favor rear sequences.
|
|
|
|
|
if (!comp(S(i)[a[i] - 1], *maxleft))
|
|
|
|
|
maxleft = &(S(i)[a[i] - 1]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (b[i] < ns[i])
|
|
|
|
|
{
|
|
|
|
|
if (!minright)
|
|
|
|
|
minright = &(S(i)[b[i]]);
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// Min, favor fore sequences.
|
|
|
|
|
if (comp(S(i)[b[i]], *minright))
|
|
|
|
|
minright = &(S(i)[b[i]]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int seq = 0;
|
|
|
|
|
for (int i = 0; i < m; i++)
|
|
|
|
|
begin_offsets[i] = S(i) + a[i];
|
|
|
|
|
|
|
|
|
|
delete[] ns;
|
|
|
|
|
delete[] a;
|
|
|
|
|
delete[] b;
|
|
|
|
|
}
|
2007-09-11 22:32:51 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Selects the element at a certain global rank from several
|
|
|
|
|
* sorted sequences.
|
|
|
|
|
*
|
|
|
|
|
* The sequences are passed via a sequence of random-access
|
|
|
|
|
* iterator pairs, none of the sequences may be empty.
|
|
|
|
|
* @param begin_seqs Begin of the sequence of iterator pairs.
|
|
|
|
|
* @param end_seqs End of the sequence of iterator pairs.
|
|
|
|
|
* @param rank The global rank to partition at.
|
|
|
|
|
* @param offset The rank of the selected element in the global
|
|
|
|
|
* subsequence of elements equal to the selected element. If the
|
|
|
|
|
* selected element is unique, this number is 0.
|
|
|
|
|
* @param comp The ordering functor, defaults to std::less.
|
|
|
|
|
*/
|
2008-01-09 18:27:27 +00:00
|
|
|
|
template<typename T, typename RanSeqs, typename RankType,
|
|
|
|
|
typename Comparator>
|
|
|
|
|
T
|
|
|
|
|
multiseq_selection(RanSeqs begin_seqs, RanSeqs end_seqs, RankType rank,
|
|
|
|
|
RankType& offset, Comparator comp = std::less<T>())
|
|
|
|
|
{
|
|
|
|
|
_GLIBCXX_CALL(end_seqs - begin_seqs)
|
2007-09-11 22:32:51 +00:00
|
|
|
|
|
2008-01-09 18:27:27 +00:00
|
|
|
|
typedef typename std::iterator_traits<RanSeqs>::value_type::first_type
|
|
|
|
|
It;
|
|
|
|
|
typedef typename std::iterator_traits<It>::difference_type
|
|
|
|
|
difference_type;
|
2007-09-11 22:32:51 +00:00
|
|
|
|
|
2008-01-09 18:27:27 +00:00
|
|
|
|
lexicographic<T, int, Comparator> lcomp(comp);
|
|
|
|
|
lexicographic_reverse<T, int, Comparator> lrcomp(comp);
|
2007-09-11 22:32:51 +00:00
|
|
|
|
|
2008-01-09 18:27:27 +00:00
|
|
|
|
// Number of sequences, number of elements in total (possibly
|
|
|
|
|
// including padding).
|
|
|
|
|
difference_type m = std::distance(begin_seqs, end_seqs);
|
|
|
|
|
difference_type N = 0;
|
|
|
|
|
difference_type nmax, n, r;
|
2007-09-11 22:32:51 +00:00
|
|
|
|
|
2008-01-09 18:27:27 +00:00
|
|
|
|
for (int i = 0; i < m; i++)
|
|
|
|
|
N += std::distance(begin_seqs[i].first, begin_seqs[i].second);
|
2007-09-11 22:32:51 +00:00
|
|
|
|
|
2008-01-09 18:27:27 +00:00
|
|
|
|
if (m == 0 || N == 0 || rank < 0 || rank >= N)
|
|
|
|
|
{
|
|
|
|
|
// Result undefined when there is no data or rank is outside bounds.
|
|
|
|
|
throw std::exception();
|
|
|
|
|
}
|
2007-09-11 22:32:51 +00:00
|
|
|
|
|
|
|
|
|
|
2008-01-09 18:27:27 +00:00
|
|
|
|
difference_type* ns = new difference_type[m];
|
|
|
|
|
difference_type* a = new difference_type[m];
|
|
|
|
|
difference_type* b = new difference_type[m];
|
|
|
|
|
difference_type l;
|
2007-09-11 22:32:51 +00:00
|
|
|
|
|
2008-01-09 18:27:27 +00:00
|
|
|
|
ns[0] = std::distance(begin_seqs[0].first, begin_seqs[0].second);
|
|
|
|
|
nmax = ns[0];
|
2008-01-10 02:07:41 +00:00
|
|
|
|
for (int i = 0; i < m; ++i)
|
2008-01-09 18:27:27 +00:00
|
|
|
|
{
|
|
|
|
|
ns[i] = std::distance(begin_seqs[i].first, begin_seqs[i].second);
|
|
|
|
|
nmax = std::max(nmax, ns[i]);
|
|
|
|
|
}
|
2007-09-11 22:32:51 +00:00
|
|
|
|
|
2008-09-19 11:37:16 +00:00
|
|
|
|
r = __log2(nmax) + 1;
|
2007-09-11 22:32:51 +00:00
|
|
|
|
|
2008-01-09 18:27:27 +00:00
|
|
|
|
// Pad all lists to this length, at least as long as any ns[i],
|
|
|
|
|
// equality iff nmax = 2^k - 1
|
|
|
|
|
l = pow2(r) - 1;
|
2007-09-11 22:32:51 +00:00
|
|
|
|
|
2008-01-09 18:27:27 +00:00
|
|
|
|
// From now on, including padding.
|
|
|
|
|
N = l * m;
|
2007-09-11 22:32:51 +00:00
|
|
|
|
|
2008-01-10 02:07:41 +00:00
|
|
|
|
for (int i = 0; i < m; ++i)
|
2008-01-09 18:27:27 +00:00
|
|
|
|
{
|
|
|
|
|
a[i] = 0;
|
|
|
|
|
b[i] = l;
|
|
|
|
|
}
|
|
|
|
|
n = l / 2;
|
2007-09-11 22:32:51 +00:00
|
|
|
|
|
2008-01-09 18:27:27 +00:00
|
|
|
|
// Invariants:
|
|
|
|
|
// 0 <= a[i] <= ns[i], 0 <= b[i] <= l
|
2007-09-11 22:32:51 +00:00
|
|
|
|
|
|
|
|
|
#define S(i) (begin_seqs[i].first)
|
|
|
|
|
|
2008-01-09 18:27:27 +00:00
|
|
|
|
// Initial partition.
|
|
|
|
|
std::vector<std::pair<T, int> > sample;
|
2007-09-11 22:32:51 +00:00
|
|
|
|
|
2008-01-09 18:27:27 +00:00
|
|
|
|
for (int i = 0; i < m; i++)
|
|
|
|
|
if (n < ns[i])
|
|
|
|
|
sample.push_back(std::make_pair(S(i)[n], i));
|
|
|
|
|
__gnu_sequential::sort(sample.begin(), sample.end(),
|
|
|
|
|
lcomp, sequential_tag());
|
2007-09-11 22:32:51 +00:00
|
|
|
|
|
2008-01-09 18:27:27 +00:00
|
|
|
|
// Conceptual infinity.
|
|
|
|
|
for (int i = 0; i < m; i++)
|
|
|
|
|
if (n >= ns[i])
|
|
|
|
|
sample.push_back(std::make_pair(S(i)[0] /*dummy element*/, i));
|
2007-09-11 22:32:51 +00:00
|
|
|
|
|
2008-01-09 18:27:27 +00:00
|
|
|
|
difference_type localrank = rank * m / N ;
|
2007-09-11 22:32:51 +00:00
|
|
|
|
|
2008-01-09 18:27:27 +00:00
|
|
|
|
int j;
|
2008-01-10 02:07:41 +00:00
|
|
|
|
for (j = 0; j < localrank && ((n + 1) <= ns[sample[j].second]); ++j)
|
2008-01-09 18:27:27 +00:00
|
|
|
|
a[sample[j].second] += n + 1;
|
2008-01-10 02:07:41 +00:00
|
|
|
|
for (; j < m; ++j)
|
2008-01-09 18:27:27 +00:00
|
|
|
|
b[sample[j].second] -= n + 1;
|
2007-09-11 22:32:51 +00:00
|
|
|
|
|
2008-01-09 18:27:27 +00:00
|
|
|
|
// Further refinement.
|
|
|
|
|
while (n > 0)
|
|
|
|
|
{
|
|
|
|
|
n /= 2;
|
2007-09-11 22:32:51 +00:00
|
|
|
|
|
2008-01-09 18:27:27 +00:00
|
|
|
|
const T* lmax = NULL;
|
2008-01-10 02:07:41 +00:00
|
|
|
|
for (int i = 0; i < m; ++i)
|
2008-01-09 18:27:27 +00:00
|
|
|
|
{
|
|
|
|
|
if (a[i] > 0)
|
|
|
|
|
{
|
|
|
|
|
if (!lmax)
|
|
|
|
|
lmax = &(S(i)[a[i] - 1]);
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (comp(*lmax, S(i)[a[i] - 1])) //max
|
|
|
|
|
lmax = &(S(i)[a[i] - 1]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int i;
|
|
|
|
|
for (i = 0; i < m; i++)
|
|
|
|
|
{
|
|
|
|
|
difference_type middle = (b[i] + a[i]) / 2;
|
|
|
|
|
if (lmax && middle < ns[i] && comp(S(i)[middle], *lmax))
|
|
|
|
|
a[i] = std::min(a[i] + n + 1, ns[i]);
|
|
|
|
|
else
|
|
|
|
|
b[i] -= n + 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
difference_type leftsize = 0, total = 0;
|
2008-01-10 02:07:41 +00:00
|
|
|
|
for (int i = 0; i < m; ++i)
|
2008-01-09 18:27:27 +00:00
|
|
|
|
{
|
|
|
|
|
leftsize += a[i] / (n + 1);
|
|
|
|
|
total += l / (n + 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
difference_type skew = ((unsigned long long)total * rank / N
|
|
|
|
|
- leftsize);
|
|
|
|
|
|
|
|
|
|
if (skew > 0)
|
|
|
|
|
{
|
|
|
|
|
// Move to the left, find smallest.
|
|
|
|
|
std::priority_queue<std::pair<T, int>,
|
|
|
|
|
std::vector<std::pair<T, int> >,
|
|
|
|
|
lexicographic_reverse<T, int, Comparator> > pq(lrcomp);
|
|
|
|
|
|
2008-01-10 02:07:41 +00:00
|
|
|
|
for (int i = 0; i < m; ++i)
|
2008-01-09 18:27:27 +00:00
|
|
|
|
if (b[i] < ns[i])
|
|
|
|
|
pq.push(std::make_pair(S(i)[b[i]], i));
|
|
|
|
|
|
|
|
|
|
for (; skew != 0 && !pq.empty(); --skew)
|
|
|
|
|
{
|
|
|
|
|
int source = pq.top().second;
|
|
|
|
|
pq.pop();
|
|
|
|
|
|
|
|
|
|
a[source] = std::min(a[source] + n + 1, ns[source]);
|
|
|
|
|
b[source] += n + 1;
|
|
|
|
|
|
|
|
|
|
if (b[source] < ns[source])
|
|
|
|
|
pq.push(std::make_pair(S(source)[b[source]], source));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (skew < 0)
|
|
|
|
|
{
|
|
|
|
|
// Move to the right, find greatest.
|
|
|
|
|
std::priority_queue<std::pair<T, int>,
|
|
|
|
|
std::vector<std::pair<T, int> >,
|
|
|
|
|
lexicographic<T, int, Comparator> > pq(lcomp);
|
|
|
|
|
|
2008-01-10 02:07:41 +00:00
|
|
|
|
for (int i = 0; i < m; ++i)
|
2008-01-09 18:27:27 +00:00
|
|
|
|
if (a[i] > 0)
|
|
|
|
|
pq.push(std::make_pair(S(i)[a[i] - 1], i));
|
|
|
|
|
|
|
|
|
|
for (; skew != 0; ++skew)
|
|
|
|
|
{
|
|
|
|
|
int source = pq.top().second;
|
|
|
|
|
pq.pop();
|
|
|
|
|
|
|
|
|
|
a[source] -= n + 1;
|
|
|
|
|
b[source] -= n + 1;
|
|
|
|
|
|
|
|
|
|
if (a[source] > 0)
|
|
|
|
|
pq.push(std::make_pair(S(source)[a[source] - 1], source));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Postconditions:
|
|
|
|
|
// a[i] == b[i] in most cases, except when a[i] has been clamped
|
|
|
|
|
// because of having reached the boundary
|
|
|
|
|
|
|
|
|
|
// Now return the result, calculate the offset.
|
|
|
|
|
|
|
|
|
|
// Compare the keys on both edges of the border.
|
|
|
|
|
|
|
|
|
|
// Maximum of left edge, minimum of right edge.
|
|
|
|
|
bool maxleftset = false, minrightset = false;
|
|
|
|
|
|
|
|
|
|
// Impossible to avoid the warning?
|
|
|
|
|
T maxleft, minright;
|
2008-01-10 02:07:41 +00:00
|
|
|
|
for (int i = 0; i < m; ++i)
|
2008-01-09 18:27:27 +00:00
|
|
|
|
{
|
|
|
|
|
if (a[i] > 0)
|
|
|
|
|
{
|
|
|
|
|
if (!maxleftset)
|
|
|
|
|
{
|
2007-09-11 22:32:51 +00:00
|
|
|
|
maxleft = S(i)[a[i] - 1];
|
2008-01-09 18:27:27 +00:00
|
|
|
|
maxleftset = true;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// Max.
|
|
|
|
|
if (comp(maxleft, S(i)[a[i] - 1]))
|
|
|
|
|
maxleft = S(i)[a[i] - 1];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (b[i] < ns[i])
|
|
|
|
|
{
|
|
|
|
|
if (!minrightset)
|
|
|
|
|
{
|
2007-09-11 22:32:51 +00:00
|
|
|
|
minright = S(i)[b[i]];
|
2008-01-09 18:27:27 +00:00
|
|
|
|
minrightset = true;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// Min.
|
|
|
|
|
if (comp(S(i)[b[i]], minright))
|
|
|
|
|
minright = S(i)[b[i]];
|
|
|
|
|
}
|
|
|
|
|
}
|
2007-09-11 22:32:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
2008-01-09 18:27:27 +00:00
|
|
|
|
// Minright is the splitter, in any case.
|
|
|
|
|
|
|
|
|
|
if (!maxleftset || comp(minright, maxleft))
|
|
|
|
|
{
|
2008-01-31 18:44:55 +00:00
|
|
|
|
// Good luck, everything is split unambiguously.
|
2008-01-09 18:27:27 +00:00
|
|
|
|
offset = 0;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// We have to calculate an offset.
|
|
|
|
|
offset = 0;
|
|
|
|
|
|
2008-01-10 02:07:41 +00:00
|
|
|
|
for (int i = 0; i < m; ++i)
|
2008-01-09 18:27:27 +00:00
|
|
|
|
{
|
|
|
|
|
difference_type lb = std::lower_bound(S(i), S(i) + ns[i],
|
|
|
|
|
minright,
|
|
|
|
|
comp) - S(i);
|
|
|
|
|
offset += a[i] - lb;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
delete[] ns;
|
|
|
|
|
delete[] a;
|
|
|
|
|
delete[] b;
|
|
|
|
|
|
|
|
|
|
return minright;
|
|
|
|
|
}
|
2007-09-11 22:32:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#undef S
|
|
|
|
|
|
2008-07-15 10:06:58 +00:00
|
|
|
|
#endif /* _GLIBCXX_PARALLEL_MULTISEQ_SELECTION_H */
|