20 template<Brush::ProgramType T>
35 program.
Tree.replace(spot, *newNode);
50 template<Brush::ProgramType T>
54 vector<float> weights;
58 std::transform(program.
Tree.begin(), program.
Tree.end(), std::back_inserter(weights),
60 size_t d = 1+program.Tree.depth(iter);
61 std::advance(iter, 1);
64 if ((d >= params.get_max_depth())
65 || (variator.search_space.node_map.find(n.ret_type) == variator.search_space.node_map.end())) {
69 return n.get_prob_change();
75 weights.resize(program.Tree.size());
76 std::fill(weights.begin(), weights.end(), 0.0f);
82 template<Brush::ProgramType T>
86 auto spot_type = spot.node->data.ret_type;
98 spot_type, spot_type, context, params.
max_size-program.
Tree.size()-1);
104 auto parent_node = program.
Tree.wrap(spot, *n);
107 bool spot_filled =
false;
108 for (
auto a: (*n).arg_types)
119 program.
Tree.append_child(parent_node, opt.value());
122 else if (a == spot_type)
132 program.
Tree.insert(spot, opt.value());
149 template<Brush::ProgramType T>
157 auto context = variator.
get_context(program, spot);
163 program.
Tree.erase_children(spot);
165 program.
Tree.replace(spot, opt.value());
180 template<Brush::ProgramType T>
184 vector<float> weights(program.
Tree.size());
187 std::transform(program.
Tree.begin(), program.
Tree.end(), weights.begin(),
190 if (Is<NodeType::OffsetSum>(n.node_type))
194 if (!n.get_is_weighted()
195 && IsWeighable(n.node_type))
197 return n.get_prob_change();
205 std::fill(weights.begin(), weights.end(), 0.0f);
211 template<Brush::ProgramType T>
215 if (spot.node->data.get_is_weighted()==
true
219 spot.node->data.set_is_weighted(
true);
233 template<Brush::ProgramType T>
237 vector<float> weights(program.
Tree.size());
239 std::transform(program.
Tree.begin(), program.
Tree.end(), weights.begin(),
242 if (Is<NodeType::OffsetSum>(n.node_type))
245 if (n.get_is_weighted()
246 && IsWeighable(n.node_type))
247 return n.get_prob_change();
255 template<Brush::ProgramType T>
259 if (spot.node->data.get_is_weighted()==
false)
262 spot.node->data.set_is_weighted(
false);
276 template<Brush::ProgramType T>
280 vector<float> weights;
286 std::transform(program.
Tree.begin(), program.
Tree.end(), std::back_inserter(weights),
288 size_t d = program.Tree.depth(iter);
289 std::advance(iter, 1);
292 if ((d >= params.max_depth)
293 || (node_map.find(n.ret_type) == node_map.end()) )
296 return n.get_prob_change();
300 weights.resize(program.
Tree.size());
301 std::fill(weights.begin(), weights.end(), 0.0f);
307 template<Brush::ProgramType T>
319 auto spot_type = spot.node->data.ret_type;
324 size_t s = params.
max_size - (program.
Tree.size() - program.
Tree.size(spot));
326 s =
r.rnd_int(1, s+1);
339 program.
Tree.erase_children(spot);
342 program.
Tree.move_ontop(spot, subtree.value().begin());
359 template<Brush::ProgramType T>
363 vector<float> weights;
367 std::transform(program.
Tree.begin(), program.
Tree.end(), std::back_inserter(weights),
369 size_t d = 1+program.Tree.depth(iter);
370 std::advance(iter, 1);
373 if (d >= params.get_max_depth()
374 || variator.search_space.node_map.find(n.ret_type) == variator.search_space.node_map.end()
380 return n.get_prob_change();
386 weights.resize(program.Tree.size());
387 std::fill(weights.begin(), weights.end(), 0.0f);
393 template<Brush::ProgramType T>
424template<Brush::ProgramType T>
434 vector<float> child_weights(child.
Tree.size());
436 auto child_iter = child.
Tree.begin();
437 std::transform(child.
Tree.begin(), child.
Tree.end(), child_weights.begin(),
439 auto s_at = child.size_at(child_iter);
440 auto d_at = child.depth_to_reach(child_iter);
442 std::advance(child_iter, 1);
444 if (s_at<parameters.max_size && d_at<parameters.max_depth)
445 return n.get_prob_change();
451 if (std::all_of(child_weights.begin(), child_weights.end(), [](
const auto& w) {
455 return std::make_tuple(std::nullopt, VectorXf());
462 while (++attempts <= 3)
464 auto child_spot =
r.select_randomly(child.
Tree.begin(),
466 child_weights.begin(),
470 auto child_ret_type = child_spot.node->data.ret_type;
477 vector<float> other_weights(other.
Tree.size());
480 auto other_iter = other.
Tree.begin();
481 std::transform(other.
Tree.begin(), other.
Tree.end(), other_weights.begin(),
482 [&other, &other_iter, allowed_size, allowed_depth, child_ret_type](
const auto& n)
mutable {
483 int s = other.size_at(other_iter);
484 int d = other.depth_at(other_iter);
486 std::advance(other_iter, 1);
489 if (s <= allowed_size && d <= allowed_depth && n.ret_type == child_ret_type) {
490 return n.get_prob_change();
497 bool matching_spots_found = std::any_of(other_weights.begin(), other_weights.end(),
498 [](
float w) { return w > 0.0f; });
500 if (matching_spots_found) {
504 auto other_spot =
r.select_randomly(
507 other_weights.begin(),
513 child.
Tree.move_ontop(child_spot, other_spot);
518 return std::make_tuple(ind, context);
522 return std::make_tuple(std::nullopt, VectorXf());
558template<Brush::ProgramType T>
567 bool all_zero =
true;
569 if (it.second > 0.0) {
576 return std::make_tuple(std::nullopt, VectorXf());
580 choice =
r.random_choice(
parameters.mutation_probs);
587 vector<float> weights;
588 if (choice.compare(
"point") == 0)
590 else if (choice.compare(
"insert") == 0)
592 else if (choice.compare(
"delete") == 0)
594 else if (choice.compare(
"subtree") == 0)
596 else if (choice.compare(
"toggle_weight_on") == 0)
598 else if (choice.compare(
"toggle_weight_off") == 0)
601 std::string msg = fmt::format(
"{} not a valid mutation choice", choice);
605 if (std::all_of(weights.begin(), weights.end(), [](
const auto& w) {
609 return std::make_tuple(std::nullopt, VectorXf());
611 VectorXf context = {};
614 while(++attempts <= 3)
620 auto spot =
r.select_randomly(child.
Tree.begin(), child.
Tree.end(),
621 weights.begin(), weights.end());
631 if (choice.compare(
"point") == 0)
633 else if (choice.compare(
"insert") == 0)
635 else if (choice.compare(
"delete") == 0)
637 else if (choice.compare(
"subtree") == 0)
639 else if (choice.compare(
"toggle_weight_on") == 0)
662 if (choice.compare(
"point") == 0
663 || choice.compare(
"insert") == 0
664 || choice.compare(
"delete") == 0
672 return std::make_tuple(ind, context);
679 return std::make_tuple(std::nullopt, context);
682template<Brush::ProgramType T>
684 const vector<size_t>& parents)
688 for (
unsigned i = 0; i<indices.size(); ++i)
696 std::optional<Individual<T>> opt=std::nullopt;
699 *
r.select_randomly(parents.begin(), parents.end())];
701 vector<Individual<T>> ind_parents;
702 VectorXf context = {};
708 *
r.select_randomly(parents.begin(), parents.end())];
710 auto variation_result =
cross(mom, dad);
711 ind_parents = {mom, dad};
712 tie(opt, context) = variation_result;
717 auto variation_result =
mutate(mom);
720 tie(opt, context) = variation_result;
767 pop.
individuals.at(indices.at(i)) = std::make_shared<Individual<T>>(ind);
771template <Brush::ProgramType T>
787 if (variation_probs.find(
"cx") != variation_probs.end())
788 parameters.set_cx_prob(variation_probs.at(
"cx"));
790 for (
const auto& variation : variation_probs)
791 if (variation.first !=
"cx")
792 parameters.mutation_probs[variation.first] = variation.second;
796 auto datatype = bandit.first;
798 auto terminal_probs = bandit.second.sample_probs(
true);
800 for (
auto& terminal : terminal_probs) {
803 auto terminal_name = terminal.first;
804 auto terminal_prob = terminal.second;
807 auto it = std::find_if(
810 [&](
auto& node) { return node.get_feature() == terminal_name; });
813 auto index = std::distance(
search_space.terminal_map.at(datatype).begin(), it);
816 search_space.terminal_weights.at(datatype)[index] = terminal_prob;
822 for (
auto& [ret_type, bandit_map] :
op_bandits) {
823 for (
auto& [args_type, bandit] : bandit_map) {
824 auto op_probs = bandit.sample_probs(
true);
826 for (
auto& [op_name, op_prob] : op_probs) {
829 for (
const auto& [node_type, node_value]:
search_space.node_map.at(ret_type).at(args_type))
832 if (node_value.name == op_name) {
834 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.
std::optional< Node > bandit_get_node_like(Node node, VectorXf &context)
Bandit< string > variation_bandit
std::tuple< std::optional< Individual< T > >, VectorXf > mutate(const Individual< T > &parent, string choice="")
Performs mutation operation on an individual.
std::tuple< std::optional< Individual< T > >, VectorXf > cross(const Individual< T > &mom, const Individual< T > &dad)
Performs croearch_spaceover operation on two individuals.
void vary(Population< T > &pop, int island, const vector< size_t > &parents)
Handles variation of a population.
map< DataType, Bandit< string > > terminal_bandits
std::optional< Node > bandit_sample_terminal(DataType R, VectorXf &context)
VectorXf get_context(const Program< T > &program, Iter spot)
map< DataType, map< size_t, Bandit< string > > > op_bandits
std::optional< Node > bandit_sample_op_with_arg(DataType ret, DataType arg, VectorXf &context, int max_args=0)
#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