| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | #include "gauss_jordan/seq/include/ops_seq.hpp" | ||
| 2 | |||
| 3 | #include <algorithm> | ||
| 4 | #include <cmath> | ||
| 5 | #include <cstddef> | ||
| 6 | #include <vector> | ||
| 7 | |||
| 8 | #include "gauss_jordan/common/include/common.hpp" | ||
| 9 | |||
| 10 | namespace gauss_jordan { | ||
| 11 | |||
| 12 | namespace { | ||
| 13 | constexpr double kEpsilon = 1e-12; | ||
| 14 | |||
| 15 | void ExchangeRows(std::vector<std::vector<double>> &augmented_matrix, int first_row, int second_row, int columns) { | ||
| 16 | if (first_row == second_row) { | ||
| 17 | return; | ||
| 18 | } | ||
| 19 | |||
| 20 |
2/2✓ Branch 0 taken 176 times.
✓ Branch 1 taken 56 times.
|
232 | for (int col_idx = 0; col_idx < columns; ++col_idx) { |
| 21 | 176 | std::swap(augmented_matrix[first_row][col_idx], augmented_matrix[second_row][col_idx]); | |
| 22 | } | ||
| 23 | } | ||
| 24 | |||
| 25 | inline bool IsNumericallyZero(double value) { | ||
| 26 |
13/14✓ Branch 0 taken 64 times.
✓ Branch 1 taken 288 times.
✓ Branch 2 taken 64 times.
✓ Branch 3 taken 224 times.
✓ Branch 4 taken 64 times.
✓ Branch 5 taken 160 times.
✓ Branch 6 taken 64 times.
✓ Branch 7 taken 96 times.
✓ Branch 8 taken 80 times.
✓ Branch 9 taken 160 times.
✓ Branch 10 taken 208 times.
✓ Branch 11 taken 208 times.
✓ Branch 12 taken 240 times.
✗ Branch 13 not taken.
|
1248 | return std::fabs(value) < kEpsilon; |
| 27 | } | ||
| 28 | |||
| 29 | 496 | void EliminateFromRow(std::vector<std::vector<double>> &augmented_matrix, int target_row, int source_row, | |
| 30 | double elimination_coefficient, int columns) { | ||
| 31 |
1/2✓ Branch 0 taken 496 times.
✗ Branch 1 not taken.
|
496 | if (IsNumericallyZero(elimination_coefficient)) { |
| 32 | return; | ||
| 33 | } | ||
| 34 | |||
| 35 |
2/2✓ Branch 0 taken 3224 times.
✓ Branch 1 taken 496 times.
|
3720 | for (int col_idx = 0; col_idx < columns; ++col_idx) { |
| 36 | 3224 | augmented_matrix[target_row][col_idx] -= elimination_coefficient * augmented_matrix[source_row][col_idx]; | |
| 37 | } | ||
| 38 | } | ||
| 39 | |||
| 40 | void NormalizeRow(std::vector<std::vector<double>> &augmented_matrix, int row_index, double normalizer, int columns) { | ||
| 41 |
1/2✓ Branch 0 taken 392 times.
✗ Branch 1 not taken.
|
392 | if (IsNumericallyZero(normalizer)) { |
| 42 | return; | ||
| 43 | } | ||
| 44 | |||
| 45 |
2/2✓ Branch 0 taken 1920 times.
✓ Branch 1 taken 392 times.
|
2312 | for (int col_idx = 0; col_idx < columns; ++col_idx) { |
| 46 | 1920 | augmented_matrix[row_index][col_idx] /= normalizer; | |
| 47 | } | ||
| 48 | } | ||
| 49 | |||
| 50 | // Разбиваем сложную функцию на более простые | ||
| 51 | int FindPivotRow(const std::vector<std::vector<double>> &augmented_matrix, int current_row, int current_col, | ||
| 52 | int equations_count) { | ||
| 53 | int pivot_row = current_row; | ||
| 54 | 392 | double max_val = std::abs(augmented_matrix[current_row][current_col]); | |
| 55 | |||
| 56 |
2/2✓ Branch 0 taken 568 times.
✓ Branch 1 taken 392 times.
|
960 | for (int i = current_row + 1; i < equations_count; i++) { |
| 57 |
2/2✓ Branch 0 taken 64 times.
✓ Branch 1 taken 504 times.
|
568 | double val = std::abs(augmented_matrix[i][current_col]); |
| 58 |
2/2✓ Branch 0 taken 64 times.
✓ Branch 1 taken 504 times.
|
568 | if (val > max_val) { |
| 59 | max_val = val; | ||
| 60 | pivot_row = i; | ||
| 61 | } | ||
| 62 | } | ||
| 63 | |||
| 64 | return pivot_row; | ||
| 65 | } | ||
| 66 | |||
| 67 | bool ShouldSkipColumn(double max_val) { | ||
| 68 | return IsNumericallyZero(max_val); | ||
| 69 | } | ||
| 70 | |||
| 71 | 392 | void ProcessPivotRow(std::vector<std::vector<double>> &augmented_matrix, int current_row, int current_col, | |
| 72 | int pivot_row, int augmented_columns) { | ||
| 73 |
2/2✓ Branch 0 taken 56 times.
✓ Branch 1 taken 336 times.
|
392 | if (pivot_row != current_row) { |
| 74 | ExchangeRows(augmented_matrix, current_row, pivot_row, augmented_columns); | ||
| 75 | } | ||
| 76 | |||
| 77 |
1/2✓ Branch 0 taken 392 times.
✗ Branch 1 not taken.
|
392 | double pivot_value = augmented_matrix[current_row][current_col]; |
| 78 | NormalizeRow(augmented_matrix, current_row, pivot_value, augmented_columns); | ||
| 79 | 392 | } | |
| 80 | |||
| 81 | 392 | void EliminateFromOtherRows(std::vector<std::vector<double>> &augmented_matrix, int current_row, int current_col, | |
| 82 | int equations_count, int augmented_columns) { | ||
| 83 |
2/2✓ Branch 0 taken 1528 times.
✓ Branch 1 taken 392 times.
|
1920 | for (int row_idx = 0; row_idx < equations_count; row_idx++) { |
| 84 |
2/2✓ Branch 0 taken 392 times.
✓ Branch 1 taken 1136 times.
|
1528 | if (row_idx == current_row) { |
| 85 | 392 | continue; | |
| 86 | } | ||
| 87 | |||
| 88 |
2/2✓ Branch 0 taken 496 times.
✓ Branch 1 taken 640 times.
|
1136 | double coefficient = augmented_matrix[row_idx][current_col]; |
| 89 |
2/2✓ Branch 0 taken 496 times.
✓ Branch 1 taken 640 times.
|
1136 | if (!IsNumericallyZero(coefficient)) { |
| 90 | 496 | EliminateFromRow(augmented_matrix, row_idx, current_row, coefficient, augmented_columns); | |
| 91 | } | ||
| 92 | } | ||
| 93 | 392 | } | |
| 94 | |||
| 95 | // Упрощенная основная функция с меньшей когнитивной сложностью | ||
| 96 | 128 | void TransformToReducedRowEchelonForm(std::vector<std::vector<double>> &augmented_matrix, int equations_count, | |
| 97 | int augmented_columns) { | ||
| 98 | int current_row = 0; | ||
| 99 | |||
| 100 |
3/4✓ Branch 0 taken 392 times.
✓ Branch 1 taken 128 times.
✓ Branch 2 taken 392 times.
✗ Branch 3 not taken.
|
520 | for (int current_col = 0; current_col < augmented_columns - 1 && current_row < equations_count; current_col++) { |
| 101 | int pivot_row = FindPivotRow(augmented_matrix, current_row, current_col, equations_count); | ||
| 102 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 392 times.
|
392 | double max_val = std::abs(augmented_matrix[pivot_row][current_col]); |
| 103 | |||
| 104 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 392 times.
|
392 | if (ShouldSkipColumn(max_val)) { |
| 105 | ✗ | continue; | |
| 106 | } | ||
| 107 | |||
| 108 | 392 | ProcessPivotRow(augmented_matrix, current_row, current_col, pivot_row, augmented_columns); | |
| 109 | 392 | EliminateFromOtherRows(augmented_matrix, current_row, current_col, equations_count, augmented_columns); | |
| 110 | |||
| 111 | current_row++; | ||
| 112 | } | ||
| 113 | 128 | } | |
| 114 | |||
| 115 | 784 | bool IsZeroRow(const std::vector<double> &row, int columns_minus_one) { | |
| 116 | return std::all_of(row.begin(), row.begin() + columns_minus_one, | ||
| 117 | 784 | [](double element) { return IsNumericallyZero(element); }); | |
| 118 | } | ||
| 119 | |||
| 120 | 128 | bool HasInconsistentEquation(const std::vector<std::vector<double>> &augmented_matrix, int equations_count, | |
| 121 | int augmented_columns) { | ||
| 122 |
2/2✓ Branch 0 taken 392 times.
✓ Branch 1 taken 128 times.
|
520 | for (int row_idx = 0; row_idx < equations_count; ++row_idx) { |
| 123 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 392 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
392 | if (IsZeroRow(augmented_matrix[row_idx], augmented_columns - 1) && |
| 124 | ✗ | !IsNumericallyZero(augmented_matrix[row_idx][augmented_columns - 1])) { | |
| 125 | return true; | ||
| 126 | } | ||
| 127 | } | ||
| 128 | return false; | ||
| 129 | } | ||
| 130 | |||
| 131 | 128 | int ComputeMatrixRank(const std::vector<std::vector<double>> &augmented_matrix, int equations_count, | |
| 132 | int augmented_columns) { | ||
| 133 | int rank = 0; | ||
| 134 |
2/2✓ Branch 0 taken 392 times.
✓ Branch 1 taken 128 times.
|
520 | for (int row_idx = 0; row_idx < equations_count; ++row_idx) { |
| 135 |
1/2✓ Branch 0 taken 392 times.
✗ Branch 1 not taken.
|
392 | if (!IsZeroRow(augmented_matrix[row_idx], augmented_columns - 1)) { |
| 136 | 392 | ++rank; | |
| 137 | } | ||
| 138 | } | ||
| 139 | 128 | return rank; | |
| 140 | } | ||
| 141 | |||
| 142 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 128 times.
|
128 | bool ValidateMatrixDimensions(const std::vector<std::vector<double>> &matrix) { |
| 143 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 128 times.
|
128 | if (matrix.empty()) { |
| 144 | return false; | ||
| 145 | } | ||
| 146 | |||
| 147 | size_t expected_cols = matrix[0].size(); | ||
| 148 |
2/2✓ Branch 0 taken 264 times.
✓ Branch 1 taken 128 times.
|
392 | for (size_t i = 1; i < matrix.size(); ++i) { |
| 149 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 264 times.
|
264 | if (matrix[i].size() != expected_cols) { |
| 150 | return false; | ||
| 151 | } | ||
| 152 | } | ||
| 153 | return true; | ||
| 154 | } | ||
| 155 | |||
| 156 | bool CheckIfZeroMatrix(const std::vector<std::vector<double>> &matrix) { | ||
| 157 |
1/2✓ Branch 0 taken 128 times.
✗ Branch 1 not taken.
|
128 | for (const auto &row : matrix) { |
| 158 |
3/4✓ Branch 0 taken 16 times.
✓ Branch 1 taken 128 times.
✓ Branch 2 taken 144 times.
✗ Branch 3 not taken.
|
144 | for (double val : row) { |
| 159 |
2/2✓ Branch 0 taken 16 times.
✓ Branch 1 taken 128 times.
|
144 | if (std::abs(val) > kEpsilon) { |
| 160 | return false; | ||
| 161 | } | ||
| 162 | } | ||
| 163 | } | ||
| 164 | return true; | ||
| 165 | } | ||
| 166 | |||
| 167 | 128 | bool CanSystemBeSolved(const std::vector<std::vector<double>> &matrix, int equations_count, int augmented_columns) { | |
| 168 |
1/2✓ Branch 0 taken 128 times.
✗ Branch 1 not taken.
|
128 | if (HasInconsistentEquation(matrix, equations_count, augmented_columns)) { |
| 169 | return false; | ||
| 170 | } | ||
| 171 | |||
| 172 | 128 | int matrix_rank = ComputeMatrixRank(matrix, equations_count, augmented_columns); | |
| 173 | 128 | int variable_count = augmented_columns - 1; | |
| 174 | |||
| 175 | // Исправлено: упрощение булевого выражения по Де Моргану | ||
| 176 | 128 | return matrix_rank >= variable_count || matrix_rank >= equations_count; | |
| 177 | } | ||
| 178 | |||
| 179 | 128 | std::vector<double> ComputeSolutionVector(const std::vector<std::vector<double>> &matrix, int n, int m) { | |
| 180 | 128 | std::vector<double> solution(m - 1, 0.0); | |
| 181 | int vars = m - 1; | ||
| 182 | 128 | int rows_to_process = (n < vars) ? n : vars; | |
| 183 | |||
| 184 |
2/2✓ Branch 0 taken 392 times.
✓ Branch 1 taken 128 times.
|
520 | for (int i = 0; i < rows_to_process; ++i) { |
| 185 | int pivot_col = -1; | ||
| 186 | |||
| 187 |
1/2✓ Branch 0 taken 960 times.
✗ Branch 1 not taken.
|
960 | for (int j = 0; j < vars; ++j) { |
| 188 |
2/2✓ Branch 0 taken 568 times.
✓ Branch 1 taken 392 times.
|
960 | if (std::abs(matrix[i][j]) > 1e-10) { |
| 189 | pivot_col = j; | ||
| 190 | break; | ||
| 191 | } | ||
| 192 | } | ||
| 193 |
1/2✓ Branch 0 taken 392 times.
✗ Branch 1 not taken.
|
392 | if (pivot_col >= 0) { |
| 194 | 392 | solution[pivot_col] = matrix[i][vars]; | |
| 195 | } else { | ||
| 196 | ✗ | solution[i] = 0.0; | |
| 197 | } | ||
| 198 | } | ||
| 199 | |||
| 200 | 128 | return solution; | |
| 201 | } | ||
| 202 | |||
| 203 | } // namespace | ||
| 204 | |||
| 205 |
1/2✓ Branch 1 taken 128 times.
✗ Branch 2 not taken.
|
128 | GaussJordanSEQ::GaussJordanSEQ(const InType &input) { |
| 206 | SetTypeOfTask(GetStaticTypeOfTask()); | ||
| 207 |
1/2✓ Branch 1 taken 128 times.
✗ Branch 2 not taken.
|
128 | InType matrix_copy(input); |
| 208 | GetInput().swap(matrix_copy); | ||
| 209 | 128 | } | |
| 210 | |||
| 211 |
1/2✓ Branch 0 taken 128 times.
✗ Branch 1 not taken.
|
128 | bool GaussJordanSEQ::ValidationImpl() { |
| 212 | const auto &input_matrix = GetInput(); | ||
| 213 | |||
| 214 |
1/2✓ Branch 0 taken 128 times.
✗ Branch 1 not taken.
|
128 | if (input_matrix.empty()) { |
| 215 | return true; | ||
| 216 | } | ||
| 217 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 128 times.
|
128 | if (!GetOutput().empty()) { |
| 218 | return false; | ||
| 219 | } | ||
| 220 | |||
| 221 | size_t column_count = input_matrix[0].size(); | ||
| 222 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 128 times.
|
128 | if (column_count == 0) { |
| 223 | return false; | ||
| 224 | } | ||
| 225 | |||
| 226 | size_t total_elements = 0; | ||
| 227 |
2/2✓ Branch 0 taken 392 times.
✓ Branch 1 taken 128 times.
|
520 | for (const auto &row : input_matrix) { |
| 228 | 392 | total_elements += row.size(); | |
| 229 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 392 times.
|
392 | if (row.size() != column_count) { |
| 230 | return false; | ||
| 231 | } | ||
| 232 | } | ||
| 233 | |||
| 234 | 128 | return total_elements == (column_count * input_matrix.size()); | |
| 235 | } | ||
| 236 | |||
| 237 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 128 times.
|
128 | bool GaussJordanSEQ::PreProcessingImpl() { |
| 238 | GetOutput().clear(); | ||
| 239 | 128 | return true; | |
| 240 | } | ||
| 241 | |||
| 242 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 128 times.
|
128 | bool GaussJordanSEQ::RunImpl() { |
| 243 | const auto &input_matrix = GetInput(); | ||
| 244 | |||
| 245 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 128 times.
|
128 | if (input_matrix.empty()) { |
| 246 | ✗ | GetOutput() = std::vector<double>(); | |
| 247 | ✗ | return true; | |
| 248 | } | ||
| 249 | |||
| 250 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 128 times.
|
128 | if (!ValidateMatrixDimensions(input_matrix)) { |
| 251 | ✗ | GetOutput() = std::vector<double>(); | |
| 252 | ✗ | return true; | |
| 253 | } | ||
| 254 | |||
| 255 | 128 | int equations_count = static_cast<int>(input_matrix.size()); | |
| 256 | 128 | int augmented_columns = static_cast<int>(input_matrix[0].size()); | |
| 257 | |||
| 258 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 128 times.
|
128 | if (augmented_columns <= 1) { |
| 259 | ✗ | GetOutput() = std::vector<double>(); | |
| 260 | ✗ | return true; | |
| 261 | } | ||
| 262 | |||
| 263 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 128 times.
|
128 | if (CheckIfZeroMatrix(input_matrix)) { |
| 264 | ✗ | GetOutput() = std::vector<double>(); | |
| 265 | ✗ | return true; | |
| 266 | } | ||
| 267 | |||
| 268 | 128 | std::vector<std::vector<double>> augmented_matrix = input_matrix; | |
| 269 | |||
| 270 | 128 | TransformToReducedRowEchelonForm(augmented_matrix, equations_count, augmented_columns); | |
| 271 | |||
| 272 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 128 times.
|
128 | if (!CanSystemBeSolved(augmented_matrix, equations_count, augmented_columns)) { |
| 273 | ✗ | GetOutput() = std::vector<double>(); | |
| 274 | ✗ | return true; | |
| 275 | } | ||
| 276 | |||
| 277 |
1/2✓ Branch 1 taken 128 times.
✗ Branch 2 not taken.
|
128 | GetOutput() = ComputeSolutionVector(augmented_matrix, equations_count, augmented_columns); |
| 278 | 128 | return true; | |
| 279 | 128 | } | |
| 280 | |||
| 281 | 128 | bool GaussJordanSEQ::PostProcessingImpl() { | |
| 282 | 128 | return true; | |
| 283 | } | ||
| 284 | } // namespace gauss_jordan | ||
| 285 |