barely functional:
parent
dae1d8cf6a
commit
b5393ea01f
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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)
|
||||
|
|
14
src/gp.cpp
14
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;
|
||||
}
|
110
src/main.cpp
110
src/main.cpp
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue