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..93a58eb --- /dev/null +++ b/tasks/ruslan_arutyunyan_task_2/solver.h @@ -0,0 +1,101 @@ +#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 + { + 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..a644226 --- /dev/null +++ b/tasks/ruslan_arutyunyan_task_2/test_solver.cpp @@ -0,0 +1,100 @@ +#include "solver.h" +#include "measure.h" +#include +#include +#include +#include +#include +#include +#include + +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); + numbers.emplace_back(remainder); + } + std::random_shuffle(numbers.begin(), numbers.end()); + return numbers; +} + +template +void ctorCall(const std::vector &array) +{ + ClassType instance(array); +} + +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 = 1000; + std::map, int32_t> performanceTests; + + 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: Ctor Solve MapLinear: Ctor Solve MapConst: Ctor Solve\n\n"; + const int32_t count = 50; + + auto run = [](ISolver *s, int n) -> int + { + return s->solve(n); + }; + + int32_t i = 0; + for (const auto& test : performanceTests) + { + 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"; + } + return 0; +} +