silly little copy bytes
parent
253f4f1fdf
commit
3972a70bc5
|
@ -1,5 +1,5 @@
|
||||||
cmake_minimum_required(VERSION 3.25)
|
cmake_minimum_required(VERSION 3.25)
|
||||||
project(blt-gp VERSION 0.0.115)
|
project(blt-gp VERSION 0.0.116)
|
||||||
|
|
||||||
include(CTest)
|
include(CTest)
|
||||||
|
|
||||||
|
|
|
@ -103,7 +103,15 @@ namespace blt::gp
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit operator_builder(type_provider& system): system(system)
|
explicit operator_builder(type_provider& system): system(system)
|
||||||
{}
|
{
|
||||||
|
// // ensure every storage has a vec defined for every type!
|
||||||
|
// for (const auto& type : system)
|
||||||
|
// {
|
||||||
|
// storage.terminals[type.second.id()] = {};
|
||||||
|
// storage.non_terminals[type.second.id()] = {};
|
||||||
|
// storage.operators_ordered_terminals[type.second.id()] = {};
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
template<typename ArgType, typename Return, typename... Args>
|
template<typename ArgType, typename Return, typename... Args>
|
||||||
operator_builder& add_operator(operation_t<ArgType, Return(Args...)>& op, bool is_static = false)
|
operator_builder& add_operator(operation_t<ArgType, Return(Args...)>& op, bool is_static = false)
|
||||||
|
@ -424,11 +432,18 @@ namespace blt::gp
|
||||||
|
|
||||||
inline operator_id select_non_terminal(type_id id)
|
inline operator_id select_non_terminal(type_id id)
|
||||||
{
|
{
|
||||||
|
// non-terminal doesn't exist, return a terminal. This is useful for types that are defined only to have a random value, nothing more.
|
||||||
|
// was considering an std::optional<> but that would complicate the generator code considerably. I'll mark this as a TODO for v2
|
||||||
|
if (storage.non_terminals[id].empty())
|
||||||
|
return select_terminal(id);
|
||||||
return get_random().select(storage.non_terminals[id]);
|
return get_random().select(storage.non_terminals[id]);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline operator_id select_non_terminal_too_deep(type_id id)
|
inline operator_id select_non_terminal_too_deep(type_id id)
|
||||||
{
|
{
|
||||||
|
// this should probably be an error.
|
||||||
|
if (storage.operators_ordered_terminals[id].empty())
|
||||||
|
BLT_ABORT("An impossible state has been reached. Please consult the manual. Error 43");
|
||||||
return get_random().select(storage.operators_ordered_terminals[id]).first;
|
return get_random().select(storage.operators_ordered_terminals[id]).first;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -136,6 +136,8 @@ namespace blt::gp
|
||||||
*/
|
*/
|
||||||
void copy_from(const stack_allocator& stack, blt::size_t bytes)
|
void copy_from(const stack_allocator& stack, blt::size_t bytes)
|
||||||
{
|
{
|
||||||
|
if (bytes == 0)
|
||||||
|
return;
|
||||||
if (stack.empty())
|
if (stack.empty())
|
||||||
{
|
{
|
||||||
BLT_WARN("This stack is empty, we will copy no bytes from it!");
|
BLT_WARN("This stack is empty, we will copy no bytes from it!");
|
||||||
|
@ -166,16 +168,51 @@ namespace blt::gp
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// we can copy the bytes directly, no special allocation
|
if (bytes_left > 0)
|
||||||
if (head->remaining_bytes_in_block() >= bytes_left)
|
|
||||||
{
|
{
|
||||||
|
auto insert = head;
|
||||||
|
while (insert != nullptr)
|
||||||
|
{
|
||||||
|
if (insert->remaining_bytes_in_block() >= bytes_left)
|
||||||
|
break;
|
||||||
|
insert = insert->metadata.next;
|
||||||
|
}
|
||||||
|
// can directly copy into a block. this stack's head is now the insert point
|
||||||
|
if (insert != nullptr && insert->remaining_bytes_in_block() >= bytes_left)
|
||||||
|
head = insert;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// need to push a block to the end.
|
||||||
|
// make sure head is at the end.
|
||||||
|
while (head != nullptr && head->metadata.next != nullptr)
|
||||||
|
head = head->metadata.next;
|
||||||
|
push_block(bytes_left);
|
||||||
|
}
|
||||||
std::memcpy(head->metadata.offset, start_point, bytes_left);
|
std::memcpy(head->metadata.offset, start_point, bytes_left);
|
||||||
head->metadata.offset += bytes_left;
|
head->metadata.offset += bytes_left;
|
||||||
start_block = start_block->metadata.next;
|
start_block = start_block->metadata.next;
|
||||||
}
|
}
|
||||||
|
// we now copy whole blocks at a time.
|
||||||
while (start_block != nullptr)
|
while (start_block != nullptr)
|
||||||
{
|
{
|
||||||
|
auto prev = head;
|
||||||
|
auto insert = head;
|
||||||
|
while (insert != nullptr)
|
||||||
|
{
|
||||||
|
if (insert->remaining_bytes_in_block() >= start_block->used_bytes_in_block())
|
||||||
|
break;
|
||||||
|
prev = insert;
|
||||||
|
insert = insert->metadata.next;
|
||||||
|
}
|
||||||
|
if (insert == nullptr)
|
||||||
|
{
|
||||||
|
head = prev;
|
||||||
|
push_block(start_block->used_bytes_in_block());
|
||||||
|
} else
|
||||||
|
head = insert;
|
||||||
|
std::memcpy(head->metadata.offset, start_block->buffer, start_block->used_bytes_in_block());
|
||||||
|
head->metadata.offset += start_block->used_bytes_in_block();
|
||||||
|
start_block = start_block->metadata.next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -257,25 +294,8 @@ namespace blt::gp
|
||||||
|
|
||||||
void pop_bytes(blt::ptrdiff_t bytes)
|
void pop_bytes(blt::ptrdiff_t bytes)
|
||||||
{
|
{
|
||||||
#if BLT_DEBUG_LEVEL >= 3
|
|
||||||
blt::size_t counter = 0;
|
|
||||||
#endif
|
|
||||||
while (bytes > 0)
|
while (bytes > 0)
|
||||||
{
|
{
|
||||||
#if BLT_DEBUG_LEVEL > 0
|
|
||||||
if (head == nullptr)
|
|
||||||
{
|
|
||||||
BLT_WARN("Head is nullptr, unable to pop bytes!");
|
|
||||||
BLT_WARN("This error is normally caused by an invalid tree!");
|
|
||||||
#if BLT_DEBUG_LEVEL >= 3
|
|
||||||
BLT_WARN("Made it to %ld iterations", counter);
|
|
||||||
#endif
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
#if BLT_DEBUG_LEVEL >= 3
|
|
||||||
counter++;
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
auto diff = head->used_bytes_in_block() - bytes;
|
auto diff = head->used_bytes_in_block() - bytes;
|
||||||
// if there is not enough room left to pop completely off the block, then move to the next previous block
|
// if there is not enough room left to pop completely off the block, then move to the next previous block
|
||||||
// and pop from it, update the amount of bytes to reflect the amount removed from the current block
|
// and pop from it, update the amount of bytes to reflect the amount removed from the current block
|
||||||
|
@ -292,7 +312,7 @@ namespace blt::gp
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
while (head->used_bytes_in_block() == 0 && move_back());
|
while (head != nullptr && head->used_bytes_in_block() == 0 && move_back());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
2
lib/blt
2
lib/blt
|
@ -1 +1 @@
|
||||||
Subproject commit 79ad108fab60159461d4c78ffb97b910d446cc11
|
Subproject commit 8535480ad57553e592640b98e9e005d7a4d27501
|
|
@ -19,6 +19,7 @@
|
||||||
#include <blt/gp/program.h>
|
#include <blt/gp/program.h>
|
||||||
#include <blt/std/ranges.h>
|
#include <blt/std/ranges.h>
|
||||||
#include <blt/std/utility.h>
|
#include <blt/std/utility.h>
|
||||||
|
#include <blt/profiling/profiler_v2.h>
|
||||||
#include <random>
|
#include <random>
|
||||||
|
|
||||||
namespace blt::gp
|
namespace blt::gp
|
||||||
|
@ -195,8 +196,15 @@ namespace blt::gp
|
||||||
auto& new_vals_r = new_tree.get_values();
|
auto& new_vals_r = new_tree.get_values();
|
||||||
|
|
||||||
stack_allocator stack_after;
|
stack_allocator stack_after;
|
||||||
//stack_allocator new_vals_flip; // this is annoying.
|
blt::size_t total_bytes_after = 0;
|
||||||
transfer_backward(vals_r, stack_after, ops_r.end() - 1, end_itr - 1);
|
for (auto it = end_itr; it != ops_r.end(); it++)
|
||||||
|
{
|
||||||
|
if (it->is_value)
|
||||||
|
total_bytes_after += stack_allocator::aligned_size(it->type_size);
|
||||||
|
}
|
||||||
|
// transfer_backward(vals_r, stack_after, ops_r.end() - 1, end_itr - 1);
|
||||||
|
stack_after.copy_from(vals_r, total_bytes_after);
|
||||||
|
vals_r.pop_bytes(static_cast<blt::ptrdiff_t>(total_bytes_after));
|
||||||
for (auto it = end_itr - 1; it != begin_itr - 1; it--)
|
for (auto it = end_itr - 1; it != begin_itr - 1; it--)
|
||||||
{
|
{
|
||||||
if (it->is_value)
|
if (it->is_value)
|
||||||
|
@ -204,12 +212,15 @@ namespace blt::gp
|
||||||
}
|
}
|
||||||
|
|
||||||
vals_r.insert(std::move(new_vals_r));
|
vals_r.insert(std::move(new_vals_r));
|
||||||
transfer_forward(stack_after, vals_r, end_itr, ops_r.end());
|
//transfer_forward(stack_after, vals_r, end_itr, ops_r.end());
|
||||||
|
vals_r.copy_from(stack_after, total_bytes_after);
|
||||||
|
stack_after = {};
|
||||||
|
|
||||||
auto before = begin_itr - 1;
|
auto before = begin_itr - 1;
|
||||||
ops_r.erase(begin_itr, end_itr);
|
ops_r.erase(begin_itr, end_itr);
|
||||||
ops_r.insert(++before, new_ops_r.begin(), new_ops_r.end());
|
ops_r.insert(++before, new_ops_r.begin(), new_ops_r.end());
|
||||||
|
|
||||||
|
// 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
|
#if BLT_DEBUG_LEVEL >= 2
|
||||||
BLT_ASSERT(new_vals_r.empty());
|
BLT_ASSERT(new_vals_r.empty());
|
||||||
BLT_ASSERT(stack_after.empty());
|
BLT_ASSERT(stack_after.empty());
|
||||||
|
@ -227,6 +238,7 @@ namespace blt::gp
|
||||||
BLT_WARN_STREAM << "Stack state: " << vals_r.size() << "\n";
|
BLT_WARN_STREAM << "Stack state: " << vals_r.size() << "\n";
|
||||||
BLT_WARN("Child tree bytes %ld vs expected %ld, difference: %ld", bytes_size, bytes_expected,
|
BLT_WARN("Child tree bytes %ld vs expected %ld, difference: %ld", bytes_size, bytes_expected,
|
||||||
static_cast<blt::ptrdiff_t>(bytes_expected) - static_cast<blt::ptrdiff_t>(bytes_size));
|
static_cast<blt::ptrdiff_t>(bytes_expected) - static_cast<blt::ptrdiff_t>(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");
|
BLT_ABORT("Amount of bytes in stack doesn't match the number of bytes expected for the operations");
|
||||||
}
|
}
|
||||||
auto copy = c;
|
auto copy = c;
|
||||||
|
@ -255,132 +267,6 @@ namespace blt::gp
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
// tree_t mutation_t::apply(gp_program& program, const tree_t& p)
|
|
||||||
// {
|
|
||||||
// auto c = p;
|
|
||||||
//
|
|
||||||
//#if BLT_DEBUG_LEVEL >= 2
|
|
||||||
// blt::size_t parent_bytes = 0;
|
|
||||||
// blt::size_t parent_size = p.get_values().size().total_used_bytes;
|
|
||||||
// for (const auto& op : p.get_operations())
|
|
||||||
// {
|
|
||||||
// if (op.is_value)
|
|
||||||
// parent_bytes += stack_allocator::aligned_size(op.type_size);
|
|
||||||
// }
|
|
||||||
// if (parent_bytes != parent_size)
|
|
||||||
// {
|
|
||||||
// BLT_WARN("Parent bytes %ld do not match expected %ld", parent_size, parent_bytes);
|
|
||||||
// BLT_ABORT("You should not ignore the mismatched parent bytes!");
|
|
||||||
// }
|
|
||||||
//#endif
|
|
||||||
//
|
|
||||||
// auto& ops = c.get_operations();
|
|
||||||
// auto& vals = c.get_values();
|
|
||||||
//
|
|
||||||
// auto point = static_cast<blt::ptrdiff_t>(program.get_random().get_size_t(0ul, ops.size()));
|
|
||||||
// const auto& type_info = program.get_operator_info(ops[point].id);
|
|
||||||
//
|
|
||||||
// auto new_tree = config.generator.get().generate({program, type_info.return_type, config.replacement_min_depth, config.replacement_max_depth});
|
|
||||||
//
|
|
||||||
// auto& new_ops = new_tree.get_operations();
|
|
||||||
// auto& new_vals = new_tree.get_values();
|
|
||||||
//
|
|
||||||
//#if BLT_DEBUG_LEVEL >= 2
|
|
||||||
// blt::size_t new_tree_bytes = 0;
|
|
||||||
// blt::size_t new_tree_size = new_vals.size().total_used_bytes;
|
|
||||||
// for (const auto& op : new_ops)
|
|
||||||
// {
|
|
||||||
// if (op.is_value)
|
|
||||||
// new_tree_bytes += stack_allocator::aligned_size(op.type_size);
|
|
||||||
// }
|
|
||||||
//#endif
|
|
||||||
//
|
|
||||||
// auto begin_p = ops.begin() + point;
|
|
||||||
// auto end_p = ops.begin() + find_endpoint(program, ops, point);
|
|
||||||
//
|
|
||||||
// stack_allocator after_stack;
|
|
||||||
//
|
|
||||||
//#if BLT_DEBUG_LEVEL >= 2
|
|
||||||
// blt::size_t after_stack_bytes = 0;
|
|
||||||
// blt::size_t for_bytes = 0;
|
|
||||||
// for (auto it = ops.end() - 1; it != end_p - 1; it--)
|
|
||||||
// {
|
|
||||||
// if (it->is_value)
|
|
||||||
// {
|
|
||||||
// after_stack_bytes += stack_allocator::aligned_size(it->type_size);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//#endif
|
|
||||||
//
|
|
||||||
// transfer_backward(vals, after_stack, ops.end() - 1, end_p - 1);
|
|
||||||
// //for (auto it = ops.end() - 1; it != end_p; it++)
|
|
||||||
//
|
|
||||||
// for (auto it = end_p - 1; it != begin_p - 1; it--)
|
|
||||||
// {
|
|
||||||
// if (it->is_value)
|
|
||||||
// {
|
|
||||||
//#if BLT_DEBUG_LEVEL >= 2
|
|
||||||
// auto size_b = vals.size().total_used_bytes;
|
|
||||||
//#endif
|
|
||||||
// vals.pop_bytes(static_cast<blt::ptrdiff_t>(stack_allocator::aligned_size(it->type_size)));
|
|
||||||
//#if BLT_DEBUG_LEVEL >= 2
|
|
||||||
// auto size_a = vals.size().total_used_bytes;
|
|
||||||
// if (size_a != size_b - stack_allocator::aligned_size(it->type_size))
|
|
||||||
// {
|
|
||||||
// BLT_WARN("After pop size: %ld before pop size: %ld; expected pop amount %ld", size_a, size_b,
|
|
||||||
// stack_allocator::aligned_size(it->type_size));
|
|
||||||
// BLT_ABORT("Popping bytes didn't remove the correct amount!");
|
|
||||||
// }
|
|
||||||
// for_bytes += stack_allocator::aligned_size(it->type_size);
|
|
||||||
//#endif
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// transfer_backward(new_vals, vals, new_ops.end() - 1, new_ops.begin() - 1);
|
|
||||||
//
|
|
||||||
// transfer_forward(after_stack, vals, end_p, ops.end());
|
|
||||||
//
|
|
||||||
// auto before = begin_p - 1;
|
|
||||||
// ops.erase(begin_p, end_p);
|
|
||||||
// ops.insert(++before, new_ops.begin(), new_ops.end());
|
|
||||||
//
|
|
||||||
//#if BLT_DEBUG_LEVEL >= 2
|
|
||||||
// blt::size_t bytes_expected = 0;
|
|
||||||
// auto bytes_size = c.get_values().size().total_used_bytes;
|
|
||||||
//
|
|
||||||
// for (const auto& op : c.get_operations())
|
|
||||||
// {
|
|
||||||
// if (op.is_value)
|
|
||||||
// bytes_expected += stack_allocator::aligned_size(op.type_size);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// if (bytes_expected != bytes_size || parent_size != parent_bytes || new_tree_size != new_tree_bytes)
|
|
||||||
// {
|
|
||||||
// BLT_WARN("Parent bytes %ld vs expected %ld", parent_size, parent_bytes);
|
|
||||||
// BLT_WARN("After stack bytes: %ld; popped bytes %ld", after_stack_bytes, for_bytes);
|
|
||||||
// BLT_WARN("Tree bytes %ld vs expected %ld", new_tree_size, new_tree_bytes);
|
|
||||||
// BLT_WARN("Child tree bytes %ld vs expected %ld", bytes_size, bytes_expected);
|
|
||||||
// BLT_ABORT("Amount of bytes in stack doesn't match the number of bytes expected for the operations");
|
|
||||||
// }
|
|
||||||
// auto copy = c;
|
|
||||||
// try
|
|
||||||
// {
|
|
||||||
// auto result = copy.evaluate(nullptr);
|
|
||||||
// blt::black_box(result);
|
|
||||||
// } catch(...) {
|
|
||||||
// std::cout << "Parent:\n";
|
|
||||||
// p.print(program, std::cout, false, true);
|
|
||||||
// std::cout << "Child:\n";
|
|
||||||
// c.print(program, std::cout, false, true);
|
|
||||||
// c.print(program, std::cout, true, true);
|
|
||||||
// throw std::exception();
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
//#endif
|
|
||||||
//
|
|
||||||
// return c;
|
|
||||||
// }
|
|
||||||
|
|
||||||
mutation_t::config_t::config_t(): generator(grow_generator)
|
mutation_t::config_t::config_t(): generator(grow_generator)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue