GCC Code Coverage Report


Directory: ./
File: tasks/kruglova_a_2d_multistep_par_opt/mpi/src/ops_mpi.cpp
Date: 2026-01-10 02:40:41
Exec Total Coverage
Lines: 124 124 100.0%
Functions: 14 14 100.0%
Branches: 96 146 65.8%

Line Branch Exec Source
1 #include "kruglova_a_2d_multistep_par_opt/mpi/include/ops_mpi.hpp"
2
3 #include <mpi.h>
4
5 #include <algorithm>
6 #include <array>
7 #include <cmath>
8 #include <cstddef>
9 #include <functional>
10 #include <limits>
11 #include <vector>
12
13 #include "kruglova_a_2d_multistep_par_opt/common/include/common.hpp"
14
15 namespace kruglova_a_2d_multistep_par_opt {
16
17 namespace {
18
19 struct Trial1D {
20 double x;
21 double z;
22 384 Trial1D(double x_val, double z_val) : x(x_val), z(z_val) {}
23 };
24
25 struct Trial2D {
26 double x;
27 double y;
28 double z;
29
1/2
✓ Branch 1 taken 102 times.
✗ Branch 2 not taken.
102 Trial2D(double x_val, double y_val, double z_val) : x(x_val), y(y_val), z(z_val) {}
30 };
31
32 struct CharIdx {
33 double r_val;
34 size_t idx;
35 };
36
37 4541 void ManualInsert1D(std::vector<Trial1D> &trials, const Trial1D &value) {
38 size_t pos = 0;
39
3/4
✓ Branch 0 taken 36119 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 31578 times.
✓ Branch 3 taken 4541 times.
36119 while (pos < trials.size() && trials[pos].x < value.x) {
40 31578 pos++;
41 }
42 4541 trials.insert(trials.begin() + static_cast<std::ptrdiff_t>(pos), value);
43 4541 }
44
45 192 void ManualInsert2D(std::vector<Trial2D> &trials, const Trial2D &value) {
46 size_t pos = 0;
47
4/4
✓ Branch 0 taken 1968 times.
✓ Branch 1 taken 90 times.
✓ Branch 2 taken 1866 times.
✓ Branch 3 taken 102 times.
2058 while (pos < trials.size() && trials[pos].x < value.x) {
48 1866 pos++;
49 }
50
3/4
✓ Branch 0 taken 102 times.
✓ Branch 1 taken 90 times.
✓ Branch 2 taken 102 times.
✗ Branch 3 not taken.
192 if (pos == trials.size() || std::abs(trials[pos].x - value.x) > 1e-12) {
51 192 trials.insert(trials.begin() + static_cast<std::ptrdiff_t>(pos), value);
52 }
53 192 }
54
55 57 void ManualSortRates(std::vector<CharIdx> &rates) {
56
2/2
✓ Branch 0 taken 1362 times.
✓ Branch 1 taken 57 times.
1419 for (size_t i = 0; i < rates.size(); ++i) {
57 size_t max_i = i;
58
2/2
✓ Branch 0 taken 17141 times.
✓ Branch 1 taken 1362 times.
18503 for (size_t j = i + 1; j < rates.size(); ++j) {
59
2/2
✓ Branch 0 taken 2734 times.
✓ Branch 1 taken 14407 times.
17141 if (rates[j].r_val > rates[max_i].r_val) {
60 max_i = j;
61 }
62 }
63
2/2
✓ Branch 0 taken 1103 times.
✓ Branch 1 taken 259 times.
1362 if (max_i != i) {
64 std::swap(rates[i], rates[max_i]);
65 }
66 }
67 57 }
68
69 template <typename T>
70 9580 double CalculateM(const std::vector<T> &trials) {
71 9580 double m_max = 0.0;
72
2/2
✓ Branch 0 taken 64706 times.
✓ Branch 1 taken 4790 times.
138992 for (size_t i = 0; (i + 1) < trials.size(); ++i) {
73 129412 const double dx = trials[i + 1].x - trials[i].x;
74
1/2
✓ Branch 0 taken 64706 times.
✗ Branch 1 not taken.
129412 if (dx > 1e-15) {
75 129412 const double dz = std::abs(trials[i + 1].z - trials[i].z);
76 129412 m_max = std::max(m_max, dz / dx);
77 }
78 }
79 9580 return m_max;
80 }
81
82 57 void PrepareIntervals(const std::vector<Trial2D> &trials, std::vector<double> &buf, int size, double eps, int &stop) {
83 57 const double m_v = CalculateM(trials);
84
1/2
✓ Branch 0 taken 57 times.
✗ Branch 1 not taken.
57 const double m_scaled = (m_v > 0.0) ? (2.0 * m_v) : 1.0;
85 57 std::vector<CharIdx> rates;
86
2/2
✓ Branch 0 taken 1362 times.
✓ Branch 1 taken 57 times.
1419 for (size_t i = 0; (i + 1) < trials.size(); ++i) {
87 1362 const double dx = trials[i + 1].x - trials[i].x;
88 1362 const double dz = trials[i + 1].z - trials[i].z;
89 1362 const double r = (m_scaled * dx) + ((dz * dz) / (m_scaled * dx)) - (2.0 * (trials[i + 1].z + trials[i].z));
90
1/4
✓ Branch 1 taken 1362 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
1362 rates.push_back({r, i});
91 }
92 57 ManualSortRates(rates);
93
3/4
✓ Branch 0 taken 57 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 51 times.
57 if (rates.empty() || (trials[rates[0].idx + 1].x - trials[rates[0].idx].x < eps)) {
94
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 stop = 1;
95 return;
96 }
97
2/2
✓ Branch 0 taken 102 times.
✓ Branch 1 taken 51 times.
153 for (int i = 0; i < size; ++i) {
98
1/2
✓ Branch 0 taken 102 times.
✗ Branch 1 not taken.
102 const size_t s_idx = (static_cast<size_t>(i) < rates.size()) ? rates[static_cast<size_t>(i)].idx : rates[0].idx;
99 102 buf[(static_cast<size_t>(i) * 4) + 0] = trials[s_idx].x;
100 102 buf[(static_cast<size_t>(i) * 4) + 1] = trials[s_idx + 1].x;
101 102 buf[(static_cast<size_t>(i) * 4) + 2] = trials[s_idx].z;
102 102 buf[(static_cast<size_t>(i) * 4) + 3] = trials[s_idx + 1].z;
103 }
104 }
105
106 192 double Solve1DStrongin(const std::function<double(double)> &func, double a, double b, double eps, int max_iters,
107 double &best_x) {
108 const double r_param = 2.0;
109 192 std::vector<Trial1D> trials;
110
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 192 times.
✓ Branch 3 taken 192 times.
✗ Branch 4 not taken.
384 trials.emplace_back(a, func(a));
111
3/6
✗ Branch 0 not taken.
✓ Branch 1 taken 192 times.
✓ Branch 3 taken 192 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 192 times.
384 trials.emplace_back(b, func(b));
112
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 192 times.
192 if (trials[0].x > trials[1].x) {
113 std::swap(trials[0], trials[1]);
114 }
115
1/2
✓ Branch 0 taken 4733 times.
✗ Branch 1 not taken.
4733 for (int iter = 0; iter < max_iters; ++iter) {
116 4733 const double m_v = CalculateM(trials);
117
2/2
✓ Branch 0 taken 4587 times.
✓ Branch 1 taken 146 times.
4733 const double m_scaled = (m_v > 0.0) ? (r_param * m_v) : 1.0;
118 double max_rate = -std::numeric_limits<double>::infinity();
119 size_t idx = 0;
120
2/2
✓ Branch 0 taken 63344 times.
✓ Branch 1 taken 4733 times.
68077 for (size_t i = 0; (i + 1) < trials.size(); ++i) {
121 63344 const double dx = trials[i + 1].x - trials[i].x;
122 63344 const double dz = trials[i + 1].z - trials[i].z;
123 63344 const double rate = (m_scaled * dx) + ((dz * dz) / (m_scaled * dx)) - (2.0 * (trials[i + 1].z + trials[i].z));
124
2/2
✓ Branch 0 taken 18972 times.
✓ Branch 1 taken 44372 times.
63344 if (rate > max_rate) {
125 max_rate = rate;
126 idx = i;
127 }
128 }
129
2/2
✓ Branch 0 taken 4541 times.
✓ Branch 1 taken 192 times.
4733 if ((trials[idx + 1].x - trials[idx].x) < eps) {
130 break;
131 }
132 const double x_new =
133
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4541 times.
4541 (0.5 * (trials[idx + 1].x + trials[idx].x)) - ((trials[idx + 1].z - trials[idx].z) / (2.0 * m_scaled));
134
1/4
✓ Branch 1 taken 4541 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
4541 ManualInsert1D(trials, Trial1D(x_new, func(x_new)));
135 }
136 size_t best = 0;
137
2/2
✓ Branch 0 taken 4733 times.
✓ Branch 1 taken 192 times.
4925 for (size_t i = 1; i < trials.size(); ++i) {
138
2/2
✓ Branch 0 taken 957 times.
✓ Branch 1 taken 3776 times.
4733 if (trials[i].z < trials[best].z) {
139 best = i;
140 }
141 }
142 192 best_x = trials[best].x;
143
1/2
✓ Branch 0 taken 192 times.
✗ Branch 1 not taken.
384 return trials[best].z;
144 }
145
146 6 void SyncBestResult(std::vector<Trial2D> &trials, double *out_data) {
147 size_t b = 0;
148
2/2
✓ Branch 0 taken 186 times.
✓ Branch 1 taken 6 times.
192 for (size_t i = 1; i < trials.size(); ++i) {
149
2/2
✓ Branch 0 taken 41 times.
✓ Branch 1 taken 145 times.
186 if (trials[i].z < trials[b].z) {
150 b = i;
151 }
152 }
153 6 out_data[0] = trials[b].x;
154 6 out_data[1] = trials[b].y;
155 6 out_data[2] = trials[b].z;
156 6 }
157
158 } // namespace
159
160 12 KruglovaA2DMuitMPI::KruglovaA2DMuitMPI(const InType &in) {
161 SetTypeOfTask(GetStaticTypeOfTask());
162 12 GetInput() = in;
163 12 }
164
165 12 bool KruglovaA2DMuitMPI::ValidationImpl() {
166 const auto &in = GetInput();
167
4/8
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 12 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 12 times.
12 return (in.x_max > in.x_min) && (in.y_max > in.y_min) && (in.eps > 0.0) && (in.max_iters > 0);
168 }
169
170 12 bool KruglovaA2DMuitMPI::PreProcessingImpl() {
171 12 GetOutput() = {0.0, 0.0, std::numeric_limits<double>::max()};
172 12 return true;
173 }
174
175 12 bool KruglovaA2DMuitMPI::RunImpl() {
176 12 int rank = 0;
177 12 int size = 0;
178 12 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
179 12 MPI_Comm_size(MPI_COMM_WORLD, &size);
180 const auto &in = GetInput();
181 12 std::vector<Trial2D> trials;
182
183 192 auto compute_z = [&](double x_v, double &y_b) {
184
1/2
✓ Branch 1 taken 192 times.
✗ Branch 2 not taken.
192 return Solve1DStrongin([&](double y) { return ObjectiveFunction(x_v, y); }, in.y_min, in.y_max, in.eps,
185
1/2
✓ Branch 0 taken 192 times.
✗ Branch 1 not taken.
384 std::max(50, in.max_iters / 15), y_b);
186 12 };
187
188
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 6 times.
12 if (rank == 0) {
189
2/2
✓ Branch 0 taken 90 times.
✓ Branch 1 taken 6 times.
96 for (int i = 0; i < 15; ++i) {
190 90 double x = in.x_min + ((in.x_max - in.x_min) * (static_cast<double>(i) / 14.0));
191 90 double y = 0.0;
192
1/2
✓ Branch 1 taken 90 times.
✗ Branch 2 not taken.
90 double z = compute_z(x, y);
193
1/2
✓ Branch 1 taken 90 times.
✗ Branch 2 not taken.
90 ManualInsert2D(trials, Trial2D(x, y, z));
194 }
195 }
196
197
1/2
✓ Branch 0 taken 114 times.
✗ Branch 1 not taken.
114 for (int iter = 0; iter < in.max_iters; ++iter) {
198 114 int stop_f = 0;
199
1/4
✓ Branch 1 taken 114 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
114 std::vector<double> int_buf(static_cast<size_t>(size) * 4, 0.0);
200
2/2
✓ Branch 0 taken 57 times.
✓ Branch 1 taken 57 times.
114 if (rank == 0) {
201
1/2
✓ Branch 1 taken 57 times.
✗ Branch 2 not taken.
57 PrepareIntervals(trials, int_buf, size, in.eps, stop_f);
202 }
203
204
1/2
✓ Branch 1 taken 114 times.
✗ Branch 2 not taken.
114 MPI_Bcast(&stop_f, 1, MPI_INT, 0, MPI_COMM_WORLD);
205
2/2
✓ Branch 0 taken 102 times.
✓ Branch 1 taken 12 times.
114 if (stop_f != 0) {
206 break;
207 }
208
209
1/2
✓ Branch 1 taken 102 times.
✗ Branch 2 not taken.
102 std::array<double, 4> my_int{};
210
1/2
✓ Branch 1 taken 102 times.
✗ Branch 2 not taken.
102 MPI_Scatter(int_buf.data(), 4, MPI_DOUBLE, my_int.data(), 4, MPI_DOUBLE, 0, MPI_COMM_WORLD);
211
212
1/2
✓ Branch 1 taken 102 times.
✗ Branch 2 not taken.
102 double m_l = std::max(1.0, 2.0 * (std::abs(my_int[3] - my_int[2]) / (my_int[1] - my_int[0])));
213 102 double x_n = (0.5 * (my_int[0] + my_int[1])) - ((my_int[3] - my_int[2]) / (2.0 * m_l));
214 102 double y_res = 0.0;
215
1/2
✓ Branch 1 taken 102 times.
✗ Branch 2 not taken.
102 double z_res = compute_z(x_n, y_res);
216
217 102 std::array<double, 3> send_v = {x_n, y_res, z_res};
218
2/6
✓ Branch 1 taken 102 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 102 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
102 std::vector<double> recv_v(static_cast<size_t>(size) * 3);
219
1/2
✓ Branch 1 taken 102 times.
✗ Branch 2 not taken.
102 MPI_Gather(send_v.data(), 3, MPI_DOUBLE, recv_v.data(), 3, MPI_DOUBLE, 0, MPI_COMM_WORLD);
220
221
2/2
✓ Branch 0 taken 51 times.
✓ Branch 1 taken 51 times.
102 if (rank == 0) {
222
2/2
✓ Branch 0 taken 102 times.
✓ Branch 1 taken 51 times.
153 for (int i = 0; i < size; ++i) {
223 102 const size_t idx = static_cast<size_t>(i) * 3;
224
1/4
✓ Branch 1 taken 102 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
102 ManualInsert2D(trials, Trial2D(recv_v[idx + 0], recv_v[idx + 1], recv_v[idx + 2]));
225 }
226 }
227 }
228
229 12 std::array<double, 3> res = {0.0, 0.0, 0.0};
230
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 6 times.
12 if (rank == 0) {
231 6 SyncBestResult(trials, res.data());
232 }
233
1/2
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
12 MPI_Bcast(res.data(), 3, MPI_DOUBLE, 0, MPI_COMM_WORLD);
234
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 6 times.
12 GetOutput() = {res[0], res[1], res[2]};
235 12 return true;
236 }
237
238 12 bool KruglovaA2DMuitMPI::PostProcessingImpl() {
239 12 return true;
240 }
241
242 } // namespace kruglova_a_2d_multistep_par_opt
243