Compare commits

..

No commits in common. "1789a9e4746beb86a3f6de74ea096bc7c4ca7768" and "d4e6c40fe1d28ab9ed02dcc3d7484aa49ae743ec" have entirely different histories.

8 changed files with 112 additions and 151 deletions

View File

@ -1,5 +1,5 @@
cmake_minimum_required(VERSION 3.25) cmake_minimum_required(VERSION 3.25)
project(blt-gp VERSION 0.1.36) project(blt-gp VERSION 0.1.35)
include(CTest) include(CTest)
@ -16,7 +16,7 @@ set(CMAKE_CXX_STANDARD 17)
set(THREADS_PREFER_PTHREAD_FLAG ON) set(THREADS_PREFER_PTHREAD_FLAG ON)
find_package(Threads REQUIRED) find_package(Threads REQUIRED)
#SET(CMAKE_CXX_FLAGS_RELEASE "-O3 -g") SET(CMAKE_CXX_FLAGS_RELEASE "-O3 -g")
if (NOT TARGET BLT) if (NOT TARGET BLT)
add_subdirectory(lib/blt) add_subdirectory(lib/blt)

View File

@ -36,18 +36,18 @@ std::array<context, 200> training_cases;
blt::gp::prog_config_t config = blt::gp::prog_config_t() 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(200) .set_elite_count(2)
.set_crossover_chance(0.9) .set_crossover_chance(0.9)
.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)
.set_pop_size(20000) .set_pop_size(500)
.set_thread_count(0); .set_thread_count(0);
blt::gp::gp_program program{SEED, config}; blt::gp::gp_program program{SEED, config};
auto lit = blt::gp::operation_t([]() { auto lit = blt::gp::operation_t([]() {
return program.get_random().get_float(-1.0f, 1.0f); return program.get_random().get_float(-320.0f, 320.0f);
}, "lit").set_ephemeral(); }, "lit").set_ephemeral();
blt::gp::operation_t op_x([](const context& context) { blt::gp::operation_t op_x([](const context& context) {

View File

@ -362,11 +362,8 @@ namespace blt::gp
#ifdef BLT_TRACK_ALLOCATIONS #ifdef BLT_TRACK_ALLOCATIONS
auto gen_alloc = blt::gp::tracker.start_measurement(); auto gen_alloc = blt::gp::tracker.start_measurement();
#endif #endif
BLT_ASSERT_MSG(current_pop.get_individuals().size() == config.population_size,
("cur pop size: " + std::to_string(current_pop.get_individuals().size())).c_str());
BLT_ASSERT_MSG(next_pop.get_individuals().size() == config.population_size,
("next pop size: " + std::to_string(next_pop.get_individuals().size())).c_str());
// should already be empty // should already be empty
next_pop.clear();
thread_helper.next_gen_left.store(config.population_size, std::memory_order_release); thread_helper.next_gen_left.store(config.population_size, std::memory_order_release);
(*thread_execution_service)(0); (*thread_execution_service)(0);
#ifdef BLT_TRACK_ALLOCATIONS #ifdef BLT_TRACK_ALLOCATIONS
@ -378,10 +375,8 @@ namespace blt::gp
void next_generation() void next_generation()
{ {
BLT_ASSERT_MSG(current_pop.get_individuals().size() == config.population_size,
("cur pop size: " + std::to_string(current_pop.get_individuals().size())).c_str());
BLT_ASSERT_MSG(next_pop.get_individuals().size() == config.population_size, BLT_ASSERT_MSG(next_pop.get_individuals().size() == config.population_size,
("next pop size: " + std::to_string(next_pop.get_individuals().size())).c_str()); ("pop size: " + std::to_string(next_pop.get_individuals().size())).c_str());
std::swap(current_pop, next_pop); std::swap(current_pop, next_pop);
current_generation++; current_generation++;
} }
@ -405,7 +400,6 @@ namespace blt::gp
current_generation = 0; current_generation = 0;
current_pop = config.pop_initializer.get().generate( current_pop = config.pop_initializer.get().generate(
{*this, root_type, config.population_size, config.initial_min_tree_size, config.initial_max_tree_size}); {*this, root_type, config.population_size, config.initial_min_tree_size, config.initial_max_tree_size});
next_pop = population_t(current_pop);
if (eval_fitness_now) if (eval_fitness_now)
evaluate_fitness_internal(); evaluate_fitness_internal();
} }
@ -471,24 +465,21 @@ namespace blt::gp
} }
if (thread_helper.next_gen_left > 0) if (thread_helper.next_gen_left > 0)
{ {
auto args = get_selector_args(); static thread_local tracked_vector<tree_t> new_children;
new_children.clear();
auto args = get_selector_args(new_children);
crossover_selection.pre_process(*this, current_pop); crossover_selection.pre_process(*this, current_pop);
mutation_selection.pre_process(*this, current_pop); mutation_selection.pre_process(*this, current_pop);
reproduction_selection.pre_process(*this, current_pop); reproduction_selection.pre_process(*this, current_pop);
perform_elitism(args, next_pop); perform_elitism(args);
blt::size_t start = config.elites; while (new_children.size() < config.population_size)
func(args, crossover_selection, mutation_selection, reproduction_selection);
while (start < config.population_size) for (auto& i : new_children)
{ next_pop.get_individuals().emplace_back(std::move(i));
tree_t& c1 = next_pop.get_individuals()[start].tree;
tree_t* c2 = nullptr;
if (start + 1 < config.population_size)
c2 = &next_pop.get_individuals()[start + 1].tree;
start += func(args, crossover_selection, mutation_selection, reproduction_selection, c1, c2);
}
thread_helper.next_gen_left = 0; thread_helper.next_gen_left = 0;
} }
@ -551,7 +542,9 @@ namespace blt::gp
} }
if (thread_helper.next_gen_left > 0) if (thread_helper.next_gen_left > 0)
{ {
auto args = get_selector_args(); static thread_local tracked_vector<tree_t> new_children;
new_children.clear();
auto args = get_selector_args(new_children);
if (id == 0) if (id == 0)
{ {
current_stats.normalized_fitness.clear(); current_stats.normalized_fitness.clear();
@ -569,35 +562,37 @@ namespace blt::gp
if (&crossover_selection != &reproduction_selection) if (&crossover_selection != &reproduction_selection)
reproduction_selection.pre_process(*this, current_pop); reproduction_selection.pre_process(*this, current_pop);
perform_elitism(args, next_pop); perform_elitism(args);
thread_helper.next_gen_left -= config.elites; for (auto& i : new_children)
next_pop.get_individuals().emplace_back(std::move(i));
thread_helper.next_gen_left -= new_children.size();
new_children.clear();
} }
thread_helper.barrier.wait(); thread_helper.barrier.wait();
while (thread_helper.next_gen_left > 0) while (thread_helper.next_gen_left > 0)
{ {
blt::size_t size = 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); blt::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);
begin = end - size;
} while (!thread_helper.next_gen_left.compare_exchange_weak(end, end - size, } while (!thread_helper.next_gen_left.compare_exchange_weak(end, end - size,
std::memory_order::memory_order_relaxed, std::memory_order::memory_order_relaxed,
std::memory_order::memory_order_relaxed)); std::memory_order::memory_order_relaxed));
while (begin != end) while (new_children.size() < size)
{ func(args, crossover_selection, mutation_selection, reproduction_selection);
auto index = config.elites + begin;
tree_t& c1 = next_pop.get_individuals()[index].tree;
tree_t* c2 = nullptr;
if (index + 1 < end)
c2 = &next_pop.get_individuals()[index + 1].tree;
begin += func(args, crossover_selection, mutation_selection, reproduction_selection, c1, c2);
}
{
std::scoped_lock lock(thread_helper.thread_generation_lock);
for (auto& i : new_children)
{
if (next_pop.get_individuals().size() < config.population_size)
next_pop.get_individuals().emplace_back(i);
}
}
} }
} }
thread_helper.barrier.wait(); thread_helper.barrier.wait();
@ -752,9 +747,9 @@ namespace blt::gp
} }
private: private:
inline selector_args get_selector_args() inline selector_args get_selector_args(tracked_vector<tree_t>& next_pop_trees)
{ {
return {*this, current_pop, current_stats, config, get_random()}; return {*this, next_pop_trees, current_pop, current_stats, config, get_random()};
} }
template<typename Return, blt::size_t size, typename Accessor, blt::size_t... indexes> template<typename Return, blt::size_t size, typename Accessor, blt::size_t... indexes>
@ -770,7 +765,7 @@ namespace blt::gp
{ {
statistic_history.push_back(current_stats); statistic_history.push_back(current_stats);
current_stats.clear(); current_stats.clear();
thread_helper.evaluation_left.store(config.population_size, std::memory_order_release); thread_helper.evaluation_left.store(current_pop.get_individuals().size(), std::memory_order_release);
(*thread_execution_service)(0); (*thread_execution_service)(0);
current_stats.average_fitness = current_stats.overall_fitness / static_cast<double>(config.population_size); current_stats.average_fitness = current_stats.overall_fitness / static_cast<double>(config.population_size);
@ -796,6 +791,7 @@ namespace blt::gp
std::vector<std::unique_ptr<std::thread>> threads; std::vector<std::unique_ptr<std::thread>> threads;
std::mutex thread_function_control{}; std::mutex thread_function_control{};
std::mutex thread_generation_lock{};
std::condition_variable thread_function_condition{}; std::condition_variable thread_function_condition{};
std::atomic_uint64_t evaluation_left = 0; std::atomic_uint64_t evaluation_left = 0;

View File

@ -32,14 +32,15 @@ namespace blt::gp
struct selector_args struct selector_args
{ {
gp_program& program; gp_program& program;
const population_t& current_pop; tracked_vector<tree_t>& next_pop;
population_t& current_pop;
population_stats& current_stats; population_stats& current_stats;
prog_config_t& config; prog_config_t& config;
random_t& random; random_t& random;
}; };
constexpr inline auto perform_elitism = [](const selector_args& args, population_t& next_pop) { constexpr inline auto perform_elitism = [](const selector_args& args) {
auto& [program, current_pop, current_stats, config, random] = args; auto& [program, next_pop, current_pop, current_stats, config, random] = args;
if (config.elites > 0) if (config.elites > 0)
{ {
@ -69,38 +70,39 @@ namespace blt::gp
} }
for (blt::size_t i = 0; i < config.elites; i++) for (blt::size_t i = 0; i < config.elites; i++)
next_pop.get_individuals()[i].copy_fast(current_pop.get_individuals()[values[i].first].tree); next_pop.push_back(current_pop.get_individuals()[values[i].first].tree);
} }
}; };
template<typename Crossover, typename Mutation, typename Reproduction> template<typename Crossover, typename Mutation, typename Reproduction>
constexpr inline auto default_next_pop_creator = []( constexpr inline auto default_next_pop_creator = [](
blt::gp::selector_args& args, Crossover& crossover_selection, Mutation& mutation_selection, Reproduction& reproduction_selection, blt::gp::selector_args& args, Crossover& crossover_selection, Mutation& mutation_selection, Reproduction& reproduction_selection) {
tree_t& c1, tree_t* c2) { auto& [program, next_pop, current_pop, current_stats, config, random] = args;
auto& [program, current_pop, current_stats, config, random] = args;
int sel = random.get_i32(0, 3); int sel = random.get_i32(0, 3);
switch (sel) switch (sel)
{ {
case 0: case 0:
if (c2 == nullptr)
return 0;
// everyone gets a chance once per loop. // everyone gets a chance once per loop.
if (random.choice(config.crossover_chance)) if (random.choice(config.crossover_chance))
{ {
// auto state = tracker.start_measurement(); // auto state = tracker.start_measurement();
// crossover // crossover
const tree_t* p1; auto& p1 = crossover_selection.select(program, current_pop);
const tree_t* p2; auto& p2 = crossover_selection.select(program, current_pop);
do
auto results = config.crossover.get().apply(program, p1, p2);
// if crossover fails, we can check for mutation on these guys. otherwise straight copy them into the next pop
if (results)
{ {
p1 = &crossover_selection.select(program, current_pop); next_pop.push_back(std::move(results->child1));
p2 = &crossover_selection.select(program, current_pop); if (next_pop.size() != config.population_size)
} while (!config.crossover.get().apply(program, *p1, *p2, c1, *c2)); next_pop.push_back(std::move(results->child2));
}
// tracker.stop_measurement(state); // tracker.stop_measurement(state);
// BLT_TRACE("Crossover Allocated %ld times with a total of %s", state.getAllocationDifference(), // BLT_TRACE("Crossover Allocated %ld times with a total of %s", state.getAllocationDifference(),
// blt::byte_convert_t(state.getAllocatedByteDifference()).convert_to_nearest_type().to_pretty_string().c_str()); // blt::byte_convert_t(state.getAllocatedByteDifference()).convert_to_nearest_type().to_pretty_string().c_str());
return 2;
} }
break; break;
case 1: case 1:
@ -108,15 +110,11 @@ namespace blt::gp
{ {
// auto state = tracker.start_measurement(); // auto state = tracker.start_measurement();
// mutation // mutation
const tree_t* p; auto& p = mutation_selection.select(program, current_pop);
do next_pop.push_back(std::move(config.mutator.get().apply(program, p)));
{
p = &mutation_selection.select(program, current_pop);
} while (!config.mutator.get().apply(program, *p, c1));
// tracker.stop_measurement(state); // tracker.stop_measurement(state);
// BLT_TRACE("Mutation Allocated %ld times with a total of %s", state.getAllocationDifference(), // BLT_TRACE("Mutation Allocated %ld times with a total of %s", state.getAllocationDifference(),
// blt::byte_convert_t(state.getAllocatedByteDifference()).convert_to_nearest_type().to_pretty_string().c_str()); // blt::byte_convert_t(state.getAllocatedByteDifference()).convert_to_nearest_type().to_pretty_string().c_str());
return 1;
} }
break; break;
case 2: case 2:
@ -124,11 +122,11 @@ namespace blt::gp
{ {
// auto state = tracker.start_measurement(); // auto state = tracker.start_measurement();
// reproduction // reproduction
c1 = reproduction_selection.select(program, current_pop); auto& p = reproduction_selection.select(program, current_pop);
next_pop.push_back(p);
// tracker.stop_measurement(state); // tracker.stop_measurement(state);
// BLT_TRACE("Reproduction Allocated %ld times with a total of %s", state.getAllocationDifference(), // BLT_TRACE("Reproduction Allocated %ld times with a total of %s", state.getAllocationDifference(),
// blt::byte_convert_t(state.getAllocatedByteDifference()).convert_to_nearest_type().to_pretty_string().c_str()); // blt::byte_convert_t(state.getAllocatedByteDifference()).convert_to_nearest_type().to_pretty_string().c_str());
return 1;
} }
break; break;
default: default:
@ -138,7 +136,6 @@ namespace blt::gp
BLT_UNREACHABLE; BLT_UNREACHABLE;
#endif #endif
} }
return 0;
}; };
class selection_t class selection_t
@ -150,7 +147,7 @@ namespace blt::gp
* @param stats the populations statistics * @param stats the populations statistics
* @return * @return
*/ */
virtual const tree_t& select(gp_program& program, const population_t& pop) = 0; virtual tree_t& select(gp_program& program, population_t& pop) = 0;
virtual void pre_process(gp_program&, population_t&) virtual void pre_process(gp_program&, population_t&)
{} {}
@ -161,19 +158,19 @@ namespace blt::gp
class select_best_t : public selection_t class select_best_t : public selection_t
{ {
public: public:
const tree_t& select(gp_program& program, const population_t& pop) final; tree_t& select(gp_program& program, population_t& pop) final;
}; };
class select_worst_t : public selection_t class select_worst_t : public selection_t
{ {
public: public:
const tree_t& select(gp_program& program, const population_t& pop) final; tree_t& select(gp_program& program, population_t& pop) final;
}; };
class select_random_t : public selection_t class select_random_t : public selection_t
{ {
public: public:
const tree_t& select(gp_program& program, const population_t& pop) final; tree_t& select(gp_program& program, population_t& pop) final;
}; };
class select_tournament_t : public selection_t class select_tournament_t : public selection_t
@ -185,7 +182,7 @@ namespace blt::gp
BLT_ABORT("Unable to select with this size. Must select at least 1 individual_t!"); BLT_ABORT("Unable to select with this size. Must select at least 1 individual_t!");
} }
const tree_t& select(gp_program& program, const population_t& pop) final; tree_t& select(gp_program& program, population_t& pop) final;
private: private:
const blt::size_t selection_size; const blt::size_t selection_size;
@ -194,7 +191,7 @@ namespace blt::gp
class select_fitness_proportionate_t : public selection_t class select_fitness_proportionate_t : public selection_t
{ {
public: public:
const tree_t& select(gp_program& program, const population_t& pop) final; tree_t& select(gp_program& program, population_t& pop) final;
}; };
} }

