Vita
evolution_recombination.tcc
1/**
2 * \file
3 * \remark This file is part of VITA.
4 *
5 * \copyright Copyright (C) 2013-2023 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_RECOMBINATION_H)
14# error "Don't include this file directly, include the specific .h instead"
15#endif
16
17#if !defined(VITA_EVOLUTION_RECOMBINATION_TCC)
18#define VITA_EVOLUTION_RECOMBINATION_TCC
19
20///
21/// \param[in] pop the current population
22/// \param[in] eva the current evaluator
23/// \param[out] stats pointer to the current set of statistics
24///
25template<class T>
26strategy<T>::strategy(const population<T> &pop, evaluator<T> &eva,
27 summary<T> *stats)
28 : pop_(pop), eva_(eva), stats_(stats)
29{
30 Expects(stats);
31}
32
33///
34/// This is a quite standard crossover + mutation operator.
35///
36/// \param[in] parent a vector of ordered parents
37/// \return the offspring
38///
39template<class T>
40typename strategy<T>::offspring_t base<T>::run(
41 const typename strategy<T>::parents_t &parent)
42{
43 const auto &pop(this->pop_);
44 const auto &prob(pop.get_problem());
45
46 const auto p_cross(prob.env.p_cross);
47 const auto p_mutation(prob.env.p_mutation);
48 const auto brood_recombination(prob.env.brood_recombination);
49
50 Expects(0.0 <= p_cross && p_cross <= 1.0);
51 Expects(0.0 <= p_mutation && p_mutation <= 1.0);
52 Expects(brood_recombination);
53 Expects(parent.size() >= 2);
54
55 const auto r1(parent[0]), r2(parent[1]);
56
57 if (random::boolean(p_cross))
58 {
59 auto cross_and_mutate(
60 [&](const T &p1, const T &p2)
61 {
62 T ret(crossover(p1, p2));
63 ++this->stats_->crossovers;
64
65 if (p_mutation > 0.0)
66 {
67 // This could be an original contribution of Vita but it's hard to be
68 // sure.
69 // It remembers of the hereditary repulsion constraint (I guess you
70 // could call it signature repulsion) and seems to:
71 // * maintain diversity during the exploration phase;
72 // * optimize the exploitation phase.
73 while (p1.signature() == ret.signature()
74 || p2.signature() == ret.signature())
75 this->stats_->mutations += ret.mutation(p_mutation, prob);
76 }
77
78 return ret;
79 });
80
81 T off(cross_and_mutate(pop[r1], pop[r2]));
82
83 if (brood_recombination > 1)
84 {
85 fitness_t fit_off(this->eva_.fast(off));
86
87 for (unsigned i(1); i < brood_recombination; ++i)
88 {
89 T tmp(cross_and_mutate(pop[r1], pop[r2]));
90
91 const auto fit_tmp(this->eva_.fast(tmp));
92 if (fit_tmp > fit_off)
93 {
94 off = tmp;
95 fit_off = fit_tmp;
96 }
97 }
98 }
99
100 return {off};
101 }
102
103 // !crossover
104 T off(pop[random::boolean() ? r1 : r2]);
105 this->stats_->mutations += off.mutation(p_mutation, prob);
106
107 return {off};
108}
109
110///
111/// This is strictly based on the DE crossover operator.
112///
113/// \param[in] parent a vector of ordered parents
114/// \return the offspring
115///
116template<class T>
117typename strategy<T>::offspring_t de<T>::run(
118 const typename strategy<T>::parents_t &parent)
119{
120 Expects(parent.size() >= 2);
121
122 const auto &pop(this->pop_);
123 const auto &env(pop.get_problem().env);
124
125 assert(0.0 < env.p_cross);
126 assert(env.p_cross <= 1.0);
127
128 const auto a(pickup(pop, parent[0]));
129 const auto b(pickup(pop, parent[0]));
130
131 return {pop[parent[0]].crossover(env.p_cross, env.de.weight,
132 pop[parent[1]], pop[a], pop[b])};
133}
134#endif // include guard