making progress

dev
Brett 2025-05-24 21:56:44 -04:00
parent b896d07109
commit b91f679915
5 changed files with 322 additions and 214 deletions

View File

@ -27,7 +27,7 @@ macro(compile_options target_name)
sanitizers(${target_name}) sanitizers(${target_name})
endmacro() endmacro()
project(blt-gp VERSION 0.5.34) project(blt-gp VERSION 0.5.35)
include(CTest) include(CTest)

View File

@ -128,9 +128,9 @@ namespace blt::gp::example
const auto& record = results[index].first; const auto& record = results[index].first;
const auto& i = *results[index].second; const auto& i = *results[index].second;
BLT_INFO("Hits %ld, Total Cases %ld, Percent Hit: %lf", record.get_hits(), record.get_total(), record.get_percent_hit()); BLT_INFO("Hits {}, Total Cases {}, Percent Hit: {}", record.get_hits(), record.get_total(), record.get_percent_hit());
std::cout << record.pretty_print() << std::endl; std::cout << record.pretty_print() << std::endl;
BLT_DEBUG("Fitness: %lf, stand: %lf, raw: %lf", i.fitness.adjusted_fitness, i.fitness.standardized_fitness, i.fitness.raw_fitness); BLT_DEBUG("Fitness: {}, stand: {}, raw: {}", i.fitness.adjusted_fitness, i.fitness.standardized_fitness, i.fitness.raw_fitness);
i.tree.print(std::cout); i.tree.print(std::cout);
std::cout << "\n"; std::cout << "\n";
@ -145,9 +145,9 @@ namespace blt::gp::example
const auto& record = results[results.size() - 1 - index].first; const auto& record = results[results.size() - 1 - index].first;
const auto& i = *results[results.size() - 1 - index].second; const auto& i = *results[results.size() - 1 - index].second;
BLT_INFO("Hits %ld, Total Cases %ld, Percent Hit: %lf", record.get_hits(), record.get_total(), record.get_percent_hit()); BLT_INFO("Hits {}, Total Cases {}, Percent Hit: {}", record.get_hits(), record.get_total(), record.get_percent_hit());
std::cout << record.pretty_print() << std::endl; std::cout << record.pretty_print() << std::endl;
BLT_DEBUG("Fitness: %lf, stand: %lf, raw: %lf", i.fitness.adjusted_fitness, i.fitness.standardized_fitness, i.fitness.raw_fitness); BLT_DEBUG("Fitness: {}, stand: {}, raw: {}", i.fitness.adjusted_fitness, i.fitness.standardized_fitness, i.fitness.raw_fitness);
std::cout << "\n"; std::cout << "\n";
} }
@ -162,7 +162,7 @@ namespace blt::gp::example
for (const auto& [matrix, _] : results) for (const auto& [matrix, _] : results)
avg += matrix; avg += matrix;
avg /= results.size(); avg /= results.size();
BLT_INFO("Hits %ld, Total Cases %ld, Percent Hit: %lf", avg.get_hits(), avg.get_total(), avg.get_percent_hit()); BLT_INFO("Hits {}, Total Cases {}, Percent Hit: {}", avg.get_hits(), avg.get_total(), avg.get_percent_hit());
std::cout << avg.pretty_print() << std::endl; std::cout << avg.pretty_print() << std::endl;
std::cout << "\n"; std::cout << "\n";
} }

View File

@ -40,7 +40,7 @@ blt::gp::prog_config_t config = blt::gp::prog_config_t()
.set_reproduction_chance(0) .set_reproduction_chance(0)
.set_max_generations(50) .set_max_generations(50)
.set_pop_size(500) .set_pop_size(500)
.set_thread_count(1); .set_thread_count(0);
int main(int argc, const char** argv) int main(int argc, const char** argv)
{ {

View File

@ -37,6 +37,59 @@ namespace blt::gp
} }
}; };
struct bool_flag_t
{
enum state_t : u8
{
FALSE = 0,
TRUE = 1,
TRUE_BUT_REMOVE = 2
};
bool_flag_t() = default;
explicit bool_flag_t(const bool value): value(value ? 1 : 0)
{
}
explicit bool_flag_t(const u8 value): value(value)
{
}
bool_flag_t(const bool_flag_t& other) = default;
bool_flag_t& operator=(const bool_flag_t& other) = default;
bool_flag_t& operator=(const bool b)
{
value = b ? 1 : 0;
return *this;
}
bool_flag_t& operator=(const u8 v)
{
value = v;
return *this;
}
bool_flag_t& operator=(const state_t s)
{
value = static_cast<u8>(s);
return *this;
}
[[nodiscard]] explicit operator bool() const
{
return value != 0;
}
[[nodiscard]] bool should_remove() const
{
return value == TRUE_BUT_REMOVE;
}
u8 value = 0;
};
void print_child(child_t child) void print_child(child_t child)
{ {
BLT_TRACE("\tChild: {} -> {} ( {} )", child.start, child.end, child.size()); BLT_TRACE("\tChild: {} -> {} ( {} )", child.start, child.end, child.size());
@ -134,7 +187,7 @@ namespace blt::gp
while (!arguments_left.empty()) while (!arguments_left.empty())
{ {
auto top = arguments_left.top(); const auto top = arguments_left.top();
arguments_left.pop(); arguments_left.pop();
if (top == 0) if (top == 0)
{ {
@ -150,7 +203,7 @@ namespace blt::gp
} }
while (!arguments_left.empty()) while (!arguments_left.empty())
{ {
auto top = arguments_left.top(); const auto top = arguments_left.top();
arguments_left.pop(); arguments_left.pop();
if (top == 0) if (top == 0)
{ {
@ -620,6 +673,24 @@ namespace blt::gp
if (point_info.return_type != other_point_info.return_type) if (point_info.return_type != other_point_info.return_type)
return; return;
// terminals are special case, since the result ends up being a subtree swap, skip building a complex type table
if (point_info.argc.argc == 0 || other_point_info.argc.argc == 0)
return swap_subtrees(point, other_tree, other_point);
// why build a type table if it isn't going to do anything?
if (point_info.argument_types != other_point_info.argument_types)
{
BLT_INFO("---------\\{Begin Point {} to {}}---------", point.get_spoint(), other_point.get_spoint());
BLT_DEBUG("Our argument types (Terminal? {}; Ephemeral? {}):", point_info.argc.argc == 0,
tree->operations[point.get_spoint()].get_flags().is_ephemeral());
for (const auto [i, type] : enumerate(point_info.argument_types))
BLT_TRACE("\t{} -> {} (Aka '{}')", i, type, tree->m_program->get_typesystem().get_type(type).name());
BLT_DEBUG("Other argument types (Terminal? {}; Ephemeral? {}):", other_point_info.argc.argc == 0,
other_tree.operations[other_point.get_spoint()].get_flags().is_ephemeral());
for (const auto [i, type] : enumerate(other_point_info.argument_types))
BLT_TRACE("\t{} -> {} (Aka '{}')", i, type, tree->m_program->get_typesystem().get_type(type).name());
BLT_TRACE("");
// const auto our_end_point_iter = tree->operations.begin() + extent; // const auto our_end_point_iter = tree->operations.begin() + extent;
// const auto other_end_point_iter = other_tree.operations.begin() + other_extent; // const auto other_end_point_iter = other_tree.operations.begin() + other_extent;
@ -633,8 +704,8 @@ namespace blt::gp
buffer_wrapper_t our_after{}; buffer_wrapper_t our_after{};
buffer_wrapper_t other_after{}; buffer_wrapper_t other_after{};
// argument index -> type_id for missing types // argument index -> type_id for missing types
std::vector<std::tuple<size_t, type_id, bool>> our_types; std::vector<std::tuple<size_t, type_id, bool_flag_t>> our_types;
std::vector<std::tuple<size_t, type_id, bool>> other_types; std::vector<std::tuple<size_t, type_id, bool_flag_t>> other_types;
std::vector<std::pair<size_t, size_t>> our_swaps; std::vector<std::pair<size_t, size_t>> our_swaps;
std::vector<std::pair<size_t, size_t>> other_swaps; std::vector<std::pair<size_t, size_t>> other_swaps;
@ -699,6 +770,7 @@ namespace blt::gp
if (other_type == type && !consumed) if (other_type == type && !consumed)
{ {
storage.other_swaps.emplace_back(index, other_index); storage.other_swaps.emplace_back(index, other_index);
BLT_TRACE("[Others] Swaps found! {} to {}", index, other_index);
consumed = true; consumed = true;
break; break;
} }
@ -710,6 +782,7 @@ namespace blt::gp
{ {
if (other_type == type && !consumed) if (other_type == type && !consumed)
{ {
BLT_TRACE("[Ours] Swaps found! {} to {}", index, other_index);
storage.our_swaps.emplace_back(index, other_index); storage.our_swaps.emplace_back(index, other_index);
consumed = true; consumed = true;
break; break;
@ -717,9 +790,9 @@ namespace blt::gp
} }
} }
BLT_TRACE("");
tree->find_child_extends(storage.our_children, point.get_point(), point_info.argc.argc); tree->find_child_extends(storage.our_children, point.get_point(), point_info.argc.argc);
BLT_DEBUG("Ours:");
print_child_vec(storage.our_children);
// apply the swaps // apply the swaps
for (const auto& [i, j] : storage.our_swaps) for (const auto& [i, j] : storage.our_swaps)
@ -734,13 +807,8 @@ namespace blt::gp
storage.our_current_types[i] = storage.our_current_types[j]; storage.our_current_types[i] = storage.our_current_types[j];
storage.our_current_types[j] = tmp; storage.our_current_types[j] = tmp;
} }
BLT_DEBUG("Ours (Swaps):");
print_child_vec(storage.our_children);
other_tree.find_child_extends(storage.other_children, other_point.get_point(), other_point_info.argc.argc); other_tree.find_child_extends(storage.other_children, other_point.get_point(), other_point_info.argc.argc);
BLT_DEBUG("-----------");
BLT_DEBUG("Other:");
print_child_vec(storage.other_children);
for (const auto& [i, j] : storage.other_swaps) for (const auto& [i, j] : storage.other_swaps)
{ {
@ -755,60 +823,84 @@ namespace blt::gp
storage.other_current_types[j] = tmp; storage.other_current_types[j] = tmp;
} }
BLT_DEBUG("Other (Swaps):");
print_child_vec(storage.other_children);
BLT_INFO("-----------");
for (size_t i = 0; i < common_size; i++) for (size_t i = 0; i < common_size; i++)
{ {
if (storage.our_current_types[i] != other_point_info.argument_types[i]) if (storage.our_current_types[i] != other_point_info.argument_types[i])
{ {
BLT_TRACE("[Our] Mismatched type at index {} found current type '{}' expected type '{}'", i,
tree->m_program->get_typesystem().get_type(storage.our_current_types[i]).name(),
tree->m_program->get_typesystem().get_type(other_point_info.argument_types[i]).name());
for (auto& [index, type, consumed] : storage.other_types) for (auto& [index, type, consumed] : storage.other_types)
{ {
if (consumed) if (consumed)
continue; continue;
if (type == other_point_info.argument_types[i]) if (type == other_point_info.argument_types[i])
{ {
BLT_TRACE("Consuming other type {} at index {} ", type, index);
consumed = true; consumed = true;
const auto s1 = storage.other_children[index].size(); const auto s1 = storage.other_children[index].size();
const auto s2 = storage.our_children[i].size(); const auto s2 = storage.our_children[i].size();
swap_subtrees(storage.our_children[i], other_tree, storage.other_children[index]); swap_subtrees(storage.our_children[i], other_tree, storage.other_children[index]);
storage.our_children[i].end = storage.our_children[i].start + s1; storage.our_children[i].end = storage.our_children[i].start + s1;
storage.other_children[index].end = storage.other_children[index].start + s2; storage.other_children[index].end = storage.other_children[index].start + s2;
auto old_type = storage.our_current_types[i];
storage.our_current_types[i] = type;
storage.other_current_types[index] = old_type;
goto b1; goto b1;
} }
} }
#if BLT_DEBUG_LEVEL >= 1 #if BLT_DEBUG_LEVEL >= 1
BLT_ERROR("Unable to find type for position {}, expected type {} but found type {}. ", i, other_point_info.argument_types[i], storage.our_current_types[i]); BLT_ERROR("Unable to find type for position {}, expected type '{}' but found type '{}'. ", i, other_point_info.argument_types[i],
storage.our_current_types[i]);
BLT_ABORT("Failure state in swap operators!"); BLT_ABORT("Failure state in swap operators!");
#endif #endif
b1:{} b1:
{
}
} }
if (storage.other_current_types[i] != point_info.argument_types[i]) if (storage.other_current_types[i] != point_info.argument_types[i])
{ {
BLT_TRACE("[Other] Mismatched type at index {} found current type '{}' expected type '{}'", i,
tree->m_program->get_typesystem().get_type(storage.other_current_types[i]).name(),
tree->m_program->get_typesystem().get_type(point_info.argument_types[i]).name());
for (auto& [index, type, consumed] : storage.our_types) for (auto& [index, type, consumed] : storage.our_types)
{ {
if (consumed) if (consumed)
continue; continue;
if (type == point_info.argument_types[i]) if (type == point_info.argument_types[i])
{ {
BLT_TRACE("Consuming our type {} at index {} ", type, index);
consumed = true; consumed = true;
const auto s1 = storage.our_children[index].size(); const auto s1 = storage.our_children[index].size();
const auto s2 = storage.other_children[i].size(); const auto s2 = storage.other_children[i].size();
other_tree.manipulate().easy_manipulator().swap_subtrees(storage.other_children[i], *tree, storage.our_children[index]); other_tree.manipulate().easy_manipulator().swap_subtrees(storage.other_children[i], *tree, storage.our_children[index]);
storage.other_children[i].end = storage.other_children[i].start + s1; storage.other_children[i].end = storage.other_children[i].start + s1;
storage.our_children[index].end = storage.our_children[index].start + s2; storage.our_children[index].end = storage.our_children[index].start + s2;
auto old_type = storage.other_current_types[i];
storage.other_current_types[i] = type;
storage.our_current_types[index] = old_type;
goto b2; goto b2;
} }
} }
#if BLT_DEBUG_LEVEL >= 1 #if BLT_DEBUG_LEVEL >= 1
BLT_WARN("Unable to find type for position {}, expected type {} but found type {}. ", i, point_info.argument_types[i], storage.other_current_types[i]); BLT_WARN("Unable to find type for position {}, expected type {} but found type {}. ", i, point_info.argument_types[i],
storage.other_current_types[i]);
BLT_ABORT("Failure state in swap operators!"); BLT_ABORT("Failure state in swap operators!");
#endif #endif
b2:{} b2:
{
} }
} }
}
#if BLT_DEBUG_LEVEL >= 1
for (const auto& [i, a, b] : in_pairs(storage.our_current_types, other_point_info.argument_types).enumerate().take(common_size).flatten())
BLT_ASSERT_MSG(a == b, ("[Our] Mismatched types at index " + std::to_string(i) + " expected '" + std::string(tree->m_program->get_typesystem().get_type(a).name()) + "' but found '" +
std::string(tree->m_program->get_typesystem().get_type(b).name()) + "'").c_str());
for (const auto& [i, a, b] : in_pairs(storage.other_current_types, point_info.argument_types).enumerate().take(common_size).flatten())
BLT_ASSERT_MSG(a == b, ("[Other] Mismatched types at index " + std::to_string(i) + " expected '" + std::string(tree->m_program->get_typesystem().get_type(a).name()) + "' but found '" +
std::string(tree->m_program->get_typesystem().get_type(b).name()) + "'").c_str());
#endif
auto insert_index = storage.other_children.back().end; auto insert_index = storage.other_children.back().end;
for (size_t i = common_size; i < point_info.argument_types.size(); i++) for (size_t i = common_size; i < point_info.argument_types.size(); i++)
@ -821,10 +913,11 @@ namespace blt::gp
continue; continue;
if (type == point_info.argument_types[i]) if (type == point_info.argument_types[i])
{ {
// BLT_TRACE("[Our] Consuming type {} at index {} being inserted into {}", type, index, insert_index);
storage.temp.clear(*tree->m_program); storage.temp.clear(*tree->m_program);
copy_subtree(storage.our_children[i], storage.temp); copy_subtree(storage.our_children[i], storage.temp);
insert_index = other_tree.manipulate().easy_manipulator().insert_subtree(subtree_point_t{insert_index}, storage.temp); insert_index = other_tree.manipulate().easy_manipulator().insert_subtree(subtree_point_t{insert_index}, storage.temp);
consumed = true; consumed = bool_flag_t::TRUE_BUT_REMOVE;
goto b3; goto b3;
} }
} }
@ -832,7 +925,9 @@ namespace blt::gp
BLT_WARN("Unable to find type for position {}, expected type {}", i, point_info.argument_types[i]); BLT_WARN("Unable to find type for position {}, expected type {}", i, point_info.argument_types[i]);
BLT_ABORT("Failure state in swap operators!"); BLT_ABORT("Failure state in swap operators!");
#endif #endif
b3:{} b3:
{
}
} }
insert_index = storage.our_children.back().end; insert_index = storage.our_children.back().end;
@ -846,26 +941,39 @@ namespace blt::gp
continue; continue;
if (type == other_point_info.argument_types[i]) if (type == other_point_info.argument_types[i])
{ {
// BLT_TRACE("[Other] Consuming type {} at index {} being inserted into {}", type, index, insert_index);
storage.temp.clear(*tree->m_program); storage.temp.clear(*tree->m_program);
other_tree.manipulate().easy_manipulator().copy_subtree(storage.other_children[i], storage.temp); other_tree.manipulate().easy_manipulator().copy_subtree(storage.other_children[i], storage.temp);
insert_index = insert_subtree(subtree_point_t{insert_index}, storage.temp); insert_index = insert_subtree(subtree_point_t{insert_index}, storage.temp);
consumed = true; consumed = bool_flag_t::TRUE_BUT_REMOVE;
goto b4; goto b4;
} }
} }
b4:{} b4:
{
}
} }
#if BLT_DEBUG_LEVEL >= 1 for (auto& [index, type, consumed] : iterate(storage.our_types).rev())
for (const auto& [index, type, consumed] : storage.our_types) {
BLT_ASSERT_MSG(consumed, ("Expected type to be consumed, was not at index " + std::to_string(index)).c_str()); if (consumed.should_remove())
for (const auto& [index, type, consumed] : storage.other_types) delete_subtree(storage.our_children[index]);
BLT_ASSERT_MSG(consumed, ("Expected type to be consumed, was not at index " + std::to_string(index)).c_str()); }
#endif
for (auto& [index, type, consumed] : iterate(storage.other_types).rev())
{
if (consumed.should_remove())
other_tree.manipulate().easy_manipulator().delete_subtree(storage.other_children[index]);
}
}
auto op = tree->operations[point.get_spoint()]; auto op = tree->operations[point.get_spoint()];
tree->operations[point.get_spoint()] = other_tree.operations[other_point.get_spoint()]; tree->operations[point.get_spoint()] = other_tree.operations[other_point.get_spoint()];
other_tree.operations[other_point.get_spoint()] = op; other_tree.operations[other_point.get_spoint()] = op;
#if BLT_DEBUG_LEVEL >= 2
if (!tree->check(detail::debug::context_ptr) || !other_tree.check(detail::debug::context_ptr))
throw std::runtime_error("Tree check failed");
#endif
} }
void slow_tree_manipulator_t::swap_operators(const size_t point, tree_t& other_tree, const size_t other_point) const void slow_tree_manipulator_t::swap_operators(const size_t point, tree_t& other_tree, const size_t other_point) const
@ -984,7 +1092,7 @@ namespace blt::gp
if (v1 != v2) if (v1 != v2)
{ {
const auto vd = std::abs(v1 - v2); const auto vd = std::abs(v1 - v2);
BLT_ERROR("found {} bytes expected {} bytes, total difference: {}", v1, v2, vd); BLT_ERROR("Tree result stack has {} bytes expected {} bytes, total difference: {}", v1, v2, vd);
BLT_ERROR("Total Produced {} || Total Consumed {} || Total Difference {}", total_produced, total_consumed, BLT_ERROR("Total Produced {} || Total Consumed {} || Total Difference {}", total_produced, total_consumed,
std::abs(static_cast<blt::ptrdiff_t>(total_produced) - static_cast<blt::ptrdiff_t>(total_consumed))); std::abs(static_cast<blt::ptrdiff_t>(total_produced) - static_cast<blt::ptrdiff_t>(total_consumed)));
return false; return false;

View File

@ -28,7 +28,7 @@ std::array crossover_chances = {0.8, 0.9, 1.0};
std::array mutation_chances = {0.0, 0.1, 0.2, 0.9, 1.0}; std::array mutation_chances = {0.0, 0.1, 0.2, 0.9, 1.0};
std::array reproduction_chances = {0.0, 0.1, 0.9, 1.0}; std::array reproduction_chances = {0.0, 0.1, 0.9, 1.0};
std::array elite_amounts = {0, 2, 50}; std::array elite_amounts = {0, 2, 50};
std::array population_sizes = {50, 500, 5000}; std::array population_sizes = {50, 500};
blt::gp::prog_config_t best_config; blt::gp::prog_config_t best_config;
double best_fitness = 0; double best_fitness = 0;