| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | #include "nikitin_a_monte_carlo/omp/include/ops_omp.hpp" | ||
| 2 | |||
| 3 | #include <omp.h> | ||
| 4 | |||
| 5 | #include <array> | ||
| 6 | #include <cmath> | ||
| 7 | #include <cstddef> | ||
| 8 | #include <vector> | ||
| 9 | |||
| 10 | #include "nikitin_a_monte_carlo/common/include/common.hpp" | ||
| 11 | |||
| 12 | namespace nikitin_a_monte_carlo { | ||
| 13 | |||
| 14 | namespace { | ||
| 15 | // Вспомогательная функция для вычисления значения тестовой функции | ||
| 16 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2004400 times.
|
2004400 | double EvaluateFunction(const std::vector<double> &point, FunctionType type) { |
| 17 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2004400 times.
|
2004400 | if (point.empty()) { |
| 18 | return 0.0; | ||
| 19 | } | ||
| 20 | |||
| 21 |
5/6✗ Branch 0 not taken.
✓ Branch 1 taken 600000 times.
✓ Branch 2 taken 200000 times.
✓ Branch 3 taken 120000 times.
✓ Branch 4 taken 80000 times.
✓ Branch 5 taken 1004400 times.
|
2004400 | switch (type) { |
| 22 | case FunctionType::kConstant: | ||
| 23 | return 1.0; | ||
| 24 | case FunctionType::kLinear: | ||
| 25 | 600000 | return point.at(0); | |
| 26 | case FunctionType::kProduct: | ||
| 27 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 200000 times.
|
200000 | if (point.size() < 2) { |
| 28 | return 0.0; | ||
| 29 | } | ||
| 30 | 200000 | return point.at(0) * point.at(1); | |
| 31 | case FunctionType::kQuadratic: | ||
| 32 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 120000 times.
|
120000 | if (point.size() < 2) { |
| 33 | return 0.0; | ||
| 34 | } | ||
| 35 | 120000 | return (point.at(0) * point.at(0)) + (point.at(1) * point.at(1)); | |
| 36 | case FunctionType::kExponential: | ||
| 37 | 80000 | return std::exp(point.at(0)); | |
| 38 | default: | ||
| 39 | return 0.0; | ||
| 40 | } | ||
| 41 | } | ||
| 42 | |||
| 43 | // Генерация квазислучайной последовательности Кронекера | ||
| 44 | 4448800 | double KroneckerSequence(int index, int dimension) { | |
| 45 | 4448800 | const std::array<double, 10> primes = {2.0, 3.0, 5.0, 7.0, 11.0, 13.0, 17.0, 19.0, 23.0, 29.0}; | |
| 46 |
1/2✓ Branch 0 taken 4448800 times.
✗ Branch 1 not taken.
|
4448800 | double alpha = std::sqrt(primes.at(static_cast<std::size_t>(dimension % 10))); |
| 47 | 4448800 | alpha = alpha - std::floor(alpha); | |
| 48 | 4448800 | return std::fmod(index * alpha, 1.0); | |
| 49 | } | ||
| 50 | } // namespace | ||
| 51 | |||
| 52 |
1/2✓ Branch 1 taken 88 times.
✗ Branch 2 not taken.
|
88 | NikitinAMonteCarloOMP::NikitinAMonteCarloOMP(const InType &in) { |
| 53 | SetTypeOfTask(GetStaticTypeOfTask()); | ||
| 54 | GetInput() = in; | ||
| 55 | 88 | GetOutput() = 0.0; | |
| 56 | 88 | } | |
| 57 | |||
| 58 |
1/2✓ Branch 0 taken 88 times.
✗ Branch 1 not taken.
|
88 | bool NikitinAMonteCarloOMP::ValidationImpl() { |
| 59 | const auto &[lower_bounds, upper_bounds, num_points, func_type] = GetInput(); | ||
| 60 | |||
| 61 |
2/4✓ Branch 0 taken 88 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 88 times.
|
88 | if (lower_bounds.empty() || upper_bounds.empty()) { |
| 62 | return false; | ||
| 63 | } | ||
| 64 | |||
| 65 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 88 times.
|
88 | if (lower_bounds.size() != upper_bounds.size()) { |
| 66 | return false; | ||
| 67 | } | ||
| 68 | |||
| 69 |
2/2✓ Branch 0 taken 156 times.
✓ Branch 1 taken 88 times.
|
244 | for (std::size_t i = 0; i < lower_bounds.size(); ++i) { |
| 70 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 156 times.
|
156 | if (lower_bounds[i] >= upper_bounds[i]) { |
| 71 | return false; | ||
| 72 | } | ||
| 73 | } | ||
| 74 | |||
| 75 | 88 | return num_points > 0; | |
| 76 | } | ||
| 77 | |||
| 78 | 88 | bool NikitinAMonteCarloOMP::PreProcessingImpl() { | |
| 79 | 88 | return true; | |
| 80 | } | ||
| 81 | |||
| 82 | 88 | bool NikitinAMonteCarloOMP::RunImpl() { | |
| 83 | // Получаем входные данные и распаковываем их в обычные переменные | ||
| 84 | const auto input = GetInput(); | ||
| 85 | const auto &lower_bounds = std::get<0>(input); | ||
| 86 | const auto &upper_bounds = std::get<1>(input); | ||
| 87 | 88 | const int num_points = std::get<2>(input); | |
| 88 | 88 | const FunctionType func_type = std::get<3>(input); | |
| 89 | |||
| 90 | std::size_t dim = lower_bounds.size(); | ||
| 91 | |||
| 92 | // Вычисление объема области интегрирования | ||
| 93 | double volume = 1.0; | ||
| 94 |
2/2✓ Branch 0 taken 156 times.
✓ Branch 1 taken 88 times.
|
244 | for (std::size_t i = 0; i < dim; ++i) { |
| 95 | 156 | volume *= (upper_bounds[i] - lower_bounds[i]); | |
| 96 | } | ||
| 97 | |||
| 98 | double sum = 0.0; | ||
| 99 | |||
| 100 | // Параллельный цикл с явным указанием всех используемых переменных | ||
| 101 | 88 | #pragma omp parallel for schedule(static) reduction(+ : sum) default(none) \ | |
| 102 | shared(lower_bounds, upper_bounds, dim, num_points, func_type) | ||
| 103 | for (int i = 0; i < num_points; ++i) { | ||
| 104 | std::vector<double> point(dim); | ||
| 105 | for (std::size_t j = 0; j < dim; ++j) { | ||
| 106 | double u = KroneckerSequence(i, static_cast<int>(j)); | ||
| 107 | point[j] = lower_bounds[j] + (u * (upper_bounds[j] - lower_bounds[j])); | ||
| 108 | } | ||
| 109 | sum += EvaluateFunction(point, func_type); | ||
| 110 | } | ||
| 111 | |||
| 112 | 88 | double result = volume * sum / static_cast<double>(num_points); | |
| 113 | 88 | GetOutput() = result; | |
| 114 | |||
| 115 | 88 | return true; | |
| 116 | } | ||
| 117 | |||
| 118 | 88 | bool NikitinAMonteCarloOMP::PostProcessingImpl() { | |
| 119 | 88 | return true; | |
| 120 | } | ||
| 121 | |||
| 122 | } // namespace nikitin_a_monte_carlo | ||
| 123 |