partial transfer to types

dev
Brett 2025-05-17 21:16:38 -04:00
parent 30372f1c71
commit ab67289745
7 changed files with 104 additions and 82 deletions

View File

@ -27,7 +27,7 @@ macro(compile_options target_name)
sanitizers(${target_name}) sanitizers(${target_name})
endmacro() endmacro()
project(blt-gp VERSION 0.5.30) project(blt-gp VERSION 0.5.31)
include(CTest) include(CTest)

View File

@ -79,7 +79,7 @@ namespace blt::gp::example
BLT_DEBUG("Begin Generation Loop"); BLT_DEBUG("Begin Generation Loop");
while (!program.should_terminate()) while (!program.should_terminate())
{ {
BLT_TRACE("------------{Begin Generation %ld}------------", program.get_current_generation()); BLT_TRACE("------------\\{Begin Generation {}}------------", program.get_current_generation());
BLT_TRACE("Creating next generation"); BLT_TRACE("Creating next generation");
program.create_next_generation(); program.create_next_generation();
BLT_TRACE("Move to next generation"); BLT_TRACE("Move to next generation");
@ -87,7 +87,7 @@ namespace blt::gp::example
BLT_TRACE("Evaluate Fitness"); BLT_TRACE("Evaluate Fitness");
program.evaluate_fitness(); program.evaluate_fitness();
auto& stats = program.get_population_stats(); auto& stats = program.get_population_stats();
BLT_TRACE("Avg Fit: %lf, Best Fit: %lf, Worst Fit: %lf, Overall Fit: %lf", BLT_TRACE("Avg Fit: {}, Best Fit: {}, Worst Fit: {}, Overall Fit: {}",
stats.average_fitness.load(std::memory_order_relaxed), stats.best_fitness.load(std::memory_order_relaxed), stats.average_fitness.load(std::memory_order_relaxed), stats.best_fitness.load(std::memory_order_relaxed),
stats.worst_fitness.load(std::memory_order_relaxed), stats.overall_fitness.load(std::memory_order_relaxed)); stats.worst_fitness.load(std::memory_order_relaxed), stats.overall_fitness.load(std::memory_order_relaxed));
BLT_TRACE("----------------------------------------------"); BLT_TRACE("----------------------------------------------");

View File

@ -52,6 +52,8 @@ namespace blt::gp
struct single_operation_tree_manipulator_t; struct single_operation_tree_manipulator_t;
struct multi_operation_tree_manipulator_t; struct multi_operation_tree_manipulator_t;
struct subtree_point_t;
class tree_t; class tree_t;

View File

@ -19,7 +19,6 @@
#ifndef BLT_GP_TRANSFORMERS_H #ifndef BLT_GP_TRANSFORMERS_H
#define BLT_GP_TRANSFORMERS_H #define BLT_GP_TRANSFORMERS_H
#include <blt/std/utility.h>
#include <blt/gp/fwdecl.h> #include <blt/gp/fwdecl.h>
#include <blt/gp/tree.h> #include <blt/gp/tree.h>
#include <blt/gp/generators.h> #include <blt/gp/generators.h>
@ -120,8 +119,8 @@ namespace blt::gp
public: public:
struct crossover_point_t struct crossover_point_t
{ {
tree_t::subtree_point_t p1_crossover_point; subtree_point_t p1_crossover_point;
tree_t::subtree_point_t p2_crossover_point; subtree_point_t p2_crossover_point;
}; };
@ -152,7 +151,7 @@ namespace blt::gp
~subtree_crossover_t() override = default; ~subtree_crossover_t() override = default;
protected: protected:
[[nodiscard]] std::optional<tree_t::subtree_point_t> get_point_traverse_retry(const tree_t& t, std::optional<type_id> type) const; [[nodiscard]] std::optional<subtree_point_t> get_point_traverse_retry(const tree_t& t, std::optional<type_id> type) const;
}; };
class one_point_crossover_t : public crossover_t class one_point_crossover_t : public crossover_t
@ -204,7 +203,7 @@ namespace blt::gp
virtual bool apply(gp_program& program, const tree_t& p, tree_t& c); virtual bool apply(gp_program& program, const tree_t& p, tree_t& c);
// returns the point after the mutation // returns the point after the mutation
size_t mutate_point(gp_program& program, tree_t& c, tree_t::subtree_point_t node) const; size_t mutate_point(gp_program& program, tree_t& c, subtree_point_t node) const;
virtual ~mutation_t() = default; virtual ~mutation_t() = default;

