about to remove the funny little tree init system and replace with something more useful

main
Brett 2024-03-19 11:46:18 -04:00
parent 10fe1e28cf
commit 319d385cd9
3 changed files with 57 additions and 33 deletions

View File

@ -1,5 +1,5 @@
cmake_minimum_required(VERSION 3.25) cmake_minimum_required(VERSION 3.25)
project(lilfbtf5 VERSION 0.1.29) project(lilfbtf5 VERSION 0.1.30)
option(ENABLE_ADDRSAN "Enable the address sanitizer" OFF) option(ENABLE_ADDRSAN "Enable the address sanitizer" OFF)
option(ENABLE_UBSAN "Enable the ub sanitizer" OFF) option(ENABLE_UBSAN "Enable the ub sanitizer" OFF)

View File

@ -72,6 +72,18 @@ namespace fb
~func_t() = default; ~func_t() = default;
}; };
enum class tree_init_t
{
// standard grow method
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
};
namespace detail namespace detail
{ {
class node_t class node_t
@ -110,12 +122,19 @@ namespace fb
} }
}; };
struct node_helper_t struct node_construction_info_t
{ {
blt::bump_allocator<blt::BLT_2MB_SIZE, false>& alloc; blt::bump_allocator<blt::BLT_2MB_SIZE, false>& alloc;
random& engine; random& engine;
type_engine_t& types; type_engine_t& types;
}; };
struct tree_construction_info_t
{
tree_init_t tree_type;
random& engine;
type_engine_t& types;
};
} }
class tree_t class tree_t
@ -128,15 +147,18 @@ namespace fb
inline blt::bump_allocator<blt::BLT_2MB_SIZE, false>& get_allocator() inline blt::bump_allocator<blt::BLT_2MB_SIZE, false>& get_allocator()
{ return alloc; } { return alloc; }
static detail::node_t* allocate_non_terminal(detail::node_helper_t details, type_id type); static detail::node_t* allocate_non_terminal(detail::node_construction_info_t info, type_id type);
static detail::node_t* allocate_non_terminal_restricted(detail::node_helper_t details, type_id type);
static detail::node_t* allocate_non_terminal_restricted(detail::node_construction_info_t info, type_id type);
static detail::node_t* allocate_terminal(detail::node_construction_info_t info, type_id type);
static detail::node_t* allocate_terminal(detail::node_helper_t details, type_id type);
public: public:
explicit tree_t(type_engine_t& types); 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, static tree_t make_tree(detail::tree_construction_info_t tree_info, blt::size_t min_depth, blt::size_t max_depth,
std::optional<type_id> starting_type = {}); std::optional<type_id> starting_type = {});
std::pair<blt::unsafe::any_t, type_id> evaluate(); std::pair<blt::unsafe::any_t, type_id> evaluate();

View File

