5
5
#include < random>
6
6
7
7
#include " operon/core/contracts.hpp"
8
+ #include " operon/formatter/formatter.hpp"
8
9
#include " operon/operators/crossover.hpp"
9
10
#include " operon/random/random.hpp"
10
11
11
12
namespace Operon {
12
-
13
13
namespace {
14
- using Limits = std::pair<size_t , size_t >;
15
-
14
+ using Limits = std::pair<std::size_t , std::size_t >;
16
15
auto NotIn (Limits t, size_t v) -> bool {
17
16
auto [a, b] = t;
18
17
return v < a || b < v;
19
18
}
20
19
} // namespace
21
20
22
- static auto SelectRandomBranch (Operon::RandomGenerator& random, Tree const & tree, double internalProb, Limits length, Limits level, Limits depth) -> size_t
21
+ auto CrossoverBase::FindCompatibleSwapLocations (Operon::RandomGenerator& random, Tree const & lhs, Tree const & rhs, size_t maxDepth, size_t maxLength, double internalProbability) -> std::pair<size_t, size_t>
22
+ {
23
+ using Signed = std::make_signed_t <size_t >;
24
+ auto diff = static_cast <Signed>(lhs.Length () - maxLength + 1 ); // +1 to account for at least one node that gets swapped in
25
+
26
+ auto i = SelectRandomBranch (random , lhs, internalProbability, Limits{std::max (diff, Signed{1 }), lhs.Length ()}, Limits{size_t {1 }, lhs.Depth ()}, Limits{size_t {1 }, lhs.Depth ()});
27
+ // we have to make some small allowances here due to the fact that the provided trees
28
+ // might actually be larger than the maxDepth and maxLength limits given here
29
+ auto maxBranchDepth = static_cast <Signed>(maxDepth - lhs[i].Level );
30
+ maxBranchDepth = std::max (maxBranchDepth, Signed{1 });
31
+
32
+ auto partialTreeLength = (lhs.Length () - (lhs[i].Length + 1 ));
33
+ auto maxBranchLength = static_cast <Signed>(maxLength - partialTreeLength);
34
+ maxBranchLength = std::max (maxBranchLength, Signed{1 });
35
+
36
+ auto j = SelectRandomBranch (random , rhs, internalProbability, Limits{1UL , maxBranchLength}, Limits{1UL , rhs.Depth ()}, Limits{1UL , maxBranchDepth});
37
+ return std::make_pair (i, j);
38
+ }
39
+
40
+ auto CrossoverBase::SelectRandomBranch (Operon::RandomGenerator& random, Tree const & tree, double internalProb, Limits length, Limits level, Limits depth) -> size_t
23
41
{
24
42
if (tree.Length () == 1 ) {
25
43
return 0 ;
@@ -54,31 +72,27 @@ static auto SelectRandomBranch(Operon::RandomGenerator& random, Tree const& tree
54
72
return *Operon::Random::Sample (random , candidates.rbegin (), tail);
55
73
}
56
74
return *Operon::Random::Sample (random , candidates.begin (), head);
57
-
58
75
}
59
76
60
- auto SubtreeCrossover::FindCompatibleSwapLocations (Operon::RandomGenerator& random, Tree const & lhs, Tree const & rhs) const -> std::pair<size_t, size_t>
61
- {
62
- using Signed = std::make_signed<size_t >::type;
63
- auto diff = static_cast <Signed>(lhs.Length () - maxLength_ + 1 ); // +1 to account for at least one node that gets swapped in
64
77
65
- auto i = SelectRandomBranch (random , lhs, internalProbability_, Limits{std::max (diff, Signed{1 }), lhs.Length ()}, Limits{size_t {1 }, lhs.Depth ()}, Limits{size_t {1 }, lhs.Depth ()});
66
- // we have to make some small allowances here due to the fact that the provided trees
67
- // might actually be larger than the maxDepth and maxLength limits given here
68
- auto maxBranchDepth = static_cast <Signed>(maxDepth_ - lhs[i].Level );
69
- maxBranchDepth = std::max (maxBranchDepth, Signed{1 });
70
-
71
- auto partialTreeLength = (lhs.Length () - (lhs[i].Length + 1 ));
72
- auto maxBranchLength = static_cast <Signed>(maxLength_ - partialTreeLength);
73
- maxBranchLength = std::max (maxBranchLength, Signed{1 });
74
-
75
- auto j = SelectRandomBranch (random , rhs, internalProbability_, Limits{1UL , maxBranchLength}, Limits{1UL , rhs.Depth ()}, Limits{1UL , maxBranchDepth});
76
- return std::make_pair (i, j);
78
+ auto CrossoverBase::Cross (const Tree& lhs, const Tree& rhs, /* index of subtree 1 */ size_t i, /* index of subtree 2 */ size_t j) -> Tree
79
+ {
80
+ auto const & left = lhs.Nodes ();
81
+ auto const & right = rhs.Nodes ();
82
+ Operon::Vector<Node> nodes;
83
+ using Signed = std::make_signed_t <size_t >;
84
+ nodes.reserve (right[j].Length - left[i].Length + left.size ());
85
+ std::copy_n (left.begin (), i - left[i].Length , back_inserter (nodes));
86
+ std::copy_n (right.begin () + static_cast <Signed>(j) - right[j].Length , right[j].Length + 1 , back_inserter (nodes));
87
+ std::copy_n (left.begin () + static_cast <Signed>(i) + 1 , left.size () - (i + 1 ), back_inserter (nodes));
88
+
89
+ auto child = Tree (nodes).UpdateNodes ();
90
+ return child;
77
91
}
78
92
79
93
auto SubtreeCrossover::operator ()(Operon::RandomGenerator& random, const Tree& lhs, const Tree& rhs) const -> Tree
80
94
{
81
- auto [i, j] = FindCompatibleSwapLocations (random , lhs, rhs);
95
+ auto [i, j] = FindCompatibleSwapLocations (random , lhs, rhs, maxDepth_, maxLength_, internalProbability_ );
82
96
auto child = Cross (lhs, rhs, i, j);
83
97
84
98
auto maxDepth{std::max (maxDepth_, lhs.Depth ())};
@@ -90,3 +104,4 @@ auto SubtreeCrossover::operator()(Operon::RandomGenerator& random, const Tree& l
90
104
return child;
91
105
}
92
106
} // namespace Operon
107
+
0 commit comments