View File

@ -29,8 +29,6 @@
#include <utility> #include <utility>
#include <stack> #include <stack>
#include "program.h"
namespace blt::gp namespace blt::gp
{ {
namespace detail namespace detail
@ -234,6 +232,16 @@ namespace blt::gp
struct subtree_point_t struct subtree_point_t
{ {
subtree_point_t() = default;
explicit subtree_point_t(const size_t point): point(point), info(nullptr)
{
}
explicit subtree_point_t(const ssize_t point): point(static_cast<size_t>(point)), info(nullptr)
{
}
subtree_point_t(const size_t point, const operator_info_t& info): point(point), info(&info) // NOLINT subtree_point_t(const size_t point, const operator_info_t& info): point(point), info(&info) // NOLINT
{ {
} }
@ -254,13 +262,17 @@ namespace blt::gp
[[nodiscard]] const operator_info_t& get_info() const [[nodiscard]] const operator_info_t& get_info() const
{ {
#if BLT_DEBUG_LEVEL > 0
if (info == nullptr)
throw std::runtime_error(
"Invalid subtree point, operator info was null! "
"(Point probably created with passthrough intentions or operator info was not available, "
"please manually acquire info from the program!)");
#endif
return *info; return *info;
} }
[[nodiscard]] type_id get_type() const [[nodiscard]] type_id get_type() const;
{
return info->return_type;
}
size_t point; size_t point;
const operator_info_t* info; const operator_info_t* info;
@ -316,7 +328,7 @@ namespace blt::gp
* @param operators vector for storing subtree operators * @param operators vector for storing subtree operators
* @param stack stack for storing subtree values * @param stack stack for storing subtree values
*/ */
void copy_subtree(const subtree_point_t point, tracked_vector<op_container_t>& operators, stack_allocator& stack) const; void copy_subtree(subtree_point_t point, tracked_vector<op_container_t>& operators, stack_allocator& stack) const;
void copy_subtree(subtree_point_t point, ptrdiff_t extent, tree_t& out_tree) const; void copy_subtree(subtree_point_t point, ptrdiff_t extent, tree_t& out_tree) const;
@ -376,19 +388,10 @@ namespace blt::gp
*/ */
ptrdiff_t insert_subtree(subtree_point_t point, tree_t& other_tree) const; ptrdiff_t insert_subtree(subtree_point_t point, tree_t& other_tree) const;
/**
* temporarily moves the last bytes amount of data from the current stack. this can be useful for if you are going to do a lot
* of consecutive operations on the tree as this will avoid extra copy + reinsert.
* The object returned by this function will automatically move the data back in when it goes out of scope.
* @param operator_index operator index to move from. this is inclusive
*/
void temporary_move(const size_t)
{
// return obt_move_t{*this, operator_index};
}
void modify_operator(size_t point, operator_id new_id, std::optional<type_id> return_type = {}) const; void modify_operator(size_t point, operator_id new_id, std::optional<type_id> return_type = {}) const;
void swap_operators(size_t point, tree_t& other_tree, size_t other_point) const;
tree_t* tree; tree_t* tree;
}; };
@ -504,6 +507,11 @@ namespace blt::gp
tree_t& operator=(tree_t&& move) = default; tree_t& operator=(tree_t&& move) = default;
tree_manipulator_t manipulate()
{
return tree_manipulator_t{*this};
}
void clear(gp_program& program); void clear(gp_program& program);
void insert_operator(size_t index, const op_container_t& container); void insert_operator(size_t index, const op_container_t& container);

View File

@ -80,7 +80,7 @@ namespace blt::gp
if (!point) if (!point)
return false; return false;
c1.swap_subtrees(point->p1_crossover_point, c2, point->p2_crossover_point); c1.manipulate().easy_manipulator().swap_subtrees(point->p1_crossover_point, c2, point->p2_crossover_point);
#if BLT_DEBUG_LEVEL >= 2 #if BLT_DEBUG_LEVEL >= 2
if (!c1.check(detail::debug::context_ptr) || !c2.check(detail::debug::context_ptr)) if (!c1.check(detail::debug::context_ptr) || !c2.check(detail::debug::context_ptr))
@ -94,7 +94,7 @@ namespace blt::gp
const tree_t& c2) const const tree_t& c2) const
{ {
const auto first = c1.select_subtree(config.terminal_chance); const auto first = c1.select_subtree(config.terminal_chance);
const auto second = c2.select_subtree(first.type, config.max_crossover_tries, config.terminal_chance); const auto second = c2.select_subtree(first.get_type(), config.max_crossover_tries, config.terminal_chance);
if (!second) if (!second)
return {}; return {};
@ -108,13 +108,13 @@ namespace blt::gp
auto c1_point_o = get_point_traverse_retry(c1, {}); auto c1_point_o = get_point_traverse_retry(c1, {});
if (!c1_point_o) if (!c1_point_o)
return {}; return {};
const auto c2_point_o = get_point_traverse_retry(c2, c1_point_o->type); const auto c2_point_o = get_point_traverse_retry(c2, c1_point_o->get_type());
if (!c2_point_o) if (!c2_point_o)
return {}; return {};
return {{*c1_point_o, *c2_point_o}}; return {{*c1_point_o, *c2_point_o}};
} }
std::optional<tree_t::subtree_point_t> subtree_crossover_t::get_point_traverse_retry(const tree_t& t, const std::optional<type_id> type) const std::optional<subtree_point_t> subtree_crossover_t::get_point_traverse_retry(const tree_t& t, const std::optional<type_id> type) const
{ {
if (type) if (type)
return t.select_subtree_traverse(*type, config.max_crossover_tries, config.terminal_chance, config.depth_multiplier); return t.select_subtree_traverse(*type, config.max_crossover_tries, config.terminal_chance, config.depth_multiplier);
@ -126,25 +126,25 @@ namespace blt::gp
// if (p1.size() < config.min_tree_size || p2.size() < config.min_tree_size) // if (p1.size() < config.min_tree_size || p2.size() < config.min_tree_size)
// return false; // return false;
tree_t::subtree_point_t point1, point2; // NOLINT subtree_point_t point1, point2; // NOLINT
if (config.traverse) if (config.traverse)
{ {
point1 = p1.select_subtree_traverse(config.terminal_chance, config.depth_multiplier); point1 = p1.select_subtree_traverse(config.terminal_chance, config.depth_multiplier);
if (const auto val = p2.select_subtree_traverse(point1.type, config.max_crossover_tries, config.terminal_chance, config.depth_multiplier)) if (const auto val = p2.select_subtree_traverse(point1.get_type(), config.max_crossover_tries, config.terminal_chance, config.depth_multiplier))
point2 = *val; point2 = *val;
else else
return false; return false;
} else } else
{ {
point1 = p1.select_subtree(config.terminal_chance); point1 = p1.select_subtree(config.terminal_chance);
if (const auto val = p2.select_subtree(point1.type, config.max_crossover_tries, config.terminal_chance)) if (const auto val = p2.select_subtree(point1.get_type(), config.max_crossover_tries, config.terminal_chance))
point2 = *val; point2 = *val;
else else
return false; return false;
} }
const auto& p1_operator = p1.get_operator(point1.pos); const auto& p1_operator = p1.get_operator(point1.get_point());
const auto& p2_operator = p2.get_operator(point2.pos); const auto& p2_operator = p2.get_operator(point2.get_point());
const auto& p1_info = program.get_operator_info(p1_operator.id()); const auto& p1_info = program.get_operator_info(p1_operator.id());
const auto& p2_info = program.get_operator_info(p2_operator.id()); const auto& p2_info = program.get_operator_info(p2_operator.id());
@ -163,8 +163,8 @@ namespace blt::gp
thread_local struct type_resolver_t thread_local struct type_resolver_t
{ {
tracked_vector<tree_t::child_t> children_data_p1; tracked_vector<child_t> children_data_p1;
tracked_vector<tree_t::child_t> children_data_p2; tracked_vector<child_t> children_data_p2;
hashmap_t<type_id, std::vector<size_t>> missing_p1_types; hashmap_t<type_id, std::vector<size_t>> missing_p1_types;
hashmap_t<type_id, std::vector<size_t>> missing_p2_types; hashmap_t<type_id, std::vector<size_t>> missing_p2_types;
hashset_t<size_t> correct_types; hashset_t<size_t> correct_types;
@ -231,7 +231,7 @@ namespace blt::gp
return correct_types.contains(index) || p2_correct_types.contains(index); return correct_types.contains(index) || p2_correct_types.contains(index);
} }
void clear() void clear(gp_program& program)
{ {
children_data_p1.clear(); children_data_p1.clear();
children_data_p2.clear(); children_data_p2.clear();
@ -249,7 +249,7 @@ namespace blt::gp
v.clear(); v.clear();
} }
} resolver; } resolver;
resolver.clear(); resolver.clear(program);
auto min_size = std::min(p1_info.argument_types.size(), p2_info.argument_types.size()); auto min_size = std::min(p1_info.argument_types.size(), p2_info.argument_types.size());
@ -321,19 +321,19 @@ namespace blt::gp
} }
// now we do the swap // now we do the swap
p1.find_child_extends(resolver.children_data_p1, point1.pos, p1_info.argument_types.size()); p1.find_child_extends(resolver.children_data_p1, point1.get_point(), p1_info.argument_types.size());
p2.find_child_extends(resolver.children_data_p2, point2.pos, p2_info.argument_types.size()); p2.find_child_extends(resolver.children_data_p2, point2.get_point(), p2_info.argument_types.size());
for (const auto& [index1, index2] : resolver.p1_reorder_types) for (const auto& [index1, index2] : resolver.p1_reorder_types)
{ {
BLT_DEBUG("Reordering in C1: {} -> {}", index1, index2); BLT_DEBUG("Reordering in C1: {} -> {}", index1, index2);
c1.swap_subtrees(resolver.children_data_p1[index1], c1, resolver.children_data_p1[index2]); c1.manipulate().easy_manipulator().swap_subtrees(resolver.children_data_p1[index1], c1, resolver.children_data_p1[index2]);
} }
for (const auto& [index1, index2] : resolver.p2_reorder_types) for (const auto& [index1, index2] : resolver.p2_reorder_types)
{ {
BLT_DEBUG("Reordering in C2: {} -> {}", index1, index2); BLT_DEBUG("Reordering in C2: {} -> {}", index1, index2);
c2.swap_subtrees(resolver.children_data_p2[index1], c2, resolver.children_data_p2[index2]); c2.manipulate().easy_manipulator().swap_subtrees(resolver.children_data_p2[index1], c2, resolver.children_data_p2[index2]);
} }
auto c1_insert = resolver.children_data_p1.back().end; auto c1_insert = resolver.children_data_p1.back().end;
@ -342,14 +342,14 @@ namespace blt::gp
for (const auto& [p1_index, p2_index] : resolver.swap_types) for (const auto& [p1_index, p2_index] : resolver.swap_types)
{ {
if (p1_index < p1_info.argument_types.size() && p2_index < p2_info.argument_types.size()) if (p1_index < p1_info.argument_types.size() && p2_index < p2_info.argument_types.size())
c1.swap_subtrees(resolver.children_data_p1[p1_index], c2, resolver.children_data_p2[p2_index]); c1.manipulate().easy_manipulator().swap_subtrees(resolver.children_data_p1[p1_index], c2, resolver.children_data_p2[p2_index]);
else if (p1_index < p1_info.argument_types.size() && p2_index >= p2_info.argument_types.size()) else if (p1_index < p1_info.argument_types.size() && p2_index >= p2_info.argument_types.size())
{ {
BLT_TRACE("(P1 IS UNDER!) Trying to swap P1 {} for P2 {} (Sizes: P1: {} P2: {})", p1_index, p2_index, p1_info.argument_types.size(), p2_info.argument_types.size()); BLT_TRACE("(P1 IS UNDER!) Trying to swap P1 {} for P2 {} (Sizes: P1: {} P2: {})", p1_index, p2_index, p1_info.argument_types.size(), p2_info.argument_types.size());
BLT_TRACE("Inserting into P2 from P1!"); BLT_TRACE("Inserting into P2 from P1!");
c1.copy_subtree(resolver.children_data_p1[p1_index], resolver.temp_tree); c1.manipulate().easy_manipulator().copy_subtree(resolver.children_data_p1[p1_index], resolver.temp_trees[0]);
c1.delete_subtree(resolver.children_data_p1[p1_index]); c1.manipulate().easy_manipulator().delete_subtree(resolver.children_data_p1[p1_index]);
c2_insert = c2.insert_subtree(tree_t::subtree_point_t{c1_insert}, resolver.temp_tree); c2_insert = c2.manipulate().easy_manipulator().insert_subtree(subtree_point_t{c1_insert}, resolver.temp_trees[0]);
} else if (p2_index < p2_info.argument_types.size() && p1_index >= p1_info.argument_types.size()) } else if (p2_index < p2_info.argument_types.size() && p1_index >= p1_info.argument_types.size())
{ {
BLT_TRACE("(P2 IS UNDER!) Trying to swap P1 {} for P2 {} (Sizes: P1: {} P2: {})", p1_index, p2_index, p1_info.argument_types.size(), p2_info.argument_types.size()); BLT_TRACE("(P2 IS UNDER!) Trying to swap P1 {} for P2 {} (Sizes: P1: {} P2: {})", p1_index, p2_index, p1_info.argument_types.size(), p2_info.argument_types.size());
@ -360,8 +360,8 @@ namespace blt::gp
} }
c1.modify_operator(point1.pos, p2_operator.id(), p2_info.return_type); c1.manipulate().easy_manipulator().modify_operator(point1.get_point(), p2_operator.id(), p2_info.return_type);
c2.modify_operator(point2.pos, p1_operator.id(), p1_info.return_type); c2.manipulate().easy_manipulator().modify_operator(point2.get_point(), p1_operator.id(), p1_info.return_type);
#if BLT_DEBUG_LEVEL >= 2 #if BLT_DEBUG_LEVEL >= 2
if (!c1.check(detail::debug::context_ptr) || !c2.check(detail::debug::context_ptr)) if (!c1.check(detail::debug::context_ptr) || !c2.check(detail::debug::context_ptr))
@ -413,17 +413,17 @@ namespace blt::gp
return true; return true;
} }
size_t mutation_t::mutate_point(gp_program& program, tree_t& c, const tree_t::subtree_point_t node) const size_t mutation_t::mutate_point(gp_program& program, tree_t& c, const subtree_point_t node) const
{ {
auto& new_tree = tree_t::get_thread_local(program); auto& new_tree = tree_t::get_thread_local(program);
#if BLT_DEBUG_LEVEL >= 2 #if BLT_DEBUG_LEVEL >= 2
auto previous_size = new_tree.size(); auto previous_size = new_tree.size();
auto previous_bytes = new_tree.total_value_bytes(); auto previous_bytes = new_tree.total_value_bytes();
#endif #endif
config.generator.get().generate(new_tree, {program, node.type, config.replacement_min_depth, config.replacement_max_depth}); config.generator.get().generate(new_tree, {program, node.get_type(), config.replacement_min_depth, config.replacement_max_depth});
#if BLT_DEBUG_LEVEL >= 2 #if BLT_DEBUG_LEVEL >= 2
const auto old_op = c.get_operator(node.pos); const auto old_op = c.get_operator(node.get_point());
if (!new_tree.check(detail::debug::context_ptr)) if (!new_tree.check(detail::debug::context_ptr))
{ {
BLT_ERROR("Mutate point new tree check failed!"); BLT_ERROR("Mutate point new tree check failed!");
@ -434,11 +434,11 @@ namespace blt::gp
} }
#endif #endif
c.replace_subtree(node, new_tree); c.manipulate().easy_manipulator().replace_subtree(node, new_tree);
// this will check to make sure that the tree is in a correct and executable state. it requires that the evaluation is context free! // 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 #if BLT_DEBUG_LEVEL >= 2
const auto new_op = c.get_operator(node.pos); const auto new_op = c.get_operator(node.get_point());
if (!c.check(detail::debug::context_ptr)) if (!c.check(detail::debug::context_ptr))
{ {
print_mutate_stats(); print_mutate_stats();
@ -450,7 +450,7 @@ namespace blt::gp
#if defined(BLT_TRACK_ALLOCATIONS) || BLT_DEBUG_LEVEL >= 2 #if defined(BLT_TRACK_ALLOCATIONS) || BLT_DEBUG_LEVEL >= 2
++mutate_point_counter; ++mutate_point_counter;
#endif #endif
return node.pos + new_tree.size(); return node.get_point() + new_tree.size();
} }
bool advanced_mutation_t::apply(gp_program& program, [[maybe_unused]] const tree_t& p, tree_t& c) bool advanced_mutation_t::apply(gp_program& program, [[maybe_unused]] const tree_t& p, tree_t& c)
@ -496,7 +496,7 @@ namespace blt::gp
auto& replacement_func_info = program.get_operator_info(random_replacement); auto& replacement_func_info = program.get_operator_info(random_replacement);
// cache memory used for offset data. // cache memory used for offset data.
thread_local tracked_vector<tree_t::child_t> children_data; thread_local tracked_vector<child_t> children_data;
children_data.clear(); children_data.clear();
c.find_child_extends(children_data, c_node, current_func_info.argument_types.size()); c.find_child_extends(children_data, c_node, current_func_info.argument_types.size());
@ -512,7 +512,7 @@ namespace blt::gp
{program, val.id, config.replacement_min_depth, config.replacement_max_depth}); {program, val.id, config.replacement_min_depth, config.replacement_max_depth});
auto& [child_start, child_end] = children_data[children_data.size() - 1 - index]; auto& [child_start, child_end] = children_data[children_data.size() - 1 - index];
c.replace_subtree(c.subtree_from_point(child_start), child_end, tree); c.manipulate().easy_manipulator().replace_subtree(c.subtree_from_point(child_start), child_end, tree);
// shift over everybody after. // shift over everybody after.
if (index > 0) if (index > 0)
@ -537,7 +537,7 @@ namespace blt::gp
{ {
auto end_index = children_data[(current_func_info.argc.argc - replacement_func_info.argc.argc) - 1].end; auto end_index = children_data[(current_func_info.argc.argc - replacement_func_info.argc.argc) - 1].end;
auto start_index = children_data.begin()->start; auto start_index = children_data.begin()->start;
c.delete_subtree(tree_t::subtree_point_t(start_index), end_index); c.manipulate().easy_manipulator().delete_subtree(subtree_point_t(start_index), 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)
{ {
@ -561,11 +561,11 @@ namespace blt::gp
program, replacement_func_info.argument_types[i].id, config.replacement_min_depth, program, replacement_func_info.argument_types[i].id, config.replacement_min_depth,
config.replacement_max_depth config.replacement_max_depth
}); });
start_index = c.insert_subtree(tree_t::subtree_point_t(static_cast<ptrdiff_t>(start_index)), tree); start_index = c.manipulate().easy_manipulator().insert_subtree(subtree_point_t(static_cast<ptrdiff_t>(start_index)), tree);
} }
} }
// now finally update the type. // now finally update the type.
c.modify_operator(c_node, random_replacement, replacement_func_info.return_type); c.manipulate().easy_manipulator().modify_operator(c_node, random_replacement, replacement_func_info.return_type);
} }
#if BLT_DEBUG_LEVEL >= 2 #if BLT_DEBUG_LEVEL >= 2
if (!c.check(detail::debug::context_ptr)) if (!c.check(detail::debug::context_ptr))
@ -636,7 +636,7 @@ namespace blt::gp
program, replacement_func_info.argument_types[i].id, config.replacement_min_depth, program, replacement_func_info.argument_types[i].id, config.replacement_min_depth,
config.replacement_max_depth config.replacement_max_depth
}); });
start_index = c.insert_subtree(tree_t::subtree_point_t(static_cast<ptrdiff_t>(start_index)), tree); start_index = c.manipulate().easy_manipulator().insert_subtree(subtree_point_t(static_cast<ptrdiff_t>(start_index)), tree);
} }
start_index += size; start_index += size;
// vals.copy_from(combined_ptr, for_bytes); // vals.copy_from(combined_ptr, for_bytes);
@ -648,7 +648,7 @@ namespace blt::gp
program, replacement_func_info.argument_types[i].id, config.replacement_min_depth, program, replacement_func_info.argument_types[i].id, config.replacement_min_depth,
config.replacement_max_depth config.replacement_max_depth
}); });
start_index = c.insert_subtree(tree_t::subtree_point_t(static_cast<ptrdiff_t>(start_index)), tree); start_index = c.manipulate().easy_manipulator().insert_subtree(subtree_point_t(static_cast<ptrdiff_t>(start_index)), tree);
} }
// vals.copy_from(combined_ptr + for_bytes, after_bytes); // vals.copy_from(combined_ptr + for_bytes, after_bytes);
@ -690,7 +690,7 @@ namespace blt::gp
if (argument_index == -1ul) if (argument_index == -1ul)
continue; continue;
thread_local tracked_vector<tree_t::child_t> child_data; thread_local tracked_vector<child_t> child_data;
child_data.clear(); child_data.clear();
c.find_child_extends(child_data, c_node, info.argument_types.size()); c.find_child_extends(child_data, c_node, info.argument_types.size());
@ -700,9 +700,9 @@ namespace blt::gp
thread_local tree_t child_tree{program}; thread_local tree_t child_tree{program};
c.copy_subtree(tree_t::subtree_point_t(child.start), child.end, child_tree); c.manipulate().easy_manipulator().copy_subtree(subtree_point_t(child.start), child.end, child_tree);
c.delete_subtree(tree_t::subtree_point_t(static_cast<ptrdiff_t>(c_node))); c.manipulate().easy_manipulator().delete_subtree(subtree_point_t(static_cast<ptrdiff_t>(c_node)));
c.insert_subtree(tree_t::subtree_point_t(static_cast<ptrdiff_t>(c_node)), child_tree); c.manipulate().easy_manipulator().insert_subtree(subtree_point_t(static_cast<ptrdiff_t>(c_node)), child_tree);
child_tree.clear(program); child_tree.clear(program);
// auto for_bytes = c.total_value_bytes(child.start, child.end); // auto for_bytes = c.total_value_bytes(child.start, child.end);
@ -769,7 +769,7 @@ namespace blt::gp
continue; continue;
const auto to_index = program.get_random().select(potential_indexes); const auto to_index = program.get_random().select(potential_indexes);
thread_local tracked_vector<tree_t::child_t> child_data; thread_local tracked_vector<child_t> child_data;
child_data.clear(); child_data.clear();
c.find_child_extends(child_data, c_node, info.argument_types.size()); c.find_child_extends(child_data, c_node, info.argument_types.size());
@ -780,8 +780,8 @@ namespace blt::gp
const auto& [to_start, to_end] = child_data[child_to_index]; const auto& [to_start, to_end] = child_data[child_to_index];
thread_local tree_t copy_tree{program}; thread_local tree_t copy_tree{program};
c.copy_subtree(tree_t::subtree_point_t{from_start}, from_end, copy_tree); c.manipulate().easy_manipulator().copy_subtree(subtree_point_t{from_start}, from_end, copy_tree);
c.replace_subtree(tree_t::subtree_point_t{to_start}, to_end, copy_tree); c.manipulate().easy_manipulator().replace_subtree(subtree_point_t{to_start}, to_end, copy_tree);
copy_tree.clear(program); copy_tree.clear(program);
#if BLT_DEBUG_LEVEL >= 2 #if BLT_DEBUG_LEVEL >= 2

