add new selection, think there is a bug in elitsm

thread
Brett 2024-07-15 17:51:16 -04:00
parent fcd2d67852
commit 2081dd3e5f
4 changed files with 72 additions and 11 deletions

View File

@ -1,5 +1,5 @@
cmake_minimum_required(VERSION 3.25)
project(blt-gp VERSION 0.0.79)
project(blt-gp VERSION 0.0.80)
include(CTest)

View File

@ -38,6 +38,8 @@ namespace blt::gp
double crossover_chance = 0.8;
// percent chance that we will do mutation
double mutation_chance = 0.1;
// percent chance we will do reproduction (copy individual)
double reproduction_chance = 0;
// everything else will just be selected
blt::size_t elites = 0;
@ -51,8 +53,8 @@ namespace blt::gp
blt::size_t threads = std::thread::hardware_concurrency();
// number of elements each thread should pull per execution. this is for granularity performance and can be optimized for better results!
blt::size_t evaluation_size = 4;
// default config (ramped half-and-half init) or for buildering
// default config (ramped half-and-half init) or for buildering
prog_config_t();
// default config with a user specified initializer
@ -143,6 +145,12 @@ namespace blt::gp
evaluation_size = s;
return *this;
}
prog_config_t& set_reproduction_chance(double chance)
{
reproduction_chance = chance;
return *this;
}
};
}

View File

@ -262,7 +262,8 @@ namespace blt::gp
mutation_selection.pre_process(*this, current_pop, current_stats);
reproduction_selection.pre_process(*this, current_pop, current_stats);
func(get_selector_args(), std::forward<Crossover>(crossover_selection), std::forward<Mutation>(mutation_selection),
auto args = get_selector_args();
func(args, std::forward<Crossover>(crossover_selection), std::forward<Mutation>(mutation_selection),
std::forward<Reproduction>(reproduction_selection));
}

View File

@ -38,15 +38,9 @@ namespace blt::gp
random_t& random;
};
template<typename Crossover, typename Mutation, typename Reproduction>
constexpr inline auto default_next_pop_creator = [](
selector_args&& args, Crossover&& crossover_selection, Mutation&& mutation_selection, Reproduction&& reproduction_selection) {
constexpr inline auto perform_elitism = [](const selector_args& args) {
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<std::pair<std::size_t, double>> values;
@ -77,6 +71,18 @@ namespace blt::gp
for (blt::size_t i = 0; i < config.elites; i++)
next_pop.get_individuals().push_back(current_pop.get_individuals()[values[i].first]);
}
};
template<typename Crossover, typename Mutation, typename Reproduction>
constexpr inline auto default_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;
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;
perform_elitism(args);
while (next_pop.get_individuals().size() < config.population_size)
{
@ -125,6 +131,52 @@ namespace blt::gp
}
};
template<typename Crossover, typename Mutation, typename Reproduction>
constexpr inline auto non_deterministic_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;
perform_elitism(args);
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});
}
}
};
class selection_t
{
public: