Ultra 0.9.4
Loading...
Searching...
No Matches
evolution_summary.tcc
Go to the documentation of this file.
1
12
13#if !defined(ULTRA_EVOLUTION_SUMMARY_H)
14# error "Don't include this file directly, include the specific .h instead"
15#endif
16
17#if !defined(ULTRA_EVOLUTION_SUMMARY_TCC)
18#define ULTRA_EVOLUTION_SUMMARY_TCC
19
23template<Individual I, Fitness F>
24void summary<I, F>::clear()
25{
26 *this = {};
27}
28
38template<Individual I, Fitness F>
39evolution_status<I, F> summary<I, F>::starting_status()
40{
41 return evolution_status<I, F>(&generation,
42 [this](scored_individual<I, F> prg)
43 {
44 update_if_better(prg);
45 });
46}
47
68template<Individual I, Fitness F>
69summary<I, F> &summary<I, F>::on_new_best(on_new_best_callback_t f)
70{
71 // This lock isn't required, but the cost is negligible and it keeps the
72 // implementation safe even if someone breaks the contract later.
73 std::lock_guard lock(mutex_);
74
75 Expects(elapsed == std::chrono::milliseconds(0));
76 Expects(!generation);
77 Expects(data_.best.empty());
78 Expects(!data_.last_improvement);
79
80 on_new_best_callback_ = std::move(f);
81 return *this;
82}
83
84template<Individual I, Fitness F>
85typename summary<I, F>::data summary<I, F>::data_snapshot() const
86{
87 std::lock_guard lock(mutex_);
88 return data_;
89}
90
97template<Individual I, Fitness F>
98bool summary<I, F>::update_if_better(scored_individual<I, F> prg)
99{
100 on_new_best_callback_t callback(nullptr);
101 bool improved(false);
102
103 if (std::lock_guard lock(mutex_); prg > data_.best)
104 {
105 data_.best = prg;
106 data_.last_improvement = generation;
107 callback = on_new_best_callback_;
108 improved = true;
109 }
110
111 if (callback)
112 callback(prg);
113
114 return improved;
115}
116
126template<Individual I, Fitness F>
127void summary<I, F>::set_best_fitness(F fit)
128{
129 // The mutex protects memory access, but cannot detect an intervening change
130 // of best.
131 std::lock_guard lock(mutex_);
132 Expects(!data_.best.empty());
133 data_.best.fit = std::move(fit);
134}
135
136template<Individual I, Fitness F>
137unsigned summary<I, F>::stagnation() const
138{
139 return generation - last_improvement();
140}
141
145template<Individual I, Fitness F>
146scored_individual<I, F> summary<I, F>::best() const
147{
148 return data_snapshot().best;
149}
150
154template<Individual I, Fitness F>
155unsigned summary<I, F>::last_improvement() const
156{
157 return data_snapshot().last_improvement;
158}
159
170template<Individual I, Fitness F>
171bool summary<I, F>::load(std::istream &in, const problem &p)
172{
173 summary tmp_summary;
174
175 std::chrono::milliseconds tmp_elapsed;
176 if (int ms; !(in >> ms))
177 return false;
178 else
179 tmp_elapsed = std::chrono::milliseconds(ms);
180
181 unsigned tmp_generation;
182 if (!(in >> tmp_generation))
183 return false;
184
185 struct data tmp_data;
186
187 if (!(in >> tmp_data.last_improvement))
188 return false;
189
190 if (!tmp_data.best.load(in, p))
191 return false;
192
193 elapsed = tmp_elapsed;
194 generation = tmp_generation;
195 data_ = tmp_data;
196
197 return true;
198}
199
206template<Individual I, Fitness F>
207bool summary<I, F>::save(std::ostream &out) const
208{
209 const auto snapshot(data_snapshot());
210
211 // Since `data_` depends on `generation`, saving `generation` before
212 // `status` is very important.
213 out << elapsed.count() << ' ' << generation << ' '
214 << snapshot.last_improvement << '\n';
215
216 // analyzer `az` doesn't need to be saved: it'll be recalculated at the
217 // beginning of evolution.
218
219 if (!snapshot.best.save(out))
220 return false;
221
222 return out.good();
223}
224
225#endif // include guard