generators!
parent
8a9ecb3484
commit
6b86f83d61
|
@ -1,5 +1,5 @@
|
||||||
cmake_minimum_required(VERSION 3.25)
|
cmake_minimum_required(VERSION 3.25)
|
||||||
project(blt-gp VERSION 0.0.29)
|
project(blt-gp VERSION 0.0.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)
|
||||||
|
|
|
@ -31,7 +31,7 @@ blt::gp::operation_t lit([]() {
|
||||||
return dist(program.get_random());
|
return dist(program.get_random());
|
||||||
});
|
});
|
||||||
|
|
||||||
int main_old()
|
int main()
|
||||||
{
|
{
|
||||||
type_system.register_type<float>();
|
type_system.register_type<float>();
|
||||||
type_system.register_type<bool>();
|
type_system.register_type<bool>();
|
||||||
|
|
|
@ -326,7 +326,7 @@ namespace blt::gp::detail
|
||||||
|
|
||||||
blt::gp::stack_allocator alloc;
|
blt::gp::stack_allocator alloc;
|
||||||
|
|
||||||
int main()
|
int main_old()
|
||||||
{
|
{
|
||||||
constexpr blt::size_t MAX_ALIGNMENT = 8;
|
constexpr blt::size_t MAX_ALIGNMENT = 8;
|
||||||
test();
|
test();
|
||||||
|
|
|
@ -29,6 +29,10 @@ namespace blt::gp
|
||||||
|
|
||||||
class type_system;
|
class type_system;
|
||||||
|
|
||||||
|
class tree_t;
|
||||||
|
|
||||||
|
class population_t;
|
||||||
|
|
||||||
class tree_generator_t;
|
class tree_generator_t;
|
||||||
|
|
||||||
class grow_generator_t;
|
class grow_generator_t;
|
||||||
|
|
|
@ -44,6 +44,36 @@ namespace blt::gp
|
||||||
tree_t generate(gp_program& program, blt::size_t min_depth, blt::size_t max_depth) final;
|
tree_t generate(gp_program& program, blt::size_t min_depth, blt::size_t max_depth) final;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class population_initializer_t
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual population_t generate(gp_program& program, blt::size_t size, blt::size_t min_depth, blt::size_t max_depth) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class grow_initializer_t
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
population_t generate(gp_program& program, blt::size_t size, blt::size_t min_depth, blt::size_t max_depth) final;
|
||||||
|
};
|
||||||
|
|
||||||
|
class full_initializer_t
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
population_t generate(gp_program& program, blt::size_t size, blt::size_t min_depth, blt::size_t max_depth) final;
|
||||||
|
};
|
||||||
|
|
||||||
|
class half_half_initializer_t
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
population_t generate(gp_program& program, blt::size_t size, blt::size_t min_depth, blt::size_t max_depth) final;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ramped_half_initializer_t
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
population_t generate(gp_program& program, blt::size_t size, blt::size_t min_depth, blt::size_t max_depth) final;
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif //BLT_GP_GENERATORS_H
|
#endif //BLT_GP_GENERATORS_H
|
||||||
|
|
|
@ -46,18 +46,34 @@ namespace blt::gp
|
||||||
static constexpr blt::size_t STATIC_T = 0x1;
|
static constexpr blt::size_t STATIC_T = 0x1;
|
||||||
static constexpr blt::size_t TERMINAL_T = 0x2;
|
static constexpr blt::size_t TERMINAL_T = 0x2;
|
||||||
|
|
||||||
|
struct argc_t
|
||||||
|
{
|
||||||
|
blt::size_t argc = 0;
|
||||||
|
blt::size_t argc_context = 0;
|
||||||
|
};
|
||||||
|
|
||||||
template<typename Context = detail::empty_t>
|
template<typename Context = detail::empty_t>
|
||||||
class gp_operations
|
class gp_operations
|
||||||
{
|
{
|
||||||
friend class gp_program;
|
friend class gp_program;
|
||||||
|
|
||||||
friend class blt::gp::detail::operator_storage_test;
|
friend class blt::gp::detail::operator_storage_test;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit gp_operations(type_system& system): system(system)
|
explicit gp_operations(type_system& system): system(system)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void add_non_context_argument(blt::gp::operator_id operator_id)
|
||||||
|
{
|
||||||
|
if constexpr (!std::is_same_v<Context, detail::remove_cv_ref<T>>)
|
||||||
|
{
|
||||||
|
argument_types[operator_id].push_back(system.get_type<T>());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
template<typename Return, typename... Args>
|
template<typename Return, typename... Args>
|
||||||
void add_operator(const operation_t<Return(Args...)>& op, bool is_static = false)
|
gp_operations& add_operator(const operation_t<Return(Args...)>& op, bool is_static = false)
|
||||||
{
|
{
|
||||||
auto return_type_id = system.get_type<Return>().id();
|
auto return_type_id = system.get_type<Return>().id();
|
||||||
auto operator_id = blt::gp::operator_id(operators.size());
|
auto operator_id = blt::gp::operator_id(operators.size());
|
||||||
|
@ -65,10 +81,24 @@ namespace blt::gp
|
||||||
auto& operator_list = op.get_argc() == 0 ? terminals : non_terminals;
|
auto& operator_list = op.get_argc() == 0 ? terminals : non_terminals;
|
||||||
operator_list[return_type_id].push_back(operator_id);
|
operator_list[return_type_id].push_back(operator_id);
|
||||||
|
|
||||||
(argument_types[operator_id].push_back(system.get_type<Args>()), ...);
|
if constexpr (sizeof...(Args) > 0)
|
||||||
|
{
|
||||||
|
(add_non_context_argument<Args>(), ...);
|
||||||
|
}
|
||||||
|
|
||||||
|
argc_t argc;
|
||||||
|
argc.argc_context = argc.argc = sizeof...(Args);
|
||||||
|
|
||||||
|
((std::is_same_v<detail::remove_cv_ref<Args>, Context> ? argc.argc -= 1 : (blt::size_t) nullptr), ...);
|
||||||
|
|
||||||
|
BLT_ASSERT(argc.argc_context - argc.argc <= 1 && "Cannot pass multiple context as arguments!");
|
||||||
|
|
||||||
|
operator_argc[operator_id] = argc;
|
||||||
|
|
||||||
operators.push_back(op.template make_callable<Context>());
|
operators.push_back(op.template make_callable<Context>());
|
||||||
if (is_static)
|
if (is_static)
|
||||||
static_types.insert(operator_id);
|
static_types.insert(operator_id);
|
||||||
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -79,6 +109,7 @@ namespace blt::gp
|
||||||
blt::expanding_buffer<std::vector<operator_id>> non_terminals;
|
blt::expanding_buffer<std::vector<operator_id>> non_terminals;
|
||||||
// indexed from OPERATOR ID (operator number)
|
// indexed from OPERATOR ID (operator number)
|
||||||
blt::expanding_buffer<std::vector<type>> argument_types;
|
blt::expanding_buffer<std::vector<type>> argument_types;
|
||||||
|
blt::expanding_buffer<argc_t> operator_argc;
|
||||||
blt::hashset_t<operator_id> static_types;
|
blt::hashset_t<operator_id> static_types;
|
||||||
std::vector<detail::callable_t> operators;
|
std::vector<detail::callable_t> operators;
|
||||||
};
|
};
|
||||||
|
@ -105,6 +136,22 @@ namespace blt::gp
|
||||||
return engine;
|
return engine;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] inline bool choice()
|
||||||
|
{
|
||||||
|
static std::uniform_int_distribution dist(0, 1);
|
||||||
|
return dist(engine);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param cutoff precent in floating point form chance of the event happening.
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
[[nodiscard]] inline bool choice(double cutoff)
|
||||||
|
{
|
||||||
|
static std::uniform_real_distribution dist(0.0, 1.0);
|
||||||
|
return dist(engine) < cutoff;
|
||||||
|
}
|
||||||
|
|
||||||
[[nodiscard]] inline type_system& get_typesystem()
|
[[nodiscard]] inline type_system& get_typesystem()
|
||||||
{
|
{
|
||||||
return system;
|
return system;
|
||||||
|
@ -137,6 +184,16 @@ namespace blt::gp
|
||||||
return non_terminals[id];
|
return non_terminals[id];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline argc_t get_argc(operator_id id)
|
||||||
|
{
|
||||||
|
return operator_argc[id];
|
||||||
|
}
|
||||||
|
|
||||||
|
inline detail::callable_t& get_operation(operator_id id)
|
||||||
|
{
|
||||||
|
return operators[id];
|
||||||
|
}
|
||||||
|
|
||||||
inline bool is_static(operator_id id)
|
inline bool is_static(operator_id id)
|
||||||
{
|
{
|
||||||
return static_types.contains(static_cast<blt::size_t>(id));
|
return static_types.contains(static_cast<blt::size_t>(id));
|
||||||
|
@ -149,6 +206,7 @@ namespace blt::gp
|
||||||
non_terminals = std::move(op.non_terminals);
|
non_terminals = std::move(op.non_terminals);
|
||||||
argument_types = std::move(op.argument_types);
|
argument_types = std::move(op.argument_types);
|
||||||
static_types = std::move(op.static_types);
|
static_types = std::move(op.static_types);
|
||||||
|
operator_argc = std::move(op.operator_argc);
|
||||||
operators = std::move(op.operators);
|
operators = std::move(op.operators);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -162,6 +220,7 @@ namespace blt::gp
|
||||||
blt::expanding_buffer<std::vector<operator_id>> non_terminals;
|
blt::expanding_buffer<std::vector<operator_id>> non_terminals;
|
||||||
// indexed from OPERATOR ID (operator number)
|
// indexed from OPERATOR ID (operator number)
|
||||||
blt::expanding_buffer<std::vector<type>> argument_types;
|
blt::expanding_buffer<std::vector<type>> argument_types;
|
||||||
|
blt::expanding_buffer<argc_t> operator_argc;
|
||||||
blt::hashset_t<operator_id> static_types;
|
blt::hashset_t<operator_id> static_types;
|
||||||
std::vector<detail::callable_t> operators;
|
std::vector<detail::callable_t> operators;
|
||||||
};
|
};
|
||||||
|
|
|
@ -22,13 +22,27 @@
|
||||||
#include <blt/gp/typesystem.h>
|
#include <blt/gp/typesystem.h>
|
||||||
#include <blt/gp/stack.h>
|
#include <blt/gp/stack.h>
|
||||||
#include <blt/gp/fwdecl.h>
|
#include <blt/gp/fwdecl.h>
|
||||||
|
#include <blt/std/types.h>
|
||||||
|
|
||||||
namespace blt::gp
|
namespace blt::gp
|
||||||
{
|
{
|
||||||
|
|
||||||
|
struct op_container_t
|
||||||
|
{
|
||||||
|
blt::gp::operator_id op_id;
|
||||||
|
blt::u16 depth;
|
||||||
|
};
|
||||||
|
|
||||||
class tree_t
|
class tree_t
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
[[nodiscard]] inline std::vector<blt::gp::operator_id>& get_operations()
|
[[nodiscard]] inline std::vector<op_container_t>& get_operations()
|
||||||
|
{
|
||||||
|
valid = false;
|
||||||
|
return operations;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] inline const std::vector<op_container_t>& get_operations() const
|
||||||
{
|
{
|
||||||
return operations;
|
return operations;
|
||||||
}
|
}
|
||||||
|
@ -37,10 +51,34 @@ namespace blt::gp
|
||||||
{
|
{
|
||||||
return values;
|
return values;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setDepth(blt::size_t d)
|
||||||
|
{
|
||||||
|
depth = d;
|
||||||
|
valid = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
blt::size_t getDepth()
|
||||||
|
{
|
||||||
|
if (valid)
|
||||||
|
return depth;
|
||||||
|
valid = true;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<blt::gp::operator_id> operations;
|
bool valid = false;
|
||||||
|
std::vector<op_container_t> operations;
|
||||||
blt::gp::stack_allocator values;
|
blt::gp::stack_allocator values;
|
||||||
|
blt::size_t depth;
|
||||||
|
};
|
||||||
|
|
||||||
|
class population_t
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<tree_t> individuals;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -28,7 +28,7 @@ namespace blt::gp
|
||||||
blt::size_t depth;
|
blt::size_t depth;
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline std::stack<stack> get_base_generator(gp_program& program)
|
inline std::stack<stack> get_initial_stack(gp_program& program)
|
||||||
{
|
{
|
||||||
std::stack<stack> tree_generator;
|
std::stack<stack> tree_generator;
|
||||||
|
|
||||||
|
@ -40,36 +40,87 @@ namespace blt::gp
|
||||||
base_type = system.select_type(program.get_random());
|
base_type = system.select_type(program.get_random());
|
||||||
} while (program.get_type_non_terminals(base_type.id()).empty());
|
} while (program.get_type_non_terminals(base_type.id()).empty());
|
||||||
|
|
||||||
tree_generator.push(stack{program.select_non_terminal(base_type.id()), 0});
|
tree_generator.push(stack{program.select_non_terminal(base_type.id()), 1});
|
||||||
|
|
||||||
return tree_generator;
|
return tree_generator;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Func>
|
template<typename Func>
|
||||||
tree_t create_tree(Func, gp_program& program, blt::size_t, blt::size_t)
|
inline tree_t create_tree(Func&& perChild, gp_program& program)
|
||||||
{
|
{
|
||||||
std::stack<stack> tree_generator = get_base_generator(program);
|
std::stack<stack> tree_generator = get_initial_stack(program);
|
||||||
|
blt::size_t max_depth = 0;
|
||||||
tree_t tree;
|
tree_t tree;
|
||||||
|
|
||||||
while (!tree_generator.empty())
|
while (!tree_generator.empty())
|
||||||
{
|
{
|
||||||
|
auto top = tree_generator.top();
|
||||||
|
tree_generator.pop();
|
||||||
|
|
||||||
|
tree.get_operations().push_back({top.id, static_cast<blt::u16>(top.depth)});
|
||||||
|
max_depth = std::max(max_depth, top.depth);
|
||||||
|
|
||||||
|
if (program.is_static(top.id))
|
||||||
|
{
|
||||||
|
program.get_operation(top.id)(nullptr, tree.get_values());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto& child : program.get_argument_types(top.id))
|
||||||
|
{
|
||||||
|
std::forward<Func>(perChild)(program, tree_generator, child, top.depth + 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tree.setDepth(max_depth);
|
||||||
|
|
||||||
return tree;
|
return tree;
|
||||||
}
|
}
|
||||||
|
|
||||||
tree_t grow_generator_t::generate(gp_program& program, blt::size_t min_depth, blt::size_t max_depth)
|
tree_t grow_generator_t::generate(gp_program& program, blt::size_t min_depth, blt::size_t max_depth)
|
||||||
{
|
{
|
||||||
return create_tree([]() {
|
return create_tree([min_depth, max_depth](gp_program& program, std::stack<stack>& tree_generator, const type& type, blt::size_t new_depth) {
|
||||||
|
if (new_depth >= max_depth)
|
||||||
}, program, min_depth, max_depth);
|
{
|
||||||
|
tree_generator.push({program.select_terminal(type.id()), new_depth});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (program.choice() || new_depth < min_depth)
|
||||||
|
tree_generator.push({program.select_non_terminal(type.id()), new_depth});
|
||||||
|
else
|
||||||
|
tree_generator.push({program.select_terminal(type.id()), new_depth});
|
||||||
|
}, program);
|
||||||
}
|
}
|
||||||
|
|
||||||
tree_t full_generator_t::generate(gp_program& program, blt::size_t min_depth, blt::size_t max_depth)
|
tree_t full_generator_t::generate(gp_program& program, blt::size_t, blt::size_t max_depth)
|
||||||
{
|
{
|
||||||
return create_tree([]() {
|
return create_tree([max_depth](gp_program& program, std::stack<stack>& tree_generator, const type& type, blt::size_t new_depth) {
|
||||||
|
if (new_depth >= max_depth)
|
||||||
}, program, min_depth, max_depth);
|
{
|
||||||
|
tree_generator.push({program.select_terminal(type.id()), new_depth});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
tree_generator.push({program.select_non_terminal(type.id()), new_depth});
|
||||||
|
}, program);
|
||||||
|
}
|
||||||
|
|
||||||
|
population_t grow_initializer_t::generate(gp_program& program, blt::size_t size, blt::size_t min_depth, blt::size_t max_depth)
|
||||||
|
{
|
||||||
|
return population_t();
|
||||||
|
}
|
||||||
|
|
||||||
|
population_t full_initializer_t::generate(gp_program& program, blt::size_t size, blt::size_t min_depth, blt::size_t max_depth)
|
||||||
|
{
|
||||||
|
return population_t();
|
||||||
|
}
|
||||||
|
|
||||||
|
population_t half_half_initializer_t::generate(gp_program& program, blt::size_t size, blt::size_t min_depth, blt::size_t max_depth)
|
||||||
|
{
|
||||||
|
return population_t();
|
||||||
|
}
|
||||||
|
|
||||||
|
population_t ramped_half_initializer_t::generate(gp_program& program, blt::size_t size, blt::size_t min_depth, blt::size_t max_depth)
|
||||||
|
{
|
||||||
|
return population_t();
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue