| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | #include "alekseev_a_global_opt_chars/seq/include/ops_seq.hpp" | ||
| 2 | |||
| 3 | #include <algorithm> | ||
| 4 | #include <cmath> | ||
| 5 | #include <cstddef> | ||
| 6 | #include <limits> | ||
| 7 | #include <utility> | ||
| 8 | #include <vector> | ||
| 9 | |||
| 10 | #include "alekseev_a_global_opt_chars/common/include/common.hpp" | ||
| 11 | |||
| 12 | namespace alekseev_a_global_opt_chars { | ||
| 13 | |||
| 14 |
1/2✓ Branch 1 taken 48 times.
✗ Branch 2 not taken.
|
48 | AlekseevAGlobalOptCharsSEQ::AlekseevAGlobalOptCharsSEQ(const InType &in) { |
| 15 | SetTypeOfTask(GetStaticTypeOfTask()); | ||
| 16 | GetInput() = in; | ||
| 17 | 48 | GetOutput() = OutType(); | |
| 18 | 48 | } | |
| 19 | |||
| 20 |
1/2✓ Branch 0 taken 48 times.
✗ Branch 1 not taken.
|
48 | bool AlekseevAGlobalOptCharsSEQ::ValidationImpl() { |
| 21 | const auto &input = GetInput(); | ||
| 22 | |||
| 23 | bool valid = true; | ||
| 24 |
1/2✓ Branch 0 taken 48 times.
✗ Branch 1 not taken.
|
48 | valid = valid && (input.func != nullptr); |
| 25 |
1/2✓ Branch 0 taken 48 times.
✗ Branch 1 not taken.
|
48 | valid = valid && (input.max_iterations > 0); |
| 26 |
1/2✓ Branch 0 taken 48 times.
✗ Branch 1 not taken.
|
48 | valid = valid && (input.epsilon > 0.0); |
| 27 |
1/2✓ Branch 0 taken 48 times.
✗ Branch 1 not taken.
|
48 | valid = valid && (input.r_param > 1.0); |
| 28 |
1/2✓ Branch 0 taken 48 times.
✗ Branch 1 not taken.
|
48 | valid = valid && (input.x_min < input.x_max); |
| 29 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 48 times.
|
48 | valid = valid && (input.y_min < input.y_max); |
| 30 | |||
| 31 | 48 | return valid; | |
| 32 | } | ||
| 33 | |||
| 34 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 48 times.
|
48 | bool AlekseevAGlobalOptCharsSEQ::PreProcessingImpl() { |
| 35 | const auto &input = GetInput(); | ||
| 36 | |||
| 37 | trial_points_.clear(); | ||
| 38 | t_points_.clear(); | ||
| 39 | 48 | lipschitz_estimate_ = 1.0; | |
| 40 | |||
| 41 | 48 | const double t_left = 0.0; | |
| 42 | 48 | const double t_right = 1.0; | |
| 43 | |||
| 44 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 48 times.
|
48 | t_points_.push_back(t_left); |
| 45 | t_points_.push_back(t_right); | ||
| 46 | |||
| 47 | 48 | const double x0 = PeanoToX(t_left, input.x_min, input.x_max, peano_level_); | |
| 48 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 48 times.
|
48 | const double y0 = PeanoToY(t_left, input.y_min, input.y_max, peano_level_); |
| 49 | 48 | const double z0 = input.func(x0, y0); | |
| 50 | |||
| 51 | 48 | const double x1 = PeanoToX(t_right, input.x_min, input.x_max, peano_level_); | |
| 52 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 48 times.
|
48 | const double y1 = PeanoToY(t_right, input.y_min, input.y_max, peano_level_); |
| 53 | 48 | const double z1 = input.func(x1, y1); | |
| 54 | |||
| 55 | 48 | trial_points_.emplace_back(x0, y0, z0); | |
| 56 | 48 | trial_points_.emplace_back(x1, y1, z1); | |
| 57 | |||
| 58 | 48 | return true; | |
| 59 | } | ||
| 60 | |||
| 61 |
1/2✓ Branch 0 taken 48 times.
✗ Branch 1 not taken.
|
48 | bool AlekseevAGlobalOptCharsSEQ::RunImpl() { |
| 62 | const auto &input = GetInput(); | ||
| 63 | auto &output = GetOutput(); | ||
| 64 | |||
| 65 |
2/4✓ Branch 0 taken 48 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 48 times.
|
48 | if (t_points_.size() < 2 || trial_points_.size() < 2) { |
| 66 | ✗ | if (!PreProcessingImpl()) { | |
| 67 | return false; | ||
| 68 | } | ||
| 69 | } | ||
| 70 | |||
| 71 | 48 | output.iterations = 0; | |
| 72 | 48 | output.converged = false; | |
| 73 | |||
| 74 |
1/2✓ Branch 0 taken 560 times.
✗ Branch 1 not taken.
|
560 | for (int iter = 0; iter < input.max_iterations; ++iter) { |
| 75 | 560 | SortingTrials(); | |
| 76 | |||
| 77 | 560 | lipschitz_estimate_ = ComputeLipschitzEstimate(); | |
| 78 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 560 times.
|
560 | if (lipschitz_estimate_ < 1e-10) { |
| 79 | ✗ | lipschitz_estimate_ = 1.0; | |
| 80 | } | ||
| 81 | |||
| 82 | 560 | const int best_interval_idx = BestInterval(); | |
| 83 | |||
| 84 |
2/2✓ Branch 0 taken 48 times.
✓ Branch 1 taken 512 times.
|
560 | const double t_left = t_points_[best_interval_idx]; |
| 85 | 560 | const double t_right = t_points_[best_interval_idx + 1]; | |
| 86 | 560 | const double z_left = trial_points_[best_interval_idx].z; | |
| 87 | 560 | const double z_right = trial_points_[best_interval_idx + 1].z; | |
| 88 | |||
| 89 | 560 | const double interval_len = t_right - t_left; | |
| 90 |
2/2✓ Branch 0 taken 48 times.
✓ Branch 1 taken 512 times.
|
560 | if (interval_len < input.epsilon) { |
| 91 | 48 | output.converged = true; | |
| 92 | 48 | output.iterations = iter + 1; | |
| 93 | 48 | break; | |
| 94 | } | ||
| 95 | |||
| 96 | 512 | const double m_val = input.r_param * lipschitz_estimate_; | |
| 97 | |||
| 98 | 512 | double t_new = (0.5 * (t_left + t_right)) - ((z_right - z_left) / (2.0 * m_val)); | |
| 99 | |||
| 100 |
2/4✗ Branch 0 not taken.
✓ Branch 1 taken 512 times.
✓ Branch 2 taken 512 times.
✗ Branch 3 not taken.
|
512 | t_new = std::max(t_left + 1e-12, std::min(t_new, t_right - 1e-12)); |
| 101 | |||
| 102 | 512 | const double z_new = PerformTrial(t_new); | |
| 103 | |||
| 104 | 512 | const double x_new = PeanoToX(t_new, input.x_min, input.x_max, peano_level_); | |
| 105 | 512 | const double y_new = PeanoToY(t_new, input.y_min, input.y_max, peano_level_); | |
| 106 | |||
| 107 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 512 times.
|
512 | t_points_.push_back(t_new); |
| 108 | 512 | trial_points_.emplace_back(x_new, y_new, z_new); | |
| 109 | |||
| 110 | 512 | output.iterations = iter + 1; | |
| 111 | } | ||
| 112 | |||
| 113 | return true; | ||
| 114 | } | ||
| 115 | |||
| 116 | 48 | bool AlekseevAGlobalOptCharsSEQ::PostProcessingImpl() { | |
| 117 | auto &output = GetOutput(); | ||
| 118 | |||
| 119 | double best_z = std::numeric_limits<double>::max(); | ||
| 120 | std::size_t best_idx = 0; | ||
| 121 | |||
| 122 |
2/2✓ Branch 0 taken 608 times.
✓ Branch 1 taken 48 times.
|
656 | for (std::size_t i = 0; i < trial_points_.size(); ++i) { |
| 123 |
2/2✓ Branch 0 taken 208 times.
✓ Branch 1 taken 400 times.
|
608 | if (trial_points_[i].z < best_z) { |
| 124 | best_z = trial_points_[i].z; | ||
| 125 | best_idx = i; | ||
| 126 | } | ||
| 127 | } | ||
| 128 | 48 | output.x_opt = trial_points_[best_idx].x; | |
| 129 | 48 | output.y_opt = trial_points_[best_idx].y; | |
| 130 | 48 | output.func_min = best_z; | |
| 131 | |||
| 132 | 48 | return true; | |
| 133 | } | ||
| 134 | |||
| 135 | 560 | void AlekseevAGlobalOptCharsSEQ::SortingTrials() { | |
| 136 | 560 | std::vector<std::size_t> idx(t_points_.size()); | |
| 137 |
2/2✓ Branch 0 taken 4272 times.
✓ Branch 1 taken 560 times.
|
4832 | for (std::size_t i = 0; i < idx.size(); ++i) { |
| 138 | 4272 | idx[i] = i; | |
| 139 | } | ||
| 140 | |||
| 141 |
3/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 not taken.
✗ Branch 18 not taken.
✓ Branch 19 taken 3712 times.
✓ Branch 20 taken 1880 times.
✓ Branch 21 taken 3712 times.
|
9304 | std::ranges::sort(idx, [this](std::size_t a, std::size_t b) { return t_points_[a] < t_points_[b]; }); |
| 142 | |||
| 143 |
2/6✓ Branch 1 taken 560 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 560 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
|
560 | std::vector<double> sorted_t(t_points_.size()); |
| 144 |
1/4✓ Branch 1 taken 560 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
|
560 | std::vector<TrialPoint> sorted_trials(trial_points_.size()); |
| 145 | |||
| 146 |
2/2✓ Branch 0 taken 4272 times.
✓ Branch 1 taken 560 times.
|
4832 | for (std::size_t i = 0; i < idx.size(); ++i) { |
| 147 | 4272 | sorted_t[i] = t_points_[idx[i]]; | |
| 148 | 4272 | sorted_trials[i] = trial_points_[idx[i]]; | |
| 149 | } | ||
| 150 | |||
| 151 | 560 | t_points_ = std::move(sorted_t); | |
| 152 | 560 | trial_points_ = std::move(sorted_trials); | |
| 153 | 560 | } | |
| 154 | |||
| 155 | 560 | double AlekseevAGlobalOptCharsSEQ::ComputeLipschitzEstimate() { | |
| 156 | 560 | double max_slope = 0.0; | |
| 157 | |||
| 158 |
2/2✓ Branch 0 taken 3712 times.
✓ Branch 1 taken 560 times.
|
4272 | for (std::size_t i = 1; i < t_points_.size(); ++i) { |
| 159 | 3712 | const double dt = t_points_[i] - t_points_[i - 1]; | |
| 160 |
1/2✓ Branch 0 taken 3712 times.
✗ Branch 1 not taken.
|
3712 | if (dt > 1e-15) { |
| 161 | 3712 | const double dz = std::abs(trial_points_[i].z - trial_points_[i - 1].z); | |
| 162 | 3712 | max_slope = std::max(max_slope, dz / dt); | |
| 163 | } | ||
| 164 | } | ||
| 165 | |||
| 166 |
2/2✓ Branch 0 taken 512 times.
✓ Branch 1 taken 48 times.
|
560 | return (max_slope > 0.0) ? max_slope : 1.0; |
| 167 | } | ||
| 168 | |||
| 169 | 3712 | double AlekseevAGlobalOptCharsSEQ::ComputeIntervalCharacteristic(int interval_idx, double m_val) const { | |
| 170 | 3712 | const double t_i = t_points_[interval_idx]; | |
| 171 | 3712 | const double t_j = t_points_[interval_idx + 1]; | |
| 172 | 3712 | const double z_i = trial_points_[interval_idx].z; | |
| 173 | 3712 | const double z_j = trial_points_[interval_idx + 1].z; | |
| 174 | |||
| 175 | 3712 | const double dt = t_j - t_i; | |
| 176 | 3712 | const double dz = z_j - z_i; | |
| 177 | |||
| 178 | 3712 | return (m_val * dt) + ((dz * dz) / (m_val * dt)) - (2.0 * (z_j + z_i)); | |
| 179 | } | ||
| 180 | |||
| 181 | 560 | int AlekseevAGlobalOptCharsSEQ::BestInterval() { | |
| 182 | const auto &input = GetInput(); | ||
| 183 | 560 | const double m_val = input.r_param * lipschitz_estimate_; | |
| 184 | |||
| 185 | double best_char = -std::numeric_limits<double>::max(); | ||
| 186 | int best_idx = 0; | ||
| 187 | |||
| 188 |
2/2✓ Branch 0 taken 3712 times.
✓ Branch 1 taken 560 times.
|
4272 | for (std::size_t i = 0; i + 1 < t_points_.size(); ++i) { |
| 189 | 3712 | const double c = ComputeIntervalCharacteristic(static_cast<int>(i), m_val); | |
| 190 |
2/2✓ Branch 0 taken 1320 times.
✓ Branch 1 taken 2392 times.
|
3712 | if (c > best_char) { |
| 191 | best_char = c; | ||
| 192 | best_idx = static_cast<int>(i); | ||
| 193 | } | ||
| 194 | } | ||
| 195 | |||
| 196 | 560 | return best_idx; | |
| 197 | } | ||
| 198 | |||
| 199 | 512 | double AlekseevAGlobalOptCharsSEQ::PerformTrial(double t) { | |
| 200 | const auto &input = GetInput(); | ||
| 201 | |||
| 202 | 512 | const double x = PeanoToX(t, input.x_min, input.x_max, peano_level_); | |
| 203 | 512 | const double y = PeanoToY(t, input.y_min, input.y_max, peano_level_); | |
| 204 | |||
| 205 | 512 | return input.func(x, y); | |
| 206 | } | ||
| 207 | |||
| 208 | } // namespace alekseev_a_global_opt_chars | ||
| 209 |