barely functional:

main
Brett 2024-01-30 14:49:39 -05:00
parent dae1d8cf6a
commit b5393ea01f
5 changed files with 90 additions and 46 deletions

View File

@ -24,10 +24,10 @@
inline constexpr blt::i32 MIN_DEPTH = 3; inline constexpr blt::i32 MIN_DEPTH = 3;
inline constexpr blt::i32 MAX_DEPTH = 12; inline constexpr blt::i32 MAX_DEPTH = 12;
inline constexpr blt::i32 width = 256, height = 256; 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 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 CROSSOVER_RATE = 0.9;
inline constexpr float MUTATION_RATE = 0.1; inline constexpr float MUTATION_RATE = 0.25;
#endif //GP_IMAGE_TEST_CONFIG_H #endif //GP_IMAGE_TEST_CONFIG_H

View File

@ -24,9 +24,11 @@
#include <random> #include <random>
struct node; struct node;
class tree; class tree;
node* createNode(function_t type); node* createNode(function_t type);
void destroyNode(node* n); void destroyNode(node* n);
struct node struct node
@ -67,6 +69,8 @@ struct node
node(const node& copy); node(const node& copy);
node* clone();
static node* construct_random_tree(blt::size_t max_depth = MAX_DEPTH); static node* construct_random_tree(blt::size_t max_depth = MAX_DEPTH);
void evaluate(); void evaluate();

View File

@ -290,7 +290,7 @@ float eval_DNF_SW_1(const image& img)
std::sort(order.begin(), order.end()); std::sort(order.begin(), order.end());
blt::size_t len = width / 4; blt::size_t len = width;
blt::size_t current_pos = 0; blt::size_t current_pos = 0;
double total = 0; double total = 0;
while (true) while (true)

View File

@ -200,9 +200,13 @@ node::node(const node& copy)
static_assert(sizeof(data_t) == sizeof(float) * 3 && "Uhhh something is wrong here!"); static_assert(sizeof(data_t) == sizeof(float) * 3 && "Uhhh something is wrong here!");
std::memcpy(data.data(), copy.data.data(), sizeof(data_t)); std::memcpy(data.data(), copy.data.data(), sizeof(data_t));
for (blt::size_t i = 0; i < argc; i++) for (blt::size_t i = 0; i < argc; i++)
{ sub_nodes[i] = copy.sub_nodes[i]->clone();
sub_nodes[i] = node_allocator.allocate(1); }
// tee hee
::new(&sub_nodes[i]) node(*copy.sub_nodes[i]); node* node::clone()
} {
auto np = node_allocator.allocate(1);
// tee hee
::new(np) node(*this);
return np;
} }

View File

@ -29,6 +29,15 @@ class tree
node* parent; node* parent;
blt::size_t index; blt::size_t index;
}; };
struct crossover_result_t
{
std::unique_ptr<tree> c1;
std::unique_ptr<tree> c2;
};
struct mutation_result_t
{
std::unique_ptr<tree> c;
};
private: private:
std::unique_ptr<node, node_deleter> root = nullptr; std::unique_ptr<node, node_deleter> root = nullptr;
@ -92,6 +101,11 @@ class tree
} }
public: public:
std::unique_ptr<tree> clone()
{
return std::make_unique<tree>(tree{root->clone()});
}
static std::unique_ptr<tree> construct_random_tree() static std::unique_ptr<tree> construct_random_tree()
{ {
return std::make_unique<tree>(tree{node::construct_random_tree()}); return std::make_unique<tree>(tree{node::construct_random_tree()});
@ -123,47 +137,54 @@ class tree
return max_depth; return max_depth;
} }
static bool crossover(tree* p1, tree* p2) static std::optional<crossover_result_t> crossover(tree* p1, tree* p2)
{ {
if (p1 == nullptr || p2 == nullptr) if (p1 == nullptr || p2 == nullptr)
return false; return {};
auto n1 = p1->select_random_child(); auto c1 = p1->clone();
auto n2 = p2->select_random_child(); auto c2 = p2->clone();
auto n1 = c1->select_random_child();
auto n2 = c2->select_random_child();
if (n1.parent == nullptr || n2.parent == nullptr) 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& 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]; const auto& p2_allowed = function_arg_allowed_set_map[to_underlying(n2.parent->type)][n2.index];
if (!p1_allowed.contains(n2.child->type)) if (!p1_allowed.contains(n2.child->type))
return false; return {};
if (!p2_allowed.contains(n1.child->type)) if (!p2_allowed.contains(n1.child->type))
return false; return {};
n1.parent->sub_nodes[n1.index] = n2.child; n1.parent->sub_nodes[n1.index] = n2.child;
n2.parent->sub_nodes[n2.index] = n1.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<mutation_result_t> mutate(tree* p)
{ {
if (p == nullptr)
return {};
static std::random_device dev; static std::random_device dev;
static std::mt19937_64 engine{dev()}; static std::mt19937_64 engine{dev()};
std::uniform_int_distribution choice(0, 1); 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) if (n.parent == nullptr)
return false; return {};
auto d = depth(n.child); auto d = depth(n.child);
node* new_subtree = node::construct_random_tree(d + 1); node* new_subtree = node::construct_random_tree(d + 1);
n.parent->sub_nodes[n.index] = new_subtree; n.parent->sub_nodes[n.index] = new_subtree;
destroyNode(n.child); destroyNode(n.child);
return true; return mutation_result_t{std::move(c)};
} }
void evaluate() void evaluate()
@ -229,31 +250,42 @@ class gp_population
evaluate_population(); evaluate_population();
} }
tree* select(blt::size_t* out = nullptr) tree* select()
{ {
tree* n = nullptr; tree* n = nullptr;
float fitness = 0; float fitness = -2 * 8192;
//BLT_TRACE("With inital %f", fitness);
for (int i = 0; i < TOURNAMENT_SIZE; i++) for (int i = 0; i < TOURNAMENT_SIZE; i++)
{ {
auto index = choice(); blt::size_t index = 0;
auto& v = pop[index]; do
if (n != v.t.get() && v.fitness > fitness)
{ {
n = v.t.get(); index = choice();
fitness = v.fitness; auto& v = pop[index];
if (out != nullptr) if (v.fitness >= fitness)
*out = index; {
} 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; return n;
} }
void run_step() void run_step()
{ {
std::array<gp_i, POPULATION_SIZE> new_pop;
static std::random_device dev; static std::random_device dev;
static std::mt19937_64 engine{dev()}; static std::mt19937_64 engine{dev()};
static std::uniform_real_distribution rand(0.0, 1.0); 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 crossover_count = 0;
blt::size_t mutation_count = 0; blt::size_t mutation_count = 0;
BLT_TRACE("Running Crossover"); BLT_TRACE("Running Crossover");
@ -261,16 +293,15 @@ class gp_population
{ {
if (rand(engine) < CROSSOVER_RATE) if (rand(engine) < CROSSOVER_RATE)
{ {
blt::size_t i1 = -1, i2 = -1; auto* p1 = select();
auto* p1 = select(&i1); auto* p2 = select();
auto* p2 = select(&i2);
// do not crossover the elite if (auto r = tree::crossover(p1, p2))
if (i1 == best || i2 == best) {
continue; new_pop[insert_pos++] = {std::move(r->c1)};
new_pop[insert_pos++] = {std::move(r->c2)};
if (tree::crossover(p1, p2))
crossover_count++; crossover_count++;
}
} }
} }
@ -279,16 +310,21 @@ class gp_population
{ {
if (rand(engine) < MUTATION_RATE) if (rand(engine) < MUTATION_RATE)
{ {
blt::size_t i1 = 0; auto* p1 = select();
auto* p1 = select(&i1);
if (i1 == best) if (auto r = tree::mutate(p1))
continue; {
new_pop[insert_pos++] = {std::move(r->c)};
if(tree::mutate(p1))
mutation_count++; 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); BLT_TRACE("ran %d crossovers and %d mutations", crossover_count, mutation_count);
} }
@ -311,7 +347,7 @@ class gp_population
std::pair<blt::size_t, float> get_best() std::pair<blt::size_t, float> get_best()
{ {
blt::size_t i = 0; blt::size_t i = 0;
float fitness = 0; float fitness = -2 * 8192;
for (blt::size_t j = 0; j < POPULATION_SIZE; j++) for (blt::size_t j = 0; j < POPULATION_SIZE; j++)
{ {
if (pop[j].fitness > fitness) if (pop[j].fitness > fitness)