diff --git a/CMakeLists.txt b/CMakeLists.txt index 11d97b0..49b8680 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 3.25) -project(blt-gp VERSION 0.0.20) +project(blt-gp VERSION 0.0.21) option(ENABLE_ADDRSAN "Enable the address sanitizer" OFF) option(ENABLE_UBSAN "Enable the ub sanitizer" OFF) diff --git a/examples/main.cpp b/examples/main.cpp index 097733c..e62ae4e 100644 --- a/examples/main.cpp +++ b/examples/main.cpp @@ -24,252 +24,252 @@ #include //// small scale -//enum class op -//{ -// ADD, -// SUB, -// MUL, -// DIV, -// LIT -//}; -// -//std::string to_string(op o) -//{ -// switch (o) -// { -// case op::ADD: -// return "ADD"; -// case op::SUB: -// return "SUB"; -// case op::MUL: -// return "MUL"; -// case op::DIV: -// return "DIV"; -// case op::LIT: -// return "LIT"; -// } -// return ""; -//} -// -//constexpr static long SEED = 41912; -// -//op generate_op() -//{ -// static std::mt19937_64 engine(SEED); -// static std::uniform_int_distribution dist(0, static_cast(op::LIT) - 1); -// return static_cast(dist(engine)); -//} -// -//bool choice() -//{ -// static std::mt19937_64 engine(SEED); -// static std::uniform_int_distribution dist(0, 1); -// return dist(engine); -//} -// -//float random_value() -//{ -// static std::mt19937_64 engine(SEED); -// static std::uniform_real_distribution dist(0.0f, 10.0f); -// return dist(engine); -//} -// -//void test() -//{ -// std::vector operations; -// std::vector values; -// -// std::stack tree_generator; -// tree_generator.push(generate_op()); -// -// while (!tree_generator.empty()) -// { -// auto opn = tree_generator.top(); -// tree_generator.pop(); -// -// operations.push_back(opn); -// if (opn == op::LIT) -// { -// values.push_back(random_value()); -// continue; -// } -// -// // child 1 -// if (choice()) -// tree_generator.push(generate_op()); -// else -// tree_generator.push(op::LIT); -// -// // child 2 -// if (choice()) -// tree_generator.push(generate_op()); -// else -// tree_generator.push(op::LIT); -// } -// -// for (const auto& v : operations) -// std::cout << to_string(v) << " "; -// std::cout << std::endl; -// -// { -// std::stack process; -// for (const auto& v : operations) -// { -// switch (v) -// { -// case op::ADD: -// case op::SUB: -// case op::MUL: -// case op::DIV: -// process.emplace(2); -// std::cout << "("; -// break; -// case op::LIT: -// break; -// } -// std::cout << to_string(v); -// while (!process.empty()) -// { -// auto top = process.top(); -// process.pop(); -// if (top == 0) -// { -// std::cout << ")"; -// continue; -// } else -// { -// std::cout << " "; -// process.push(top - 1); -// break; -// } -// } -// } -// while (!process.empty()) -// { -// auto top = process.top(); -// process.pop(); -// if (top == 0) -// { -// std::cout << ") "; -// continue; -// } else -// { -// std::cerr << "FUCK YOU\n"; -// break; -// } -// } -// std::cout << std::endl; -// } -// -// for (const auto& v : values) -// std::cout << v << " "; -// std::cout << std::endl; -// -// { -// std::stack process; -// blt::size_t index = 0; -// for (const auto& v : operations) -// { -// switch (v) -// { -// case op::ADD: -// case op::SUB: -// case op::MUL: -// case op::DIV: -// process.emplace(2); -// std::cout << "("; -// std::cout << to_string(v); -// break; -// case op::LIT: -// std::cout << values[index++]; -// break; -// } -// -// while (!process.empty()) -// { -// auto top = process.top(); -// process.pop(); -// if (top == 0) -// { -// std::cout << ")"; -// continue; -// } else -// { -// std::cout << " "; -// process.push(top - 1); -// break; -// } -// } -// } -// while (!process.empty()) -// { -// auto top = process.top(); -// process.pop(); -// if (top == 0) -// { -// std::cout << ") "; -// continue; -// } else -// { -// std::cerr << "FUCK YOU\n"; -// break; -// } -// } -// std::cout << std::endl; -// } -// -// std::stack process; -// std::stack operators; -// -// for (const auto& v : operations) -// operators.push(v); -// -// while (!operators.empty()) -// { -// auto oper = operators.top(); -// operators.pop(); -// if (oper == op::LIT) -// { -// process.push(values.back()); -// values.pop_back(); -// } else -// { -// auto v1 = process.top(); -// process.pop(); -// auto v2 = process.top(); -// process.pop(); -// std::cout << "processing oper " << to_string(oper) << " with values " << v1 << " " << v2 << std::endl; -// switch (oper) -// { -// case op::ADD: -// values.push_back(v1 + v2); -// operators.push(op::LIT); -// break; -// case op::SUB: -// values.push_back(v1 - v2); -// operators.push(op::LIT); -// break; -// case op::MUL: -// values.push_back(v1 * v2); -// operators.push(op::LIT); -// break; -// case op::DIV: -// if (v2 == 0) -// v2 = 1; -// values.push_back(v1 / v2); -// operators.push(op::LIT); -// break; -// case op::LIT: -// break; -// } -// std::cout << "\tresult: " << values.back() << std::endl; -// } -// } -// -// std::cout << process.size() << std::endl; -// std::cout << process.top() << std::endl; -// -//} +enum class op +{ + ADD, + SUB, + MUL, + DIV, + LIT +}; + +std::string to_string(op o) +{ + switch (o) + { + case op::ADD: + return "ADD"; + case op::SUB: + return "SUB"; + case op::MUL: + return "MUL"; + case op::DIV: + return "DIV"; + case op::LIT: + return "LIT"; + } + return ""; +} + +constexpr static long SEED = 41912; + +op generate_op() +{ + static std::mt19937_64 engine(SEED); + static std::uniform_int_distribution dist(0, static_cast(op::LIT) - 1); + return static_cast(dist(engine)); +} + +bool choice() +{ + static std::mt19937_64 engine(SEED); + static std::uniform_int_distribution dist(0, 1); + return dist(engine); +} + +float random_value() +{ + static std::mt19937_64 engine(SEED); + static std::uniform_real_distribution dist(0.0f, 10.0f); + return dist(engine); +} + +void test() +{ + std::vector operations; + std::vector values; + + std::stack tree_generator; + tree_generator.push(generate_op()); + + while (!tree_generator.empty()) + { + auto opn = tree_generator.top(); + tree_generator.pop(); + + operations.push_back(opn); + if (opn == op::LIT) + { + values.push_back(random_value()); + continue; + } + + // child 1 + if (choice()) + tree_generator.push(generate_op()); + else + tree_generator.push(op::LIT); + + // child 2 + if (choice()) + tree_generator.push(generate_op()); + else + tree_generator.push(op::LIT); + } + + for (const auto& v : operations) + std::cout << to_string(v) << " "; + std::cout << std::endl; + + { + std::stack process; + for (const auto& v : operations) + { + switch (v) + { + case op::ADD: + case op::SUB: + case op::MUL: + case op::DIV: + process.emplace(2); + std::cout << "("; + break; + case op::LIT: + break; + } + std::cout << to_string(v); + while (!process.empty()) + { + auto top = process.top(); + process.pop(); + if (top == 0) + { + std::cout << ")"; + continue; + } else + { + std::cout << " "; + process.push(top - 1); + break; + } + } + } + while (!process.empty()) + { + auto top = process.top(); + process.pop(); + if (top == 0) + { + std::cout << ") "; + continue; + } else + { + std::cerr << "FUCK YOU\n"; + break; + } + } + std::cout << std::endl; + } + + for (const auto& v : values) + std::cout << v << " "; + std::cout << std::endl; + + { + std::stack process; + blt::size_t index = 0; + for (const auto& v : operations) + { + switch (v) + { + case op::ADD: + case op::SUB: + case op::MUL: + case op::DIV: + process.emplace(2); + std::cout << "("; + std::cout << to_string(v); + break; + case op::LIT: + std::cout << values[index++]; + break; + } + + while (!process.empty()) + { + auto top = process.top(); + process.pop(); + if (top == 0) + { + std::cout << ")"; + continue; + } else + { + std::cout << " "; + process.push(top - 1); + break; + } + } + } + while (!process.empty()) + { + auto top = process.top(); + process.pop(); + if (top == 0) + { + std::cout << ") "; + continue; + } else + { + std::cerr << "FUCK YOU\n"; + break; + } + } + std::cout << std::endl; + } + + std::stack process; + std::stack operators; + + for (const auto& v : operations) + operators.push(v); + + while (!operators.empty()) + { + auto oper = operators.top(); + operators.pop(); + if (oper == op::LIT) + { + process.push(values.back()); + values.pop_back(); + } else + { + auto v1 = process.top(); + process.pop(); + auto v2 = process.top(); + process.pop(); + std::cout << "processing oper " << to_string(oper) << " with values " << v1 << " " << v2 << std::endl; + switch (oper) + { + case op::ADD: + values.push_back(v1 + v2); + operators.push(op::LIT); + break; + case op::SUB: + values.push_back(v1 - v2); + operators.push(op::LIT); + break; + case op::MUL: + values.push_back(v1 * v2); + operators.push(op::LIT); + break; + case op::DIV: + if (v2 == 0) + v2 = 1; + values.push_back(v1 / v2); + operators.push(op::LIT); + break; + case op::LIT: + break; + } + std::cout << "\tresult: " << values.back() << std::endl; + } + } + + std::cout << process.size() << std::endl; + std::cout << process.top() << std::endl; + +} // //struct silly //{ @@ -368,12 +368,12 @@ int main() alloc.push(120); alloc.push(true); - blt::gp::operation silly_op(nyah); - blt::gp::operation silly_op_2([](float f, float g) { + blt::gp::operation_t silly_op(nyah); + blt::gp::operation_t silly_op_2([](float f, float g) { return f + g; }); - std::cout << silly_op_2(alloc) << std::endl; + std::cout << silly_op(alloc) << std::endl; std::cout << "Is empty? " << alloc.empty() << std::endl; diff --git a/include/blt/gp/fwdecl.h b/include/blt/gp/fwdecl.h index 93effe3..e452ac8 100644 --- a/include/blt/gp/fwdecl.h +++ b/include/blt/gp/fwdecl.h @@ -21,7 +21,7 @@ namespace blt::gp { - class identifier; + } #endif //BLT_GP_FWDECL_H diff --git a/include/blt/gp/program.h b/include/blt/gp/program.h index 218b079..ae3a3ec 100644 --- a/include/blt/gp/program.h +++ b/include/blt/gp/program.h @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -34,9 +35,6 @@ namespace blt::gp { - class identifier - { - }; class type { @@ -79,33 +77,39 @@ namespace blt::gp template inline type register_type() { - types.push_back(type::make_type(types.size())); - return types.back(); + types[blt::type_string_raw()](type::make_type(types.size())); + return types[blt::type_string_raw()]; + } + + template + inline type get_type() + { + return types[blt::type_string_raw()]; } private: - std::vector types; + blt::hashmap_t types; }; template - class operation; + class operation_t; template - class operation + class operation_t { public: using function_t = std::function; - constexpr operation(const operation& copy) = default; + constexpr operation_t(const operation_t& copy) = default; - constexpr operation(operation&& move) = default; + constexpr operation_t(operation_t&& move) = default; template - constexpr explicit operation(const Functor& functor): func(functor) + constexpr explicit operation_t(const Functor& functor): func(functor) {} template - [[nodiscard]] inline constexpr blt::size_t getByteOffset() const + [[nodiscard]] inline constexpr static blt::size_t getByteOffset() { blt::size_t offset = 0; blt::size_t current_index = 0; @@ -114,7 +118,7 @@ namespace blt::gp } template - inline constexpr Return sequence_to_indices(stack_allocator& allocator, std::integer_sequence) const + inline constexpr Return exec_sequence_to_indices(stack_allocator& allocator, std::integer_sequence) const { // expands Args and indices, providing each argument with its index calculating the current argument byte offset return func(allocator.from(getByteOffset())...); @@ -123,29 +127,30 @@ namespace blt::gp [[nodiscard]] constexpr inline Return operator()(stack_allocator& allocator) const { constexpr auto seq = std::make_integer_sequence(); - Return ret = sequence_to_indices(allocator, seq); + Return ret = exec_sequence_to_indices(allocator, seq); + allocator.call_destructors(); allocator.pop_bytes((stack_allocator::aligned_size() + ...)); return ret; } + + [[nodiscard]] std::function make_callable() const + { + return [this](stack_allocator& values) { + values.push(this->operator()(values)); + }; + } + + [[nodiscard]] blt::size_t get_argc() const + { + return sizeof...(Args); + } private: -// template -// static inline T& access_pack_index(blt::span args) -// { -// return *reinterpret_cast(args[index]); -// } -// -// template -// Return function_evaluator(blt::span args, std::integer_sequence) -// { -// return func(access_pack_index(args)...); -// } - function_t func; }; template - operation(Return (*)(Args...)) -> operation; + operation_t(Return (*)(Args...)) -> operation_t; // // template // operation(std::function) -> operation; @@ -153,6 +158,37 @@ namespace blt::gp // template // operation(std::function) -> operation; + class gp_program + { + public: + explicit gp_program(type_system system): system(std::move(system)) + {} + + template + void add_operator(const operation_t& op) + { + if (op.get_argc() == 0) + terminals.push_back(operators.size()); + else + non_terminals.push_back(operators.size()); + + operators.push_back(op.make_callable()); + + std::vector types; + (types.push_back(system.get_type()), ...); + arg_types.push_back(std::move(types)); + + return_types.push_back(system.get_type()); + } + + private: + type_system system; + std::vector> operators; + std::vector terminals; + std::vector non_terminals; + std::vector return_types; + std::vector> arg_types; + }; } diff --git a/include/blt/gp/stack.h b/include/blt/gp/stack.h index f899548..1b216f9 100644 --- a/include/blt/gp/stack.h +++ b/include/blt/gp/stack.h @@ -112,6 +112,13 @@ namespace blt::gp } } + template + void call_destructors() + { + blt::size_t offset = 0; + ((from(offset).~Args(), offset += stack_allocator::aligned_size()), ...); + } + [[nodiscard]] bool empty() const { if (head == nullptr) diff --git a/lib/blt b/lib/blt index 8d3bfbc..2266d64 160000 --- a/lib/blt +++ b/lib/blt @@ -1 +1 @@ -Subproject commit 8d3bfbcdc36fb769257ae58c0374ef44253e0a34 +Subproject commit 2266d64f042bc97b54e7e50dcaac730bcc3ab4c3