diff --git a/CMakeLists.txt b/CMakeLists.txt index f3941d3..84709f5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 3.25) -project(blt-gp VERSION 0.0.26) +project(blt-gp VERSION 0.0.27) 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 55c1eb3..5c64961 100644 --- a/examples/gp_test_2.cpp +++ b/examples/gp_test_2.cpp @@ -37,9 +37,11 @@ int main() type_system.register_type(); type_system.register_type(); - type_system.add_operator(add); - type_system.add_operator(sub); - type_system.add_operator(mul); - type_system.add_operator(pro_div); - type_system.add_operator(lit); + program.add_operator(add); + program.add_operator(sub); + program.add_operator(mul); + program.add_operator(pro_div); + program.add_operator(lit, true); + + return 0; } \ No newline at end of file diff --git a/examples/main.cpp b/examples/main.cpp index 10b3db5..7b67789 100644 --- a/examples/main.cpp +++ b/examples/main.cpp @@ -219,6 +219,7 @@ void test() std::cout << std::endl; } + // run the tree std::stack process; std::stack operators; @@ -398,4 +399,6 @@ int main_old() std::cout << silly_op.operator()(alloc) << std::endl; std::cout << "Hello World!" << std::endl; + + return 0; } \ No newline at end of file diff --git a/include/blt/gp/operations.h b/include/blt/gp/operations.h index c2a9556..51fe5ac 100644 --- a/include/blt/gp/operations.h +++ b/include/blt/gp/operations.h @@ -26,7 +26,7 @@ namespace blt::gp { - template + template class operation_t; template diff --git a/include/blt/gp/program.h b/include/blt/gp/program.h index b56e4d6..2f9da23 100644 --- a/include/blt/gp/program.h +++ b/include/blt/gp/program.h @@ -42,28 +42,96 @@ namespace blt::gp { + static constexpr blt::size_t NONE_T = 0x0; + static constexpr blt::size_t STATIC_T = 0x1; + static constexpr blt::size_t TERMINAL_T = 0x2; + class gp_program { public: - explicit gp_program(type_system& system, std::mt19937_64 engine): system(system), engine(engine) + /** + * Note about context size: This is required as context is passed to every operator in the GP tree, this context will be provided by your + * call to one of the evaluator functions. This was the nicest way to provide this as C++ lacks reflection + * + * @param system type system to use in tree generation + * @param engine random engine to use throughout the program. TODO replace this with something better + * @param context_size number of arguments which are always present as "context" to the GP system / operators + */ + explicit gp_program(type_system& system, std::mt19937_64 engine): + system(system), engine(engine) {} + void generate_tree(); + + [[nodiscard]] inline std::mt19937_64& get_random() + { + return engine; + } + [[nodiscard]] inline type_system& get_typesystem() { return system; } - void generate_tree(); - - inline std::mt19937_64& get_random() + inline operator_id select_terminal(type_id id) { - return engine; + std::uniform_int_distribution dist(0, terminals[id].size() - 1); + return terminals[id][dist(engine)]; + } + + inline operator_id select_non_terminal(type_id id) + { + std::uniform_int_distribution dist(0, non_terminals[id].size() - 1); + return non_terminals[id][dist(engine)]; + } + + inline std::vector& get_argument_types(operator_id id) + { + return argument_types[id]; + } + + inline std::vector& get_type_terminals(type_id id) + { + return terminals[id]; + } + + inline std::vector& get_type_non_terminals(type_id id) + { + return non_terminals[id]; + } + + inline bool is_static(operator_id id) + { + return static_types.contains(static_cast(id)); + } + + template + void 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()); + + 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()), ...); + operators.push_back(op.make_callable()); + if (is_static) + static_types.insert(operator_id); } private: type_system& system; blt::gp::stack_allocator alloc; std::mt19937_64 engine; + + // indexed from return TYPE ID, returns index of operator + blt::expanding_buffer> terminals; + blt::expanding_buffer> non_terminals; + // indexed from OPERATOR ID (operator number) + blt::expanding_buffer> argument_types; + blt::hashset_t static_types; + std::vector> operators; }; } diff --git a/include/blt/gp/typesystem.h b/include/blt/gp/typesystem.h index 1be619f..84cc22e 100644 --- a/include/blt/gp/typesystem.h +++ b/include/blt/gp/typesystem.h @@ -112,55 +112,28 @@ namespace blt::gp itr = itr++; return itr->second; } - - inline operator_id select_terminal(std::mt19937_64& engine, type_id id) - { - std::uniform_int_distribution dist(0, terminals[id].size() - 1); - return terminals[id][dist(engine)]; - } - - inline operator_id select_non_terminal(std::mt19937_64& engine, type_id id) - { - std::uniform_int_distribution dist(0, non_terminals[id].size() - 1); - return non_terminals[id][dist(engine)]; - } - - inline std::vector& get_argument_types(operator_id id) - { - return argument_types[id]; - } - - inline std::vector& get_type_terminals(type_id id) - { - return terminals[id]; - } - - inline std::vector& get_type_non_terminals(type_id id) - { - return non_terminals[id]; - } - - template - void add_operator(const operation_t& op) - { - auto return_type_id = get_type().id(); - auto& operator_list = op.get_argc() == 0 ? terminals : non_terminals; - operator_list[return_type_id].push_back(operators.size()); - - auto operator_index = operators.size(); - (argument_types[operator_index].push_back(get_type()), ...); - operators.push_back(op.make_callable()); - } private: blt::hashmap_t types; - // indexed from return TYPE ID, returns index of operator - blt::expanding_buffer> terminals; - blt::expanding_buffer> non_terminals; - // indexed from OPERATOR ID (operator number) - blt::expanding_buffer> argument_types; - std::vector> operators; }; } +template<> +struct std::hash +{ + std::size_t operator()(const blt::gp::operator_id& s) const noexcept + { + return std::hash{}(s); + } +}; + +template<> +struct std::hash +{ + std::size_t operator()(const blt::gp::type_id& s) const noexcept + { + return std::hash{}(s); + } +}; + #endif //BLT_GP_TYPESYSTEM_H diff --git a/lib/blt b/lib/blt index 1ca46b9..cc788e9 160000 --- a/lib/blt +++ b/lib/blt @@ -1 +1 @@ -Subproject commit 1ca46b9d7bb9621a2f7d02a9ca1eff99e91e3f1a +Subproject commit cc788e98f4a739f450f487f6a7c758990128a698 diff --git a/src/generators.cpp b/src/generators.cpp index 9bbc46d..53d5ffc 100644 --- a/src/generators.cpp +++ b/src/generators.cpp @@ -38,9 +38,9 @@ namespace blt::gp do { base_type = system.select_type(program.get_random()); - } while (system.get_type_non_terminals(base_type.id()).empty()); + } while (program.get_type_non_terminals(base_type.id()).empty()); - tree_generator.emplace(system.select_non_terminal(program.get_random(), base_type.id()), 0); + tree_generator.emplace(program.select_non_terminal(base_type.id()), 0); return tree_generator; }