barely functional:
parent
dae1d8cf6a
commit
b5393ea01f
|
@ -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
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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)
|
||||||
|
|
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!");
|
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;
|
||||||
}
|
}
|
102
src/main.cpp
102
src/main.cpp
|
@ -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;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
index = choice();
|
||||||
auto& v = pop[index];
|
auto& v = pop[index];
|
||||||
if (n != v.t.get() && v.fitness > fitness)
|
if (v.fitness >= fitness)
|
||||||
{
|
{
|
||||||
n = v.t.get();
|
n = v.t.get();
|
||||||
fitness = v.fitness;
|
fitness = v.fitness;
|
||||||
if (out != nullptr)
|
|
||||||
*out = index;
|
|
||||||
}
|
}
|
||||||
|
//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,34 +293,38 @@ 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++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
BLT_TRACE("Running Mutation");
|
BLT_TRACE("Running Mutation");
|
||||||
for (blt::size_t i = 0; i < POPULATION_SIZE; i++)
|
for (blt::size_t i = 0; i < POPULATION_SIZE; i++)
|
||||||
{
|
{
|
||||||
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)
|
||||||
|
|
Loading…
Reference in New Issue