Ultra 0.9.4
Loading...
Searching...
No Matches
search.tcc
Go to the documentation of this file.
1
12
13#if !defined(ULTRA_SEARCH_H)
14# error "Don't include this file directly, include the specific .h instead"
15#endif
16
17#if !defined(ULTRA_SEARCH_TCC)
18#define ULTRA_SEARCH_TCC
19
26template<template<class> class ES, Evaluator E>
27basic_search<ES, E>::basic_search(problem &prob, E eva)
28 : eva_(std::move(eva), prob.params.cache.size), prob_(prob)
29{
30 Ensures(is_valid());
31}
32
44template<template<class> class ES, Evaluator E>
45void basic_search<ES, E>::init()
46{
47 tune_parameters();
48
49 if (!load())
50 ultraINFO("Init continues without cache");
51}
52
53template<template<class> class ES, Evaluator E>
54basic_search<ES, E> &basic_search<ES, E>::messages(bool m) noexcept
55{
56 emit_messages_ = m;
57 return *this;
58}
59
72template<template<class> class ES, Evaluator E>
73basic_search<ES, E> &basic_search<ES, E>::stop_source(std::stop_source ss)
74{
75 stop_source_ = ss;
76 return *this;
77}
78
90template<template<class> class ES, Evaluator E>
91basic_search<ES, E> &basic_search<ES, E>::logger(search_log &sl) noexcept
92{
93 search_log_ = &sl;
94 return *this;
95}
96
107template<template<class> class ES, Evaluator E>
108basic_search<ES, E> &basic_search<ES, E>::tag(const std::string &t)
109{
110 tag_ = t;
111 return *this;
112}
113
121template<template<class> class ES, Evaluator E>
122void basic_search<ES, E>::after_evolution(
123 unsigned run, const std::vector<model_measurements<fitness_t>> &mm)
124{
125 Expects(mm.size());
126
127 static const std::vector<std::string> phase_names {"TRAINING", "VALIDATION"};
128
129 const std::string tags(tag_.empty() ? tag_ : "[" + tag_ + "] ");
130
131 for (std::size_t i(0); const auto &m : mm)
132 {
133 std::string accuracy;
134 if (m.accuracy)
135 accuracy = std::format("{:.6g}%", *m.accuracy * 100.0);
136
137 if (emit_messages_)
138 {
139 const auto phase(mm.size() <= phase_names.size()
140 ? phase_names[i] : "PHASE" + std::to_string(i));
141
142 ultraPAROUT("{}Run {} {}. Fitness: {} Accuracy: {}",
143 tags, run, phase, internal::streamed(*m.fitness), accuracy);
144 }
145
146 ++i;
147 }
148}
149
150template<template<class> class ES, Evaluator E>
151basic_search<ES, E> &basic_search<ES, E>::refinement(refinement_callback_t f)
152{
153 refinement_callback_ = std::move(f);
154 return *this;
155}
156
164template<template<class> class ES, Evaluator E>
165basic_search<ES, E> &basic_search<ES, E>::after_generation(
166 after_generation_callback_t f)
167{
168 after_generation_callback_ = std::move(f);
169 return *this;
170}
171
179template<template<class> class ES, Evaluator E>
180basic_search<ES, E> &basic_search<ES, E>::on_training_new_best(
181 on_training_new_best_callback_t f)
182{
183 on_training_new_best_callback_ = std::move(f);
184 return *this;
185}
186
196template<template<class> class ES, Evaluator E>
197void basic_search<ES, E>::tune_parameters()
198{
199 auto &params(prob_.params);
200
201 // The `shape` function modifies the default parameters with
202 // strategy-specific values.
203 const auto dflt(ES<E>::shape(parameters().init()));
204 assert(!dflt.needs_init());
205
206 // User specified values are constraints.
207 const auto constrained(params);
208
209 params.fill_undefined_from(dflt);
210
211 if (!constrained.evolution.mate_zone)
212 params.evolution.mate_zone =
213 std::max<std::size_t>(params.population.individuals / 5, 4);
214
215 Ensures(params.is_valid(true));
216}
217
226template<template<class> class ES, Evaluator E>
227search_stats<typename basic_search<ES, E>::individual_t,
228 typename basic_search<ES, E>::fitness_t>
229basic_search<ES, E>::run(unsigned n,
230 const model_measurements<fitness_t> &threshold)
231{
232 init();
233
234 shake_function_callback_t shake([this](unsigned g) { return vs_->shake(g); });
235 search_stats<individual_t, fitness_t> stats;
236
237 for (unsigned r(0); r < n && !stop_source_.stop_requested(); ++r)
238 {
239 if (vs_->training_setup(r) == evaluation_context::changed)
241
242 evolution evo(prob_, eva_);
243 if (search_log_)
244 evo.logger(*search_log_);
245 evo.after_generation(after_generation_callback_)
246 .messages(emit_messages_)
247 .on_new_best(on_training_new_best_callback_)
248 .refinement(refinement_callback_)
249 .shake_function(shake)
250 .stop_source(stop_source_)
251 .tag(tag_);
252
253 const auto run_summary(evo.template run<ES>());
254
255 if (const auto prg(run_summary.best().ind); !prg.empty())
256 {
257 std::vector metrics = { calculate_metrics(prg) }; // training metrics
258
259 if (vs_->validation_setup(r))
260 metrics.push_back(calculate_metrics(prg)); // validation metrics
261
262 after_evolution(r, metrics);
263
264 // Update the search statistics (possibly using the validation setup).
265 stats.update(prg, metrics.back(), run_summary.elapsed);
266 }
267
268 if (search_log_)
269 search_log_->save_summary(stats, threshold);
270 }
271
272 return stats;
273}
274
287template<template<class> class ES, Evaluator E>
288model_measurements<typename basic_search<ES, E>::fitness_t>
289basic_search<ES, E>::calculate_metrics(const individual_t &prg) const
290{
291 model_measurements<fitness_t> ret;
292
293 // `calculate_metrics` is called after an environment-switch and must not use
294 // a cached value (so using `core()`).
295 ret.fitness = eva_.core()(prg);
296
297 return ret;
298}
299
306template<template<class> class ES, Evaluator E>
307template<ValidationStrategy V, class... Args>
308basic_search<ES, E> &basic_search<ES, E>::validation_strategy(Args && ...args)
309{
310 vs_ = std::make_unique<V>(std::forward<Args>(args)...);
311 return *this;
312}
313
320template<template<class> class ES, Evaluator E>
321basic_search<ES, E> &basic_search<ES, E>::validation_strategy(
323{
324 vs_ = vs.clone();
325 return *this;
326}
327
337template<template<class> class ES, Evaluator E>
338bool basic_search<ES, E>::load()
339{
340 const auto &file(prob_.params.cache.serialization_file);
341
342 if (file.empty())
343 return true;
344
345 if (!prob_.params.cache.size)
346 {
347 ultraINFO("Cache size is 0; skipping cache load from {}", file.string());
348 return false;
349 }
350
351 std::ifstream in(file);
352 if (!in)
353 {
354 ultraWARNING("Cannot open cache file {}", file.string());
355 return false;
356 }
357
358 if (!eva_.load_cache(in))
359 {
360 ultraWARNING("Cannot load cache from {}", file.string());
361 return false;
362 }
363
364 ultraINFO("Loaded cache from {}", file.string());
365 return true;
366}
367
371template<template<class> class ES, Evaluator E>
372bool basic_search<ES, E>::is_valid() const
373{
374 return true;
375}
376
377#endif // include guard
basic_search(problem &, E)
Definition search.h:28
Definition validation_strategy.h:29
Definition evaluator.h:44
bool load(std::istream &in, F *f)
Definition fitness.tcc:190
double accuracy(const P &p, const dataframe &d)
Definition metrics.h:47
STL namespace.
void invalidate_cache_if_supported(E &eva)
Definition evaluation_context.h:48