function mutation but something is broken
parent
f8c641c9ee
commit
98af35f357
|
@ -1,11 +1,17 @@
|
||||||
cmake_minimum_required(VERSION 3.25)
|
cmake_minimum_required(VERSION 3.25)
|
||||||
project(image-gp-6 VERSION 0.0.27)
|
project(image-gp-6 VERSION 0.0.28)
|
||||||
|
|
||||||
include(FetchContent)
|
include(FetchContent)
|
||||||
|
|
||||||
option(ENABLE_ADDRSAN "Enable the address sanitizer" OFF)
|
option(ENABLE_ADDRSAN "Enable the address sanitizer" OFF)
|
||||||
option(ENABLE_UBSAN "Enable the ub sanitizer" OFF)
|
option(ENABLE_UBSAN "Enable the ub sanitizer" OFF)
|
||||||
option(ENABLE_TSAN "Enable the thread data race sanitizer" OFF)
|
option(ENABLE_TSAN "Enable the thread data race sanitizer" OFF)
|
||||||
|
option(ENABLE_NATIVE_SSE "Enable native ASM generation" ON)
|
||||||
|
option(DEBUG_LEVEL "Enable debug features which prints extra information to the console, might slow processing down. [0, 3)" 0)
|
||||||
|
|
||||||
|
if (${ENABLE_NATIVE_SSE})
|
||||||
|
add_compile_options(-march=native)
|
||||||
|
endif ()
|
||||||
|
|
||||||
set(CMAKE_CXX_STANDARD 17)
|
set(CMAKE_CXX_STANDARD 17)
|
||||||
|
|
||||||
|
@ -23,6 +29,8 @@ file(GLOB_RECURSE PROJECT_BUILD_FILES "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp")
|
||||||
|
|
||||||
add_executable(image-gp-6 ${PROJECT_BUILD_FILES})
|
add_executable(image-gp-6 ${PROJECT_BUILD_FILES})
|
||||||
|
|
||||||
|
target_compile_definitions(image-gp-6 PRIVATE BLT_DEBUG_LEVEL=${DEBUG_LEVEL})
|
||||||
|
|
||||||
target_compile_options(image-gp-6 PRIVATE -Wall -Wextra -Wpedantic -Wno-comment)
|
target_compile_options(image-gp-6 PRIVATE -Wall -Wextra -Wpedantic -Wno-comment)
|
||||||
target_link_options(image-gp-6 PRIVATE -Wall -Wextra -Wpedantic -Wno-comment)
|
target_link_options(image-gp-6 PRIVATE -Wall -Wextra -Wpedantic -Wno-comment)
|
||||||
|
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 1.2 MiB |
|
@ -36,6 +36,8 @@ inline constexpr blt::u64 u64_size_min = 1;
|
||||||
inline constexpr blt::u64 u64_size_max = 9;
|
inline constexpr blt::u64 u64_size_max = 9;
|
||||||
inline constexpr float THRESHOLD = 0.5;
|
inline constexpr float THRESHOLD = 0.5;
|
||||||
inline constexpr auto load_image = "../GSab4SWWcAA1TNR.png";
|
inline constexpr auto load_image = "../GSab4SWWcAA1TNR.png";
|
||||||
|
//inline constexpr auto load_image = "../hannah.png";
|
||||||
|
inline constexpr blt::size_t MAX_ARG_C = 8;
|
||||||
|
|
||||||
inline blt::gp::image_crossover_t image_crossover;
|
inline blt::gp::image_crossover_t image_crossover;
|
||||||
inline blt::gp::image_mutation_t image_mutation;
|
inline blt::gp::image_mutation_t image_mutation;
|
||||||
|
|
|
@ -63,8 +63,8 @@ namespace blt::gp
|
||||||
enum class mutation_operator : blt::i32
|
enum class mutation_operator : blt::i32
|
||||||
{
|
{
|
||||||
EXPRESSION, // Generate a new random expression
|
EXPRESSION, // Generate a new random expression
|
||||||
ADJUST, // adjust the value of the type.
|
ADJUST, // adjust the value of the type. (if it is a function it will mutate it to a different one)
|
||||||
FUNC, // Change node into a different function. Args will be generated / removed.
|
//FUNC, // Change node into a different function. Args will be generated / removed.
|
||||||
SUB_FUNC, // subexpression becomes argument to new random function. Other args are generated.
|
SUB_FUNC, // subexpression becomes argument to new random function. Other args are generated.
|
||||||
JUMP_FUNC, // subexpression becomes this new node. Other arguments discarded.
|
JUMP_FUNC, // subexpression becomes this new node. Other arguments discarded.
|
||||||
COPY, // node can become copy of another subexpression.
|
COPY, // node can become copy of another subexpression.
|
||||||
|
@ -87,7 +87,7 @@ namespace blt::gp
|
||||||
static constexpr std::array<double, operators_size> mutation_operator_chances = aggregate_array<operators_size>(
|
static constexpr std::array<double, operators_size> mutation_operator_chances = aggregate_array<operators_size>(
|
||||||
0.01, // EXPRESSION
|
0.01, // EXPRESSION
|
||||||
0.11, // ADJUST
|
0.11, // ADJUST
|
||||||
0.05, // FUNC
|
//0.05, // FUNC
|
||||||
0.01, // SUB_FUNC
|
0.01, // SUB_FUNC
|
||||||
0.1, // JUMP_FUNC
|
0.1, // JUMP_FUNC
|
||||||
0.05 // COPY
|
0.05 // COPY
|
||||||
|
|
|
@ -177,13 +177,13 @@ inline blt::gp::operation_t median_blur([](const full_image_t& a, blt::u64 size)
|
||||||
return img;
|
return img;
|
||||||
}, "median_blur");
|
}, "median_blur");
|
||||||
|
|
||||||
inline blt::gp::operation_t bilateral_filter([](const full_image_t& a, blt::u64 size) {
|
inline blt::gp::operation_t bilateral_filter([](const full_image_t& a, blt::u64 size, float color, float space) {
|
||||||
cv::Mat src(IMAGE_SIZE, IMAGE_SIZE, CV_32FC3, const_cast<float*>(a.rgb_data));
|
|
||||||
full_image_t img{};
|
full_image_t img{};
|
||||||
|
cv::Mat src(IMAGE_SIZE, IMAGE_SIZE, CV_32FC3, const_cast<float*>(a.rgb_data));
|
||||||
cv::Mat dst{IMAGE_SIZE, IMAGE_SIZE, CV_32FC3, img.rgb_data};
|
cv::Mat dst{IMAGE_SIZE, IMAGE_SIZE, CV_32FC3, img.rgb_data};
|
||||||
if (size % 2 == 0)
|
if (size % 2 == 0)
|
||||||
size++;
|
size++;
|
||||||
cv::bilateralFilter(src, dst, static_cast<int>(size), static_cast<int>(size) * 2, static_cast<int>(size) / 2.0);
|
cv::bilateralFilter(src, dst, static_cast<int>(size), color * static_cast<double>(size) * 2.0, space * static_cast<double>(size) * 2.0);
|
||||||
return img;
|
return img;
|
||||||
}, "bilateral_filter");
|
}, "bilateral_filter");
|
||||||
|
|
||||||
|
@ -399,7 +399,10 @@ void create_image_operations(blt::gp::operator_builder<context>& builder)
|
||||||
builder.add_operator(hsv_to_rgb);
|
builder.add_operator(hsv_to_rgb);
|
||||||
builder.add_operator(gaussian_blur);
|
builder.add_operator(gaussian_blur);
|
||||||
builder.add_operator(median_blur);
|
builder.add_operator(median_blur);
|
||||||
|
// idk when it got enabled but this works on 4.10
|
||||||
|
#if CV_VERSION_MAJOR >= 4 && CV_VERSION_MINOR >= 10
|
||||||
builder.add_operator(bilateral_filter);
|
builder.add_operator(bilateral_filter);
|
||||||
|
#endif
|
||||||
builder.add_operator(high_pass);
|
builder.add_operator(high_pass);
|
||||||
|
|
||||||
bool state = false;
|
bool state = false;
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit 64e8d71468c632d17e01750083f1e5ebd5236910
|
Subproject commit 9f7c647952ab41a59d8b7d0a196fb3dc3147d23f
|
|
@ -24,12 +24,20 @@
|
||||||
namespace blt::gp
|
namespace blt::gp
|
||||||
{
|
{
|
||||||
|
|
||||||
|
template<typename>
|
||||||
|
static blt::u8* get_thread_pointer_for_size(blt::size_t bytes)
|
||||||
|
{
|
||||||
|
static thread_local blt::expanding_buffer<blt::u8> buffer;
|
||||||
|
if (bytes > buffer.size())
|
||||||
|
buffer.resize(bytes);
|
||||||
|
return buffer.data();
|
||||||
|
}
|
||||||
|
|
||||||
blt::expected<crossover_t::result_t, crossover_t::error_t> image_crossover_t::apply(gp_program& program, const tree_t& p1, const tree_t& p2)
|
blt::expected<crossover_t::result_t, crossover_t::error_t> image_crossover_t::apply(gp_program& program, const tree_t& p1, const tree_t& p2)
|
||||||
{
|
{
|
||||||
return crossover_t::apply(program, p1, p2);
|
return crossover_t::apply(program, p1, p2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
tree_t image_mutation_t::apply(gp_program& program, const tree_t& p)
|
tree_t image_mutation_t::apply(gp_program& program, const tree_t& p)
|
||||||
{
|
{
|
||||||
// child tree
|
// child tree
|
||||||
|
@ -44,9 +52,10 @@ namespace blt::gp
|
||||||
{
|
{
|
||||||
if (!program.get_random().choice(node_mutation_chance))
|
if (!program.get_random().choice(node_mutation_chance))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
// select an operator to apply
|
||||||
auto selected_point = static_cast<blt::i32>(mutation_operator::COPY);
|
auto selected_point = static_cast<blt::i32>(mutation_operator::COPY);
|
||||||
auto choice = program.get_random().get_double();
|
auto choice = program.get_random().get_double();
|
||||||
|
|
||||||
for (const auto& [index, value] : blt::enumerate(mutation_operator_chances))
|
for (const auto& [index, value] : blt::enumerate(mutation_operator_chances))
|
||||||
{
|
{
|
||||||
if (index == 0)
|
if (index == 0)
|
||||||
|
@ -75,7 +84,188 @@ namespace blt::gp
|
||||||
{
|
{
|
||||||
// this is going to be evil >:3
|
// this is going to be evil >:3
|
||||||
const auto& node = ops[c_node];
|
const auto& node = ops[c_node];
|
||||||
if (node.is_value)
|
if (!node.is_value)
|
||||||
|
{
|
||||||
|
BLT_TRACE("Running adjust on function");
|
||||||
|
auto& current_func_info = program.get_operator_info(ops[c_node].id);
|
||||||
|
operator_id random_replacement = program.get_random().select(
|
||||||
|
program.get_type_non_terminals(current_func_info.return_type.id));
|
||||||
|
auto& replacement_func_info = program.get_operator_info(random_replacement);
|
||||||
|
|
||||||
|
struct child_t
|
||||||
|
{
|
||||||
|
blt::ptrdiff_t start;
|
||||||
|
// one past the end
|
||||||
|
blt::ptrdiff_t end;
|
||||||
|
};
|
||||||
|
|
||||||
|
// cache memory used for offset data.
|
||||||
|
thread_local static std::vector<child_t> children_data;
|
||||||
|
children_data.clear();
|
||||||
|
|
||||||
|
while (children_data.size() < current_func_info.argument_types.size())
|
||||||
|
{
|
||||||
|
auto current_point = children_data.size();
|
||||||
|
child_t prev{};
|
||||||
|
if (current_point == 0)
|
||||||
|
{
|
||||||
|
// first child.
|
||||||
|
prev = {static_cast<blt::ptrdiff_t>(c_node + 1),
|
||||||
|
c.find_endpoint(program, static_cast<blt::ptrdiff_t>(c_node + 1))};
|
||||||
|
children_data.push_back(prev);
|
||||||
|
continue;
|
||||||
|
} else
|
||||||
|
prev = children_data[current_point - 1];
|
||||||
|
child_t next = {prev.end, c.find_endpoint(program, prev.end)};
|
||||||
|
children_data.push_back(next);
|
||||||
|
}
|
||||||
|
|
||||||
|
BLT_TRACE("%ld vs %ld, replacement will be size %ld", children_data.size(), current_func_info.argument_types.size(),
|
||||||
|
replacement_func_info.argument_types.size());
|
||||||
|
|
||||||
|
for (const auto& [index, val] : blt::enumerate(replacement_func_info.argument_types))
|
||||||
|
{
|
||||||
|
// need to generate replacement.
|
||||||
|
if (index < current_func_info.argument_types.size() && val.id != current_func_info.argument_types[index].id)
|
||||||
|
{
|
||||||
|
BLT_TRACE_STREAM << "Replacing tree argument from type "
|
||||||
|
<< program.get_typesystem().get_type(current_func_info.argument_types[index]).name() << " to type "
|
||||||
|
<< program.get_typesystem().get_type(val).name() << "\n";
|
||||||
|
// TODO: new config?
|
||||||
|
auto tree = config.generator.get().generate(
|
||||||
|
{program, val.id, config.replacement_min_depth, config.replacement_max_depth});
|
||||||
|
blt::size_t total_bytes_after = 0;
|
||||||
|
blt::size_t total_bytes_for = 0;
|
||||||
|
|
||||||
|
auto& child = children_data[index];
|
||||||
|
for (blt::ptrdiff_t i = child.start; i < child.end; i++)
|
||||||
|
{
|
||||||
|
if (ops[i].is_value)
|
||||||
|
total_bytes_for += stack_allocator::aligned_size(ops[i].type_size);
|
||||||
|
}
|
||||||
|
for (blt::size_t i = child.end; i < ops.size(); i++)
|
||||||
|
{
|
||||||
|
if (ops[i].is_value)
|
||||||
|
total_bytes_after += stack_allocator::aligned_size(ops[i].type_size);
|
||||||
|
}
|
||||||
|
BLT_TRACE("Size for %ld size after: %ld", total_bytes_for, total_bytes_after);
|
||||||
|
|
||||||
|
auto after_ptr = get_thread_pointer_for_size<struct mutation_func>(total_bytes_after);
|
||||||
|
vals.copy_to(after_ptr, total_bytes_after);
|
||||||
|
vals.pop_bytes(static_cast<blt::ptrdiff_t>(total_bytes_after + total_bytes_for));
|
||||||
|
|
||||||
|
blt::size_t total_child_bytes = 0;
|
||||||
|
for (const auto& v : tree.get_operations())
|
||||||
|
{
|
||||||
|
if (v.is_value)
|
||||||
|
total_child_bytes += stack_allocator::aligned_size(v.type_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
BLT_TRACE("Copying %ld bytes back into stack", total_child_bytes);
|
||||||
|
|
||||||
|
vals.copy_from(tree.get_values(), total_child_bytes);
|
||||||
|
vals.copy_from(after_ptr, total_bytes_after);
|
||||||
|
|
||||||
|
ops.erase(ops.begin() + child.start, ops.begin() + child.end);
|
||||||
|
ops.insert(ops.begin() + child.start, tree.get_operations().begin(), tree.get_operations().end());
|
||||||
|
|
||||||
|
// shift over everybody after.
|
||||||
|
for (auto& new_child : blt::iterate(children_data.begin() + static_cast<blt::ptrdiff_t>(index), children_data.end()))
|
||||||
|
{
|
||||||
|
// remove the old tree size, then add the new tree size to get the correct positions.
|
||||||
|
new_child.start =
|
||||||
|
new_child.start - (child.end - child.start) + static_cast<blt::ptrdiff_t>(tree.get_operations().size());
|
||||||
|
new_child.end =
|
||||||
|
new_child.end - (child.end - child.start) + static_cast<blt::ptrdiff_t>(tree.get_operations().size());
|
||||||
|
}
|
||||||
|
child.end = static_cast<blt::ptrdiff_t>(child.start + tree.get_operations().size());
|
||||||
|
|
||||||
|
#if BLT_DEBUG_LEVEL >= 2
|
||||||
|
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) {
|
||||||
|
if (v2.is_value)
|
||||||
|
return v1 + stack_allocator::aligned_size(v2.type_size);
|
||||||
|
return v1;
|
||||||
|
});
|
||||||
|
if (found_bytes != expected_bytes)
|
||||||
|
{
|
||||||
|
BLT_WARN("Found bytes %ld vs Expected Bytes %ld", found_bytes, expected_bytes);
|
||||||
|
BLT_ABORT("Amount of bytes in stack doesn't match the number of bytes expected for the operations");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (current_func_info.argc.argc > replacement_func_info.argc.argc)
|
||||||
|
{
|
||||||
|
BLT_TRACE("TOO MANY ARGS");
|
||||||
|
// too many args
|
||||||
|
blt::size_t end_index = children_data.back().end;
|
||||||
|
blt::size_t start_index = children_data[replacement_func_info.argc.argc].start;
|
||||||
|
blt::size_t total_bytes_for = 0;
|
||||||
|
blt::size_t total_bytes_after = 0;
|
||||||
|
for (blt::size_t i = start_index; i < end_index; i++)
|
||||||
|
{
|
||||||
|
if (ops[i].is_value)
|
||||||
|
total_bytes_for += stack_allocator::aligned_size(ops[i].type_size);
|
||||||
|
}
|
||||||
|
for (blt::size_t i = end_index; i < ops.size(); i++)
|
||||||
|
{
|
||||||
|
if (ops[i].is_value)
|
||||||
|
total_bytes_after += stack_allocator::aligned_size(ops[i].type_size);
|
||||||
|
}
|
||||||
|
auto* data = get_thread_pointer_for_size<struct mutation_func>(total_bytes_after);
|
||||||
|
vals.copy_to(data, total_bytes_after);
|
||||||
|
vals.pop_bytes(static_cast<blt::ptrdiff_t>(total_bytes_after + total_bytes_for));
|
||||||
|
vals.copy_from(data, total_bytes_after);
|
||||||
|
ops.erase(ops.begin() + static_cast<blt::ptrdiff_t>(start_index), ops.begin() + static_cast<blt::ptrdiff_t>(end_index));
|
||||||
|
} else if (current_func_info.argc.argc == replacement_func_info.argc.argc)
|
||||||
|
{
|
||||||
|
BLT_TRACE("JUST ENOUGH ARGS");
|
||||||
|
// exactly enough args
|
||||||
|
// return types should have been replaced if needed. this part should do nothing?
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
BLT_TRACE("NOT ENOUGH ARGS");
|
||||||
|
// not enough args
|
||||||
|
blt::size_t total_bytes_after = 0;
|
||||||
|
blt::size_t start_index = c_node + 1;
|
||||||
|
if (current_func_info.argc.argc != 0)
|
||||||
|
start_index = children_data.back().end;
|
||||||
|
for (blt::size_t i = start_index; i < ops.size(); i++)
|
||||||
|
{
|
||||||
|
if (ops[i].is_value)
|
||||||
|
total_bytes_after += stack_allocator::aligned_size(ops[i].type_size);
|
||||||
|
}
|
||||||
|
auto* data = get_thread_pointer_for_size<struct mutation_func>(total_bytes_after);
|
||||||
|
vals.copy_to(data, total_bytes_after);
|
||||||
|
vals.pop_bytes(static_cast<blt::ptrdiff_t>(total_bytes_after));
|
||||||
|
|
||||||
|
for (blt::size_t i = current_func_info.argc.argc; i < replacement_func_info.argc.argc; i++)
|
||||||
|
{
|
||||||
|
BLT_TRACE("Generating argument %ld", i);
|
||||||
|
auto tree = config.generator.get().generate(
|
||||||
|
{program, replacement_func_info.argument_types[i].id, config.replacement_min_depth,
|
||||||
|
config.replacement_max_depth});
|
||||||
|
blt::size_t total_bytes_for = 0;
|
||||||
|
for (const auto& op : tree.get_operations())
|
||||||
|
{
|
||||||
|
if (op.is_value)
|
||||||
|
total_bytes_for += stack_allocator::aligned_size(op.type_size);
|
||||||
|
}
|
||||||
|
vals.copy_from(tree.get_values(), total_bytes_for);
|
||||||
|
ops.insert(ops.begin() + static_cast<blt::ptrdiff_t>(start_index), tree.get_operations().begin(),
|
||||||
|
tree.get_operations().end());
|
||||||
|
start_index += tree.get_operations().size();
|
||||||
|
}
|
||||||
|
vals.copy_from(data, total_bytes_after);
|
||||||
|
}
|
||||||
|
// now finally update the type.
|
||||||
|
ops[c_node] = {replacement_func_info.function, program.get_typesystem().get_type(replacement_func_info.return_type).size(),
|
||||||
|
random_replacement, false};
|
||||||
|
} else
|
||||||
{
|
{
|
||||||
blt::size_t bytes_from_head = 0;
|
blt::size_t bytes_from_head = 0;
|
||||||
for (auto it = ops.begin() + static_cast<blt::ptrdiff_t>(c_node) + 1; it != ops.end(); it++)
|
for (auto it = ops.begin() + static_cast<blt::ptrdiff_t>(c_node) + 1; it != ops.end(); it++)
|
||||||
|
@ -93,7 +283,7 @@ namespace blt::gp
|
||||||
val = program.get_random().get_u64(val, u64_size_max);
|
val = program.get_random().get_u64(val, u64_size_max);
|
||||||
else
|
else
|
||||||
val = program.get_random().get_u64(u64_size_min, val + 1);
|
val = program.get_random().get_u64(u64_size_min, val + 1);
|
||||||
} else // is an image
|
} else if (node.type_size == sizeof(full_image_t))// is an image
|
||||||
{
|
{
|
||||||
auto& val = vals.from<full_image_t>(bytes_from_head);
|
auto& val = vals.from<full_image_t>(bytes_from_head);
|
||||||
auto type = program.get_typesystem().get_type<full_image_t>();
|
auto type = program.get_typesystem().get_type<full_image_t>();
|
||||||
|
@ -119,12 +309,13 @@ namespace blt::gp
|
||||||
value += adjustment.rgb_data[index];
|
value += adjustment.rgb_data[index];
|
||||||
value /= 2.0f;
|
value /= 2.0f;
|
||||||
}
|
}
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
BLT_ABORT("This type size doesn't exist!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case mutation_operator::FUNC:
|
|
||||||
break;
|
|
||||||
case mutation_operator::SUB_FUNC:
|
case mutation_operator::SUB_FUNC:
|
||||||
break;
|
break;
|
||||||
case mutation_operator::JUMP_FUNC:
|
case mutation_operator::JUMP_FUNC:
|
||||||
|
@ -141,6 +332,44 @@ namespace blt::gp
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if BLT_DEBUG_LEVEL >= 2
|
||||||
|
blt::size_t bytes_expected = 0;
|
||||||
|
auto bytes_size = vals.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)
|
||||||
|
{
|
||||||
|
BLT_WARN_STREAM << "Stack state: " << vals.size() << "\n";
|
||||||
|
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));
|
||||||
|
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 (const std::exception& e)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
BLT_WARN(e.what());
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
BLT_TRACE("- - - - - - - - - Passed and finished - - - - - - - - -");
|
||||||
|
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue