GCC Code Coverage Report


Directory: ./
File: tasks/levonychev_i_multistep_2d_optimization/mpi/src/ops_mpi.cpp
Date: 2026-01-10 02:40:41
Exec Total Coverage
Lines: 102 107 95.3%
Functions: 10 11 90.9%
Branches: 65 150 43.3%

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 &params = 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 &params,
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 &params,
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 &params,
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 &params,
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 &params,
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 &params = 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 &params = 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