34 :
individual(), genome_(p.env.mep.code_length, p.sset.categories()),
35 best_{0, 0}, active_crossover_type_(random::sup(NUM_CROSSOVERS))
46 for (
index_t i(0); i < patch; ++i)
51 for (
index_t i(patch); i < i_sup; ++i)
65i_mep::i_mep(
const std::vector<gene> &gv)
68 std::max_element(std::begin(gv), std::end(gv),
71 return g1.sym->category() < g2.sym->category();
72 })->sym->category() + 1),
74 active_crossover_type_(random::sup(NUM_CROSSOVERS))
78 for (
const auto &g : gv)
79 genome_(i++, g.sym->category()) = g;
105 return static_cast<unsigned>(std::distance(
begin(),
end()));
122 ret.signature_.
clear();
138 Expects(0.0 <= pgm && pgm <= 1.0);
142 const auto i_size(
size());
145 for (
auto i(
begin()); i !=
end(); ++i)
146 if (random::boolean(pgm))
148 const auto ix(i.locus().index);
149 const auto ct(i.locus().category);
183 for (
auto i(
begin()); i !=
end(); ++i)
185 bl.insert(i.locus());
203 ret.signature_.
clear();
229 Expects(index <
size());
236 ret.signature_.
clear();
247 return best().category;
259 const bool eq(genome_ == x.genome_);
263 || signature_ == x.signature_);
275 return !(lhs == rhs);
295 for (
index_t i(0); i < i_sup; ++i)
299 if (lhs[l] != rhs[l])
316void i_mep::pack(
const locus &l, std::vector<std::byte> *p)
const
318 const gene &g(genome_(l));
325 const auto opcode(
static_cast<std::uint16_t
>(g.sym->opcode()));
326 assert(g.sym->opcode() <= std::numeric_limits<
decltype(opcode)>::max());
328 auto s1 =
reinterpret_cast<const std::byte *
>(&opcode);
329 for (std::size_t i(0); i <
sizeof(opcode); ++i)
332 auto arity(g.sym->arity());
334 for (
const auto &al : g.arguments())
340 const auto param(g.par);
342 auto s2 =
reinterpret_cast<const std::byte *
>(¶m);
343 for (std::size_t i(0); i <
sizeof(param); ++i)
355hash_t i_mep::hash()
const
362 thread_local std::vector<std::byte> packed;
365 pack(
best(), &packed);
368 const auto len(packed.size() *
sizeof(packed[0]));
389 if (signature_.
empty())
402 if (!genome_.empty())
404 vitaERROR <<
"Inconsistent internal status for empty individual";
408 if (
best() != locus::npos())
410 vitaERROR <<
"Empty individual must have undefined best locus";
414 if (!signature_.
empty())
416 vitaERROR <<
"Empty individual and non-empty signature";
430 vitaERROR <<
"Empty symbol pointer at locus " << l;
435 const auto arity(genome_(l).sym->arity());
436 if (genome_(l).args.size() != arity)
438 vitaERROR <<
"Arity and actual arguments don't match";
443 for (
const auto &arg : genome_(l).args)
448 vitaERROR <<
"Argument is out of range";
455 vitaERROR <<
"Wrong reference in locus " << l;
462 if (!genome_(genome_.rows() - 1, c).sym->terminal())
464 vitaERROR <<
"Last symbol of type " << c
465 <<
" in the genome isn't a terminal";
475 if (genome_(l).sym->category() != c)
477 vitaERROR <<
"Wrong category: " << l << genome_(l).sym->name()
478 <<
" -> " << genome_(l).sym->category()
479 <<
" should be " << c;
486 vitaERROR <<
"Incorrect index for first active symbol";
491 vitaERROR <<
"Incorrect category for first active symbol";
497 vitaERROR <<
"`active_symbols()` cannot be greater than `size()` "
498 "in single-category individuals";
502 return signature_.
empty() || signature_ ==
hash();
514bool i_mep::load_impl(std::istream &in,
const symbol_set &ss)
517 if (!(in >> rows >> cols))
524 decltype(genome_) genome(rows, cols);
525 for (
auto &g : genome)
533 temp.sym = ss.
decode(opcode);
538 if (!(in >> temp.par))
541 auto arity(temp.sym->arity());
544 temp.args.resize(arity);
546 for (
auto &arg : temp.args)
554 auto best(locus::npos());
556 if (rows && !(in >>
best.index >>
best.category))
569bool i_mep::save_impl(std::ostream &
out)
const
571 out << genome_.rows() <<
' ' << genome_.cols() <<
'\n';
572 for (
const auto &g : genome_)
574 out << g.sym->opcode();
579 const auto arity(g.sym->arity());
580 for (
auto i(
decltype(arity){0}); i < arity; ++i)
581 out <<
' ' << g.args[i];
587 out <<
best().index <<
' ' <<
best().category <<
'\n';
613 bool operator()(
const gene &a,
const gene &b)
const
623 auto arity(a.sym->arity());
624 for (
decltype(arity) i(0); i < arity; ++i)
625 if (a.args[i] < b.args[i])
633 std::map<gene, locus, gene_cmp> new_locus;
636 for (
category_t c(0); c < genome_.cols(); ++c)
638 const locus current_locus({i - 1, c});
639 gene &g(ret.genome_(current_locus));
642 g.args.begin(), g.args.end(),
644 [&, i=0u](
auto arg) mutable -> gene::packed_index_t
646 const gene gene_arg(ret[g.locus_of_argument(i++)]);
647 const auto where(new_locus.find(gene_arg));
649 if (where == new_locus.end())
652 assert(where->second.index <=
653 std::numeric_limits<gene::packed_index_t>::max());
654 return where->second.index;
657 new_locus.try_emplace(g, current_locus);
738 const bool b(random::boolean());
739 const i_mep &from(b ? rhs : lhs);
740 i_mep to(b ? lhs : rhs);
742 switch (from.active_crossover_type_)
744 case i_mep::crossover_t::one_point:
746 const auto i_sup(from.
size());
748 const auto cut(random::between<index_t>(1, i_sup - 1));
750 for (
index_t i(cut); i < i_sup; ++i)
754 to.genome_(l) = from[l];
759 case i_mep::crossover_t::two_points:
761 const auto i_sup(from.
size());
764 const auto cut1(random::sup(i_sup - 1));
765 const auto cut2(random::between(cut1 + 1, i_sup));
767 for (
index_t i(cut1); i != cut2; ++i)
771 to.genome_(l) = from[l];
776 case i_mep::crossover_t::uniform:
778 const auto i_sup(from.
size());
781 for (
index_t i(0); i != i_sup; ++i)
783 if (random::boolean())
786 to.genome_(l) = from[l];
793 auto crossover_ = [&](
locus l,
const auto &lambda) ->
void
795 to.genome_(l) = from[l];
797 for (
const auto &al : from[l].arguments())
801 crossover_(random_locus(from), crossover_);
806 to.active_crossover_type_ = from.active_crossover_type_;
807 to.set_older_age(from.age());
808 to.signature_.
clear();
816 std::set exons({prg.
best()});
817 auto iter(exons.begin());
820 const auto args(prg[*iter].arguments());
821 exons.insert(args.begin(), args.end());
822 }
while (++iter != exons.end());
824 return random::element(std::as_const(exons));
829std::ostream &language(std::ostream &s,
symbol::format f,
const i_mep &mep)
831 std::function<std::string (
const gene &)> language_;
832 language_ = [&](
const gene &g)
834 std::string ret(g.sym->terminal()
838 auto arity(g.sym->arity());
839 for (
decltype(arity) i(0); i < arity; ++i)
841 const std::string from(
"%%" + std::to_string(i + 1) +
"%%");
842 ret = replace_all(ret, from,
843 language_(mep[g.locus_of_argument(i)]));
849 std::string
out(language_(mep[mep.best()]));
850 if (
out.length() > 2 &&
out.front() ==
'(' &&
out.back() ==
')')
856std::ostream &
dump(
const i_mep &mep, std::ostream &s)
860 const auto size(mep.size());
861 const auto categories(mep.categories());
863 const auto w1(1 +
static_cast<int>(std::log10(size - 1)));
864 const auto w2(1 +
static_cast<int>(std::log10(categories)));
866 for (
index_t i(0); i < size; ++i)
869 const gene &g(mep[{i, c}]);
871 s <<
'[' << std::setfill(
'0') << std::setw(w1) << i;
874 s <<
',' << std::setw(w2) << c;
878 for (
const auto &l : g.arguments())
880 s <<
" [" << std::setw(w1) << l.index;
882 s <<
',' << std::setw(w2) << l.category;
892void graphviz(
const i_mep &mep, std::ostream &s)
896 for (
auto i(mep.begin()); i != mep.end(); ++i)
898 s <<
'g' << i.locus().index <<
'_' << i.locus().category <<
" [label="
899 << *i <<
", shape=" << (i->sym->arity() ?
"box" :
"circle") <<
"];";
901 for (
unsigned j(0); j < i->sym->arity(); ++j)
902 s <<
'g' << i.locus().index <<
'_' << i.locus().category <<
" -- g"
909std::ostream &
in_line(
const i_mep &mep, std::ostream &s)
911 std::function<void (locus)> in_line_;
912 in_line_ = [&](locus l)
914 const gene &g(mep[l]);
920 for (
const auto &al : g.arguments())
924 in_line_(mep.best());
928std::ostream &
list(
const i_mep &mep, std::ostream &s)
932 const auto size(mep.size());
933 const auto categories(mep.categories());
935 const auto w1(1 +
static_cast<int>(std::log10(size - 1)));
936 const auto w2(1 +
static_cast<int>(std::log10(categories)));
938 const bool short_form(!out::long_form_flag(s));
940 for (
auto i(mep.begin()); i != mep.end(); ++i)
942 if (short_form && i->sym->terminal() && i.locus() != mep.best())
945 s <<
'[' << std::setfill(
'0') << std::setw(w1) << i.locus().index;
948 s <<
',' << std::setw(w2) << i.locus().category;
952 for (
const auto &l: i->arguments())
956 if (short_form && mep[l].sym->terminal())
960 s <<
'[' << std::setw(w1) << l.index;
962 s <<
',' << std::setw(w2) << l.category;
973std::ostream &
tree(
const i_mep &mep, std::ostream &s)
975 std::function<void (
const gene &,
const gene &,
unsigned)> tree_;
976 tree_ = [&](
const gene &parent,
const gene &child,
unsigned indent)
978 if (child == parent ||
979 parent.sym != child.sym ||
982 s << std::string(indent,
' ') << child <<
'\n';
986 for (
const auto &l : child.arguments())
987 tree_(child, mep[l], indent);
990 tree_(mep[mep.best()], mep[mep.best()], 0);
1005 const auto format(out::print_format_flag(s));
1010 return dump(ind, s);
1012 case out::graphviz_f:
1016 case out::in_line_f:
1017 return in_line(ind, s);
1020 return list(ind, s);
1023 return tree(ind, s);
1026 assert(format >= out::language_f);
1027 return language(s,
symbol::format(format - out::language_f), ind);
A gene is a unit of heredity in a living organism.
static const function * cast(const symbol *)
This is a short cut function.
category_t arg_category(std::size_t) const
virtual std::string display(format=c_format) const
virtual bool associative() const
Is the symbol subject to the associative law of arithmetic?
A MEP (Multi Expression Programming) single member of a population.
bool operator==(const i_mep &) const
hash_t signature() const
Signature maps syntactically distinct (but logically equivalent) individuals to the same value.
i_mep get_block(const locus &) const
std::ostream & operator<<(std::ostream &s, const i_mep &ind)
i_mep replace(const gene &) const
Creates a new individual obtained from this replacing the original symbol at locus best() with g.
std::set< locus > blocks() const
Calculates a set of loci referring to blocks contained in the individual.
unsigned distance(const i_mep &lhs, const i_mep &rhs)
i_mep destroy_block(index_t, const symbol_set &) const
category_t categories() const
i_mep crossover(const i_mep &lhs, const i_mep &rhs)
A Self-Adaptive Crossover operator.
category_t category() const
const_iterator begin() const
unsigned mutation(double, const problem &)
A new individual is created mutating this.
const_iterator end() const
unsigned active_symbols() const
Number of active symbols.
i_mep cse() const
A sort of "common subexpression elimination" optimization.
A single member of a population.
MurmurHash3 (https://github.com/aappleby/smhasher) by Austin Appleby.
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.
Aggregates the problem-related data needed by an evolutionary program.
A container for the symbols used by the GP engine.
symbol * decode(opcode_t) const
const symbol & roulette(category_t) const
Extracts a random symbol from the symbol set without bias between terminals and functions .
const terminal & roulette_terminal(category_t) const
format
Symbol rendering format.
opcode_t opcode() const
An opcode is a unique, numerical session ID for a symbol.
virtual bool parametric() const
A parametric terminal needs an additional parameter to be evaluated.
static const terminal * cast(const symbol *)
This is a short cut function.
virtual std::string display(terminal_param_t, format=c_format) const
std::ostream & graphviz(std::ostream &o)
Used to print a graph, in dot language, representing the individual.
std::ostream & list(std::ostream &o)
Used to print a human readable representation of the individual.
std::ostream & in_line(std::ostream &o)
Used to print the individual on a single line.
std::ostream & tree(std::ostream &o)
Used to print the individual as a tree structure.
std::ostream & short_form(std::ostream &o)
Hide secondary details of the individual.
std::ostream & dump(std::ostream &o)
Used to print the complete content of an individual.
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.
basic_gene< 4 > gene
A basic_gene with the standard size.
std::size_t category_t
A category provide operations which supplement or supersede those of the domain but which are restric...
unsigned opcode_t
This is the type used as key for symbol identification.
std::size_t patch_length
The number of symbols in the patch section (the tail section of the genome containing only terminals)...
A 128bit unsigned integer used as individual's signature / hash table look-up key.
bool empty() const
We assume that a string of 128 zero bits means empty.
void clear()
Resets the content of the object.