From b5393ea01fa3b5b19ec049e18f6fef9dddf62bed Mon Sep 17 00:00:00 2001 From: Brett Laptop Date: Tue, 30 Jan 2024 14:49:39 -0500 Subject: [PATCH] barely functional: --- include/config.h | 6 +-- include/gp.h | 4 ++ src/functions.cpp | 2 +- src/gp.cpp | 14 +++--- src/main.cpp | 110 ++++++++++++++++++++++++++++++---------------- 5 files changed, 90 insertions(+), 46 deletions(-) diff --git a/include/config.h b/include/config.h index b1e8a0a..0d95505 100644 --- a/include/config.h +++ b/include/config.h @@ -24,10 +24,10 @@ inline constexpr blt::i32 MIN_DEPTH = 3; inline constexpr blt::i32 MAX_DEPTH = 12; inline constexpr blt::i32 width = 256, height = 256; -inline constexpr blt::i32 POPULATION_SIZE = 20; +inline constexpr blt::i32 POPULATION_SIZE = 50; inline constexpr blt::i32 GEN_COUNT = 20; -inline constexpr blt::i32 TOURNAMENT_SIZE = 3; +inline constexpr blt::i32 TOURNAMENT_SIZE = 4; inline constexpr float CROSSOVER_RATE = 0.9; -inline constexpr float MUTATION_RATE = 0.1; +inline constexpr float MUTATION_RATE = 0.25; #endif //GP_IMAGE_TEST_CONFIG_H diff --git a/include/gp.h b/include/gp.h index fa40926..dd6d6b0 100644 --- a/include/gp.h +++ b/include/gp.h @@ -24,9 +24,11 @@ #include struct node; + class tree; node* createNode(function_t type); + void destroyNode(node* n); struct node @@ -67,6 +69,8 @@ struct node node(const node& copy); + node* clone(); + static node* construct_random_tree(blt::size_t max_depth = MAX_DEPTH); void evaluate(); diff --git a/src/functions.cpp b/src/functions.cpp index 6f41926..d0474cd 100644 --- a/src/functions.cpp +++ b/src/functions.cpp @@ -290,7 +290,7 @@ float eval_DNF_SW_1(const image& img) std::sort(order.begin(), order.end()); - blt::size_t len = width / 4; + blt::size_t len = width; blt::size_t current_pos = 0; double total = 0; while (true) diff --git a/src/gp.cpp b/src/gp.cpp index 91fac9b..56d3092 100644 --- a/src/gp.cpp +++ b/src/gp.cpp @@ -200,9 +200,13 @@ node::node(const node& copy) static_assert(sizeof(data_t) == sizeof(float) * 3 && "Uhhh something is wrong here!"); std::memcpy(data.data(), copy.data.data(), sizeof(data_t)); for (blt::size_t i = 0; i < argc; i++) - { - sub_nodes[i] = node_allocator.allocate(1); - // tee hee - ::new(&sub_nodes[i]) node(*copy.sub_nodes[i]); - } + sub_nodes[i] = copy.sub_nodes[i]->clone(); } + +node* node::clone() +{ + auto np = node_allocator.allocate(1); + // tee hee + ::new(np) node(*this); + return np; +} \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index 2744164..cbc4ec7 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -29,6 +29,15 @@ class tree node* parent; blt::size_t index; }; + struct crossover_result_t + { + std::unique_ptr c1; + std::unique_ptr c2; + }; + struct mutation_result_t + { + std::unique_ptr c; + }; private: std::unique_ptr root = nullptr; @@ -92,6 +101,11 @@ class tree } public: + std::unique_ptr clone() + { + return std::make_unique(tree{root->clone()}); + } + static std::unique_ptr construct_random_tree() { return std::make_unique(tree{node::construct_random_tree()}); @@ -123,47 +137,54 @@ class tree return max_depth; } - static bool crossover(tree* p1, tree* p2) + static std::optional crossover(tree* p1, tree* p2) { if (p1 == nullptr || p2 == nullptr) - return false; - auto n1 = p1->select_random_child(); - auto n2 = p2->select_random_child(); + return {}; + auto c1 = p1->clone(); + auto c2 = p2->clone(); + + auto n1 = c1->select_random_child(); + auto n2 = c2->select_random_child(); if (n1.parent == nullptr || n2.parent == nullptr) - return false; + return {}; const auto& p1_allowed = function_arg_allowed_set_map[to_underlying(n1.parent->type)][n1.index]; const auto& p2_allowed = function_arg_allowed_set_map[to_underlying(n2.parent->type)][n2.index]; if (!p1_allowed.contains(n2.child->type)) - return false; + return {}; if (!p2_allowed.contains(n1.child->type)) - return false; + return {}; n1.parent->sub_nodes[n1.index] = n2.child; n2.parent->sub_nodes[n2.index] = n1.child; - return true; + return crossover_result_t{std::move(c1), std::move(c2)}; } - static bool mutate(tree* p) + static std::optional mutate(tree* p) { + if (p == nullptr) + return {}; static std::random_device dev; static std::mt19937_64 engine{dev()}; std::uniform_int_distribution choice(0, 1); - auto n = p->select_random_child(); + auto c = p->clone(); + + auto n = c->select_random_child(); if (n.parent == nullptr) - return false; + return {}; auto d = depth(n.child); node* new_subtree = node::construct_random_tree(d + 1); n.parent->sub_nodes[n.index] = new_subtree; destroyNode(n.child); - return true; + return mutation_result_t{std::move(c)}; } void evaluate() @@ -229,31 +250,42 @@ class gp_population evaluate_population(); } - tree* select(blt::size_t* out = nullptr) + tree* select() { tree* n = nullptr; - float fitness = 0; + float fitness = -2 * 8192; + //BLT_TRACE("With inital %f", fitness); for (int i = 0; i < TOURNAMENT_SIZE; i++) { - auto index = choice(); - auto& v = pop[index]; - if (n != v.t.get() && v.fitness > fitness) + blt::size_t index = 0; + do { - n = v.t.get(); - fitness = v.fitness; - if (out != nullptr) - *out = index; - } + index = choice(); + auto& v = pop[index]; + if (v.fitness >= fitness) + { + n = v.t.get(); + fitness = v.fitness; + } + //BLT_TRACE("%d: %p -> %f ? %p -> %f || %d %d", index, v.t.get(), v.fitness, n, fitness, n != v.t.get(), v.fitness > fitness); + } while (n == pop[index].t.get()); } + //BLT_DEBUG("%p -> %f", n, fitness); + BLT_ASSERT(n != nullptr); return n; } void run_step() { + std::array new_pop; static std::random_device dev; static std::mt19937_64 engine{dev()}; static std::uniform_real_distribution rand(0.0, 1.0); + auto b = get_best(); + new_pop[0] = {pop[b.first].t->clone(), b.second}; + blt::size_t insert_pos = 1; + blt::size_t crossover_count = 0; blt::size_t mutation_count = 0; BLT_TRACE("Running Crossover"); @@ -261,16 +293,15 @@ class gp_population { if (rand(engine) < CROSSOVER_RATE) { - blt::size_t i1 = -1, i2 = -1; - auto* p1 = select(&i1); - auto* p2 = select(&i2); + auto* p1 = select(); + auto* p2 = select(); - // do not crossover the elite - if (i1 == best || i2 == best) - continue; - - if (tree::crossover(p1, p2)) + if (auto r = tree::crossover(p1, p2)) + { + new_pop[insert_pos++] = {std::move(r->c1)}; + new_pop[insert_pos++] = {std::move(r->c2)}; crossover_count++; + } } } @@ -279,16 +310,21 @@ class gp_population { if (rand(engine) < MUTATION_RATE) { - blt::size_t i1 = 0; - auto* p1 = select(&i1); + auto* p1 = select(); - if (i1 == best) - continue; - - if(tree::mutate(p1)) + if (auto r = tree::mutate(p1)) + { + new_pop[insert_pos++] = {std::move(r->c)}; mutation_count++; + } } } + + while (insert_pos < POPULATION_SIZE) + { + new_pop[insert_pos++] = {select()->clone()}; + } + pop = std::move(new_pop); BLT_TRACE("ran %d crossovers and %d mutations", crossover_count, mutation_count); } @@ -311,7 +347,7 @@ class gp_population std::pair get_best() { blt::size_t i = 0; - float fitness = 0; + float fitness = -2 * 8192; for (blt::size_t j = 0; j < POPULATION_SIZE; j++) { if (pop[j].fitness > fitness)