fix copy op, change selection behaviour
parent
82c535dbd1
commit
a58fe64c0e
|
@ -27,7 +27,7 @@ macro(compile_options target_name)
|
|||
sanitizers(${target_name})
|
||||
endmacro()
|
||||
|
||||
project(blt-gp VERSION 0.3.30)
|
||||
project(blt-gp VERSION 0.3.31)
|
||||
|
||||
include(CTest)
|
||||
|
||||
|
|
|
@ -35,7 +35,7 @@ blt::gp::prog_config_t config = blt::gp::prog_config_t()
|
|||
.set_initial_min_tree_size(2)
|
||||
.set_initial_max_tree_size(6)
|
||||
.set_elite_count(2)
|
||||
.set_crossover_chance(0.9)
|
||||
.set_crossover_chance(0.8)
|
||||
.set_mutation_chance(0.1)
|
||||
.set_reproduction_chance(0)
|
||||
.set_max_generations(50)
|
||||
|
|
|
@ -568,9 +568,9 @@ namespace blt::gp
|
|||
|
||||
while (thread_helper.next_gen_left > 0)
|
||||
{
|
||||
blt::size_t size = 0;
|
||||
blt::size_t begin = 0;
|
||||
blt::size_t end = thread_helper.next_gen_left.load(std::memory_order_relaxed);
|
||||
size_t size = 0;
|
||||
size_t begin = 0;
|
||||
size_t end = thread_helper.next_gen_left.load(std::memory_order_relaxed);
|
||||
do
|
||||
{
|
||||
size = std::min(end, config.evaluation_size);
|
||||
|
@ -766,26 +766,24 @@ namespace blt::gp
|
|||
{
|
||||
if (get_random().choice(selection_probabilities.crossover_chance))
|
||||
{
|
||||
// if (c2 == nullptr)
|
||||
// return 0;
|
||||
// auto ptr = c2;
|
||||
// if (ptr == nullptr)
|
||||
// ptr = &tree_t::get_thread_local(*this);
|
||||
auto ptr = c2;
|
||||
if (ptr == nullptr)
|
||||
ptr = &tree_t::get_thread_local(*this);
|
||||
#ifdef BLT_TRACK_ALLOCATIONS
|
||||
auto state = tracker.start_measurement_thread_local();
|
||||
#endif
|
||||
const tree_t* p1;
|
||||
const tree_t* p2;
|
||||
size_t runs = 0;
|
||||
tree_t tree{*this};
|
||||
do
|
||||
{
|
||||
// BLT_TRACE("%lu %p %p", runs, &c1, &tree);
|
||||
p1 = &crossover.select(*this, current_pop);
|
||||
p2 = &crossover.select(*this, current_pop);
|
||||
// BLT_TRACE("%p %p || %lu", p1, p2, current_pop.get_individuals().size());
|
||||
|
||||
c1.copy_fast(*p1);
|
||||
tree.copy_fast(*p2);
|
||||
ptr->copy_fast(*p2);
|
||||
// ptr->copy_fast(*p2);
|
||||
|
||||
if (++runs >= config.crossover.get().get_config().max_crossover_iterations)
|
||||
|
@ -794,7 +792,7 @@ namespace blt::gp
|
|||
crossover_calls.value(1);
|
||||
#endif
|
||||
}
|
||||
while (!config.crossover.get().apply(*this, *p1, *p2, c1, tree));
|
||||
while (!config.crossover.get().apply(*this, *p1, *p2, c1, *ptr));
|
||||
#ifdef BLT_TRACK_ALLOCATIONS
|
||||
tracker.stop_measurement_thread_local(state);
|
||||
crossover_calls.call();
|
||||
|
@ -804,10 +802,11 @@ namespace blt::gp
|
|||
crossover_allocations.set_value(std::max(crossover_allocations.get_value(), state.getAllocatedByteDifference()));
|
||||
}
|
||||
#endif
|
||||
// if (c2 == nullptr)
|
||||
// tree_t::get_thread_local(*this);
|
||||
if (c2 != nullptr)
|
||||
*c2 = tree;
|
||||
if (c2 == nullptr)
|
||||
{
|
||||
tree_t::get_thread_local(*this).clear(*this);
|
||||
return 1;
|
||||
}
|
||||
return 2;
|
||||
}
|
||||
if (get_random().choice(selection_probabilities.mutation_chance))
|
||||
|
|
|
@ -30,16 +30,16 @@ namespace blt::gp
|
|||
{
|
||||
namespace detail
|
||||
{
|
||||
template<typename T>
|
||||
template <typename T>
|
||||
inline static constexpr double sum(const T& array)
|
||||
{
|
||||
double init = 0.0;
|
||||
for (double i : array)
|
||||
for (const double i : array)
|
||||
init += i;
|
||||
return init;
|
||||
}
|
||||
|
||||
template<blt::size_t size, typename... Args>
|
||||
|
||||
template <size_t size, typename... Args>
|
||||
static constexpr std::array<double, size> aggregate_array(Args... list)
|
||||
{
|
||||
std::array<double, size> data{list...};
|
||||
|
@ -54,145 +54,151 @@ namespace blt::gp
|
|||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class crossover_t
|
||||
{
|
||||
public:
|
||||
struct point_info_t
|
||||
{
|
||||
ptrdiff_t point;
|
||||
operator_info_t& type_operator_info;
|
||||
};
|
||||
struct crossover_point_t
|
||||
{
|
||||
tree_t::subtree_point_t p1_crossover_point;
|
||||
tree_t::subtree_point_t p2_crossover_point;
|
||||
};
|
||||
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
|
||||
u32 max_crossover_tries = 5;
|
||||
// how many times the crossover function can fail before we will skip this operation.
|
||||
u32 max_crossover_iterations = 10;
|
||||
// if tree have fewer nodes than this number, they will not be considered for crossover
|
||||
// should be at least 5 as crossover will not select the root node.
|
||||
u32 min_tree_size = 5;
|
||||
// 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 depth_multiplier = 0.5;
|
||||
// how often should we select terminals over functions. By default, we only allow selection of terminals 10% of the time
|
||||
// this applies to both types of crossover point functions. Traversal will use the parent if it should not pick a terminal.
|
||||
f32 terminal_chance = 0.1;
|
||||
// use traversal to select point instead of random selection
|
||||
bool traverse = false;
|
||||
};
|
||||
|
||||
crossover_t() = default;
|
||||
|
||||
explicit crossover_t(const config_t& config): config(config)
|
||||
{}
|
||||
public:
|
||||
struct point_info_t
|
||||
{
|
||||
ptrdiff_t point;
|
||||
operator_info_t& type_operator_info;
|
||||
};
|
||||
|
||||
[[nodiscard]] const config_t& get_config() const
|
||||
{
|
||||
return config;
|
||||
}
|
||||
|
||||
std::optional<crossover_point_t> get_crossover_point(const tree_t& c1, const tree_t& c2) const;
|
||||
|
||||
std::optional<crossover_point_t> get_crossover_point_traverse(const tree_t& c1, const tree_t& c2) const;
|
||||
|
||||
/**
|
||||
* child1 and child2 are copies of the parents, the result of selecting a crossover point and performing standard subtree crossover.
|
||||
* the parents are not modified during this process
|
||||
* @param program reference to the global program container responsible for managing these trees
|
||||
* @param p1 reference to the first parent
|
||||
* @param p2 reference to the second parent
|
||||
* @return expected pair of child otherwise returns error enum
|
||||
*/
|
||||
virtual bool apply(gp_program& program, const tree_t& p1, const tree_t& p2, tree_t& c1, tree_t& c2); // NOLINT
|
||||
|
||||
virtual ~crossover_t() = default;
|
||||
|
||||
protected:
|
||||
[[nodiscard]] std::optional<tree_t::subtree_point_t> get_point_traverse_retry(const tree_t& t, std::optional<type_id> type) const;
|
||||
|
||||
config_t config;
|
||||
struct crossover_point_t
|
||||
{
|
||||
tree_t::subtree_point_t p1_crossover_point;
|
||||
tree_t::subtree_point_t p2_crossover_point;
|
||||
};
|
||||
|
||||
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
|
||||
u32 max_crossover_tries = 5;
|
||||
// how many times the crossover function can fail before we will skip this operation.
|
||||
u32 max_crossover_iterations = 10;
|
||||
// if tree have fewer nodes than this number, they will not be considered for crossover
|
||||
// should be at least 5 as crossover will not select the root node.
|
||||
u32 min_tree_size = 5;
|
||||
// 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 depth_multiplier = 0.5;
|
||||
// how often should we select terminals over functions. By default, we only allow selection of terminals 10% of the time
|
||||
// this applies to both types of crossover point functions. Traversal will use the parent if it should not pick a terminal.
|
||||
f32 terminal_chance = 0.1;
|
||||
// use traversal to select point instead of random selection
|
||||
bool traverse = false;
|
||||
};
|
||||
|
||||
crossover_t() = default;
|
||||
|
||||
explicit crossover_t(const config_t& config): config(config)
|
||||
{
|
||||
}
|
||||
|
||||
[[nodiscard]] const config_t& get_config() const
|
||||
{
|
||||
return config;
|
||||
}
|
||||
|
||||
std::optional<crossover_point_t> get_crossover_point(const tree_t& c1, const tree_t& c2) const;
|
||||
|
||||
std::optional<crossover_point_t> get_crossover_point_traverse(const tree_t& c1, const tree_t& c2) const;
|
||||
|
||||
/**
|
||||
* child1 and child2 are copies of the parents, the result of selecting a crossover point and performing standard subtree crossover.
|
||||
* the parents are not modified during this process
|
||||
* @param program reference to the global program container responsible for managing these trees
|
||||
* @param p1 reference to the first parent
|
||||
* @param p2 reference to the second parent
|
||||
* @return expected pair of child otherwise returns error enum
|
||||
*/
|
||||
virtual bool apply(gp_program& program, const tree_t& p1, const tree_t& p2, tree_t& c1, tree_t& c2); // NOLINT
|
||||
|
||||
virtual ~crossover_t() = default;
|
||||
|
||||
protected:
|
||||
[[nodiscard]] std::optional<tree_t::subtree_point_t> get_point_traverse_retry(const tree_t& t, std::optional<type_id> type) const;
|
||||
|
||||
config_t config;
|
||||
};
|
||||
|
||||
|
||||
class mutation_t
|
||||
{
|
||||
public:
|
||||
struct config_t
|
||||
public:
|
||||
struct config_t
|
||||
{
|
||||
blt::size_t replacement_min_depth = 2;
|
||||
blt::size_t replacement_max_depth = 6;
|
||||
|
||||
std::reference_wrapper<tree_generator_t> generator;
|
||||
|
||||
config_t(tree_generator_t& generator): generator(generator) // NOLINT
|
||||
{
|
||||
blt::size_t replacement_min_depth = 2;
|
||||
blt::size_t replacement_max_depth = 6;
|
||||
|
||||
std::reference_wrapper<tree_generator_t> generator;
|
||||
|
||||
config_t(tree_generator_t& generator): generator(generator) // NOLINT
|
||||
{}
|
||||
|
||||
config_t();
|
||||
};
|
||||
|
||||
mutation_t() = default;
|
||||
|
||||
explicit mutation_t(const config_t& config): config(config)
|
||||
{}
|
||||
|
||||
virtual bool apply(gp_program& program, const tree_t& p, tree_t& c);
|
||||
|
||||
// returns the point after the mutation
|
||||
size_t mutate_point(gp_program& program, tree_t& c, tree_t::subtree_point_t node) const;
|
||||
|
||||
virtual ~mutation_t() = default;
|
||||
|
||||
protected:
|
||||
config_t config;
|
||||
}
|
||||
|
||||
config_t();
|
||||
};
|
||||
|
||||
mutation_t() = default;
|
||||
|
||||
explicit mutation_t(const config_t& config): config(config)
|
||||
{
|
||||
}
|
||||
|
||||
virtual bool apply(gp_program& program, const tree_t& p, tree_t& c);
|
||||
|
||||
// returns the point after the mutation
|
||||
size_t mutate_point(gp_program& program, tree_t& c, tree_t::subtree_point_t node) const;
|
||||
|
||||
virtual ~mutation_t() = default;
|
||||
|
||||
protected:
|
||||
config_t config;
|
||||
};
|
||||
|
||||
|
||||
class advanced_mutation_t : public mutation_t
|
||||
{
|
||||
public:
|
||||
enum class mutation_operator : blt::i32
|
||||
{
|
||||
EXPRESSION, // Generate a new random expression
|
||||
ADJUST, // adjust the value of the type. (if it is a function it will mutate it to a different one)
|
||||
SUB_FUNC, // subexpression becomes argument to new random function. Other args are generated.
|
||||
JUMP_FUNC, // subexpression becomes this new node. Other arguments discarded.
|
||||
COPY, // node can become copy of another subexpression.
|
||||
END, // helper
|
||||
};
|
||||
|
||||
advanced_mutation_t() = default;
|
||||
|
||||
explicit advanced_mutation_t(const config_t& config): mutation_t(config)
|
||||
{}
|
||||
|
||||
bool apply(gp_program& program, const tree_t& p, tree_t& c) final;
|
||||
|
||||
advanced_mutation_t& set_per_node_mutation_chance(double v)
|
||||
{
|
||||
per_node_mutation_chance = v;
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
static constexpr auto operators_size = static_cast<blt::i32>(mutation_operator::END);
|
||||
private:
|
||||
// this value is adjusted inversely to the size of the tree.
|
||||
double per_node_mutation_chance = 5.0;
|
||||
|
||||
static constexpr std::array<double, operators_size> mutation_operator_chances = detail::aggregate_array<operators_size>(
|
||||
0.25, // EXPRESSION
|
||||
0.15, // ADJUST
|
||||
0.01, // SUB_FUNC
|
||||
0.01, // JUMP_FUNC
|
||||
0.05 // COPY
|
||||
);
|
||||
public:
|
||||
enum class mutation_operator : i32
|
||||
{
|
||||
EXPRESSION, // Generate a new random expression
|
||||
ADJUST, // adjust the value of the type. (if it is a function it will mutate it to a different one)
|
||||
SUB_FUNC, // subexpression becomes argument to new random function. Other args are generated.
|
||||
JUMP_FUNC, // subexpression becomes this new node. Other arguments discarded.
|
||||
COPY, // node can become copy of another subexpression.
|
||||
END, // helper
|
||||
};
|
||||
|
||||
advanced_mutation_t() = default;
|
||||
|
||||
explicit advanced_mutation_t(const config_t& config): mutation_t(config)
|
||||
{
|
||||
}
|
||||
|
||||
bool apply(gp_program& program, const tree_t& p, tree_t& c) final;
|
||||
|
||||
advanced_mutation_t& set_per_node_mutation_chance(double v)
|
||||
{
|
||||
per_node_mutation_chance = v;
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
static constexpr auto operators_size = static_cast<blt::i32>(mutation_operator::END);
|
||||
|
||||
private:
|
||||
// this value is adjusted inversely to the size of the tree.
|
||||
double per_node_mutation_chance = 5.0;
|
||||
|
||||
static constexpr std::array<double, operators_size> mutation_operator_chances = detail::aggregate_array<operators_size>(
|
||||
0.25, // EXPRESSION
|
||||
0.20, // ADJUST
|
||||
0.05, // SUB_FUNC
|
||||
0.15, // JUMP_FUNC
|
||||
0.10 // COPY
|
||||
);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif //BLT_GP_TRANSFORMERS_H
|
||||
|
|
2
lib/blt
2
lib/blt
|
@ -1 +1 @@
|
|||
Subproject commit 74c1010118c3ae13f27499f564ce477b23ae0b0a
|
||||
Subproject commit baa5952666594ce0d07a2b013e46c4bc343ba164
|
|
@ -26,7 +26,7 @@
|
|||
|
||||
namespace blt::gp
|
||||
{
|
||||
#if BLT_DEBUG_LEVEL >= 2
|
||||
#if BLT_DEBUG_LEVEL >= 2 || defined(BLT_TRACK_ALLOCATIONS)
|
||||
std::atomic_uint64_t mutate_point_counter = 0;
|
||||
std::atomic_uint64_t mutate_expression_counter = 0;
|
||||
std::atomic_uint64_t mutate_adjust_counter = 0;
|
||||
|
@ -36,35 +36,31 @@ namespace blt::gp
|
|||
|
||||
inline void print_mutate_stats()
|
||||
{
|
||||
std::cerr << "Mutation statistics:" << std::endl;
|
||||
std::cerr << "Mutation statistics (Total: " << (mutate_point_counter + mutate_expression_counter + mutate_adjust_counter +
|
||||
mutate_sub_func_counter + mutate_jump_counter + mutate_copy_counter) << "):" << std::endl;
|
||||
std::cerr << "\tSuccessful Point Mutations: " << mutate_point_counter << std::endl;
|
||||
std::cerr << "\tSuccessful Expression Mutations: " << mutate_expression_counter << std::endl;
|
||||
std::cerr << "\tSuccessful Adjust Mutations: " << mutate_adjust_counter << std::endl;
|
||||
std::cerr << "\tSuccessful Sub Func Mutations: " << mutate_sub_func_counter << std::endl;
|
||||
std::cerr << "\tSuccessful Func Jump Mutations: " << mutate_jump_counter << std::endl;
|
||||
std::cerr << "\tSuccessful Jump Mutations: " << mutate_jump_counter << std::endl;
|
||||
std::cerr << "\tSuccessful Copy Mutations: " << mutate_copy_counter << std::endl;
|
||||
}
|
||||
#ifdef BLT_TRACK_ALLOCATIONS
|
||||
|
||||
struct run_me_baby
|
||||
{
|
||||
~run_me_baby()
|
||||
{
|
||||
print_mutate_stats();
|
||||
}
|
||||
};
|
||||
|
||||
run_me_baby this_will_run_when_program_exits;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
grow_generator_t grow_generator;
|
||||
|
||||
inline tree_t& get_static_tree_tl(gp_program& program)
|
||||
{
|
||||
thread_local tree_t new_tree{program};
|
||||
new_tree.clear(program);
|
||||
return new_tree;
|
||||
}
|
||||
|
||||
// TODO: consolidate the two copies of this. other is in tree.cpp
|
||||
template <typename>
|
||||
static u8* get_thread_pointer_for_size(const size_t bytes)
|
||||
{
|
||||
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)
|
||||
{
|
||||
}
|
||||
|
@ -147,7 +143,7 @@ namespace blt::gp
|
|||
|
||||
size_t mutation_t::mutate_point(gp_program& program, tree_t& c, const tree_t::subtree_point_t node) const
|
||||
{
|
||||
auto& new_tree = get_static_tree_tl(program);
|
||||
auto& new_tree = tree_t::get_thread_local(program);
|
||||
config.generator.get().generate(new_tree, {program, node.type, config.replacement_min_depth, config.replacement_max_depth});
|
||||
|
||||
c.replace_subtree(node, new_tree);
|
||||
|
@ -159,6 +155,8 @@ namespace blt::gp
|
|||
print_mutate_stats();
|
||||
throw std::runtime_error("Mutate Point tree check failed");
|
||||
}
|
||||
#endif
|
||||
#if defined(BLT_TRACK_ALLOCATIONS) || BLT_DEBUG_LEVEL >= 2
|
||||
++mutate_point_counter;
|
||||
#endif
|
||||
return node.pos + new_tree.size();
|
||||
|
@ -177,23 +175,13 @@ namespace blt::gp
|
|||
// select an operator to apply
|
||||
auto selected_point = static_cast<i32>(mutation_operator::COPY);
|
||||
auto choice = program.get_random().get_double();
|
||||
for (const auto& [index, value] : blt::enumerate(mutation_operator_chances))
|
||||
|
||||
for (const auto& [index, value] : enumerate(mutation_operator_chances))
|
||||
{
|
||||
if (index == 0)
|
||||
if (choice <= value)
|
||||
{
|
||||
if (choice <= value)
|
||||
{
|
||||
selected_point = static_cast<blt::i32>(index);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (choice > mutation_operator_chances[index - 1] && choice <= value)
|
||||
{
|
||||
selected_point = static_cast<blt::i32>(index);
|
||||
break;
|
||||
}
|
||||
selected_point = static_cast<i32>(index);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -201,7 +189,7 @@ namespace blt::gp
|
|||
{
|
||||
case mutation_operator::EXPRESSION:
|
||||
c_node += mutate_point(program, c, c.subtree_from_point(static_cast<ptrdiff_t>(c_node)));
|
||||
#if BLT_DEBUG_LEVEL >= 2
|
||||
#if BLT_TRACK_ALLOCATIONS || BLT_DEBUG_LEVEL >= 2
|
||||
++mutate_expression_counter;
|
||||
#endif
|
||||
break;
|
||||
|
@ -228,7 +216,7 @@ namespace blt::gp
|
|||
if (index < current_func_info.argument_types.size() && val.id != current_func_info.argument_types[index].id)
|
||||
{
|
||||
// TODO: new config?
|
||||
auto& tree = get_static_tree_tl(program);
|
||||
auto& tree = tree_t::get_thread_local(program);
|
||||
config.generator.get().generate(tree,
|
||||
{program, val.id, config.replacement_min_depth, config.replacement_max_depth});
|
||||
|
||||
|
@ -251,15 +239,6 @@ namespace blt::gp
|
|||
}
|
||||
}
|
||||
child_end = static_cast<ptrdiff_t>(child_start + tree.size());
|
||||
|
||||
#if BLT_DEBUG_LEVEL >= 2
|
||||
if (!c.check(detail::debug::context_ptr))
|
||||
{
|
||||
print_mutate_stats();
|
||||
throw std::runtime_error("Adjust Tree check failed");
|
||||
}
|
||||
++mutate_adjust_counter;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -285,7 +264,7 @@ namespace blt::gp
|
|||
for (ptrdiff_t i = static_cast<ptrdiff_t>(replacement_func_info.argc.argc) - 1;
|
||||
i >= current_func_info.argc.argc; i--)
|
||||
{
|
||||
auto& tree = get_static_tree_tl(program);
|
||||
auto& tree = tree_t::get_thread_local(program);
|
||||
config.generator.get().generate(tree,
|
||||
{
|
||||
program, replacement_func_info.argument_types[i].id, config.replacement_min_depth,
|
||||
|
@ -308,6 +287,8 @@ namespace blt::gp
|
|||
print_mutate_stats();
|
||||
BLT_ABORT("Adjust Tree Check Failed.");
|
||||
}
|
||||
#endif
|
||||
#if defined(BLT_TRACK_ALLOCATIONS) || BLT_DEBUG_LEVEL >= 2
|
||||
++mutate_adjust_counter;
|
||||
#endif
|
||||
}
|
||||
|
@ -358,7 +339,7 @@ namespace blt::gp
|
|||
size_t start_index = c_node;
|
||||
for (ptrdiff_t i = new_argc - 1; i > static_cast<ptrdiff_t>(arg_position); i--)
|
||||
{
|
||||
auto& tree = get_static_tree_tl(program);
|
||||
auto& tree = tree_t::get_thread_local(program);
|
||||
config.generator.get().generate(tree,
|
||||
{
|
||||
program, replacement_func_info.argument_types[i].id, config.replacement_min_depth,
|
||||
|
@ -370,7 +351,7 @@ namespace blt::gp
|
|||
// vals.copy_from(combined_ptr, for_bytes);
|
||||
for (blt::ptrdiff_t i = static_cast<blt::ptrdiff_t>(arg_position) - 1; i >= 0; i--)
|
||||
{
|
||||
auto& tree = get_static_tree_tl(program);
|
||||
auto& tree = tree_t::get_thread_local(program);
|
||||
config.generator.get().generate(tree,
|
||||
{
|
||||
program, replacement_func_info.argument_types[i].id, config.replacement_min_depth,
|
||||
|
@ -397,6 +378,8 @@ namespace blt::gp
|
|||
print_mutate_stats();
|
||||
BLT_ABORT("SUB_FUNC Tree Check Failed.");
|
||||
}
|
||||
#endif
|
||||
#if defined(BLT_TRACK_ALLOCATIONS) || BLT_DEBUG_LEVEL >= 2
|
||||
++mutate_sub_func_counter;
|
||||
#endif
|
||||
}
|
||||
|
@ -469,6 +452,8 @@ namespace blt::gp
|
|||
print_mutate_stats();
|
||||
BLT_ABORT("JUMP_FUNC Tree Check Failed.");
|
||||
}
|
||||
#endif
|
||||
#if defined(BLT_TRACK_ALLOCATIONS) || BLT_DEBUG_LEVEL >= 2
|
||||
++mutate_jump_counter;
|
||||
#endif
|
||||
}
|
||||
|
@ -476,55 +461,36 @@ namespace blt::gp
|
|||
case mutation_operator::COPY:
|
||||
{
|
||||
auto& info = program.get_operator_info(c.get_operator(c_node).id());
|
||||
size_t pt = -1ul;
|
||||
size_t pf = -1ul;
|
||||
for (const auto& [index, v] : blt::enumerate(info.argument_types))
|
||||
{
|
||||
for (size_t i = index + 1; i < info.argument_types.size(); i++)
|
||||
{
|
||||
auto& v1 = info.argument_types[i];
|
||||
if (v == v1)
|
||||
{
|
||||
if (pt == -1ul)
|
||||
pt = index;
|
||||
else
|
||||
pf = index;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (pt != -1ul && pf != -1ul)
|
||||
break;
|
||||
}
|
||||
if (pt == -1ul || pf == -1ul)
|
||||
if (c.get_operator(c_node).is_value())
|
||||
continue;
|
||||
thread_local tracked_vector<size_t> potential_indexes;
|
||||
potential_indexes.clear();
|
||||
|
||||
size_t from = 0;
|
||||
size_t to = 0;
|
||||
|
||||
if (program.get_random().choice())
|
||||
const auto from_index = program.get_random().get_u64(0, info.argument_types.size());
|
||||
for (const auto [index, type] : enumerate(info.argument_types))
|
||||
{
|
||||
from = pt;
|
||||
to = pf;
|
||||
}
|
||||
else
|
||||
{
|
||||
from = pf;
|
||||
to = pt;
|
||||
if (index == from_index)
|
||||
continue;
|
||||
if (info.argument_types[from_index] == type)
|
||||
potential_indexes.push_back(index);
|
||||
}
|
||||
if (potential_indexes.empty())
|
||||
continue;
|
||||
const auto to_index = program.get_random().select(potential_indexes);
|
||||
|
||||
thread_local tracked_vector<tree_t::child_t> child_data;
|
||||
child_data.clear();
|
||||
|
||||
c.find_child_extends(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];
|
||||
auto& to_child = child_data[to_index];
|
||||
const auto child_from_index = child_data.size() - 1 - from_index;
|
||||
const auto child_to_index = child_data.size() - 1 - to_index;
|
||||
const auto& [from_start, from_end] = child_data[child_from_index];
|
||||
const auto& [to_start, to_end] = child_data[child_to_index];
|
||||
|
||||
thread_local tree_t copy_tree{program};
|
||||
c.copy_subtree(tree_t::subtree_point_t{from_child.start}, from_child.end, copy_tree);
|
||||
c.replace_subtree(tree_t::subtree_point_t{to_child.start}, to_child.end, copy_tree);
|
||||
c.copy_subtree(tree_t::subtree_point_t{from_start}, from_end, copy_tree);
|
||||
c.replace_subtree(tree_t::subtree_point_t{to_start}, to_end, copy_tree);
|
||||
copy_tree.clear(program);
|
||||
|
||||
#if BLT_DEBUG_LEVEL >= 2
|
||||
|
@ -538,6 +504,8 @@ namespace blt::gp
|
|||
print_mutate_stats();
|
||||
BLT_ABORT("COPY Tree Check Failed.");
|
||||
}
|
||||
#endif
|
||||
#if defined(BLT_TRACK_ALLOCATIONS) || BLT_DEBUG_LEVEL >= 2
|
||||
++mutate_copy_counter;
|
||||
#endif
|
||||
|
||||
|
|
|
@ -501,7 +501,6 @@ namespace blt::gp
|
|||
tree_t& tree_t::get_thread_local(gp_program& program)
|
||||
{
|
||||
thread_local tree_t tree{program};
|
||||
tree.clear(program);
|
||||
return tree;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue