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)
project(lilfbtf5 VERSION 0.1.29)
project(lilfbtf5 VERSION 0.1.30)
option(ENABLE_ADDRSAN "Enable the address sanitizer" OFF)
option(ENABLE_UBSAN "Enable the ub sanitizer" OFF)

View File

@ -72,6 +72,18 @@ namespace fb
~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
{
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;
random& engine;
type_engine_t& types;
};
struct tree_construction_info_t
{
tree_init_t tree_type;
random& engine;
type_engine_t& types;
};
}
class tree_t
@ -128,15 +147,18 @@ namespace fb
inline blt::bump_allocator<blt::BLT_2MB_SIZE, false>& 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_non_terminal(detail::node_construction_info_t info, 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:
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::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,
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;
tree_t tree(types);
@ -70,7 +70,7 @@ namespace fb
const auto& terminals = types.get_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
function_id selection = non_terminals[engine.random_long(0, non_terminals.size() - 1)];
@ -79,7 +79,7 @@ namespace fb
func_init.value()(func);
node->children[i] = tree.alloc.template emplace<node_t>(func, tree.alloc);
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
function_id selection = terminals[engine.random_long(0, terminals.size() - 1)];
@ -133,6 +133,7 @@ namespace fb
nodes.push(root);
// create the correct ordering for the node evaluation
while (!nodes.empty())
{
auto* top = nodes.top();
@ -151,48 +152,49 @@ 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)
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);
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))
const auto& non_terminals = info.types.get_non_terminals(type);
function_id selection = non_terminals[info.engine.random_long(0, non_terminals.size() - 1)];
func_t func(info.types.get_function_argc(selection), info.types.get_function(selection), type, selection);
if (const auto& func_init = info.types.get_function_initializer(selection))
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
// 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);
return allocate_non_terminal_restricted(info, 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))
function_id selection = terminals[info.engine.random_long(0, terminals.size() - 1)];
func_t func(info.types.get_function_argc(selection), info.types.get_function(selection), type, selection);
if (const auto& func_init = info.types.get_function_initializer(selection))
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;
do {
const auto& non_terminals = details.types.get_non_terminals(type);
selection = details.engine.random_long(0, non_terminals.size() - 1);
auto& sel_v = details.types.get_function_allowed_arguments(selection);
// if it does not accept the type we are
do
{
const auto& non_terminals = info.types.get_non_terminals(type);
selection = info.engine.random_long(0, non_terminals.size() - 1);
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())
break;
} while(true);
} while (true);
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<detail::node_t>(func, details.alloc);
func_t func(info.types.get_function_argc(selection), info.types.get_function(selection), type, selection);
if (const auto& func_init = info.types.get_function_initializer(selection))
(*func_init)(func);
return info.alloc.template emplace<detail::node_t>(func, info.alloc);
}