main
parent
a8e5673555
commit
93188a6120
|
@ -1,3 +1,6 @@
|
|||
[submodule "libraries/BLT-With-Graphics-Template"]
|
||||
path = libraries/BLT-With-Graphics-Template
|
||||
url = https://git.tpgc.me/tri11paragon/BLT-With-Graphics-Template.git
|
||||
[submodule "libraries/stats"]
|
||||
path = libraries/stats
|
||||
url = https://github.com/kthohr/stats.git
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* <Short Description>
|
||||
* Copyright (C) 2024 Brett Terpstra
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef GP_IMAGE_TEST_CONFIG_H
|
||||
#define GP_IMAGE_TEST_CONFIG_H
|
||||
|
||||
#include <blt/std/types.h>
|
||||
|
||||
inline constexpr blt::i32 MAX_DEPTH = 12;
|
||||
inline constexpr blt::i32 width = 256, height = 256;
|
||||
|
||||
#endif //GP_IMAGE_TEST_CONFIG_H
|
|
@ -244,6 +244,19 @@ inline static allowed_funcs<function_t> intersection_comp(const allowed_funcs<fu
|
|||
|
||||
// distribution from normality (DFN)
|
||||
float eval_DNF_SW(const image& img);
|
||||
|
||||
float eval_DNF_KS(const image& img);
|
||||
|
||||
//template<typename F>
|
||||
//bool isNan(F f)
|
||||
//{
|
||||
// return f == std::numeric_limits<F>::quiet_NaN() || f == std::numeric_limits<F>::signaling_NaN();
|
||||
//}
|
||||
|
||||
template<typename F>
|
||||
bool isInf(F f)
|
||||
{
|
||||
return f == std::numeric_limits<F>::infinity() || f == -std::numeric_limits<F>::infinity();
|
||||
}
|
||||
|
||||
#endif //GP_IMAGE_TEST_FUNCTIONS_H
|
||||
|
|
|
@ -0,0 +1,110 @@
|
|||
/*
|
||||
* <Short Description>
|
||||
* Copyright (C) 2024 Brett Terpstra
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef GP_IMAGE_TEST_GP_H
|
||||
#define GP_IMAGE_TEST_GP_H
|
||||
|
||||
#include <config.h>
|
||||
#include <functions.h>
|
||||
#include <random>
|
||||
|
||||
struct node;
|
||||
class tree;
|
||||
|
||||
node* createNode(function_t type);
|
||||
void destroyNode(node* n);
|
||||
|
||||
struct node
|
||||
{
|
||||
friend tree;
|
||||
private:
|
||||
// only valid up to the argc
|
||||
std::array<node*, MAX_ARGS> sub_nodes{nullptr};
|
||||
size_t argc = 0;
|
||||
|
||||
function_t type = function_t::ADD;
|
||||
data_t data{};
|
||||
|
||||
std::optional<image> img;
|
||||
|
||||
void grow(bool use_terminals);
|
||||
|
||||
void full(bool use_terminals);
|
||||
|
||||
void populate_node(size_t i, std::mt19937_64& engine, const allowed_funcs<function_t>& allowed_args, bool use_terminal);
|
||||
|
||||
void print_tree();
|
||||
|
||||
public:
|
||||
explicit node(function_t type): type(type)
|
||||
{
|
||||
static thread_local std::random_device dev;
|
||||
static thread_local std::mt19937_64 engine{dev()};
|
||||
static thread_local std::uniform_real_distribution<float> dist(0.0f, 1.0f);
|
||||
if (type == function_t::SCALAR)
|
||||
data[0] = dist(engine);
|
||||
else if (type == function_t::COLOR)
|
||||
{
|
||||
for (auto& v : data)
|
||||
v = dist(engine);
|
||||
}
|
||||
}
|
||||
|
||||
static node* construct_random_tree();
|
||||
|
||||
void evaluate();
|
||||
|
||||
void evaluate_tree()
|
||||
{
|
||||
for (size_t i = 0; i < argc; i++)
|
||||
sub_nodes[i]->evaluate_tree();
|
||||
evaluate();
|
||||
}
|
||||
|
||||
void printTree()
|
||||
{
|
||||
print_tree();
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
bool hasImage()
|
||||
{
|
||||
return img.has_value();
|
||||
}
|
||||
|
||||
image& getImage()
|
||||
{
|
||||
return img.value();
|
||||
}
|
||||
|
||||
~node()
|
||||
{
|
||||
for (auto* node : sub_nodes)
|
||||
destroyNode(node);
|
||||
}
|
||||
};
|
||||
|
||||
struct node_deleter
|
||||
{
|
||||
void operator()(node* ptr)
|
||||
{
|
||||
destroyNode(ptr);
|
||||
}
|
||||
};
|
||||
|
||||
#endif //GP_IMAGE_TEST_GP_H
|
|
@ -27,8 +27,7 @@
|
|||
#include "blt/std/allocator.h"
|
||||
#include "blt/math/vectors.h"
|
||||
#include <variant>
|
||||
|
||||
inline constexpr blt::i32 width = 256, height = 256;
|
||||
#include <config.h>
|
||||
|
||||
using image_data_t = std::array<blt::vec3, width * height>;
|
||||
inline blt::area_allocator<image_data_t, 32> img_allocator;
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
Subproject commit f8dcb15ae51cce7142b239805745a0de56aa509f
|
|
@ -20,6 +20,7 @@
|
|||
#include <blt/gfx/stb/stb_perlin.h>
|
||||
#include <blt/std/memory_util.h>
|
||||
#include <extern.h>
|
||||
#include <cmath>
|
||||
|
||||
#define FUNCTION_COORD() \
|
||||
int xi = static_cast<int>(x); \
|
||||
|
@ -234,16 +235,18 @@ void f_if(image& img, float x, float y, blt::size_t argc, const image** argv, co
|
|||
|
||||
double on_data(const double* data, blt::size_t len)
|
||||
{
|
||||
static float NEGATION = -1;
|
||||
const static float NEGATION = 0;
|
||||
willbruh results(data, len);
|
||||
switch (results->error)
|
||||
{
|
||||
case 0:
|
||||
return results->estimate;
|
||||
if (!std::isnan(results->estimate))
|
||||
return results->estimate;
|
||||
return 0;
|
||||
case 1:
|
||||
BLT_INFO("Somehow we have sent more than 5000 values!");
|
||||
case -1:
|
||||
case -3:
|
||||
return 0;
|
||||
default:
|
||||
return 0;
|
||||
case -2:
|
||||
// should never consider this a valid solution / punish for having large sections of no difference
|
||||
|
|
|
@ -0,0 +1,194 @@
|
|||
/*
|
||||
* <Short Description>
|
||||
* Copyright (C) 2024 Brett Terpstra
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <gp.h>
|
||||
#include <blt/std/allocator.h>
|
||||
#include <blt/std/logging.h>
|
||||
#include <functions.h>
|
||||
#include <random>
|
||||
#include <queue>
|
||||
|
||||
blt::area_allocator<node, 32000> node_allocator;
|
||||
|
||||
node* createNode(function_t type)
|
||||
{
|
||||
auto* n = node_allocator.allocate(1);
|
||||
node_allocator.construct(n, type);
|
||||
return n;
|
||||
}
|
||||
|
||||
void destroyNode(node* n)
|
||||
{
|
||||
node_allocator.destroy(n);
|
||||
node_allocator.deallocate(n, 1);
|
||||
}
|
||||
|
||||
void node::grow(bool use_terminals)
|
||||
{
|
||||
auto min_children = function_arg_min_map[to_underlying(type)];
|
||||
auto max_children = function_arg_max_map[to_underlying(type)];
|
||||
|
||||
static thread_local std::random_device dev;
|
||||
static thread_local std::mt19937_64 engine{dev()};
|
||||
std::uniform_int_distribution<blt::i32> dist(min_children, max_children);
|
||||
static std::uniform_int_distribution<int> choice(0, 1);
|
||||
|
||||
argc = dist(engine);
|
||||
if (argc == 0)
|
||||
return;
|
||||
const auto& allowed_args_args = function_arg_allowed_map[to_underlying(type)];
|
||||
for (size_t i = 0; i < argc; i++)
|
||||
{
|
||||
// 50/50 chance to either use a terminal or use from the function list.
|
||||
populate_node(i, engine, allowed_args_args[i], choice(engine) || use_terminals);
|
||||
}
|
||||
}
|
||||
|
||||
void node::full(bool use_terminals)
|
||||
{
|
||||
static thread_local std::random_device dev;
|
||||
static thread_local std::mt19937_64 engine{dev()};
|
||||
|
||||
argc = function_arg_max_map[to_underlying(type)];
|
||||
if (argc == 0)
|
||||
return;
|
||||
|
||||
const auto& allowed_args_args = function_arg_allowed_map[to_underlying(type)];
|
||||
for (size_t i = 0; i < argc; i++)
|
||||
populate_node(i, engine, allowed_args_args[i], use_terminals);
|
||||
}
|
||||
|
||||
void node::populate_node(size_t i, std::mt19937_64& engine, const allowed_funcs<function_t>& allowed_args, bool use_terminal)
|
||||
{
|
||||
if (use_terminal)
|
||||
{
|
||||
auto terminals = intersection(allowed_args, FUNC_ALLOW_TERMINALS_SET);
|
||||
if (terminals.empty())
|
||||
{
|
||||
terminals = FUNC_ALLOW_TERMINALS;
|
||||
// BLT_INFO("%s:", function_name_map[to_underlying(type)].c_str());
|
||||
// for (auto v : allowed_args)
|
||||
// BLT_INFO(function_name_map[to_underlying(v)]);
|
||||
}
|
||||
std::uniform_int_distribution<blt::size_t> select(0, terminals.size() - 1);
|
||||
sub_nodes[i] = createNode(terminals[select(engine)]);
|
||||
} else
|
||||
{
|
||||
auto non_terminals = intersection_comp(allowed_args, FUNC_ALLOW_TERMINALS_SET);
|
||||
if (non_terminals.empty())
|
||||
{
|
||||
BLT_WARN("Empty non-terminals set! Filling from terminals!");
|
||||
std::uniform_int_distribution<blt::size_t> select(0, allowed_args.size() - 1);
|
||||
sub_nodes[i] = createNode(allowed_args[select(engine)]);
|
||||
} else
|
||||
{
|
||||
std::uniform_int_distribution<blt::size_t> select(0, non_terminals.size() - 1);
|
||||
sub_nodes[i] = createNode(non_terminals[select(engine)]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void node::print_tree()
|
||||
{
|
||||
if (argc > 0)
|
||||
std::cout << "(";
|
||||
if (argc > 0)
|
||||
std::cout << function_name_map[to_underlying(type)] << " ";
|
||||
else
|
||||
{
|
||||
if (type == function_t::SCALAR)
|
||||
{
|
||||
evaluate();
|
||||
std::cout << img->get().x() << " ";
|
||||
} else if (type == function_t::COLOR)
|
||||
{
|
||||
evaluate();
|
||||
std::cout << '{' << img->get().x() << ", " << img->get().y() << ", " << img->get().z() << "} ";
|
||||
} else
|
||||
std::cout << function_name_map[to_underlying(type)] << " ";
|
||||
}
|
||||
for (size_t i = 0; i < argc; i++)
|
||||
sub_nodes[i]->print_tree();
|
||||
if (argc > 0)
|
||||
std::cout << ") ";
|
||||
}
|
||||
|
||||
node* node::construct_random_tree()
|
||||
{
|
||||
static std::random_device dev;
|
||||
static std::mt19937_64 engine{dev()};
|
||||
std::uniform_int_distribution<int> choice(0, 1);
|
||||
|
||||
static auto NON_TERMINALS = intersection_comp(FUNC_ALLOW_ANY, FUNC_ALLOW_TERMINALS_SET);
|
||||
|
||||
std::uniform_int_distribution<int> select(0, static_cast<int>(NON_TERMINALS.size()) - 1);
|
||||
|
||||
node* n = createNode(NON_TERMINALS[select(engine)]);
|
||||
|
||||
std::queue<std::pair<node*, size_t>> grow_queue;
|
||||
size_t current_depth = 0;
|
||||
grow_queue.emplace(n, current_depth);
|
||||
while (!grow_queue.empty())
|
||||
{
|
||||
auto front = grow_queue.front();
|
||||
if (front.second != current_depth)
|
||||
current_depth++;
|
||||
|
||||
if (choice(engine))
|
||||
front.first->grow(front.second >= MAX_DEPTH);
|
||||
else
|
||||
front.first->full(front.second >= MAX_DEPTH);
|
||||
|
||||
for (size_t i = 0; i < front.first->argc; i++)
|
||||
grow_queue.emplace(front.first->sub_nodes[i], current_depth + 1);
|
||||
grow_queue.pop();
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
void node::evaluate()
|
||||
{
|
||||
img = image{};
|
||||
std::array<image*, MAX_ARGS> sub_node_images{nullptr};
|
||||
for (size_t i = 0; i < argc; i++)
|
||||
{
|
||||
BLT_ASSERT(sub_nodes[i] != nullptr && sub_nodes[i]->img.has_value() && "Node must have evaluated children!");
|
||||
sub_node_images[i] = &sub_nodes[i]->img.value();
|
||||
}
|
||||
#define FUNC_DEFINE(NAME, MIN_ARGS, MAX_ARGS, FUNC, ...) case function_t::NAME: { \
|
||||
if (FUNC_ALLOW_TERMINALS_SET.contains(function_t::NAME)){ \
|
||||
FUNC(img.value(), 0, 0, argc, const_cast<const image**>(sub_node_images.data()), data); \
|
||||
} else { \
|
||||
for (blt::i32 y = 0; y < height; y++) { \
|
||||
for (blt::i32 x = 0; x < width; x++) { \
|
||||
FUNC(img.value(), static_cast<float>(x), static_cast<float>(y), argc, const_cast<const image**>(sub_node_images.data()), data); \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
break;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
FUNC_FUNCTIONS
|
||||
default:
|
||||
BLT_WARN("How did we get here?");
|
||||
break;
|
||||
}
|
||||
#undef FUNC_DEFINE
|
||||
}
|
387
src/main.cpp
387
src/main.cpp
|
@ -3,7 +3,6 @@
|
|||
#include <blt/gfx/window.h>
|
||||
#include <blt/gfx/state.h>
|
||||
#include <blt/gfx/stb/stb_image.h>
|
||||
#include <blt/std/hashmap.h>
|
||||
#include <functions.h>
|
||||
#include "blt/gfx/renderer/resource_manager.h"
|
||||
#include "blt/gfx/renderer/batch_2d_renderer.h"
|
||||
|
@ -13,264 +12,157 @@
|
|||
#include <random>
|
||||
#include <queue>
|
||||
#include <stack>
|
||||
#include <extern.h>
|
||||
#include <config.h>
|
||||
#include <gp.h>
|
||||
|
||||
blt::gfx::matrix_state_manager global_matrices;
|
||||
blt::gfx::resource_manager resources;
|
||||
blt::gfx::batch_renderer_2d renderer_2d(resources);
|
||||
|
||||
constexpr blt::i32 MAX_DEPTH = 17;
|
||||
|
||||
struct node;
|
||||
|
||||
blt::area_allocator<node, 32000> node_allocator;
|
||||
|
||||
node* createNode(function_t type)
|
||||
class tree
|
||||
{
|
||||
auto* n = node_allocator.allocate(1);
|
||||
node_allocator.construct(n, type);
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
void destroyNode(node* n)
|
||||
{
|
||||
node_allocator.destroy(n);
|
||||
node_allocator.deallocate(n, 1);
|
||||
}
|
||||
|
||||
class tree;
|
||||
|
||||
struct node
|
||||
{
|
||||
friend tree;
|
||||
private:
|
||||
// only valid up to the argc
|
||||
std::array<node*, MAX_ARGS> sub_nodes{nullptr};
|
||||
size_t argc = 0;
|
||||
|
||||
function_t type = function_t::ADD;
|
||||
data_t data{};
|
||||
|
||||
std::optional<image> img;
|
||||
|
||||
void grow(bool use_terminals)
|
||||
{
|
||||
auto min_children = function_arg_min_map[to_underlying(type)];
|
||||
auto max_children = function_arg_max_map[to_underlying(type)];
|
||||
|
||||
static thread_local std::random_device dev;
|
||||
static thread_local std::mt19937_64 engine{dev()};
|
||||
std::uniform_int_distribution<blt::i32> dist(min_children, max_children);
|
||||
static std::uniform_int_distribution<int> choice(0, 1);
|
||||
|
||||
argc = dist(engine);
|
||||
if (argc == 0)
|
||||
return;
|
||||
const auto& allowed_args_args = function_arg_allowed_map[to_underlying(type)];
|
||||
for (size_t i = 0; i < argc; i++)
|
||||
{
|
||||
// 50/50 chance to either use a terminal or use from the function list.
|
||||
populate_node(i, engine, allowed_args_args[i], choice(engine) || use_terminals);
|
||||
}
|
||||
}
|
||||
|
||||
void full(bool use_terminals)
|
||||
{
|
||||
static thread_local std::random_device dev;
|
||||
static thread_local std::mt19937_64 engine{dev()};
|
||||
|
||||
argc = function_arg_max_map[to_underlying(type)];
|
||||
if (argc == 0)
|
||||
return;
|
||||
|
||||
const auto& allowed_args_args = function_arg_allowed_map[to_underlying(type)];
|
||||
for (size_t i = 0; i < argc; i++)
|
||||
populate_node(i, engine, allowed_args_args[i], use_terminals);
|
||||
}
|
||||
|
||||
inline void populate_node(size_t i, std::mt19937_64& engine, const allowed_funcs<function_t>& allowed_args, bool use_terminal)
|
||||
{
|
||||
if (use_terminal)
|
||||
{
|
||||
auto terminals = intersection(allowed_args, FUNC_ALLOW_TERMINALS_SET);
|
||||
if (terminals.empty())
|
||||
{
|
||||
terminals = FUNC_ALLOW_TERMINALS;
|
||||
// BLT_INFO("%s:", function_name_map[to_underlying(type)].c_str());
|
||||
// for (auto v : allowed_args)
|
||||
// BLT_INFO(function_name_map[to_underlying(v)]);
|
||||
}
|
||||
std::uniform_int_distribution<blt::size_t> select(0, terminals.size() - 1);
|
||||
sub_nodes[i] = createNode(terminals[select(engine)]);
|
||||
} else
|
||||
{
|
||||
auto non_terminals = intersection_comp(allowed_args, FUNC_ALLOW_TERMINALS_SET);
|
||||
if (non_terminals.empty())
|
||||
{
|
||||
BLT_WARN("Empty non-terminals set! Filling from terminals!");
|
||||
std::uniform_int_distribution<blt::size_t> select(0, allowed_args.size() - 1);
|
||||
sub_nodes[i] = createNode(allowed_args[select(engine)]);
|
||||
} else
|
||||
{
|
||||
std::uniform_int_distribution<blt::size_t> select(0, non_terminals.size() - 1);
|
||||
sub_nodes[i] = createNode(non_terminals[select(engine)]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void print_tree()
|
||||
{
|
||||
if (argc > 0)
|
||||
std::cout << "(";
|
||||
if (argc > 0)
|
||||
std::cout << function_name_map[to_underlying(type)] << " ";
|
||||
else
|
||||
{
|
||||
if (type == function_t::SCALAR)
|
||||
{
|
||||
evaluate();
|
||||
std::cout << img->get().x() << " ";
|
||||
} else if (type == function_t::COLOR)
|
||||
{
|
||||
evaluate();
|
||||
std::cout << '{' << img->get().x() << ", " << img->get().y() << ", " << img->get().z() << "} ";
|
||||
} else
|
||||
std::cout << function_name_map[to_underlying(type)] << " ";
|
||||
}
|
||||
for (size_t i = 0; i < argc; i++)
|
||||
sub_nodes[i]->print_tree();
|
||||
if (argc > 0)
|
||||
std::cout << ") ";
|
||||
}
|
||||
|
||||
public:
|
||||
explicit node(function_t type): type(type)
|
||||
struct crossover_result_t
|
||||
{
|
||||
static thread_local std::random_device dev;
|
||||
static thread_local std::mt19937_64 engine{dev()};
|
||||
static thread_local std::uniform_real_distribution<float> dist(0.0f, 1.0f);
|
||||
if (type == function_t::SCALAR)
|
||||
data[0] = dist(engine);
|
||||
else if (type == function_t::COLOR)
|
||||
std::unique_ptr<tree> c1, c2;
|
||||
};
|
||||
private:
|
||||
std::unique_ptr<node, node_deleter> root = nullptr;
|
||||
|
||||
explicit tree(node* root): root(root)
|
||||
{}
|
||||
|
||||
void normalize_image()
|
||||
{
|
||||
float mx = 0, my = 0, mz = 0;
|
||||
float sx = 0, sy = 0, sz = 0;
|
||||
for (auto& v : root->getImage().getData())
|
||||
{
|
||||
for (auto& v : data)
|
||||
v = dist(engine);
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
if (std::isnan(v[i]))
|
||||
{
|
||||
v[i] = 0.0f;
|
||||
}
|
||||
}
|
||||
mx = std::max(v.x(), mx);
|
||||
my = std::max(v.y(), my);
|
||||
mz = std::max(v.z(), mz);
|
||||
sx = std::min(v.x(), sx);
|
||||
sy = std::min(v.y(), sy);
|
||||
sz = std::min(v.z(), sz);
|
||||
}
|
||||
for (auto& v : root->getImage().getData())
|
||||
{
|
||||
if (mx - sx != 0)
|
||||
v[0] = (v.x() - sx) / (mx - sx);
|
||||
if (my - sy != 0)
|
||||
v[1] = (v.y() - sy) / (my - sy);
|
||||
if (mz - sz != 0)
|
||||
v[2] = (v.z() - sz) / (mz - sz);
|
||||
}
|
||||
}
|
||||
|
||||
static node* construct_random_tree()
|
||||
node* select_random_child()
|
||||
{
|
||||
static std::random_device dev;
|
||||
static std::mt19937_64 engine{dev()};
|
||||
std::uniform_int_distribution<int> choice(0, 1);
|
||||
auto d = depth();
|
||||
std::uniform_int_distribution depth_dist(0, static_cast<int>(d));
|
||||
std::uniform_int_distribution select(0, 3);
|
||||
|
||||
static auto NON_TERMINALS = intersection_comp(FUNC_ALLOW_ANY, FUNC_ALLOW_TERMINALS_SET);
|
||||
node* current = root.get();
|
||||
|
||||
std::uniform_int_distribution<int> select(0, NON_TERMINALS.size() - 1);
|
||||
|
||||
node* n = createNode(NON_TERMINALS[select(engine)]);
|
||||
|
||||
std::queue<std::pair<node*, size_t>> grow_queue;
|
||||
size_t current_depth = 0;
|
||||
grow_queue.emplace(n, current_depth);
|
||||
while (!grow_queue.empty())
|
||||
while (true)
|
||||
{
|
||||
auto front = grow_queue.front();
|
||||
if (front.second != current_depth)
|
||||
current_depth++;
|
||||
|
||||
if (choice(engine))
|
||||
front.first->grow(front.second >= MAX_DEPTH);
|
||||
else
|
||||
front.first->full(front.second >= MAX_DEPTH);
|
||||
|
||||
for (size_t i = 0; i < front.first->argc; i++)
|
||||
grow_queue.emplace(front.first->sub_nodes[i], current_depth + 1);
|
||||
grow_queue.pop();
|
||||
std::uniform_int_distribution<size_t> children(0, current->argc - 1);
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
static std::unique_ptr<tree> construct_random_tree()
|
||||
{
|
||||
return std::make_unique<tree>(tree{node::construct_random_tree()});
|
||||
}
|
||||
|
||||
blt::size_t depth()
|
||||
{
|
||||
// depth -> node
|
||||
std::stack<std::pair<blt::size_t, node*>> stack;
|
||||
blt::size_t max_depth = 0;
|
||||
|
||||
stack.emplace(0, root.get());
|
||||
while (!stack.empty())
|
||||
{
|
||||
auto top = stack.top();
|
||||
auto* node = top.second;
|
||||
auto depth = top.first;
|
||||
max_depth = std::max(max_depth, depth);
|
||||
for (blt::size_t i = 0; i < node->argc; i++)
|
||||
{
|
||||
if (node->sub_nodes[i] != nullptr)
|
||||
{
|
||||
stack.emplace(depth + 1, node->sub_nodes[i]);
|
||||
}
|
||||
}
|
||||
stack.pop();
|
||||
}
|
||||
|
||||
return n;
|
||||
return max_depth;
|
||||
}
|
||||
|
||||
static crossover_result_t crossover(tree* p1, tree* p2)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void evaluate()
|
||||
{
|
||||
img = image{};
|
||||
std::array<image*, MAX_ARGS> sub_node_images{nullptr};
|
||||
for (size_t i = 0; i < argc; i++)
|
||||
{
|
||||
BLT_ASSERT(sub_nodes[i] != nullptr && sub_nodes[i]->img.has_value() && "Node must have evaluated children!");
|
||||
sub_node_images[i] = &sub_nodes[i]->img.value();
|
||||
}
|
||||
#define FUNC_DEFINE(NAME, MIN_ARGS, MAX_ARGS, FUNC, ...) case function_t::NAME: { \
|
||||
if (FUNC_ALLOW_TERMINALS_SET.contains(function_t::NAME)){ \
|
||||
FUNC(img.value(), 0, 0, argc, const_cast<const image**>(sub_node_images.data()), data); \
|
||||
} else { \
|
||||
for (blt::i32 y = 0; y < height; y++) { \
|
||||
for (blt::i32 x = 0; x < width; x++) { \
|
||||
FUNC(img.value(), static_cast<float>(x), static_cast<float>(y), argc, const_cast<const image**>(sub_node_images.data()), data); \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
break;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
FUNC_FUNCTIONS
|
||||
default:
|
||||
BLT_WARN("How did we get here?");
|
||||
break;
|
||||
}
|
||||
#undef FUNC_DEFINE
|
||||
}
|
||||
|
||||
void evaluate_tree()
|
||||
{
|
||||
for (size_t i = 0; i < argc; i++)
|
||||
sub_nodes[i]->evaluate_tree();
|
||||
evaluate();
|
||||
}
|
||||
|
||||
void printTree()
|
||||
{
|
||||
print_tree();
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
bool hasImage()
|
||||
{
|
||||
return img.has_value();
|
||||
root->evaluate_tree();
|
||||
normalize_image();
|
||||
}
|
||||
|
||||
image& getImage()
|
||||
{
|
||||
return img.value();
|
||||
return root->getImage();
|
||||
}
|
||||
|
||||
~node()
|
||||
bool hasImage()
|
||||
{
|
||||
for (auto* node : sub_nodes)
|
||||
destroyNode(node);
|
||||
return root->hasImage();
|
||||
}
|
||||
|
||||
bool hasTree()
|
||||
{
|
||||
return root != nullptr;
|
||||
}
|
||||
|
||||
float fitness()
|
||||
{
|
||||
return eval_DNF_SW(root->getImage());
|
||||
}
|
||||
|
||||
void printTree()
|
||||
{
|
||||
root->printTree();
|
||||
}
|
||||
};
|
||||
|
||||
class tree
|
||||
{
|
||||
public:
|
||||
node* root;
|
||||
|
||||
|
||||
};
|
||||
|
||||
node* root;
|
||||
std::unique_ptr<tree> test_tree;
|
||||
blt::gfx::texture_gl2D* texture;
|
||||
|
||||
bool fucky(float f)
|
||||
void print_bits(float f)
|
||||
{
|
||||
return f == std::numeric_limits<float>::quiet_NaN() || f == -std::numeric_limits<float>::quiet_NaN() ||
|
||||
f == std::numeric_limits<float>::infinity() ||
|
||||
f == -std::numeric_limits<float>::infinity();
|
||||
auto u = blt::mem::type_cast<blt::u32>(f);
|
||||
for (size_t i = 31; i > 0; i--)
|
||||
{
|
||||
std::cout << ((u >> i) & 0x1);
|
||||
if (i % 8 == 0)
|
||||
std::cout << ", ";
|
||||
else if (i % 4 == 0)
|
||||
std::cout << " ";
|
||||
}
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
void init()
|
||||
|
@ -293,59 +185,22 @@ void update(std::int32_t w, std::int32_t h)
|
|||
if (ImGui::Button("Regenerate"))
|
||||
{
|
||||
BLT_INFO("Regen tree");
|
||||
destroyNode(root);
|
||||
root = node::construct_random_tree();
|
||||
root->evaluate_tree();
|
||||
BLT_INFO("Preprocess");
|
||||
|
||||
float mx = 0, my = 0, mz = 0;
|
||||
float sx = 0, sy = 0, sz = 0;
|
||||
if (root->hasImage())
|
||||
{
|
||||
for (auto& v : root->getImage().getData())
|
||||
{
|
||||
//v = v.normalize();
|
||||
for (int i = 0; i < 3; i++)
|
||||
v[i] = std::abs(v[i]);
|
||||
mx = std::max(v.x(), mx);
|
||||
my = std::max(v.y(), my);
|
||||
mz = std::max(v.z(), mz);
|
||||
sx = std::min(v.x(), sx);
|
||||
sy = std::min(v.y(), sy);
|
||||
sz = std::min(v.z(), sz);
|
||||
}
|
||||
for (auto& v : root->getImage().getData())
|
||||
{
|
||||
if (mx - sx != 0)
|
||||
v[0] = (v.x() - sx) / (mx - sx);
|
||||
if (my - sy != 0)
|
||||
v[1] = (v.y() - sy) / (my - sy);
|
||||
if (mz - sz != 0)
|
||||
v[2] = (v.z() - sz) / (mz - sz);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
test_tree = tree::construct_random_tree();
|
||||
test_tree->evaluate();
|
||||
BLT_INFO("Uploading");
|
||||
//delete texture;
|
||||
if (root->hasImage())
|
||||
texture->upload((void*) root->getImage().getData().data(), GL_RGB, 0, 0, 0, -1, -1, GL_FLOAT);
|
||||
//texture->upload((void*) test.data(), GL_RGBA, 0, 0, 0, width, height, GL_UNSIGNED_BYTE);
|
||||
//texture->upload(file);
|
||||
//texture = new blt::gfx::texture_gl2D(file);
|
||||
resources.set("img", texture);
|
||||
texture->upload((void*) test_tree->getImage().getData().data(), GL_RGB, 0, 0, 0, -1, -1, GL_FLOAT);
|
||||
}
|
||||
|
||||
if (ImGui::Button("Display"))
|
||||
{
|
||||
if (root)
|
||||
root->printTree();
|
||||
if (test_tree->hasTree())
|
||||
test_tree->printTree();
|
||||
}
|
||||
|
||||
if (ImGui::Button("Eval"))
|
||||
{
|
||||
if (root && root->hasImage())
|
||||
BLT_DEBUG(eval_DNF_SW(root->getImage()));
|
||||
if (test_tree->hasImage())
|
||||
BLT_DEBUG(test_tree->fitness());
|
||||
}
|
||||
|
||||
auto lw = 512.0f;
|
||||
|
|
Loading…
Reference in New Issue