From 5da2af01ce04f7c5badb22d7046be85b9528597c Mon Sep 17 00:00:00 2001 From: Brett Laptop Date: Tue, 9 Jul 2024 21:57:18 -0400 Subject: [PATCH] silly little guys --- examples/gp_test_2.cpp | 6 +- examples/gp_test_3.cpp | 6 +- examples/gp_test_4.cpp | 6 +- examples/gp_test_5.cpp | 11 ++- examples/gp_test_6.cpp | 6 +- examples/gp_test_7.cpp | 84 ++++++++------------ include/blt/gp/program.h | 156 +++++++++++++++++-------------------- include/blt/gp/random.h | 80 ++++++++++++++++++- include/blt/gp/selection.h | 123 ++++++++++++++++------------- lib/blt | 2 +- src/generators.cpp | 8 +- src/selection.cpp | 12 +-- src/transformers.cpp | 12 +-- 13 files changed, 281 insertions(+), 231 deletions(-) diff --git a/examples/gp_test_2.cpp b/examples/gp_test_2.cpp index 8e15485..a3161e7 100644 --- a/examples/gp_test_2.cpp +++ b/examples/gp_test_2.cpp @@ -24,7 +24,7 @@ static constexpr long SEED = 41912; blt::gp::type_provider type_system; -blt::gp::gp_program program(type_system, std::mt19937_64{SEED}); // NOLINT +blt::gp::gp_program program(type_system, blt::gp::random_t{SEED}); // NOLINT blt::gp::operation_t add([](float a, float b) { BLT_TRACE("a: %f + b: %f = %f", a, b, a + b); @@ -41,8 +41,8 @@ blt::gp::operation_t pro_div([](float a, float b) { return b == 0 ? 0.0f : a / b; }); blt::gp::operation_t lit([]() { //static std::uniform_real_distribution dist(-32000, 32000); - static std::uniform_real_distribution dist(0.0f, 10.0f); - return dist(program.get_random()); +// static std::uniform_real_distribution dist(0.0f, 10.0f); + return program.get_random().get_float(0.0f, 10.0f); }); /** diff --git a/examples/gp_test_3.cpp b/examples/gp_test_3.cpp index 41edb8d..6025366 100644 --- a/examples/gp_test_3.cpp +++ b/examples/gp_test_3.cpp @@ -23,7 +23,7 @@ static constexpr long SEED = 41912; blt::gp::type_provider type_system; -blt::gp::gp_program program(type_system, std::mt19937_64{SEED}); // NOLINT +blt::gp::gp_program program(type_system, blt::gp::random_t{SEED}); // NOLINT blt::gp::operation_t add([](float a, float b) { return a + b; }); blt::gp::operation_t sub([](float a, float b) { return a - b; }); @@ -42,8 +42,8 @@ blt::gp::operation_t op_not([](bool b) {return !b; }); blt::gp::operation_t lit([]() { //static std::uniform_real_distribution dist(-32000, 32000); - static std::uniform_real_distribution dist(0.0f, 10.0f); - return dist(program.get_random()); +// static std::uniform_real_distribution dist(0.0f, 10.0f); + return program.get_random().get_float(0.0f, 10.f); }); /** diff --git a/examples/gp_test_4.cpp b/examples/gp_test_4.cpp index 88e1bdc..505fcb6 100644 --- a/examples/gp_test_4.cpp +++ b/examples/gp_test_4.cpp @@ -23,7 +23,7 @@ static constexpr long SEED = 41912; blt::gp::type_provider type_system; -blt::gp::gp_program program(type_system, std::mt19937_64{SEED}); // NOLINT +blt::gp::gp_program program(type_system, blt::gp::random_t{SEED}); // NOLINT blt::gp::operation_t add([](float a, float b) { return a + b; }); blt::gp::operation_t sub([](float a, float b) { return a - b; }); @@ -42,8 +42,8 @@ blt::gp::operation_t op_not([](bool b) { return !b; }); blt::gp::operation_t lit([]() { //static std::uniform_real_distribution dist(-32000, 32000); - static std::uniform_real_distribution dist(0.0f, 10.0f); - return dist(program.get_random()); +// static std::uniform_real_distribution dist(0.0f, 10.0f); + return program.get_random().get_float(0.0f, 10.0f); }); /** diff --git a/examples/gp_test_5.cpp b/examples/gp_test_5.cpp index 89483fa..d983ae7 100644 --- a/examples/gp_test_5.cpp +++ b/examples/gp_test_5.cpp @@ -44,7 +44,7 @@ static constexpr long SEED = 41912; blt::gp::type_provider type_system; -blt::gp::gp_program program(type_system, std::mt19937_64{SEED}); // NOLINT +blt::gp::gp_program program(type_system, blt::gp::random_t{SEED}); // NOLINT blt::gp::operation_t add([](float a, float b) { return a + b; }, "add"); // 0 blt::gp::operation_t sub([](float a, float b) { return a - b; }, "sub"); // 1 @@ -63,8 +63,8 @@ blt::gp::operation_t op_not([](bool b) { return !b; }, "not"); // 12 blt::gp::operation_t lit([]() { // 13 //static std::uniform_real_distribution dist(-32000, 32000); - static std::uniform_real_distribution dist(0.0f, 10.0f); - return dist(program.get_random()); +// static std::uniform_real_distribution dist(0.0f, 10.0f); + return program.get_random().get_float(0.0f, 10.f); }, "lit"); /** @@ -126,12 +126,11 @@ int main() while (new_pop.get_individuals().size() < pop.get_individuals().size()) { auto& random = program.get_random(); - std::uniform_int_distribution dist(0ul, pop.get_individuals().size() - 1); - blt::size_t first = dist(random); + blt::size_t first = random.get_size_t(0ul, pop.get_individuals().size()); blt::size_t second; do { - second = dist(random); + second = random.get_size_t(0ul, pop.get_individuals().size()); } while (second == first); auto results = crossover.apply(program, ind[first].tree, ind[second].tree); diff --git a/examples/gp_test_6.cpp b/examples/gp_test_6.cpp index ea12c9d..5bd072f 100644 --- a/examples/gp_test_6.cpp +++ b/examples/gp_test_6.cpp @@ -42,7 +42,7 @@ static constexpr long SEED = 41912; blt::gp::type_provider type_system; -blt::gp::gp_program program(type_system, std::mt19937_64{SEED}); // NOLINT +blt::gp::gp_program program(type_system, blt::gp::random_t{SEED}); // NOLINT blt::gp::operation_t add([](float a, float b) { return a + b; }, "add"); // 0 blt::gp::operation_t sub([](float a, float b) { return a - b; }, "sub"); // 1 @@ -61,8 +61,8 @@ blt::gp::operation_t op_not([](bool b) { return !b; }, "not"); // 12 blt::gp::operation_t lit([]() { // 13 //static std::uniform_real_distribution dist(-32000, 32000); - static std::uniform_real_distribution dist(0.0f, 10.0f); - return dist(program.get_random()); +// static std::uniform_real_distribution dist(0.0f, 10.0f); + return program.get_random().get_float(0.0f, 10.0f); }, "lit"); /** diff --git a/examples/gp_test_7.cpp b/examples/gp_test_7.cpp index 8ff3190..a7bad5d 100644 --- a/examples/gp_test_7.cpp +++ b/examples/gp_test_7.cpp @@ -23,8 +23,11 @@ static constexpr long SEED = 41912; +blt::gp::prog_config_t config = blt::gp::prog_config_t().set_elite_count(0); + blt::gp::type_provider type_system; -blt::gp::gp_program program(type_system, std::mt19937_64{SEED}); // NOLINT +blt::gp::gp_program program(type_system, blt::gp::random_t{SEED}, config); // NOLINT +std::array result_container; blt::gp::operation_t add([](float a, float b) { return a + b; }, "add"); // 0 blt::gp::operation_t sub([](float a, float b) { return a - b; }, "sub"); // 1 @@ -43,10 +46,23 @@ blt::gp::operation_t op_not([](bool b) { return !b; }, "not"); // 12 blt::gp::operation_t lit([]() { // 13 //static std::uniform_real_distribution dist(-32000, 32000); - static std::uniform_real_distribution dist(0.0f, 10.0f); - return dist(program.get_random()); +// static std::uniform_real_distribution dist(0.0f, 10.0f); + return program.get_random().get_float(0.0f, 10.0f); }, "lit"); +void print_best() +{ + BLT_TRACE("----{Current Gen: %ld}----", program.get_current_generation()); + auto best = program.get_best<10>(); + + for (auto& v : best) + BLT_TRACE(v.get().get_evaluation_value(nullptr)); + std::string small("--------------------------"); + for (blt::size_t i = 0; i < std::to_string(program.get_current_generation()).size(); i++) + small += "-"; + BLT_TRACE(small); +} + /** * This is a test using multiple types with blt::gp */ @@ -75,58 +91,26 @@ int main() program.set_operations(builder.build()); - blt::gp::ramped_half_initializer_t pop_init; + program.generate_population(type_system.get_type().id()); - auto pop = pop_init.generate(blt::gp::initializer_arguments{program, type_system.get_type().id(), 500, 3, 10}); - - blt::gp::population_t new_pop; - blt::gp::mutation_t mutator; - blt::gp::grow_generator_t generator; - - std::vector pre; - std::vector pos; - - BLT_INFO("Pre-Mutation:"); - for (auto& tree : pop.for_each_tree()) + while (!program.should_terminate()) { - auto f = tree.get_evaluation_value(nullptr); - pre.push_back(f); - BLT_TRACE(f); - } - BLT_INFO("Mutation:"); - for (auto& tree : pop.for_each_tree()) - { - new_pop.get_individuals().emplace_back(mutator.apply(program, tree)); - } - BLT_INFO("Post-Mutation"); - for (auto& tree : new_pop.for_each_tree()) - { - auto f = tree.get_evaluation_value(nullptr); - pos.push_back(f); - BLT_TRACE(f); + program.evaluate_fitness([](blt::gp::tree_t& current_tree, decltype(result_container)& container, blt::size_t index) { + container[index] = current_tree.get_evaluation_value(nullptr); + return container[index]; + }, result_container); + print_best(); + program.create_next_generation(blt::gp::select_tournament_t{}, blt::gp::select_tournament_t{}, + blt::gp::select_tournament_t{}); + program.next_generation(); } - BLT_INFO("Stats:"); - blt::size_t eq = 0; - for (const auto& v : pos) - { - for (const auto m : pre) - { - if (v == m) - { - eq++; - break; - } - } - } - BLT_INFO("Equal values: %ld", eq); + program.evaluate_fitness([](blt::gp::tree_t& current_tree, decltype(result_container)& container, blt::size_t index) { + container[index] = current_tree.get_evaluation_value(nullptr); + return container[index]; + }, result_container); - blt::u32 seed = 691; - for (blt::size_t i = 0; i < 500; i++) - { - auto random = blt::random::pcg_int(seed); - BLT_INFO(random); - } + print_best(); return 0; } \ No newline at end of file diff --git a/include/blt/gp/program.h b/include/blt/gp/program.h index b3911f1..ad3b704 100644 --- a/include/blt/gp/program.h +++ b/include/blt/gp/program.h @@ -27,15 +27,16 @@ #include #include #include -#include #include #include +#include #include #include #include #include #include +#include #include #include #include @@ -238,87 +239,46 @@ namespace blt::gp * @param engine random engine to use throughout the program. TODO replace this with something better * @param context_size number of arguments which are always present as "context" to the GP system / operators */ - explicit gp_program(type_provider& system, std::mt19937_64 engine): + explicit gp_program(type_provider& system, random_t engine): system(system), engine(engine) {} - explicit gp_program(type_provider& system, std::mt19937_64 engine, prog_config_t config): + explicit gp_program(type_provider& system, random_t engine, prog_config_t config): system(system), engine(engine), config(config) {} - void generate_population(type_id root_type); - - template - void create_next_generation(Crossover&& crossover_selection, Mutation&& mutation_selection, Reproduction&& reproduction_selection) + void generate_population(type_id root_type) + { + current_pop = config.pop_initializer.get().generate( + {*this, root_type, config.population_size, config.initial_min_tree_size, config.initial_max_tree_size}); + } + + template)> + void create_next_generation(Crossover&& crossover_selection, Mutation&& mutation_selection, Reproduction&& reproduction_selection, + Creation_Func& func = default_next_pop_creator) { - static std::uniform_real_distribution dist(0.0, 1.0); - double total_prob = config.mutation_chance + config.crossover_chance; - double crossover_chance = config.crossover_chance / total_prob; - double mutation_chance = crossover_chance + config.mutation_chance / total_prob; - // should already be empty next_pop.clear(); crossover_selection.pre_process(*this, current_pop, current_stats); mutation_selection.pre_process(*this, current_pop, current_stats); reproduction_selection.pre_process(*this, current_pop, current_stats); - while(next_pop.get_individuals().size() < config.population_size) - { - auto type = dist(get_random()); - if (type > crossover_chance && type < mutation_chance) - { - // crossover - auto& p1 = crossover_selection.select(*this, current_pop, current_stats); - auto& p2 = crossover_selection.select(*this, current_pop, current_stats); - - auto results = config.crossover.get().apply(*this, p1, p2); - - // if crossover fails, we can check for mutation on these guys. otherwise straight copy them into the next pop - if (results) - { - next_pop.get_individuals().emplace_back(std::move(results->child1)); - // annoying check - if (next_pop.get_individuals().size() < config.population_size) - next_pop.get_individuals().emplace_back(std::move(results->child2)); - } else - { - if (config.try_mutation_on_crossover_failure && choice(config.mutation_chance)) - next_pop.get_individuals().emplace_back(std::move(config.mutator.get().apply(*this, p1))); - else - next_pop.get_individuals().push_back(p1); - // annoying check. - if (next_pop.get_individuals().size() < config.population_size) - { - if (config.try_mutation_on_crossover_failure && choice(config.mutation_chance)) - next_pop.get_individuals().emplace_back(std::move(config.mutator.get().apply(*this, p2))); - else - next_pop.get_individuals().push_back(p2); - } - } - } else if (type > mutation_chance) - { - // mutation - auto& p = mutation_selection.select(*this, current_pop, current_stats); - next_pop.get_individuals().emplace_back(std::move(config.mutator.get().apply(*this, p))); - } else - { - // reproduction - auto& p = reproduction_selection.select(*this, current_pop, current_stats); - next_pop.get_individuals().push_back(p); - } - } + func(get_selector_args(), std::forward(crossover_selection), std::forward(mutation_selection), + std::forward(reproduction_selection)); } /** * takes in a lambda for the fitness evaluation function (must return a value convertable to double) * The lambda must accept a tree for evaluation, container for evaluation context, and a index into that container (current tree) * + * tree_t&, Container&, blt::size_t + * * Container must be concurrently accessible from multiple threads using operator[] * * NOTE: 0 is considered the best, in terms of standardized and adjusted fitness */ - template - void evaluate_fitness(Lambda&& fitness_function, Container& result_storage) + template + void evaluate_fitness(Callable&& fitness_function, Container& result_storage) { for (const auto& ind : blt::enumerate(current_pop.get_individuals())) ind.second.raw_fitness = static_cast(fitness_function(ind.second.tree, result_storage, ind.first)); @@ -366,27 +326,43 @@ namespace blt::gp current_generation++; } - [[nodiscard]] inline std::mt19937_64& get_random() + template + std::array get_best_indexes() + { + std::array arr; + + std::vector> values; + values.reserve(current_pop.get_individuals().size()); + + for (const auto& ind : blt::enumerate(current_pop.get_individuals())) + values.emplace_back(ind.first, ind.second.adjusted_fitness); + + std::sort(values.begin(), values.end(), [](const auto& a, const auto& b) { + return a.second < b.second; + }); + + for (blt::size_t i = 0; i < size; i++) + arr[i] = values[i].first; + + return arr; + } + + template + std::array, size> get_best() + { + return convert_array(get_best_indexes(), std::make_integer_sequence()); + } + + [[nodiscard]] bool should_terminate() const + { + return current_generation >= config.max_generations; + } + + [[nodiscard]] inline random_t& get_random() { return engine; } - [[nodiscard]] inline bool choice() - { - static std::uniform_int_distribution dist(0, 1); - return dist(engine); - } - - /** - * @param cutoff percent in floating point form chance of the event happening. - * @return - */ - [[nodiscard]] inline bool choice(double cutoff) - { - static std::uniform_real_distribution dist(0.0, 1.0); - return dist(engine) < cutoff; - } - [[nodiscard]] inline type_provider& get_typesystem() { return system; @@ -397,20 +373,17 @@ namespace blt::gp // we wanted a terminal, but could not find one, so we will select from a function that has a terminal if (storage.terminals[id].empty()) return select_non_terminal_too_deep(id); - std::uniform_int_distribution dist(0, storage.terminals[id].size() - 1); - return storage.terminals[id][dist(engine)]; + return storage.terminals[id][engine.get_size_t(0, storage.terminals[id].size())]; } inline operator_id select_non_terminal(type_id id) { - std::uniform_int_distribution dist(0, storage.non_terminals[id].size() - 1); - return storage.non_terminals[id][dist(engine)]; + return storage.non_terminals[id][engine.get_size_t(0, storage.non_terminals[id].size())]; } inline operator_id select_non_terminal_too_deep(type_id id) { - std::uniform_int_distribution dist(0, storage.operators_ordered_terminals[id].size() - 1); - return storage.operators_ordered_terminals[id][dist(engine)].first; + return storage.operators_ordered_terminals[id][engine.get_size_t(0, storage.operators_ordered_terminals[id].size())].first; } inline operator_info& get_operator_info(operator_id id) @@ -447,6 +420,11 @@ namespace blt::gp { storage = std::move(op); } + + [[nodiscard]] inline auto get_current_generation() const + { + return current_generation; + } private: type_provider& system; @@ -459,8 +437,20 @@ namespace blt::gp population_t next_pop; blt::size_t current_generation = 0; - std::mt19937_64 engine; + random_t engine; prog_config_t config; + + inline selector_args get_selector_args() + { + return {*this, next_pop, current_pop, current_stats, config, engine}; + } + + template + inline std::array, size> convert_array(std::array&& arr, + std::integer_sequence) + { + return {current_pop.get_individuals()[arr[indexes]].tree...}; + } }; } diff --git a/include/blt/gp/random.h b/include/blt/gp/random.h index 436d50f..eecc3bd 100644 --- a/include/blt/gp/random.h +++ b/include/blt/gp/random.h @@ -24,21 +24,93 @@ namespace blt::gp { + +#define BLT_RANDOM_FUNCTION blt::random::murmur_random64 +#define BLT_RANDOM_FLOAT blt::random::murmur_float64 +#define BLT_RANDOM_DOUBLE blt::random::murmur_double64 class random_t { public: - explicit random_t(blt::size_t seed): seed(seed) + explicit random_t(blt::u64 seed): seed(seed) {} - void set_seed(blt::size_t s) + void set_seed(blt::u64 s) { seed = s; } - + + float get_float() + { + return BLT_RANDOM_FLOAT(seed); + } + + double get_double() + { + return BLT_RANDOM_DOUBLE(seed); + } + + // [min, max) + double get_double(double min, double max) + { + return BLT_RANDOM_FUNCTION(seed, min, max); + } + + // [min, max) + float get_float(float min, float max) + { + return BLT_RANDOM_FUNCTION(seed, min, max); + } + + i32 get_i32(i32 min, i32 max) + { + return BLT_RANDOM_FUNCTION(seed, min, max); + } + + u32 get_u32(u32 min, u32 max) + { + return BLT_RANDOM_FUNCTION(seed, min, max); + } + + i64 get_i64(i64 min, i64 max) + { + return BLT_RANDOM_FUNCTION(seed, min, max); + } + + u64 get_u64(u64 min, u64 max) + { + return BLT_RANDOM_FUNCTION(seed, min, max); + } + + blt::size_t get_size_t(blt::size_t min, blt::size_t max) + { + return BLT_RANDOM_FUNCTION(seed, min, max); + } + + bool choice() + { + return BLT_RANDOM_DOUBLE(seed) < 0.5; + } + + bool choice(double cutoff) + { + return BLT_RANDOM_DOUBLE(seed) <= cutoff; + } + + template + auto& select(Container& container) + { + return container[get_u64(0, container.size())]; + } + + template + const auto& select(const Container& container) + { + return container[get_u64(0, container.size())]; + } private: - blt::size_t seed; + blt::u64 seed; }; } diff --git a/include/blt/gp/selection.h b/include/blt/gp/selection.h index 09490b8..68fed2c 100644 --- a/include/blt/gp/selection.h +++ b/include/blt/gp/selection.h @@ -38,61 +38,74 @@ namespace blt::gp random_t& random; }; -// template -// constexpr inline auto default_next_pop_selector = []( -// selector_args&& args, Crossover&& crossover_selection, Mutation&& mutation_selection, Reproduction&& reproduction_selection) { -// auto& [program, next_pop, current_pop, current_stats, config, random] = args; -// -// double total_prob = config.mutation_chance + config.crossover_chance; -// double crossover_chance = config.crossover_chance / total_prob; -// double mutation_chance = crossover_chance + config.mutation_chance / total_prob; -// -// while (next_pop.get_individuals().size() < config.population_size) -// { -// auto type = random.; -// if (type > crossover_chance && type < mutation_chance) -// { -// // crossover -// auto& p1 = crossover_selection.select(program, current_pop, current_stats); -// auto& p2 = crossover_selection.select(program, current_pop, current_stats); -// -// auto results = config.crossover.get().apply(program, p1, p2); -// -// // if crossover fails, we can check for mutation on these guys. otherwise straight copy them into the next pop -// if (results) -// { -// next_pop.get_individuals().emplace_back(std::move(results->child1)); -// // annoying check -// if (next_pop.get_individuals().size() < config.population_size) -// next_pop.get_individuals().emplace_back(std::move(results->child2)); -// } else -// { -// if (config.try_mutation_on_crossover_failure && program.choice(config.mutation_chance)) -// next_pop.get_individuals().emplace_back(std::move(config.mutator.get().apply(program, p1))); -// else -// next_pop.get_individuals().push_back(p1); -// // annoying check. -// if (next_pop.get_individuals().size() < config.population_size) -// { -// if (config.try_mutation_on_crossover_failure && choice(config.mutation_chance)) -// next_pop.get_individuals().emplace_back(std::move(config.mutator.get().apply(program, p2))); -// else -// next_pop.get_individuals().push_back(p2); -// } -// } -// } else if (type > mutation_chance) -// { -// // mutation -// auto& p = mutation_selection.select(program, current_pop, current_stats); -// next_pop.get_individuals().emplace_back(std::move(config.mutator.get().apply(program, p))); -// } else -// { -// // reproduction -// auto& p = reproduction_selection.select(program, current_pop, current_stats); -// next_pop.get_individuals().push_back(p); -// } -// } -// }; + template + constexpr inline auto default_next_pop_creator = []( + selector_args&& args, Crossover&& crossover_selection, Mutation&& mutation_selection, Reproduction&& reproduction_selection) { + auto& [program, next_pop, current_pop, current_stats, config, random] = args; + + double total_prob = config.mutation_chance + config.crossover_chance; + double crossover_chance = config.crossover_chance / total_prob; + double mutation_chance = crossover_chance + config.mutation_chance / total_prob; + + if (config.elites > 0) + { + std::vector> values; + + for (blt::size_t i = 0; i < config.elites; i++) + values.emplace_back(i, current_pop.get_individuals()[i].adjusted_fitness); + + for (auto& ind : current_pop.get_individuals()) + { + + } + } + + while (next_pop.get_individuals().size() < config.population_size) + { + auto type = random.get_double(); + if (type > crossover_chance && type < mutation_chance) + { + // crossover + auto& p1 = crossover_selection.select(program, current_pop, current_stats); + auto& p2 = crossover_selection.select(program, current_pop, current_stats); + + auto results = config.crossover.get().apply(program, p1, p2); + + // if crossover fails, we can check for mutation on these guys. otherwise straight copy them into the next pop + if (results) + { + next_pop.get_individuals().emplace_back(std::move(results->child1)); + // annoying check + if (next_pop.get_individuals().size() < config.population_size) + next_pop.get_individuals().emplace_back(std::move(results->child2)); + } else + { + if (config.try_mutation_on_crossover_failure && random.choice(config.mutation_chance)) + next_pop.get_individuals().emplace_back(std::move(config.mutator.get().apply(program, p1))); + else + next_pop.get_individuals().push_back(individual{p1}); + // annoying check. + if (next_pop.get_individuals().size() < config.population_size) + { + if (config.try_mutation_on_crossover_failure && random.choice(config.mutation_chance)) + next_pop.get_individuals().emplace_back(std::move(config.mutator.get().apply(program, p2))); + else + next_pop.get_individuals().push_back(individual{p2}); + } + } + } else if (type > mutation_chance) + { + // mutation + auto& p = mutation_selection.select(program, current_pop, current_stats); + next_pop.get_individuals().emplace_back(std::move(config.mutator.get().apply(program, p))); + } else + { + // reproduction + auto& p = reproduction_selection.select(program, current_pop, current_stats); + next_pop.get_individuals().push_back(individual{p}); + } + } + }; class selection_t { diff --git a/lib/blt b/lib/blt index c88f1c3..b6048ed 160000 --- a/lib/blt +++ b/lib/blt @@ -1 +1 @@ -Subproject commit c88f1c3e382d9da9068cdd9ff87af6fef0ed9bd0 +Subproject commit b6048ed39c9f34a4480f2a99c5d83817d3ccf1bf diff --git a/src/generators.cpp b/src/generators.cpp index 11bd95d..5259208 100644 --- a/src/generators.cpp +++ b/src/generators.cpp @@ -93,7 +93,7 @@ namespace blt::gp tree_generator.push({program.select_terminal(type), new_depth}); return; } - if (program.choice() || new_depth < args.min_depth) + if (program.get_random().choice() || new_depth < args.min_depth) tree_generator.push({program.select_non_terminal(type), new_depth}); else tree_generator.push({program.select_terminal(type), new_depth}); @@ -141,7 +141,7 @@ namespace blt::gp for (auto i = 0ul; i < args.size; i++) { - if (args.program.choice()) + if (args.program.get_random().choice()) pop.get_individuals().emplace_back(full.generate(args.to_gen_args())); else pop.get_individuals().emplace_back(grow.generate(args.to_gen_args())); @@ -161,7 +161,7 @@ namespace blt::gp { for (auto i = 0ul; i < per_step; i++) { - if (args.program.choice()) + if (args.program.get_random().choice()) pop.get_individuals().emplace_back(full.generate({args.program, args.root_type, args.min_depth, depth})); else pop.get_individuals().emplace_back(grow.generate({args.program, args.root_type, args.min_depth, depth})); @@ -170,7 +170,7 @@ namespace blt::gp for (auto i = 0ul; i < remainder; i++) { - if (args.program.choice()) + if (args.program.get_random().choice()) pop.get_individuals().emplace_back(full.generate(args.to_gen_args())); else pop.get_individuals().emplace_back(grow.generate(args.to_gen_args())); diff --git a/src/selection.cpp b/src/selection.cpp index 7f44a8b..b5b78f1 100644 --- a/src/selection.cpp +++ b/src/selection.cpp @@ -55,21 +55,18 @@ namespace blt::gp tree_t& select_random_t::select(gp_program& program, population_t& pop, population_stats&) { - // TODO: use a more generic randomness solution. - std::uniform_int_distribution dist(0ul, pop.get_individuals().size()); - return pop.get_individuals()[dist(program.get_random())].tree; + return pop.get_individuals()[program.get_random().get_size_t(0ul, pop.get_individuals().size())].tree; } tree_t& select_tournament_t::select(gp_program& program, population_t& pop, population_stats&) { - std::uniform_int_distribution dist(0ul, pop.get_individuals().size()); - auto& first = pop.get_individuals()[dist(program.get_random())]; + auto& first = pop.get_individuals()[program.get_random().get_size_t(0ul, pop.get_individuals().size())]; individual* ind = &first; double best_guy = first.adjusted_fitness; for (blt::size_t i = 0; i < selection_size - 1; i++) { - auto& sel = pop.get_individuals()[dist(program.get_random())]; + auto& sel = pop.get_individuals()[program.get_random().get_size_t(0ul, pop.get_individuals().size())]; if (sel.adjusted_fitness < best_guy) { best_guy = sel.adjusted_fitness; @@ -82,8 +79,7 @@ namespace blt::gp tree_t& select_fitness_proportionate_t::select(gp_program& program, population_t& pop, population_stats&) { - static std::uniform_real_distribution dist(0.0, 1.0); - auto choice = dist(program.get_random()); + auto choice = program.get_random().get_double(); for (const auto& ind : blt::enumerate(pop)) { if (ind.first == pop.get_individuals().size()-1) diff --git a/src/transformers.cpp b/src/transformers.cpp index a324d51..943ec58 100644 --- a/src/transformers.cpp +++ b/src/transformers.cpp @@ -42,13 +42,10 @@ namespace blt::gp if (c1_ops.size() < 5 || c2_ops.size() < 5) return blt::unexpected(error_t::TREE_TOO_SMALL); - std::uniform_int_distribution op_sel1(3ul, c1_ops.size() - 1); - std::uniform_int_distribution op_sel2(3ul, c2_ops.size() - 1); - - blt::size_t crossover_point = op_sel1(program.get_random()); + blt::size_t crossover_point = program.get_random().get_size_t(1ul, c1_ops.size()); while (config.avoid_terminals && program.get_operator_info(c1_ops[crossover_point].id).argc.is_terminal()) - crossover_point = op_sel1(program.get_random()); + crossover_point = program.get_random().get_size_t(1ul, c1_ops.size()); blt::size_t attempted_point = 0; @@ -83,7 +80,7 @@ namespace blt::gp return blt::unexpected(error_t::NO_VALID_TYPE); } else { - attempted_point = op_sel2(program.get_random()); + attempted_point = program.get_random().get_size_t(1ul, c2_ops.size()); attempted_point_type = &program.get_operator_info(c2_ops[attempted_point].id); if (config.avoid_terminals && attempted_point_type->argc.is_terminal()) continue; @@ -263,8 +260,7 @@ namespace blt::gp auto& ops = c.get_operations(); auto& vals = c.get_values(); - std::uniform_int_distribution point_sel_dist(0ul, ops.size() - 1); - auto point = point_sel_dist(program.get_random()); + auto point = program.get_random().get_size_t(0ul, ops.size()); const auto& type_info = program.get_operator_info(ops[point].id); blt::i64 children_left = 0;