From 34a3343a89e7a4329952d8853212f5a937392294 Mon Sep 17 00:00:00 2001 From: Brett Laptop Date: Mon, 15 Jul 2024 18:18:13 -0400 Subject: [PATCH] change default function to be more in line with koza's description of a gp --- CMakeLists.txt | 2 +- include/blt/gp/program.h | 5 ++- include/blt/gp/selection.h | 79 +++++++++++++++++++++----------------- 3 files changed, 47 insertions(+), 39 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a09a0bc..63f3b2a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 3.25) -project(blt-gp VERSION 0.0.80) +project(blt-gp VERSION 0.0.81) include(CTest) diff --git a/include/blt/gp/program.h b/include/blt/gp/program.h index 96afd3c..593e142 100644 --- a/include/blt/gp/program.h +++ b/include/blt/gp/program.h @@ -283,7 +283,7 @@ namespace blt::gp * NOTE: 0 is considered the best, in terms of standardized fitness */ template - void generate_population(type_id root_type, FitnessFunc& fitness_function) + void generate_population(type_id root_type, FitnessFunc& fitness_function, bool eval_fitness_now = true) { current_pop = config.pop_initializer.get().generate( {*this, root_type, config.population_size, config.initial_min_tree_size, config.initial_max_tree_size}); @@ -351,7 +351,8 @@ namespace blt::gp }); thread_helper.thread_function_condition.notify_all(); } - evaluate_fitness_internal(); + if (eval_fitness_now) + evaluate_fitness_internal(); } void next_generation() diff --git a/include/blt/gp/selection.h b/include/blt/gp/selection.h index 7e68f31..0107456 100644 --- a/include/blt/gp/selection.h +++ b/include/blt/gp/selection.h @@ -52,7 +52,7 @@ namespace blt::gp { for (blt::size_t i = 0; i < config.elites; i++) { -// BLT_INFO("%lf >= %lf? // %lf", ind.second.fitness.adjusted_fitness, values[i].second, ind.second.fitness.raw_fitness); + //BLT_INFO("%lf >= %lf? // %lf", ind.second.fitness.adjusted_fitness, values[i].second, ind.second.fitness.raw_fitness); if (ind.second.fitness.adjusted_fitness >= values[i].second) { bool doesnt_contain = true; @@ -74,7 +74,7 @@ namespace blt::gp }; template - constexpr inline auto default_next_pop_creator = []( + constexpr inline auto proportionate_next_pop_creator = []( const selector_args& args, Crossover crossover_selection, Mutation mutation_selection, Reproduction reproduction_selection) { auto& [program, next_pop, current_pop, current_stats, config, random] = args; @@ -132,7 +132,7 @@ namespace blt::gp }; template - constexpr inline auto non_deterministic_next_pop_creator = []( + constexpr inline auto default_next_pop_creator = []( const blt::gp::selector_args& args, Crossover crossover_selection, Mutation mutation_selection, Reproduction reproduction_selection) { auto& [program, next_pop, current_pop, current_stats, config, random] = args; @@ -140,39 +140,46 @@ namespace blt::gp while (next_pop.get_individuals().size() < config.population_size) { - // everyone gets a chance once per loop. - if (random.choice(config.crossover_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)); - } - } - if (next_pop.get_individuals().size() >= config.population_size) - break; - if (random.choice(config.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))); - } - if (next_pop.get_individuals().size() >= config.population_size) - break; - if (config.reproduction_chance > 0 && random.choice(config.reproduction_chance)) - { - // reproduction - auto& p = reproduction_selection.select(program, current_pop, current_stats); - next_pop.get_individuals().push_back(individual{p}); + int sel = random.get_i32(0, 3); + switch (sel){ + case 0: + // everyone gets a chance once per loop. + if (random.choice(config.crossover_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)); + } + } + break; + case 1: + if (random.choice(config.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))); + } + break; + case 2: + if (config.reproduction_chance > 0 && random.choice(config.reproduction_chance)) + { + // reproduction + auto& p = reproduction_selection.select(program, current_pop, current_stats); + next_pop.get_individuals().push_back(individual{p}); + } + break; + default: + BLT_ABORT("This is not possible!"); } } };