@ -28,7 +28,7 @@ namespace fb
{} {}
tree_t tree_t::make_tree(type_engine_t& types, random& engine, tree_t tree_t::make_tree(type_engine_t& types, random& engine,
blt::size_t min_height, blt::size_t max_height, std::optional<type_id> starting_type) blt::size_t min_depth, blt::size_t max_depth, std::optional<type_id> starting_type)
{ {
using detail::node_t; using detail::node_t;
tree_t tree(types); tree_t tree(types);
@ -70,7 +70,7 @@ namespace fb
const auto& terminals = types.get_terminals(type_category); const auto& terminals = types.get_terminals(type_category);
const auto& non_terminals = types.get_non_terminals(type_category); const auto& non_terminals = types.get_non_terminals(type_category);
if (depth < min_height && !has_one_non_terminal) if (depth < min_depth && !has_one_non_terminal)
{ {
// make sure we have at least min height possible by using at least 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)]; function_id selection = non_terminals[engine.random_long(0, non_terminals.size() - 1)];
@ -79,7 +79,7 @@ namespace fb
func_init.value()(func); func_init.value()(func);
node->children[i] = tree.alloc.template emplace<node_t>(func, tree.alloc); node->children[i] = tree.alloc.template emplace<node_t>(func, tree.alloc);
has_one_non_terminal = true; has_one_non_terminal = true;
} else if (depth >= max_height) } else if (depth >= max_depth)
{ {
// if we are above the max_height select only terminals // if we are above the max_height select only terminals
function_id selection = terminals[engine.random_long(0, terminals.size() - 1)]; function_id selection = terminals[engine.random_long(0, terminals.size() - 1)];
@ -133,6 +133,7 @@ namespace fb
nodes.push(root); nodes.push(root);
// create the correct ordering for the node evaluation
while (!nodes.empty()) while (!nodes.empty())
{ {
auto* top = nodes.top(); auto* top = nodes.top();
@ -151,48 +152,49 @@ namespace fb
return {root->type.getValue(), root->type.getType()}; return {root->type.getValue(), root->type.getType()};
} }
detail::node_t* tree_t::allocate_non_terminal(detail::node_helper_t details, type_id type) detail::node_t* tree_t::allocate_non_terminal(detail::node_construction_info_t info, type_id type)
{ {
const auto& non_terminals = details.types.get_non_terminals(type); const auto& non_terminals = info.types.get_non_terminals(type);
function_id selection = non_terminals[details.engine.random_long(0, non_terminals.size() - 1)]; function_id selection = non_terminals[info.engine.random_long(0, non_terminals.size() - 1)];
func_t func(details.types.get_function_argc(selection), details.types.get_function(selection), type, selection); func_t func(info.types.get_function_argc(selection), info.types.get_function(selection), type, selection);
if (const auto& func_init = details.types.get_function_initializer(selection)) if (const auto& func_init = info.types.get_function_initializer(selection))
func_init.value()(func); func_init.value()(func);
return details.alloc.template emplace<detail::node_t>(func, details.alloc); return info.alloc.template emplace<detail::node_t>(func, info.alloc);
} }
detail::node_t* tree_t::allocate_terminal(detail::node_helper_t details, type_id type) detail::node_t* tree_t::allocate_terminal(detail::node_construction_info_t info, type_id type)
{ {
const auto& terminals = details.types.get_terminals(type); const auto& terminals = info.types.get_terminals(type);
// if we cannot allocate a terminal, we need to allocate a non-terminal in hopes of finding a closing path // 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. // for example bools might not have an ending terminal, it doesn't make sense to.
if (terminals.empty()) if (terminals.empty())
return allocate_non_terminal_restricted(details, type); return allocate_non_terminal_restricted(info, type);
function_id selection = terminals[details.engine.random_long(0, terminals.size() - 1)]; function_id selection = terminals[info.engine.random_long(0, terminals.size() - 1)];
func_t func(details.types.get_function_argc(selection), details.types.get_function(selection), type, selection); func_t func(info.types.get_function_argc(selection), info.types.get_function(selection), type, selection);
if (const auto& func_init = details.types.get_function_initializer(selection)) if (const auto& func_init = info.types.get_function_initializer(selection))
func_init.value()(func); func_init.value()(func);
return details.alloc.template emplace<detail::node_t>(func, details.alloc); return info.alloc.template emplace<detail::node_t>(func, info.alloc);
} }
detail::node_t* tree_t::allocate_non_terminal_restricted(detail::node_helper_t details, type_id type) detail::node_t* tree_t::allocate_non_terminal_restricted(detail::node_construction_info_t info, type_id type)
{ {
function_id selection = 0; function_id selection = 0;
do { do
const auto& non_terminals = details.types.get_non_terminals(type); {
selection = details.engine.random_long(0, non_terminals.size() - 1); const auto& non_terminals = info.types.get_non_terminals(type);
auto& sel_v = details.types.get_function_allowed_arguments(selection); selection = info.engine.random_long(0, non_terminals.size() - 1);
// if it does not accept the type we are auto& sel_v = info.types.get_function_allowed_arguments(selection);
// if it does not accept the type we are, we will accept this as a valid "temp" non-terminal
if (std::find(sel_v.begin(), sel_v.end(), type) == sel_v.end()) if (std::find(sel_v.begin(), sel_v.end(), type) == sel_v.end())
break; break;
} while (true); } while (true);
func_t func(details.types.get_function_argc(selection), details.types.get_function(selection), type, selection); func_t func(info.types.get_function_argc(selection), info.types.get_function(selection), type, selection);
if (const auto& func_init = details.types.get_function_initializer(selection)) if (const auto& func_init = info.types.get_function_initializer(selection))
func_init.value()(func); (*func_init)(func);
return details.alloc.template emplace<detail::node_t>(func, details.alloc); return info.alloc.template emplace<detail::node_t>(func, info.alloc);
} }