43template<ProgramType T>
78 map<string, float> variation_probs;
79 for (
const auto& mutation :
parameters.get_mutation_probs())
81 if (mutation.second > 0.0)
82 variation_probs[mutation.first] = mutation.second;
95 for (
const auto& entry : this->
search_space.terminal_weights) {
101 map<string, float> terminal_probs;
102 for (
int i = 0; i < entry.second.size(); i++)
104 if (entry.second[i] > 0.0)
106 auto node_name =
search_space.terminal_map.at(entry.first).at(i).get_feature();
107 terminal_probs[node_name] = entry.second[i];
110 if (terminal_probs.size()>0)
119 for (
auto& [ret_type, arg_w_map]:
search_space.node_map)
124 for (
const auto& [args_type, node_map] : arg_w_map)
130 map<string, float> node_probs;
132 for (
const auto& [node_type, node]: node_map)
134 auto weight =
search_space.node_map_weights.at(ret_type).at(args_type).at(node_type);
139 auto [it, inserted] = node_probs.try_emplace(node.name, weight);
148 if (node_probs.size() > 0)
158 for (
const auto& entry : this->
search_space.terminal_weights) {
159 map<string, float> terminal_probs;
160 for (
int i = 0; i < entry.second.size(); i++)
161 if (entry.second[i] > 0.0)
165 tree<Node> dummy_tree;
166 dummy_tree.insert(dummy_tree.begin(), node);
167 auto it = dummy_tree.begin();
182 std::optional<Individual<T>>
cross(
192 std::optional<Individual<T>>
mutate(
230 vector<std::shared_ptr<Individual<T>>> aux_individuals;
231 for (
unsigned i = 0; i < indices.size(); ++i)
239 std::optional<Individual<T>> opt = std::nullopt;
243 auto idx = parents.at(i % parents.size());
248 vector<Individual<T>> ind_parents = {mom};
259 [](
const auto& n) { return n.get_prob_change()<=0.0; }))
277 if (choice.compare(
"cx") == 0)
281 const Individual<T>& dad = pop[parents.at((i+1) % parents.size())];
283 opt =
cross(mom, dad);
284 ind_parents.push_back(dad);
288 opt =
mutate(mom, choice);
308 while (tries++<=3 && !opt) {
309 opt = this->
mutate(mom,
"subtree");
352 if (
parameters.constants_simplification && do_simplification)
361 vector<size_t> idx(inputDim);
362 std::iota(idx.begin(), idx.end(), 0);
365 if (do_simplification)
383 vector<float> deltas;
398 else if (obj.compare(
"complexity") == 0) {
401 else if (obj.compare(
"linear_complexity") == 0) {
404 else if (obj.compare(
"size") == 0) {
407 else if (obj.compare(
"depth") == 0) {
420 float weighted_delta =
delta * weight;
421 deltas.push_back(weighted_delta);
424 bool allPositive =
true;
425 bool allNegative =
true;
426 for (
float d : deltas) {
434 if (allPositive && !allNegative)
446 for (
auto& node : changed_nodes) {
447 if (node.get_arg_count() == 0) {
448 auto datatype = node.get_ret_type();
453 auto ret_type = node.get_ret_type();
454 auto args_type = node.args_type();
455 auto name = node.name;
457 this->
op_bandits[ret_type][args_type].update(name,
r);
468 pop.
individuals.at(indices.at(i)) = std::make_shared<Individual<T>>(ind);
495 string terminal_name = bandit.choose();
497 auto it = std::find_if(
500 [&](
auto& node) { return node.get_feature() == terminal_name; });
503 auto index = std::distance(
search_space.terminal_map.at(R).begin(), it);
530 string node_name = bandit.choose();
534 for (
const auto& [node_type, node_value]: entries)
536 if (node_value.name == node_name) {
548 vector<size_t> matches;
549 vector<float> weights;
551 for (
const auto& [args_type, name_map]: args_map) {
552 for (
const auto& [name, node]: name_map) {
553 auto node_arg_types = node.get_arg_types();
555 auto within_size_limit = !(max_args) || (node.get_arg_count() <= max_args);
557 if (
in(node_arg_types, arg)
559 &&
search_space.node_map_weights.at(ret).at(args_type).at(name) > 0.0f ) {
561 matches.push_back(node.args_type());
566 if (matches.size()==0)
570 auto args_type = *
r.select_randomly(matches.begin(),
573 string node_name = bandit.choose();
577 for (
const auto& [node_type, node_value]: entries)
579 if (node_value.name == node_name) {
594 auto& [args_type, bandit] = *
r.select_randomly(
op_bandits[ret].begin(),
597 string node_name = bandit.choose();
600 for (
const auto& [node_type, node_value]: entries)
602 if (node_value.name == node_name) {
644 using Iter = tree<Node>::pre_order_iterator;
646 template<Brush::ProgramType T>
650 vector<float> weights(program.
Tree.size());
653 std::transform(program.
Tree.begin(), program.
Tree.end(), weights.begin(),
654 [&](
const auto& n){ return n.get_prob_change();});
660 template<Brush::ProgramType T>
holds variable type data.
Class for evaluating the fitness of individuals in a population.
void assign_fit(Individual< T > &ind, const Dataset &data, const Parameters ¶ms, bool val=false)
Assign fitness to an individual.
static std::map< std::string, float > weightsMap
set parent ids using id values
vector< Node > get_sampled_nodes() const
Fitness fitness
aggregate fitness score
string get_variation() const
vector< string > get_objectives() const
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
static auto find_spots(Program< T > &program, Variation< T > &variator, const Parameters ¶ms)
tree< Node >::pre_order_iterator Iter
static auto mutate(Program< T > &program, Iter spot, Variation< T > &variator, const Parameters ¶ms)
Class representing the variation operators in Brush.
std::optional< Node > bandit_sample_op(DataType ret)
map< DataType, map< size_t, Bandit > > op_bandits
void vary_and_update(Population< T > &pop, int island, const vector< size_t > &parents, const Dataset &data, Evaluation< T > &evaluator, bool do_simplification)
Varies a population and updates the selection strategy based on rewards.
void vary(Population< T > &pop, int island, const vector< size_t > &parents)
Handles variation of a population.
void init()
Initializes the Variation object with parameters and search space.
Variation()=default
Default constructor.
Inexact_simplifier inexact_simplifier
std::optional< Node > bandit_sample_op_with_arg(DataType ret, DataType arg, int max_args=0)
Constants_simplifier constants_simplifier
Variation(Parameters ¶ms, SearchSpace &ss, Dataset &d)
Constructor that initializes the Variation object with parameters and search space.
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)
void log_simplification_table(std::ofstream &log)
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)
bool in(const V &v, const T &i)
check if element is in vector.
< nsga2 selection operator for getting the front
auto Is(NodeType nt) -> bool
unsigned int get_prev_depth() const
float get_prev_loss() const
unsigned int get_prev_size() const
unsigned int get_prev_complexity() const
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_prev_linear_complexity() const
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
The Bandit struct represents a multi-armed bandit.
class holding the data for a node in a tree.
NodeType node_type
the node type
DataType ret_type
return data type
std::size_t args_type() const
An individual program, a.k.a. model.
Program< PType > & fit(const Dataset &d)
int size(bool include_weight=true) const
count the tree size of the program, including the weights in weighted nodes.
Holds a search space, consisting of operations and terminals and functions, and methods to sample tha...