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 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

View File

@ -24,9 +24,11 @@
#include <random>
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();

View File

@ -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)

View File

@ -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;
}

View File

@ -29,6 +29,15 @@ class tree
node* parent;
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:
std::unique_ptr<node, node_deleter> root = nullptr;
@ -92,6 +101,11 @@ class tree
}
public:
std::unique_ptr<tree> clone()
{
return std::make_unique<tree>(tree{root->clone()});
}
static std::unique_ptr<tree> construct_random_tree()
{
return std::make_unique<tree>(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_result_t> 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<mutation_result_t> 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<gp_i, POPULATION_SIZE> 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<blt::size_t, float> 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)