diff --git a/CMakeLists.txt b/CMakeLists.txt index fac6e7b..3ea3f79 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 3.25) -project(lilfbtf5 VERSION 0.1.31) +project(lilfbtf5 VERSION 0.1.32) option(ENABLE_ADDRSAN "Enable the address sanitizer" OFF) option(ENABLE_UBSAN "Enable the ub sanitizer" OFF) diff --git a/include/lilfbtf/tree.h b/include/lilfbtf/tree.h index 68968fa..7a0d080 100644 --- a/include/lilfbtf/tree.h +++ b/include/lilfbtf/tree.h @@ -74,14 +74,12 @@ namespace fb enum class tree_init_t { - // standard grow method + // standard koza grow method GROW, + + BRETT_GROW, // standard full method - FULL, - // standard ramped half-and-half method - RAMPED_HALF_HALF, - // variant of grow/full method where at each level a choice is made between using only non-terminals or terminals - BRETT_HALF_HALF + FULL }; namespace detail @@ -160,6 +158,7 @@ namespace fb static detail::node_t* allocate_terminal(detail::node_construction_info_t info, type_id type); static void grow(detail::node_construction_info_t info, blt::size_t min_depth, blt::size_t max_depth); + static void brett_grow(detail::node_construction_info_t info, blt::size_t min_depth, blt::size_t max_depth); static void full(detail::node_construction_info_t info, blt::size_t depth); diff --git a/src/tree.cpp b/src/tree.cpp index de7503b..6b2ed7c 100644 --- a/src/tree.cpp +++ b/src/tree.cpp @@ -52,13 +52,12 @@ namespace fb case tree_init_t::GROW: grow({tree, tree_info}, min_depth, max_depth); break; + case tree_init_t::BRETT_GROW: + brett_grow({tree, tree_info}, min_depth, max_depth); + break; case tree_init_t::FULL: full({tree, tree_info}, tree_info.engine.random_long(min_depth, max_depth)); break; - case tree_init_t::RAMPED_HALF_HALF: - break; - case tree_init_t::BRETT_HALF_HALF: - break; } return tree; @@ -136,7 +135,7 @@ namespace fb return info.tree.alloc.template emplace(func, info.tree.alloc); } - void tree_t::grow(detail::node_construction_info_t info, blt::size_t min_depth, blt::size_t max_depth) + void tree_t::brett_grow(detail::node_construction_info_t info, blt::size_t min_depth, blt::size_t max_depth) { using namespace detail; std::stack> stack; @@ -209,5 +208,55 @@ namespace fb } } + void tree_t::grow(detail::node_construction_info_t info, blt::size_t min_depth, blt::size_t max_depth) + { + using namespace detail; + std::stack> stack; + stack.emplace(info.tree.root, 0); + while (!stack.empty()) + { + auto top = stack.top(); + auto* node = top.first; + auto depth = top.second; + stack.pop(); + + const auto& allowed_types = info.types.get_function_allowed_arguments(node->type.getFunction()); + // we need to make sure there is at least one non-terminal generation, until we hit the min height + bool has_one_non_terminal = false; + for (blt::size_t i = 0; i < node->type.argc(); i++) + { + type_id type_category = allowed_types[i]; + + if (depth < min_depth && !has_one_non_terminal) + { + // make sure we have at least min depth possible by using at least one non terminal + node->children[i] = allocate_non_terminal(info, type_category); + has_one_non_terminal = true; + } else if (depth >= max_depth) + { + // if we are above the max_height select only terminals + node->children[i] = allocate_terminal(info, type_category); + } else + { + const auto& non_terminals = info.types.get_non_terminals(type_category); + const auto& terminals = info.types.get_terminals(type_category); + auto index = info.engine.random_long(0, terminals.size() + non_terminals.size()); + function_id selection; + if (index >= non_terminals.size()) + selection = terminals[index - non_terminals.size()]; + else + selection = non_terminals[index]; + func_t func(info.types.get_function_argc(selection), info.types.get_function(selection), type_category, selection); + if (const auto& func_init = info.types.get_function_initializer(selection)) + func_init.value()(func); + node->children[i] = info.tree.alloc.template emplace(func, info.tree.alloc); + } + // node has children that need populated + if (node->children[i]->type.argc() != 0) + stack.emplace(node->children[i], depth + 1); + } + } + } + } \ No newline at end of file