| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | #include "levonychev_i_multistep_2d_optimization/mpi/include/ops_mpi.hpp" | ||
| 2 | |||
| 3 | #include <mpi.h> | ||
| 4 | |||
| 5 | #include <algorithm> | ||
| 6 | #include <cmath> | ||
| 7 | #include <cstddef> | ||
| 8 | #include <iterator> | ||
| 9 | #include <limits> | ||
| 10 | #include <utility> | ||
| 11 | #include <vector> | ||
| 12 | |||
| 13 | #include "levonychev_i_multistep_2d_optimization/common/include/common.hpp" | ||
| 14 | #include "levonychev_i_multistep_2d_optimization/common/include/optimization_common.hpp" | ||
| 15 | |||
| 16 | namespace levonychev_i_multistep_2d_optimization { | ||
| 17 | |||
| 18 |
1/2✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
|
6 | LevonychevIMultistep2dOptimizationMPI::LevonychevIMultistep2dOptimizationMPI(const InType &in) { |
| 19 | SetTypeOfTask(GetStaticTypeOfTask()); | ||
| 20 |
1/2✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
|
6 | GetInput() = in; |
| 21 | 6 | GetOutput() = OptimizationResult(); | |
| 22 | 6 | } | |
| 23 | |||
| 24 | 6 | bool LevonychevIMultistep2dOptimizationMPI::ValidationImpl() { | |
| 25 | const auto ¶ms = GetInput(); | ||
| 26 | |||
| 27 |
2/4✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 6 times.
|
6 | bool is_correct_ranges = (params.x_min < params.x_max) && (params.y_min < params.y_max); |
| 28 | bool isnt_correct_func = !params.func; | ||
| 29 |
3/6✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 6 times.
|
6 | bool is_correct_params = (params.num_steps > 0) && (params.grid_size_step1 > 0) && (params.candidates_per_step > 0); |
| 30 | |||
| 31 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
|
6 | return is_correct_ranges && !isnt_correct_func && is_correct_params; |
| 32 | } | ||
| 33 | |||
| 34 | 6 | bool LevonychevIMultistep2dOptimizationMPI::PreProcessingImpl() { | |
| 35 | 6 | GetOutput() = OptimizationResult(); | |
| 36 | 6 | return true; | |
| 37 | } | ||
| 38 | |||
| 39 | ✗ | void LevonychevIMultistep2dOptimizationMPI::InitializeRegions(int rank, int size, const OptimizationParams ¶ms, | |
| 40 | SearchRegion &my_region) { | ||
| 41 | 6 | double total_width = params.x_max - params.x_min; | |
| 42 | 6 | double width_per_process = total_width / size; | |
| 43 | |||
| 44 | 6 | double x_min_proc = params.x_min + (rank * width_per_process); | |
| 45 |
0/2✗ Branch 0 not taken.
✗ Branch 1 not taken.
|
3 | double x_max_proc = (rank == size - 1) ? params.x_max : params.x_min + ((rank + 1) * width_per_process); |
| 46 | 6 | my_region = SearchRegion(x_min_proc, x_max_proc, params.y_min, params.y_max); | |
| 47 | ✗ | } | |
| 48 | 18 | void LevonychevIMultistep2dOptimizationMPI::ProcessLocalCandidates(const OptimizationParams ¶ms, | |
| 49 | const std::vector<Point> &local_points, | ||
| 50 | std::vector<Point> &local_candidates) { | ||
| 51 | 18 | int num_local_candidates = std::min(params.candidates_per_step, static_cast<int>(local_points.size())); | |
| 52 | 18 | local_candidates.assign(local_points.begin(), local_points.begin() + num_local_candidates); | |
| 53 | |||
| 54 |
1/2✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
|
18 | while (std::cmp_less(local_candidates.size(), params.candidates_per_step)) { |
| 55 | ✗ | local_candidates.emplace_back(); | |
| 56 | } | ||
| 57 | 18 | } | |
| 58 | |||
| 59 | 6 | void LevonychevIMultistep2dOptimizationMPI::ExecuteOptimizationSteps(int rank, int size, | |
| 60 | const OptimizationParams ¶ms, | ||
| 61 | SearchRegion &my_region) { | ||
| 62 |
2/2✓ Branch 0 taken 18 times.
✓ Branch 1 taken 6 times.
|
24 | for (int step = 0; step < params.num_steps; ++step) { |
| 63 | 18 | int grid_size = params.grid_size_step1 * (1 << step); | |
| 64 | 18 | std::vector<Point> local_points; | |
| 65 |
1/2✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
|
18 | local_points.reserve(grid_size * grid_size / size); |
| 66 |
1/2✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
|
18 | SearchInRegion(local_points, params.func, my_region, grid_size, size); |
| 67 | |||
| 68 | 18 | std::vector<Point> local_candidates; | |
| 69 |
1/2✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
|
18 | ProcessLocalCandidates(params, local_points, local_candidates); |
| 70 | |||
| 71 |
3/4✓ Branch 0 taken 6 times.
✓ Branch 1 taken 12 times.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
|
18 | if (step >= params.num_steps - 1) { |
| 72 | continue; | ||
| 73 | } | ||
| 74 | |||
| 75 | 12 | std::vector<Point> all_candidates; | |
| 76 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 6 times.
|
12 | if (rank == 0) { |
| 77 |
1/2✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
|
6 | all_candidates.resize(static_cast<size_t>(params.candidates_per_step) * static_cast<size_t>(size)); |
| 78 | } | ||
| 79 | |||
| 80 | 12 | MPI_Gather(local_candidates.data(), static_cast<int>(params.candidates_per_step * sizeof(Point)), MPI_BYTE, | |
| 81 |
1/2✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
|
12 | all_candidates.data(), static_cast<int>(params.candidates_per_step * sizeof(Point)), MPI_BYTE, 0, |
| 82 | MPI_COMM_WORLD); | ||
| 83 | |||
| 84 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 6 times.
|
12 | if (rank == 0) { |
| 85 | 6 | std::vector<Point> valid_candidates; | |
| 86 | std::ranges::copy_if(all_candidates, std::back_inserter(valid_candidates), | ||
| 87 |
1/2✓ Branch 0 taken 48 times.
✗ Branch 1 not taken.
|
48 | [](const Point &p) { return p.value < std::numeric_limits<double>::max(); }); |
| 88 |
4/24✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✓ Branch 18 taken 1 times.
✓ Branch 19 taken 41 times.
✓ Branch 20 taken 20 times.
✓ Branch 21 taken 41 times.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
|
103 | std::ranges::sort(valid_candidates, [](const Point &a, const Point &b) { return a.value < b.value; }); |
| 89 | |||
| 90 |
1/2✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
|
6 | int num_global_candidates = std::min(params.candidates_per_step, static_cast<int>(valid_candidates.size())); |
| 91 |
1/2✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
|
6 | all_candidates.assign(valid_candidates.begin(), valid_candidates.begin() + num_global_candidates); |
| 92 | } | ||
| 93 | |||
| 94 |
1/4✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
|
12 | std::vector<Point> bcast_candidates(params.candidates_per_step); |
| 95 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 6 times.
|
12 | if (rank == 0) { |
| 96 |
1/2✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
|
6 | bcast_candidates = all_candidates; |
| 97 | } | ||
| 98 |
1/2✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
|
12 | MPI_Bcast(bcast_candidates.data(), static_cast<int>(params.candidates_per_step * sizeof(Point)), MPI_BYTE, 0, |
| 99 | MPI_COMM_WORLD); | ||
| 100 |
1/2✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
|
12 | if (!bcast_candidates.empty()) { |
| 101 | 12 | int candidate_idx = rank % static_cast<int>(bcast_candidates.size()); | |
| 102 | 12 | const auto &cand = bcast_candidates[candidate_idx]; | |
| 103 | |||
| 104 | 12 | double margin_x = (params.x_max - params.x_min) * 0.05 / (1 << step); | |
| 105 | 12 | double margin_y = (params.y_max - params.y_min) * 0.05 / (1 << step); | |
| 106 | |||
| 107 | 12 | my_region = SearchRegion(std::max(params.x_min, cand.x - margin_x), std::min(params.x_max, cand.x + margin_x), | |
| 108 | 12 | std::max(params.y_min, cand.y - margin_y), std::min(params.y_max, cand.y + margin_y)); | |
| 109 | } | ||
| 110 | } | ||
| 111 | 6 | } | |
| 112 | |||
| 113 | 6 | void LevonychevIMultistep2dOptimizationMPI::GatherFinalPoints(int rank, int size, const Point &my_best, | |
| 114 | std::vector<Point> &all_final_points) { | ||
| 115 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
|
6 | if (rank == 0) { |
| 116 | 3 | all_final_points.resize(static_cast<size_t>(size)); | |
| 117 | } | ||
| 118 | |||
| 119 | 6 | MPI_Gather(&my_best, sizeof(Point), MPI_BYTE, (rank == 0) ? all_final_points.data() : nullptr, sizeof(Point), | |
| 120 | MPI_BYTE, 0, MPI_COMM_WORLD); | ||
| 121 | 6 | } | |
| 122 | |||
| 123 | 6 | Point LevonychevIMultistep2dOptimizationMPI::SelectGlobalBest(int rank, const OptimizationParams ¶ms, | |
| 124 | const std::vector<Point> &all_final_points) { | ||
| 125 | 6 | Point global_best; | |
| 126 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
|
6 | if (rank == 0) { |
| 127 | 3 | std::vector<Point> valid_points; | |
| 128 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 3 times.
|
9 | for (const auto &point : all_final_points) { |
| 129 |
1/2✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
|
6 | if (point.value < std::numeric_limits<double>::max()) { |
| 130 |
1/2✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
|
6 | valid_points.push_back(point); |
| 131 | } | ||
| 132 | } | ||
| 133 | |||
| 134 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | if (!valid_points.empty()) { |
| 135 |
2/22✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✓ Branch 17 taken 3 times.
✗ Branch 18 not taken.
✓ Branch 19 taken 3 times.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
|
6 | std::ranges::sort(valid_points, [](const Point &a, const Point &b) { return a.value < b.value; }); |
| 136 | 3 | global_best = valid_points[0]; | |
| 137 | } else { | ||
| 138 | ✗ | global_best = Point((params.x_min + params.x_max) / 2.0, (params.y_min + params.y_max) / 2.0, | |
| 139 | ✗ | params.func((params.x_min + params.x_max) / 2.0, (params.y_min + params.y_max) / 2.0)); | |
| 140 | } | ||
| 141 | } | ||
| 142 | 6 | return global_best; | |
| 143 | } | ||
| 144 | |||
| 145 | 6 | Point LevonychevIMultistep2dOptimizationMPI::FindGlobalBest(int rank, int size, const OptimizationParams ¶ms, | |
| 146 | const SearchRegion &my_region) { | ||
| 147 | 6 | Point my_best; | |
| 148 | |||
| 149 |
2/4✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
|
6 | if (my_region.x_min < my_region.x_max && my_region.y_min < my_region.y_max) { |
| 150 | int power_of_2 = 1; | ||
| 151 |
2/2✓ Branch 0 taken 12 times.
✓ Branch 1 taken 6 times.
|
18 | for (int i = 0; i < params.num_steps - 1; ++i) { |
| 152 | 12 | power_of_2 *= 2; | |
| 153 | } | ||
| 154 | 6 | std::vector<Point> local_points; | |
| 155 |
1/2✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
|
6 | local_points.reserve(params.grid_size_step1 * power_of_2 * params.grid_size_step1 * power_of_2 / size); |
| 156 |
1/2✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
|
6 | SearchInRegion(local_points, params.func, my_region, params.grid_size_step1 * power_of_2, size); |
| 157 | |||
| 158 |
1/2✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
|
6 | if (!local_points.empty()) { |
| 159 | 6 | my_best = local_points[0]; | |
| 160 |
1/2✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
|
6 | if (params.use_local_optimization) { |
| 161 | 6 | my_best = LocalOptimization(params.func, my_best.x, my_best.y, params.x_min, params.x_max, params.y_min, | |
| 162 |
1/2✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
|
6 | params.y_max); |
| 163 | } | ||
| 164 | } | ||
| 165 | } | ||
| 166 | |||
| 167 | 6 | std::vector<Point> all_final_points; | |
| 168 |
1/2✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
|
6 | GatherFinalPoints(rank, size, my_best, all_final_points); |
| 169 | |||
| 170 |
1/2✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
|
6 | Point global_best = SelectGlobalBest(rank, params, all_final_points); |
| 171 | |||
| 172 |
1/2✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
|
6 | MPI_Bcast(&global_best, sizeof(Point), MPI_BYTE, 0, MPI_COMM_WORLD); |
| 173 | |||
| 174 | 6 | return global_best; | |
| 175 | } | ||
| 176 | |||
| 177 | 6 | bool LevonychevIMultistep2dOptimizationMPI::RunImpl() { | |
| 178 | const auto ¶ms = GetInput(); | ||
| 179 | auto &result = GetOutput(); | ||
| 180 | |||
| 181 | 6 | int rank = 0; | |
| 182 | 6 | int size = 0; | |
| 183 | 6 | MPI_Comm_rank(MPI_COMM_WORLD, &rank); | |
| 184 | 6 | MPI_Comm_size(MPI_COMM_WORLD, &size); | |
| 185 | |||
| 186 | SearchRegion my_region; | ||
| 187 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
|
6 | InitializeRegions(rank, size, params, my_region); |
| 188 | 6 | ExecuteOptimizationSteps(rank, size, params, my_region); | |
| 189 | 6 | Point global_best = FindGlobalBest(rank, size, params, my_region); | |
| 190 | 6 | result.x_min = global_best.x; | |
| 191 | 6 | result.y_min = global_best.y; | |
| 192 | 6 | result.value = global_best.value; | |
| 193 | 6 | return true; | |
| 194 | } | ||
| 195 | |||
| 196 | 6 | bool LevonychevIMultistep2dOptimizationMPI::PostProcessingImpl() { | |
| 197 | const auto ¶ms = GetInput(); | ||
| 198 | auto &result = GetOutput(); | ||
| 199 | |||
| 200 |
3/6✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
|
6 | return result.x_min >= params.x_min && result.x_min <= params.x_max && result.y_min >= params.y_min && |
| 201 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
|
6 | result.y_min <= params.y_max; |
| 202 | } | ||
| 203 | |||
| 204 | } // namespace levonychev_i_multistep_2d_optimization | ||
| 205 |