Ultra 0.9.4
Loading...
Searching...
No Matches
gp/src/search.tcc
Go to the documentation of this file.
1
12
13#if !defined(ULTRA_SRC_SEARCH_H)
14# error "Don't include this file directly, include the specific .h instead"
15#endif
16
17#if !defined(ULTRA_SRC_SEARCH_TCC)
18#define ULTRA_SRC_SEARCH_TCC
19
25{
26};
27
28namespace internal
29{
30
31template<class P>
32[[nodiscard]] std::unique_ptr<basic_oracle> make_basic_oracle(P &&p)
33{
34 using predictor_t = std::remove_cvref_t<P>;
35
36 if constexpr (std::derived_from<predictor_t, basic_oracle>)
37 return std::make_unique<predictor_t>(std::forward<P>(p));
38 // Check classification predictor before since it's the richer contract.
39 else if constexpr (ClassificationPredictor<predictor_t>)
40 return std::make_unique<class_oracle_adaptor<predictor_t>>(std::forward<P>(p));
41 else if constexpr (RegressionPredictor<predictor_t>)
42 return std::make_unique<reg_oracle_adaptor<predictor_t>>(std::forward<P>(p));
43
44 return nullptr;
45}
46
47} // namespace internal
48
49[[nodiscard]] constexpr std::underlying_type_t<metric_flags> operator&(
50 metric_flags f1, metric_flags f2)
51{
52 return std::to_underlying(f1) & std::to_underlying(f2);
53}
54
63template<template<class> class ES, Evaluator E>
64basic_search<ES, E>::basic_search(problem &p, metric_flags m)
65 : ultra::basic_search<ES, E>(p, E(p.data)), metrics_(m)
66{
67 Ensures(this->is_valid());
68}
69
82/// compile time via the `no_predictor` fallback rather than via runtime errors.
83///
84template<template<class> class ES, Evaluator E>
85auto basic_search<ES, E>::predictor(const individual_t &ind) const
86{
87 const auto &eva_core(this->eva_.core());
88
89 if constexpr (requires { eva_core.predictor(ind); })
90 return eva_core.predictor(ind);
91 else
92 return no_predictor();
93}
94
98template<template<class> class ES, Evaluator E>
99problem &basic_search<ES, E>::prob() const noexcept
100{
101 return static_cast<problem &>(this->prob_);
102}
103
116template<template<class> class ES, Evaluator E>
117model_measurements<typename basic_search<ES, E>::fitness_t>
118basic_search<ES, E>::calculate_metrics(const individual_t &prg) const
119{
121 const auto prg_predictor(predictor(prg));
122
123 if constexpr (ClassificationPredictor<decltype(prg_predictor)>)
124 if ((metrics_ & metric_flags::accuracy) && prob().classification())
125 {
126 ret.accuracy = metrics::accuracy(prg_predictor, prob().data.selected());
127 }
128
129 return ret;
130}
131
160template<template<class> class ES, Evaluator E>
162{
163 // The `shape` function modifies the default parameters with
164 // strategy-specific values.
165 const auto dflt(ES<E>::shape(parameters().init()));
166
167 auto &params(prob().params);
168
169 // Contains user-specified parameters that will be partly changed by this
170 // function.
171 const auto constrained(params);
172
174
175 const auto d_size(prob().data.selected().size());
176 Expects(d_size);
177
178 if (!constrained.population.init_subgroups)
179 {
180 if (dflt.population.init_subgroups > 1 && d_size > 8)
181 params.population.init_subgroups =
182 static_cast<std::size_t>(std::log(d_size));
183 else
184 params.population.init_subgroups = dflt.population.init_subgroups;
185
186 ultraINFO("Number of layers set to {}", params.population.init_subgroups);
187 }
188
189 // A larger number of training cases requires an increase in the population
190 // size (e.g. https://github.com/morinim/ultra/wiki/bibliography#11 suggests
191 // 10 - 1000 individuals for smaller problems; between 1000 and 10000
192 // individuals for complex problem (more than 200 fitness cases).
193 //
194 // We chose a strictly increasing function to link training set size and
195 // population size.
196 if (!constrained.population.individuals)
197 {
198 if (d_size > 8)
199 {
200 params.population.individuals =
201 2 * static_cast<std::size_t>(std::pow(std::log2(d_size), 3))
202 / params.population.init_subgroups;
203 }
204 else
205 params.population.individuals = dflt.population.individuals;
206
207 if (params.population.individuals < 4)
208 params.population.individuals = 4;
209
210 ultraINFO("Population size set to {}", params.population.individuals);
211 }
212
213 Ensures(params.is_valid(true));
214}
215
219template<template<class> class ES, Evaluator E>
224
225template<Individual P>
226search<P>::search(problem &p, metric_flags m)
227 : engine_(make_engine(p, m)), prob_(p), classification_(p.classification())
228{
229}
230
231template<Individual P>
232typename search<P>::engine_t search<P>::make_engine(problem &p, metric_flags m)
233{
234 if (p.classification())
235 return engine_t(std::in_place_type<class_search_t>, p, m);
236
237 return engine_t(std::in_place_type<reg_search_t>, p, m);
238}
239
240template<Individual P>
241bool search<P>::problem_type_unchanged() const noexcept
242{
243 return classification_ == prob_.classification();
244}
245
253template<Individual P>
254search<P> &search<P>::stop_source(std::stop_source ss)
255{
256 std::visit([&](auto &s) { s.stop_source(ss); }, engine_);
257 return *this;
258}
259
271template<Individual P>
273{
274 Expects(sl.is_valid());
275
276 std::visit([&](auto &s) { s.logger(sl); }, engine_);
277 return *this;
278}
279
280template<Individual P>
281search<P> &search<P>::messages(bool m) noexcept
282{
283 std::visit([&](auto &s) { s.messages(m); }, engine_);
284 return *this;
285}
286
297template<Individual P>
298search<P> &search<P>::tag(const std::string &t)
299{
300 std::visit([&](auto &s) { s.tag(t); }, engine_);
301 return *this;
302}
303
304template<Individual P>
306 unsigned n, const model_measurements<fitness_t> &threshold)
307{
308 Expects(problem_type_unchanged());
309
310 return std::visit([&](auto &s) { return s.run(n, threshold); }, engine_);
311}
312
359template<Individual P>
360template<class F>
361search<P> &search<P>::refinement(F &&f)
362{
363 using callback_t = std::remove_cvref_t<F>;
364
365 constexpr bool class_ok = std::is_invocable_r_v<
366 std::optional<fitness_t>, callback_t &, P &,
369
370 constexpr bool reg_ok = std::is_invocable_r_v<
371 std::optional<fitness_t>, callback_t &, P &,
374
375 static_assert(class_ok || reg_ok,
376 "Refinement callback is not compatible with available "
377 "evaluator signatures");
378
379 auto callback(std::forward<F>(f));
380
381 std::visit(
382 [&](auto &s)
383 {
384 s.refinement({});
385
386 using search_t = std::remove_cvref_t<decltype(s)>;
387
388 constexpr bool compatible =
389 (std::same_as<search_t, class_search_t> && class_ok)
390 || (std::same_as<search_t, reg_search_t> && reg_ok);
391
392 if constexpr (compatible)
393 s.refinement(callback);
394 },
395 engine_);
396
397 return *this;
398}
399
416template<Individual P>
417std::unique_ptr<basic_oracle> search<P>::predictor(const P &prg) const
418{
419 Expects(problem_type_unchanged());
420
421 return std::visit(
422 [&](const auto &s) { return internal::make_basic_oracle(s.predictor(prg)); },
423 engine_);
424}
425
433template<Individual P>
434search<P> &search<P>::after_generation(after_generation_callback_t f)
435{
436 std::visit([&](auto &s) { s.after_generation(std::move(f)); }, engine_);
437 return *this;
438}
439
447template<Individual P>
448search<P> &search<P>::on_training_new_best(on_training_new_best_callback_t f)
449{
450 std::visit([&](auto &s) { s.on_training_new_best(std::move(f)); }, engine_);
451 return *this;
452}
453
460template<Individual P>
461template<ValidationStrategy V, class... Args>
462search<P> &search<P>::validation_strategy(Args && ...args)
463{
464 std::visit(
465 [&](auto &s)
466 { s.template validation_strategy<V>(std::forward<Args>(args)...); },
467 engine_);
468 return *this;
469}
470
471#endif // include guard
Definition search.h:43
search_stats< individual_t, fitness_t > run(unsigned=1, const model_measurements< fitness_t > &={})
Definition search.h:230
basic_search & logger(search_log &) noexcept
Definition search.h:92
basic_search & after_generation(after_generation_callback_t)
Definition search.h:166
virtual void tune_parameters()
Definition gp/src/search.tcc:161
basic_search & stop_source(std::stop_source)
Definition search.h:74
basic_search & tag(const std::string &)
Definition search.h:109
basic_search< alps_es, E > & validation_strategy(Args &&...args)
Definition search.h:309
virtual model_measurements< fitness_t > calculate_metrics(const individual_t &) const
Definition search.h:290
basic_search(problem &, E)
Definition search.h:28
basic_search & on_training_new_best(on_training_new_best_callback_t)
Definition search.h:181
virtual bool is_valid() const
Definition gp/src/search.tcc:220
Definition evaluator_proxy.h:45
Definition search_log.h:28
Definition search_stats.h:44
Definition search.h:122
std::unique_ptr< basic_oracle > predictor(const P &) const
Definition gp/src/search.h:418
Definition evaluator.h:44
Definition validation_strategy.h:84
Definition gp/src/search.tcc:25
Definition model_measurements.h:28
Parameters controlling numerical optimisation of GP individuals.
Definition parameters.h:203
Definition parameters.h:26
Definition problem.h:26