Ultra 0.9.4
Loading...
Searching...
No Matches
search_stats.tcc
Go to the documentation of this file.
1
12
13#if !defined(ULTRA_SEARCH_STATS_H)
14# error "Don't include this file directly, include the specific .h instead"
15#endif
16
17#if !defined(ULTRA_SEARCH_STATS_TCC)
18#define ULTRA_SEARCH_STATS_TCC
19
39template<Individual I, Fitness F>
40void search_stats<I, F>::update(const I &lr_best_prg,
41 const model_measurements<F> &lr_measurements,
42 std::chrono::milliseconds lr_elapsed)
43{
44 Expects(lr_measurements.fitness.has_value());
45 Expects(!std::isnan(*lr_measurements.fitness));
46
47 const std::size_t initial_run_id(runs());
48
49 // `upper_bound` finds the first run ranked after `lr_measurements` according
50 // to the comparator below, so insertion preserves the descending
51 // lexicographic order of `stats_`.
52 auto it(std::ranges::upper_bound(
53 stats_, lr_measurements,
54 [](const auto &lhs, const auto &rhs)
55 {
56 if (*lhs.fitness > *rhs.fitness)
57 return true;
58
59 if (*rhs.fitness > *lhs.fitness)
60 return false;
61
62 return lhs.accuracy > rhs.accuracy;
63 },
64 &run_summary::best_measurements));
65
66 run_summary new_run{initial_run_id, lr_best_prg, lr_measurements};
67 stats_.insert(it, std::move(new_run));
68
69 using std::isfinite;
70 if (const auto fit(lr_measurements.fitness); fit && isfinite(*fit))
71 fitness_distribution.add(*fit);
72
73 elapsed += lr_elapsed;
74}
75
88template<Individual I, Fitness F>
89std::set<std::size_t> search_stats<I, F>::good_runs(
90 const model_measurements<F> &threshold) const
91{
92 std::set<std::size_t> ret;
93
94 if (threshold.empty())
95 return ret;
96
97 for (const auto &s : stats_)
98 if (s.best_measurements >= threshold)
99 ret.insert(s.run);
100
101 // When an accuracy threshold is present, `best_run()` (selected primarily by
102 // fitness) might fail it even if another run with lower fitness satisfies it.
103 Ensures(ret.empty() || threshold.accuracy.has_value()
104 || ret.contains(best_run()));
105 return ret;
106}
107
116template<Individual I, Fitness F>
117std::size_t search_stats<I, F>::best_run() const noexcept
118{
119 Expects(runs());
120 return stats_.front().run;
121}
122
128template<Individual I, Fitness F>
129const I &search_stats<I, F>::best_individual() const noexcept
130{
131 Expects(runs());
132 return stats_.front().best_individual;
133}
134
140template<Individual I, Fitness F>
141const model_measurements<F> &
142search_stats<I, F>::best_measurements() const noexcept
143{
144 Expects(runs());
145 return stats_.front().best_measurements;
146}
147
151template<Individual I, Fitness F>
152std::size_t search_stats<I, F>::runs() const noexcept
153{
154 return stats_.size();
155}
156
168template<Individual I, Fitness F>
169double search_stats<I, F>::success_rate(
170 const model_measurements<F> &threshold) const noexcept
171{
172 const auto solutions(static_cast<double>(good_runs(threshold).size()));
173
174 return runs() ? solutions / static_cast<double>(runs()) : 0;
175}
176
196template<Individual I, Fitness F>
197std::span<const typename search_stats<I, F>::run_summary>
198search_stats<I, F>::elite_runs(double perc) const noexcept
199{
200 Expects(in_0_1(perc));
201
202 const std::size_t total(stats_.size());
203 if (total == 0 || issmall(perc))
204 return {};
205
206 const auto n(static_cast<std::size_t>(
207 std::ceil(static_cast<double>(total) * perc)));
208
209 return {stats_.data(), n};
210}
211
212#endif // include guard