diff --git a/CMakeLists.txt b/CMakeLists.txt index 27ddba2..2f6a0f3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 3.25) -project(blt-gp VERSION 0.0.47) +project(blt-gp VERSION 0.0.48) include(CTest) diff --git a/examples/gp_test_5.cpp b/examples/gp_test_5.cpp index 376f047..4bfd96f 100644 --- a/examples/gp_test_5.cpp +++ b/examples/gp_test_5.cpp @@ -36,6 +36,7 @@ #include #include #include +#include static constexpr long SEED = 41912; @@ -94,13 +95,39 @@ int main() blt::gp::ramped_half_initializer_t pop_init; auto pop = pop_init.generate(blt::gp::initializer_arguments{program, type_system.get_type().id(), 500, 3, 10}); + +// for (auto& tree : pop.getIndividuals()) +// { +// auto value = tree.get_evaluation_value(nullptr); +// +// BLT_TRACE(value); +// } - for (auto& tree : pop.getIndividuals()) + blt::gp::crossover_t crossover; + + auto& ind = pop.getIndividuals(); + auto results = crossover.apply(program, ind[0], ind[1]); + + if (results.has_value()) { - auto value = tree.get_evaluation_value(nullptr); - - BLT_TRACE(value); + BLT_TRACE("Parent 1: %f", ind[0].get_evaluation_value(nullptr)); + BLT_TRACE("Parent 2: %f", ind[1].get_evaluation_value(nullptr)); + BLT_TRACE("------------"); + BLT_TRACE("Child 1: %f", results->child1.get_evaluation_value(nullptr)); + BLT_TRACE("Child 2: %f", results->child2.get_evaluation_value(nullptr)); + } else + { + switch (results.error()) + { + case blt::gp::crossover_t::error_t::NO_VALID_TYPE: + BLT_ERROR("No valid type!"); + break; + case blt::gp::crossover_t::error_t::TREE_TOO_SMALL: + BLT_ERROR("Tree is too small!"); + break; + } } + return 0; } diff --git a/include/blt/gp/tree.h b/include/blt/gp/tree.h index 003616e..d209209 100644 --- a/include/blt/gp/tree.h +++ b/include/blt/gp/tree.h @@ -36,8 +36,8 @@ namespace blt::gp func(func), transfer(transfer), id(id), is_value(is_value) {} - detail::callable_t& func; - detail::transfer_t& transfer; + std::reference_wrapper func; + std::reference_wrapper transfer; operator_id id; bool is_value; }; diff --git a/src/transformers.cpp b/src/transformers.cpp index d079c8a..a429999 100644 --- a/src/transformers.cpp +++ b/src/transformers.cpp @@ -27,6 +27,9 @@ namespace blt::gp const auto& config = program.get_config(); result_t result{p1, p2}; + BLT_INFO("Child 1 Stack empty? %s", result.child1.get_values().empty() ? "true" : "false"); + BLT_INFO("Child 2 Stack empty? %s", result.child2.get_values().empty() ? "true" : "false"); + auto& c1 = result.child1; auto& c2 = result.child2; @@ -86,6 +89,7 @@ namespace blt::gp index++; } while (children_left > 0); + auto crossover_point_begin_itr = c1_ops.begin() + static_cast(crossover_point); auto crossover_point_end_itr = c1_ops.begin() + static_cast(index); children_left = 0; @@ -104,19 +108,111 @@ namespace blt::gp break; } while (true); - auto found_point_end_iter = c2_ops.begin() + static_cast(index); + auto found_point_begin_itr = c2_ops.begin() + static_cast(attempted_point); + auto found_point_end_itr = c2_ops.begin() + static_cast(index); - stack_allocator c1_stack_init = c1.get_values(); - stack_allocator c2_stack_init = c2.get_values(); + stack_allocator& c1_stack_init = c1.get_values(); + stack_allocator& c2_stack_init = c2.get_values(); std::vector c1_operators; std::vector c2_operators; - for (const auto& op : blt::enumerate(c1_ops.begin() + static_cast(crossover_point), crossover_point_end_itr)) + for (const auto& op : blt::enumerate(crossover_point_begin_itr, crossover_point_end_itr)) c1_operators.push_back(op); - for (const auto& op : blt::enumerate(c2_ops.begin() + static_cast(attempted_point), found_point_end_iter)) + for (const auto& op : blt::enumerate(found_point_begin_itr, found_point_end_itr)) c2_operators.push_back(op); + stack_allocator c1_stack_after_copy; + stack_allocator c1_stack_for_copy; + stack_allocator c2_stack_after_copy; + stack_allocator c2_stack_for_copy; + + // transfer all values after the crossover point. these will need to be transferred back to child2 + for (auto it = c1_ops.end() - 1; it != crossover_point_end_itr - 1; it--) + { + if (it->is_value) + it->transfer(c1_stack_after_copy, c1_stack_init, -1); + } + + // transfer all values for the crossover point. + for (auto it = crossover_point_end_itr - 1; it != crossover_point_begin_itr - 1; it--) + { + if (it->is_value) + it->transfer(c1_stack_for_copy, c1_stack_init, -1); + } + + // transfer child2 values for copying back into c1 + for (auto it = c2_ops.end() - 1; it != found_point_end_itr - 1; it--) + { + if (it->is_value) + it->transfer(c2_stack_after_copy, c2_stack_init, -1); + } + + for (auto it = found_point_end_itr - 1; it != found_point_begin_itr - 1; it--) + { + if (it->is_value) + it->transfer(c2_stack_for_copy, c2_stack_init, -1); + } + + BLT_TRACE("c1_stack_after_copy empty? %s", c1_stack_after_copy.empty() ? "true" : "false"); + BLT_TRACE("c1_stack_for_copy empty? %s", c1_stack_for_copy.empty() ? "true" : "false"); + BLT_TRACE("c2_stack_after_copy empty? %s", c2_stack_after_copy.empty() ? "true" : "false"); + BLT_TRACE("c2_stack_for_copy empty? %s", c2_stack_for_copy.empty() ? "true" : "false"); + BLT_INFO("Child 1 Stack empty? %s", result.child1.get_values().empty() ? "true" : "false"); + BLT_INFO("Child 2 Stack empty? %s", result.child2.get_values().empty() ? "true" : "false"); + + // now copy back into the respective children + for (auto it = found_point_begin_itr; it != found_point_end_itr; it++) + { + if (it->is_value) + it->transfer(c1.get_values(), c2_stack_for_copy, -1); + } + + for (auto it = crossover_point_begin_itr; it != crossover_point_end_itr; it++) + { + if (it->is_value) + it->transfer(c2.get_values(), c1_stack_for_copy, -1); + } + + BLT_TRACE("c1_stack_after_copy empty? %s", c1_stack_after_copy.empty() ? "true" : "false"); + BLT_TRACE("c1_stack_for_copy empty? %s", c1_stack_for_copy.empty() ? "true" : "false"); + BLT_TRACE("c2_stack_after_copy empty? %s", c2_stack_after_copy.empty() ? "true" : "false"); + BLT_TRACE("c2_stack_for_copy empty? %s", c2_stack_for_copy.empty() ? "true" : "false"); + BLT_INFO("Child 1 Stack empty? %s", result.child1.get_values().empty() ? "true" : "false"); + BLT_INFO("Child 2 Stack empty? %s", result.child2.get_values().empty() ? "true" : "false"); + + // now copy after the crossover point back to the correct children + for (auto it = crossover_point_end_itr; it != c1_ops.end(); it++) + { + if (it->is_value) + it->transfer(c1.get_values(), c1_stack_after_copy, -1); + } + + for (auto it = found_point_end_itr; it != c2_ops.end(); it++) + { + if (it->is_value) + it->transfer(c2.get_values(), c2_stack_after_copy, -1); + } + + BLT_TRACE("c1_stack_after_copy empty? %s", c1_stack_after_copy.empty() ? "true" : "false"); + BLT_TRACE("c1_stack_for_copy empty? %s", c1_stack_for_copy.empty() ? "true" : "false"); + BLT_TRACE("c2_stack_after_copy empty? %s", c2_stack_after_copy.empty() ? "true" : "false"); + BLT_TRACE("c2_stack_for_copy empty? %s", c2_stack_for_copy.empty() ? "true" : "false"); + + // now swap the operators + auto insert_point_c1 = crossover_point_begin_itr - 1; + auto insert_point_c2 = found_point_begin_itr - 1; + + // invalidates [begin, end()) so the insert points should be fine + c1_ops.erase(crossover_point_begin_itr, crossover_point_end_itr); + c2_ops.erase(found_point_begin_itr, found_point_end_itr); + + c1_ops.insert(++insert_point_c1, c2_operators.begin(), c2_operators.end()); + c1_ops.insert(++insert_point_c2, c1_operators.begin(), c1_operators.end()); + + BLT_INFO("Child 1 Stack empty? %s", result.child1.get_values().empty() ? "true" : "false"); + BLT_INFO("Child 2 Stack empty? %s", result.child2.get_values().empty() ? "true" : "false"); + return result; } } \ No newline at end of file