silly little guys
parent
1a05bb5c94
commit
5da2af01ce
|
@ -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<float> dist(-32000, 32000);
|
||||
static std::uniform_real_distribution<float> dist(0.0f, 10.0f);
|
||||
return dist(program.get_random());
|
||||
// static std::uniform_real_distribution<float> dist(0.0f, 10.0f);
|
||||
return program.get_random().get_float(0.0f, 10.0f);
|
||||
});
|
||||
|
||||
/**
|
||||
|
|
|
@ -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<float> dist(-32000, 32000);
|
||||
static std::uniform_real_distribution<float> dist(0.0f, 10.0f);
|
||||
return dist(program.get_random());
|
||||
// static std::uniform_real_distribution<float> dist(0.0f, 10.0f);
|
||||
return program.get_random().get_float(0.0f, 10.f);
|
||||
});
|
||||
|
||||
/**
|
||||
|
|
|
@ -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<float> dist(-32000, 32000);
|
||||
static std::uniform_real_distribution<float> dist(0.0f, 10.0f);
|
||||
return dist(program.get_random());
|
||||
// static std::uniform_real_distribution<float> dist(0.0f, 10.0f);
|
||||
return program.get_random().get_float(0.0f, 10.0f);
|
||||
});
|
||||
|
||||
/**
|
||||
|
|
|
@ -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<float> dist(-32000, 32000);
|
||||
static std::uniform_real_distribution<float> dist(0.0f, 10.0f);
|
||||
return dist(program.get_random());
|
||||
// static std::uniform_real_distribution<float> 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);
|
||||
|
|
|
@ -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<float> dist(-32000, 32000);
|
||||
static std::uniform_real_distribution<float> dist(0.0f, 10.0f);
|
||||
return dist(program.get_random());
|
||||
// static std::uniform_real_distribution<float> dist(0.0f, 10.0f);
|
||||
return program.get_random().get_float(0.0f, 10.0f);
|
||||
}, "lit");
|
||||
|
||||
/**
|
||||
|
|
|
@ -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<float, 500> 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<float> dist(-32000, 32000);
|
||||
static std::uniform_real_distribution<float> dist(0.0f, 10.0f);
|
||||
return dist(program.get_random());
|
||||
// static std::uniform_real_distribution<float> 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<float>(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<float>().id());
|
||||
|
||||
auto pop = pop_init.generate(blt::gp::initializer_arguments{program, type_system.get_type<float>().id(), 500, 3, 10});
|
||||
|
||||
blt::gp::population_t new_pop;
|
||||
blt::gp::mutation_t mutator;
|
||||
blt::gp::grow_generator_t generator;
|
||||
|
||||
std::vector<float> pre;
|
||||
std::vector<float> pos;
|
||||
|
||||
BLT_INFO("Pre-Mutation:");
|
||||
for (auto& tree : pop.for_each_tree())
|
||||
while (!program.should_terminate())
|
||||
{
|
||||
auto f = tree.get_evaluation_value<float>(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<float>(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<float>(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<float>(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;
|
||||
}
|
|
@ -27,15 +27,16 @@
|
|||
#include <string>
|
||||
#include <utility>
|
||||
#include <iostream>
|
||||
#include <random>
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
#include <array>
|
||||
|
||||
#include <blt/std/ranges.h>
|
||||
#include <blt/std/hashmap.h>
|
||||
#include <blt/std/types.h>
|
||||
#include <blt/std/utility.h>
|
||||
#include <blt/std/memory.h>
|
||||
#include <blt/std/meta.h>
|
||||
#include <blt/gp/fwdecl.h>
|
||||
#include <blt/gp/typesystem.h>
|
||||
#include <blt/gp/operations.h>
|
||||
|
@ -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<typename Crossover, typename Mutation, typename Reproduction>
|
||||
void create_next_generation(Crossover&& crossover_selection, Mutation&& mutation_selection, Reproduction&& reproduction_selection)
|
||||
void generate_population(type_id root_type)
|
||||
{
|
||||
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;
|
||||
current_pop = config.pop_initializer.get().generate(
|
||||
{*this, root_type, config.population_size, config.initial_min_tree_size, config.initial_max_tree_size});
|
||||
}
|
||||
|
||||
template<typename Crossover, typename Mutation, typename Reproduction, typename Creation_Func = decltype(default_next_pop_creator<Crossover, Mutation, Reproduction>)>
|
||||
void create_next_generation(Crossover&& crossover_selection, Mutation&& mutation_selection, Reproduction&& reproduction_selection,
|
||||
Creation_Func& func = default_next_pop_creator<Crossover, Mutation, Reproduction>)
|
||||
{
|
||||
// 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>(crossover_selection), std::forward<Mutation>(mutation_selection),
|
||||
std::forward<Reproduction>(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<typename Return, typename Class, typename Container, typename Lambda = Return(Class::*)(tree_t, Container, blt::size_t) const>
|
||||
void evaluate_fitness(Lambda&& fitness_function, Container& result_storage)
|
||||
template<typename Container, typename Callable>
|
||||
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<double>(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<blt::size_t size>
|
||||
std::array<blt::size_t, size> get_best_indexes()
|
||||
{
|
||||
std::array<blt::size_t, size> arr;
|
||||
|
||||
std::vector<std::pair<blt::size_t, double>> 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<blt::size_t size>
|
||||
std::array<std::reference_wrapper<tree_t>, size> get_best()
|
||||
{
|
||||
return convert_array(get_best_indexes<size>(), std::make_integer_sequence<blt::size_t, size>());
|
||||
}
|
||||
|
||||
[[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<blt::size_t> 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<blt::size_t> 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<blt::size_t> 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)
|
||||
|
@ -448,6 +421,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<blt::size_t size, blt::size_t... indexes>
|
||||
inline std::array<std::reference_wrapper<tree_t>, size> convert_array(std::array<blt::size_t, size>&& arr,
|
||||
std::integer_sequence<blt::size_t, indexes...>)
|
||||
{
|
||||
return {current_pop.get_individuals()[arr[indexes]].tree...};
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -25,20 +25,92 @@
|
|||
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<typename Container>
|
||||
auto& select(Container& container)
|
||||
{
|
||||
return container[get_u64(0, container.size())];
|
||||
}
|
||||
|
||||
template<typename Container>
|
||||
const auto& select(const Container& container)
|
||||
{
|
||||
return container[get_u64(0, container.size())];
|
||||
}
|
||||
|
||||
private:
|
||||
blt::size_t seed;
|
||||
blt::u64 seed;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -38,61 +38,74 @@ namespace blt::gp
|
|||
random_t& random;
|
||||
};
|
||||
|
||||
// template<typename Crossover, typename Mutation, typename Reproduction>
|
||||
// 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<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) {
|
||||
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;
|
||||
|
||||
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
|
||||
{
|
||||
|
|
2
lib/blt
2
lib/blt
|
@ -1 +1 @@
|
|||
Subproject commit c88f1c3e382d9da9068cdd9ff87af6fef0ed9bd0
|
||||
Subproject commit b6048ed39c9f34a4480f2a99c5d83817d3ccf1bf
|
|
@ -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()));
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue