Program Listing for File minimum_maximum_ops.h¶
↰ Return to documentation for file (include/shad/core/impl/minimum_maximum_ops.h
)
//===------------------------------------------------------------*- C++ -*-===//
//
// SHAD
//
// The Scalable High-performance Algorithms and Data Structure Library
//
//===----------------------------------------------------------------------===//
//
// Copyright 2018 Battelle Memorial Institute
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
// use this file except in compliance with the License. You may obtain a copy
// of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.
//
//===----------------------------------------------------------------------===//
#ifndef INCLUDE_SHAD_CORE_IMPL_MINIMUM_MAXIMUM_OPS_H
#define INCLUDE_SHAD_CORE_IMPL_MINIMUM_MAXIMUM_OPS_H
#include <algorithm>
#include <functional>
#include <iterator>
#include <tuple>
#include <type_traits>
#include <vector>
#include "shad/core/execution.h"
#include "shad/distributed_iterator_traits.h"
#include "shad/runtime/runtime.h"
#include "impl_patterns.h"
namespace shad {
namespace impl {
template <class ForwardIt, class Compare>
ForwardIt max_element(distributed_sequential_tag&& policy, ForwardIt first,
ForwardIt last, Compare comp) {
using itr_traits = distributed_iterator_traits<ForwardIt>;
using value_t = typename itr_traits::value_type;
static_assert(std::is_default_constructible<value_t>::value,
"max_element requires DefaultConstructible value type");
if (first == last) return last;
auto map_res = distributed_folding_map(
// range
first, last,
// kernel
[](ForwardIt first, ForwardIt last,
const std::pair<ForwardIt, value_t>& partial_solution, Compare comp) {
using local_iterator_t = typename itr_traits::local_iterator_type;
// local processing
auto lrange = itr_traits::local_range(first, last);
auto lmax = std::max_element(lrange.begin(), lrange.end(), comp);
// update the partial solution
auto nil_val = itr_traits::local_range(first, last).end();
if (lmax != nil_val && (partial_solution.first == last ||
comp(partial_solution.second, *lmax))) {
auto gmax = itr_traits::iterator_from_local(first, last, lmax);
return std::make_pair(gmax, *lmax);
}
return partial_solution;
},
// initial solution
std::make_pair(last, value_t{}),
// map arguments
comp);
return map_res.first;
}
template <class ForwardIt, class Compare>
ForwardIt max_element(distributed_parallel_tag&& policy, ForwardIt first,
ForwardIt last, Compare comp) {
using itr_traits = distributed_iterator_traits<ForwardIt>;
using value_t = typename itr_traits::value_type;
static_assert(std::is_default_constructible<value_t>::value,
"max_element requires DefaultConstructible value type");
if (first == last) return last;
// distributed map
auto map_res = distributed_map(
// range
first, last,
// kernel
[](ForwardIt first, ForwardIt last, Compare comp) {
using local_iterator_t = typename itr_traits::local_iterator_type;
// local map
auto lrange = itr_traits::local_range(first, last);
auto map_res = local_map(
// range
lrange.begin(), lrange.end(),
// kernel
[&](local_iterator_t b, local_iterator_t e) {
return std::max_element(b, e, comp);
});
// local reduce
auto nil_val = itr_traits::local_range(first, last).end();
auto lmax_it = std::max_element(
map_res.begin(), map_res.end(),
[&](const local_iterator_t& x, const local_iterator_t& y) {
return y != nil_val && comp(*x, *y);
});
// local solution
auto lmax = lmax_it != map_res.end() ? *lmax_it : nil_val;
ForwardIt gres = itr_traits::iterator_from_local(first, last, lmax);
return std::make_pair(gres, lmax != nil_val ? *lmax : value_t{});
},
// map arguments
comp);
// reduce
using map_res_t = typeof(map_res);
using res_t = typename map_res_t::value_type;
auto res_it = std::max_element(
map_res.begin(), map_res.end(), [&](const res_t& x, const res_t& y) {
return y.first != last && comp(x.second, y.second);
});
return res_it->first;
}
template <class ForwardIt, class Compare>
ForwardIt min_element(distributed_sequential_tag&& policy, ForwardIt first,
ForwardIt last, Compare comp) {
using itr_traits = distributed_iterator_traits<ForwardIt>;
using value_t = typename itr_traits::value_type;
static_assert(std::is_default_constructible<value_t>::value,
"min_element requires DefaultConstructible value type");
if (first == last) return last;
auto map_res = distributed_folding_map(
// range
first, last,
// kernel
[](ForwardIt first, ForwardIt last,
const std::pair<ForwardIt, value_t>& partial_solution, Compare comp) {
using local_iterator_t = typename itr_traits::local_iterator_type;
// local processing
auto lrange = itr_traits::local_range(first, last);
auto lmin = std::min_element(lrange.begin(), lrange.end(), comp);
// update the partial solution
auto nil_val = itr_traits::local_range(first, last).end();
if (lmin != nil_val && (partial_solution.first == last ||
comp(*lmin, partial_solution.second))) {
auto gmin = itr_traits::iterator_from_local(first, last, lmin);
return std::make_pair(gmin, *lmin);
}
return partial_solution;
},
// initial solution
std::make_pair(last, value_t{}),
// map arguments
comp);
return map_res.first;
}
template <class ForwardIt, class Compare>
ForwardIt min_element(distributed_parallel_tag&& policy, ForwardIt first,
ForwardIt last, Compare comp) {
using itr_traits = distributed_iterator_traits<ForwardIt>;
using value_t = typename itr_traits::value_type;
static_assert(std::is_default_constructible<value_t>::value,
"min_element requires DefaultConstructible value type");
if (first == last) return last;
// distributed map
auto map_res = distributed_map(
// range
first, last,
// kernel
[](ForwardIt first, ForwardIt last, Compare comp) {
using local_iterator_t = typename itr_traits::local_iterator_type;
// local map
auto lrange = itr_traits::local_range(first, last);
auto map_res = local_map(
// range
lrange.begin(), lrange.end(),
// kernel
[&](local_iterator_t b, local_iterator_t e) {
return std::min_element(b, e, comp);
});
// local reduce
auto nil_val = itr_traits::local_range(first, last).end();
auto lmin_it =
std::min_element(map_res.begin(), map_res.end(),
[&](local_iterator_t x, local_iterator_t y) {
return x != nil_val && comp(*x, *y);
});
// local solution
auto lmin = lmin_it != map_res.end() ? *lmin_it : nil_val;
ForwardIt gres = itr_traits::iterator_from_local(first, last, lmin);
return std::make_pair(gres, lmin != nil_val ? *lmin : value_t{});
},
// map arguments
comp);
// reduce
using map_res_t = typeof(map_res);
using res_t = typename map_res_t::value_type;
auto res_it = std::min_element(
map_res.begin(), map_res.end(), [&](const res_t& x, const res_t& y) {
return x.first != last && comp(x.second, y.second);
});
return res_it->first;
}
template <class ForwardIt, class Compare>
std::pair<ForwardIt, ForwardIt> minmax_element(
distributed_sequential_tag&& policy, ForwardIt first, ForwardIt last,
Compare comp) {
using itr_traits = distributed_iterator_traits<ForwardIt>;
using value_t = typename itr_traits::value_type;
static_assert(std::is_default_constructible<value_t>::value,
"minmax_element requires DefaultConstructible value type");
struct sol_t {
ForwardIt min, max;
value_t min_val, max_val;
};
if (first == last) return std::make_pair(last, last);
auto map_res = distributed_folding_map(
// range
first, last,
// kernel
[](ForwardIt first, ForwardIt last, const sol_t& partial_solution,
Compare comp) {
using local_iterator_t = typename itr_traits::local_iterator_type;
// local processing
auto lrange = itr_traits::local_range(first, last);
auto lminmax = std::minmax_element(lrange.begin(), lrange.end(), comp);
// update the partial solution
auto nil_val = itr_traits::local_range(first, last).end();
auto res = partial_solution;
if (lminmax.first != nil_val &&
(partial_solution.min == last ||
comp(*lminmax.first, partial_solution.min_val))) {
auto gmin =
itr_traits::iterator_from_local(first, last, lminmax.first);
res.min = gmin;
res.min_val = *lminmax.first;
}
if (lminmax.second != nil_val &&
(partial_solution.max == last ||
comp(partial_solution.max_val, *lminmax.second))) {
auto gmax =
itr_traits::iterator_from_local(first, last, lminmax.second);
res.max = gmax;
res.max_val = *lminmax.second;
}
return res;
},
// initial solution
sol_t{last, last, value_t{}, value_t{}},
// map arguments
comp);
return std::make_pair(map_res.min, map_res.max);
}
template <class ForwardIt, class Compare>
std::pair<ForwardIt, ForwardIt> minmax_element(
distributed_parallel_tag&& policy, ForwardIt first, ForwardIt last,
Compare comp) {
if (first == last) return std::make_pair(last, last);
using itr_traits = distributed_iterator_traits<ForwardIt>;
using value_t = typename itr_traits::value_type;
static_assert(std::is_default_constructible<value_t>::value,
"minmax_element requires DefaultConstructible value type");
struct sol_t {
ForwardIt min, max;
value_t min_val, max_val;
};
if (first == last) return std::make_pair(last, last);
// distributed map
auto map_res = distributed_map(
// range
first, last,
// kernel
[](ForwardIt first, ForwardIt last, Compare comp) {
using local_iterator_t = typename itr_traits::local_iterator_type;
// local map
auto lrange = itr_traits::local_range(first, last);
auto map_res = local_map(
// range
lrange.begin(), lrange.end(),
// kernel
[&](local_iterator_t b, local_iterator_t e) {
return std::minmax_element(b, e, comp);
});
// reduce
auto nil_val = itr_traits::local_range(first, last).end();
auto lmin_it = std::min_element(
map_res.begin(), map_res.end(),
[&](const std::pair<local_iterator_t, local_iterator_t>& x,
const std::pair<local_iterator_t, local_iterator_t>& y) {
return x.first != nil_val && comp(*x.first, *y.first);
});
auto lmax_it = std::max_element(
map_res.begin(), map_res.end(),
[&](const std::pair<local_iterator_t, local_iterator_t>& x,
const std::pair<local_iterator_t, local_iterator_t>& y) {
return y.second != nil_val && comp(*x.second, *y.second);
});
// local solution
auto lmin = lmin_it != map_res.end() ? lmin_it->first : nil_val;
auto lmax = lmax_it != map_res.end() ? lmax_it->second : nil_val;
return sol_t{itr_traits::iterator_from_local(first, last, lmin),
itr_traits::iterator_from_local(first, last, lmax),
lmin != nil_val ? *lmin : value_t{},
lmax != nil_val ? *lmax : value_t{}};
},
// map arguments
comp);
// reduce
auto res_min = std::min_element(
map_res.begin(), map_res.end(), [&](const sol_t& x, const sol_t& y) {
return x.min != last && comp(x.min_val, y.min_val);
});
auto res_max = std::max_element(
map_res.begin(), map_res.end(), [&](const sol_t& x, const sol_t& y) {
return y.max != last && comp(x.max_val, y.max_val);
});
return std::make_pair(res_min->min, res_max->max);
}
} // namespace impl
} // namespace shad
#endif /* INCLUDE_SHAD_CORE_IMPL_MINIMUM_MAXIMUM_OPS_H */