diff --git a/CMakeLists.txt b/CMakeLists.txt index 1a0d7fb..e862ccb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -27,7 +27,7 @@ macro(compile_options target_name) sanitizers(${target_name}) endmacro() -project(blt-gp VERSION 0.3.15) +project(blt-gp VERSION 0.3.16) include(CTest) diff --git a/examples/symbolic_regression.h b/examples/symbolic_regression.h index 3e2a9f1..bff2ae1 100644 --- a/examples/symbolic_regression.h +++ b/examples/symbolic_regression.h @@ -164,7 +164,7 @@ namespace blt::gp::example { auto& i = i_ref.get(); BLT_DEBUG("Fitness: %lf, stand: %lf, raw: %lf", i.fitness.adjusted_fitness, i.fitness.standardized_fitness, i.fitness.raw_fitness); - i.tree.print(program, std::cout); + i.tree.print(std::cout); std::cout << "\n"; } diff --git a/include/blt/gp/tree.h b/include/blt/gp/tree.h index 8a38ca3..54c5b6d 100644 --- a/include/blt/gp/tree.h +++ b/include/blt/gp/tree.h @@ -27,9 +27,6 @@ #include #include -#include -#include -#include namespace blt::gp { @@ -182,7 +179,9 @@ namespace blt::gp type_id type; }; - explicit tree_t(gp_program& program); + explicit tree_t(gp_program& program): m_program(&program) + { + } tree_t(const tree_t& copy): m_program(copy.m_program) { @@ -216,27 +215,45 @@ namespace blt::gp for (; op_it != operations.end(); ++op_it) { - if (op_it->has_ephemeral_drop()) + if (op_it->get_flags().is_ephemeral()) { + if (op_it->has_ephemeral_drop()) + { + } } if (copy_it == copy.operations.end()) break; *op_it = *copy_it; - if (copy_it->has_ephemeral_drop()) + if (op_it->get_flags().is_ephemeral()) { + if (copy_it->has_ephemeral_drop()) + { + } } ++copy_it; } const auto op_it_cpy = op_it; for (; op_it != operations.end(); ++op_it) { - if (op_it->has_ephemeral_drop()) + if (op_it->get_flags().is_ephemeral()) { + if (op_it->has_ephemeral_drop()) + { + } } } operations.erase(op_it_cpy, operations.end()); for (; copy_it != copy.operations.end(); ++copy_it) + { + if (copy_it->get_flags().is_ephemeral()) + { + if (copy_it->has_ephemeral_drop()) + { + + } + } operations.emplace_back(*copy_it); + } values.reserve(copy.values.stored()); values.reset(); @@ -284,16 +301,40 @@ namespace blt::gp size_t get_depth(gp_program& program) const; - subtree_point_t select_subtree(double terminal_chance = 0.1) const; - std::optional select_subtree(type_id type, u32 max_tries = 5, double terminal_chance = 0.1) const; - subtree_point_t select_subtree_traverse(double terminal_chance = 0.1, double depth_multiplier = 0.6) const; - std::optional select_subtree_traverse(type_id type, u32 max_tries = 5, double terminal_chance = 0.1, - double depth_multiplier = 0.6) const; + /** + * Selects a random index inside this tree's operations stack + * @param terminal_chance if we select a terminal this is the chance we will actually pick it, otherwise continue the loop. + */ + [[nodiscard]] subtree_point_t select_subtree(double terminal_chance = 0.1) const; + /** + * Selects a random index inside the tree's operations stack, with a limit on the max number of times we will attempt to select this point. + * @param type type to find + * @param max_tries maximum number of times we are allowed to select a tree without finding a corresponding type. + * @param terminal_chance if we select a terminal this is the chance that we will actually pick it + */ + [[nodiscard]] std::optional select_subtree(type_id type, u32 max_tries = 5, double terminal_chance = 0.1) const; + /** + * Select an index by traversing through the tree structure + * @param terminal_chance if we select a terminal this is the chance that we will actually pick it. + * @param depth_multiplier this controls how the depth contributes to the chance to exit. + * By default, a depth of 3.5 will have a 50% chance of returning the current index. + */ + [[nodiscard]] subtree_point_t select_subtree_traverse(double terminal_chance = 0.1, double depth_multiplier = 0.6) const; + /** + * SSelect an index by traversing through the tree structure, with a limit on the max number of times we will attempt to select this point. + * @param type type to find + * @param max_tries maximum number of times we are allowed to select a tree without finding a corresponding type. + * @param terminal_chance if we select a terminal this is the chance that we will actually pick it + * @param depth_multiplier this controls how the depth contributes to the chance to exit. + * By default, a depth of 3.5 will have a 50% chance of returning the current index. + */ + [[nodiscard]] std::optional select_subtree_traverse(type_id type, u32 max_tries = 5, double terminal_chance = 0.1, + double depth_multiplier = 0.6) const; /** - * User function for evaluating this tree using a context reference. This function should only be used if the tree is expecting the context value - * This function returns a copy of your value, if it is too large for the stack, or you otherwise need a reference, please use the corresponding - * get_evaluation_ref function! + * User function for evaluating this tree using a context reference. This function should only be used if the tree is expecting the context value + * This function returns a copy of your value, if it is too large for the stack, or you otherwise need a reference, please use the corresponding + * get_evaluation_ref function! */ template T get_evaluation_value(const Context& context) const @@ -350,10 +391,10 @@ namespace blt::gp return evaluation_ref{val, ctx}; } - void print(gp_program& program, std::ostream& output, bool print_literals = true, bool pretty_indent = false, + void print(std::ostream& output, bool print_literals = true, bool pretty_indent = false, bool include_types = false) const; - bool check(gp_program& program, void* context) const; + bool check(void* context) const; void find_child_extends(tracked_vector& vec, blt::size_t parent_node, blt::size_t argc) const; diff --git a/lib/blt b/lib/blt index 4c462df..2e6abb8 160000 --- a/lib/blt +++ b/lib/blt @@ -1 +1 @@ -Subproject commit 4c462dff38a982bc5dc5212337af160bc018cce1 +Subproject commit 2e6abb8013a622771330c17f0d938db5f672f12b diff --git a/src/transformers.cpp b/src/transformers.cpp index cdfd4d9..b97a276 100644 --- a/src/transformers.cpp +++ b/src/transformers.cpp @@ -146,7 +146,7 @@ namespace blt::gp break; default: #if BLT_DEBUG_LEVEL > 0 - BLT_ABORT("This place should be unreachable!"); + BLT_ABORT("This place should be unreachable!"); #else BLT_UNREACHABLE; #endif @@ -156,13 +156,15 @@ namespace blt::gp blt::size_t c1_found_bytes = c1.get_values().size().total_used_bytes; blt::size_t c2_found_bytes = c2.get_values().size().total_used_bytes; blt::size_t c1_expected_bytes = std::accumulate(c1.get_operations().begin(), c1.get_operations().end(), 0ul, - [](const auto& v1, const auto& v2) { + [](const auto& v1, const auto& v2) + { if (v2.is_value()) return v1 + v2.type_size(); return v1; }); blt::size_t c2_expected_bytes = std::accumulate(c2.get_operations().begin(), c2.get_operations().end(), 0ul, - [](const auto& v1, const auto& v2) { + [](const auto& v1, const auto& v2) + { if (v2.is_value()) return v1 + v2.type_size(); return v1; @@ -331,48 +333,50 @@ namespace blt::gp // this will check to make sure that the tree is in a correct and executable state. it requires that the evaluation is context free! #if BLT_DEBUG_LEVEL >= 2 // BLT_ASSERT(new_vals_r.empty()); - //BLT_ASSERT(stack_after.empty()); - blt::size_t bytes_expected = 0; - auto bytes_size = vals_r.size().total_used_bytes; + //BLT_ASSERT(stack_after.empty()); + blt::size_t bytes_expected = 0; + auto bytes_size = vals_r.size().total_used_bytes; - for (const auto& op : c.get_operations()) - { - if (op.is_value()) - bytes_expected += op.type_size(); - } + for (const auto& op : c.get_operations()) + { + if (op.is_value()) + bytes_expected += op.type_size(); + } - if (bytes_expected != bytes_size) - { - BLT_WARN_STREAM << "Stack state: " << vals_r.size() << "\n"; - BLT_WARN("Child tree bytes %ld vs expected %ld, difference: %ld", bytes_size, bytes_expected, - static_cast(bytes_expected) - static_cast(bytes_size)); - BLT_TRACE("Total bytes after: %ld", total_bytes_after); - BLT_ABORT("Amount of bytes in stack doesn't match the number of bytes expected for the operations"); - } - auto copy = c; - try - { - if (!copy.check(program, detail::debug::context_ptr)) - throw std::runtime_error("Tree check failed"); - // TODO a work around for the whole needing to access a now private function - // const auto& result = copy.evaluate(*static_cast(detail::debug::context_ptr)); - // blt::black_box(result); - } catch (...) - { - std::cout << "This occurred at point " << begin_point << " ending at (old) " << end_point << "\n"; - std::cout << "our root type is " << ops_r[begin_point].id() << " with size " << ops_r[begin_point].type_size() - << "\n"; - std::cout << "now Named: " << (program.get_name(ops_r[begin_point].id()) ? *program.get_name(ops_r[begin_point].id()) : "Unnamed") << "\n"; - std::cout << "Was named: " << (program.get_name(begin_operator_id) ? *program.get_name(begin_operator_id) : "Unnamed") << "\n"; - //std::cout << "Parent:" << std::endl; - //p.print(program, std::cout, false, true); - std::cout << "Child:" << std::endl; - c.print(program, std::cout, false, true); - std::cout << std::endl; - c.print(program, std::cout, true, true); - std::cout << std::endl; - throw std::exception(); - } + if (bytes_expected != bytes_size) + { + BLT_WARN_STREAM << "Stack state: " << vals_r.size() << "\n"; + BLT_WARN("Child tree bytes %ld vs expected %ld, difference: %ld", bytes_size, bytes_expected, + static_cast(bytes_expected) - static_cast(bytes_size)); + BLT_TRACE("Total bytes after: %ld", total_bytes_after); + BLT_ABORT("Amount of bytes in stack doesn't match the number of bytes expected for the operations"); + } + auto copy = c; + try + { + if (!copy.check(detail::debug::context_ptr)) + throw std::runtime_error("Tree check failed"); + // TODO a work around for the whole needing to access a now private function + // const auto& result = copy.evaluate(*static_cast(detail::debug::context_ptr)); + // blt::black_box(result); + } + catch (...) + { + std::cout << "This occurred at point " << begin_point << " ending at (old) " << end_point << "\n"; + std::cout << "our root type is " << ops_r[begin_point].id() << " with size " << ops_r[begin_point].type_size() + << "\n"; + std::cout << "now Named: " << (program.get_name(ops_r[begin_point].id()) ? *program.get_name(ops_r[begin_point].id()) : "Unnamed") << + "\n"; + std::cout << "Was named: " << (program.get_name(begin_operator_id) ? *program.get_name(begin_operator_id) : "Unnamed") << "\n"; + //std::cout << "Parent:" << std::endl; + //p.print(program, std::cout, false, true); + std::cout << "Child:" << std::endl; + c.print(std::cout, false, true); + std::cout << std::endl; + c.print(std::cout, true, true); + std::cout << std::endl; + throw std::exception(); + } #endif return begin_point + new_ops_r.size(); } @@ -485,7 +489,8 @@ namespace blt::gp blt::size_t found_bytes = vals.size().total_used_bytes; blt::size_t expected_bytes = std::accumulate(ops.begin(), ops.end(), 0ul, - [](const auto& v1, const auto& v2) { + [](const auto& v1, const auto& v2) + { if (v2.is_value()) return v1 + v2.type_size(); return v1; @@ -550,12 +555,12 @@ namespace blt::gp }; } #if BLT_DEBUG_LEVEL >= 2 - if (!c.check(program, detail::debug::context_ptr)) + if (!c.check(detail::debug::context_ptr)) { std::cout << "Parent: " << std::endl; - c_copy.print(program, std::cout, false, true); + c_copy.print(std::cout, false, true); std::cout << "Child Values:" << std::endl; - c.print(program, std::cout, true, true); + c.print(std::cout, true, true); std::cout << std::endl; BLT_ABORT("Tree Check Failed."); } @@ -647,14 +652,14 @@ namespace blt::gp }); #if BLT_DEBUG_LEVEL >= 2 - if (!c.check(program, detail::debug::context_ptr)) + if (!c.check(detail::debug::context_ptr)) { std::cout << "Parent: " << std::endl; - p.print(program, std::cout, false, true); + p.print(std::cout, false, true); std::cout << "Child:" << std::endl; - c.print(program, std::cout, false, true); + c.print(std::cout, false, true); std::cout << "Child Values:" << std::endl; - c.print(program, std::cout, true, true); + c.print(std::cout, true, true); std::cout << std::endl; BLT_ABORT("Tree Check Failed."); } @@ -710,12 +715,12 @@ namespace blt::gp vals.copy_from(storage_ptr, for_bytes + after_bytes); #if BLT_DEBUG_LEVEL >= 2 - if (!c.check(program, detail::debug::context_ptr)) + if (!c.check(detail::debug::context_ptr)) { std::cout << "Parent: " << std::endl; - p.print(program, std::cout, false, true); + p.print(std::cout, false, true); std::cout << "Child Values:" << std::endl; - c.print(program, std::cout, true, true); + c.print(std::cout, true, true); std::cout << std::endl; BLT_ABORT("Tree Check Failed."); } @@ -802,7 +807,7 @@ namespace blt::gp case mutation_operator::END: default: #if BLT_DEBUG_LEVEL > 1 - BLT_ABORT("You shouldn't be able to get here!"); + BLT_ABORT("You shouldn't be able to get here!"); #else BLT_UNREACHABLE; #endif @@ -810,12 +815,12 @@ namespace blt::gp } #if BLT_DEBUG_LEVEL >= 2 - if (!c.check(program, detail::debug::context_ptr)) + if (!c.check(detail::debug::context_ptr)) { std::cout << "Parent: " << std::endl; - p.print(program, std::cout, false, true); + p.print(std::cout, false, true); std::cout << "Child Values:" << std::endl; - c.print(program, std::cout, true, true); + c.print(std::cout, true, true); std::cout << std::endl; BLT_ABORT("Tree Check Failed."); } diff --git a/src/tree.cpp b/src/tree.cpp index 4663c7b..03f30ca 100644 --- a/src/tree.cpp +++ b/src/tree.cpp @@ -58,7 +58,7 @@ namespace blt::gp return "(" + std::string(program.get_typesystem().get_type(id).name()) + ")"; } - void tree_t::print(gp_program& program, std::ostream& out, bool print_literals, bool pretty_print, bool include_types) const + void tree_t::print(std::ostream& out, bool print_literals, bool pretty_print, bool include_types) const { std::stack arguments_left; blt::size_t indent = 0; @@ -78,9 +78,9 @@ namespace blt::gp } for (const auto& v : operations) { - auto info = program.get_operator_info(v.id()); - const auto name = program.get_name(v.id()) ? program.get_name(v.id()).value() : "NULL"; - auto return_type = get_return_type(program, info.return_type, include_types); + auto info = m_program->get_operator_info(v.id()); + const auto name = m_program->get_name(v.id()) ? m_program->get_name(v.id()).value() : "NULL"; + auto return_type = get_return_type(*m_program, info.return_type, include_types); if (info.argc.argc > 0) { create_indent(out, indent, pretty_print) << "("; @@ -93,9 +93,9 @@ namespace blt::gp if (print_literals) { create_indent(out, indent, pretty_print); - if (program.is_operator_ephemeral(v.id())) + if (m_program->is_operator_ephemeral(v.id())) { - program.get_print_func(v.id())(out, reversed); + m_program->get_print_func(v.id())(out, reversed); reversed.pop_bytes(v.type_size()); } else @@ -286,7 +286,7 @@ namespace blt::gp return m_program->get_eval_func()(*this, ptr); } - bool tree_t::check(gp_program& program, void* context) const + bool tree_t::check(void* context) const { blt::size_t bytes_expected = 0; const auto bytes_size = values.size().total_used_bytes; @@ -312,8 +312,8 @@ namespace blt::gp auto value_stack = values; auto& values_process = results.values; - blt::size_t total_produced = 0; - blt::size_t total_consumed = 0; + size_t total_produced = 0; + size_t total_consumed = 0; for (const auto& operation : iterate(operations).rev()) { @@ -323,17 +323,17 @@ namespace blt::gp total_produced += operation.type_size(); continue; } - auto& info = program.get_operator_info(operation.id()); + auto& info = m_program->get_operator_info(operation.id()); for (auto& arg : info.argument_types) - total_consumed += program.get_typesystem().get_type(arg).size(); - program.get_operator_info(operation.id()).func(context, values_process, values_process); - total_produced += program.get_typesystem().get_type(info.return_type).size(); + total_consumed += m_program->get_typesystem().get_type(arg).size(); + m_program->get_operator_info(operation.id()).func(context, values_process, values_process); + total_produced += m_program->get_typesystem().get_type(info.return_type).size(); } const auto v1 = results.values.bytes_in_head(); const auto v2 = static_cast(operations.front().type_size()); - program.get_destroy_func(operations.front().id())(detail::destroy_t::RETURN, results.values); + m_program->get_destroy_func(operations.front().id())(detail::destroy_t::RETURN, results.values); if (v1 != v2) { const auto vd = std::abs(v1 - v2); @@ -367,10 +367,6 @@ namespace blt::gp } } - tree_t::tree_t(gp_program& program): m_program(&program) - { - } - void tree_t::clear(gp_program& program) { auto* f = &program; diff --git a/tests/drop_test.cpp b/tests/drop_test.cpp index fb0385d..6c2115e 100644 --- a/tests/drop_test.cpp +++ b/tests/drop_test.cpp @@ -127,6 +127,11 @@ bool fitness_function(const tree_t& current_tree, fitness_t& fitness, size_t) int main() { + int hello = 32; + int* silly = &hello; + blt::mem::print_bytes(std::cout, silly); + return 0; + operator_builder builder{}; builder.build(add, sub, mul, pro_div, op_sin, op_cos, op_exp, op_log, lit, op_x); regression.get_program().set_operations(builder.grab());