main
parent
a8e5673555
commit
93188a6120
|
@ -1,3 +1,6 @@
|
||||||
[submodule "libraries/BLT-With-Graphics-Template"]
|
[submodule "libraries/BLT-With-Graphics-Template"]
|
||||||
path = libraries/BLT-With-Graphics-Template
|
path = libraries/BLT-With-Graphics-Template
|
||||||
url = https://git.tpgc.me/tri11paragon/BLT-With-Graphics-Template.git
|
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)
|
// distribution from normality (DFN)
|
||||||
float eval_DNF_SW(const image& img);
|
float eval_DNF_SW(const image& img);
|
||||||
|
|
||||||
float eval_DNF_KS(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
|
#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/std/allocator.h"
|
||||||
#include "blt/math/vectors.h"
|
#include "blt/math/vectors.h"
|
||||||
#include <variant>
|
#include <variant>
|
||||||
|
#include <config.h>
|
||||||
inline constexpr blt::i32 width = 256, height = 256;
|
|
||||||
|
|
||||||
using image_data_t = std::array<blt::vec3, width * height>;
|
using image_data_t = std::array<blt::vec3, width * height>;
|
||||||
inline blt::area_allocator<image_data_t, 32> img_allocator;
|
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/gfx/stb/stb_perlin.h>
|
||||||
#include <blt/std/memory_util.h>
|
#include <blt/std/memory_util.h>
|
||||||
#include <extern.h>
|
#include <extern.h>
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
#define FUNCTION_COORD() \
|
#define FUNCTION_COORD() \
|
||||||
int xi = static_cast<int>(x); \
|
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)
|
double on_data(const double* data, blt::size_t len)
|
||||||
{
|
{
|
||||||
static float NEGATION = -1;
|
const static float NEGATION = 0;
|
||||||
willbruh results(data, len);
|
willbruh results(data, len);
|
||||||
switch (results->error)
|
switch (results->error)
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
return results->estimate;
|
if (!std::isnan(results->estimate))
|
||||||
|
return results->estimate;
|
||||||
|
return 0;
|
||||||
case 1:
|
case 1:
|
||||||
BLT_INFO("Somehow we have sent more than 5000 values!");
|
BLT_INFO("Somehow we have sent more than 5000 values!");
|
||||||
case -1:
|
return 0;
|
||||||
case -3:
|
default:
|
||||||
return 0;
|
return 0;
|
||||||
case -2:
|
case -2:
|
||||||
// should never consider this a valid solution / punish for having large sections of no difference
|
// 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
|
||||||
|
}
|
383
src/main.cpp
383
src/main.cpp
|
@ -3,7 +3,6 @@
|
||||||
#include <blt/gfx/window.h>
|
#include <blt/gfx/window.h>
|
||||||
#include <blt/gfx/state.h>
|
#include <blt/gfx/state.h>
|
||||||
#include <blt/gfx/stb/stb_image.h>
|
#include <blt/gfx/stb/stb_image.h>
|
||||||
#include <blt/std/hashmap.h>
|
|
||||||
#include <functions.h>
|
#include <functions.h>
|
||||||
#include "blt/gfx/renderer/resource_manager.h"
|
#include "blt/gfx/renderer/resource_manager.h"
|
||||||
#include "blt/gfx/renderer/batch_2d_renderer.h"
|
#include "blt/gfx/renderer/batch_2d_renderer.h"
|
||||||
|
@ -13,264 +12,157 @@
|
||||||
#include <random>
|
#include <random>
|
||||||
#include <queue>
|
#include <queue>
|
||||||
#include <stack>
|
#include <stack>
|
||||||
#include <extern.h>
|
#include <config.h>
|
||||||
|
#include <gp.h>
|
||||||
|
|
||||||
blt::gfx::matrix_state_manager global_matrices;
|
blt::gfx::matrix_state_manager global_matrices;
|
||||||
blt::gfx::resource_manager resources;
|
blt::gfx::resource_manager resources;
|
||||||
blt::gfx::batch_renderer_2d renderer_2d(resources);
|
blt::gfx::batch_renderer_2d renderer_2d(resources);
|
||||||
|
|
||||||
constexpr blt::i32 MAX_DEPTH = 17;
|
class tree
|
||||||
|
|
||||||
struct node;
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
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:
|
public:
|
||||||
explicit node(function_t type): type(type)
|
struct crossover_result_t
|
||||||
{
|
{
|
||||||
static thread_local std::random_device dev;
|
std::unique_ptr<tree> c1, c2;
|
||||||
static thread_local std::mt19937_64 engine{dev()};
|
};
|
||||||
static thread_local std::uniform_real_distribution<float> dist(0.0f, 1.0f);
|
private:
|
||||||
if (type == function_t::SCALAR)
|
std::unique_ptr<node, node_deleter> root = nullptr;
|
||||||
data[0] = dist(engine);
|
|
||||||
else if (type == function_t::COLOR)
|
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)
|
for (int i = 0; i < 3; i++)
|
||||||
v = dist(engine);
|
{
|
||||||
|
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::random_device dev;
|
||||||
static std::mt19937_64 engine{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);
|
while (true)
|
||||||
|
|
||||||
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();
|
std::uniform_int_distribution<size_t> children(0, current->argc - 1);
|
||||||
if (front.second != current_depth)
|
}
|
||||||
current_depth++;
|
}
|
||||||
|
|
||||||
if (choice(engine))
|
public:
|
||||||
front.first->grow(front.second >= MAX_DEPTH);
|
static std::unique_ptr<tree> construct_random_tree()
|
||||||
else
|
{
|
||||||
front.first->full(front.second >= MAX_DEPTH);
|
return std::make_unique<tree>(tree{node::construct_random_tree()});
|
||||||
|
}
|
||||||
|
|
||||||
for (size_t i = 0; i < front.first->argc; i++)
|
blt::size_t depth()
|
||||||
grow_queue.emplace(front.first->sub_nodes[i], current_depth + 1);
|
{
|
||||||
grow_queue.pop();
|
// 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()
|
void evaluate()
|
||||||
{
|
{
|
||||||
img = image{};
|
root->evaluate_tree();
|
||||||
std::array<image*, MAX_ARGS> sub_node_images{nullptr};
|
normalize_image();
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
image& getImage()
|
image& getImage()
|
||||||
{
|
{
|
||||||
return img.value();
|
return root->getImage();
|
||||||
}
|
}
|
||||||
|
|
||||||
~node()
|
bool hasImage()
|
||||||
{
|
{
|
||||||
for (auto* node : sub_nodes)
|
return root->hasImage();
|
||||||
destroyNode(node);
|
}
|
||||||
|
|
||||||
|
bool hasTree()
|
||||||
|
{
|
||||||
|
return root != nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
float fitness()
|
||||||
|
{
|
||||||
|
return eval_DNF_SW(root->getImage());
|
||||||
|
}
|
||||||
|
|
||||||
|
void printTree()
|
||||||
|
{
|
||||||
|
root->printTree();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class tree
|
std::unique_ptr<tree> test_tree;
|
||||||
{
|
|
||||||
public:
|
|
||||||
node* root;
|
|
||||||
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
node* root;
|
|
||||||
blt::gfx::texture_gl2D* texture;
|
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() ||
|
auto u = blt::mem::type_cast<blt::u32>(f);
|
||||||
f == std::numeric_limits<float>::infinity() ||
|
for (size_t i = 31; i > 0; i--)
|
||||||
f == -std::numeric_limits<float>::infinity();
|
{
|
||||||
|
std::cout << ((u >> i) & 0x1);
|
||||||
|
if (i % 8 == 0)
|
||||||
|
std::cout << ", ";
|
||||||
|
else if (i % 4 == 0)
|
||||||
|
std::cout << " ";
|
||||||
|
}
|
||||||
|
std::cout << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
void init()
|
void init()
|
||||||
|
@ -293,59 +185,22 @@ void update(std::int32_t w, std::int32_t h)
|
||||||
if (ImGui::Button("Regenerate"))
|
if (ImGui::Button("Regenerate"))
|
||||||
{
|
{
|
||||||
BLT_INFO("Regen tree");
|
BLT_INFO("Regen tree");
|
||||||
destroyNode(root);
|
test_tree = tree::construct_random_tree();
|
||||||
root = node::construct_random_tree();
|
test_tree->evaluate();
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
BLT_INFO("Uploading");
|
BLT_INFO("Uploading");
|
||||||
//delete texture;
|
texture->upload((void*) test_tree->getImage().getData().data(), GL_RGB, 0, 0, 0, -1, -1, GL_FLOAT);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ImGui::Button("Display"))
|
if (ImGui::Button("Display"))
|
||||||
{
|
{
|
||||||
if (root)
|
if (test_tree->hasTree())
|
||||||
root->printTree();
|
test_tree->printTree();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ImGui::Button("Eval"))
|
if (ImGui::Button("Eval"))
|
||||||
{
|
{
|
||||||
if (root && root->hasImage())
|
if (test_tree->hasImage())
|
||||||
BLT_DEBUG(eval_DNF_SW(root->getImage()));
|
BLT_DEBUG(test_tree->fitness());
|
||||||
}
|
}
|
||||||
|
|
||||||
auto lw = 512.0f;
|
auto lw = 512.0f;
|
||||||
|
|
Loading…
Reference in New Issue