00001
00023 #ifndef GALOIS_PARALLELSTL_PARALLELSTL_H
00024 #define GALOIS_PARALLELSTL_PARALLELSTL_H
00025
00026 #include "Galois/UserContext.h"
00027 #include "Galois/NoDerefIterator.h"
00028 #include "Galois/WorkList/WorkList.h"
00029 #include "Galois/Runtime/ParallelWork.h"
00030 #include "Galois/Runtime/DoAll.h"
00031
00032 namespace Galois {
00034 namespace ParallelSTL {
00035
00036 template<typename Predicate>
00037 struct count_if_helper {
00038 Predicate f;
00039 ptrdiff_t ret;
00040 count_if_helper(Predicate p): f(p), ret(0) { }
00041 template<typename T>
00042 void operator()(const T& v) {
00043 if (f(v)) ++ret;
00044 }
00045 };
00046
00047 struct count_if_reducer {
00048 template<typename CIH>
00049 void operator()(CIH& dest, const CIH& src) {
00050 dest.ret += src.ret;
00051 }
00052 };
00053
00054 template<class InputIterator, class Predicate>
00055 ptrdiff_t count_if(InputIterator first, InputIterator last, Predicate pred)
00056 {
00057 return Runtime::do_all_impl(Runtime::makeStandardRange(first, last),
00058 count_if_helper<Predicate>(pred), count_if_reducer(), "count_if").ret;
00059 }
00060
00061 template<typename InputIterator, class Predicate>
00062 struct find_if_helper {
00063 typedef int tt_does_not_need_stats;
00064 typedef int tt_does_not_need_push;
00065 typedef int tt_does_not_need_aborts;
00066 typedef int tt_needs_parallel_break;
00067
00068 typedef Galois::optional<InputIterator> ElementTy;
00069 typedef Runtime::PerThreadStorage<ElementTy> AccumulatorTy;
00070 AccumulatorTy& accum;
00071 Predicate& f;
00072 find_if_helper(AccumulatorTy& a, Predicate& p): accum(a), f(p) { }
00073 void operator()(const InputIterator& v, UserContext<InputIterator>& ctx) {
00074 if (f(*v)) {
00075 *accum.getLocal() = v;
00076 ctx.breakLoop();
00077 }
00078 }
00079 };
00080
00081 template<class InputIterator, class Predicate>
00082 InputIterator find_if(InputIterator first, InputIterator last, Predicate pred)
00083 {
00084 typedef find_if_helper<InputIterator,Predicate> HelperTy;
00085 typedef typename HelperTy::AccumulatorTy AccumulatorTy;
00086 typedef Galois::WorkList::dChunkedFIFO<256> WL;
00087 AccumulatorTy accum;
00088 HelperTy helper(accum, pred);
00089 Runtime::for_each_impl<WL>(Runtime::makeStandardRange(
00090 make_no_deref_iterator(first),
00091 make_no_deref_iterator(last)), helper, 0);
00092 for (unsigned i = 0; i < accum.size(); ++i) {
00093 if (*accum.getRemote(i))
00094 return **accum.getRemote(i);
00095 }
00096 return last;
00097 }
00098
00099 template<class Iterator>
00100 Iterator choose_rand(Iterator first, Iterator last) {
00101 size_t dist = std::distance(first,last);
00102 if (dist)
00103 std::advance(first, rand() % dist);
00104 return first;
00105 }
00106
00107 template<class Compare>
00108 struct sort_helper {
00109 typedef int tt_does_not_need_aborts;
00110 Compare comp;
00111
00113 template<class value_type>
00114 struct neq_to: public std::binary_function<value_type,value_type,bool> {
00115 Compare comp;
00116 neq_to(Compare c): comp(c) { }
00117 bool operator()(const value_type& a, const value_type& b) const {
00118 return comp(a, b) || comp(b, a);
00119 }
00120 };
00121
00122 sort_helper(Compare c): comp(c) { }
00123
00124 template <class RandomAccessIterator, class Context>
00125 void operator()(std::pair<RandomAccessIterator,RandomAccessIterator> bounds,
00126 Context& ctx) {
00127 if (std::distance(bounds.first, bounds.second) <= 1024) {
00128 std::sort(bounds.first, bounds.second, comp);
00129 } else {
00130 typedef typename std::iterator_traits<RandomAccessIterator>::value_type VT;
00131 RandomAccessIterator pivot = choose_rand(bounds.first, bounds.second);
00132 VT pv = *pivot;
00133 pivot = std::partition(bounds.first, bounds.second,
00134 std::bind(comp, std::placeholders::_1, pv));
00135
00136 if (bounds.first != pivot)
00137 ctx.push(std::make_pair(bounds.first, pivot));
00138
00139 pivot = std::find_if(pivot, bounds.second,
00140 std::bind(neq_to<VT>(comp), std::placeholders::_1, pv));
00141
00142 if (bounds.second != pivot)
00143 ctx.push(std::make_pair(pivot, bounds.second));
00144 }
00145 }
00146 };
00147
00148 template<typename RandomAccessIterator, class Predicate>
00149 std::pair<RandomAccessIterator, RandomAccessIterator>
00150 dual_partition(RandomAccessIterator first1, RandomAccessIterator last1,
00151 RandomAccessIterator first2, RandomAccessIterator last2,
00152 Predicate pred) {
00153 typedef std::reverse_iterator<RandomAccessIterator> RI;
00154 RI first3(last2), last3(first2);
00155 while (true) {
00156 while (first1 != last1 && pred(*first1)) ++first1;
00157 if (first1 == last1) break;
00158 while (first3 != last3 && !pred(*first3)) ++first3;
00159 if (first3 == last3) break;
00160 std::swap(*first1++, *first3++);
00161 }
00162 return std::make_pair(first1, first3.base());
00163 }
00164
00165 template<typename RandomAccessIterator, class Predicate>
00166 struct partition_helper {
00167 typedef std::pair<RandomAccessIterator, RandomAccessIterator> RP;
00168 struct partition_helper_state {
00169 RandomAccessIterator first, last;
00170 RandomAccessIterator rfirst, rlast;
00171 Runtime::LL::SimpleLock<true> Lock;
00172 Predicate pred;
00173 typename std::iterator_traits<RandomAccessIterator>::difference_type BlockSize() { return 1024; }
00174
00175 partition_helper_state(RandomAccessIterator f, RandomAccessIterator l, Predicate p)
00176 :first(f), last(l), rfirst(l), rlast(f), pred(p)
00177 {}
00178 RP takeHigh() {
00179 Lock.lock();
00180 unsigned BS = std::min(BlockSize(), std::distance(first,last));
00181 last -= BS;
00182 RandomAccessIterator rv = last;
00183 Lock.unlock();
00184 return std::make_pair(rv, rv+BS);
00185 }
00186 RP takeLow() {
00187 Lock.lock();
00188 unsigned BS = std::min(BlockSize(), std::distance(first,last));
00189 RandomAccessIterator rv = first;
00190 first += BS;
00191 Lock.unlock();
00192 return std::make_pair(rv, rv+BS);
00193 }
00194 void update(RP low, RP high) {
00195 Lock.lock();
00196 if (low.first != low.second) {
00197 rfirst = std::min(rfirst, low.first);
00198 rlast = std::max(rlast, low.second);
00199 }
00200 if (high.first != high.second) {
00201 rfirst = std::min(rfirst, high.first);
00202 rlast = std::max(rlast, high.second);
00203 }
00204 Lock.unlock();
00205 }
00206 };
00207
00208 partition_helper(partition_helper_state* s) :state(s) {}
00209
00210 partition_helper_state* state;
00211
00212 void operator()(unsigned, unsigned) {
00213 RP high, low;
00214 do {
00215 RP parts = dual_partition(low.first, low.second, high.first, high.second, state->pred);
00216 low.first = parts.first;
00217 high.second = parts.second;
00218 if (low.first == low.second) low = state->takeLow();
00219 if (high.first == high.second) high = state->takeHigh();
00220 } while (low.first != low.second && high.first != high.second);
00221 state->update(low,high);
00222 }
00223 };
00224
00225 template<class RandomAccessIterator, class Predicate>
00226 RandomAccessIterator partition(RandomAccessIterator first,
00227 RandomAccessIterator last,
00228 Predicate pred) {
00229 if (std::distance(first, last) <= 1024)
00230 return std::partition(first, last, pred);
00231 typedef partition_helper<RandomAccessIterator, Predicate> P;
00232 typename P::partition_helper_state s(first, last, pred);
00233 Runtime::on_each_impl(P(&s), 0);
00234 if (s.rfirst == first && s.rlast == last) {
00235
00236 return s.first;
00237 }
00238 return std::partition(s.rfirst, s.rlast, pred);
00239 }
00240
00241 struct pair_dist {
00242 template<typename RP>
00243 bool operator()(const RP& x, const RP& y) {
00244 return std::distance(x.first, x.second) > std::distance(y.first, y.second);
00245 }
00246 };
00247
00248 template <class RandomAccessIterator,class Compare>
00249 void sort(RandomAccessIterator first, RandomAccessIterator last, Compare comp) {
00250 if (std::distance(first, last) <= 1024) {
00251 std::sort(first, last, comp);
00252 return;
00253 }
00254 typedef Galois::WorkList::dChunkedFIFO<1> WL;
00255 typedef std::pair<RandomAccessIterator,RandomAccessIterator> Pair;
00256 Pair initial[1] = { std::make_pair(first, last) };
00257
00258 Runtime::for_each_impl<WL>(Runtime::makeStandardRange(&initial[0], &initial[1]), sort_helper<Compare>(comp), 0);
00259 }
00260
00261 template<class RandomAccessIterator>
00262 void sort(RandomAccessIterator first, RandomAccessIterator last) {
00263 Galois::ParallelSTL::sort(first, last, std::less<typename std::iterator_traits<RandomAccessIterator>::value_type>());
00264 }
00265
00266 template<typename T, typename BinOp>
00267 struct accumulate_helper {
00268 T init;
00269 BinOp op;
00270 accumulate_helper(T i, BinOp o) :init(i), op(o) {}
00271 void operator()(const T& v) {
00272 init = op(init,v);
00273 }
00274 };
00275
00276 template<typename BinOp>
00277 struct accumulate_helper_reduce {
00278 BinOp op;
00279 accumulate_helper_reduce(BinOp o) :op(o) {}
00280 template<typename T>
00281 void operator()(T& dest, const T& src) const {
00282 dest.init = op(dest.init, src.init);
00283 }
00284 };
00285
00286 template <class InputIterator, class T, typename BinaryOperation>
00287 T accumulate (InputIterator first, InputIterator last, T init, BinaryOperation binary_op) {
00288 return Runtime::do_all_impl(Runtime::makeStandardRange(first, last),
00289 accumulate_helper<T,BinaryOperation>(init, binary_op),
00290 accumulate_helper_reduce<BinaryOperation>(binary_op), "accumulate").init;
00291 }
00292
00293 template<class InputIterator, class T>
00294 T accumulate(InputIterator first, InputIterator last, T init) {
00295 return accumulate(first, last, init, std::plus<T>());
00296 }
00297
00298 template<typename T, typename MapFn, typename ReduceFn>
00299 struct map_reduce_helper {
00300 T init;
00301 MapFn fn;
00302 ReduceFn reduce;
00303 map_reduce_helper(T i, MapFn fn, ReduceFn reduce) :init(i), fn(fn), reduce(reduce) {}
00304 template<typename U>
00305 void operator()(U&& v) {
00306 init = reduce(fn(std::forward<U>(v)), init);
00307 }
00308 };
00309
00310 template<class InputIterator, class MapFn, class T, class ReduceFn>
00311 T map_reduce(InputIterator first, InputIterator last, MapFn fn, T init, ReduceFn reduce) {
00312 return Runtime::do_all_impl(Runtime::makeStandardRange(first, last),
00313 map_reduce_helper<T,MapFn,ReduceFn>(init, fn, reduce),
00314 accumulate_helper_reduce<ReduceFn>(reduce), "map_reduce").init;
00315 }
00316
00317 }
00318 }
00319 #endif