From 8255d25c21fc64fd6af6dab2451eeaa0a509a373 Mon Sep 17 00:00:00 2001 From: Pronina Date: Tue, 30 Jan 2018 16:03:53 +0300 Subject: [PATCH 1/6] Added solutions of Ruslan A. task #2 --- tasks/ruslan_arutyunyan_task_2/measure.h | 49 +++++++++ tasks/ruslan_arutyunyan_task_2/solver.h | 102 ++++++++++++++++++ .../ruslan_arutyunyan_task_2/test_solver.cpp | 85 +++++++++++++++ 3 files changed, 236 insertions(+) create mode 100644 tasks/ruslan_arutyunyan_task_2/measure.h create mode 100644 tasks/ruslan_arutyunyan_task_2/solver.h create mode 100644 tasks/ruslan_arutyunyan_task_2/test_solver.cpp diff --git a/tasks/ruslan_arutyunyan_task_2/measure.h b/tasks/ruslan_arutyunyan_task_2/measure.h new file mode 100644 index 0000000..aff470b --- /dev/null +++ b/tasks/ruslan_arutyunyan_task_2/measure.h @@ -0,0 +1,49 @@ +#pragma once +#include +#if defined(_OPENMP) +#include +#endif + +namespace measure +{ + namespace chrono + { + template + static std::chrono::milliseconds::rep execution(int32_t count, F func, Args&&... args) + { + std::chrono::milliseconds::rep times_average = 0; + + for (int i = 0; i < count; ++i) + { + auto start = std::chrono::system_clock::now(); + + func(std::forward(args)...); + + times_average += std::chrono::duration_cast + (std::chrono::system_clock::now() - start).count(); + } + + return times_average / count; + } + } +#if defined(_OPENMP) + namespace omp + { + template + static double execution(int32_t count, F func, Args&&... args) + { + double times_average = 0.; + for (int i = 0; i < count; ++i) + { + auto start = omp_get_wtime(); + + func(std::forward(args)...); + + times_average += omp_get_wtime() - start; + } + + return (times_average / count) * 1000; + } + } +#endif +} diff --git a/tasks/ruslan_arutyunyan_task_2/solver.h b/tasks/ruslan_arutyunyan_task_2/solver.h new file mode 100644 index 0000000..509b0f9 --- /dev/null +++ b/tasks/ruslan_arutyunyan_task_2/solver.h @@ -0,0 +1,102 @@ +#pragma once + +#include +#include + +class ISolver +{ +public: + virtual int32_t solve(int number) = 0; +}; + +class SimpleSolver : public ISolver +{ +public: + SimpleSolver(const std::vector& num) : numbers(num) { } + + int32_t solve(int32_t number) override + { + //Worst case: O((n^2)*log(n)) + int32_t count{ }; + auto end{ numbers.cend() }; + for (auto it = numbers.cbegin(); it != end; ++it) + { + auto remainder = number - *it; + auto it1 = std::find(it + 1, end, remainder); + while (it1 != end) + { + it1 = std::find(it1 + 1, end, remainder); + ++count; + } + } + return count; + } + +private: + std::vector numbers; +}; + +class MapLinearSolver : public ISolver +{ +public: + MapLinearSolver(const std::vector &array) + { + for (const auto &number : array) + { + ++unique_els[number]; + } + } + + int32_t solve(int32_t number) override + { + int32_t count { }; + + for (const auto& it : unique_els) + { + int32_t remainder = number - it.first; + + if (remainder == it.first) + { + count += ((it.second - 1) * it.second) / 2; + } + else if (remainder > it.first) + { + auto it2 = unique_els.find(remainder); + + if (it2 != unique_els.end()) + { + count += it.second * it2->second; + } + } + } + return count; + } + +private: + std::unordered_map unique_els; +}; + + +class MapConstantSolver : public ISolver +{ +public: + MapConstantSolver(const std::vector& numbers) + { + auto end{ numbers.cend() }; + for (auto it = numbers.cbegin(); it != end; ++it) + { + for (auto it1 = it + 1; it1 != end; ++it1) + { + ++sums[*it + *it1]; + } + } + } + + int32_t solve(int32_t number) override + { + return sums[number]; + } + +private: + std::unordered_map sums; +}; \ No newline at end of file diff --git a/tasks/ruslan_arutyunyan_task_2/test_solver.cpp b/tasks/ruslan_arutyunyan_task_2/test_solver.cpp new file mode 100644 index 0000000..0a2c3f8 --- /dev/null +++ b/tasks/ruslan_arutyunyan_task_2/test_solver.cpp @@ -0,0 +1,85 @@ +#include "solver.h" +#include "measure.h" +#include +#include +#include +#include +#include +#include + +std::vector getRandomPerfomancveTest(int32_t elementCount, int32_t source) +{ + std::vector numbers; + for (auto i = 0; i < elementCount / 2; ++i) + { + auto el = rand() % (source * 2); + auto remainder = source - el; + numbers.emplace_back(el); + numbers.emplace_back(remainder); + } + std::random_shuffle(numbers.begin(), numbers.end()); + return numbers; +} + +int main() +{ + // correctness tests + std::map, std::pair> correctnessTests = { + { { 2, 2, 2, 2 }, { 4, 6 } }, + { { 1, 2, -1, 4 }, { 3, 2 } }, + { { 1, 2, 1, 2 }, { 3, 4 } }, + { { 1, 0 }, { 2, 0 } } + }; + for (const auto& it : correctnessTests) + { + const auto& test = it.first; + const auto& source = it.second.first; + const auto& target = it.second.second; + + SimpleSolver ss(test); + auto result = ss.solve(source); + assert(result == target); + + MapConstantSolver ms(test); + result = ms.solve(source); + assert(result == target); + + MapLinearSolver mls(test); + result = mls.solve(source); + assert(result == target); + } + + // performance tests + const int32_t N = 10000000; + std::map,int32_t> performanceTests; + + performanceTests[getRandomPerfomancveTest(N, 5)] = 5; + performanceTests[getRandomPerfomancveTest(N, 1000)] = 1000; + performanceTests[getRandomPerfomancveTest(N, 31)] = 31; + performanceTests[getRandomPerfomancveTest(N, 1)] = 1; + performanceTests[getRandomPerfomancveTest(N, 45)] = 1; + performanceTests[getRandomPerfomancveTest(N, 0)] = 0; + performanceTests[getRandomPerfomancveTest(N, 2345654)] = 2345654; + performanceTests[getRandomPerfomancveTest(N, 22345)] = 22345; + performanceTests[getRandomPerfomancveTest(N, 512)] = 512; + + std::cout << "\t\tSimple\t\tMapConst\t\tMapLinear\t\t\n\n"; + const int32_t count = 50; + + auto run = [&](ISolver* s, int n) -> int + { + auto result = s->solve(n); + delete s; + return result; + }; + int32_t i = 0; + for (const auto& test : performanceTests) + { + std::cout << i++ << "\t\t"; + std::cout << measure::chrono::execution(count, run, new SimpleSolver(test.first), test.second) << "ms \t\t" + << measure::chrono::execution(count, run, new MapConstantSolver(test.first), test.second) << "ms \t\t" + << measure::chrono::execution(count, run, new MapLinearSolver(test.first), test.second) << "ms \t\t\n"; + } + return 0; +} + From b9a6168677f9159daf0826f7f01a80aace745e96 Mon Sep 17 00:00:00 2001 From: Pronina Date: Tue, 30 Jan 2018 16:17:59 +0300 Subject: [PATCH 2/6] Small fixes --- .../ruslan_arutyunyan_task_2/test_solver.cpp | 47 ++++++++++--------- 1 file changed, 24 insertions(+), 23 deletions(-) diff --git a/tasks/ruslan_arutyunyan_task_2/test_solver.cpp b/tasks/ruslan_arutyunyan_task_2/test_solver.cpp index 0a2c3f8..e364ffb 100644 --- a/tasks/ruslan_arutyunyan_task_2/test_solver.cpp +++ b/tasks/ruslan_arutyunyan_task_2/test_solver.cpp @@ -6,12 +6,14 @@ #include #include #include +#include -std::vector getRandomPerfomancveTest(int32_t elementCount, int32_t source) +std::vector getRandomPerfomanceTest(int32_t elementCount, int32_t source) { std::vector numbers; for (auto i = 0; i < elementCount / 2; ++i) { + source = source ? source : 1; auto el = rand() % (source * 2); auto remainder = source - el; numbers.emplace_back(el); @@ -25,10 +27,10 @@ int main() { // correctness tests std::map, std::pair> correctnessTests = { - { { 2, 2, 2, 2 }, { 4, 6 } }, - { { 1, 2, -1, 4 }, { 3, 2 } }, - { { 1, 2, 1, 2 }, { 3, 4 } }, - { { 1, 0 }, { 2, 0 } } + { { 2, 2, 2, 2 },{ 4, 6 } }, + { { 1, 2, -1, 4 },{ 3, 2 } }, + { { 1, 2, 1, 2 },{ 3, 4 } }, + { { 1, 0 },{ 2, 0 } } }; for (const auto& it : correctnessTests) { @@ -51,34 +53,33 @@ int main() // performance tests const int32_t N = 10000000; - std::map,int32_t> performanceTests; + std::map, int32_t> performanceTests; - performanceTests[getRandomPerfomancveTest(N, 5)] = 5; - performanceTests[getRandomPerfomancveTest(N, 1000)] = 1000; - performanceTests[getRandomPerfomancveTest(N, 31)] = 31; - performanceTests[getRandomPerfomancveTest(N, 1)] = 1; - performanceTests[getRandomPerfomancveTest(N, 45)] = 1; - performanceTests[getRandomPerfomancveTest(N, 0)] = 0; - performanceTests[getRandomPerfomancveTest(N, 2345654)] = 2345654; - performanceTests[getRandomPerfomancveTest(N, 22345)] = 22345; - performanceTests[getRandomPerfomancveTest(N, 512)] = 512; + performanceTests[getRandomPerfomanceTest(N, 5)] = 5; + performanceTests[getRandomPerfomanceTest(N, 1000)] = 1000; + performanceTests[getRandomPerfomanceTest(N, 31)] = 31; + performanceTests[getRandomPerfomanceTest(N, 1)] = 1; + performanceTests[getRandomPerfomanceTest(N, 45)] = 1; + performanceTests[getRandomPerfomanceTest(N, 0)] = 0; + performanceTests[getRandomPerfomanceTest(N, 2345654)] = 2345654; + performanceTests[getRandomPerfomanceTest(N, 22345)] = 22345; + performanceTests[getRandomPerfomanceTest(N, 512)] = 512; - std::cout << "\t\tSimple\t\tMapConst\t\tMapLinear\t\t\n\n"; + std::cout << "\t\tSimple\t\tMapLinear\tMapConst\t\t\n\n"; const int32_t count = 50; - auto run = [&](ISolver* s, int n) -> int + auto run = [](std::shared_ptr s, int n) -> int { - auto result = s->solve(n); - delete s; - return result; + return s->solve(n); }; + int32_t i = 0; for (const auto& test : performanceTests) { std::cout << i++ << "\t\t"; - std::cout << measure::chrono::execution(count, run, new SimpleSolver(test.first), test.second) << "ms \t\t" - << measure::chrono::execution(count, run, new MapConstantSolver(test.first), test.second) << "ms \t\t" - << measure::chrono::execution(count, run, new MapLinearSolver(test.first), test.second) << "ms \t\t\n"; + std::cout << measure::chrono::execution(count, run, std::shared_ptr(new SimpleSolver(test.first)), test.second) << "ms \t\t" + << measure::chrono::execution(count, run, std::shared_ptr(new MapLinearSolver(test.first)), test.second) << "ms \t\t" + << measure::chrono::execution(count, run, std::shared_ptr(new MapConstantSolver(test.first)), test.second) << "ms \t\t\n"; } return 0; } From 67860c612d622699c61beaf5d86cff42cc222b4a Mon Sep 17 00:00:00 2001 From: Pronina Date: Tue, 30 Jan 2018 16:39:40 +0300 Subject: [PATCH 3/6] Separated tests --- tasks/ruslan_arutyunyan_task_2/test_solver.cpp | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/tasks/ruslan_arutyunyan_task_2/test_solver.cpp b/tasks/ruslan_arutyunyan_task_2/test_solver.cpp index e364ffb..2cdf3df 100644 --- a/tasks/ruslan_arutyunyan_task_2/test_solver.cpp +++ b/tasks/ruslan_arutyunyan_task_2/test_solver.cpp @@ -23,6 +23,12 @@ std::vector getRandomPerfomanceTest(int32_t elementCount, int32_t sourc return numbers; } +template +void ctorCall(const std::vector &array) +{ + ClassType instance(array); +} + int main() { // correctness tests @@ -65,7 +71,7 @@ int main() performanceTests[getRandomPerfomanceTest(N, 22345)] = 22345; performanceTests[getRandomPerfomanceTest(N, 512)] = 512; - std::cout << "\t\tSimple\t\tMapLinear\tMapConst\t\t\n\n"; + std::cout << "\t\tSimple\tConstructor\tSolve\t\t\tMapLinear\\tConstructor\tSolve\tMapConst\t\t\tConstructor\tSolve\n\n"; const int32_t count = 50; auto run = [](std::shared_ptr s, int n) -> int @@ -77,9 +83,14 @@ int main() for (const auto& test : performanceTests) { std::cout << i++ << "\t\t"; - std::cout << measure::chrono::execution(count, run, std::shared_ptr(new SimpleSolver(test.first)), test.second) << "ms \t\t" + std::cout << measure::chrono::execution(count, ctorCall, test.first) << "ms \t\t" + << measure::chrono::execution(count, run, std::shared_ptr(new SimpleSolver(test.first)), test.second) << "ms \t\t" + << measure::chrono::execution(count, ctorCall, test.first) << "ms \t\t" << measure::chrono::execution(count, run, std::shared_ptr(new MapLinearSolver(test.first)), test.second) << "ms \t\t" + << measure::chrono::execution(count, ctorCall, test.first) << "ms \t\t" << measure::chrono::execution(count, run, std::shared_ptr(new MapConstantSolver(test.first)), test.second) << "ms \t\t\n"; + + } return 0; } From 9f6b1d4b53a5f3d5b42018c9249e9d9491a46142 Mon Sep 17 00:00:00 2001 From: Pronina Date: Tue, 30 Jan 2018 16:54:34 +0300 Subject: [PATCH 4/6] Aligned metrics --- .../ruslan_arutyunyan_task_2/test_solver.cpp | 25 +++++++++++-------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/tasks/ruslan_arutyunyan_task_2/test_solver.cpp b/tasks/ruslan_arutyunyan_task_2/test_solver.cpp index 2cdf3df..409a8cf 100644 --- a/tasks/ruslan_arutyunyan_task_2/test_solver.cpp +++ b/tasks/ruslan_arutyunyan_task_2/test_solver.cpp @@ -58,7 +58,7 @@ int main() } // performance tests - const int32_t N = 10000000; + const int32_t N = 100; std::map, int32_t> performanceTests; performanceTests[getRandomPerfomanceTest(N, 5)] = 5; @@ -71,10 +71,10 @@ int main() performanceTests[getRandomPerfomanceTest(N, 22345)] = 22345; performanceTests[getRandomPerfomanceTest(N, 512)] = 512; - std::cout << "\t\tSimple\tConstructor\tSolve\t\t\tMapLinear\\tConstructor\tSolve\tMapConst\t\t\tConstructor\tSolve\n\n"; + std::cout << "\t\tSimple: Ctor Solve MapLinear: Ctor Solve MapConst: Ctor Solve\n\n"; const int32_t count = 50; - auto run = [](std::shared_ptr s, int n) -> int + auto run = [](ISolver *s, int n) -> int { return s->solve(n); }; @@ -82,13 +82,18 @@ int main() int32_t i = 0; for (const auto& test : performanceTests) { - std::cout << i++ << "\t\t"; - std::cout << measure::chrono::execution(count, ctorCall, test.first) << "ms \t\t" - << measure::chrono::execution(count, run, std::shared_ptr(new SimpleSolver(test.first)), test.second) << "ms \t\t" - << measure::chrono::execution(count, ctorCall, test.first) << "ms \t\t" - << measure::chrono::execution(count, run, std::shared_ptr(new MapLinearSolver(test.first)), test.second) << "ms \t\t" - << measure::chrono::execution(count, ctorCall, test.first) << "ms \t\t" - << measure::chrono::execution(count, run, std::shared_ptr(new MapConstantSolver(test.first)), test.second) << "ms \t\t\n"; + std::cout << i++ << "\t\t\t"; + std::cout << measure::chrono::execution(count, ctorCall, test.first) << "ms "; + SimpleSolver ss(test.first); + std::cout << measure::chrono::execution(count, run, &ss, test.second) << "ms \t\t"; + + std::cout << measure::chrono::execution(count, ctorCall, test.first) << "ms "; + MapLinearSolver mls(test.first); + std::cout << measure::chrono::execution(count, run, &mls, test.second) << "ms \t\t"; + + std::cout << measure::chrono::execution(count, ctorCall, test.first) << "ms "; + MapConstantSolver mcs(test.first); + std::cout << measure::chrono::execution(count, run, &mcs, test.second) << "ms \t\t\n"; } From 06509fb68633ceca886d5f1c48bb85787b2e198f Mon Sep 17 00:00:00 2001 From: Pronina Date: Tue, 30 Jan 2018 16:57:07 +0300 Subject: [PATCH 5/6] Aligned metrics --- tasks/ruslan_arutyunyan_task_2/test_solver.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/tasks/ruslan_arutyunyan_task_2/test_solver.cpp b/tasks/ruslan_arutyunyan_task_2/test_solver.cpp index 409a8cf..a644226 100644 --- a/tasks/ruslan_arutyunyan_task_2/test_solver.cpp +++ b/tasks/ruslan_arutyunyan_task_2/test_solver.cpp @@ -58,7 +58,7 @@ int main() } // performance tests - const int32_t N = 100; + const int32_t N = 1000; std::map, int32_t> performanceTests; performanceTests[getRandomPerfomanceTest(N, 5)] = 5; @@ -83,19 +83,17 @@ int main() for (const auto& test : performanceTests) { std::cout << i++ << "\t\t\t"; - std::cout << measure::chrono::execution(count, ctorCall, test.first) << "ms "; + std::cout << measure::chrono::execution(count, ctorCall, test.first) << "ms "; SimpleSolver ss(test.first); std::cout << measure::chrono::execution(count, run, &ss, test.second) << "ms \t\t"; - std::cout << measure::chrono::execution(count, ctorCall, test.first) << "ms "; + std::cout << measure::chrono::execution(count, ctorCall, test.first) << "ms "; MapLinearSolver mls(test.first); std::cout << measure::chrono::execution(count, run, &mls, test.second) << "ms \t\t"; std::cout << measure::chrono::execution(count, ctorCall, test.first) << "ms "; MapConstantSolver mcs(test.first); std::cout << measure::chrono::execution(count, run, &mcs, test.second) << "ms \t\t\n"; - - } return 0; } From a5c50e2dc2a1f8a433e57a2180993510781743c1 Mon Sep 17 00:00:00 2001 From: Pronina Date: Tue, 30 Jan 2018 18:53:27 +0300 Subject: [PATCH 6/6] Fixed tests run count --- tasks/ruslan_arutyunyan_task_2/solver.h | 1 - 1 file changed, 1 deletion(-) diff --git a/tasks/ruslan_arutyunyan_task_2/solver.h b/tasks/ruslan_arutyunyan_task_2/solver.h index 509b0f9..93a58eb 100644 --- a/tasks/ruslan_arutyunyan_task_2/solver.h +++ b/tasks/ruslan_arutyunyan_task_2/solver.h @@ -16,7 +16,6 @@ class SimpleSolver : public ISolver int32_t solve(int32_t number) override { - //Worst case: O((n^2)*log(n)) int32_t count{ }; auto end{ numbers.cend() }; for (auto it = numbers.cbegin(); it != end; ++it)