20 template<Brush::ProgramType T>
33 program.
Tree.replace(spot, *newNode);
48 template<Brush::ProgramType T>
52 vector<float> weights;
56 std::transform(program.
Tree.begin(), program.
Tree.end(), std::back_inserter(weights),
58 size_t d = 1+program.Tree.depth(iter);
59 std::advance(iter, 1);
62 if ((d >= params.get_max_depth())
63 || (variator.search_space.node_map.find(n.ret_type) == variator.search_space.node_map.end())) {
67 return n.get_prob_change();
73 weights.resize(program.Tree.size());
74 std::fill(weights.begin(), weights.end(), 0.0f);
80 template<Brush::ProgramType T>
84 auto spot_type = spot.node->data.ret_type;
95 spot_type, spot_type, params.
max_size-program.
Tree.size()-1);
101 auto parent_node = program.
Tree.wrap(spot, *n);
104 bool spot_filled =
false;
105 for (
auto a: (*n).arg_types)
115 program.
Tree.append_child(parent_node, opt.value());
118 else if (a == spot_type)
127 program.
Tree.insert(spot, opt.value());
144 template<Brush::ProgramType T>
156 program.
Tree.erase_children(spot);
158 program.
Tree.replace(spot, opt.value());
173 template<Brush::ProgramType T>
177 vector<float> weights(program.
Tree.size());
180 std::transform(program.
Tree.begin(), program.
Tree.end(), weights.begin(),
183 if (Is<NodeType::OffsetSum>(n.node_type) || Is<NodeType::Constant>(n.node_type))
187 if (!n.get_is_weighted()
188 && IsWeighable(n.node_type))
190 return n.get_prob_change();
198 std::fill(weights.begin(), weights.end(), 0.0f);
204 template<Brush::ProgramType T>
208 if (spot.node->data.get_is_weighted()==
true
212 spot.node->data.set_is_weighted(
true);
226 template<Brush::ProgramType T>
230 vector<float> weights(program.
Tree.size());
232 std::transform(program.
Tree.begin(), program.
Tree.end(), weights.begin(),
235 if (Is<NodeType::OffsetSum>(n.node_type) || Is<NodeType::Constant>(n.node_type))
238 if (n.get_is_weighted()
239 && IsWeighable(n.node_type))
240 return n.get_prob_change();
248 template<Brush::ProgramType T>
252 if (spot.node->data.get_is_weighted()==
false)
255 spot.node->data.set_is_weighted(
false);
269 template<Brush::ProgramType T>
273 vector<float> weights;
280 std::transform(program.
Tree.begin(), program.
Tree.end(), std::back_inserter(weights),
282 size_t d = program.Tree.depth(iter);
283 size_t s = program.Tree.size(iter);
284 std::advance(iter, 1);
287 if ((d >= params.max_depth)
288 || (node_map.find(n.ret_type) == node_map.end()) )
291 return n.get_prob_change();
297 template<Brush::ProgramType T>
309 auto spot_type = spot.node->data.ret_type;
322 s =
r.rnd_int(1, s+1);
333 program.
Tree.erase_children(spot);
335 program.
Tree.move_ontop(spot, subtree.value().begin());
350 template<Brush::ProgramType T>
354 vector<float> weights;
358 std::transform(program.
Tree.begin(), program.
Tree.end(), std::back_inserter(weights),
360 size_t d = 1+program.Tree.depth(iter);
361 std::advance(iter, 1);
364 if (d >= params.get_max_depth()
365 || variator.search_space.node_map.find(n.ret_type) == variator.search_space.node_map.end()
371 return n.get_prob_change();
377 weights.resize(program.Tree.size());
378 std::fill(weights.begin(), weights.end(), 0.0f);
384 template<Brush::ProgramType T>
415template<Brush::ProgramType T>
425 vector<float> child_weights(child.
Tree.size());
427 auto child_iter = child.
Tree.begin();
428 std::transform(child.
Tree.begin(), child.
Tree.end(), child_weights.begin(),
430 auto s_at = child.size_at(child_iter);
431 auto d_at = child.depth_to_reach(child_iter);
433 std::advance(child_iter, 1);
439 d_at<parameters.max_depth
441 return n.get_prob_change();
447 if (std::all_of(child_weights.begin(), child_weights.end(), [](
const auto& w) {
458 while (++attempts <= 3)
460 auto child_spot =
r.select_randomly(child.
Tree.begin(),
462 child_weights.begin(),
466 auto child_ret_type = child_spot.node->data.ret_type;
473 vector<float> other_weights(other.
Tree.size());
476 auto other_iter = other.
Tree.begin();
477 std::transform(other.
Tree.begin(), other.
Tree.end(), other_weights.begin(),
478 [&other, &other_iter, allowed_size, allowed_depth, child_ret_type](
const auto& n)
mutable {
479 int s = other.size_at(other_iter);
480 int d = other.depth_at(other_iter);
482 std::advance(other_iter, 1);
485 if (s <= allowed_size && d <= allowed_depth && n.ret_type == child_ret_type) {
486 return n.get_prob_change();
493 bool matching_spots_found = std::any_of(other_weights.begin(), other_weights.end(),
494 [](
float w) { return w > 0.0f; });
496 if (matching_spots_found) {
498 auto other_spot =
r.select_randomly(
501 other_weights.begin(),
507 child.
Tree.move_ontop(child_spot, other_spot);
559template<Brush::ProgramType T>
567 bool all_zero =
true;
569 if (it.second > 0.0) {
580 choice =
r.random_choice(
parameters.mutation_probs);
585 vector<float> weights;
586 if (choice.compare(
"point") == 0)
588 else if (choice.compare(
"insert") == 0)
590 else if (choice.compare(
"delete") == 0)
592 else if (choice.compare(
"subtree") == 0)
594 else if (choice.compare(
"toggle_weight_on") == 0)
596 else if (choice.compare(
"toggle_weight_off") == 0)
599 std::string msg = fmt::format(
"{} not a valid mutation choice", choice);
603 if (std::all_of(weights.begin(), weights.end(), [](
const auto& w) {
611 while(attempts++ < 3)
616 auto spot =
r.select_randomly(child.
Tree.begin(), child.
Tree.end(),
617 weights.begin(), weights.end());
624 if (choice.compare(
"point") == 0)
626 else if (choice.compare(
"insert") == 0)
628 else if (choice.compare(
"delete") == 0)
630 else if (choice.compare(
"subtree") == 0)
632 else if (choice.compare(
"toggle_weight_on") == 0)
656 if (choice.compare(
"point") == 0
657 || choice.compare(
"insert") == 0
658 || choice.compare(
"delete") == 0
673template<Brush::ProgramType T>
675 const vector<size_t>& parents)
679 for (
unsigned i = 0; i<indices.size(); ++i)
687 std::optional<Individual<T>> opt=std::nullopt;
690 *
r.select_randomly(parents.begin(), parents.end())];
692 vector<Individual<T>> ind_parents;
698 *
r.select_randomly(parents.begin(), parents.end())];
700 auto variation_result =
cross(mom, dad);
701 ind_parents = {mom, dad};
702 opt = variation_result;
706 auto variation_result =
mutate(mom);
709 opt = variation_result;
755 pop.
individuals.at(indices.at(i)) = std::make_shared<Individual<T>>(ind);
759template <Brush::ProgramType T>
770 if (variation_probs.find(
"cx") != variation_probs.end())
771 parameters.set_cx_prob(variation_probs.at(
"cx"));
773 for (
const auto& variation : variation_probs)
774 if (variation.first !=
"cx")
775 parameters.mutation_probs[variation.first] = variation.second;
779 auto datatype = bandit.first;
781 auto terminal_probs = bandit.second.sample_probs(
true);
783 for (
auto& [terminal_name, terminal_prob] : terminal_probs) {
785 auto it = std::find_if(
788 [&](
auto& node) { return node.get_feature() == terminal_name; });
791 auto index = std::distance(
search_space.terminal_map.at(datatype).begin(), it);
794 search_space.terminal_weights.at(datatype)[index] = terminal_prob;
800 for (
auto& [ret_type, bandit_map] :
op_bandits) {
801 for (
auto& [args_type, bandit] : bandit_map) {
802 auto op_probs = bandit.sample_probs(
true);
804 for (
auto& [op_name, op_prob] : op_probs) {
806 for (
const auto& [node_type, node_value]:
search_space.node_map.at(ret_type).at(args_type))
808 if (node_value.name == op_name) {
810 search_space.node_map_weights.at(ret_type).at(args_type).at(node_type) = op_prob;
void set_variation(string v)
void set_sampled_nodes(const vector< Node > &nodes)
Fitness fitness
aggregate fitness score
vector< string > get_objectives() const
void set_objectives(vector< string > objs)
void set_parents(const vector< Individual< T > > &parents)
void init(SearchSpace &ss, const Parameters ¶ms)
Program< T > program
executable data structure
vector< size_t > get_island_indexes(int island)
vector< std::shared_ptr< Individual< T > > > individuals
delete subtree and replace it with a terminal of the same return type
static auto mutate(Program< T > &program, Iter spot, Variation< T > &variator, const Parameters ¶ms)
insert a node with spot as a child
static auto mutate(Program< T > &program, Iter spot, Variation< T > &variator, const Parameters ¶ms)
static auto find_spots(Program< T > &program, Variation< T > &variator, const Parameters ¶ms)
static auto find_spots(Program< T > &program, Variation< T > &variator, const Parameters ¶ms)
tree< Node >::pre_order_iterator Iter
replace node with same typed node
static auto mutate(Program< T > &program, Iter spot, Variation< T > &variator, const Parameters ¶ms)
Inserts an split node in the spot
static auto find_spots(Program< T > &program, Variation< T > &variator, const Parameters ¶ms)
static auto mutate(Program< T > &program, Iter spot, Variation< T > &variator, const Parameters ¶ms)
replaces the subtree rooted in spot
static auto find_spots(Program< T > &program, Variation< T > &variator, const Parameters ¶ms)
static auto mutate(Program< T > &program, Iter spot, Variation< T > &variator, const Parameters ¶ms)
toggle the node's weight OFF
static auto find_spots(Program< T > &program, Variation< T > &variator, const Parameters ¶ms)
static auto mutate(Program< T > &program, Iter spot, Variation< T > &variator, const Parameters ¶ms)
toggle the node's weight ON
static auto mutate(Program< T > &program, Iter spot, Variation< T > &variator, const Parameters ¶ms)
static auto find_spots(Program< T > &program, Variation< T > &variator, const Parameters ¶ms)
Class representing the variation operators in Brush.
map< DataType, map< size_t, Bandit > > op_bandits
void vary(Population< T > &pop, int island, const vector< size_t > &parents)
Handles variation of a population.
std::optional< Node > bandit_sample_op_with_arg(DataType ret, DataType arg, int max_args=0)
std::optional< Individual< T > > cross(const Individual< T > &mom, const Individual< T > &dad)
Performs croearch_spaceover operation on two individuals.
std::optional< Node > bandit_sample_terminal(DataType R)
std::optional< Node > bandit_get_node_like(Node node)
map< DataType, Bandit > terminal_bandits
std::optional< Individual< T > > mutate(const Individual< T > &parent, string choice="")
Performs mutation operation on an individual.
#define HANDLE_ERROR_THROW(err)
< nsga2 selection operator for getting the front
auto IsWeighable() noexcept -> bool
void set_linear_complexity(unsigned int new_lc)
void set_complexity(unsigned int new_c)
void set_loss_v(float f_v)
void set_depth(unsigned int new_d)
unsigned int get_complexity() const
void set_size(unsigned int new_s)
unsigned int get_depth() const
unsigned int get_linear_complexity() const
unsigned int get_size() const
unsigned get_max_size() const
An individual program, a.k.a. model.
int size_at(Iter &top, bool include_weight=true) const
count the size of a given subtree, optionally including the weights in weighted nodes....
int depth() const
count the tree depth of the program. The depth is not influenced by weighted nodes.
int depth_to_reach(Iter &top) const
count the depth until reaching the given subtree. The depth is not influenced by weighted nodes....
int size(bool include_weight=true) const
count the tree size of the program, including the weights in weighted nodes.
Map< Node > node_map
Maps return types to argument types to node types.
std::optional< tree< Node > > sample_subtree(Node root, int max_d, int max_size) const
create a subtree with maximum size and depth restrictions and root of type root_type