Vita
gene.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_GENE_H)
14# error "Don't include this file directly, include the specific .h instead"
15#endif
16
17#if !defined(VITA_GENE_TCC)
18#define VITA_GENE_TCC
19
20///
21/// A new gene built from terminal `t`.
22///
23/// \param[in] t a terminal
24///
25/// \note
26/// This is usually called for filling the patch section of an individual.
27///
28template<unsigned K>
29basic_gene<K>::basic_gene(const terminal &t) : sym(&t), par(), args(0)
30{
31 init_if_parametric();
32}
33
34///
35/// Possibly inits the parameter.
36///
37template<unsigned K>
38void basic_gene<K>::init_if_parametric()
39{
40 Expects(sym->terminal());
41
42 const auto t(terminal::cast(sym));
43 if (t->parametric())
44 par = t->init();
45}
46
47///
48/// Utility constructor to input hard-coded genomes.
49///
50/// \param[in] g a reference to a symbol and its arguments
51///
52/// A constructor that makes it easy to write genome "by hand":
53/// std::vector<gene> g(
54/// {
55/// {{f_add, {1, 2}}}, // [0] ADD 1,2
56/// {{ y, {}}}, // [1] Y
57/// {{ x, {}}} // [2] X
58/// };
59///
60template<unsigned K>
61basic_gene<K>::basic_gene(const std::pair<symbol *, std::vector<index_t>> &g)
62 : sym(g.first), args(g.first->arity())
63{
64 if (sym->arity())
65 {
66 std::transform(g.second.begin(), g.second.end(), args.begin(),
67 [](index_t i)
68 {
69 Expects(i <= std::numeric_limits<packed_index_t>::max());
70 return static_cast<packed_index_t>(i);
71 });
72 }
73 else
74 init_if_parametric();
75}
76
77///
78/// A new gene built from symbol `s` with argument in the `[from;sup[` range.
79///
80/// \param[in] s a symbol
81/// \param[in] from a starting index in the genome
82/// \param[in] sup an upper limit in the genome
83///
84/// \note
85/// This is usually called for filling the standard section of an individual.
86///
87template<unsigned K>
88basic_gene<K>::basic_gene(const symbol &s, index_t from, index_t sup)
89 : sym(&s), args(s.arity())
90{
91 Expects(from < sup);
92
93 if (s.arity())
94 {
95 assert(sup <= std::numeric_limits<packed_index_t>::max());
96
97 std::generate(args.begin(), args.end(),
98 [from, sup]()
99 {
100 return static_cast<packed_index_t>(random::between(from,
101 sup));
102 });
103 }
104 else
105 init_if_parametric();
106}
107
108///
109/// \return the list of loci associated with the arguments of the current
110/// gene.
111///
112template<unsigned K>
113small_vector<locus, K> basic_gene<K>::arguments() const
114{
115 small_vector<locus, K> ret(sym->arity());
116
117 std::generate(ret.begin(), ret.end(),
118 [this, i = 0u]() mutable
119 {
120 return locus_of_argument(i++);
121 });
122
123 return ret;
124}
125
126///
127/// \param[in] i ordinal of an argument
128/// \return the locus that `i`-th argument of the current symbol refers to
129///
130template<unsigned K>
131locus basic_gene<K>::locus_of_argument(std::size_t i) const
132{
133 Expects(i < sym->arity());
134
135 return {args[i], function::cast(sym)->arg_category(i)};
136}
137
138///
139/// \param[in] g1 first term of comparison
140/// \param[in] g2 second term of comparison
141/// \return `true` if `g1 == g2`
142///
143template<unsigned K>
144bool operator==(const basic_gene<K> &g1, const basic_gene<K> &g2)
145{
146 if (g1.sym != g2.sym)
147 return false;
148
149 assert(g1.sym->arity() == g2.sym->arity());
150
151 if (g1.sym->arity())
152 return std::equal(g1.args.begin(), g1.args.end(),
153 g2.args.begin(), g2.args.end());
154
155 assert(g1.sym->terminal());
156 const auto t(terminal::cast(g1.sym));
157
158 return !t->parametric() || almost_equal(g1.par, g2.par);
159}
160
161///
162/// \param[in] g1 first term of comparison
163/// \param[in] g2 second term of comparison
164/// \return `true` if `g1 != g2`
165///
166template<unsigned K>
167bool operator!=(const basic_gene<K> &g1, const basic_gene<K> &g2)
168{
169 return !(g1 == g2);
170}
171
172///
173/// \param[out] s output stream
174/// \param[in] g gene to print
175/// \return output stream including `g`
176///
177template<unsigned K>
178std::ostream &operator<<(std::ostream &s, const basic_gene<K> &g)
179{
180 const auto *sym(g.sym);
181
182 if (sym->terminal())
183 {
184 const auto t(terminal::cast(g.sym));
185 if (t->parametric())
186 return s << t->display(g.par);
187 }
188
189 return s << sym->name();
190}
191
192#endif // include guard