weird complexity

main
Brett 2025-07-13 14:21:52 -04:00
parent 4729e94d4f
commit e390cd262d
5 changed files with 94 additions and 75 deletions

View File

@ -35,7 +35,7 @@ void regenerate_image(blt::size_t index, float& image_storage, blt::i32 width, b
void set_population_size(blt::u32 size); void set_population_size(blt::u32 size);
std::array<image_pixel_t, IMAGE_DIMENSIONS * IMAGE_DIMENSIONS * 3>& get_image(blt::size_t index); std::array<image_ipixel_t, IMAGE_DIMENSIONS * IMAGE_DIMENSIONS * 3>& get_image(blt::size_t index);
void cleanup(); void cleanup();

View File

@ -28,6 +28,7 @@
#include <blt/std/hashmap.h> #include <blt/std/hashmap.h>
using image_pixel_t = float; using image_pixel_t = float;
using image_ipixel_t = blt::u32;
constexpr blt::i32 IMAGE_DIMENSIONS = 256; constexpr blt::i32 IMAGE_DIMENSIONS = 256;
constexpr blt::i32 IMAGE_CHANNELS = 1; constexpr blt::i32 IMAGE_CHANNELS = 1;
@ -54,6 +55,25 @@ struct image_storage_t
void normalize(); void normalize();
}; };
struct image_istorage_t
{
std::array<image_ipixel_t, IMAGE_SIZE_CHANNELS> data;
static std::array<image_storage_t, 3> from_file(const std::string& path);
image_ipixel_t& get(const blt::size_t x, const blt::size_t y)
{
return data[(y * IMAGE_DIMENSIONS + x) * IMAGE_CHANNELS];
}
[[nodiscard]] const image_ipixel_t& get(const blt::size_t x, const blt::size_t y) const
{
return data[(y * IMAGE_DIMENSIONS + x) * IMAGE_CHANNELS];
}
void normalize();
};
inline std::atomic_uint64_t g_allocated_blocks = 0; inline std::atomic_uint64_t g_allocated_blocks = 0;
inline std::atomic_uint64_t g_deallocated_blocks = 0; inline std::atomic_uint64_t g_deallocated_blocks = 0;
@ -67,7 +87,7 @@ struct image_cleaner_t
delete v; delete v;
} }
std::vector<image_storage_t*> images; std::vector<image_istorage_t*> images;
}; };
inline image_cleaner_t g_image_list; inline image_cleaner_t g_image_list;
@ -76,7 +96,7 @@ struct image_t
{ {
explicit image_t() explicit image_t()
{ {
image_storage_t* front = nullptr; image_istorage_t* front = nullptr;
{ {
std::scoped_lock lock(g_image_list_mutex); std::scoped_lock lock(g_image_list_mutex);
if (!g_image_list.images.empty()) if (!g_image_list.images.empty())
@ -88,7 +108,7 @@ struct image_t
if (front) if (front)
data = front; data = front;
else else
data = new image_storage_t; data = new image_istorage_t{};
++g_allocated_blocks; ++g_allocated_blocks;
} }
@ -125,18 +145,18 @@ struct image_t
friend image_t operator/(const image_t& lhs, const image_t& rhs); friend image_t operator/(const image_t& lhs, const image_t& rhs);
image_storage_t& get_data() image_istorage_t& get_data()
{ {
return *data; return *data;
} }
[[nodiscard]] const image_storage_t& get_data() const [[nodiscard]] const image_istorage_t& get_data() const
{ {
return *data; return *data;
} }
private: private:
image_storage_t* data; image_istorage_t* data;
}; };
#endif //IMAGE_STORAGE_H #endif //IMAGE_STORAGE_H

View File

@ -40,7 +40,7 @@ float filter_nan(const float f, const float failure = 0.0f)
std::array<gp_program*, 3> programs; std::array<gp_program*, 3> programs;
prog_config_t config{}; prog_config_t config{};
std::vector<std::array<image_pixel_t, IMAGE_DIMENSIONS * IMAGE_DIMENSIONS * 3>> images; std::vector<std::array<image_ipixel_t, IMAGE_DIMENSIONS * IMAGE_DIMENSIONS * 3>> images;
auto reference_image = image_storage_t::from_file("../silly.png"); auto reference_image = image_storage_t::from_file("../silly.png");
std::vector<float> average_fitness; std::vector<float> average_fitness;
@ -52,7 +52,7 @@ template <size_t Channel>
void fitness_func(const tree_t& tree, fitness_t& fitness, const blt::size_t index) void fitness_func(const tree_t& tree, fitness_t& fitness, const blt::size_t index)
{ {
auto image = tree.get_evaluation_ref<image_t>(); auto image = tree.get_evaluation_ref<image_t>();
image->normalize(); // image->normalize();
// std::memcpy(images[index].data.data(), image->get_data().data.data(), IMAGE_SIZE_BYTES); // std::memcpy(images[index].data.data(), image->get_data().data.data(), IMAGE_SIZE_BYTES);
auto& data = image->get_data(); auto& data = image->get_data();
@ -64,117 +64,127 @@ void fitness_func(const tree_t& tree, fitness_t& fitness, const blt::size_t inde
auto multiplier = (1 - std::abs((static_cast<float>(x) / (static_cast<float>(IMAGE_DIMENSIONS) / 2)) - 1)) + (1 - std::abs( auto multiplier = (1 - std::abs((static_cast<float>(x) / (static_cast<float>(IMAGE_DIMENSIONS) / 2)) - 1)) + (1 - std::abs(
(static_cast<float>(y) / (static_cast<float>(IMAGE_DIMENSIONS) / 2)) - 1)); (static_cast<float>(y) / (static_cast<float>(IMAGE_DIMENSIONS) / 2)) - 1));
auto our = data.get(x, y);
auto our2 = blt::mem::type_cast<blt::u32>(our); auto our3 = static_cast<double>(data.get(x, y)) / static_cast<double>(std::numeric_limits<blt::u32>::max());
auto our3 = static_cast<double>(our2) / static_cast<double>(std::numeric_limits<blt::u32>::max());
auto theirs = reference_image[Channel].get(x, y); auto theirs = reference_image[Channel].get(x, y);
const auto diff = std::pow(our3, 1.0f/2.2f) - std::pow(theirs, 1.0f/2.2f); const auto diff = std::pow(our3, 2.2f) - std::pow(theirs, 2.2f);
fitness.raw_fitness += static_cast<float>(diff * multiplier); if (std::isnan(diff))
{
if (std::isnan(our3))
BLT_DEBUG("Our is nan");
if (std::isnan(theirs))
BLT_DEBUG("Theirs is nan");
BLT_TRACE("We got {} vs {}", our3, theirs);
continue;
}
fitness.raw_fitness += static_cast<float>(diff);
} }
} }
// fitness.raw_fitness /= static_cast<float>(IMAGE_SIZE_CHANNELS); // fitness.raw_fitness /= static_cast<float>(IMAGE_SIZE_CHANNELS);
fitness.raw_fitness = static_cast<float>(std::sqrt(fitness.raw_fitness)); // fitness.raw_fitness = static_cast<float>(std::sqrt(fitness.raw_fitness));
fitness.standardized_fitness = fitness.raw_fitness; fitness.standardized_fitness = fitness.raw_fitness;
fitness.adjusted_fitness = 1 - 1 / (1 + fitness.standardized_fitness); fitness.adjusted_fitness = -fitness.standardized_fitness;
} }
template <typename T> template <typename T>
void setup_operations(gp_program* program) void setup_operations(gp_program* program)
{ {
static operation_t op_image_x([]() { static operation_t op_image_x([]() {
constexpr auto mul = std::numeric_limits<blt::u32>::max() - static_cast<blt::u32>(IMAGE_DIMENSIONS - 1);
image_t ret{}; image_t ret{};
for (blt::size_t x = 0; x < IMAGE_DIMENSIONS; ++x) for (blt::u32 x = 0; x < IMAGE_DIMENSIONS; ++x)
{ {
for (blt::size_t y = 0; y < IMAGE_DIMENSIONS; ++y) for (blt::u32 y = 0; y < IMAGE_DIMENSIONS; ++y)
ret.get_data().get(x, y) = static_cast<float>(x) / static_cast<float>(IMAGE_DIMENSIONS - 1); ret.get_data().get(x, y) = x * mul;
} }
return ret; return ret;
}); });
static operation_t op_image_y([]() { static operation_t op_image_y([]() {
constexpr auto mul = std::numeric_limits<blt::u32>::max() - static_cast<blt::u32>(IMAGE_DIMENSIONS - 1);
image_t ret{}; image_t ret{};
for (blt::size_t x = 0; x < IMAGE_DIMENSIONS; ++x) for (blt::u32 x = 0; x < IMAGE_DIMENSIONS; ++x)
{ {
for (blt::size_t y = 0; y < IMAGE_DIMENSIONS; ++y) for (blt::u32 y = 0; y < IMAGE_DIMENSIONS; ++y)
ret.get_data().get(x, y) = static_cast<float>(y) / static_cast<float>(IMAGE_DIMENSIONS - 1); ret.get_data().get(x, y) = y * mul;
} }
return ret; return ret;
}); });
static auto op_image_noise = operation_t([program]() { static auto op_image_noise = operation_t([program]() {
image_t ret{}; image_t ret{};
for (auto& v : ret.get_data().data) for (auto& v : ret.get_data().data)
v = program->get_random().get_float(0, 1.0f); v = program->get_random().get_u32(0, std::numeric_limits<blt::u32>::max());
return ret; return ret;
}).set_ephemeral(); }).set_ephemeral();
static auto op_image_ephemeral = operation_t([program]() { static auto op_image_ephemeral = operation_t([program]() {
image_t ret{}; image_t ret{};
const auto value = program->get_random().get_float(); const auto value = program->get_random().get_u32(0, std::numeric_limits<blt::u32>::max());
for (auto& v : ret.get_data().data) for (auto& v : ret.get_data().data)
v = value; v = value;
return ret; return ret;
}).set_ephemeral(); }).set_ephemeral();
static operation_t op_image_blend([](const image_t a, const image_t b, const float f) { // static operation_t op_image_blend([](const image_t a, const image_t b, const float f) {
const auto blend = std::min(std::max(f, 0.0f), 1.0f); // const auto blend = std::min(std::max(f, 0.0f), 1.0f);
const auto beta = 1.0f - blend; // const auto beta = 1.0f - blend;
image_t ret{}; // image_t ret{};
const cv::Mat src1{IMAGE_DIMENSIONS, IMAGE_DIMENSIONS, CV_32F, a.as_void_const()}; // const cv::Mat src1{IMAGE_DIMENSIONS, IMAGE_DIMENSIONS, CV_32F, a.as_void_const()};
const cv::Mat src2{IMAGE_DIMENSIONS, IMAGE_DIMENSIONS, CV_32F, b.as_void_const()}; // const cv::Mat src2{IMAGE_DIMENSIONS, IMAGE_DIMENSIONS, CV_32F, b.as_void_const()};
cv::Mat dst{IMAGE_DIMENSIONS, IMAGE_DIMENSIONS, CV_32F, ret.get_data().data.data()}; // cv::Mat dst{IMAGE_DIMENSIONS, IMAGE_DIMENSIONS, CV_32F, ret.get_data().data.data()};
addWeighted(src1, blend, src2, beta, 0.0, dst); // addWeighted(src1, blend, src2, beta, 0.0, dst);
return ret; // return ret;
}, "blend_image"); // }, "blend_image");
static operation_t op_image_sin([](const image_t a) { static operation_t op_image_sin([](const image_t a) {
image_t ret{}; image_t ret{};
for (const auto& [i, v] : blt::enumerate(std::as_const(a.get_data().data))) for (const auto& [i, v] : blt::enumerate(std::as_const(a.get_data().data)))
ret.get_data().data[i] = filter_nan(std::sin(v)); ret.get_data().data[i] = blt::mem::type_cast<blt::u32>(static_cast<float>(std::sin(v)));
return ret; return ret;
}, "sin_image"); }, "sin_image");
static operation_t op_image_cos([](const image_t a) { static operation_t op_image_cos([](const image_t a) {
image_t ret{}; image_t ret{};
for (const auto& [i, v] : blt::enumerate(std::as_const(a.get_data().data))) for (const auto& [i, v] : blt::enumerate(std::as_const(a.get_data().data)))
ret.get_data().data[i] = filter_nan(std::cos(v)); ret.get_data().data[i] = blt::mem::type_cast<blt::u32>(static_cast<float>(std::cos(v)));
return ret; return ret;
}, "cos_image"); }, "cos_image");
static operation_t op_image_log([](const image_t a) { static operation_t op_image_log([](const image_t a) {
image_t ret{}; image_t ret{};
for (const auto& [i, v] : blt::enumerate(std::as_const(a.get_data().data))) for (const auto& [i, v] : blt::enumerate(std::as_const(a.get_data().data)))
{ {
if (blt::f_equal(v, 0)) if (v == 0)
ret.get_data().data[i] = 0; ret.get_data().data[i] = 0;
else if (v < 0)
ret.get_data().data[i] = -filter_nan(std::log(-v));
else else
ret.get_data().data[i] = filter_nan(std::log(v)); ret.get_data().data[i] = blt::mem::type_cast<blt::u32>(static_cast<float>(std::log(v)));
} }
return ret; return ret;
}, "log_image"); }, "log_image");
static operation_t op_image_exp([](const image_t a) { static operation_t op_image_exp([](const image_t a) {
image_t ret{}; image_t ret{};
for (const auto& [i, v] : blt::enumerate(std::as_const(a.get_data().data))) for (const auto& [i, v] : blt::enumerate(std::as_const(a.get_data().data)))
ret.get_data().data[i] = filter_nan(std::exp(v)); ret.get_data().data[i] = blt::mem::type_cast<blt::u32>(static_cast<float>(std::exp(v)));
return ret; return ret;
}, "exp_image"); }, "exp_image");
static operation_t op_image_or([](const image_t a, const image_t b) { static operation_t op_image_or([](const image_t a, const image_t b) {
image_t ret{}; image_t ret{};
for (const auto& [i, av, bv] : blt::in_pairs(std::as_const(a.get_data().data), std::as_const(b.get_data().data)).enumerate().flatten()) for (const auto& [i, av, bv] : blt::in_pairs(std::as_const(a.get_data().data), std::as_const(b.get_data().data)).enumerate().flatten())
ret.get_data().data[i] = blt::mem::type_cast<float>(blt::mem::type_cast<blt::u32>(av) | blt::mem::type_cast<blt::u32>(bv)); ret.get_data().data[i] = av | bv;
return ret; return ret;
}, "bit_or_image"); }, "bit_or_image");
static operation_t op_image_and([](const image_t a, const image_t b) { static operation_t op_image_and([](const image_t a, const image_t b) {
image_t ret{}; image_t ret{};
for (const auto& [i, av, bv] : blt::in_pairs(std::as_const(a.get_data().data), std::as_const(b.get_data().data)).enumerate().flatten()) for (const auto& [i, av, bv] : blt::in_pairs(std::as_const(a.get_data().data), std::as_const(b.get_data().data)).enumerate().flatten())
ret.get_data().data[i] = blt::mem::type_cast<float>(blt::mem::type_cast<blt::u32>(av) & blt::mem::type_cast<blt::u32>(bv)); ret.get_data().data[i] = av & bv;
return ret; return ret;
}, "bit_and_image"); }, "bit_and_image");
static operation_t op_image_xor([](const image_t a, const image_t b) { static operation_t op_image_xor([](const image_t a, const image_t b) {
image_t ret{}; image_t ret{};
for (const auto& [i, av, bv] : blt::in_pairs(std::as_const(a.get_data().data), std::as_const(b.get_data().data)).enumerate().flatten()) for (const auto& [i, av, bv] : blt::in_pairs(std::as_const(a.get_data().data), std::as_const(b.get_data().data)).enumerate().flatten())
ret.get_data().data[i] = blt::mem::type_cast<float>(blt::mem::type_cast<blt::u32>(av) ^ blt::mem::type_cast<blt::u32>(bv)); ret.get_data().data[i] = av ^ bv;
return ret; return ret;
}, "bit_xor_image"); }, "bit_xor_image");
static operation_t op_image_not([](const image_t a, const image_t b) { static operation_t op_image_not([](const image_t a) {
image_t ret{}; image_t ret{};
for (const auto& [i, av, bv] : blt::in_pairs(std::as_const(a.get_data().data), std::as_const(b.get_data().data)).enumerate().flatten()) for (const auto& [i, av] : blt::enumerate(std::as_const(a.get_data().data)).flatten())
ret.get_data().data[i] = blt::mem::type_cast<float>(~blt::mem::type_cast<blt::u32>(av)); ret.get_data().data[i] = ~av;
return ret; return ret;
}, "bit_not_image"); }, "bit_not_image");
static operation_t op_image_gt([](const image_t a, const image_t b) { static operation_t op_image_gt([](const image_t a, const image_t b) {
@ -193,16 +203,18 @@ void setup_operations(gp_program* program)
const float octaves) { const float octaves) {
image_t ret{}; image_t ret{};
for (const auto& [i, out] : blt::enumerate(ret.get_data().data)) for (const auto& [i, out] : blt::enumerate(ret.get_data().data))
out = stb_perlin_ridge_noise3(static_cast<float>(i % IMAGE_DIMENSIONS) + ofx, static_cast<float>(i / IMAGE_DIMENSIONS) + ofy, ofz, out = blt::mem::type_cast<blt::u32>(stb_perlin_ridge_noise3(static_cast<float>(i % IMAGE_DIMENSIONS) + ofx,
lacunarity + 2, gain + 0.5f, 1.0f, static_cast<int>(octaves)); static_cast<float>(i / IMAGE_DIMENSIONS) + ofy, ofz, lacunarity + 2,
gain + 0.5f, 1.0f, static_cast<int>(octaves)));
return ret; return ret;
}, "perlin_image"); }, "perlin_image");
static operation_t op_image_perlin_bounded([](float octaves) { static operation_t op_image_perlin_bounded([](float octaves) {
octaves = std::min(std::max(octaves, 4.0f), 8.0f); octaves = std::min(std::max(octaves, 4.0f), 8.0f);
image_t ret{}; image_t ret{};
for (const auto& [i, out] : blt::enumerate(ret.get_data().data)) for (const auto& [i, out] : blt::enumerate(ret.get_data().data))
out = stb_perlin_fbm_noise3(static_cast<float>(i % IMAGE_DIMENSIONS) + 0.23423f, static_cast<float>(i / IMAGE_DIMENSIONS) + 0.6234f, out = blt::mem::type_cast<blt::u32>(stb_perlin_fbm_noise3(static_cast<float>(i % IMAGE_DIMENSIONS) + 0.23423f,
0.4861f, 2, 0.5, static_cast<int>(octaves)); static_cast<float>(i) / IMAGE_DIMENSIONS + 0.6234f, 0.4861f, 2, 0.5,
static_cast<int>(octaves)));
return ret; return ret;
}, "perlin_image_bounded"); }, "perlin_image_bounded");
static operation_t op_sin([](const float a) { static operation_t op_sin([](const float a) {
@ -228,7 +240,7 @@ void setup_operations(gp_program* program)
operator_builder builder{}; operator_builder builder{};
builder.build(op_image_ephemeral, make_add<image_t>(), make_sub<image_t>(), make_mul<image_t>(), make_div<image_t>(), op_image_x, op_image_y, builder.build(op_image_ephemeral, make_add<image_t>(), make_sub<image_t>(), make_mul<image_t>(), make_div<image_t>(), op_image_x, op_image_y,
op_image_sin, op_image_gt, op_image_lt, op_image_cos, op_image_log, op_image_exp, op_image_or, op_image_and, op_image_xor, op_image_sin, op_image_gt, op_image_lt, op_image_cos, op_image_log, op_image_exp, op_image_or, op_image_and, op_image_xor,
op_image_not, op_image_perlin_bounded, op_image_blend, make_add<float>(), make_sub<float>(), make_mul<float>(), op_image_not, op_image_perlin_bounded, make_add<float>(), make_sub<float>(), make_mul<float>(),
make_prot_div<float>(), op_sin, op_cos, op_exp, op_log, lit); make_prot_div<float>(), op_sin, op_cos, op_exp, op_log, lit);
program->set_operations(builder.grab()); program->set_operations(builder.grab());
} }
@ -309,7 +321,7 @@ bool should_terminate()
return programs[0]->should_terminate() || programs[1]->should_terminate() || programs[2]->should_terminate(); return programs[0]->should_terminate() || programs[1]->should_terminate() || programs[2]->should_terminate();
} }
std::array<image_pixel_t, IMAGE_DIMENSIONS * IMAGE_DIMENSIONS * 3>& get_image(const blt::size_t index) std::array<image_ipixel_t, IMAGE_DIMENSIONS * IMAGE_DIMENSIONS * 3>& get_image(const blt::size_t index)
{ {
return images[index]; return images[index];
} }
@ -362,9 +374,7 @@ void reset_programs()
} }
void regenerate_image(blt::size_t index, float& image_storage, blt::i32 width, blt::i32 height) void regenerate_image(blt::size_t index, float& image_storage, blt::i32 width, blt::i32 height)
{ {}
}
std::tuple<const std::vector<float>&, const std::vector<float>&, const std::vector<float>&, const std::vector<float>&> get_fitness_history() std::tuple<const std::vector<float>&, const std::vector<float>&, const std::vector<float>&, const std::vector<float>&> get_fitness_history()
{ {

View File

@ -48,6 +48,12 @@ std::array<image_storage_t, 3> image_storage_t::from_file(const std::string& pat
return {storage_r, storage_g, storage_b}; return {storage_r, storage_g, storage_b};
} }
std::array<image_storage_t, 3> image_istorage_t::from_file(const std::string& path)
{}
void image_istorage_t::normalize()
{}
void image_storage_t::normalize() void image_storage_t::normalize()
{ {
float min = std::numeric_limits<float>::max(); float min = std::numeric_limits<float>::max();

View File

@ -191,7 +191,7 @@ void update(const blt::gfx::window_data& data)
if (ImGui::BeginTabItem("Reference")) if (ImGui::BeginTabItem("Reference"))
{ {
auto w = data.width; blt::f32 w = data.width;
auto h = data.height - top_bar_height - 10; auto h = data.height - top_bar_height - 10;
renderer_2d.drawRectangle({static_cast<blt::f32>(w / 2), h / 2, w, h}, "reference"); renderer_2d.drawRectangle({static_cast<blt::f32>(w / 2), h / 2, w, h}, "reference");
ImGui::EndTabItem(); ImGui::EndTabItem();
@ -241,24 +241,7 @@ void update(const blt::gfx::window_data& data)
for (blt::size_t i = 0; i < population_size; i++) for (blt::size_t i = 0; i < population_size; i++)
{ {
auto& image = get_image(i); gl_images[i]->upload(get_image(i).data(), IMAGE_DIMENSIONS, IMAGE_DIMENSIONS, GL_RGB, GL_UNSIGNED_INT);
float min = std::numeric_limits<float>::max();
float max = std::numeric_limits<float>::min();
for (auto& pixel : image)
{
if (std::isnan(pixel) || std::isinf(pixel))
pixel = 0;
if (pixel > max)
max = pixel;
if (pixel < min)
min = pixel;
}
for (auto& pixel : image)
pixel = (pixel - min) / (max - min);
gl_images[i]->upload(get_image(i).data(), IMAGE_DIMENSIONS, IMAGE_DIMENSIONS, GL_RGB, GL_FLOAT);
} }
if ((blt::gfx::isMousePressed(0) && blt::gfx::mousePressedLastFrame() && !clicked_on_image) || (blt::gfx::isKeyPressed(GLFW_KEY_ESCAPE) && blt::gfx::keyPressedLastFrame())) if ((blt::gfx::isMousePressed(0) && blt::gfx::mousePressedLastFrame() && !clicked_on_image) || (blt::gfx::isKeyPressed(GLFW_KEY_ESCAPE) && blt::gfx::keyPressedLastFrame()))