GCC Code Coverage Report


Directory: ./
File: tasks/leonova_a_star/mpi/src/ops_mpi.cpp
Date: 2026-01-10 02:40:41
Exec Total Coverage
Lines: 305 368 82.9%
Functions: 33 34 97.1%
Branches: 231 406 56.9%

Line Branch Exec Source
1 #include "leonova_a_star/mpi/include/ops_mpi.hpp"
2
3 #include <mpi.h>
4
5 #include <algorithm>
6 #include <array>
7 #include <climits>
8 #include <cstddef>
9 #include <cstdint>
10 #include <limits>
11 #include <new>
12 #include <utility>
13 #include <vector>
14
15 #include "leonova_a_star/common/include/common.hpp"
16
17 namespace leonova_a_star {
18
19 namespace {
20
21 constexpr size_t kMaxMatrixSize = 10000;
22 constexpr size_t kMaxVectorSize = 1000000;
23 constexpr int kMaxProcesses = 1024;
24
25 bool CheckMatricesNotEmpty(const std::vector<std::vector<int>> &matrix_a,
26 const std::vector<std::vector<int>> &matrix_b) {
27
8/16
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 12 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 12 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 12 times.
✓ Branch 8 taken 12 times.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✓ Branch 11 taken 12 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 12 times.
✗ Branch 14 not taken.
✓ Branch 15 taken 12 times.
24 return !matrix_a.empty() && !matrix_b.empty() && !matrix_a[0].empty() && !matrix_b[0].empty();
28 }
29
30 15 void FillMatrixBRow(int row_idx, int cols, const std::vector<std::vector<int>> &matrix_b, std::vector<int> &output) {
31
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 15 times.
15 if (static_cast<size_t>(row_idx) >= matrix_b.size()) {
32 output.insert(output.end(), static_cast<size_t>(cols), 0);
33 return;
34 }
35
36 const auto &row = matrix_b[static_cast<size_t>(row_idx)];
37 size_t row_size = row.size();
38
2/2
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 15 times.
45 for (int col_idx = 0; col_idx < cols; ++col_idx) {
39 30 output.push_back(std::cmp_less(col_idx, row_size) ? row[static_cast<size_t>(col_idx)] : 0);
40 }
41 }
42
43 void FillMatrixBFlat(int cols_a_int, int cols_b_int, const std::vector<std::vector<int>> &matrix_b,
44 std::vector<int> &matrix_b_flat) {
45
2/2
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 6 times.
21 for (int index = 0; index < cols_a_int; ++index) {
46 15 FillMatrixBRow(index, cols_b_int, matrix_b, matrix_b_flat);
47 }
48 }
49
50 12 void DistributeMatrixB(int rank, int cols_a_int, int cols_b_int, const std::vector<std::vector<int>> &matrix_b,
51 std::vector<int> &matrix_b_flat) {
52
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 6 times.
12 if (rank == 0) {
53 6 size_t reserve_size = static_cast<size_t>(cols_a_int) * static_cast<size_t>(cols_b_int);
54
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 if (reserve_size <= kMaxVectorSize) {
55 6 matrix_b_flat.reserve(reserve_size);
56 }
57 FillMatrixBFlat(cols_a_int, cols_b_int, matrix_b, matrix_b_flat);
58 } else {
59 6 size_t new_size = static_cast<size_t>(cols_a_int) * static_cast<size_t>(cols_b_int);
60
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 if (new_size <= kMaxVectorSize) {
61 6 matrix_b_flat.resize(new_size);
62 }
63 }
64
65 12 int total_elements = cols_a_int * cols_b_int;
66 // Проверка на переполнение
67
3/6
✓ 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.
12 if (total_elements > 0 && std::cmp_less_equal(total_elements, static_cast<int>(kMaxVectorSize)) &&
68
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 static_cast<size_t>(total_elements) <= matrix_b_flat.size()) {
69 12 MPI_Bcast(matrix_b_flat.data(), total_elements, MPI_INT, 0, MPI_COMM_WORLD);
70 }
71 12 }
72
73 17 bool SafeVectorResize(std::vector<int> &vec, size_t new_size) {
74
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 17 times.
17 if (new_size == 0 || new_size > kMaxVectorSize) {
75 return false;
76 }
77
78 try {
79
1/2
✓ Branch 1 taken 17 times.
✗ Branch 2 not taken.
17 vec.resize(new_size);
80 return true;
81 } catch (const std::bad_alloc &) {
82 return false;
83 }
84 }
85
86 11 bool SafeVectorResize(std::vector<int> &vec, size_t new_size, int value) {
87
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
11 if (new_size == 0 || new_size > kMaxVectorSize) {
88 return false;
89 }
90
91 try {
92 vec.assign(new_size, value);
93 return true;
94 } catch (const std::bad_alloc &) {
95 return false;
96 }
97 }
98
99 12 bool PrepareRowDistribution(int size, int rows_a_int, int cols_a_int, std::vector<int> &rows_per_rank,
100 std::vector<int> &displacements, std::vector<int> &elements_per_rank) {
101
2/4
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
12 if (rows_a_int <= 0 || cols_a_int <= 0 || size <= 0 || size > kMaxProcesses ||
102
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 std::cmp_greater(static_cast<size_t>(rows_a_int), kMaxMatrixSize)) {
103 rows_per_rank.clear();
104 displacements.clear();
105 elements_per_rank.clear();
106 return false;
107 }
108
109 // Проверка на переполнение при умножении
110 12 if (static_cast<size_t>(rows_a_int) > SIZE_MAX / static_cast<size_t>(cols_a_int) ||
111
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 static_cast<size_t>(rows_a_int) * static_cast<size_t>(cols_a_int) > kMaxVectorSize) {
112 rows_per_rank.clear();
113 displacements.clear();
114 elements_per_rank.clear();
115 return false;
116 }
117
118 12 int rows_per_process = rows_a_int / size;
119
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 int extra_rows = rows_a_int % size;
120
121 rows_per_rank.clear();
122 displacements.clear();
123 elements_per_rank.clear();
124
125 12 rows_per_rank.reserve(static_cast<size_t>(size));
126 12 displacements.reserve(static_cast<size_t>(size));
127 12 elements_per_rank.reserve(static_cast<size_t>(size));
128
129
2/2
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 12 times.
36 for (int index = 0; index < size; ++index) {
130 24 int rows = rows_per_process;
131
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 20 times.
24 if (index < extra_rows) {
132 4 rows += 1;
133 }
134 rows_per_rank.push_back(rows);
135 }
136
137 int offset = 0;
138
2/2
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 12 times.
36 for (int index = 0; index < size; ++index) {
139 // Проверка на переполнение
140
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 24 times.
24 if (offset > INT_MAX / cols_a_int) {
141 rows_per_rank.clear();
142 displacements.clear();
143 elements_per_rank.clear();
144 return false;
145 }
146 24 displacements.push_back(offset * cols_a_int);
147 24 offset += rows_per_rank[static_cast<size_t>(index)];
148 }
149
150
2/2
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 12 times.
36 for (int index = 0; index < size; ++index) {
151 24 elements_per_rank.push_back(rows_per_rank[static_cast<size_t>(index)] * cols_a_int);
152 }
153
154 return true;
155 }
156
157
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 void FlattenMatrixA(const std::vector<std::vector<int>> &matrix_a, int cols_a_int, std::vector<int> &matrix_a_flat) {
158 size_t rows = matrix_a.size();
159
160 // Проверка на переполнение перед умножением
161
2/4
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
6 if (static_cast<size_t>(cols_a_int) > 0 && rows > SIZE_MAX / static_cast<size_t>(cols_a_int)) {
162 return;
163 }
164
165 6 size_t reserve_size = rows * static_cast<size_t>(cols_a_int);
166
167
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 if (reserve_size == 0 || reserve_size > kMaxVectorSize) {
168 return;
169 }
170
171 6 matrix_a_flat.reserve(reserve_size);
172
173
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 6 times.
18 for (size_t i = 0; i < rows; ++i) {
174 const auto &row = matrix_a[i];
175
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 size_t row_size = row.size();
176 size_t copy_size = std::min(row_size, static_cast<size_t>(cols_a_int));
177
178
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 if (copy_size > 0) {
179 // Безопасное преобразование с проверкой
180
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 if (copy_size > static_cast<size_t>(std::numeric_limits<int64_t>::max())) {
181 return;
182 }
183 auto copy_offset = static_cast<int64_t>(copy_size);
184
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 if (row.begin() + copy_offset > row.end()) {
185 return;
186 }
187 12 matrix_a_flat.insert(matrix_a_flat.end(), row.begin(), row.begin() + copy_offset);
188 }
189
190
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if (std::cmp_greater(static_cast<size_t>(cols_a_int), row_size)) {
191 size_t padding = static_cast<size_t>(cols_a_int) - row_size;
192 matrix_a_flat.insert(matrix_a_flat.end(), padding, 0);
193 }
194 }
195 }
196
197 11 void ScatterMatrixA(int rank, int cols_a_int, const std::vector<std::vector<int>> &matrix_a,
198 const std::vector<int> &displacements, const std::vector<int> &elements_per_rank,
199 std::vector<int> &local_rows_flat) {
200
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 5 times.
11 if (rank == 0) {
201 6 std::vector<int> matrix_a_flat;
202
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 FlattenMatrixA(matrix_a, cols_a_int, matrix_a_flat);
203
204
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (matrix_a_flat.size() > kMaxVectorSize) {
205 if (!local_rows_flat.empty()) {
206 std::ranges::fill(local_rows_flat, 0);
207 }
208 return;
209 }
210
211
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 MPI_Scatterv(matrix_a_flat.data(), elements_per_rank.data(), displacements.data(), MPI_INT, local_rows_flat.data(),
212 elements_per_rank[static_cast<size_t>(rank)], MPI_INT, 0, MPI_COMM_WORLD);
213 } else {
214 5 MPI_Scatterv(nullptr, elements_per_rank.data(), displacements.data(), MPI_INT, local_rows_flat.data(),
215 5 elements_per_rank[static_cast<size_t>(rank)], MPI_INT, 0, MPI_COMM_WORLD);
216 }
217 }
218
219 30 void MultiplyRowByElement(int value, const std::vector<int> &b_row, int *result_row, int cols) {
220
3/6
✓ Branch 0 taken 30 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 30 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 30 times.
✗ Branch 5 not taken.
30 if (result_row == nullptr || b_row.empty() || cols <= 0) {
221 return;
222 }
223
224 30 size_t b_size = b_row.size();
225
1/2
✓ Branch 0 taken 30 times.
✗ Branch 1 not taken.
30 size_t limit = std::min(b_size, static_cast<size_t>(cols));
226
227 // Проверка, что result_row имеет достаточно места
228
1/2
✓ Branch 0 taken 30 times.
✗ Branch 1 not taken.
30 if (limit == 0) {
229 return;
230 }
231
232
2/2
✓ Branch 0 taken 66 times.
✓ Branch 1 taken 30 times.
96 for (size_t j = 0; j < limit; ++j) {
233 66 result_row[j] += value * b_row[j];
234 }
235 }
236
237 12 void MultiplyRow(const std::vector<int> &row_a, const std::vector<std::vector<int>> &local_b, int *result_row,
238 int cols_a, int cols_b) {
239
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 if (result_row == nullptr || row_a.empty() || local_b.empty() || cols_a <= 0 || cols_b <= 0) {
240 return;
241 }
242
243 size_t row_a_size = row_a.size();
244 size_t local_b_size = local_b.size();
245 size_t limit = std::min(row_a_size, local_b_size);
246 12 limit = std::min(limit, static_cast<size_t>(cols_a));
247
248
2/2
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 12 times.
42 for (size_t k = 0; k < limit; ++k) {
249 // Проверка, что local_b[k] существует
250
1/2
✓ Branch 0 taken 30 times.
✗ Branch 1 not taken.
30 if (k >= local_b.size()) {
251 break;
252 }
253 30 int aik = row_a[k];
254 const auto &b_row = local_b[k];
255 30 MultiplyRowByElement(aik, b_row, result_row, cols_b);
256 }
257 }
258
259
1/2
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
11 void ComputeLocalMultiplication(int local_rows_count, int cols_a_int, int cols_b_int,
260 const std::vector<std::vector<int>> &local_a,
261 const std::vector<std::vector<int>> &local_b, std::vector<int> &local_result_flat) {
262
2/4
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 11 times.
✗ Branch 3 not taken.
11 if (local_result_flat.empty() || cols_b_int <= 0) {
263 return;
264 }
265
266 std::ranges::fill(local_result_flat, 0);
267
268 11 size_t rows = std::min(static_cast<size_t>(local_rows_count), local_a.size());
269 11 auto cols_b = static_cast<size_t>(cols_b_int);
270
271
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 11 times.
23 for (size_t i = 0; i < rows; ++i) {
272 // Проверка, что local_a[i] существует
273
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 if (i >= local_a.size()) {
274 break;
275 }
276
277 // Проверка на переполнение при вычислении offset
278
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 if (i > SIZE_MAX / cols_b) {
279 break;
280 }
281
282
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 size_t offset = i * cols_b;
283
284 // Проверка границ
285
2/4
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
12 if (offset > local_result_flat.size() || local_result_flat.size() - offset < cols_b) {
286 break;
287 }
288
289 12 int *result_row = local_result_flat.data() + offset;
290 12 MultiplyRow(local_a[i], local_b, result_row, cols_a_int, cols_b_int);
291 }
292 }
293
294
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
11 bool PrepareGatherParameters(const std::vector<int> &rows_per_rank, int cols_b_int,
295 std::vector<int> &result_elements_per_rank, std::vector<int> &result_displacements) {
296
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
11 if (rows_per_rank.empty()) {
297 result_elements_per_rank.clear();
298 result_displacements.clear();
299 return true;
300 }
301
302 size_t size = rows_per_rank.size();
303
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
11 if (size > kMaxVectorSize) {
304 result_elements_per_rank.clear();
305 result_displacements.clear();
306 return false;
307 }
308
309 result_elements_per_rank.clear();
310 result_displacements.clear();
311
312 11 result_elements_per_rank.reserve(size);
313 11 result_displacements.reserve(size);
314
315 11 int displacement = 0;
316
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 22 times.
33 for (size_t index = 0; index < size; ++index) {
317 22 int rows = rows_per_rank[index];
318 // Проверка на переполнение
319
4/6
✓ Branch 0 taken 22 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 21 times.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 21 times.
22 if (rows < 0 || cols_b_int < 0 || (rows > 0 && cols_b_int > INT_MAX / rows)) {
320 result_elements_per_rank.clear();
321 result_displacements.clear();
322 return false;
323 }
324
325
1/2
✓ Branch 0 taken 22 times.
✗ Branch 1 not taken.
22 int elements = rows * cols_b_int;
326 result_elements_per_rank.push_back(elements);
327 result_displacements.push_back(displacement);
328
329 // Проверка на переполнение displacement
330
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 22 times.
22 if (displacement > INT_MAX - elements) {
331 result_elements_per_rank.clear();
332 result_displacements.clear();
333 return false;
334 }
335 22 displacement += elements;
336 }
337
338 return true;
339 }
340
341 11 void GatherResults(int local_rows_count, int cols_b_int, const std::vector<int> &rows_per_rank,
342 const std::vector<int> &local_result_flat, std::vector<int> &full_result_flat) {
343 11 std::vector<int> result_elements_per_rank;
344 11 std::vector<int> result_displacements;
345
346
2/4
✓ Branch 1 taken 11 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 11 times.
✗ Branch 4 not taken.
11 if (!PrepareGatherParameters(rows_per_rank, cols_b_int, result_elements_per_rank, result_displacements)) {
347 return;
348 }
349
350
2/4
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 11 times.
✗ Branch 3 not taken.
11 if (result_elements_per_rank.empty() || result_displacements.empty()) {
351 return;
352 }
353
354 // Проверка на переполнение
355
2/4
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 11 times.
✗ Branch 3 not taken.
11 if (local_rows_count > 0 && cols_b_int > 0 && local_rows_count <= INT_MAX / cols_b_int) {
356 11 int send_count = local_rows_count * cols_b_int;
357
1/2
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
11 if (send_count > 0 && static_cast<size_t>(send_count) <= local_result_flat.size()) {
358
1/2
✓ Branch 1 taken 11 times.
✗ Branch 2 not taken.
11 MPI_Gatherv(local_result_flat.data(), send_count, MPI_INT, full_result_flat.data(),
359 result_elements_per_rank.data(), result_displacements.data(), MPI_INT, 0, MPI_COMM_WORLD);
360 }
361 }
362 }
363
364 6 std::vector<std::vector<int>> ConvertFlatToMatrix(const std::vector<int> &flat_data, int rows, int cols) {
365
2/4
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 6 times.
6 if (rows <= 0 || cols <= 0 || flat_data.empty()) {
366 return {};
367 }
368
369 // Проверка на переполнение
370
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (rows > INT_MAX / cols) {
371 return {};
372 }
373
374 // Проверка на переполнение size_t
375 6 if (static_cast<size_t>(rows) > SIZE_MAX / static_cast<size_t>(cols)) {
376 return {};
377 }
378
379
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 size_t expected_size = static_cast<size_t>(rows) * static_cast<size_t>(cols);
380
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (flat_data.size() < expected_size) {
381 return {};
382 }
383
384 6 std::vector<std::vector<int>> result;
385 try {
386
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 result.resize(static_cast<size_t>(rows));
387
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 6 times.
18 for (auto &row : result) {
388
1/2
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
12 row.resize(static_cast<size_t>(cols), 0);
389 }
390 } catch (const std::bad_alloc &) {
391 return {};
392 }
393
394
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 6 times.
18 for (int i = 0; i < rows; ++i) {
395 // Проверка на переполнение при вычислении индекса
396 size_t row_offset = 0;
397 12 if (static_cast<size_t>(i) > SIZE_MAX / static_cast<size_t>(cols)) {
398 return {};
399 }
400 12 row_offset = static_cast<size_t>(i) * static_cast<size_t>(cols);
401
402
2/2
✓ Branch 0 taken 26 times.
✓ Branch 1 taken 12 times.
38 for (int j = 0; j < cols; ++j) {
403
1/2
✓ Branch 0 taken 26 times.
✗ Branch 1 not taken.
26 size_t idx = row_offset + static_cast<size_t>(j);
404
1/2
✓ Branch 0 taken 26 times.
✗ Branch 1 not taken.
26 if (idx < flat_data.size()) {
405 26 result[static_cast<size_t>(i)][static_cast<size_t>(j)] = flat_data[idx];
406 }
407 }
408 }
409
410 return result;
411 6 }
412
413 12 std::pair<bool, std::array<int, 3>> ValidateAndGetDimensions(int rank, int size,
414 const std::vector<std::vector<int>> &matrix_a,
415 const std::vector<std::vector<int>> &matrix_b) {
416
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if (size <= 0 || size > kMaxProcesses) {
417 return {false, {}};
418 }
419
420 if (!CheckMatricesNotEmpty(matrix_a, matrix_b)) {
421 return {false, {}};
422 }
423
424 size_t rows_a = matrix_a.size();
425 size_t cols_a = matrix_a[0].size();
426 size_t cols_b = matrix_b[0].size();
427
428
2/4
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 12 times.
12 if (rows_a > kMaxMatrixSize || cols_a > kMaxMatrixSize || cols_b > kMaxMatrixSize) {
429 return {false, {}};
430 }
431
432 12 std::array<int, 3> dims{0, 0, 0};
433
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 6 times.
12 if (rank == 0) {
434 6 dims[0] = static_cast<int>(rows_a);
435 6 dims[1] = static_cast<int>(cols_a);
436 6 dims[2] = static_cast<int>(cols_b);
437 }
438
439 12 MPI_Bcast(dims.data(), 3, MPI_INT, 0, MPI_COMM_WORLD);
440 12 return {true, dims};
441 }
442
443 12 bool ValidateDimensions(int rows_a_int, int cols_a_int, int cols_b_int) {
444
2/4
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
12 if (rows_a_int <= 0 || cols_a_int <= 0 || cols_b_int <= 0) {
445 return false;
446 }
447
448 24 if (std::cmp_greater(static_cast<size_t>(rows_a_int), kMaxMatrixSize) ||
449
2/4
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
12 std::cmp_greater(static_cast<size_t>(cols_a_int), kMaxMatrixSize) ||
450
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 std::cmp_greater(static_cast<size_t>(cols_b_int), kMaxMatrixSize)) {
451 return false;
452 }
453
454 // Проверка на возможное переполнение при умножении
455 if (static_cast<size_t>(rows_a_int) > SIZE_MAX / static_cast<size_t>(cols_a_int) ||
456 static_cast<size_t>(cols_a_int) > SIZE_MAX / static_cast<size_t>(cols_b_int) ||
457 static_cast<size_t>(rows_a_int) > SIZE_MAX / static_cast<size_t>(cols_b_int)) {
458 return false;
459 }
460
461
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 if (static_cast<size_t>(rows_a_int) * static_cast<size_t>(cols_a_int) > kMaxVectorSize ||
462
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 static_cast<size_t>(cols_a_int) * static_cast<size_t>(cols_b_int) > kMaxVectorSize ||
463
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 static_cast<size_t>(rows_a_int) * static_cast<size_t>(cols_b_int) > kMaxVectorSize) {
464 return false;
465 }
466
467 return true;
468 }
469
470 12 bool PrepareLocalData(int rank, int cols_a_int, int cols_b_int, const std::vector<std::vector<int>> &matrix_b,
471 std::vector<int> &matrix_b_flat, const std::vector<int> &elements_per_rank,
472 std::vector<int> &local_rows_flat) {
473 12 DistributeMatrixB(rank, cols_a_int, cols_b_int, matrix_b, matrix_b_flat);
474
475
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 auto rank_idx = static_cast<size_t>(rank);
476
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if (rank_idx >= elements_per_rank.size()) {
477 return false;
478 }
479
480 12 int elements = elements_per_rank[rank_idx];
481
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 11 times.
12 if (elements <= 0) {
482 return false;
483 }
484
485 try {
486
1/2
✓ Branch 1 taken 11 times.
✗ Branch 2 not taken.
11 local_rows_flat.reserve(static_cast<size_t>(elements));
487 } catch (const std::bad_alloc &) {
488 return false;
489 }
490
491 11 return SafeVectorResize(local_rows_flat, static_cast<size_t>(elements));
492 }
493
494 // Вспомогательная функция для заполнения матрицы из плоского массива
495 22 bool FillMatrixFromFlat(std::vector<std::vector<int>> &matrix, int rows, int cols, const std::vector<int> &flat_data,
496 size_t start_idx) {
497
3/6
✓ Branch 0 taken 22 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 22 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 22 times.
22 if (rows <= 0 || cols <= 0 || matrix.empty() || flat_data.empty()) {
498 return false;
499 }
500
501 // Проверка на переполнение при вычислении индексов
502 22 if (static_cast<size_t>(rows) > SIZE_MAX / static_cast<size_t>(cols)) {
503 return false;
504 }
505
506
2/2
✓ Branch 0 taken 39 times.
✓ Branch 1 taken 22 times.
61 for (int i = 0; i < rows; ++i) {
507 // Проверка на переполнение
508 39 if (static_cast<size_t>(i) > SIZE_MAX / static_cast<size_t>(cols)) {
509 return false;
510 }
511
512 39 size_t row_offset = static_cast<size_t>(i) * static_cast<size_t>(cols);
513 size_t base_idx = 0;
514
515 // Проверка на переполнение при сложении
516
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 39 times.
39 if (start_idx > SIZE_MAX - row_offset) {
517 return false;
518 }
519
520 39 base_idx = start_idx + row_offset;
521
522
2/2
✓ Branch 0 taken 87 times.
✓ Branch 1 taken 39 times.
126 for (int j = 0; j < cols; ++j) {
523
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 87 times.
87 size_t idx = base_idx + static_cast<size_t>(j);
524
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 87 times.
87 if (idx >= flat_data.size()) {
525 return false;
526 }
527 87 matrix[static_cast<size_t>(i)][static_cast<size_t>(j)] = flat_data[idx];
528 }
529 }
530
531 return true;
532 }
533
534 // Разделенная на две функции для уменьшения cognitive complexity
535 11 std::vector<std::vector<int>> CreateLocalMatrixA(int local_rows_count, int cols_a_int,
536 const std::vector<int> &local_rows_flat) {
537
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
11 if (cols_a_int <= 0 || local_rows_count <= 0) {
538 return {};
539 }
540
541 // Проверка на переполнение
542
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
11 if (cols_a_int > 0 && local_rows_count > INT_MAX / cols_a_int) {
543 return {};
544 }
545
546 // Проверка на переполнение size_t
547 11 if (static_cast<size_t>(local_rows_count) > SIZE_MAX / static_cast<size_t>(cols_a_int)) {
548 return {};
549 }
550
551 11 std::vector<std::vector<int>> local_a;
552 try {
553
1/2
✓ Branch 1 taken 11 times.
✗ Branch 2 not taken.
11 local_a.resize(static_cast<size_t>(local_rows_count));
554
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 11 times.
23 for (auto &row : local_a) {
555
1/2
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
12 row.resize(static_cast<size_t>(cols_a_int), 0);
556 }
557 } catch (const std::bad_alloc &) {
558 return {};
559 }
560
561
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 11 times.
11 if (!FillMatrixFromFlat(local_a, local_rows_count, cols_a_int, local_rows_flat, 0)) {
562 return {};
563 }
564
565 return local_a;
566 11 }
567
568 11 std::vector<std::vector<int>> CreateLocalMatrixB(int cols_a_int, int cols_b_int,
569 const std::vector<int> &matrix_b_flat) {
570
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
11 if (cols_a_int <= 0 || cols_b_int <= 0) {
571 return {};
572 }
573
574 // Проверка на переполнение
575
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
11 if (cols_b_int > 0 && cols_a_int > INT_MAX / cols_b_int) {
576 return {};
577 }
578
579 // Проверка на переполнение size_t
580 11 if (static_cast<size_t>(cols_a_int) > SIZE_MAX / static_cast<size_t>(cols_b_int)) {
581 return {};
582 }
583
584 11 std::vector<std::vector<int>> local_b;
585 try {
586
1/2
✓ Branch 1 taken 11 times.
✗ Branch 2 not taken.
11 local_b.resize(static_cast<size_t>(cols_a_int));
587
2/2
✓ Branch 0 taken 27 times.
✓ Branch 1 taken 11 times.
38 for (auto &row : local_b) {
588
1/2
✓ Branch 1 taken 27 times.
✗ Branch 2 not taken.
27 row.resize(static_cast<size_t>(cols_b_int), 0);
589 }
590 } catch (const std::bad_alloc &) {
591 return {};
592 }
593
594
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 11 times.
11 if (!FillMatrixFromFlat(local_b, cols_a_int, cols_b_int, matrix_b_flat, 0)) {
595 return {};
596 }
597
598 return local_b;
599 11 }
600
601 // Основная функция теперь просто объединяет результаты
602 11 std::pair<std::vector<std::vector<int>>, std::vector<std::vector<int>>> CreateLocalMatrices(
603 int local_rows_count, int cols_a_int, int cols_b_int, const std::vector<int> &local_rows_flat,
604 const std::vector<int> &matrix_b_flat) {
605 11 auto local_a = CreateLocalMatrixA(local_rows_count, cols_a_int, local_rows_flat);
606
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
11 if (local_a.empty()) {
607 return {{}, {}};
608 }
609
610
1/2
✓ Branch 1 taken 11 times.
✗ Branch 2 not taken.
11 auto local_b = CreateLocalMatrixB(cols_a_int, cols_b_int, matrix_b_flat);
611
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
11 if (local_b.empty()) {
612 return {{}, {}};
613 }
614
615 return {std::move(local_a), std::move(local_b)};
616 11 }
617
618 11 std::vector<int> ComputeLocalResult(int local_rows_count, int cols_a_int, int cols_b_int,
619 const std::vector<std::vector<int>> &local_a,
620 const std::vector<std::vector<int>> &local_b) {
621 11 std::vector<int> local_result_flat;
622
623 // Проверка на переполнение
624
2/4
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 11 times.
11 if (local_rows_count > 0 && cols_b_int > 0 && local_rows_count > INT_MAX / cols_b_int) {
625 return {};
626 }
627
628 // Проверка на переполнение size_t
629
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
11 if (static_cast<size_t>(local_rows_count) > SIZE_MAX / static_cast<size_t>(cols_b_int)) {
630 return {};
631 }
632
633 11 size_t local_result_size = static_cast<size_t>(local_rows_count) * static_cast<size_t>(cols_b_int);
634
635
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
11 if (local_result_size == 0 || local_result_size > kMaxVectorSize) {
636 return {};
637 }
638
639
2/4
✓ Branch 1 taken 11 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 11 times.
11 if (!SafeVectorResize(local_result_flat, local_result_size, 0)) {
640 return {};
641 }
642
643 11 ComputeLocalMultiplication(local_rows_count, cols_a_int, cols_b_int, local_a, local_b, local_result_flat);
644 return local_result_flat;
645 }
646
647 } // namespace
648
649
1/2
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
12 LeonovaAStarMPI::LeonovaAStarMPI(const InType &in) {
650 SetTypeOfTask(GetStaticTypeOfTask());
651 GetInput() = in;
652 12 }
653
654
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 bool LeonovaAStarMPI::ValidateMatricesOnMaster() {
655 const auto &matrix_a = std::get<0>(GetInput());
656 const auto &matrix_b = std::get<1>(GetInput());
657
658 if (!CheckMatricesNotEmpty(matrix_a, matrix_b)) {
659 return false;
660 }
661
662
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 12 times.
12 if (matrix_a.size() > kMaxMatrixSize || matrix_b.size() > kMaxMatrixSize) {
663 return false;
664 }
665
666 size_t rows_a = matrix_a.size();
667 size_t cols_a = matrix_a[0].size();
668
669
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 12 times.
24 for (size_t index = 1; index < rows_a; ++index) {
670
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if (index >= matrix_a.size() || matrix_a[index].size() != cols_a) {
671 return false;
672 }
673 }
674
675 size_t rows_b = matrix_b.size();
676 size_t cols_b = matrix_b[0].size();
677
678
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 12 times.
30 for (size_t index = 1; index < rows_b; ++index) {
679
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
18 if (index >= matrix_b.size() || matrix_b[index].size() != cols_b) {
680 return false;
681 }
682 }
683
684 12 return cols_a == rows_b;
685 }
686
687 24 bool LeonovaAStarMPI::ValidationImpl() {
688 24 int rank = 0;
689 24 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
690
691 bool is_valid_local = true;
692
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 12 times.
24 if (rank == 0) {
693 12 is_valid_local = ValidateMatricesOnMaster();
694 }
695
696
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 int is_valid_int = is_valid_local ? 1 : 0;
697 24 MPI_Bcast(&is_valid_int, 1, MPI_INT, 0, MPI_COMM_WORLD);
698 24 return (is_valid_int == 1);
699 }
700
701 12 bool LeonovaAStarMPI::PreProcessingImpl() {
702 12 return true;
703 }
704
705 12 std::vector<std::vector<int>> LeonovaAStarMPI::MultiplyMatricesMpi(const std::vector<std::vector<int>> &matrix_a,
706 const std::vector<std::vector<int>> &matrix_b) {
707 12 int rank = 0;
708 12 int size = 0;
709 12 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
710 12 MPI_Comm_size(MPI_COMM_WORLD, &size);
711
712 12 auto [valid, dims] = ValidateAndGetDimensions(rank, size, matrix_a, matrix_b);
713
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if (!valid) {
714 return {};
715 }
716
717 12 int rows_a_int = dims[0];
718 12 int cols_a_int = dims[1];
719 12 int cols_b_int = dims[2];
720
721
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if (!::leonova_a_star::ValidateDimensions(rows_a_int, cols_a_int, cols_b_int)) {
722 return {};
723 }
724
725 12 std::vector<int> rows_per_rank;
726 12 std::vector<int> displacements;
727 12 std::vector<int> elements_per_rank;
728
2/4
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 12 times.
12 if (!PrepareRowDistribution(size, rows_a_int, cols_a_int, rows_per_rank, displacements, elements_per_rank)) {
729 return {};
730 }
731
732
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if (rows_per_rank.empty()) {
733 return {};
734 }
735
736
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 int local_rows_count = rows_per_rank[static_cast<size_t>(rank)];
737
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if (local_rows_count < 0) {
738 return {};
739 }
740
741 12 std::vector<int> matrix_b_flat;
742 12 std::vector<int> local_rows_flat;
743
3/4
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 11 times.
12 if (!PrepareLocalData(rank, cols_a_int, cols_b_int, matrix_b, matrix_b_flat, elements_per_rank, local_rows_flat)) {
744 1 return {};
745 }
746
747
1/2
✓ Branch 1 taken 11 times.
✗ Branch 2 not taken.
11 ScatterMatrixA(rank, cols_a_int, matrix_a, displacements, elements_per_rank, local_rows_flat);
748 auto [local_a, local_b] =
749
1/2
✓ Branch 1 taken 11 times.
✗ Branch 2 not taken.
11 CreateLocalMatrices(local_rows_count, cols_a_int, cols_b_int, local_rows_flat, matrix_b_flat);
750
2/4
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 11 times.
11 if (local_a.empty() || local_b.empty()) {
751 return {};
752 }
753
754
1/2
✓ Branch 1 taken 11 times.
✗ Branch 2 not taken.
11 std::vector<int> local_result_flat = ComputeLocalResult(local_rows_count, cols_a_int, cols_b_int, local_a, local_b);
755
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
11 if (local_result_flat.empty()) {
756 return {};
757 }
758
759 11 std::vector<int> full_result_flat;
760
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 5 times.
11 if (rank == 0) {
761 // Проверка на переполнение size_t
762
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (static_cast<size_t>(rows_a_int) > SIZE_MAX / static_cast<size_t>(cols_b_int)) {
763 return {};
764 }
765
766 6 size_t full_result_size = static_cast<size_t>(rows_a_int) * static_cast<size_t>(cols_b_int);
767
2/4
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 6 times.
6 if (!SafeVectorResize(full_result_flat, full_result_size)) {
768 return {};
769 }
770 }
771
772
1/2
✓ Branch 1 taken 11 times.
✗ Branch 2 not taken.
11 GatherResults(local_rows_count, cols_b_int, rows_per_rank, local_result_flat, full_result_flat);
773
774
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 5 times.
11 if (rank == 0) {
775
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 return ConvertFlatToMatrix(full_result_flat, rows_a_int, cols_b_int);
776 }
777
778 5 return {};
779 }
780
781 12 bool LeonovaAStarMPI::ResizeOutputMatrix(int rows, int cols) {
782
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if (rows < 0 || cols < 0) {
783 GetOutput().clear();
784 return false;
785 }
786
787
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 if (std::cmp_greater(static_cast<size_t>(rows), kMaxMatrixSize) ||
788
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 std::cmp_greater(static_cast<size_t>(cols), kMaxMatrixSize)) {
789 GetOutput().clear();
790 return false;
791 }
792
793 try {
794
1/2
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
12 GetOutput().resize(static_cast<size_t>(rows));
795
2/2
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 12 times.
36 for (auto &row : GetOutput()) {
796
1/2
✓ Branch 1 taken 24 times.
✗ Branch 2 not taken.
24 row.resize(static_cast<size_t>(cols), 0);
797 }
798 return true;
799 } catch (const std::bad_alloc &) {
800 GetOutput().clear();
801 return false;
802 }
803 }
804
805 12 std::pair<int, int> LeonovaAStarMPI::GetResultDimensions(int rank) {
806 12 int rows = 0;
807 12 int cols = 0;
808
809
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 6 times.
12 if (rank == 0) {
810 6 rows = static_cast<int>(GetOutput().size());
811
2/4
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
6 if (rows > 0 && !GetOutput().empty()) {
812 6 cols = static_cast<int>(GetOutput()[0].size());
813 }
814 }
815
816 12 MPI_Bcast(&rows, 1, MPI_INT, 0, MPI_COMM_WORLD);
817 12 MPI_Bcast(&cols, 1, MPI_INT, 0, MPI_COMM_WORLD);
818
819 12 return {rows, cols};
820 }
821
822 bool LeonovaAStarMPI::ValidateDimensions(int rows, int cols) {
823 12 return rows >= 0 && cols >= 0;
824 }
825
826 6 void LeonovaAStarMPI::BroadcastFromMaster(int rows, int cols) {
827
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 6 times.
18 for (int i = 0; i < rows; ++i) {
828
3/6
✓ 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.
12 if (static_cast<size_t>(i) < GetOutput().size() && !GetOutput()[static_cast<size_t>(i)].empty() && cols > 0) {
829 12 MPI_Bcast(GetOutput()[static_cast<size_t>(i)].data(), cols, MPI_INT, 0, MPI_COMM_WORLD);
830 }
831 }
832 6 }
833
834 6 void LeonovaAStarMPI::ReceiveFromMaster(int rows, int cols) {
835 6 GetOutput().resize(static_cast<size_t>(rows));
836
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 6 times.
18 for (auto &row : GetOutput()) {
837 12 row.resize(static_cast<size_t>(cols));
838 }
839
840
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 6 times.
18 for (int i = 0; i < rows; ++i) {
841
2/4
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
12 if (static_cast<size_t>(i) < GetOutput().size() && cols > 0) {
842 12 MPI_Bcast(GetOutput()[static_cast<size_t>(i)].data(), cols, MPI_INT, 0, MPI_COMM_WORLD);
843 }
844 }
845 6 }
846
847 12 void LeonovaAStarMPI::BroadcastResult(int rank) {
848 12 auto [result_rows, result_cols] = GetResultDimensions(rank);
849
850
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if (!ValidateDimensions(result_rows, result_cols)) {
851 GetOutput().clear();
852 return;
853 }
854
855
1/2
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
12 if (!ResizeOutputMatrix(result_rows, result_cols)) {
856 return;
857 }
858
859
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 6 times.
12 if (rank == 0) {
860 6 BroadcastFromMaster(result_rows, result_cols);
861 } else {
862 6 ReceiveFromMaster(result_rows, result_cols);
863 }
864 }
865
866 12 bool LeonovaAStarMPI::RunImpl() {
867
1/2
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
12 if (!ValidationImpl()) {
868 return false;
869 }
870
871 12 int rank = 0;
872 12 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
873
874 const auto &matrix_a = std::get<0>(GetInput());
875 const auto &matrix_b = std::get<1>(GetInput());
876
877 12 std::vector<std::vector<int>> result = MultiplyMatricesMpi(matrix_a, matrix_b);
878
879
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 6 times.
12 if (rank == 0) {
880 6 GetOutput() = std::move(result);
881 } else {
882 GetOutput().clear();
883 }
884
885
1/2
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
12 BroadcastResult(rank);
886 return true;
887 12 }
888
889 12 bool LeonovaAStarMPI::PostProcessingImpl() {
890 12 return true;
891 }
892
893 } // namespace leonova_a_star
894