20 template<Brush::ProgramType T>
33 if (
IsWeighable(spot.node->data.node_type) && spot.node->data.weight_is_fixed){
37 (*newNode).W = spot.node->data.W;
38 (*newNode).set_is_weighted(
true);
39 (*newNode).weight_is_fixed=
true;
43 program.
Tree.replace(spot, *newNode);
58 template<Brush::ProgramType T>
62 vector<float> weights;
66 std::transform(program.
Tree.begin(), program.
Tree.end(), std::back_inserter(weights),
68 size_t d = 1+program.Tree.depth(iter);
69 std::advance(iter, 1);
72 if ((d >= params.get_max_depth())
73 || (variator.search_space.node_map.find(n.ret_type) == variator.search_space.node_map.end())) {
77 return n.get_prob_change();
83 weights.resize(program.Tree.size());
84 std::fill(weights.begin(), weights.end(), 0.0f);
90 template<Brush::ProgramType T>
94 auto spot_type = spot.node->data.ret_type;
105 spot_type, spot_type, params.
max_size-program.
Tree.size()-1);
112 if (
IsWeighable(spot.node->data.node_type) && spot.node->data.weight_is_fixed){
113 Node& prev_n = spot.node->data;
118 (*n).
W = spot.node->data.W;
119 (*n).set_is_weighted(
true);
120 (*n).weight_is_fixed=
true;
128 auto parent_node = program.
Tree.wrap(spot, *n);
131 bool spot_filled =
false;
132 for (
auto a: (*n).arg_types)
142 program.
Tree.append_child(parent_node, opt.value());
145 else if (a == spot_type)
154 program.
Tree.insert(spot, opt.value());
171 template<Brush::ProgramType T>
175 vector<float> weights(program.
Tree.size());
178 std::transform(program.
Tree.begin(), program.
Tree.end(), weights.begin(),
181 if (n.weight_is_fixed){
187 return n.get_prob_change();
194 template<Brush::ProgramType T>
206 program.
Tree.erase_children(spot);
208 program.
Tree.replace(spot, opt.value());
223 template<Brush::ProgramType T>
227 vector<float> weights(program.
Tree.size());
230 std::transform(program.
Tree.begin(), program.
Tree.end(), weights.begin(),
233 if (Is<NodeType::OffsetSum>(n.node_type) || Is<NodeType::Constant>(n.node_type))
237 if ((!n.get_is_weighted())
238 && (!n.weight_is_fixed)
239 && IsWeighable(n.node_type))
241 return n.get_prob_change();
249 std::fill(weights.begin(), weights.end(), 0.0f);
255 template<Brush::ProgramType T>
259 if (spot.node->data.get_is_weighted()==
true
263 spot.node->data.set_is_weighted(
true);
277 template<Brush::ProgramType T>
281 vector<float> weights(program.
Tree.size());
283 std::transform(program.
Tree.begin(), program.
Tree.end(), weights.begin(),
286 if (Is<NodeType::OffsetSum>(n.node_type) || Is<NodeType::Constant>(n.node_type))
289 if (n.get_is_weighted()
290 && (!n.weight_is_fixed)
291 && IsWeighable(n.node_type))
292 return n.get_prob_change();
300 template<Brush::ProgramType T>
304 if (spot.node->data.get_is_weighted()==
false)
307 spot.node->data.set_is_weighted(
false);
321 template<Brush::ProgramType T>
325 vector<float> weights;
332 std::transform(program.
Tree.begin(), program.
Tree.end(), std::back_inserter(weights),
334 size_t d = program.Tree.depth(iter);
335 size_t s = program.Tree.size(iter);
336 std::advance(iter, 1);
339 if ((d >= params.max_depth)
340 || (node_map.find(n.ret_type) == node_map.end()) )
343 return n.get_prob_change();
349 template<Brush::ProgramType T>
361 auto spot_type = spot.node->data.ret_type;
374 s =
r.rnd_int(1, s+1);
386 if (
IsWeighable(spot.node->data.node_type) && spot.node->data.weight_is_fixed){
387 Node& n = subtree.value().begin().node->data;
390 n.
W = spot.node->data.W;
396 program.
Tree.erase_children(spot);
398 program.
Tree.move_ontop(spot, subtree.value().begin());
427template<Brush::ProgramType T>
437 vector<float> child_weights(child.
Tree.size());
439 auto child_iter = child.
Tree.begin();
440 std::transform(child.
Tree.begin(), child.
Tree.end(), child_weights.begin(),
442 auto s_at = child.size_at(child_iter);
443 auto d_at = child.depth_to_reach(child_iter);
445 std::advance(child_iter, 1);
451 d_at<parameters.max_depth
453 return n.get_prob_change();
459 if (std::all_of(child_weights.begin(), child_weights.end(), [](
const auto& w) {
470 while (++attempts <= 3)
472 auto child_spot =
r.select_randomly(child.
Tree.begin(),
474 child_weights.begin(),
478 auto child_ret_type = child_spot.node->data.ret_type;
485 vector<float> other_weights(other.
Tree.size());
488 auto other_iter = other.
Tree.begin();
489 std::transform(other.
Tree.begin(), other.
Tree.end(), other_weights.begin(),
490 [&other, &other_iter, allowed_size, allowed_depth, child_ret_type](
const auto& n)
mutable {
491 int s = other.size_at(other_iter);
492 int d = other.depth_at(other_iter);
494 std::advance(other_iter, 1);
497 if ( (s <= allowed_size)
498 && (d <= allowed_depth)
499 && (n.ret_type == child_ret_type)
501 return n.get_prob_change();
508 bool matching_spots_found = std::any_of(other_weights.begin(), other_weights.end(),
509 [](
float w) { return w > 0.0f; });
511 if (matching_spots_found) {
512 auto other_spot =
r.select_randomly(
513 other.
Tree.begin(), other.
Tree.end(),
514 other_weights.begin(), other_weights.end()
518 if (
IsWeighable(child_spot.node->data.node_type) && child_spot.node->data.weight_is_fixed){
519 Node& n = other_spot.node->data;
522 n.
W = child_spot.node->data.W;
529 child.
Tree.move_ontop(child_spot, other_spot);
581template<Brush::ProgramType T>
589 bool all_zero =
true;
591 if (it.second > 0.0) {
602 choice =
r.random_choice(
parameters.mutation_probs);
607 vector<float> weights;
608 if (choice.compare(
"point") == 0)
610 else if (choice.compare(
"insert") == 0)
612 else if (choice.compare(
"delete") == 0)
614 else if (choice.compare(
"subtree") == 0)
616 else if (choice.compare(
"toggle_weight_on") == 0)
618 else if (choice.compare(
"toggle_weight_off") == 0)
621 std::string msg = fmt::format(
"{} not a valid mutation choice", choice);
625 if (std::all_of(weights.begin(), weights.end(), [](
const auto& w) {
633 while(attempts++ < 3)
638 auto spot =
r.select_randomly(child.
Tree.begin(), child.
Tree.end(),
639 weights.begin(), weights.end());
646 if (choice.compare(
"point") == 0)
648 else if (choice.compare(
"insert") == 0)
650 else if (choice.compare(
"delete") == 0)
652 else if (choice.compare(
"subtree") == 0)
654 else if (choice.compare(
"toggle_weight_on") == 0)
679 if (choice.compare(
"point") == 0
680 || choice.compare(
"insert") == 0
681 || choice.compare(
"delete") == 0
696template<Brush::ProgramType T>
698 const vector<size_t>& parents)
702 for (
unsigned i = 0; i<indices.size(); ++i)
710 std::optional<Individual<T>> opt=std::nullopt;
713 *
r.select_randomly(parents.begin(), parents.end())];
715 vector<Individual<T>> ind_parents;
721 *
r.select_randomly(parents.begin(), parents.end())];
723 auto variation_result =
cross(mom, dad);
724 ind_parents = {mom, dad};
725 opt = variation_result;
729 auto variation_result =
mutate(mom);
732 opt = variation_result;
778 pop.
individuals.at(indices.at(i)) = std::make_shared<Individual<T>>(ind);
782template <Brush::ProgramType T>
793 if (variation_probs.find(
"cx") != variation_probs.end())
794 parameters.set_cx_prob(variation_probs.at(
"cx"));
796 for (
const auto& variation : variation_probs)
797 if (variation.first !=
"cx")
798 parameters.mutation_probs[variation.first] = variation.second;
802 auto datatype = bandit.first;
804 auto terminal_probs = bandit.second.sample_probs(
true);
806 for (
auto& [terminal_name, terminal_prob] : terminal_probs) {
808 auto it = std::find_if(
811 [&](
auto& node) { return node.get_feature() == terminal_name; });
814 auto index = std::distance(
search_space.terminal_map.at(datatype).begin(), it);
817 search_space.terminal_weights.at(datatype)[index] = terminal_prob;
823 for (
auto& [ret_type, bandit_map] :
op_bandits) {
824 for (
auto& [args_type, bandit] : bandit_map) {
825 auto op_probs = bandit.sample_probs(
true);
827 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))
831 if (node_value.name == op_name) {
833 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)
static auto find_spots(Program< T > &program, 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)
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
class holding the data for a node in a tree.
bool weight_is_fixed
whether the weight should be kept during variation. Notice that weight_is_fixed alows us to fix the w...
void set_is_weighted(bool is_weighted)
float W
the weights of the node. also used for splitting thresholds.
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