things are working now. missing fitness reset was partial problem
parent
e1083426fc
commit
3e0fe06017
|
@ -27,7 +27,7 @@ macro(compile_options target_name)
|
|||
sanitizers(${target_name})
|
||||
endmacro()
|
||||
|
||||
project(blt-gp VERSION 0.2.4)
|
||||
project(blt-gp VERSION 0.2.5)
|
||||
|
||||
include(CTest)
|
||||
|
||||
|
|
|
@ -45,6 +45,7 @@ namespace blt::gp::example
|
|||
};
|
||||
|
||||
bool fitness_function(const tree_t& current_tree, fitness_t& fitness, size_t) const;
|
||||
|
||||
public:
|
||||
template <typename SEED>
|
||||
rice_classification_t(SEED&& seed, const prog_config_t& config): example_base_t{std::forward<SEED>(seed), config}
|
||||
|
@ -60,7 +61,7 @@ namespace blt::gp::example
|
|||
|
||||
void load_rice_data(std::string_view rice_file_path);
|
||||
|
||||
confusion_matrix_t test_individual(const individual_t& individual) const;
|
||||
[[nodiscard]] confusion_matrix_t test_individual(const individual_t& individual) const;
|
||||
|
||||
void execute(const std::string_view rice_file_path)
|
||||
{
|
||||
|
@ -166,6 +167,9 @@ namespace blt::gp::example
|
|||
std::cout << "\n";
|
||||
}
|
||||
|
||||
auto& get_results() { return results; }
|
||||
const auto& get_results() const { return results; }
|
||||
|
||||
private:
|
||||
std::vector<rice_record> training_cases;
|
||||
std::vector<rice_record> testing_cases;
|
||||
|
|
|
@ -122,7 +122,7 @@ bool blt::gp::example::rice_classification_t::fitness_function(const tree_t& cur
|
|||
{
|
||||
for (auto& training_case : training_cases)
|
||||
{
|
||||
auto v = current_tree.get_evaluation_value<float>(training_case);
|
||||
const auto v = current_tree.get_evaluation_value<float>(training_case);
|
||||
switch (training_case.type)
|
||||
{
|
||||
case rice_type_t::Cammeo:
|
||||
|
@ -137,7 +137,8 @@ bool blt::gp::example::rice_classification_t::fitness_function(const tree_t& cur
|
|||
}
|
||||
fitness.raw_fitness = static_cast<double>(fitness.hits);
|
||||
fitness.standardized_fitness = fitness.raw_fitness;
|
||||
fitness.adjusted_fitness = 1.0 - (1.0 / (1.0 + fitness.standardized_fitness));
|
||||
// fitness.adjusted_fitness = 1.0 - (1.0 / (1.0 + fitness.standardized_fitness));
|
||||
fitness.adjusted_fitness = fitness.standardized_fitness / static_cast<double>(training_cases.size());
|
||||
return static_cast<size_t>(fitness.hits) == training_cases.size();
|
||||
}
|
||||
|
||||
|
@ -169,20 +170,20 @@ void blt::gp::example::rice_classification_t::load_rice_data(const std::string_v
|
|||
}
|
||||
}
|
||||
|
||||
size_t total_records = c.size() + o.size();
|
||||
size_t training_size = std::min(total_records / 3, 1000ul);
|
||||
for (size_t i = 0; i < training_size; i++)
|
||||
const size_t total_records = c.size() + o.size();
|
||||
const size_t testing_size = total_records / 3;
|
||||
for (size_t i = 0; i < testing_size; i++)
|
||||
{
|
||||
auto& random = program.get_random();
|
||||
auto& vec = random.choice() ? c : o;
|
||||
auto pos = random.get_i64(0, static_cast<i64>(vec.size()));
|
||||
training_cases.push_back(vec[pos]);
|
||||
const auto pos = random.get_i64(0, static_cast<i64>(vec.size()));
|
||||
testing_cases.push_back(vec[pos]);
|
||||
vec.erase(vec.begin() + pos);
|
||||
}
|
||||
testing_cases.insert(testing_cases.end(), c.begin(), c.end());
|
||||
testing_cases.insert(testing_cases.end(), o.begin(), o.end());
|
||||
std::shuffle(testing_cases.begin(), testing_cases.end(), program.get_random());
|
||||
BLT_INFO("Created training set of size %ld, testing set is of size %ld", training_size, testing_cases.size());
|
||||
training_cases.insert(training_cases.end(), c.begin(), c.end());
|
||||
training_cases.insert(training_cases.end(), o.begin(), o.end());
|
||||
std::shuffle(training_cases.begin(), training_cases.end(), program.get_random());
|
||||
BLT_INFO("Created testing set of size %ld, training set is of size %ld", testing_cases.size(), training_cases.size());
|
||||
}
|
||||
|
||||
blt::gp::confusion_matrix_t blt::gp::example::rice_classification_t::test_individual(const individual_t& individual) const
|
||||
|
|
|
@ -35,14 +35,14 @@ int main()
|
|||
.set_elite_count(2)
|
||||
.set_crossover_chance(0.9)
|
||||
.set_mutation_chance(0.1)
|
||||
.set_reproduction_chance(0.25)
|
||||
.set_reproduction_chance(0.0)
|
||||
.set_max_generations(50)
|
||||
.set_pop_size(500)
|
||||
.set_thread_count(16);
|
||||
|
||||
// example on how you can change the mutation config
|
||||
blt::gp::mutation_t::config_t mut_config{};
|
||||
mut_config.generator = full_generator;
|
||||
mut_config.generator = grow_generator;
|
||||
mut_config.replacement_min_depth = 2;
|
||||
mut_config.replacement_max_depth = 6;
|
||||
|
||||
|
|
|
@ -490,6 +490,7 @@ namespace blt::gp
|
|||
double sum_of_prob = 0;
|
||||
for (const auto& [index, ind] : blt::enumerate(current_pop.get_individuals()))
|
||||
{
|
||||
ind.fitness = {};
|
||||
if constexpr (std::is_same_v<LambdaReturn, bool> || std::is_convertible_v<LambdaReturn, bool>)
|
||||
{
|
||||
auto result = fitness_function(ind.tree, ind.fitness, index);
|
||||
|
@ -565,7 +566,7 @@ namespace blt::gp
|
|||
{
|
||||
auto& ind = current_pop.get_individuals()[i];
|
||||
|
||||
|
||||
ind.fitness = {};
|
||||
if constexpr (std::is_same_v<LambdaReturn, bool> || std::is_convertible_v<LambdaReturn, bool>)
|
||||
{
|
||||
auto result = fitness_function(ind.tree, ind.fitness, i);
|
||||
|
|
|
@ -71,9 +71,14 @@ namespace blt::gp
|
|||
struct config_t
|
||||
{
|
||||
// number of times crossover will try to pick a valid point in the tree. this is purely based on the return type of the operators
|
||||
blt::u16 max_crossover_tries = 5;
|
||||
blt::f32 traverse_chance = 0.5;
|
||||
blt::u32 min_tree_size = 5;
|
||||
u32 max_crossover_tries = 5;
|
||||
// if tree have fewer nodes than this number, they will not be considered for crossover
|
||||
u32 min_tree_size = 3;
|
||||
// used by the traverse version of get_crossover_point
|
||||
// at each depth level, what chance do we have to exit with this as our point? or in other words what's the chance we continue traversing
|
||||
// this is what this option configures.
|
||||
f32 traverse_chance = 0.5;
|
||||
|
||||
|
||||
// legacy settings:
|
||||
|
||||
|
@ -88,9 +93,9 @@ namespace blt::gp
|
|||
explicit crossover_t(const config_t& config): config(config)
|
||||
{}
|
||||
|
||||
std::optional<crossover_t::crossover_point_t> get_crossover_point(gp_program& program, const tree_t& c1, const tree_t& c2) const;
|
||||
std::optional<crossover_point_t> get_crossover_point(gp_program& program, const tree_t& c1, const tree_t& c2) const;
|
||||
|
||||
std::optional<crossover_t::crossover_point_t> get_crossover_point_traverse(gp_program& program, const tree_t& c1, const tree_t& c2) const;
|
||||
std::optional<crossover_point_t> get_crossover_point_traverse(gp_program& program, const tree_t& c1, const tree_t& c2) const;
|
||||
|
||||
std::optional<point_info_t> get_point_traverse(gp_program& program, const tree_t& t, std::optional<type_id> type) const;
|
||||
|
||||
|
|
|
@ -213,7 +213,7 @@ namespace blt::gp
|
|||
double raw_fitness = 0;
|
||||
double standardized_fitness = 0;
|
||||
double adjusted_fitness = 0;
|
||||
blt::i64 hits = 0;
|
||||
i64 hits = 0;
|
||||
};
|
||||
|
||||
struct individual_t
|
||||
|
|
|
@ -26,19 +26,18 @@
|
|||
|
||||
namespace blt::gp
|
||||
{
|
||||
|
||||
grow_generator_t grow_generator;
|
||||
|
||||
|
||||
inline tree_t& get_static_tree_tl(gp_program& program)
|
||||
{
|
||||
static thread_local tree_t new_tree{program};
|
||||
thread_local tree_t new_tree{program};
|
||||
new_tree.clear(program);
|
||||
return new_tree;
|
||||
}
|
||||
|
||||
inline blt::size_t accumulate_type_sizes(detail::op_iter_t begin, detail::op_iter_t end)
|
||||
|
||||
inline size_t accumulate_type_sizes(detail::op_iter_t begin, detail::op_iter_t end)
|
||||
{
|
||||
blt::size_t total = 0;
|
||||
size_t total = 0;
|
||||
for (auto it = begin; it != end; ++it)
|
||||
{
|
||||
if (it->is_value)
|
||||
|
@ -46,62 +45,63 @@ namespace blt::gp
|
|||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
template<typename>
|
||||
blt::u8* get_thread_pointer_for_size(blt::size_t bytes)
|
||||
|
||||
template <typename>
|
||||
u8* get_thread_pointer_for_size(size_t bytes)
|
||||
{
|
||||
static thread_local blt::expanding_buffer<blt::u8> buffer;
|
||||
thread_local expanding_buffer<u8> buffer;
|
||||
if (bytes > buffer.size())
|
||||
buffer.resize(bytes);
|
||||
return buffer.data();
|
||||
}
|
||||
|
||||
|
||||
mutation_t::config_t::config_t(): generator(grow_generator)
|
||||
{}
|
||||
|
||||
{
|
||||
}
|
||||
|
||||
bool crossover_t::apply(gp_program& program, const tree_t& p1, const tree_t& p2, tree_t& c1, tree_t& c2) // NOLINT
|
||||
{
|
||||
if (p1.get_operations().size() < config.min_tree_size || p2.get_operations().size() < config.min_tree_size)
|
||||
return false;
|
||||
|
||||
|
||||
auto& c1_ops = c1.get_operations();
|
||||
auto& c2_ops = c2.get_operations();
|
||||
|
||||
auto point = get_crossover_point(program, p1, p2);
|
||||
|
||||
|
||||
const auto point = get_crossover_point(program, p1, p2);
|
||||
|
||||
if (!point)
|
||||
return false;
|
||||
|
||||
auto selection = program.get_random().get_u32(0, 2);
|
||||
|
||||
|
||||
const auto selection = program.get_random().get_u32(0, 2);
|
||||
|
||||
// Used to make copies of operators. Statically stored for memory caching purposes.
|
||||
// Thread local as this function cannot have external modifications / will be called from multiple threads.
|
||||
static thread_local tracked_vector<op_container_t> c1_operators;
|
||||
static thread_local tracked_vector<op_container_t> c2_operators;
|
||||
thread_local tracked_vector<op_container_t> c1_operators;
|
||||
thread_local tracked_vector<op_container_t> c2_operators;
|
||||
c1_operators.clear();
|
||||
c2_operators.clear();
|
||||
|
||||
|
||||
// TODO: more crossover!
|
||||
switch (selection)
|
||||
{
|
||||
case 0:
|
||||
case 1:
|
||||
case 0:
|
||||
case 1:
|
||||
{
|
||||
// basic crossover
|
||||
auto crossover_point_begin_itr = c1_ops.begin() + point->p1_crossover_point;
|
||||
auto crossover_point_end_itr = c1_ops.begin() + c1.find_endpoint(program, point->p1_crossover_point);
|
||||
|
||||
|
||||
auto found_point_begin_itr = c2_ops.begin() + point->p2_crossover_point;
|
||||
auto found_point_end_itr = c2_ops.begin() + c2.find_endpoint(program, point->p2_crossover_point);
|
||||
|
||||
|
||||
stack_allocator& c1_stack = c1.get_values();
|
||||
stack_allocator& c2_stack = c2.get_values();
|
||||
|
||||
|
||||
for (const auto& op : blt::iterate(crossover_point_begin_itr, crossover_point_end_itr))
|
||||
c1_operators.push_back(op);
|
||||
for (const auto& op : blt::iterate(found_point_begin_itr, found_point_end_itr))
|
||||
c2_operators.push_back(op);
|
||||
|
||||
|
||||
blt::size_t c1_stack_after_bytes = accumulate_type_sizes(crossover_point_end_itr, c1_ops.end());
|
||||
blt::size_t c1_stack_for_bytes = accumulate_type_sizes(crossover_point_begin_itr, crossover_point_end_itr);
|
||||
blt::size_t c2_stack_after_bytes = accumulate_type_sizes(found_point_end_itr, c2_ops.end());
|
||||
|
@ -110,40 +110,40 @@ namespace blt::gp
|
|||
auto c2_total = static_cast<blt::ptrdiff_t>(c2_stack_after_bytes + c2_stack_for_bytes);
|
||||
auto copy_ptr_c1 = get_thread_pointer_for_size<struct c1_t>(c1_total);
|
||||
auto copy_ptr_c2 = get_thread_pointer_for_size<struct c2_t>(c2_total);
|
||||
|
||||
|
||||
c1_stack.reserve(c1_stack.bytes_in_head() - c1_stack_for_bytes + c2_stack_for_bytes);
|
||||
c2_stack.reserve(c2_stack.bytes_in_head() - c2_stack_for_bytes + c1_stack_for_bytes);
|
||||
|
||||
|
||||
c1_stack.copy_to(copy_ptr_c1, c1_total);
|
||||
c1_stack.pop_bytes(c1_total);
|
||||
|
||||
|
||||
c2_stack.copy_to(copy_ptr_c2, c2_total);
|
||||
c2_stack.pop_bytes(c2_total);
|
||||
|
||||
|
||||
c2_stack.copy_from(copy_ptr_c1, c1_stack_for_bytes);
|
||||
c2_stack.copy_from(copy_ptr_c2 + c2_stack_for_bytes, c2_stack_after_bytes);
|
||||
|
||||
|
||||
c1_stack.copy_from(copy_ptr_c2, c2_stack_for_bytes);
|
||||
c1_stack.copy_from(copy_ptr_c1 + c1_stack_for_bytes, c1_stack_after_bytes);
|
||||
|
||||
|
||||
// now swap the operators
|
||||
auto insert_point_c1 = crossover_point_begin_itr - 1;
|
||||
auto insert_point_c2 = found_point_begin_itr - 1;
|
||||
|
||||
|
||||
// invalidates [begin, end()) so the insert points should be fine
|
||||
c1_ops.erase(crossover_point_begin_itr, crossover_point_end_itr);
|
||||
c2_ops.erase(found_point_begin_itr, found_point_end_itr);
|
||||
|
||||
|
||||
c1_ops.insert(++insert_point_c1, c2_operators.begin(), c2_operators.end());
|
||||
c2_ops.insert(++insert_point_c2, c1_operators.begin(), c1_operators.end());
|
||||
}
|
||||
break;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
break;
|
||||
default:
|
||||
#if BLT_DEBUG_LEVEL > 0
|
||||
BLT_ABORT("This place should be unreachable!");
|
||||
#else
|
||||
BLT_UNREACHABLE;
|
||||
BLT_UNREACHABLE;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -169,26 +169,26 @@ namespace blt::gp
|
|||
BLT_ABORT("Amount of bytes in stack doesn't match the number of bytes expected for the operations");
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
std::optional<crossover_t::crossover_point_t> crossover_t::get_crossover_point(gp_program& program, const tree_t& c1,
|
||||
const tree_t& c2) const
|
||||
{
|
||||
auto& c1_ops = c1.get_operations();
|
||||
auto& c2_ops = c2.get_operations();
|
||||
|
||||
blt::size_t crossover_point = program.get_random().get_size_t(1ul, c1_ops.size());
|
||||
|
||||
|
||||
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 = program.get_random().get_size_t(1ul, c1_ops.size());
|
||||
|
||||
blt::size_t attempted_point = 0;
|
||||
|
||||
|
||||
size_t attempted_point = 0;
|
||||
|
||||
const auto& crossover_point_type = program.get_operator_info(c1_ops[crossover_point].id);
|
||||
operator_info_t* attempted_point_type = nullptr;
|
||||
|
||||
|
||||
blt::size_t counter = 0;
|
||||
do
|
||||
{
|
||||
|
@ -215,34 +215,32 @@ namespace blt::gp
|
|||
}
|
||||
// should we try again over the whole tree? probably not.
|
||||
return {};
|
||||
} else
|
||||
{
|
||||
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;
|
||||
if (crossover_point_type.return_type == attempted_point_type->return_type)
|
||||
break;
|
||||
counter++;
|
||||
}
|
||||
} while (true);
|
||||
|
||||
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;
|
||||
if (crossover_point_type.return_type == attempted_point_type->return_type)
|
||||
break;
|
||||
counter++;
|
||||
}
|
||||
while (true);
|
||||
|
||||
return crossover_point_t{static_cast<blt::ptrdiff_t>(crossover_point), static_cast<blt::ptrdiff_t>(attempted_point)};
|
||||
}
|
||||
|
||||
|
||||
std::optional<crossover_t::crossover_point_t> crossover_t::get_crossover_point_traverse(gp_program& program, const tree_t& c1,
|
||||
const tree_t& c2) const
|
||||
{
|
||||
auto c1_point_o = get_point_traverse_retry(program, c1, {});
|
||||
const auto c1_point_o = get_point_traverse_retry(program, c1, {});
|
||||
if (!c1_point_o)
|
||||
return {};
|
||||
auto c2_point_o = get_point_traverse_retry(program, c2, c1_point_o->type_operator_info.return_type);
|
||||
const auto c2_point_o = get_point_traverse_retry(program, c2, c1_point_o->type_operator_info.return_type);
|
||||
if (!c2_point_o)
|
||||
return {};
|
||||
|
||||
return {{c1_point_o->point, c2_point_o->point}};
|
||||
}
|
||||
|
||||
|
||||
std::optional<crossover_t::point_info_t> crossover_t::random_place_of_type(gp_program& program, const tree_t& t, type_id type)
|
||||
{
|
||||
auto attempted_point = program.get_random().get_i64(1ul, t.get_operations().size());
|
||||
|
@ -251,12 +249,12 @@ namespace blt::gp
|
|||
return {{attempted_point, attempted_point_type}};
|
||||
return {};
|
||||
}
|
||||
|
||||
|
||||
std::optional<crossover_t::point_info_t> crossover_t::get_point_traverse(gp_program& program, const tree_t& t, std::optional<type_id> type) const
|
||||
{
|
||||
auto& random = program.get_random();
|
||||
|
||||
blt::ptrdiff_t point = 0;
|
||||
|
||||
ptrdiff_t point = 0;
|
||||
while (true)
|
||||
{
|
||||
auto& current_op_type = program.get_operator_info(t.get_operations()[point].id);
|
||||
|
@ -269,88 +267,88 @@ namespace blt::gp
|
|||
// traverse to a child
|
||||
if (random.choice(config.traverse_chance))
|
||||
{
|
||||
auto args = current_op_type.argc.argc;
|
||||
auto argument = random.get_size_t(0, args);
|
||||
|
||||
const auto args = current_op_type.argc.argc;
|
||||
const auto argument = random.get_size_t(0, args);
|
||||
|
||||
// move to the first child
|
||||
point += 1;
|
||||
// loop through all the children we wish to skip. The result will be the first node of the next child, becoming the new parent
|
||||
for (blt::size_t i = 0; i < argument; i++)
|
||||
for (size_t i = 0; i < argument; i++)
|
||||
point = t.find_endpoint(program, point);
|
||||
|
||||
|
||||
continue;
|
||||
}
|
||||
if (!type || (type && *type == current_op_type.return_type))
|
||||
return {{point, current_op_type}};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::optional<crossover_t::point_info_t> crossover_t::get_point_traverse_retry(gp_program& program, const tree_t& t,
|
||||
std::optional<type_id> type) const
|
||||
{
|
||||
for (blt::size_t i = 0; i < config.max_crossover_tries; i++)
|
||||
for (size_t i = 0; i < config.max_crossover_tries; i++)
|
||||
{
|
||||
if (auto found = get_point_traverse(program, t, type))
|
||||
return found;
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
|
||||
bool mutation_t::apply(gp_program& program, const tree_t&, tree_t& c)
|
||||
{
|
||||
mutate_point(program, c, program.get_random().get_size_t(0ul, c.get_operations().size()));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
blt::size_t mutation_t::mutate_point(gp_program& program, tree_t& c, blt::size_t node)
|
||||
{
|
||||
auto& ops_r = c.get_operations();
|
||||
auto& vals_r = c.get_values();
|
||||
|
||||
|
||||
auto begin_point = static_cast<blt::ptrdiff_t>(node);
|
||||
auto end_point = c.find_endpoint(program, begin_point);
|
||||
auto begin_operator_id = ops_r[begin_point].id;
|
||||
const auto& type_info = program.get_operator_info(begin_operator_id);
|
||||
|
||||
|
||||
auto begin_itr = ops_r.begin() + begin_point;
|
||||
auto end_itr = ops_r.begin() + end_point;
|
||||
|
||||
|
||||
auto& new_tree = get_static_tree_tl(program);
|
||||
config.generator.get().generate(new_tree, {program, type_info.return_type, config.replacement_min_depth, config.replacement_max_depth});
|
||||
|
||||
|
||||
auto& new_ops_r = new_tree.get_operations();
|
||||
auto& new_vals_r = new_tree.get_values();
|
||||
|
||||
|
||||
blt::size_t total_bytes_after = accumulate_type_sizes(end_itr, ops_r.end());
|
||||
auto* stack_after_data = get_thread_pointer_for_size<struct mutation>(total_bytes_after);
|
||||
|
||||
|
||||
// make a copy of any stack data after the mutation point / children.
|
||||
vals_r.copy_to(stack_after_data, total_bytes_after);
|
||||
|
||||
|
||||
// remove the bytes of the data after the mutation point and the data for the children of the mutation node.
|
||||
vals_r.pop_bytes(static_cast<blt::ptrdiff_t>(total_bytes_after + accumulate_type_sizes(begin_itr, end_itr)));
|
||||
|
||||
|
||||
// insert the new tree then move back the data from after the original mutation point.
|
||||
vals_r.insert(new_vals_r);
|
||||
vals_r.copy_from(stack_after_data, total_bytes_after);
|
||||
|
||||
|
||||
auto before = begin_itr - 1;
|
||||
ops_r.erase(begin_itr, end_itr);
|
||||
ops_r.insert(++before, new_ops_r.begin(), new_ops_r.end());
|
||||
|
||||
|
||||
// this will check to make sure that the tree is in a correct and executable state. it requires that the evaluation is context free!
|
||||
#if BLT_DEBUG_LEVEL >= 2
|
||||
// BLT_ASSERT(new_vals_r.empty());
|
||||
//BLT_ASSERT(stack_after.empty());
|
||||
blt::size_t bytes_expected = 0;
|
||||
auto bytes_size = vals_r.size().total_used_bytes;
|
||||
|
||||
|
||||
for (const auto& op : c.get_operations())
|
||||
{
|
||||
if (op.is_value)
|
||||
bytes_expected += stack_allocator::aligned_size(op.type_size);
|
||||
}
|
||||
|
||||
|
||||
if (bytes_expected != bytes_size)
|
||||
{
|
||||
BLT_WARN_STREAM << "Stack state: " << vals_r.size() << "\n";
|
||||
|
@ -383,13 +381,13 @@ namespace blt::gp
|
|||
#endif
|
||||
return begin_point + new_ops_r.size();
|
||||
}
|
||||
|
||||
|
||||
bool advanced_mutation_t::apply(gp_program& program, const tree_t& p, tree_t& c)
|
||||
{
|
||||
(void) p;
|
||||
(void)p;
|
||||
auto& ops = c.get_operations();
|
||||
auto& vals = c.get_values();
|
||||
|
||||
|
||||
for (blt::size_t c_node = 0; c_node < ops.size(); c_node++)
|
||||
{
|
||||
double node_mutation_chance = per_node_mutation_chance / static_cast<double>(ops.size());
|
||||
|
@ -399,7 +397,7 @@ namespace blt::gp
|
|||
#if BLT_DEBUG_LEVEL >= 2
|
||||
tree_t c_copy = c;
|
||||
#endif
|
||||
|
||||
|
||||
// select an operator to apply
|
||||
auto selected_point = static_cast<blt::i32>(mutation_operator::COPY);
|
||||
auto choice = program.get_random().get_double();
|
||||
|
@ -412,7 +410,8 @@ namespace blt::gp
|
|||
selected_point = static_cast<blt::i32>(index);
|
||||
break;
|
||||
}
|
||||
} else
|
||||
}
|
||||
else
|
||||
{
|
||||
if (choice > mutation_operator_chances[index - 1] && choice <= value)
|
||||
{
|
||||
|
@ -421,13 +420,13 @@ namespace blt::gp
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
switch (static_cast<mutation_operator>(selected_point))
|
||||
{
|
||||
case mutation_operator::EXPRESSION:
|
||||
c_node += mutate_point(program, c, c_node);
|
||||
break;
|
||||
case mutation_operator::ADJUST:
|
||||
case mutation_operator::EXPRESSION:
|
||||
c_node += mutate_point(program, c, c_node);
|
||||
break;
|
||||
case mutation_operator::ADJUST:
|
||||
{
|
||||
// this is going to be evil >:3
|
||||
const auto& node = ops[c_node];
|
||||
|
@ -435,15 +434,15 @@ namespace blt::gp
|
|||
{
|
||||
auto& current_func_info = program.get_operator_info(ops[c_node].id);
|
||||
operator_id random_replacement = program.get_random().select(
|
||||
program.get_type_non_terminals(current_func_info.return_type.id));
|
||||
program.get_type_non_terminals(current_func_info.return_type.id));
|
||||
auto& replacement_func_info = program.get_operator_info(random_replacement);
|
||||
|
||||
|
||||
// cache memory used for offset data.
|
||||
thread_local static tracked_vector<tree_t::child_t> children_data;
|
||||
children_data.clear();
|
||||
|
||||
|
||||
c.find_child_extends(program, children_data, c_node, current_func_info.argument_types.size());
|
||||
|
||||
|
||||
for (const auto& [index, val] : blt::enumerate(replacement_func_info.argument_types))
|
||||
{
|
||||
// need to generate replacement.
|
||||
|
@ -453,23 +452,23 @@ namespace blt::gp
|
|||
auto& tree = get_static_tree_tl(program);
|
||||
config.generator.get().generate(tree,
|
||||
{program, val.id, config.replacement_min_depth, config.replacement_max_depth});
|
||||
|
||||
|
||||
auto& child = children_data[children_data.size() - 1 - index];
|
||||
blt::size_t total_bytes_for = c.total_value_bytes(child.start, child.end);
|
||||
blt::size_t total_bytes_after = c.total_value_bytes(child.end);
|
||||
|
||||
|
||||
auto after_ptr = get_thread_pointer_for_size<struct mutation_func>(total_bytes_after);
|
||||
vals.copy_to(after_ptr, total_bytes_after);
|
||||
vals.pop_bytes(static_cast<blt::ptrdiff_t>(total_bytes_after + total_bytes_for));
|
||||
|
||||
|
||||
blt::size_t total_child_bytes = tree.total_value_bytes();
|
||||
|
||||
|
||||
vals.copy_from(tree.get_values(), total_child_bytes);
|
||||
vals.copy_from(after_ptr, total_bytes_after);
|
||||
|
||||
|
||||
ops.erase(ops.begin() + child.start, ops.begin() + child.end);
|
||||
ops.insert(ops.begin() + child.start, tree.get_operations().begin(), tree.get_operations().end());
|
||||
|
||||
|
||||
// shift over everybody after.
|
||||
if (index > 0)
|
||||
{
|
||||
|
@ -479,10 +478,10 @@ namespace blt::gp
|
|||
{
|
||||
// remove the old tree size, then add the new tree size to get the correct positions.
|
||||
new_child.start =
|
||||
new_child.start - (child.end - child.start) +
|
||||
static_cast<blt::ptrdiff_t>(tree.get_operations().size());
|
||||
new_child.start - (child.end - child.start) +
|
||||
static_cast<blt::ptrdiff_t>(tree.get_operations().size());
|
||||
new_child.end =
|
||||
new_child.end - (child.end - child.start) + static_cast<blt::ptrdiff_t>(tree.get_operations().size());
|
||||
new_child.end - (child.end - child.start) + static_cast<blt::ptrdiff_t>(tree.get_operations().size());
|
||||
}
|
||||
}
|
||||
child.end = static_cast<blt::ptrdiff_t>(child.start + tree.get_operations().size());
|
||||
|
@ -504,7 +503,7 @@ namespace blt::gp
|
|||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (current_func_info.argc.argc > replacement_func_info.argc.argc)
|
||||
{
|
||||
blt::size_t end_index = children_data[(current_func_info.argc.argc - replacement_func_info.argc.argc) - 1].end;
|
||||
|
@ -516,11 +515,13 @@ namespace blt::gp
|
|||
vals.pop_bytes(static_cast<blt::ptrdiff_t>(total_bytes_after + total_bytes_for));
|
||||
vals.copy_from(data, total_bytes_after);
|
||||
ops.erase(ops.begin() + static_cast<blt::ptrdiff_t>(start_index), ops.begin() + static_cast<blt::ptrdiff_t>(end_index));
|
||||
} else if (current_func_info.argc.argc == replacement_func_info.argc.argc)
|
||||
}
|
||||
else if (current_func_info.argc.argc == replacement_func_info.argc.argc)
|
||||
{
|
||||
// exactly enough args
|
||||
// return types should have been replaced if needed. this part should do nothing?
|
||||
} else
|
||||
}
|
||||
else
|
||||
{
|
||||
// not enough args
|
||||
blt::size_t start_index = c_node + 1;
|
||||
|
@ -528,14 +529,16 @@ namespace blt::gp
|
|||
auto* data = get_thread_pointer_for_size<struct mutation_func>(total_bytes_after);
|
||||
vals.copy_to(data, total_bytes_after);
|
||||
vals.pop_bytes(static_cast<blt::ptrdiff_t>(total_bytes_after));
|
||||
|
||||
|
||||
for (blt::ptrdiff_t i = static_cast<blt::ptrdiff_t>(replacement_func_info.argc.argc) - 1;
|
||||
i >= current_func_info.argc.argc; i--)
|
||||
{
|
||||
auto& tree = get_static_tree_tl(program);
|
||||
config.generator.get().generate(tree,
|
||||
{program, replacement_func_info.argument_types[i].id, config.replacement_min_depth,
|
||||
config.replacement_max_depth});
|
||||
{
|
||||
program, replacement_func_info.argument_types[i].id, config.replacement_min_depth,
|
||||
config.replacement_max_depth
|
||||
});
|
||||
vals.insert(tree.get_values());
|
||||
ops.insert(ops.begin() + static_cast<blt::ptrdiff_t>(start_index), tree.get_operations().begin(),
|
||||
tree.get_operations().end());
|
||||
|
@ -544,8 +547,10 @@ namespace blt::gp
|
|||
vals.copy_from(data, total_bytes_after);
|
||||
}
|
||||
// now finally update the type.
|
||||
ops[c_node] = {program.get_typesystem().get_type(replacement_func_info.return_type).size(), random_replacement,
|
||||
program.is_operator_ephemeral(random_replacement)};
|
||||
ops[c_node] = {
|
||||
program.get_typesystem().get_type(replacement_func_info.return_type).size(), random_replacement,
|
||||
program.is_operator_ephemeral(random_replacement)
|
||||
};
|
||||
}
|
||||
#if BLT_DEBUG_LEVEL >= 2
|
||||
if (!c.check(program, nullptr))
|
||||
|
@ -559,16 +564,16 @@ namespace blt::gp
|
|||
}
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
case mutation_operator::SUB_FUNC:
|
||||
break;
|
||||
case mutation_operator::SUB_FUNC:
|
||||
{
|
||||
auto& current_func_info = program.get_operator_info(ops[c_node].id);
|
||||
|
||||
|
||||
// need to:
|
||||
// mutate the current function.
|
||||
// current function is moved to one of the arguments.
|
||||
// other arguments are generated.
|
||||
|
||||
|
||||
// get a replacement which returns the same type.
|
||||
auto& non_terminals = program.get_type_non_terminals(current_func_info.return_type.id);
|
||||
if (non_terminals.empty())
|
||||
|
@ -587,7 +592,8 @@ namespace blt::gp
|
|||
}
|
||||
}
|
||||
random_replacement = program.get_random().select(program.get_type_non_terminals(current_func_info.return_type.id));
|
||||
} while (true);
|
||||
}
|
||||
while (true);
|
||||
exit:
|
||||
auto& replacement_func_info = program.get_operator_info(random_replacement);
|
||||
auto new_argc = replacement_func_info.argc.argc;
|
||||
|
@ -596,19 +602,21 @@ namespace blt::gp
|
|||
blt::size_t for_bytes = c.total_value_bytes(c_node, current_end);
|
||||
blt::size_t after_bytes = c.total_value_bytes(current_end);
|
||||
auto size = current_end - c_node;
|
||||
|
||||
|
||||
auto combined_ptr = get_thread_pointer_for_size<struct SUB_FUNC_FOR>(for_bytes + after_bytes);
|
||||
|
||||
|
||||
vals.copy_to(combined_ptr, for_bytes + after_bytes);
|
||||
vals.pop_bytes(static_cast<blt::ptrdiff_t>(for_bytes + after_bytes));
|
||||
|
||||
|
||||
blt::size_t start_index = c_node;
|
||||
for (blt::ptrdiff_t i = new_argc - 1; i > static_cast<blt::ptrdiff_t>(arg_position); i--)
|
||||
{
|
||||
auto& tree = get_static_tree_tl(program);
|
||||
config.generator.get().generate(tree,
|
||||
{program, replacement_func_info.argument_types[i].id, config.replacement_min_depth,
|
||||
config.replacement_max_depth});
|
||||
{
|
||||
program, replacement_func_info.argument_types[i].id, config.replacement_min_depth,
|
||||
config.replacement_max_depth
|
||||
});
|
||||
blt::size_t total_bytes_for = tree.total_value_bytes();
|
||||
vals.copy_from(tree.get_values(), total_bytes_for);
|
||||
ops.insert(ops.begin() + static_cast<blt::ptrdiff_t>(start_index), tree.get_operations().begin(),
|
||||
|
@ -621,8 +629,10 @@ namespace blt::gp
|
|||
{
|
||||
auto& tree = get_static_tree_tl(program);
|
||||
config.generator.get().generate(tree,
|
||||
{program, replacement_func_info.argument_types[i].id, config.replacement_min_depth,
|
||||
config.replacement_max_depth});
|
||||
{
|
||||
program, replacement_func_info.argument_types[i].id, config.replacement_min_depth,
|
||||
config.replacement_max_depth
|
||||
});
|
||||
blt::size_t total_bytes_for = tree.total_value_bytes();
|
||||
vals.copy_from(tree.get_values(), total_bytes_for);
|
||||
ops.insert(ops.begin() + static_cast<blt::ptrdiff_t>(start_index), tree.get_operations().begin(),
|
||||
|
@ -630,10 +640,12 @@ namespace blt::gp
|
|||
start_index += tree.get_operations().size();
|
||||
}
|
||||
vals.copy_from(combined_ptr + for_bytes, after_bytes);
|
||||
|
||||
|
||||
ops.insert(ops.begin() + static_cast<blt::ptrdiff_t>(c_node),
|
||||
{program.get_typesystem().get_type(replacement_func_info.return_type).size(),
|
||||
random_replacement, program.is_operator_ephemeral(random_replacement)});
|
||||
{
|
||||
program.get_typesystem().get_type(replacement_func_info.return_type).size(),
|
||||
random_replacement, program.is_operator_ephemeral(random_replacement)
|
||||
});
|
||||
|
||||
#if BLT_DEBUG_LEVEL >= 2
|
||||
if (!c.check(program, nullptr))
|
||||
|
@ -649,8 +661,8 @@ namespace blt::gp
|
|||
}
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
case mutation_operator::JUMP_FUNC:
|
||||
break;
|
||||
case mutation_operator::JUMP_FUNC:
|
||||
{
|
||||
auto& info = program.get_operator_info(ops[c_node].id);
|
||||
blt::size_t argument_index = -1ul;
|
||||
|
@ -664,21 +676,21 @@ namespace blt::gp
|
|||
}
|
||||
if (argument_index == -1ul)
|
||||
continue;
|
||||
|
||||
|
||||
static thread_local tracked_vector<tree_t::child_t> child_data;
|
||||
child_data.clear();
|
||||
|
||||
|
||||
c.find_child_extends(program, child_data, c_node, info.argument_types.size());
|
||||
|
||||
|
||||
auto child_index = child_data.size() - 1 - argument_index;
|
||||
auto child = child_data[child_index];
|
||||
auto for_bytes = c.total_value_bytes(child.start, child.end);
|
||||
auto after_bytes = c.total_value_bytes(child_data.back().end);
|
||||
|
||||
|
||||
auto storage_ptr = get_thread_pointer_for_size<struct jump_func>(for_bytes + after_bytes);
|
||||
vals.copy_to(storage_ptr + for_bytes, after_bytes);
|
||||
vals.pop_bytes(static_cast<blt::ptrdiff_t>(after_bytes));
|
||||
|
||||
|
||||
for (auto i = static_cast<blt::ptrdiff_t>(child_data.size() - 1); i > static_cast<blt::ptrdiff_t>(child_index); i--)
|
||||
{
|
||||
auto& cc = child_data[i];
|
||||
|
@ -710,8 +722,8 @@ namespace blt::gp
|
|||
}
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
case mutation_operator::COPY:
|
||||
break;
|
||||
case mutation_operator::COPY:
|
||||
{
|
||||
auto& info = program.get_operator_info(ops[c_node].id);
|
||||
blt::size_t pt = -1ul;
|
||||
|
@ -735,25 +747,26 @@ namespace blt::gp
|
|||
}
|
||||
if (pt == -1ul || pf == -1ul)
|
||||
continue;
|
||||
|
||||
|
||||
blt::size_t from = 0;
|
||||
blt::size_t to = 0;
|
||||
|
||||
|
||||
if (program.get_random().choice())
|
||||
{
|
||||
from = pt;
|
||||
to = pf;
|
||||
} else
|
||||
}
|
||||
else
|
||||
{
|
||||
from = pf;
|
||||
to = pt;
|
||||
}
|
||||
|
||||
|
||||
static thread_local tracked_vector<tree_t::child_t> child_data;
|
||||
child_data.clear();
|
||||
|
||||
|
||||
c.find_child_extends(program, child_data, c_node, info.argument_types.size());
|
||||
|
||||
|
||||
auto from_index = child_data.size() - 1 - from;
|
||||
auto to_index = child_data.size() - 1 - to;
|
||||
auto& from_child = child_data[from_index];
|
||||
|
@ -762,37 +775,37 @@ namespace blt::gp
|
|||
blt::size_t after_from_bytes = c.total_value_bytes(from_child.end);
|
||||
blt::size_t to_bytes = c.total_value_bytes(to_child.start, to_child.end);
|
||||
blt::size_t after_to_bytes = c.total_value_bytes(to_child.end);
|
||||
|
||||
|
||||
auto after_bytes = std::max(after_from_bytes, after_to_bytes);
|
||||
|
||||
|
||||
auto from_ptr = get_thread_pointer_for_size<struct copy>(from_bytes);
|
||||
auto after_ptr = get_thread_pointer_for_size<struct copy_after>(after_bytes);
|
||||
|
||||
|
||||
vals.copy_to(after_ptr, after_from_bytes);
|
||||
vals.pop_bytes(static_cast<blt::ptrdiff_t>(after_from_bytes));
|
||||
vals.copy_to(from_ptr, from_bytes);
|
||||
vals.copy_from(after_ptr, after_from_bytes);
|
||||
|
||||
|
||||
vals.copy_to(after_ptr, after_to_bytes);
|
||||
vals.pop_bytes(static_cast<blt::ptrdiff_t>(after_to_bytes + to_bytes));
|
||||
|
||||
|
||||
vals.copy_from(from_ptr, from_bytes);
|
||||
vals.copy_from(after_ptr, after_to_bytes);
|
||||
|
||||
|
||||
static thread_local tracked_vector<op_container_t> op_copy;
|
||||
op_copy.clear();
|
||||
op_copy.insert(op_copy.begin(), ops.begin() + from_child.start, ops.begin() + from_child.end);
|
||||
|
||||
|
||||
ops.erase(ops.begin() + to_child.start, ops.begin() + to_child.end);
|
||||
ops.insert(ops.begin() + to_child.start, op_copy.begin(), op_copy.end());
|
||||
}
|
||||
break;
|
||||
case mutation_operator::END:
|
||||
default:
|
||||
break;
|
||||
case mutation_operator::END:
|
||||
default:
|
||||
#if BLT_DEBUG_LEVEL > 1
|
||||
BLT_ABORT("You shouldn't be able to get here!");
|
||||
#else
|
||||
BLT_UNREACHABLE;
|
||||
BLT_UNREACHABLE;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
@ -808,7 +821,7 @@ namespace blt::gp
|
|||
BLT_ABORT("Tree Check Failed.");
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue