diff --git a/include/config.h b/include/config.h index 6085b6e..b1e8a0a 100644 --- a/include/config.h +++ b/include/config.h @@ -21,12 +21,13 @@ #include +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 GEN_COUNT = 20; inline constexpr blt::i32 TOURNAMENT_SIZE = 3; inline constexpr float CROSSOVER_RATE = 0.9; -inline constexpr float MUTATION_RATE = 0.9; +inline constexpr float MUTATION_RATE = 0.1; #endif //GP_IMAGE_TEST_CONFIG_H diff --git a/include/functions.h b/include/functions.h index 091e8d3..37a918a 100644 --- a/include/functions.h +++ b/include/functions.h @@ -244,8 +244,7 @@ inline static allowed_funcs intersection_comp(const allowed_funcs //bool isNan(F f) diff --git a/include/gp.h b/include/gp.h index 4a9f84a..fa40926 100644 --- a/include/gp.h +++ b/include/gp.h @@ -65,6 +65,8 @@ struct node } } + node(const node& copy); + static node* construct_random_tree(blt::size_t max_depth = MAX_DEPTH); void evaluate(); diff --git a/src/extern.cpp b/src/extern.cpp index b9b9387..ebdbcef 100644 --- a/src/extern.cpp +++ b/src/extern.cpp @@ -10,44 +10,47 @@ #include #include -const std::vector large_c { +const std::vector large_c{ 0.139E100, 0.157E100, 0.175E100, 0.256E100, 0.344E100, 0.413E100, 0.503E100, 0.577E100, 0.614E100, 0.655E100, 0.954E100, 1.392E100, 1.557E100, 1.648E100, 1.690E100, 1.994E100, 2.174E100, 2.206E100, 3.245E100, 3.510E100, 3.571E100, 4.354E100, 4.980E100, 6.084E100, 8.351E100}; -const std::vector normally_c {-0.4417998157703872, - -0.310841224215176, - -0.2544758389229413, - -0.21509882047762266, - -0.18254731741828356, - -0.1541570107663562, - -0.12852819470327187, - -0.1048199468783084, - -0.08247628697708857, - -0.061100278634889656, - -0.040388574421146996, - -0.020093702456713224, - 0.0, - 0.020093702456713224, - 0.040388574421146996, - 0.061100278634889656, - 0.08247628697708857, - 0.1048199468783084, - 0.12852819470327187, - 0.1541570107663562, - 0.18254731741828356, - 0.21509882047762266, - 0.2544758389229413, - 0.310841224215176, - 0.4417998157703872}; +const std::vector normally_c{-0.4417998157703872, + -0.310841224215176, + -0.2544758389229413, + -0.21509882047762266, + -0.18254731741828356, + -0.1541570107663562, + -0.12852819470327187, + -0.1048199468783084, + -0.08247628697708857, + -0.061100278634889656, + -0.040388574421146996, + -0.020093702456713224, + 0.0, + 0.020093702456713224, + 0.040388574421146996, + 0.061100278634889656, + 0.08247628697708857, + 0.1048199468783084, + 0.12852819470327187, + 0.1541570107663562, + 0.18254731741828356, + 0.21509882047762266, + 0.2544758389229413, + 0.310841224215176, + 0.4417998157703872}; -const std::vector nearly_c { +const std::vector nearly_c{ -0.44, -0.31, -0.25, -0.21, -0.18, -0.15, -0.12, -0.10, -0.08, -0.06, -0.04, -0.02, 0.0, 0.02, 0.04, 0.06, 0.08, 0.10, 0.12, 0.15, 0.18, 0.21, 0.25, 0.31, 0.44}; +const auto runs = 500000; + #undef BLT_DEBUG #define BLT_DEBUG(...) + void shapiro_test_local() { auto normally = normally_c; @@ -57,21 +60,26 @@ void shapiro_test_local() std::sort(normally.begin(), normally.end()); std::sort(nearly.begin(), nearly.end()); std::sort(large.begin(), large.end()); - - willbruh w1(normally); - BLT_ASSERT(w1->estimate == 0.9999999999999999); - BLT_ASSERT(w1->p_value == 1.0); - BLT_DEBUG("%f // %f", w1->estimate, w1->p_value); - willbruh w2(nearly); - BLT_ASSERT(w2->estimate == 0.9997987717271388); - BLT_ASSERT(w2->p_value == 1.0); - BLT_DEBUG("%f // %f", w2->estimate, w2->p_value); - - willbruh w3(large); - BLT_ASSERT(w3->estimate == 0.8346662753181684); - BLT_ASSERT(w3->p_value == 0.0009134904817755807); - BLT_DEBUG("%f // %f", w3->estimate, w3->p_value); + BLT_START_INTERVAL("shapiro", "local_sorted"); + for (size_t i = 0; i < runs; i++) + { + willbruh w1(normally); + BLT_ASSERT(w1->estimate == 0.9999999999999999); + BLT_ASSERT(w1->p_value == 1.0); + BLT_DEBUG("%f // %f", w1->estimate, w1->p_value); + + willbruh w2(nearly); + BLT_ASSERT(w2->estimate == 0.9997987717271388); + BLT_ASSERT(w2->p_value == 1.0); + BLT_DEBUG("%f // %f", w2->estimate, w2->p_value); + + willbruh w3(large); + BLT_ASSERT(w3->estimate == 0.8346662753181684); + BLT_ASSERT(w3->p_value == 0.0009134904817755807); + BLT_DEBUG("%f // %f", w3->estimate, w3->p_value); + } + BLT_END_INTERVAL("shapiro", "local_sorted"); } void shapiro_test_unsorted() @@ -80,20 +88,25 @@ void shapiro_test_unsorted() auto nearly = nearly_c; auto large = large_c; - willbruh w1(willbert_unsorted(normally.data(), normally.size())); - BLT_ASSERT(w1->estimate == 0.9999999999999999); - BLT_ASSERT(w1->p_value == 1.0); - BLT_DEBUG("%f // %f", w1->estimate, w1->p_value); - - willbruh w2(willbert_unsorted(nearly.data(), nearly.size())); - BLT_ASSERT(w2->estimate == 0.9997987717271388); - BLT_ASSERT(w2->p_value == 1.0); - BLT_DEBUG("%f // %f", w2->estimate, w2->p_value); - - willbruh w3(willbert_unsorted(large.data(), large.size())); - BLT_ASSERT(w3->estimate == 0.8346662753181684); - BLT_ASSERT(w3->p_value == 0.0009134904817755807); - BLT_DEBUG("%f // %f", w3->estimate, w3->p_value); + BLT_START_INTERVAL("shapiro", "unsorted_mut"); + for (int i = 0; i < runs; i++) + { + willbruh w1(willbert_unsorted(normally.data(), normally.size())); + BLT_ASSERT(w1->estimate == 0.9999999999999999); + BLT_ASSERT(w1->p_value == 1.0); + BLT_DEBUG("%f // %f", w1->estimate, w1->p_value); + + willbruh w2(willbert_unsorted(nearly.data(), nearly.size())); + BLT_ASSERT(w2->estimate == 0.9997987717271388); + BLT_ASSERT(w2->p_value == 1.0); + BLT_DEBUG("%f // %f", w2->estimate, w2->p_value); + + willbruh w3(willbert_unsorted(large.data(), large.size())); + BLT_ASSERT(w3->estimate == 0.8346662753181684); + BLT_ASSERT(w3->p_value == 0.0009134904817755807); + BLT_DEBUG("%f // %f", w3->estimate, w3->p_value); + } + BLT_END_INTERVAL("shapiro", "unsorted_mut"); } void shapiro_test_copy() @@ -102,36 +115,32 @@ void shapiro_test_copy() auto nearly = nearly_c; auto large = large_c; - willbruh w1(willbert_unsorted_copy(normally.data(), normally.size())); - BLT_ASSERT(w1->estimate == 0.9999999999999999); - BLT_ASSERT(w1->p_value == 1.0); - BLT_DEBUG("%f // %f", w1->estimate, w1->p_value); - - willbruh w2(willbert_unsorted_copy(nearly.data(), nearly.size())); - BLT_ASSERT(w2->estimate == 0.9997987717271388); - BLT_ASSERT(w2->p_value == 1.0); - BLT_DEBUG("%f // %f", w2->estimate, w2->p_value); - - willbruh w3(willbert_unsorted_copy(large.data(), large.size())); - BLT_ASSERT(w3->estimate == 0.8346662753181684); - BLT_ASSERT(w3->p_value == 0.0009134904817755807); - BLT_DEBUG("%f // %f", w3->estimate, w3->p_value); + BLT_START_INTERVAL("shapiro", "copy"); + for (int i = 0; i < runs; i++) + { + willbruh w1(willbert_unsorted_copy(normally.data(), normally.size())); + BLT_ASSERT(w1->estimate == 0.9999999999999999); + BLT_ASSERT(w1->p_value == 1.0); + BLT_DEBUG("%f // %f", w1->estimate, w1->p_value); + + willbruh w2(willbert_unsorted_copy(nearly.data(), nearly.size())); + BLT_ASSERT(w2->estimate == 0.9997987717271388); + BLT_ASSERT(w2->p_value == 1.0); + BLT_DEBUG("%f // %f", w2->estimate, w2->p_value); + + willbruh w3(willbert_unsorted_copy(large.data(), large.size())); + BLT_ASSERT(w3->estimate == 0.8346662753181684); + BLT_ASSERT(w3->p_value == 0.0009134904817755807); + BLT_DEBUG("%f // %f", w3->estimate, w3->p_value); + } + BLT_END_INTERVAL("shapiro", "copy"); } void shapiro_test_run() { - const auto runs = 500000; - BLT_START_INTERVAL("shapiro", "copy"); - for (size_t i = 0; i < runs; i++) - shapiro_test_copy(); - BLT_END_INTERVAL("shapiro", "copy"); - BLT_START_INTERVAL("shapiro", "unsorted_mut"); - for (size_t i = 0; i < runs; i++) - shapiro_test_unsorted(); - BLT_END_INTERVAL("shapiro", "unsorted_mut"); - BLT_START_INTERVAL("shapiro", "local_sorted"); - for (size_t i = 0; i < runs; i++) - shapiro_test_local(); - BLT_END_INTERVAL("shapiro", "local_sorted"); + + shapiro_test_copy(); + shapiro_test_unsorted(); + shapiro_test_local(); BLT_PRINT_PROFILE("shapiro"); } diff --git a/src/functions.cpp b/src/functions.cpp index 385e2fc..6f41926 100644 --- a/src/functions.cpp +++ b/src/functions.cpp @@ -281,8 +281,30 @@ float eval_DNF_SW(const image& img) return static_cast(total); } -float eval_DNF_KS(const image& img) +float eval_DNF_SW_1(const image& img) { - return 0; + std::vector order(width * height); + + for (const auto& v : img.getData()) + order.push_back(v.magnitude()); + + std::sort(order.begin(), order.end()); + + blt::size_t len = width / 4; + blt::size_t current_pos = 0; + double total = 0; + while (true) + { + if (order.size() - current_pos < len) + { + len = order.size() - current_pos; + if (len <= 0) + break; + } + total += on_data(order.data() + current_pos, len); + current_pos += len; + } + + return static_cast(total); } diff --git a/src/gp.cpp b/src/gp.cpp index 55047b6..91fac9b 100644 --- a/src/gp.cpp +++ b/src/gp.cpp @@ -148,7 +148,7 @@ node* node::construct_random_tree(blt::size_t max_depth) if (front.second != current_depth) current_depth++; - if (choice(engine)) + if (choice(engine) && current_depth >= MIN_DEPTH) front.first->grow(front.second >= max_depth); else front.first->full(front.second >= max_depth); @@ -192,3 +192,17 @@ void node::evaluate() } #undef FUNC_DEFINE } + +node::node(const node& copy) +{ + argc = copy.argc; + type = copy.type; + 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]); + } +} diff --git a/src/main.cpp b/src/main.cpp index 9365b87..2744164 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -109,6 +109,7 @@ class tree auto top = stack.top(); auto* node = top.second; auto depth = top.first; + stack.pop(); max_depth = std::max(max_depth, depth); for (blt::size_t i = 0; i < node->argc; i++) { @@ -117,7 +118,6 @@ class tree stack.emplace(depth + 1, node->sub_nodes[i]); } } - stack.pop(); } return max_depth; @@ -125,9 +125,14 @@ class tree static bool crossover(tree* p1, tree* p2) { + if (p1 == nullptr || p2 == nullptr) + return false; auto n1 = p1->select_random_child(); auto n2 = p2->select_random_child(); + if (n1.parent == nullptr || n2.parent == nullptr) + return false; + 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]; @@ -142,7 +147,7 @@ class tree return true; } - static void mutate(tree* p) + static bool mutate(tree* p) { static std::random_device dev; static std::mt19937_64 engine{dev()}; @@ -150,11 +155,15 @@ class tree auto n = p->select_random_child(); + if (n.parent == nullptr) + return false; + 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; } void evaluate() @@ -180,7 +189,8 @@ class tree float fitness() { - return eval_DNF_SW(root->getImage()); + auto& img = root->getImage(); + return eval_DNF_SW(img) * eval_DNF_SW_1(img); } void printTree() @@ -197,6 +207,7 @@ class gp_population std::unique_ptr t = nullptr; float fitness = 0; }; + blt::size_t best = -1; private: std::array pop; public: @@ -218,17 +229,20 @@ class gp_population evaluate_population(); } - tree* select() + tree* select(blt::size_t* out = nullptr) { tree* n = nullptr; float fitness = 0; for (int i = 0; i < TOURNAMENT_SIZE; i++) { - auto& v = pop[choice()]; + auto index = choice(); + auto& v = pop[index]; if (n != v.t.get() && v.fitness > fitness) { n = v.t.get(); fitness = v.fitness; + if (out != nullptr) + *out = index; } } return n; @@ -240,35 +254,53 @@ class gp_population static std::mt19937_64 engine{dev()}; static std::uniform_real_distribution rand(0.0, 1.0); + blt::size_t crossover_count = 0; + blt::size_t mutation_count = 0; + BLT_TRACE("Running Crossover"); for (blt::size_t i = 0; i < POPULATION_SIZE; i++) { if (rand(engine) < CROSSOVER_RATE) { - auto* p1 = select(); - auto* p2 = select(); + blt::size_t i1 = -1, i2 = -1; + auto* p1 = select(&i1); + auto* p2 = select(&i2); - tree::crossover(p1, p2); + // do not crossover the elite + if (i1 == best || i2 == best) + continue; + + if (tree::crossover(p1, p2)) + crossover_count++; } } + BLT_TRACE("Running Mutation"); for (blt::size_t i = 0; i < POPULATION_SIZE; i++) { if (rand(engine) < MUTATION_RATE) { - auto* p1 = select(); + blt::size_t i1 = 0; + auto* p1 = select(&i1); - tree::mutate(p1); + if (i1 == best) + continue; + + if(tree::mutate(p1)) + mutation_count++; } } + BLT_TRACE("ran %d crossovers and %d mutations", crossover_count, mutation_count); } void evaluate_population() { + BLT_TRACE("Running Eval"); for (auto& v : pop) { v.t->evaluate(); v.fitness = v.t->fitness(); } + BLT_TRACE("Complete"); } image& display(blt::size_t i) @@ -288,6 +320,7 @@ class gp_population fitness = pop[j].fitness; } } + best = i; return {i, fitness}; } @@ -341,6 +374,7 @@ void update(std::int32_t w, std::int32_t h) if (ImGui::Button("Regenerate")) { BLT_INFO("Regen tree"); + pop = {}; pop.init(); best = pop.best_fitness(); } @@ -358,10 +392,6 @@ void update(std::int32_t w, std::int32_t h) { BLT_INFO("Uploading"); texture->upload((void*) pop.display_best().getData().data(), GL_RGB, 0, 0, 0, -1, -1, GL_FLOAT); - - ; -// if (test_tree->hasTree()) -// test_tree->printTree(); } ImGui::Text("Best Fitness: %f", best);