diff --git a/CMakeLists.txt b/CMakeLists.txt index 14f7883..c972a4f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ 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_UBSAN "Enable the ub sanitizer" OFF) diff --git a/examples/gp_test_2.cpp b/examples/gp_test_2.cpp index 4829051..894e2ad 100644 --- a/examples/gp_test_2.cpp +++ b/examples/gp_test_2.cpp @@ -31,7 +31,7 @@ blt::gp::operation_t lit([]() { return dist(program.get_random()); }); -int main_old() +int main() { type_system.register_type(); type_system.register_type(); diff --git a/examples/main.cpp b/examples/main.cpp index a330691..212a53f 100644 --- a/examples/main.cpp +++ b/examples/main.cpp @@ -326,7 +326,7 @@ namespace blt::gp::detail blt::gp::stack_allocator alloc; -int main() +int main_old() { constexpr blt::size_t MAX_ALIGNMENT = 8; test(); diff --git a/include/blt/gp/fwdecl.h b/include/blt/gp/fwdecl.h index a1afacb..90a87a7 100644 --- a/include/blt/gp/fwdecl.h +++ b/include/blt/gp/fwdecl.h @@ -29,6 +29,10 @@ namespace blt::gp class type_system; + class tree_t; + + class population_t; + class tree_generator_t; class grow_generator_t; diff --git a/include/blt/gp/generators.h b/include/blt/gp/generators.h index f20dbf2..51dcfd1 100644 --- a/include/blt/gp/generators.h +++ b/include/blt/gp/generators.h @@ -44,6 +44,36 @@ namespace blt::gp 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 diff --git a/include/blt/gp/program.h b/include/blt/gp/program.h index 80fb5c0..79d10db 100644 --- a/include/blt/gp/program.h +++ b/include/blt/gp/program.h @@ -46,18 +46,34 @@ namespace blt::gp static constexpr blt::size_t STATIC_T = 0x1; static constexpr blt::size_t TERMINAL_T = 0x2; + struct argc_t + { + blt::size_t argc = 0; + blt::size_t argc_context = 0; + }; + template class gp_operations { friend class gp_program; + friend class blt::gp::detail::operator_storage_test; public: explicit gp_operations(type_system& system): system(system) {} + template + void add_non_context_argument(blt::gp::operator_id operator_id) + { + if constexpr (!std::is_same_v>) + { + argument_types[operator_id].push_back(system.get_type()); + } + } + template - void add_operator(const operation_t& op, bool is_static = false) + gp_operations& add_operator(const operation_t& op, bool is_static = false) { auto return_type_id = system.get_type().id(); 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; operator_list[return_type_id].push_back(operator_id); - (argument_types[operator_id].push_back(system.get_type()), ...); + if constexpr (sizeof...(Args) > 0) + { + (add_non_context_argument(), ...); + } + + argc_t argc; + argc.argc_context = argc.argc = sizeof...(Args); + + ((std::is_same_v, 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()); if (is_static) static_types.insert(operator_id); + return *this; } private: @@ -79,6 +109,7 @@ namespace blt::gp blt::expanding_buffer> non_terminals; // indexed from OPERATOR ID (operator number) blt::expanding_buffer> argument_types; + blt::expanding_buffer operator_argc; blt::hashset_t static_types; std::vector operators; }; @@ -105,6 +136,22 @@ namespace blt::gp 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() { return system; @@ -137,6 +184,16 @@ namespace blt::gp 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) { return static_types.contains(static_cast(id)); @@ -149,6 +206,7 @@ namespace blt::gp non_terminals = std::move(op.non_terminals); argument_types = std::move(op.argument_types); static_types = std::move(op.static_types); + operator_argc = std::move(op.operator_argc); operators = std::move(op.operators); } @@ -162,6 +220,7 @@ namespace blt::gp blt::expanding_buffer> non_terminals; // indexed from OPERATOR ID (operator number) blt::expanding_buffer> argument_types; + blt::expanding_buffer operator_argc; blt::hashset_t static_types; std::vector operators; }; diff --git a/include/blt/gp/tree.h b/include/blt/gp/tree.h index 6859f19..ff53c9e 100644 --- a/include/blt/gp/tree.h +++ b/include/blt/gp/tree.h @@ -22,13 +22,27 @@ #include #include #include +#include namespace blt::gp { + + struct op_container_t + { + blt::gp::operator_id op_id; + blt::u16 depth; + }; + class tree_t { public: - [[nodiscard]] inline std::vector& get_operations() + [[nodiscard]] inline std::vector& get_operations() + { + valid = false; + return operations; + } + + [[nodiscard]] inline const std::vector& get_operations() const { return operations; } @@ -37,10 +51,34 @@ namespace blt::gp { 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: - std::vector operations; + bool valid = false; + std::vector operations; blt::gp::stack_allocator values; + blt::size_t depth; + }; + + class population_t + { + public: + + private: + std::vector individuals; }; } diff --git a/src/generators.cpp b/src/generators.cpp index 5e63cda..c1e971b 100644 --- a/src/generators.cpp +++ b/src/generators.cpp @@ -28,7 +28,7 @@ namespace blt::gp blt::size_t depth; }; - static inline std::stack get_base_generator(gp_program& program) + inline std::stack get_initial_stack(gp_program& program) { std::stack tree_generator; @@ -40,36 +40,87 @@ namespace blt::gp base_type = system.select_type(program.get_random()); } 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; } template - 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 tree_generator = get_base_generator(program); + std::stack tree_generator = get_initial_stack(program); + blt::size_t max_depth = 0; tree_t tree; while (!tree_generator.empty()) { - + auto top = tree_generator.top(); + tree_generator.pop(); + + tree.get_operations().push_back({top.id, static_cast(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(perChild)(program, tree_generator, child, top.depth + 1); + } } + tree.setDepth(max_depth); + return tree; } tree_t grow_generator_t::generate(gp_program& program, blt::size_t min_depth, blt::size_t max_depth) { - return create_tree([]() { - - }, program, min_depth, max_depth); + return create_tree([min_depth, max_depth](gp_program& program, std::stack& tree_generator, const type& type, blt::size_t new_depth) { + if (new_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([]() { - - }, program, min_depth, max_depth); + return create_tree([max_depth](gp_program& program, std::stack& tree_generator, const type& type, blt::size_t new_depth) { + if (new_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(); } } \ No newline at end of file