Compare commits

..

4 Commits

Author SHA1 Message Date
Brett 1789a9e474 i think it's shared now? 2024-08-31 22:03:22 -04:00
Brett 3572539b74 silly2 2024-08-31 00:10:25 -04:00
Brett 2f3ea1b3bf silly 2024-08-31 00:05:04 -04:00
Brett 91bda10b0a meow 2024-08-30 23:33:52 -04:00
8 changed files with 150 additions and 111 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.35) project(blt-gp VERSION 0.1.36)
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(2) .set_elite_count(200)
.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(500) .set_pop_size(20000)
.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(-320.0f, 320.0f); return program.get_random().get_float(-1.0f, 1.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,8 +362,11 @@ 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
@ -375,8 +378,10 @@ 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,
("pop size: " + std::to_string(next_pop.get_individuals().size())).c_str()); ("next 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++;
} }
@ -400,6 +405,7 @@ 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();
} }
@ -465,21 +471,24 @@ namespace blt::gp
} }
if (thread_helper.next_gen_left > 0) if (thread_helper.next_gen_left > 0)
{ {
static thread_local tracked_vector<tree_t> new_children; auto args = get_selector_args();
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); perform_elitism(args, next_pop);
while (new_children.size() < config.population_size) blt::size_t start = config.elites;
func(args, crossover_selection, mutation_selection, reproduction_selection);
for (auto& i : new_children) while (start < config.population_size)
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;
} }
@ -542,9 +551,7 @@ namespace blt::gp
} }
if (thread_helper.next_gen_left > 0) if (thread_helper.next_gen_left > 0)
{ {
static thread_local tracked_vector<tree_t> new_children; auto args = get_selector_args();
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();
@ -562,37 +569,35 @@ 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); perform_elitism(args, next_pop);
for (auto& i : new_children) thread_helper.next_gen_left -= config.elites;
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 (new_children.size() < size) while (begin != end)
func(args, crossover_selection, mutation_selection, reproduction_selection);
{ {
std::scoped_lock lock(thread_helper.thread_generation_lock); auto index = config.elites + begin;
for (auto& i : new_children) tree_t& c1 = next_pop.get_individuals()[index].tree;
{ tree_t* c2 = nullptr;
if (next_pop.get_individuals().size() < config.population_size) if (index + 1 < end)
next_pop.get_individuals().emplace_back(i); c2 = &next_pop.get_individuals()[index + 1].tree;
} begin += func(args, crossover_selection, mutation_selection, reproduction_selection, c1, c2);
} }
} }
} }
thread_helper.barrier.wait(); thread_helper.barrier.wait();
@ -747,9 +752,9 @@ namespace blt::gp
} }
private: private:
inline selector_args get_selector_args(tracked_vector<tree_t>& next_pop_trees) inline selector_args get_selector_args()
{ {
return {*this, next_pop_trees, current_pop, current_stats, config, get_random()}; return {*this, 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>
@ -765,7 +770,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(current_pop.get_individuals().size(), std::memory_order_release); thread_helper.evaluation_left.store(config.population_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);
@ -791,7 +796,6 @@ 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,15 +32,14 @@ namespace blt::gp
struct selector_args struct selector_args
{ {
gp_program& program; gp_program& program;
tracked_vector<tree_t>& next_pop; const population_t& current_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) { constexpr inline auto perform_elitism = [](const selector_args& args, population_t& next_pop) {
auto& [program, next_pop, current_pop, current_stats, config, random] = args; auto& [program, current_pop, current_stats, config, random] = args;
if (config.elites > 0) if (config.elites > 0)
{ {
@ -70,39 +69,38 @@ 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.push_back(current_pop.get_individuals()[values[i].first].tree); next_pop.get_individuals()[i].copy_fast(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,
auto& [program, next_pop, current_pop, current_stats, config, random] = args; tree_t& c1, tree_t* c2) {
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
auto& p1 = crossover_selection.select(program, current_pop); const tree_t* p1;
auto& p2 = crossover_selection.select(program, current_pop); const tree_t* p2;
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)
{ {
next_pop.push_back(std::move(results->child1)); p1 = &crossover_selection.select(program, current_pop);
if (next_pop.size() != config.population_size) p2 = &crossover_selection.select(program, current_pop);
next_pop.push_back(std::move(results->child2)); } while (!config.crossover.get().apply(program, *p1, *p2, c1, *c2));
}
// 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:
@ -110,11 +108,15 @@ namespace blt::gp
{ {
// auto state = tracker.start_measurement(); // auto state = tracker.start_measurement();
// mutation // mutation
auto& p = mutation_selection.select(program, current_pop); const tree_t* p;
next_pop.push_back(std::move(config.mutator.get().apply(program, p))); do
{
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:
@ -122,11 +124,11 @@ namespace blt::gp
{ {
// auto state = tracker.start_measurement(); // auto state = tracker.start_measurement();
// reproduction // reproduction
auto& p = reproduction_selection.select(program, current_pop); c1 = 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:
@ -136,6 +138,7 @@ namespace blt::gp
BLT_UNREACHABLE; BLT_UNREACHABLE;
#endif #endif
} }
return 0;
}; };
class selection_t class selection_t
@ -147,7 +150,7 @@ namespace blt::gp
* @param stats the populations statistics * @param stats the populations statistics
* @return * @return
*/ */
virtual tree_t& select(gp_program& program, population_t& pop) = 0; virtual const tree_t& select(gp_program& program, const population_t& pop) = 0;
virtual void pre_process(gp_program&, population_t&) virtual void pre_process(gp_program&, population_t&)
{} {}
@ -158,19 +161,19 @@ namespace blt::gp
class select_best_t : public selection_t class select_best_t : public selection_t
{ {
public: public:
tree_t& select(gp_program& program, population_t& pop) final; const tree_t& select(gp_program& program, const population_t& pop) final;
}; };
class select_worst_t : public selection_t class select_worst_t : public selection_t
{ {
public: public:
tree_t& select(gp_program& program, population_t& pop) final; const tree_t& select(gp_program& program, const population_t& pop) final;
}; };
class select_random_t : public selection_t class select_random_t : public selection_t
{ {
public: public:
tree_t& select(gp_program& program, population_t& pop) final; const tree_t& select(gp_program& program, const population_t& pop) final;
}; };
class select_tournament_t : public selection_t class select_tournament_t : public selection_t
@ -182,7 +185,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!");
} }
tree_t& select(gp_program& program, population_t& pop) final; const tree_t& select(gp_program& program, const population_t& pop) final;
private: private:
const blt::size_t selection_size; const blt::size_t selection_size;
@ -191,7 +194,7 @@ namespace blt::gp
class select_fitness_proportionate_t : public selection_t class select_fitness_proportionate_t : public selection_t
{ {
public: public:
tree_t& select(gp_program& program, population_t& pop) final; const tree_t& select(gp_program& program, const population_t& pop) final;
}; };
} }

View File

@ -57,16 +57,6 @@ 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;
@ -87,7 +77,7 @@ namespace blt::gp
explicit crossover_t(const config_t& config): config(config) explicit crossover_t(const config_t& config): config(config)
{} {}
blt::expected<crossover_t::crossover_point_t, error_t> get_crossover_point(gp_program& program, const tree_t& c1, const tree_t& c2) const; std::optional<crossover_t::crossover_point_t> get_crossover_point(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.
@ -97,7 +87,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 blt::expected<result_t, error_t> apply(gp_program& program, const tree_t& p1, const tree_t& p2); // NOLINT 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; virtual ~crossover_t() = default;
@ -126,7 +116,7 @@ namespace blt::gp
explicit mutation_t(const config_t& config): config(config) explicit mutation_t(const config_t& config): config(config)
{} {}
virtual tree_t apply(gp_program& program, const tree_t& p); 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
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);
@ -155,7 +145,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)
{} {}
tree_t apply(gp_program& program, const tree_t& p) 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)
{ {
@ -170,11 +160,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.1, // EXPRESSION 0.25, // EXPRESSION
0.25, // ADJUST 0.15, // ADJUST
0.01, // SUB_FUNC 0.01, // SUB_FUNC
0.25, // JUMP_FUNC 0.01, // JUMP_FUNC
0.12 // COPY 0.05 // COPY
); );
}; };

View File

@ -56,6 +56,37 @@ 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
@ -178,6 +209,14 @@ 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))
@ -284,6 +323,11 @@ 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
{ {
tree_t& select_best_t::select(gp_program&, population_t& pop) const tree_t& select_best_t::select(gp_program&, const 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;
tree_t* tree = &first.tree; const 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;
} }
tree_t& select_worst_t::select(gp_program&, population_t& pop) const tree_t& select_worst_t::select(gp_program&, const 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;
tree_t* tree = &first.tree; const 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;
} }
tree_t& select_random_t::select(gp_program& program, population_t& pop) const tree_t& select_random_t::select(gp_program& program, const 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;
} }
tree_t& select_tournament_t::select(gp_program& program, population_t& pop) const tree_t& select_tournament_t::select(gp_program& program, const 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;
} }
tree_t& select_fitness_proportionate_t::select(gp_program& program, population_t& pop) const tree_t& select_fitness_proportionate_t::select(gp_program& program, const 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,23 +59,21 @@ namespace blt::gp
mutation_t::config_t::config_t(): generator(grow_generator) mutation_t::config_t::config_t(): generator(grow_generator)
{} {}
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 bool crossover_t::apply(gp_program& program, const tree_t& p1, const tree_t& p2, tree_t& c1, tree_t& c2) // NOLINT
{ {
result_t result{p1, p2}; c1.copy_fast(p1);
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 blt::unexpected(error_t::TREE_TOO_SMALL); return false;
auto point = get_crossover_point(program, c1, c2); auto point = get_crossover_point(program, p1, p2);
if (!point) if (!point)
return blt::unexpected(point.error()); return false;
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);
@ -104,8 +102,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>(c1_total); auto copy_ptr_c1 = get_thread_pointer_for_size<struct c1_t>(c1_total);
auto copy_ptr_c2 = get_thread_pointer_for_size<struct c2>(c2_total); auto copy_ptr_c2 = get_thread_pointer_for_size<struct c2_t>(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);
@ -131,8 +129,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 = result.child1.get_values().size().total_used_bytes; blt::size_t c1_found_bytes = c1.get_values().size().total_used_bytes;
blt::size_t c2_found_bytes = result.child2.get_values().size().total_used_bytes; blt::size_t c2_found_bytes = c2.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)
@ -153,10 +151,10 @@ namespace blt::gp
} }
#endif #endif
return result; return true;
} }
blt::expected<crossover_t::crossover_point_t, crossover_t::error_t> crossover_t::get_crossover_point(gp_program& program, const tree_t& c1, std::optional<crossover_t::crossover_point_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();
@ -194,10 +192,10 @@ namespace blt::gp
} }
} }
if (!found) if (!found)
return blt::unexpected(error_t::NO_VALID_TYPE); return {};
} }
// should we try again over the whole tree? probably not. // should we try again over the whole tree? probably not.
return blt::unexpected(error_t::NO_VALID_TYPE); return {};
} 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());
@ -213,13 +211,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)};
} }
tree_t mutation_t::apply(gp_program& program, const tree_t& p) bool mutation_t::apply(gp_program& program, const tree_t& p, tree_t& c)
{ {
auto c = p; c.copy_fast(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 c; return true;
} }
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)
@ -304,10 +302,10 @@ namespace blt::gp
return begin_point + new_ops_r.size(); return begin_point + new_ops_r.size();
} }
tree_t advanced_mutation_t::apply(gp_program& program, const tree_t& p) bool advanced_mutation_t::apply(gp_program& program, const tree_t& p, tree_t& c)
{ {
// child tree // child tree
tree_t c = p; c.copy_fast(p);
auto& ops = c.get_operations(); auto& ops = c.get_operations();
auto& vals = c.get_values(); auto& vals = c.get_values();
@ -732,6 +730,6 @@ namespace blt::gp
} }
#endif #endif
return c; return true;
} }
} }