diff --git a/CMakeLists.txt b/CMakeLists.txt index ffa858a..b79814a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -27,7 +27,7 @@ macro(compile_options target_name) sanitizers(${target_name}) endmacro() -project(blt-gp VERSION 0.5.25) +project(blt-gp VERSION 0.5.26) include(CTest) diff --git a/include/blt/gp/tree.h b/include/blt/gp/tree.h index ac4ed08..3d6eb44 100644 --- a/include/blt/gp/tree.h +++ b/include/blt/gp/tree.h @@ -418,6 +418,11 @@ namespace blt::gp copy_subtree(point, find_endpoint(point.pos), out_tree); } + void copy_subtree(const child_t subtree, tree_t& out_tree) + { + copy_subtree(subtree_point_t{subtree.start}, subtree.end, out_tree); + } + void swap_subtrees(child_t our_subtree, tree_t& other_tree, child_t other_subtree); /** @@ -466,6 +471,11 @@ namespace blt::gp delete_subtree(point, find_endpoint(point.pos)); } + void delete_subtree(const child_t subtree) + { + delete_subtree(subtree_point_t{subtree.start}, subtree.end); + } + /** * Insert a subtree before the specified point * @param point point to insert into diff --git a/src/program.cpp b/src/program.cpp index 747e792..c3bcf88 100644 --- a/src/program.cpp +++ b/src/program.cpp @@ -31,8 +31,8 @@ namespace blt::gp // this is largely to not break the tests :3 // it's also to allow for quick setup of a gp program if you don't care how crossover or mutation is handled static advanced_mutation_t s_mutator; - // static subtree_crossover_t s_crossover; - static one_point_crossover_t s_crossover; + static subtree_crossover_t s_crossover; + // static one_point_crossover_t s_crossover; static ramped_half_initializer_t s_init; prog_config_t::prog_config_t(): mutator(s_mutator), crossover(s_crossover), pop_initializer(s_init) diff --git a/src/transformers.cpp b/src/transformers.cpp index d85f55f..bcbc50f 100644 --- a/src/transformers.cpp +++ b/src/transformers.cpp @@ -173,22 +173,29 @@ namespace blt::gp std::vector p1_reorder_types; std::vector p2_reorder_types; std::vector swap_types; + std::vector temp_trees; void print_missing_types() { for (const auto& [id, v] : missing_p1_types) { - BLT_INFO("(P1) For type {} missing indexes:", id); - for (const auto idx : v) - BLT_INFO("\t{}", idx); - BLT_INFO("----"); + if (!v.empty()) + { + BLT_INFO("(P1) For type {} missing indexes:", id); + for (const auto idx : v) + BLT_INFO("\t{}", idx); + BLT_INFO("----"); + } } for (const auto& [id, v] : missing_p2_types) { - BLT_INFO("(P2) For type {} missing indexes:", id); - for (const auto idx : v) - BLT_INFO("\t{}", idx); - BLT_INFO("----"); + if (!v.empty()) + { + BLT_INFO("(P2) For type {} missing indexes:", id); + for (const auto idx : v) + BLT_INFO("\t{}", idx); + BLT_INFO("----"); + } } } @@ -234,6 +241,8 @@ namespace blt::gp p1_reorder_types.clear(); p2_reorder_types.clear(); swap_types.clear(); + for (auto& tree : temp_trees) + tree.clear(program); for (auto& [id, v] : missing_p1_types) v.clear(); for (auto& [id, v] : missing_p2_types) @@ -275,6 +284,14 @@ namespace blt::gp } } + BLT_DEBUG("Operator C1 {} expects types: ", p1_operator.id()); + for (const auto [i, type] : enumerate(p1_info.argument_types)) + BLT_TRACE("{} -> {}", i, type); + BLT_DEBUG("Operator C2 {} expects types: ", p2_operator.id()); + for (const auto [i, type] : enumerate(p2_info.argument_types)) + BLT_TRACE("{} -> {}", i, type); + resolver.print_missing_types(); + for (size_t i = 0; i < p2_info.argument_types.size(); i++) { if (resolver.correct_types.contains(i)) @@ -308,13 +325,40 @@ namespace blt::gp p2.find_child_extends(resolver.children_data_p2, point2.pos, p2_info.argument_types.size()); for (const auto& [index1, index2] : resolver.p1_reorder_types) + { + BLT_DEBUG("Reordering in C1: {} -> {}", index1, index2); c1.swap_subtrees(resolver.children_data_p1[index1], c1, resolver.children_data_p1[index2]); + } for (const auto& [index1, index2] : resolver.p2_reorder_types) + { + BLT_DEBUG("Reordering in C2: {} -> {}", index1, index2); c2.swap_subtrees(resolver.children_data_p2[index1], c2, resolver.children_data_p2[index2]); + } + + auto c1_insert = resolver.children_data_p1.back().end; + auto c2_insert = resolver.children_data_p2.back().end; for (const auto& [p1_index, p2_index] : resolver.swap_types) - c1.swap_subtrees(resolver.children_data_p1[p1_index], c2, resolver.children_data_p2[p2_index]); + { + if (p1_index < p1_info.argument_types.size() && p2_index < p2_info.argument_types.size()) + c1.swap_subtrees(resolver.children_data_p1[p1_index], c2, resolver.children_data_p2[p2_index]); + else if (p1_index < p1_info.argument_types.size() && p2_index >= p2_info.argument_types.size()) + { + BLT_TRACE("(P1 IS UNDER!) Trying to swap P1 {} for P2 {} (Sizes: P1: {} P2: {})", p1_index, p2_index, p1_info.argument_types.size(), p2_info.argument_types.size()); + BLT_TRACE("Inserting into P2 from P1!"); + c1.copy_subtree(resolver.children_data_p1[p1_index], resolver.temp_tree); + c1.delete_subtree(resolver.children_data_p1[p1_index]); + c2_insert = c2.insert_subtree(tree_t::subtree_point_t{c1_insert}, resolver.temp_tree); + } else if (p2_index < p2_info.argument_types.size() && p1_index >= p1_info.argument_types.size()) + { + BLT_TRACE("(P2 IS UNDER!) Trying to swap P1 {} for P2 {} (Sizes: P1: {} P2: {})", p1_index, p2_index, p1_info.argument_types.size(), p2_info.argument_types.size()); + } else + { + BLT_WARN("This should be an impossible state!"); + } + } + c1.modify_operator(point1.pos, p2_operator.id(), p2_info.return_type); c2.modify_operator(point2.pos, p1_operator.id(), p1_info.return_type); diff --git a/tests/serialization_test.cpp b/tests/serialization_test.cpp index ed70b30..4ff77e9 100644 --- a/tests/serialization_test.cpp +++ b/tests/serialization_test.cpp @@ -41,7 +41,7 @@ prog_config_t config = prog_config_t() .set_reproduction_chance(0.1) .set_max_generations(50) .set_pop_size(500) - .set_thread_count(0); + .set_thread_count(1); example::symbolic_regression_t regression{691ul, config};