GCC Code Coverage Report


Directory: ./
File: tasks/liulin_y_complex_ccs/all/src/ops_all.cpp
Date: 2026-06-04 20:25:32
Exec Total Coverage
Lines: 121 127 95.3%
Functions: 9 9 100.0%
Branches: 73 124 58.9%

Line Branch Exec Source
1 #include "liulin_y_complex_ccs/all/include/ops_all.hpp"
2
3 #include <mpi.h>
4 #include <omp.h>
5
6 #include <cmath>
7 #include <complex>
8 #include <cstddef>
9 #include <utility>
10 #include <vector>
11
12 #include "liulin_y_complex_ccs/common/include/common.hpp"
13
14 namespace liulin_y_complex_ccs {
15
16 namespace {
17 constexpr double kEpsilon = 1e-15;
18
19 26 std::complex<double> DotProduct(const CCSMatrix &mat_at, int row_idx, const CCSMatrix &mat_b, int col_idx) {
20 std::complex<double> sum(0.0, 0.0);
21 26 int a_ptr = mat_at.col_index[static_cast<size_t>(row_idx)];
22 26 int a_end = mat_at.col_index[static_cast<size_t>(row_idx) + 1];
23 26 int b_ptr = mat_b.col_index[static_cast<size_t>(col_idx)];
24 26 int b_end = mat_b.col_index[static_cast<size_t>(col_idx) + 1];
25
26
2/2
✓ Branch 0 taken 22 times.
✓ Branch 1 taken 26 times.
48 while (a_ptr < a_end && b_ptr < b_end) {
27
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 12 times.
22 int idx_a = mat_at.row_index[static_cast<size_t>(a_ptr)];
28 22 int idx_b = mat_b.row_index[static_cast<size_t>(b_ptr)];
29
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 12 times.
22 if (idx_a == idx_b) {
30 sum += mat_at.values[static_cast<size_t>(a_ptr)] * mat_b.values[static_cast<size_t>(b_ptr)];
31 10 a_ptr++;
32 10 b_ptr++;
33
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 6 times.
12 } else if (idx_a < idx_b) {
34 6 a_ptr++;
35 } else {
36 6 b_ptr++;
37 }
38 }
39 26 return sum;
40 }
41
42 18 void GatherColumnData(int col_idx, int sender, int count, int rank, const std::vector<int> &local_rows,
43 const std::vector<std::complex<double>> &local_vals, CCSMatrix &mat_c) {
44 18 std::vector<double> r_buf(static_cast<size_t>(count));
45
1/4
✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
18 std::vector<double> i_buf(static_cast<size_t>(count));
46
1/4
✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
18 std::vector<int> row_buf(static_cast<size_t>(count));
47
48
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 9 times.
18 if (rank == sender) {
49
1/2
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
9 row_buf = local_rows;
50 9 for (size_t k = 0; std::cmp_less(k, count); ++k) {
51 9 r_buf[k] = local_vals[k].real();
52 9 i_buf[k] = local_vals[k].imag();
53 }
54 }
55
56
1/2
✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
18 MPI_Bcast(row_buf.data(), count, MPI_INT, sender, MPI_COMM_WORLD);
57
1/2
✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
18 MPI_Bcast(r_buf.data(), count, MPI_DOUBLE, sender, MPI_COMM_WORLD);
58
1/2
✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
18 MPI_Bcast(i_buf.data(), count, MPI_DOUBLE, sender, MPI_COMM_WORLD);
59
60 18 auto start_pos = static_cast<size_t>(mat_c.col_index[static_cast<size_t>(col_idx)]);
61 36 for (size_t k = 0; std::cmp_less(k, count); ++k) {
62 18 mat_c.row_index[start_pos + k] = row_buf[k];
63 18 mat_c.values[start_pos + k] = {r_buf[k], i_buf[k]};
64 }
65 18 }
66
67 24 void BroadcastMatrix(CCSMatrix &mat, int root, MPI_Comm comm) {
68 24 MPI_Bcast(&mat.count_rows, 1, MPI_INT, root, comm);
69 24 MPI_Bcast(&mat.count_cols, 1, MPI_INT, root, comm);
70 24 int nnz = static_cast<int>(mat.values.size());
71 24 MPI_Bcast(&nnz, 1, MPI_INT, root, comm);
72
73
1/2
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
24 if (std::cmp_not_equal(mat.col_index.size(), mat.count_cols + 1)) {
74 mat.col_index.resize(static_cast<size_t>(mat.count_cols) + 1);
75 }
76
1/2
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
24 if (std::cmp_not_equal(mat.values.size(), nnz)) {
77 mat.values.resize(static_cast<size_t>(nnz));
78 mat.row_index.resize(static_cast<size_t>(nnz));
79 }
80
81 24 MPI_Bcast(mat.col_index.data(), static_cast<int>(mat.col_index.size()), MPI_INT, root, comm);
82 24 MPI_Bcast(mat.row_index.data(), static_cast<int>(mat.row_index.size()), MPI_INT, root, comm);
83
84
1/2
✓ Branch 2 taken 24 times.
✗ Branch 3 not taken.
24 std::vector<double> real_p(mat.values.size());
85
1/4
✓ Branch 1 taken 24 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
24 std::vector<double> imag_p(mat.values.size());
86 24 int rank = 0;
87
1/2
✓ Branch 1 taken 24 times.
✗ Branch 2 not taken.
24 MPI_Comm_rank(comm, &rank);
88
89
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 12 times.
24 if (rank == root) {
90
2/2
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 12 times.
37 for (size_t i = 0; i < mat.values.size(); ++i) {
91 25 real_p[i] = mat.values[i].real();
92 25 imag_p[i] = mat.values[i].imag();
93 }
94 }
95
1/2
✓ Branch 1 taken 24 times.
✗ Branch 2 not taken.
24 MPI_Bcast(real_p.data(), static_cast<int>(real_p.size()), MPI_DOUBLE, root, comm);
96
1/2
✓ Branch 1 taken 24 times.
✗ Branch 2 not taken.
24 MPI_Bcast(imag_p.data(), static_cast<int>(imag_p.size()), MPI_DOUBLE, root, comm);
97
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 12 times.
24 if (rank != root) {
98
2/2
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 12 times.
37 for (size_t i = 0; i < mat.values.size(); ++i) {
99 25 mat.values[i] = {real_p[i], imag_p[i]};
100 }
101 }
102 24 }
103
104 12 void Transpose(const CCSMatrix &in, CCSMatrix &out) {
105 12 out.count_rows = in.count_cols;
106 12 out.count_cols = in.count_rows;
107 12 out.col_index.assign(static_cast<size_t>(out.count_cols) + 1, 0);
108
2/2
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 12 times.
42 for (int idx_r : in.row_index) {
109 30 out.col_index[static_cast<size_t>(idx_r) + 1]++;
110 }
111
1/2
✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
36 for (size_t i = 0; std::cmp_less(i, out.count_cols); ++i) {
112 24 out.col_index[i + 1] += out.col_index[i];
113 }
114
115 12 std::vector<int> current_pos = out.col_index;
116
1/2
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
12 out.row_index.resize(in.values.size());
117
1/2
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
12 out.values.resize(in.values.size());
118
2/2
✓ Branch 0 taken 26 times.
✓ Branch 1 taken 12 times.
38 for (int idx_j = 0; idx_j < in.count_cols; ++idx_j) {
119
2/2
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 26 times.
56 for (int idx_k = in.col_index[static_cast<size_t>(idx_j)]; idx_k < in.col_index[static_cast<size_t>(idx_j) + 1];
120 ++idx_k) {
121 30 int row = in.row_index[static_cast<size_t>(idx_k)];
122 30 int pos = current_pos[static_cast<size_t>(row)]++;
123 30 out.row_index[static_cast<size_t>(pos)] = idx_j;
124 30 out.values[static_cast<size_t>(pos)] = in.values[static_cast<size_t>(idx_k)];
125 }
126 }
127 12 }
128 } // namespace
129
130
1/2
✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
12 LiulinYComplexCcsAll::LiulinYComplexCcsAll(const InType &in) : BaseTask() {
131 SetTypeOfTask(GetStaticTypeOfTask());
132 GetInput() = in;
133 12 }
134
135 12 bool LiulinYComplexCcsAll::ValidationImpl() {
136 12 int rank = 0;
137 12 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
138
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 6 times.
12 if (rank == 0) {
139 const auto &mat_a = GetInput().first;
140 const auto &mat_b = GetInput().second;
141
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 if (mat_a.count_cols != mat_b.count_rows) {
142 return false;
143 }
144
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 if (mat_a.count_rows <= 0 || mat_a.count_cols <= 0 || mat_b.count_cols <= 0) {
145 return false;
146 }
147
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 if (std::cmp_not_equal(mat_a.col_index.size(), mat_a.count_cols + 1)) {
148 return false;
149 }
150
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (std::cmp_not_equal(mat_b.col_index.size(), mat_b.count_cols + 1)) {
151 return false;
152 }
153 }
154 return true;
155 }
156
157 12 bool LiulinYComplexCcsAll::PreProcessingImpl() {
158 12 return true;
159 }
160
161 12 bool LiulinYComplexCcsAll::RunImpl() {
162 12 int rank = 0;
163 12 int size = 0;
164 12 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
165 12 MPI_Comm_size(MPI_COMM_WORLD, &size);
166
167 12 CCSMatrix mat_a = GetInput().first;
168
1/2
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
12 CCSMatrix mat_b = GetInput().second;
169
170 try {
171
1/2
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
12 BroadcastMatrix(mat_a, 0, MPI_COMM_WORLD);
172
1/2
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
12 BroadcastMatrix(mat_b, 0, MPI_COMM_WORLD);
173 12 CCSMatrix mat_at;
174
1/2
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
12 Transpose(mat_a, mat_at);
175
176
1/2
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
12 std::vector<std::vector<int>> local_rows(static_cast<size_t>(mat_b.count_cols));
177
1/2
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
12 std::vector<std::vector<std::complex<double>>> local_vals(static_cast<size_t>(mat_b.count_cols));
178
1/2
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
12 std::vector<int> local_nnz(static_cast<size_t>(mat_b.count_cols), 0);
179
180 12 #pragma omp parallel for default(none) shared(rank, size, mat_a, mat_b, mat_at, local_rows, local_vals, local_nnz) \
181 schedule(dynamic)
182 for (int idx_j = rank; idx_j < mat_b.count_cols; idx_j += size) {
183 for (int idx_i = 0; idx_i < mat_a.count_rows; ++idx_i) {
184 std::complex<double> res = DotProduct(mat_at, idx_i, mat_b, idx_j);
185 if (std::abs(res.real()) > kEpsilon || std::abs(res.imag()) > kEpsilon) {
186 local_rows[static_cast<size_t>(idx_j)].push_back(idx_i);
187 local_vals[static_cast<size_t>(idx_j)].push_back(res);
188 local_nnz[static_cast<size_t>(idx_j)]++;
189 }
190 }
191 }
192
193
1/4
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
12 std::vector<int> global_nnz(static_cast<size_t>(mat_b.count_cols));
194
1/2
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
12 MPI_Allreduce(local_nnz.data(), global_nnz.data(), mat_b.count_cols, MPI_INT, MPI_SUM, MPI_COMM_WORLD);
195
196 CCSMatrix &mat_res = GetOutput();
197 12 mat_res.count_rows = mat_a.count_rows;
198 12 mat_res.count_cols = mat_b.count_cols;
199
1/4
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
12 mat_res.col_index.assign(static_cast<size_t>(mat_res.count_cols) + 1, 0);
200
1/2
✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
36 for (size_t i = 0; std::cmp_less(i, mat_res.count_cols); ++i) {
201 24 mat_res.col_index[i + 1] = mat_res.col_index[i] + global_nnz[i];
202 }
203
1/2
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
12 mat_res.row_index.resize(static_cast<size_t>(mat_res.col_index.back()));
204
1/2
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
12 mat_res.values.resize(static_cast<size_t>(mat_res.col_index.back()));
205
206
2/2
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 12 times.
36 for (int idx_j = 0; idx_j < mat_b.count_cols; ++idx_j) {
207
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 6 times.
24 int count = global_nnz[static_cast<size_t>(idx_j)];
208
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 6 times.
24 if (count > 0) {
209
1/2
✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
18 GatherColumnData(idx_j, idx_j % size, count, rank, local_rows[static_cast<size_t>(idx_j)],
210 local_vals[static_cast<size_t>(idx_j)], mat_res);
211 }
212 }
213 12 } catch (...) {
214 return false;
215 }
216 12 return true;
217 12 }
218
219 12 bool LiulinYComplexCcsAll::PostProcessingImpl() {
220 12 int rank = 0;
221 12 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
222
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 6 times.
12 if (rank == 0) {
223 const auto &mat_res = GetOutput();
224
2/4
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 6 times.
6 if (mat_res.count_rows <= 0 || mat_res.count_cols <= 0) {
225 return false;
226 }
227 }
228 return true;
229 }
230
231 } // namespace liulin_y_complex_ccs
232