diff --git a/tasks/orehov_n_jarvis_pass_seq/common/include/common.hpp b/tasks/orehov_n_jarvis_pass/common/include/common.hpp similarity index 88% rename from tasks/orehov_n_jarvis_pass_seq/common/include/common.hpp rename to tasks/orehov_n_jarvis_pass/common/include/common.hpp index 65693023b..988e447ca 100644 --- a/tasks/orehov_n_jarvis_pass_seq/common/include/common.hpp +++ b/tasks/orehov_n_jarvis_pass/common/include/common.hpp @@ -5,7 +5,7 @@ #include "task/include/task.hpp" -namespace orehov_n_jarvis_pass_seq { +namespace orehov_n_jarvis_pass { struct Point { double x; @@ -27,4 +27,4 @@ using OutType = std::vector; using TestType = int; using BaseTask = ppc::task::Task; -} // namespace orehov_n_jarvis_pass_seq +} // namespace orehov_n_jarvis_pass diff --git a/tasks/orehov_n_jarvis_pass_seq/info.json b/tasks/orehov_n_jarvis_pass/info.json similarity index 100% rename from tasks/orehov_n_jarvis_pass_seq/info.json rename to tasks/orehov_n_jarvis_pass/info.json diff --git a/tasks/orehov_n_jarvis_pass/omp/include/ops_omp.hpp b/tasks/orehov_n_jarvis_pass/omp/include/ops_omp.hpp new file mode 100644 index 000000000..76d2e7745 --- /dev/null +++ b/tasks/orehov_n_jarvis_pass/omp/include/ops_omp.hpp @@ -0,0 +1,31 @@ +#pragma once + +#include +#include + +#include "orehov_n_jarvis_pass/common/include/common.hpp" +#include "task/include/task.hpp" + +namespace orehov_n_jarvis_pass { + +class OrehovNJarvisPassOMP : public ppc::task::Task, std::vector> { + public: + static constexpr ppc::task::TypeOfTask GetStaticTypeOfTask() { + return ppc::task::TypeOfTask::kOMP; + } + explicit OrehovNJarvisPassOMP(const std::vector &in); + + private: + static double CheckLeft(Point a, Point b, Point c); + static double DistanceSquared(Point a, Point b); + + Point FindFirstElem(const std::vector &input) const; + Point FindNext(Point current, const std::vector &input) const; + + bool ValidationImpl() override; + bool PreProcessingImpl() override; + bool RunImpl() override; + bool PostProcessingImpl() override; +}; + +} // namespace orehov_n_jarvis_pass diff --git a/tasks/orehov_n_jarvis_pass/omp/src/ops_omp.cpp b/tasks/orehov_n_jarvis_pass/omp/src/ops_omp.cpp new file mode 100644 index 000000000..68fa1bdee --- /dev/null +++ b/tasks/orehov_n_jarvis_pass/omp/src/ops_omp.cpp @@ -0,0 +1,123 @@ +#include "orehov_n_jarvis_pass/omp/include/ops_omp.hpp" + +#include + +#include +#include +#include + +#include "orehov_n_jarvis_pass/common/include/common.hpp" + +namespace orehov_n_jarvis_pass { + +OrehovNJarvisPassOMP::OrehovNJarvisPassOMP(const InType &in) { + SetTypeOfTask(GetStaticTypeOfTask()); + GetInput() = in; + GetOutput() = std::vector(); +} + +bool OrehovNJarvisPassOMP::ValidationImpl() { + return !GetInput().empty(); +} + +bool OrehovNJarvisPassOMP::PreProcessingImpl() { + return true; +} + +bool OrehovNJarvisPassOMP::RunImpl() { + const auto &input = GetInput(); + + if (input.size() == 1 || input.size() == 2) { + GetOutput() = input; + return true; + } + + Point current = FindFirstElem(input); + GetOutput().push_back(current); + + while (true) { + Point next = FindNext(current, input); + if (next == GetOutput()[0]) { + break; + } + + current = next; + GetOutput().push_back(next); + } + + return true; +} + +Point OrehovNJarvisPassOMP::FindNext(Point current, const std::vector &input) const { + const size_t n = input.size(); + Point initial_candidate = (current == input[0]) ? input[1] : input[0]; + + int max_threads = omp_get_max_threads(); + std::vector local_bests(max_threads, initial_candidate); + const int n_int = static_cast(n); + +#pragma omp parallel default(none) shared(input, n_int, current, local_bests) + { + int tid = omp_get_thread_num(); + Point thread_local_best = local_bests[tid]; + +#pragma omp for nowait + for (int i = 0; i < n_int; ++i) { + const Point &point = input[i]; + if (current == point) { + continue; + } + + double orient = CheckLeft(current, thread_local_best, point); + + if (orient > 0) { + thread_local_best = point; + } else if (std::abs(orient) < 1e-9) { + if (DistanceSquared(current, point) > DistanceSquared(current, thread_local_best)) { + thread_local_best = point; + } + } + } + local_bests[tid] = thread_local_best; + } + + Point global_next = local_bests[0]; + for (int i = 1; i < max_threads; ++i) { + double orient = CheckLeft(current, global_next, local_bests[i]); + if (orient > 0) { + global_next = local_bests[i]; + } else if (std::abs(orient) < 1e-9) { + if (DistanceSquared(current, local_bests[i]) > DistanceSquared(current, global_next)) { + global_next = local_bests[i]; + } + } + } + + return global_next; +} + +double OrehovNJarvisPassOMP::CheckLeft(Point a, Point b, Point c) { + return ((b.x - a.x) * (c.y - a.y)) - ((b.y - a.y) * (c.x - a.x)); +} + +Point OrehovNJarvisPassOMP::FindFirstElem(const std::vector &input) const { + Point current = input[0]; + for (const auto &f : input) { + if (f.x < current.x || (f.y < current.y && f.x == current.x)) { + current = f; + } + } + return current; +} + +double OrehovNJarvisPassOMP::DistanceSquared(Point a, Point b) { + double dx = a.x - b.x; + double dy = a.y - b.y; + return dx * dx + dy * dy; +} + +bool OrehovNJarvisPassOMP::PostProcessingImpl() { + return true; +} + +} // namespace orehov_n_jarvis_pass diff --git a/tasks/orehov_n_jarvis_pass_seq/seq/include/ops_seq.hpp b/tasks/orehov_n_jarvis_pass/seq/include/ops_seq.hpp similarity index 83% rename from tasks/orehov_n_jarvis_pass_seq/seq/include/ops_seq.hpp rename to tasks/orehov_n_jarvis_pass/seq/include/ops_seq.hpp index f643c08e6..15c58e1ec 100644 --- a/tasks/orehov_n_jarvis_pass_seq/seq/include/ops_seq.hpp +++ b/tasks/orehov_n_jarvis_pass/seq/include/ops_seq.hpp @@ -2,10 +2,10 @@ #include -#include "orehov_n_jarvis_pass_seq/common/include/common.hpp" +#include "orehov_n_jarvis_pass/common/include/common.hpp" #include "task/include/task.hpp" -namespace orehov_n_jarvis_pass_seq { +namespace orehov_n_jarvis_pass { class OrehovNJarvisPassSEQ : public BaseTask { public: @@ -29,4 +29,4 @@ class OrehovNJarvisPassSEQ : public BaseTask { std::vector input_; }; -} // namespace orehov_n_jarvis_pass_seq +} // namespace orehov_n_jarvis_pass diff --git a/tasks/orehov_n_jarvis_pass_seq/seq/src/ops_seq.cpp b/tasks/orehov_n_jarvis_pass/seq/src/ops_seq.cpp similarity index 90% rename from tasks/orehov_n_jarvis_pass_seq/seq/src/ops_seq.cpp rename to tasks/orehov_n_jarvis_pass/seq/src/ops_seq.cpp index 91037dcc9..b1309b6e4 100644 --- a/tasks/orehov_n_jarvis_pass_seq/seq/src/ops_seq.cpp +++ b/tasks/orehov_n_jarvis_pass/seq/src/ops_seq.cpp @@ -1,12 +1,12 @@ -#include "orehov_n_jarvis_pass_seq/seq/include/ops_seq.hpp" +#include "orehov_n_jarvis_pass/seq/include/ops_seq.hpp" #include #include #include -#include "orehov_n_jarvis_pass_seq/common/include/common.hpp" +#include "orehov_n_jarvis_pass/common/include/common.hpp" -namespace orehov_n_jarvis_pass_seq { +namespace orehov_n_jarvis_pass { OrehovNJarvisPassSEQ::OrehovNJarvisPassSEQ(const InType &in) { SetTypeOfTask(GetStaticTypeOfTask()); @@ -88,4 +88,4 @@ bool OrehovNJarvisPassSEQ::PostProcessingImpl() { return true; } -} // namespace orehov_n_jarvis_pass_seq +} // namespace orehov_n_jarvis_pass diff --git a/tasks/orehov_n_jarvis_pass_seq/settings.json b/tasks/orehov_n_jarvis_pass/settings.json similarity index 100% rename from tasks/orehov_n_jarvis_pass_seq/settings.json rename to tasks/orehov_n_jarvis_pass/settings.json diff --git a/tasks/orehov_n_jarvis_pass/tbb/include/ops_tbb.hpp b/tasks/orehov_n_jarvis_pass/tbb/include/ops_tbb.hpp new file mode 100644 index 000000000..c626e5150 --- /dev/null +++ b/tasks/orehov_n_jarvis_pass/tbb/include/ops_tbb.hpp @@ -0,0 +1,32 @@ +#pragma once + +#include + +#include "orehov_n_jarvis_pass/common/include/common.hpp" +#include "task/include/task.hpp" + +namespace orehov_n_jarvis_pass { + +class OrehovNJarvisPassTBB : public BaseTask { + public: + static constexpr ppc::task::TypeOfTask GetStaticTypeOfTask() { + return ppc::task::TypeOfTask::kTBB; + } + explicit OrehovNJarvisPassTBB(const InType &in); + + private: + bool ValidationImpl() override; + bool PreProcessingImpl() override; + bool RunImpl() override; + bool PostProcessingImpl() override; + + [[nodiscard]] static double CheckLeft(Point a, Point b, Point c); + [[nodiscard]] Point FindFirstElem() const; + [[nodiscard]] static double Distance(Point a, Point b); + [[nodiscard]] Point FindNext(Point current) const; + + std::vector res_; + std::vector input_; +}; + +} // namespace orehov_n_jarvis_pass diff --git a/tasks/orehov_n_jarvis_pass/tbb/src/ops_tbb.cpp b/tasks/orehov_n_jarvis_pass/tbb/src/ops_tbb.cpp new file mode 100644 index 000000000..b68e33043 --- /dev/null +++ b/tasks/orehov_n_jarvis_pass/tbb/src/ops_tbb.cpp @@ -0,0 +1,126 @@ +#include "orehov_n_jarvis_pass/tbb/include/ops_tbb.hpp" + +#include +#include +#include +#include + +#include "oneapi/tbb.h" +#include "orehov_n_jarvis_pass/common/include/common.hpp" + +namespace orehov_n_jarvis_pass { + +OrehovNJarvisPassTBB::OrehovNJarvisPassTBB(const InType &in) { + SetTypeOfTask(GetStaticTypeOfTask()); + GetInput() = in; + GetOutput() = std::vector(); +} + +bool OrehovNJarvisPassTBB::ValidationImpl() { + return (!GetInput().empty()); +} + +bool OrehovNJarvisPassTBB::PreProcessingImpl() { + std::set tmp(GetInput().begin(), GetInput().end()); + input_.assign(tmp.begin(), tmp.end()); + return true; +} + +bool OrehovNJarvisPassTBB::RunImpl() { + if (input_.size() == 1 || input_.size() == 2) { + res_ = input_; + return true; + } + + Point current = FindFirstElem(); + res_.push_back(current); + + while (true) { + Point next = FindNext(current); + if (next == res_[0]) { + break; + } + + current = next; + res_.push_back(next); + } + + return true; +} + +Point OrehovNJarvisPassTBB::FindNext(Point current) const { + const size_t n = input_.size(); + const auto &input = input_; + + struct Body { + const Point ¤t; + const std::vector &input; + Point best_point; + + Body(const Point &c, const std::vector &in) + : current(c), input(in), best_point((current == in[0]) ? in[1] : in[0]) {} + + Body(Body &other, tbb::split) : current(other.current), input(other.input), best_point(other.best_point) {} + + void operator()(const tbb::blocked_range &range) { + for (size_t i = range.begin(); i != range.end(); ++i) { + const Point &point = input[i]; + if (current == point) { + continue; + } + + double orient = OrehovNJarvisPassTBB::CheckLeft(current, best_point, point); + + if (orient > 0) { + best_point = point; + } else if (orient == 0) { + if (OrehovNJarvisPassTBB::Distance(current, point) > OrehovNJarvisPassTBB::Distance(current, best_point)) { + best_point = point; + } + } + } + } + + void join(const Body &other) { + double global_orient = OrehovNJarvisPassTBB::CheckLeft(current, best_point, other.best_point); + if (global_orient > 0) { + best_point = other.best_point; + } else if (global_orient == 0) { + if (OrehovNJarvisPassTBB::Distance(current, other.best_point) > + OrehovNJarvisPassTBB::Distance(current, best_point)) { + best_point = other.best_point; + } + } + } + }; + + Body body(current, input); + tbb::parallel_reduce(tbb::blocked_range(0, n), body); + + return body.best_point; +} + +double OrehovNJarvisPassTBB::CheckLeft(Point a, Point b, Point c) { + return ((b.x - a.x) * (c.y - a.y)) - ((b.y - a.y) * (c.x - a.x)); +} + +Point OrehovNJarvisPassTBB::FindFirstElem() const { + Point current = input_[0]; + for (auto f : input_) { + if (f.x < current.x || (f.y < current.y && f.x == current.x)) { + current = f; + } + } + return current; +} + +double OrehovNJarvisPassTBB::Distance(Point a, Point b) { + return std::sqrt(std::pow(a.y - b.y, 2) + std::pow(a.x - b.x, 2)); +} + +bool OrehovNJarvisPassTBB::PostProcessingImpl() { + GetOutput() = res_; + return true; +} + +} // namespace orehov_n_jarvis_pass diff --git a/tasks/orehov_n_jarvis_pass_seq/tests/functional/main.cpp b/tasks/orehov_n_jarvis_pass/tests/functional/main.cpp similarity index 64% rename from tasks/orehov_n_jarvis_pass_seq/tests/functional/main.cpp rename to tasks/orehov_n_jarvis_pass/tests/functional/main.cpp index f235bb105..a659b603b 100644 --- a/tasks/orehov_n_jarvis_pass_seq/tests/functional/main.cpp +++ b/tasks/orehov_n_jarvis_pass/tests/functional/main.cpp @@ -6,14 +6,16 @@ #include #include -#include "orehov_n_jarvis_pass_seq/common/include/common.hpp" -#include "orehov_n_jarvis_pass_seq/seq/include/ops_seq.hpp" +#include "orehov_n_jarvis_pass/common/include/common.hpp" +#include "orehov_n_jarvis_pass/omp/include/ops_omp.hpp" +#include "orehov_n_jarvis_pass/seq/include/ops_seq.hpp" +#include "orehov_n_jarvis_pass/tbb/include/ops_tbb.hpp" #include "util/include/func_test_util.hpp" #include "util/include/util.hpp" -namespace orehov_n_jarvis_pass_seq { +namespace orehov_n_jarvis_pass { -class OrehovNJarvisPassSEQFuncTests : public ppc::util::BaseRunFuncTests { +class OrehovNJarvisPassFuncTests : public ppc::util::BaseRunFuncTests { public: static std::string PrintTestParam(const TestType &test_param) { return std::to_string(test_param); @@ -63,21 +65,23 @@ class OrehovNJarvisPassSEQFuncTests : public ppc::util::BaseRunFuncTests kTestParam = {1, 2, 3}; const auto kTestTasksList = - std::tuple_cat(ppc::util::AddFuncTask(kTestParam, PPC_SETTINGS_example_threads)); + std::tuple_cat(ppc::util::AddFuncTask(kTestParam, PPC_SETTINGS_orehov_n_jarvis_pass), + ppc::util::AddFuncTask(kTestParam, PPC_SETTINGS_orehov_n_jarvis_pass), + ppc::util::AddFuncTask(kTestParam, PPC_SETTINGS_orehov_n_jarvis_pass)); const auto kGtestValues = ppc::util::ExpandToValues(kTestTasksList); -const auto kPerfTestName = OrehovNJarvisPassSEQFuncTests::PrintFuncTestName; +const auto kPerfTestName = OrehovNJarvisPassFuncTests::PrintFuncTestName; -INSTANTIATE_TEST_SUITE_P(PicMatrixTests, OrehovNJarvisPassSEQFuncTests, kGtestValues, kPerfTestName); +INSTANTIATE_TEST_SUITE_P(PicMatrixTests, OrehovNJarvisPassFuncTests, kGtestValues, kPerfTestName); } // namespace -} // namespace orehov_n_jarvis_pass_seq +} // namespace orehov_n_jarvis_pass diff --git a/tasks/orehov_n_jarvis_pass/tests/performance/main.cpp b/tasks/orehov_n_jarvis_pass/tests/performance/main.cpp new file mode 100644 index 000000000..288b5e22d --- /dev/null +++ b/tasks/orehov_n_jarvis_pass/tests/performance/main.cpp @@ -0,0 +1,56 @@ +#include + +#include + +#include "orehov_n_jarvis_pass/common/include/common.hpp" +#include "orehov_n_jarvis_pass/omp/include/ops_omp.hpp" +#include "orehov_n_jarvis_pass/seq/include/ops_seq.hpp" +#include "orehov_n_jarvis_pass/tbb/include/ops_tbb.hpp" +#include "util/include/perf_test_util.hpp" + +namespace orehov_n_jarvis_pass { + +class OrehovNJarvisPassPerfTests : public ppc::util::BaseRunPerfTests { + const int kCount_ = 2000; + InType input_data_; + + void SetUp() override { + double radius = 2000; + for (int i = 0; i < kCount_ - 1; i++) { + double angle = 2 * 3.14 * i / kCount_; + + double x = radius * std::cos(angle); + double y = radius * std::sin(angle); + + input_data_.emplace_back(x, y); + } + } + + bool CheckTestOutputData(OutType &output_data) final { + return !output_data.empty(); + } + + InType GetTestInputData() final { + return input_data_; + } +}; + +TEST_P(OrehovNJarvisPassPerfTests, RunPerfModes) { + ExecuteTest(GetParam()); +} + +namespace { + +const auto kAllPerfTasks = + ppc::util::MakeAllPerfTasks( + PPC_SETTINGS_orehov_n_jarvis_pass); + +const auto kGtestValues = ppc::util::TupleToGTestValues(kAllPerfTasks); + +const auto kPerfTestName = OrehovNJarvisPassPerfTests::CustomPerfTestName; + +INSTANTIATE_TEST_SUITE_P(RunModeTests, OrehovNJarvisPassPerfTests, kGtestValues, kPerfTestName); + +} // namespace + +} // namespace orehov_n_jarvis_pass diff --git a/tasks/orehov_n_jarvis_pass_seq/tests/performance/main.cpp b/tasks/orehov_n_jarvis_pass_seq/tests/performance/main.cpp deleted file mode 100644 index dae7b7b63..000000000 --- a/tasks/orehov_n_jarvis_pass_seq/tests/performance/main.cpp +++ /dev/null @@ -1,52 +0,0 @@ -#include - -#include - -#include "orehov_n_jarvis_pass_seq/common/include/common.hpp" -#include "orehov_n_jarvis_pass_seq/seq/include/ops_seq.hpp" -#include "util/include/perf_test_util.hpp" - -namespace orehov_n_jarvis_pass_seq { - -class OrehovNJarvisPassSEQPerfTests : public ppc::util::BaseRunPerfTests { - const int kCount_ = 2000; - InType input_data_; - - void SetUp() override { - double radius = 2000; - for (int i = 0; i < kCount_ - 1; i++) { - double angle = 2 * 3.14 * i / kCount_; - - double x = radius * std::cos(angle); - double y = radius * std::sin(angle); - - input_data_.emplace_back(x, y); - } - } - - bool CheckTestOutputData(OutType &output_data) final { - return !output_data.empty(); - } - - InType GetTestInputData() final { - return input_data_; - } -}; - -TEST_P(OrehovNJarvisPassSEQPerfTests, RunPerfModes) { - ExecuteTest(GetParam()); -} - -namespace { - -const auto kAllPerfTasks = ppc::util::MakeAllPerfTasks(PPC_SETTINGS_example_threads); - -const auto kGtestValues = ppc::util::TupleToGTestValues(kAllPerfTasks); - -const auto kPerfTestName = OrehovNJarvisPassSEQPerfTests::CustomPerfTestName; - -INSTANTIATE_TEST_SUITE_P(RunModeTests, OrehovNJarvisPassSEQPerfTests, kGtestValues, kPerfTestName); - -} // namespace - -} // namespace orehov_n_jarvis_pass_seq