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