diff --git a/CMakeLists.txt b/CMakeLists.txt index 1aca375..ab95e26 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 3.25) -project(lilfbtf5 VERSION 0.1.27) +project(lilfbtf5 VERSION 0.1.28) option(ENABLE_ADDRSAN "Enable the address sanitizer" OFF) option(ENABLE_UBSAN "Enable the ub sanitizer" OFF) diff --git a/include/lilfbtf/system.h b/include/lilfbtf/system.h index c4e41b6..a135468 100644 --- a/include/lilfbtf/system.h +++ b/include/lilfbtf/system.h @@ -23,7 +23,12 @@ namespace fb { - + + class gp_system_t + { + + }; + } #endif //LILFBTF5_SYSTEM_H diff --git a/include/lilfbtf/tree.h b/include/lilfbtf/tree.h index 8515e63..cca1b64 100644 --- a/include/lilfbtf/tree.h +++ b/include/lilfbtf/tree.h @@ -109,6 +109,13 @@ namespace fb alloc.deallocate(children, type.argc()); } }; + + struct node_helper_t + { + blt::bump_allocator& alloc; + random& engine; + type_engine_t& types; + }; } class tree_t @@ -120,10 +127,17 @@ namespace fb inline blt::bump_allocator& get_allocator() { return alloc; } + + static detail::node_t* allocate_non_terminal(detail::node_helper_t details, type_id type); + static detail::node_t* allocate_non_terminal_restricted(detail::node_helper_t details, type_id type); + + static detail::node_t* allocate_terminal(detail::node_helper_t details, type_id type); + public: explicit tree_t(type_engine_t& types); - static tree_t make_tree(type_engine_t& types, random& engine, blt::size_t min_height, blt::size_t max_height, std::optional starting_type = {}); + static tree_t make_tree(type_engine_t& types, random& engine, blt::size_t min_height, blt::size_t max_height, + std::optional starting_type = {}); std::pair evaluate(); }; diff --git a/src/tree.cpp b/src/tree.cpp index 0658078..6fc5901 100644 --- a/src/tree.cpp +++ b/src/tree.cpp @@ -70,33 +70,26 @@ namespace fb const auto& terminals = types.get_terminals(type_category); const auto& non_terminals = types.get_non_terminals(type_category); - if (depth < max_height) - stack.emplace(node->children[i], depth + 1); - if (depth < min_height && !has_one_non_terminal) { + // make sure we have at least min height possible by using at least one non terminal function_id selection = non_terminals[engine.random_long(0, non_terminals.size() - 1)]; func_t func(types.get_function_argc(selection), types.get_function(selection), type_category, selection); if (const auto& func_init = types.get_function_initializer(selection)) func_init.value()(func); node->children[i] = tree.alloc.template emplace(func, tree.alloc); has_one_non_terminal = true; - continue; - } - - if (depth >= max_height) + } else if (depth >= max_height) { + // if we are above the max_height select only terminals function_id selection = terminals[engine.random_long(0, terminals.size() - 1)]; func_t func(types.get_function_argc(selection), types.get_function(selection), type_category, selection); if (const auto& func_init = types.get_function_initializer(selection)) func_init.value()(func); node->children[i] = tree.alloc.template emplace(func, tree.alloc); - continue; - } - - if (engine.choice()) + } else if (engine.choice()) { - // use full() method + // otherwise select between use full() method function_id selection = non_terminals[engine.random_long(0, non_terminals.size() - 1)]; func_t func(types.get_function_argc(selection), types.get_function(selection), type_category, selection); if (const auto& func_init = types.get_function_initializer(selection)) @@ -104,10 +97,10 @@ namespace fb node->children[i] = tree.alloc.template emplace(func, tree.alloc); } else { - // use grow() method, meaning select choice again + // and use grow() method, meaning select choice again if (engine.choice()) { - // use non-terminals + // to use non-terminals function_id selection = non_terminals[engine.random_long(0, non_terminals.size() - 1)]; func_t func(types.get_function_argc(selection), types.get_function(selection), type_category, selection); if (const auto& func_init = types.get_function_initializer(selection)) @@ -115,7 +108,7 @@ namespace fb node->children[i] = tree.alloc.template emplace(func, tree.alloc); } else { - // use terminals + // or use terminals function_id selection = terminals[engine.random_long(0, terminals.size() - 1)]; func_t func(types.get_function_argc(selection), types.get_function(selection), type_category, selection); if (const auto& func_init = types.get_function_initializer(selection)) @@ -123,6 +116,9 @@ namespace fb node->children[i] = tree.alloc.template emplace(func, tree.alloc); } } + // node has children that need populated + if (node->children[i]->type.argc() != 0) + stack.emplace(node->children[i], depth + 1); } } @@ -155,5 +151,45 @@ namespace fb return {root->type.getValue(), root->type.getType()}; } + detail::node_t* tree_t::allocate_non_terminal(detail::node_helper_t details, type_id type) + { + const auto& non_terminals = details.types.get_non_terminals(type); + function_id selection = non_terminals[details.engine.random_long(0, non_terminals.size() - 1)]; + func_t func(details.types.get_function_argc(selection), details.types.get_function(selection), type, selection); + if (const auto& func_init = details.types.get_function_initializer(selection)) + func_init.value()(func); + return details.alloc.template emplace(func, details.alloc); + } + + detail::node_t* tree_t::allocate_terminal(detail::node_helper_t details, type_id type) + { + const auto& terminals = details.types.get_terminals(type); + + // if we cannot allocate a terminal, we need to allocate a non-terminal in hopes of finding a closing path + // for example bools might not have an ending terminal, it doesn't make sense to. + if (terminals.empty()) + return allocate_non_terminal_restricted(details, type); + + function_id selection = terminals[details.engine.random_long(0, terminals.size() - 1)]; + func_t func(details.types.get_function_argc(selection), details.types.get_function(selection), type, selection); + if (const auto& func_init = details.types.get_function_initializer(selection)) + func_init.value()(func); + return details.alloc.template emplace(func, details.alloc); + } + + detail::node_t* tree_t::allocate_non_terminal_restricted(detail::node_helper_t details, type_id type) + { + const auto& non_terminals = details.types.get_non_terminals(type); + function_id selection = 0; + + + + + func_t func(details.types.get_function_argc(selection), details.types.get_function(selection), type, selection); + if (const auto& func_init = details.types.get_function_initializer(selection)) + func_init.value()(func); + return details.alloc.template emplace(func, details.alloc); + } + } \ No newline at end of file diff --git a/src/type.cpp b/src/type.cpp index 03b226e..cdaad3a 100644 --- a/src/type.cpp +++ b/src/type.cpp @@ -39,7 +39,7 @@ namespace fb all_non_terminals.emplace_back(tid, id); function_argc.insert(id, argc); if (auto& init = initializer) - function_initializer.insert(id, init.value()); + function_initializer.insert({id, init.value()}); return id; } @@ -63,7 +63,7 @@ namespace fb terminals.at(tid).push_back(id); function_argc.insert(id, 0); if (auto& init = initializer) - function_initializer.insert(id, init.value()); + function_initializer.insert({id, init.value()}); return id; } } \ No newline at end of file