View File

@ -57,6 +57,16 @@ namespace blt::gp
class crossover_t class crossover_t
{ {
public: public:
enum class error_t
{
NO_VALID_TYPE,
TREE_TOO_SMALL
};
struct result_t
{
tree_t child1;
tree_t child2;
};
struct crossover_point_t struct crossover_point_t
{ {
blt::ptrdiff_t p1_crossover_point; blt::ptrdiff_t p1_crossover_point;
@ -77,7 +87,7 @@ namespace blt::gp
explicit crossover_t(const config_t& config): config(config) 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; blt::expected<crossover_t::crossover_point_t, error_t> get_crossover_point(gp_program& program, 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. * child1 and child2 are copies of the parents, the result of selecting a crossover point and performing standard subtree crossover.
@ -87,7 +97,7 @@ namespace blt::gp
* @param p2 reference to the second parent * @param p2 reference to the second parent
* @return expected pair of child otherwise returns error enum * @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 blt::expected<result_t, error_t> apply(gp_program& program, const tree_t& p1, const tree_t& p2); // NOLINT
virtual ~crossover_t() = default; virtual ~crossover_t() = default;
@ -116,7 +126,7 @@ namespace blt::gp
explicit mutation_t(const config_t& config): config(config) explicit mutation_t(const config_t& config): config(config)
{} {}
virtual bool apply(gp_program& program, const tree_t& p, tree_t& c); virtual tree_t apply(gp_program& program, const tree_t& p);
// returns the point after the mutation // returns the point after the mutation
blt::size_t mutate_point(gp_program& program, tree_t& c, blt::size_t node); blt::size_t mutate_point(gp_program& program, tree_t& c, blt::size_t node);
@ -145,7 +155,7 @@ namespace blt::gp
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; tree_t apply(gp_program& program, const tree_t& p) final;
advanced_mutation_t& set_per_node_mutation_chance(double v) advanced_mutation_t& set_per_node_mutation_chance(double v)
{ {
@ -160,11 +170,11 @@ namespace blt::gp
double per_node_mutation_chance = 5.0; double per_node_mutation_chance = 5.0;
static constexpr std::array<double, operators_size> mutation_operator_chances = detail::aggregate_array<operators_size>( static constexpr std::array<double, operators_size> mutation_operator_chances = detail::aggregate_array<operators_size>(
0.25, // EXPRESSION 0.1, // EXPRESSION
0.15, // ADJUST 0.25, // ADJUST
0.01, // SUB_FUNC 0.01, // SUB_FUNC
0.01, // JUMP_FUNC 0.25, // JUMP_FUNC
0.05 // COPY 0.12 // COPY
); );
}; };

View File

@ -56,37 +56,6 @@ namespace blt::gp
public: public:
explicit tree_t(gp_program& program); explicit tree_t(gp_program& program);
tree_t(const tree_t& copy) = default;
tree_t& operator=(const tree_t& copy)
{
if (this == &copy)
return *this;
copy_fast(copy);
return *this;
}
/**
* This function copies the data from the provided tree, will attempt to reserve and copy in one step.
* will avoid reallocation if enough space is already present.
*/
void copy_fast(const tree_t& copy)
{
if (this == &copy)
return;
values.reserve(copy.values.internal_storage_size());
values.reset();
values.insert(copy.values);
operations.clear();
operations.reserve(copy.operations.size());
operations.insert(operations.begin(), copy.operations.begin(), copy.operations.end());
}
tree_t(tree_t&& move) = default;
tree_t& operator=(tree_t&& move) = default;
void clear(gp_program& program); void clear(gp_program& program);
struct child_t struct child_t
@ -209,14 +178,6 @@ namespace blt::gp
tree_t tree; tree_t tree;
fitness_t fitness; fitness_t fitness;
void copy_fast(const tree_t& copy)
{
// fast copy of the tree
tree.copy_fast(copy);
// reset fitness
fitness = {};
}
individual_t() = delete; individual_t() = delete;
explicit individual_t(tree_t&& tree): tree(std::move(tree)) explicit individual_t(tree_t&& tree): tree(std::move(tree))
@ -323,11 +284,6 @@ namespace blt::gp
return individuals; return individuals;
} }
[[nodiscard]] const tracked_vector<individual_t>& get_individuals() const
{
return individuals;
}
population_tree_iterator for_each_tree() population_tree_iterator for_each_tree()
{ {
return population_tree_iterator{individuals, 0}; return population_tree_iterator{individuals, 0};

View File

@ -21,11 +21,11 @@
namespace blt::gp namespace blt::gp
{ {
const tree_t& select_best_t::select(gp_program&, const population_t& pop) tree_t& select_best_t::select(gp_program&, population_t& pop)
{ {
auto& first = pop.get_individuals()[0]; auto& first = pop.get_individuals()[0];
double best_fitness = first.fitness.adjusted_fitness; double best_fitness = first.fitness.adjusted_fitness;
const tree_t* tree = &first.tree; tree_t* tree = &first.tree;
for (auto& ind : pop.get_individuals()) for (auto& ind : pop.get_individuals())
{ {
if (ind.fitness.adjusted_fitness > best_fitness) if (ind.fitness.adjusted_fitness > best_fitness)
@ -37,11 +37,11 @@ namespace blt::gp
return *tree; return *tree;
} }
const tree_t& select_worst_t::select(gp_program&, const population_t& pop) tree_t& select_worst_t::select(gp_program&, population_t& pop)
{ {
auto& first = pop.get_individuals()[0]; auto& first = pop.get_individuals()[0];
double worst_fitness = first.fitness.adjusted_fitness; double worst_fitness = first.fitness.adjusted_fitness;
const tree_t* tree = &first.tree; tree_t* tree = &first.tree;
for (auto& ind : pop.get_individuals()) for (auto& ind : pop.get_individuals())
{ {
if (ind.fitness.adjusted_fitness < worst_fitness) if (ind.fitness.adjusted_fitness < worst_fitness)
@ -53,12 +53,12 @@ namespace blt::gp
return *tree; return *tree;
} }
const tree_t& select_random_t::select(gp_program& program, const population_t& pop) tree_t& select_random_t::select(gp_program& program, population_t& pop)
{ {
return pop.get_individuals()[program.get_random().get_size_t(0ul, pop.get_individuals().size())].tree; return pop.get_individuals()[program.get_random().get_size_t(0ul, pop.get_individuals().size())].tree;
} }
const tree_t& select_tournament_t::select(gp_program& program, const population_t& pop) tree_t& select_tournament_t::select(gp_program& program, population_t& pop)
{ {
blt::u64 best = program.get_random().get_u64(0, pop.get_individuals().size()); blt::u64 best = program.get_random().get_u64(0, pop.get_individuals().size());
auto& i_ref = pop.get_individuals(); auto& i_ref = pop.get_individuals();
@ -71,7 +71,7 @@ namespace blt::gp
return i_ref[best].tree; return i_ref[best].tree;
} }
const tree_t& select_fitness_proportionate_t::select(gp_program& program, const population_t& pop) tree_t& select_fitness_proportionate_t::select(gp_program& program, population_t& pop)
{ {
auto& stats = program.get_population_stats(); auto& stats = program.get_population_stats();
auto choice = program.get_random().get_double(); auto choice = program.get_random().get_double();

View File

@ -59,21 +59,23 @@ namespace blt::gp
mutation_t::config_t::config_t(): generator(grow_generator) 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 blt::expected<crossover_t::result_t, crossover_t::error_t> crossover_t::apply(gp_program& program, const tree_t& p1, const tree_t& p2) // NOLINT
{ {
c1.copy_fast(p1); result_t result{p1, p2};
c2.copy_fast(p2);
auto& c1 = result.child1;
auto& c2 = result.child2;
auto& c1_ops = c1.get_operations(); auto& c1_ops = c1.get_operations();
auto& c2_ops = c2.get_operations(); auto& c2_ops = c2.get_operations();
if (c1_ops.size() < 5 || c2_ops.size() < 5) if (c1_ops.size() < 5 || c2_ops.size() < 5)
return false; return blt::unexpected(error_t::TREE_TOO_SMALL);
auto point = get_crossover_point(program, p1, p2); auto point = get_crossover_point(program, c1, c2);
if (!point) if (!point)
return false; return blt::unexpected(point.error());
auto crossover_point_begin_itr = c1_ops.begin() + point->p1_crossover_point; 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 crossover_point_end_itr = c1_ops.begin() + c1.find_endpoint(program, point->p1_crossover_point);
@ -102,8 +104,8 @@ namespace blt::gp
blt::size_t c2_stack_for_bytes = accumulate_type_sizes(found_point_begin_itr, found_point_end_itr); blt::size_t c2_stack_for_bytes = accumulate_type_sizes(found_point_begin_itr, found_point_end_itr);
auto c1_total = static_cast<blt::ptrdiff_t>(c1_stack_after_bytes + c1_stack_for_bytes); auto c1_total = static_cast<blt::ptrdiff_t>(c1_stack_after_bytes + c1_stack_for_bytes);
auto c2_total = static_cast<blt::ptrdiff_t>(c2_stack_after_bytes + c2_stack_for_bytes); 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_c1 = get_thread_pointer_for_size<struct c1>(c1_total);
auto copy_ptr_c2 = get_thread_pointer_for_size<struct c2_t>(c2_total); auto copy_ptr_c2 = get_thread_pointer_for_size<struct c2>(c2_total);
c1_stack.copy_to(copy_ptr_c1, c1_total); c1_stack.copy_to(copy_ptr_c1, c1_total);
c1_stack.pop_bytes(c1_total); c1_stack.pop_bytes(c1_total);
@ -129,8 +131,8 @@ namespace blt::gp
c2_ops.insert(++insert_point_c2, c1_operators.begin(), c1_operators.end()); c2_ops.insert(++insert_point_c2, c1_operators.begin(), c1_operators.end());
#if BLT_DEBUG_LEVEL >= 2 #if BLT_DEBUG_LEVEL >= 2
blt::size_t c1_found_bytes = c1.get_values().size().total_used_bytes; blt::size_t c1_found_bytes = result.child1.get_values().size().total_used_bytes;
blt::size_t c2_found_bytes = c2.get_values().size().total_used_bytes; blt::size_t c2_found_bytes = result.child2.get_values().size().total_used_bytes;
blt::size_t c1_expected_bytes = std::accumulate(result.child1.get_operations().begin(), result.child1.get_operations().end(), 0ul, blt::size_t c1_expected_bytes = std::accumulate(result.child1.get_operations().begin(), result.child1.get_operations().end(), 0ul,
[](const auto& v1, const auto& v2) { [](const auto& v1, const auto& v2) {
if (v2.is_value) if (v2.is_value)
@ -151,10 +153,10 @@ namespace blt::gp
} }
#endif #endif
return true; return result;
} }
std::optional<crossover_t::crossover_point_t> crossover_t::get_crossover_point(gp_program& program, const tree_t& c1, blt::expected<crossover_t::crossover_point_t, crossover_t::error_t> crossover_t::get_crossover_point(gp_program& program, const tree_t& c1,
const tree_t& c2) const const tree_t& c2) const
{ {
auto& c1_ops = c1.get_operations(); auto& c1_ops = c1.get_operations();
@ -192,10 +194,10 @@ namespace blt::gp
} }
} }
if (!found) if (!found)
return {}; return blt::unexpected(error_t::NO_VALID_TYPE);
} }
// should we try again over the whole tree? probably not. // should we try again over the whole tree? probably not.
return {}; return blt::unexpected(error_t::NO_VALID_TYPE);
} else } else
{ {
attempted_point = program.get_random().get_size_t(1ul, c2_ops.size()); attempted_point = program.get_random().get_size_t(1ul, c2_ops.size());
@ -211,13 +213,13 @@ namespace blt::gp
return crossover_point_t{static_cast<blt::ptrdiff_t>(crossover_point), static_cast<blt::ptrdiff_t>(attempted_point)}; return crossover_point_t{static_cast<blt::ptrdiff_t>(crossover_point), static_cast<blt::ptrdiff_t>(attempted_point)};
} }
bool mutation_t::apply(gp_program& program, const tree_t& p, tree_t& c) tree_t mutation_t::apply(gp_program& program, const tree_t& p)
{ {
c.copy_fast(p); auto c = p;
mutate_point(program, c, program.get_random().get_size_t(0ul, c.get_operations().size())); mutate_point(program, c, program.get_random().get_size_t(0ul, c.get_operations().size()));
return true; return c;
} }
blt::size_t mutation_t::mutate_point(gp_program& program, tree_t& c, blt::size_t node) blt::size_t mutation_t::mutate_point(gp_program& program, tree_t& c, blt::size_t node)
@ -302,10 +304,10 @@ namespace blt::gp
return begin_point + new_ops_r.size(); return begin_point + new_ops_r.size();
} }
bool advanced_mutation_t::apply(gp_program& program, const tree_t& p, tree_t& c) tree_t advanced_mutation_t::apply(gp_program& program, const tree_t& p)
{ {
// child tree // child tree
c.copy_fast(p); tree_t c = p;
auto& ops = c.get_operations(); auto& ops = c.get_operations();
auto& vals = c.get_values(); auto& vals = c.get_values();
@ -730,6 +732,6 @@ namespace blt::gp
} }
#endif #endif
return true; return c;
} }
} }