Vita
i_mep.cc
Go to the documentation of this file.
1
13#include <algorithm>
14#include <functional>
15#include <map>
16#include <utility>
17
18#include "kernel/gp/mep/i_mep.h"
19#include "kernel/cache_hash.h"
20#include "kernel/log.h"
21#include "kernel/random.h"
22
23namespace vita
24{
33i_mep::i_mep(const problem &p)
34 : individual(), genome_(p.env.mep.code_length, p.sset.categories()),
35 best_{0, 0}, active_crossover_type_(random::sup(NUM_CROSSOVERS))
36{
37 Expects(size());
38 Expects(p.env.mep.patch_length);
39 Expects(size() > p.env.mep.patch_length);
40 Expects(categories());
41
42 const index_t i_sup(size()), patch(i_sup - p.env.mep.patch_length);
43 const category_t c_sup(categories());
44
45 // STANDARD SECTION. Filling the genome with random symbols.
46 for (index_t i(0); i < patch; ++i)
47 for (category_t c(0); c < c_sup; ++c)
48 genome_(i, c) = gene(p.sset.roulette(c), i + 1, i_sup);
49
50 // PATCH SUBSECTION. Placing terminals for satisfying constraints on types.
51 for (index_t i(patch); i < i_sup; ++i)
52 for (category_t c(0); c < c_sup; ++c)
53 genome_(i, c) = gene(p.sset.roulette_terminal(c));
54
55 Ensures(is_valid());
56}
57
65i_mep::i_mep(const std::vector<gene> &gv)
66 : individual(),
67 genome_(gv.size(),
68 std::max_element(std::begin(gv), std::end(gv),
69 [](gene g1, gene g2)
70 {
71 return g1.sym->category() < g2.sym->category();
72 })->sym->category() + 1),
73 best_{0, 0},
74 active_crossover_type_(random::sup(NUM_CROSSOVERS))
75{
76 index_t i(0);
77
78 for (const auto &g : gv)
79 genome_(i++, g.sym->category()) = g;
80
81 Ensures(is_valid());
82}
83
84
103unsigned i_mep::active_symbols() const
104{
105 return static_cast<unsigned>(std::distance(begin(), end()));
106}
107
116{
117 i_mep ret(*this);
118
119 if (ret.best_ != l)
120 {
121 ret.best_ = l;
122 ret.signature_.clear();
123 }
124
125 Ensures(ret.is_valid());
126 return ret;
127}
128
136unsigned i_mep::mutation(double pgm, const problem &prb)
137{
138 Expects(0.0 <= pgm && pgm <= 1.0);
139
140 unsigned n(0);
141
142 const auto i_size(size());
143 const auto patch(i_size - prb.env.mep.patch_length);
144
145 for (auto i(begin()); i != end(); ++i) // here mutation affects only exons
146 if (random::boolean(pgm))
147 {
148 const auto ix(i.locus().index);
149 const auto ct(i.locus().category);
150
151 const gene g(ix < patch ? gene(prb.sset.roulette(ct), ix + 1, i_size)
152 : gene(prb.sset.roulette_terminal(ct)));
153
154 if (*i != g)
155 {
156 ++n;
157 *i = g;
158 }
159 }
160
161 if (n)
162 signature_.clear();
163
164 Ensures(is_valid());
165 return n;
166}
167
179std::set<locus> i_mep::blocks() const
180{
181 std::set<locus> bl;
182
183 for (auto i(begin()); i != end(); ++i)
184 if (i->sym->arity())
185 bl.insert(i.locus());
186
187 return bl;
188}
189
198i_mep i_mep::replace(const locus &l, const gene &g) const
199{
200 i_mep ret(*this);
201
202 ret.genome_(l) = g;
203 ret.signature_.clear();
204
205 Ensures(ret.is_valid());
206 return ret;
207}
208
216i_mep i_mep::replace(const gene &g) const
217{
218 return replace(best(), g);
219}
220
228{
229 Expects(index < size());
230
231 i_mep ret(*this);
232 const category_t c_sup(categories());
233 for (category_t c(0); c < c_sup; ++c)
234 ret.genome_(index, c) = gene(sset.roulette_terminal(c));
235
236 ret.signature_.clear();
237
238 Ensures(ret.is_valid());
239 return ret;
240}
241
246{
247 return best().category;
248}
249
257bool i_mep::operator==(const i_mep &x) const
258{
259 const bool eq(genome_ == x.genome_);
260
261 Ensures(!eq
262 || signature_.empty() != x.signature_.empty()
263 || signature_ == x.signature_);
264
265 return eq;
266}
267
273bool operator!=(const i_mep &lhs, const i_mep &rhs)
274{
275 return !(lhs == rhs);
276}
277
286unsigned distance(const i_mep &lhs, const i_mep &rhs)
287{
288 Expects(lhs.size() == rhs.size());
289 Expects(lhs.categories() == rhs.categories());
290
291 const index_t i_sup(lhs.size());
292 const category_t c_sup(lhs.categories());
293
294 unsigned d(0);
295 for (index_t i(0); i < i_sup; ++i)
296 for (category_t c(0); c < c_sup; ++c)
297 {
298 const locus l{i, c};
299 if (lhs[l] != rhs[l])
300 ++d;
301 }
302
303 return d;
304}
305
316void i_mep::pack(const locus &l, std::vector<std::byte> *p) const
317{
318 const gene &g(genome_(l));
319
320 // Although 16 bit are enough to contain opcodes and parameters, they are
321 // usually stored in unsigned variables (i.e. 32 or 64 bit) for performance
322 // reasons.
323 // Anyway before hashing opcodes/parameters we convert them to 16 bit types
324 // to avoid hashing more than necessary.
325 const auto opcode(static_cast<std::uint16_t>(g.sym->opcode()));
326 assert(g.sym->opcode() <= std::numeric_limits<decltype(opcode)>::max());
327
328 auto s1 = reinterpret_cast<const std::byte *>(&opcode);
329 for (std::size_t i(0); i < sizeof(opcode); ++i)
330 p->push_back(s1[i]);
331
332 auto arity(g.sym->arity());
333 if (arity)
334 for (const auto &al : g.arguments())
335 pack(al, p);
336 else
337 {
338 if (terminal::cast(g.sym)->parametric())
339 {
340 const auto param(g.par);
341
342 auto s2 = reinterpret_cast<const std::byte *>(&param);
343 for (std::size_t i(0); i < sizeof(param); ++i)
344 p->push_back(s2[i]);
345 }
346 }
347}
348
355hash_t i_mep::hash() const
356{
357 Expects(size());
358 // if (empty())
359 // return hash_t();
360
361 // From an individual to a packed byte stream...
362 thread_local std::vector<std::byte> packed;
363
364 packed.clear();
365 pack(best(), &packed);
366
368 const auto len(packed.size() * sizeof(packed[0])); // length in bytes
369
370 return vita::hash::hash128(packed.data(), len);
371}
372
388{
389 if (signature_.empty())
390 signature_ = hash();
391
392 return signature_;
393}
394
398bool i_mep::is_valid() const
399{
400 if (empty())
401 {
402 if (!genome_.empty())
403 {
404 vitaERROR << "Inconsistent internal status for empty individual";
405 return false;
406 }
407
408 if (best() != locus::npos())
409 {
410 vitaERROR << "Empty individual must have undefined best locus";
411 return false;
412 }
413
414 if (!signature_.empty())
415 {
416 vitaERROR << "Empty individual and non-empty signature";
417 return false;
418 }
419
420 return true;
421 }
422
423 for (index_t i(0); i < size(); ++i)
424 for (category_t c(0); c < categories(); ++c)
425 {
426 const locus l{i, c};
427
428 if (!genome_(l).sym)
429 {
430 vitaERROR << "Empty symbol pointer at locus " << l;
431 return false;
432 }
433
434 // Correspondence between arity of the symbol and numbers of parameters.
435 const auto arity(genome_(l).sym->arity());
436 if (genome_(l).args.size() != arity)
437 {
438 vitaERROR << "Arity and actual arguments don't match";
439 return false;
440 }
441
442 // Checking arguments' addresses.
443 for (const auto &arg : genome_(l).args)
444 {
445 // Arguments' addresses must be smaller than the size of the genome.
446 if (arg >= size())
447 {
448 vitaERROR << "Argument is out of range";
449 return false;
450 }
451
452 // Function address must be smaller than its arguments' addresses.
453 if (arg <= i)
454 {
455 vitaERROR << "Wrong reference in locus " << l;
456 return false;
457 }
458 }
459 }
460
461 for (category_t c(0); c < categories(); ++c)
462 if (!genome_(genome_.rows() - 1, c).sym->terminal())
463 {
464 vitaERROR << "Last symbol of type " << c
465 << " in the genome isn't a terminal";
466 return false;
467 }
468
469 // Type checking.
470 for (index_t i(0); i < size(); ++i)
471 for (category_t c(0); c < categories(); ++c)
472 {
473 const locus l{i, c};
474
475 if (genome_(l).sym->category() != c)
476 {
477 vitaERROR << "Wrong category: " << l << genome_(l).sym->name()
478 << " -> " << genome_(l).sym->category()
479 << " should be " << c;
480 return false;
481 }
482 }
483
484 if (best().index >= size())
485 {
486 vitaERROR << "Incorrect index for first active symbol";
487 return false;
488 }
489 if (best().category >= categories())
490 {
491 vitaERROR << "Incorrect category for first active symbol";
492 return false;
493 }
494
495 if (categories() == 1 && active_symbols() > size())
496 {
497 vitaERROR << "`active_symbols()` cannot be greater than `size()` "
498 "in single-category individuals";
499 return false;
500 }
501
502 return signature_.empty() || signature_ == hash();
503}
504
514bool i_mep::load_impl(std::istream &in, const symbol_set &ss)
515{
516 unsigned rows, cols;
517 if (!(in >> rows >> cols))
518 return false;
519
520 // The matrix class has a basic support for serialization but we cannot
521 // take advantage of it here: the gene class needs a special management
522 // (among other things it needs access to the symbol_set to decode the
523 // symbols).
524 decltype(genome_) genome(rows, cols);
525 for (auto &g : genome)
526 {
527 opcode_t opcode;
528 if (!(in >> opcode))
529 return false;
530
531 gene temp;
532
533 temp.sym = ss.decode(opcode);
534 if (!temp.sym)
535 return false;
536
537 if (temp.sym->terminal() && terminal::cast(temp.sym)->parametric())
538 if (!(in >> temp.par))
539 return false;
540
541 auto arity(temp.sym->arity());
542 if (arity)
543 {
544 temp.args.resize(arity);
545
546 for (auto &arg : temp.args)
547 if (!(in >> arg))
548 return false;
549 }
550
551 g = temp;
552 }
553
554 auto best(locus::npos());
555
556 if (rows && !(in >> best.index >> best.category))
557 return false;
558
559 best_ = best;
560 genome_ = genome;
561
562 return true;
563}
564
569bool i_mep::save_impl(std::ostream &out) const
570{
571 out << genome_.rows() << ' ' << genome_.cols() << '\n';
572 for (const auto &g : genome_)
573 {
574 out << g.sym->opcode();
575
576 if (g.sym->terminal() && terminal::cast(g.sym)->parametric())
577 out << ' ' << g.par;
578
579 const auto arity(g.sym->arity());
580 for (auto i(decltype(arity){0}); i < arity; ++i)
581 out << ' ' << g.args[i];
582
583 out << '\n';
584 }
585
586 if (!empty())
587 out << best().index << ' ' << best().category << '\n';
588
589 return out.good();
590}
591
606{
607 i_mep ret(*this);
608
609 // std::map needs a compare function and there isn't a predefined less
610 // operator for gene class.
611 struct gene_cmp
612 {
613 bool operator()(const gene &a, const gene &b) const
614 {
615 if (a.sym->opcode() < b.sym->opcode())
616 return true;
617
618 if (a.sym->opcode() == b.sym->opcode())
619 {
620 if (a.sym->terminal())
621 return terminal::cast(a.sym)->parametric() ? a.par < b.par : false;
622
623 auto arity(a.sym->arity());
624 for (decltype(arity) i(0); i < arity; ++i)
625 if (a.args[i] < b.args[i])
626 return true;
627 }
628
629 return false;
630 }
631 };
632
633 std::map<gene, locus, gene_cmp> new_locus;
634
635 for (index_t i(size()); i > 0; --i)
636 for (category_t c(0); c < genome_.cols(); ++c)
637 {
638 const locus current_locus({i - 1, c});
639 gene &g(ret.genome_(current_locus));
640
641 std::transform(
642 g.args.begin(), g.args.end(),
643 g.args.begin(),
644 [&, i=0u](auto arg) mutable -> gene::packed_index_t
645 {
646 const gene gene_arg(ret[g.locus_of_argument(i++)]);
647 const auto where(new_locus.find(gene_arg));
648
649 if (where == new_locus.end())
650 return arg;
651
652 assert(where->second.index <=
653 std::numeric_limits<gene::packed_index_t>::max());
654 return where->second.index;
655 });
656
657 new_locus.try_emplace(g, current_locus);
658 }
659
660 return ret;
661}
662
734i_mep crossover(const i_mep &lhs, const i_mep &rhs)
735{
736 Expects(lhs.size() == rhs.size());
737
738 const bool b(random::boolean());
739 const i_mep &from(b ? rhs : lhs);
740 i_mep to(b ? lhs : rhs);
741
742 switch (from.active_crossover_type_)
743 {
744 case i_mep::crossover_t::one_point:
745 {
746 const auto i_sup(from.size());
747 const auto c_sup(from.categories());
748 const auto cut(random::between<index_t>(1, i_sup - 1));
749
750 for (index_t i(cut); i < i_sup; ++i)
751 for (category_t c(0); c < c_sup; ++c)
752 {
753 const locus l{i, c};
754 to.genome_(l) = from[l];
755 }
756 }
757 break;
758
759 case i_mep::crossover_t::two_points:
760 {
761 const auto i_sup(from.size());
762 const auto c_sup(from.categories());
763
764 const auto cut1(random::sup(i_sup - 1));
765 const auto cut2(random::between(cut1 + 1, i_sup));
766
767 for (index_t i(cut1); i != cut2; ++i)
768 for (category_t c(0); c < c_sup; ++c)
769 {
770 const locus l{i, c};
771 to.genome_(l) = from[l];
772 }
773 }
774 break;
775
776 case i_mep::crossover_t::uniform:
777 {
778 const auto i_sup(from.size());
779 const auto c_sup(from.categories());
780
781 for (index_t i(0); i != i_sup; ++i)
782 for (category_t c(0); c < c_sup; ++c)
783 if (random::boolean())
784 {
785 const locus l{i, c};
786 to.genome_(l) = from[l];
787 }
788 }
789 break;
790
791 default: // Tree crossover
792 {
793 auto crossover_ = [&](locus l, const auto &lambda) -> void
794 {
795 to.genome_(l) = from[l];
796
797 for (const auto &al : from[l].arguments())
798 lambda(al, lambda);
799 };
800
801 crossover_(random_locus(from), crossover_);
802 }
803 break;
804 }
805
806 to.active_crossover_type_ = from.active_crossover_type_;
807 to.set_older_age(from.age());
808 to.signature_.clear();
809
810 Ensures(to.is_valid());
811 return to;
812}
813
814locus random_locus(const i_mep &prg)
815{
816 std::set exons({prg.best()});
817 auto iter(exons.begin());
818 do
819 {
820 const auto args(prg[*iter].arguments());
821 exons.insert(args.begin(), args.end());
822 } while (++iter != exons.end());
823
824 return random::element(std::as_const(exons));
825}
826
827namespace
828{
829std::ostream &language(std::ostream &s, symbol::format f, const i_mep &mep)
830{
831 std::function<std::string (const gene &)> language_;
832 language_ = [&](const gene &g)
833 {
834 std::string ret(g.sym->terminal()
835 ? terminal::cast(g.sym)->display(g.par, f)
836 : function::cast(g.sym)->display(f));
837
838 auto arity(g.sym->arity());
839 for (decltype(arity) i(0); i < arity; ++i)
840 {
841 const std::string from("%%" + std::to_string(i + 1) + "%%");
842 ret = replace_all(ret, from,
843 language_(mep[g.locus_of_argument(i)]));
844 }
845
846 return ret;
847 };
848
849 std::string out(language_(mep[mep.best()]));
850 if (out.length() > 2 && out.front() == '(' && out.back() == ')')
851 out = out.substr(1, out.length() - 2);
852
853 return s << out;
854}
855
856std::ostream &dump(const i_mep &mep, std::ostream &s)
857{
858 SAVE_FLAGS(s);
859
860 const auto size(mep.size());
861 const auto categories(mep.categories());
862
863 const auto w1(1 + static_cast<int>(std::log10(size - 1)));
864 const auto w2(1 + static_cast<int>(std::log10(categories)));
865
866 for (index_t i(0); i < size; ++i)
867 for (category_t c(0); c < categories; ++c)
868 {
869 const gene &g(mep[{i, c}]);
870
871 s << '[' << std::setfill('0') << std::setw(w1) << i;
872
873 if (categories > 1)
874 s << ',' << std::setw(w2) << c;
875
876 s << "] " << g;
877
878 for (const auto &l : g.arguments())
879 {
880 s << " [" << std::setw(w1) << l.index;
881 if (categories > 1)
882 s << ',' << std::setw(w2) << l.category;
883 s << ']';
884 }
885
886 s << '\n';
887 }
888
889 return s;
890}
891
892void graphviz(const i_mep &mep, std::ostream &s)
893{
894 s << "graph {";
895
896 for (auto i(mep.begin()); i != mep.end(); ++i)
897 {
898 s << 'g' << i.locus().index << '_' << i.locus().category << " [label="
899 << *i << ", shape=" << (i->sym->arity() ? "box" : "circle") << "];";
900
901 for (unsigned j(0); j < i->sym->arity(); ++j)
902 s << 'g' << i.locus().index << '_' << i.locus().category << " -- g"
903 << i->args[j] << '_' << function::cast(i->sym)->arg_category(j) << ';';
904 }
905
906 s << '}';
907}
908
909std::ostream &in_line(const i_mep &mep, std::ostream &s)
910{
911 std::function<void (locus)> in_line_;
912 in_line_ = [&](locus l)
913 {
914 const gene &g(mep[l]);
915
916 if (l != mep.best())
917 s << ' ';
918 s << g;
919
920 for (const auto &al : g.arguments())
921 in_line_(al);
922 };
923
924 in_line_(mep.best());
925 return s;
926}
927
928std::ostream &list(const i_mep &mep, std::ostream &s)
929{
930 SAVE_FLAGS(s);
931
932 const auto size(mep.size());
933 const auto categories(mep.categories());
934
935 const auto w1(1 + static_cast<int>(std::log10(size - 1)));
936 const auto w2(1 + static_cast<int>(std::log10(categories)));
937
938 const bool short_form(!out::long_form_flag(s));
939
940 for (auto i(mep.begin()); i != mep.end(); ++i)
941 {
942 if (short_form && i->sym->terminal() && i.locus() != mep.best())
943 continue;
944
945 s << '[' << std::setfill('0') << std::setw(w1) << i.locus().index;
946
947 if (categories > 1)
948 s << ',' << std::setw(w2) << i.locus().category;
949
950 s << "] " << *i;
951
952 for (const auto &l: i->arguments())
953 {
954 s << ' ';
955
956 if (short_form && mep[l].sym->terminal())
957 s << mep[l];
958 else
959 {
960 s << '[' << std::setw(w1) << l.index;
961 if (categories > 1)
962 s << ',' << std::setw(w2) << l.category;
963 s << ']';
964 }
965 }
966
967 s << '\n';
968 }
969
970 return s;
971}
972
973std::ostream &tree(const i_mep &mep, std::ostream &s)
974{
975 std::function<void (const gene &, const gene &, unsigned)> tree_;
976 tree_ = [&](const gene &parent, const gene &child, unsigned indent)
977 {
978 if (child == parent ||
979 parent.sym != child.sym ||
980 function::cast(parent.sym)->associative() == false)
981 {
982 s << std::string(indent, ' ') << child << '\n';
983 indent += 2;
984 }
985
986 for (const auto &l : child.arguments())
987 tree_(child, mep[l], indent);
988 };
989
990 tree_(mep[mep.best()], mep[mep.best()], 0);
991 return s;
992}
993
994} // namespace
995
1003std::ostream &operator<<(std::ostream &s, const i_mep &ind)
1004{
1005 const auto format(out::print_format_flag(s));
1006
1007 switch (format)
1008 {
1009 case out::dump_f:
1010 return dump(ind, s);
1011
1012 case out::graphviz_f:
1013 graphviz(ind, s);
1014 return s;
1015
1016 case out::in_line_f:
1017 return in_line(ind, s);
1018
1019 case out::list_f:
1020 return list(ind, s);
1021
1022 case out::tree_f:
1023 return tree(ind, s);
1024
1025 default:
1026 assert(format >= out::language_f);
1027 return language(s, symbol::format(format - out::language_f), ind);
1028 }
1029}
1030
1031} // namespace vita
A gene is a unit of heredity in a living organism.
Definition: gene.h:34
static const function * cast(const symbol *)
This is a short cut function.
Definition: function.h:101
category_t arg_category(std::size_t) const
Definition: function.h:89
virtual std::string display(format=c_format) const
Definition: function.cc:52
virtual bool associative() const
Is the symbol subject to the associative law of arithmetic?
Definition: function.h:80
A MEP (Multi Expression Programming) single member of a population.
Definition: i_mep.h:34
bool operator==(const i_mep &) const
Definition: i_mep.cc:257
hash_t signature() const
Signature maps syntactically distinct (but logically equivalent) individuals to the same value.
Definition: i_mep.cc:387
i_mep get_block(const locus &) const
Definition: i_mep.cc:115
bool empty() const
Definition: i_mep.h:157
std::ostream & operator<<(std::ostream &s, const i_mep &ind)
Definition: i_mep.cc:1003
i_mep replace(const gene &) const
Creates a new individual obtained from this replacing the original symbol at locus best() with g.
Definition: i_mep.cc:216
std::set< locus > blocks() const
Calculates a set of loci referring to blocks contained in the individual.
Definition: i_mep.cc:179
unsigned distance(const i_mep &lhs, const i_mep &rhs)
Definition: i_mep.cc:286
bool is_valid() const
Definition: i_mep.cc:398
locus best() const
Definition: i_mep.h:119
i_mep destroy_block(index_t, const symbol_set &) const
Definition: i_mep.cc:227
category_t categories() const
Definition: i_mep.h:136
i_mep crossover(const i_mep &lhs, const i_mep &rhs)
A Self-Adaptive Crossover operator.
Definition: i_mep.cc:734
category_t category() const
Definition: i_mep.cc:245
const_iterator begin() const
Definition: i_mep.h:171
unsigned size() const
Definition: i_mep.h:149
unsigned mutation(double, const problem &)
A new individual is created mutating this.
Definition: i_mep.cc:136
const_iterator end() const
Definition: i_mep.h:179
unsigned active_symbols() const
Number of active symbols.
Definition: i_mep.cc:103
i_mep cse() const
A sort of "common subexpression elimination" optimization.
Definition: i_mep.cc:605
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
symbol * decode(opcode_t) const
Definition: symbol_set.cc:179
const symbol & roulette(category_t) const
Extracts a random symbol from the symbol set without bias between terminals and functions .
Definition: symbol_set.cc:143
const terminal & roulette_terminal(category_t) const
Definition: symbol_set.cc:113
format
Symbol rendering format.
Definition: symbol.h:39
bool terminal() const
Definition: symbol.h:153
opcode_t opcode() const
An opcode is a unique, numerical session ID for a symbol.
Definition: symbol.h:145
virtual bool parametric() const
A parametric terminal needs an additional parameter to be evaluated.
Definition: terminal.h:59
static const terminal * cast(const symbol *)
This is a short cut function.
Definition: terminal.h:83
virtual std::string display(terminal_param_t, format=c_format) const
Definition: terminal.cc:24
std::ostream & graphviz(std::ostream &o)
Used to print a graph, in dot language, representing the individual.
Definition: individual.cc:124
std::ostream & list(std::ostream &o)
Used to print a human readable representation of the individual.
Definition: individual.cc:154
std::ostream & in_line(std::ostream &o)
Used to print the individual on a single line.
Definition: individual.cc:137
std::ostream & tree(std::ostream &o)
Used to print the individual as a tree structure.
Definition: individual.cc:165
std::ostream & short_form(std::ostream &o)
Hide secondary details of the individual.
Definition: individual.cc:187
std::ostream & dump(std::ostream &o)
Used to print the complete content of an individual.
Definition: individual.cc:112
Contains flags and manipulators to control the output format of individuals.
The main namespace for the project.
std::size_t index_t
Index in the genome.
Definition: locus.h:25
basic_gene< 4 > gene
A basic_gene with the standard size.
Definition: gene.h:73
std::size_t category_t
A category provide operations which supplement or supersede those of the domain but which are restric...
Definition: common.h:44
unsigned opcode_t
This is the type used as key for symbol identification.
Definition: symbol.h:26
std::size_t patch_length
The number of symbols in the patch section (the tail section of the genome containing only terminals)...
Definition: environment.h:86
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