diff --git a/CMakeLists.txt b/CMakeLists.txt index 8d3fe00..1232fc6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 3.25) -project(image-gp-6 VERSION 0.0.20) +project(image-gp-6 VERSION 0.0.21) include(FetchContent) diff --git a/include/config.h b/include/config.h index 3f60150..ae49026 100644 --- a/include/config.h +++ b/include/config.h @@ -19,13 +19,15 @@ #ifndef IMAGE_GP_6_CONFIG_H #define IMAGE_GP_6_CONFIG_H +#include + inline constexpr size_t log2(size_t n) // NOLINT { return ((n < 2) ? 1 : 1 + log2(n / 2)); } -//inline const blt::u64 SEED = std::random_device()(); -inline const blt::u64 SEED = 553372510; +inline const blt::u64 SEED = std::random_device()(); +//inline const blt::u64 SEED = 553372510; inline constexpr blt::size_t IMAGE_SIZE = 128; inline constexpr blt::size_t IMAGE_PADDING = 16; inline constexpr blt::size_t POP_SIZE = 64; @@ -35,9 +37,15 @@ inline constexpr blt::size_t DATA_CHANNELS_SIZE = DATA_SIZE * CHANNELS; inline constexpr blt::size_t BOX_COUNT = static_cast(log2(IMAGE_SIZE / 2)); inline constexpr float THRESHOLD = 0.3; inline constexpr auto load_image = "../GSab4SWWcAA1TNR.png"; + +inline blt::gp::image_crossover_t image_crossover; +inline blt::gp::image_mutation_t image_mutation; + //inline constexpr auto load_image = "../miles.png"; inline blt::gp::prog_config_t config = blt::gp::prog_config_t() + .set_crossover(image_crossover) + .set_mutation(image_mutation) .set_initial_min_tree_size(4) .set_initial_max_tree_size(8) .set_elite_count(2) diff --git a/include/custom_transformer.h b/include/custom_transformer.h index 0a3b550..c5a5830 100644 --- a/include/custom_transformer.h +++ b/include/custom_transformer.h @@ -19,4 +19,80 @@ #ifndef IMAGE_GP_6_CUSTOM_TRANSFORMER_H #define IMAGE_GP_6_CUSTOM_TRANSFORMER_H +#include + +namespace blt::gp +{ + template + inline static constexpr double sum(const T& array) + { + double init = 0.0; + for (double i : array) + init += i; + return init; + } + + template + static constexpr std::array aggregate_array(Args... list) + { + std::array data {list...}; + auto total_prob = sum(data); + double sum_of_prob = 0; + for (auto& d : data) { + auto prob = d / total_prob; + d = prob + sum_of_prob; + sum_of_prob += prob; + } + return data; + } + + class image_crossover_t : public crossover_t + { + public: + image_crossover_t() = default; + + explicit image_crossover_t(const config_t& config): crossover_t(config) + {} + + blt::expected apply(gp_program& program, const tree_t& p1, const tree_t& p2) final; + }; + + class image_mutation_t : public mutation_t + { + public: + enum class mutation_operator : blt::i32 + { + EXPRESSION, // Generate a new random expression + ADJUST, // adjust the value of the type. + 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. + JUMP_FUNC, // subexpression becomes this new node. Other arguments discarded. + COPY, // node can become copy of another subexpression. + END, // helper + }; + + image_mutation_t() = default; + + explicit image_mutation_t(const config_t& config): mutation_t(config) + {} + + tree_t apply(gp_program& program, const tree_t& p) final; + + private: + static constexpr auto operators_size = static_cast(mutation_operator::END); + private: + // this value is adjusted inversely to the size of the tree. + double per_node_mutation_chance = 1.0; + + static constexpr std::array mutation_operator_chances = aggregate_array( + 0.01, // EXPRESSION + 0.11, // ADJUST + 0.05, // FUNC + 0.01, // SUB_FUNC + 0.1, // JUMP_FUNC + 0.05 // COPY + ); + }; +} + #endif //IMAGE_GP_6_CUSTOM_TRANSFORMER_H diff --git a/include/helper.h b/include/helper.h index d023391..3481504 100644 --- a/include/helper.h +++ b/include/helper.h @@ -20,6 +20,7 @@ #define IMAGE_GP_6_HELPER_H #include +#include template constexpr static auto make_single(SINGLE_FUNC&& func) diff --git a/include/image_operations.h b/include/image_operations.h index 330939b..0998569 100644 --- a/include/image_operations.h +++ b/include/image_operations.h @@ -16,9 +16,11 @@ * along with this program. If not, see . */ +#include #include #include #include +#include #ifndef IMAGE_GP_6_IMAGE_OPERATIONS_H #define IMAGE_GP_6_IMAGE_OPERATIONS_H diff --git a/include/images.h b/include/images.h index 5e39812..73772aa 100644 --- a/include/images.h +++ b/include/images.h @@ -20,6 +20,9 @@ #define IMAGE_GP_6_IMAGES_H #include +#include +#include +#include struct full_image_t { diff --git a/lib/blt-gp b/lib/blt-gp index 593e02b..b10b438 160000 --- a/lib/blt-gp +++ b/lib/blt-gp @@ -1 +1 @@ -Subproject commit 593e02b6ffd36cfabda85e9dcfd88ec60b8a8741 +Subproject commit b10b4388897b1673b0dbe84b1db34584db0e9660 diff --git a/meow.jpg b/meow.jpg new file mode 100644 index 0000000..366ed0a Binary files /dev/null and b/meow.jpg differ diff --git a/src/custom_transformer.cpp b/src/custom_transformer.cpp index ebd4c47..18481b9 100644 --- a/src/custom_transformer.cpp +++ b/src/custom_transformer.cpp @@ -15,4 +15,132 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -#include \ No newline at end of file +#include +#include +#include +#include +#include + +namespace blt::gp +{ + + blt::expected image_crossover_t::apply(gp_program& program, const tree_t& p1, const tree_t& p2) + { + return crossover_t::apply(program, p1, p2); + } + + + tree_t image_mutation_t::apply(gp_program& program, const tree_t& p) + { + // child tree + tree_t c = p; + + auto& ops = c.get_operations(); + auto& vals = c.get_values(); + + double node_mutation_chance = per_node_mutation_chance * (1.0 / static_cast(ops.size())); + + for (blt::size_t c_node = 0; c_node < ops.size(); c_node++) + { + if (!program.get_random().choice(node_mutation_chance)) + continue; + auto selected_point = static_cast(mutation_operator::COPY); + auto choice = program.get_random().get_double(); + + for (const auto& [index, value] : blt::enumerate(mutation_operator_chances)) + { + if (index == 0) + { + if (choice <= value) + { + selected_point = static_cast(index); + break; + } + } else + { + if (choice > mutation_operator_chances[index - 1] && choice <= value) + { + selected_point = static_cast(index); + break; + } + } + } + + switch (static_cast(selected_point)) + { + case mutation_operator::EXPRESSION: + c_node += mutate_point(program, c, c_node); + break; + case mutation_operator::ADJUST: + { + // this is going to be evil >:3 + const auto& node = ops[c_node]; + if (node.is_value) + { + blt::size_t bytes_from_head = 0; + for (auto it = ops.begin() + static_cast(c_node) + 1; it != ops.end(); it++) + bytes_from_head += it->is_value ? stack_allocator::aligned_size(it->type_size) : 0; + // is a float + if (node.type_size == sizeof(float)) + { + auto& val = vals.from(bytes_from_head); + auto old = val; + val += f_literal.get_function()(); + val /= 2.0f; + if (std::isnan(val)) + val = old; + } else // is an image + { + auto& val = vals.from(bytes_from_head); + auto type = program.get_typesystem().get_type(); + auto& terminals = program.get_type_terminals(type.id()); + + // Annoying. TODO: fix all of this. + operator_id id; + do{ + id = program.get_random().select(terminals); + } while(!program.is_static(id)); + + stack_allocator stack; + + program.get_operator_info(id).function(nullptr, stack, stack); + + //auto adjustment = lit.get_function()(); + auto& adjustment = stack.from(0); + + for (const auto& [index, value] : blt::enumerate(val.rgb_data)) + { + auto old = value; + // add and normalize. + value += adjustment.rgb_data[index]; + value /= 2.0f; + if (std::isnan(value)) + value = old; + } + } + } + } + break; + case mutation_operator::FUNC: + break; + case mutation_operator::SUB_FUNC: + break; + case mutation_operator::JUMP_FUNC: + break; + case mutation_operator::COPY: + break; + case mutation_operator::END: + default: +#if BLT_DEBUG_LEVEL > 1 + BLT_ABORT("You shouldn't be able to get here!"); +#else + BLT_UNREACHABLE; +#endif + } + } + + return c; + } + +} + diff --git a/src/main.cpp b/src/main.cpp index f107706..d0a55f0 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -22,10 +22,6 @@ #include #include #include -#include -#include -#include -#include #include #include "blt/gfx/renderer/resource_manager.h" #include "blt/gfx/renderer/batch_2d_renderer.h"