View File

@ -125,13 +125,10 @@ namespace blt::gp
create_indent(out, indent, pretty_print) << ")" << end_indent(pretty_print); create_indent(out, indent, pretty_print) << ")" << end_indent(pretty_print);
continue; continue;
} }
else if (!pretty_print)
{ out << " ";
if (!pretty_print) arguments_left.push(top - 1);
out << " "; break;
arguments_left.push(top - 1);
break;
}
} }
} }
while (!arguments_left.empty()) while (!arguments_left.empty())
@ -252,7 +249,7 @@ namespace blt::gp
} }
std::optional<subtree_point_t> tree_t::select_subtree_traverse(const type_id type, const u32 max_tries, const double terminal_chance, std::optional<subtree_point_t> tree_t::select_subtree_traverse(const type_id type, const u32 max_tries, const double terminal_chance,
const double depth_multiplier) const const double depth_multiplier) const
{ {
for (u32 i = 0; i < max_tries; ++i) for (u32 i = 0; i < max_tries; ++i)
{ {
@ -262,7 +259,8 @@ namespace blt::gp
return {}; return {};
} }
void slow_tree_manipulator_t::copy_subtree(const subtree_point_t point, const ptrdiff_t extent, tracked_vector<op_container_t>& operators, stack_allocator& stack) const void slow_tree_manipulator_t::copy_subtree(const subtree_point_t point, const ptrdiff_t extent, tracked_vector<op_container_t>& operators,
stack_allocator& stack) const
{ {
const auto point_begin_itr = tree->operations.begin() + point.get_spoint(); const auto point_begin_itr = tree->operations.begin() + point.get_spoint();
const auto point_end_itr = tree->operations.begin() + extent; const auto point_end_itr = tree->operations.begin() + extent;
@ -310,7 +308,7 @@ namespace blt::gp
void slow_tree_manipulator_t::copy_subtree(const child_t subtree, tree_t& out_tree) const void slow_tree_manipulator_t::copy_subtree(const child_t subtree, tree_t& out_tree) const
{ {
copy_subtree(subtree_point_t{subtree.start, tree->m_program->get_operator_info(tree->operations[subtree.start].id())}, subtree.end, out_tree); copy_subtree(subtree_point_t{subtree.start}, subtree.end, out_tree);
} }
void slow_tree_manipulator_t::swap_subtrees(const child_t our_subtree, tree_t& other_tree, const child_t other_subtree) const void slow_tree_manipulator_t::swap_subtrees(const child_t our_subtree, tree_t& other_tree, const child_t other_subtree) const
@ -385,7 +383,7 @@ namespace blt::gp
void slow_tree_manipulator_t::swap_subtrees(const subtree_point_t our_subtree, tree_t& other_tree, const subtree_point_t other_subtree) const void slow_tree_manipulator_t::swap_subtrees(const subtree_point_t our_subtree, tree_t& other_tree, const subtree_point_t other_subtree) const
{ {
swap_subtrees(child_t{our_subtree.get_spoint(), tree->find_endpoint(our_subtree.get_spoint())}, other_tree, swap_subtrees(child_t{our_subtree.get_spoint(), tree->find_endpoint(our_subtree.get_spoint())}, other_tree,
child_t{other_subtree.get_spoint(), tree->find_endpoint(other_subtree.get_spoint())}); child_t{other_subtree.get_spoint(), other_tree.find_endpoint(other_subtree.get_spoint())});
} }
void slow_tree_manipulator_t::replace_subtree(const subtree_point_t point, const ptrdiff_t extent, const tree_t& other_tree) const void slow_tree_manipulator_t::replace_subtree(const subtree_point_t point, const ptrdiff_t extent, const tree_t& other_tree) const
@ -660,6 +658,17 @@ namespace blt::gp
{ {
} }
type_id subtree_point_t::get_type() const
{
#if BLT_DEBUG_LEVEL > 0
if (info == nullptr)
throw std::runtime_error(
"Invalid subtree point, operator info was null! (Point probably created with passthrough "
"intentions or operator info was not available, please manually acquire type)");
#endif
return info->return_type;
}
void single_operation_tree_manipulator_t::replace_subtree(tree_t& other_tree) void single_operation_tree_manipulator_t::replace_subtree(tree_t& other_tree)
{ {
replace_subtree(other_tree.operations, other_tree.values); replace_subtree(other_tree.operations, other_tree.values);
@ -667,7 +676,6 @@ namespace blt::gp
void single_operation_tree_manipulator_t::replace_subtree(tracked_vector<op_container_t>& operations, stack_allocator& stack) void single_operation_tree_manipulator_t::replace_subtree(tracked_vector<op_container_t>& operations, stack_allocator& stack)
{ {
} }
void tree_t::copy_fast(const tree_t& copy) void tree_t::copy_fast(const tree_t& copy)
@ -877,13 +885,18 @@ namespace blt::gp
{ {
if (move_data.empty()) if (move_data.empty())
{ {
const size_t after_bytes = calculate_ephemeral_size(tree->operations.begin() + static_cast<ptrdiff_t>(point) + 1, tree->operations.end()); const size_t after_bytes = calculate_ephemeral_size(tree->operations.begin() + static_cast<ptrdiff_t>(point) + 1,
tree->operations.end());
move_data.move(after_bytes); move_data.move(after_bytes);
} }
tree->handle_operator_inserted(tree->operations[point]); tree->handle_operator_inserted(tree->operations[point]);
} }
} }
void slow_tree_manipulator_t::swap_operators(size_t point, tree_t& other_tree, size_t other_point) const
{
}
bool operator==(const tree_t& a, const tree_t& b) bool operator==(const tree_t& a, const tree_t& b)
{ {
if (a.operations.size() != b.operations.size()) if (a.operations.size() != b.operations.size())