Vita
i_de.cc
Go to the documentation of this file.
1
13#include "kernel/ga/i_de.h"
14#include "kernel/cache_hash.h"
15#include "kernel/log.h"
16#include "kernel/random.h"
17
18namespace vita
19{
29i_de::i_de(const problem &p) : individual(), genome_(p.sset.categories())
30{
31 Expects(parameters());
32
33 std::generate(genome_.begin(), genome_.end(),
34 [&, n = 0]() mutable
35 {
36 return p.sset.roulette_terminal(n++).init();
37 });
38
39 Ensures(is_valid());
40}
41
51void i_de::graphviz(std::ostream &s) const
52{
53 s << "graph {";
54
55 for (const auto &g : genome_)
56 s << "g [label=" << g << ", shape=circle];";
57
58 s << '}';
59}
60
70std::ostream &in_line(const i_de &de, std::ostream &s)
71{
72 std::copy(de.begin(), de.end(), infix_iterator<i_de::value_type>(s, " "));
73 return s;
74}
75
105 const i_de &a, const i_de &b, const i_de &c) const
106{
107 Expects(0.0 <= p && p <= 1.0);
108
109 const auto ps(parameters());
110 Expects(ps == a.parameters());
111 Expects(ps == b.parameters());
112 Expects(ps == c.parameters());
113
114 // The weighting factor is randomly selected from an interval for each
115 // difference vector (a technique called dither). Dither improves convergence
116 // behaviour significantly, especially for noisy objective functions.
117 const auto rf(random::in(f));
118
119 i_de ret(c);
120
121 for (auto i(decltype(ps){0}); i < ps - 1; ++i)
122 if (random::boolean(p))
123 ret[i] += rf * (a[i] - b[i]);
124 else
125 ret[i] = operator[](i);
126 ret[ps - 1] += rf * (a[ps - 1] - b[ps - 1]);
127
128 ret.set_older_age(std::max({age(), a.age(), b.age()}));
129
130 ret.signature_.clear();
131 Ensures(ret.is_valid());
132 return ret;
133}
134
141{
142 if (signature_.empty())
143 signature_ = hash();
144
145 return signature_;
146}
147
155hash_t i_de::hash() const
156{
157 const auto len(genome_.size() * sizeof(genome_[0]));
158 return vita::hash::hash128(genome_.data(), len);
159}
160
167double distance(const i_de &lhs, const i_de &rhs)
168{
169 Expects(lhs.parameters() == rhs.parameters());
170
171 const auto cs(lhs.parameters());
172 assert(cs);
173
174 double d(0.0);
175 for (unsigned i(0); i < cs; ++i)
176 d += std::fabs(lhs[i] - rhs[i]);
177
178 Ensures(d >= 0.0);
179 return d;
180}
181
188i_de &i_de::operator=(const std::vector<i_de::value_type> &v)
189{
190 Expects(v.size() == parameters());
191
192 genome_ = v;
193
194 return *this;
195}
196
200bool i_de::is_valid() const
201{
202 if (empty())
203 {
204 if (!genome_.empty())
205 {
206 vitaERROR << "Inconsistent internal status for empty individual";
207 return false;
208 }
209
210 if (!signature_.empty())
211 {
212 vitaERROR << "Empty individual must have empty signature";
213 return false;
214 }
215
216 return true;
217 }
218
219 if (!signature_.empty() && signature_ != hash())
220 {
221 vitaERROR << "Wrong signature: " << signature_ << " should be " << hash();
222 return false;
223 }
224
225 return true;
226}
227
236bool i_de::load_impl(std::istream &in, const symbol_set &)
237{
238 decltype(parameters()) sz;
239 if (!(in >> sz))
240 return false;
241
242 decltype(genome_) v(sz);
243 for (auto &g : v)
244 if (!load_float_from_stream(in, &g))
245 return false;
246
247 genome_ = v;
248
249 return true;
250}
251
256bool i_de::save_impl(std::ostream &out) const
257{
258 out << parameters() << '\n';
259 for (const auto &v : genome_)
260 {
261 save_float_to_stream(out, v);
262 out << '\n';
263 }
264
265 return out.good();
266}
267
275std::ostream &operator<<(std::ostream &s, const i_de &ind)
276{
277 return in_line(ind, s);
278}
279
286i_de::operator std::vector<i_de::value_type>() const
287{
288 return genome_;
289}
290
298bool operator==(const i_de &lhs, const i_de &rhs)
299{
300 const bool eq(std::equal(lhs.begin(), lhs.end(), rhs.begin(), rhs.end()));
301
302 Ensures((lhs.signature() == rhs.signature()) == eq);
303 return eq;
304}
305
306} // namespace vita
An individual optimized for differential evolution.
Definition: i_de.h:27
std::ostream & operator<<(std::ostream &s, const i_de &ind)
Definition: i_de.cc:275
bool is_valid() const
Definition: i_de.cc:200
std::ostream & in_line(const i_de &de, std::ostream &s)
Prints the genes of the individual.
Definition: i_de.cc:70
std::size_t parameters() const
Definition: i_de.h:67
void graphviz(std::ostream &) const
Inserts into the output stream the graph representation of the individual.
Definition: i_de.cc:51
hash_t signature() const
Definition: i_de.cc:140
const_iterator begin() const
Definition: i_de.h:103
bool empty() const
Definition: i_de.h:64
i_de crossover(double, const range_t< double > &, const i_de &, const i_de &, const i_de &) const
Differential evolution crossover.
Definition: i_de.cc:104
const_iterator end() const
Definition: i_de.h:111
i_de & operator=(const std::vector< value_type > &)
Sets up the individual with values from a vector.
Definition: i_de.cc:188
A single member of a population.
Definition: individual.h:41
MurmurHash3 (https://github.com/aappleby/smhasher) by Austin Appleby.
Definition: cache_hash.h:101
static hash_t hash128(const void *const, std::size_t, std::uint32_t=1973)
Hashes a single message in one call, return 128-bit output.
Definition: cache_hash.h:119
Aggregates the problem-related data needed by an evolutionary program.
Definition: problem.h:24
A container for the symbols used by the GP engine.
Definition: symbol_set.h:37
Contains flags and manipulators to control the output format of individuals.
The main namespace for the project.
std::pair< T, T > range_t
Right-open interval.
Definition: range.h:25
A 128bit unsigned integer used as individual's signature / hash table look-up key.
Definition: cache_hash.h:27
bool empty() const
We assume that a string of 128 zero bits means empty.
Definition: cache_hash.h:61
void clear()
Resets the content of the object.
Definition: cache_hash.h:31