Vita
evolution_strategy.tcc
1/**
2 * \file
3 * \remark This file is part of VITA.
4 *
5 * \copyright Copyright (C) 2013-2022 EOS di Manlio Morini.
6 *
7 * \license
8 * This Source Code Form is subject to the terms of the Mozilla Public
9 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
10 * You can obtain one at http://mozilla.org/MPL/2.0/
11 */
12
13#if !defined(VITA_EVOLUTION_STRATEGY_H)
14# error "Don't include this file directly, include the specific .h instead"
15#endif
16
17#if !defined(VITA_EVOLUTION_STRATEGY_TCC)
18#define VITA_EVOLUTION_STRATEGY_TCC
19
20///
21/// \param[out] env environment
22/// \return a strategy-specific environment
23///
24/// \remark For standard evolution we only need one layer.
25///
26template<class T>
27environment std_es<T>::shape(environment env)
28{
29 env.layers = 1;
30 return env;
31}
32
33///
34/// \return `true` when evolution must be stopped
35///
36/// We use an accelerated stop condition when:
37/// - after `max_stuck_time` generations the situation doesn't change;
38/// - all the individuals have the same fitness.
39///
40template<class T>
41bool std_es<T>::stop_condition() const
42{
43 const auto &env(this->pop_.get_problem().env);
44 Expects(env.max_stuck_time.has_value());
45
46 const auto &sum(this->sum_);
47 Expects(sum->gen >= sum->last_imp);
48
49 // Pay attention to `env.max_stuck_time`: it can be a large number and cause
50 // overflow. E.g. `sum->gen > sum->last_imp + *env.max_stuck_time`
51
52 if (sum->gen - sum->last_imp > *env.max_stuck_time
53 && issmall(sum->az.fit_dist().variance()))
54 return true;
55
56 return false;
57}
58
59///
60/// \param[out] env environemnt
61/// \return a strategy-specific environment
62///
63/// \remark ALPS requires more than one layer.
64///
65template<class T, template<class> class CS>
66environment basic_alps_es<T, CS>::shape(environment env)
67{
68 env.layers = 4;
69 return env;
70}
71
72///
73/// Increments population's age and checks if it's time to add a new layer.
74///
75template<class T, template<class> class CS>
76void basic_alps_es<T, CS>::after_generation()
77{
78 const auto &sum(this->sum_);
79 auto &pop(this->pop_);
80 const auto &env(pop.get_problem().env);
81
82 pop.inc_age();
83
84 for (auto l(pop.layers() - 1); l; --l)
85 if (almost_equal(sum->az.fit_dist(l - 1).mean(),
86 sum->az.fit_dist( l).mean()))
87 pop.remove_layer(l);
88
89 auto layers(pop.layers());
90
91 for (decltype(layers) l(1); l < layers; ++l)
92 if (issmall(sum->az.fit_dist(l).standard_deviation()))
93 {
94 const auto current(pop.individuals(l));
95 pop.set_allowed(l, std::max(env.min_individuals, current / 2));
96 }
97 else
98 {
99 const auto allowed(env.individuals);
100 pop.set_allowed(l, allowed);
101 }
102
103 // Code executed every `age_gap` interval.
104 if (sum->gen && sum->gen % env.alps.age_gap == 0)
105 {
106 if (layers < env.layers
107 || sum->az.age_dist(layers - 1).mean() > env.alps.max_age(layers))
108 pop.add_layer();
109 else
110 {
111 this->replacement.try_move_up_layer(0);
112 pop.init_layer(0);
113 }
114 }
115}
116
117///
118/// Saves working / statistical informations about layer status.
119///
120/// \param[in] last_run last run processed
121/// \param[in] current_run current run
122///
123/// Parameters from the environment:
124/// * `env.stat.layers_file` if empty the method will not write any data.
125///
126template<class T, template<class> class CS>
127void basic_alps_es<T, CS>::log_strategy(unsigned last_run,
128 unsigned current_run) const
129{
130 const auto &pop(this->pop_);
131 const auto &env(pop.get_problem().env);
132
133 if (!env.stat.layers_file.empty())
134 {
135 const auto n_lys(env.stat.dir / env.stat.layers_file);
136 std::ofstream f_lys(n_lys, std::ios_base::app);
137 if (!f_lys.good())
138 return;
139
140 if (last_run != current_run)
141 f_lys << "\n\n";
142
143 auto layers(pop.layers());
144 for (decltype(layers) l(0); l < layers; ++l)
145 {
146 f_lys << current_run << ' ' << this->sum_->gen << ' ' << l << " <";
147
148 const auto ma(env.alps.allowed_age(l, layers));
149 if (ma == std::numeric_limits<decltype(ma)>::max())
150 f_lys << "inf";
151 else
152 f_lys << ma + 1;
153
154 f_lys << ' ' << this->sum_->az.age_dist(l).mean()
155 << ' ' << this->sum_->az.age_dist(l).standard_deviation()
156 << ' ' << static_cast<unsigned>(this->sum_->az.age_dist(l).min())
157 << '-' << static_cast<unsigned>(this->sum_->az.age_dist(l).max())
158 << ' ' << this->sum_->az.fit_dist(l).mean()
159 << ' ' << this->sum_->az.fit_dist(l).standard_deviation()
160 << ' ' << this->sum_->az.fit_dist(l).min()
161 << '-' << this->sum_->az.fit_dist(l).max()
162 << ' ' << pop.individuals(l) << '\n';
163 }
164 }
165}
166#endif // include guard