weird complexity
parent
4729e94d4f
commit
e390cd262d
|
@ -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);
|
||||
|
||||
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();
|
||||
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#include <blt/std/hashmap.h>
|
||||
|
||||
using image_pixel_t = float;
|
||||
using image_ipixel_t = blt::u32;
|
||||
constexpr blt::i32 IMAGE_DIMENSIONS = 256;
|
||||
constexpr blt::i32 IMAGE_CHANNELS = 1;
|
||||
|
||||
|
@ -54,6 +55,25 @@ struct image_storage_t
|
|||
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_deallocated_blocks = 0;
|
||||
|
||||
|
@ -67,7 +87,7 @@ struct image_cleaner_t
|
|||
delete v;
|
||||
}
|
||||
|
||||
std::vector<image_storage_t*> images;
|
||||
std::vector<image_istorage_t*> images;
|
||||
};
|
||||
|
||||
inline image_cleaner_t g_image_list;
|
||||
|
@ -76,7 +96,7 @@ struct image_t
|
|||
{
|
||||
explicit image_t()
|
||||
{
|
||||
image_storage_t* front = nullptr;
|
||||
image_istorage_t* front = nullptr;
|
||||
{
|
||||
std::scoped_lock lock(g_image_list_mutex);
|
||||
if (!g_image_list.images.empty())
|
||||
|
@ -88,7 +108,7 @@ struct image_t
|
|||
if (front)
|
||||
data = front;
|
||||
else
|
||||
data = new image_storage_t;
|
||||
data = new image_istorage_t{};
|
||||
++g_allocated_blocks;
|
||||
}
|
||||
|
||||
|
@ -125,18 +145,18 @@ struct image_t
|
|||
|
||||
friend image_t operator/(const image_t& lhs, const image_t& rhs);
|
||||
|
||||
image_storage_t& get_data()
|
||||
image_istorage_t& get_data()
|
||||
{
|
||||
return *data;
|
||||
}
|
||||
|
||||
[[nodiscard]] const image_storage_t& get_data() const
|
||||
[[nodiscard]] const image_istorage_t& get_data() const
|
||||
{
|
||||
return *data;
|
||||
}
|
||||
|
||||
private:
|
||||
image_storage_t* data;
|
||||
image_istorage_t* data;
|
||||
};
|
||||
|
||||
#endif //IMAGE_STORAGE_H
|
||||
|
|
|
@ -40,7 +40,7 @@ float filter_nan(const float f, const float failure = 0.0f)
|
|||
std::array<gp_program*, 3> programs;
|
||||
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");
|
||||
|
||||
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)
|
||||
{
|
||||
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);
|
||||
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(
|
||||
(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>(our2) / static_cast<double>(std::numeric_limits<blt::u32>::max());
|
||||
|
||||
auto our3 = static_cast<double>(data.get(x, y)) / static_cast<double>(std::numeric_limits<blt::u32>::max());
|
||||
|
||||
|
||||
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);
|
||||
fitness.raw_fitness += static_cast<float>(diff * multiplier);
|
||||
const auto diff = std::pow(our3, 2.2f) - std::pow(theirs, 2.2f);
|
||||
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>(std::sqrt(fitness.raw_fitness));
|
||||
// fitness.raw_fitness = static_cast<float>(std::sqrt(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>
|
||||
void setup_operations(gp_program* program)
|
||||
{
|
||||
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{};
|
||||
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)
|
||||
ret.get_data().get(x, y) = static_cast<float>(x) / static_cast<float>(IMAGE_DIMENSIONS - 1);
|
||||
for (blt::u32 y = 0; y < IMAGE_DIMENSIONS; ++y)
|
||||
ret.get_data().get(x, y) = x * mul;
|
||||
}
|
||||
return ret;
|
||||
});
|
||||
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{};
|
||||
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)
|
||||
ret.get_data().get(x, y) = static_cast<float>(y) / static_cast<float>(IMAGE_DIMENSIONS - 1);
|
||||
for (blt::u32 y = 0; y < IMAGE_DIMENSIONS; ++y)
|
||||
ret.get_data().get(x, y) = y * mul;
|
||||
}
|
||||
return ret;
|
||||
});
|
||||
static auto op_image_noise = operation_t([program]() {
|
||||
image_t ret{};
|
||||
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;
|
||||
}).set_ephemeral();
|
||||
static auto op_image_ephemeral = operation_t([program]() {
|
||||
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)
|
||||
v = value;
|
||||
return ret;
|
||||
}).set_ephemeral();
|
||||
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 beta = 1.0f - blend;
|
||||
image_t ret{};
|
||||
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()};
|
||||
cv::Mat dst{IMAGE_DIMENSIONS, IMAGE_DIMENSIONS, CV_32F, ret.get_data().data.data()};
|
||||
addWeighted(src1, blend, src2, beta, 0.0, dst);
|
||||
return ret;
|
||||
}, "blend_image");
|
||||
// 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 beta = 1.0f - blend;
|
||||
// image_t ret{};
|
||||
// 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()};
|
||||
// cv::Mat dst{IMAGE_DIMENSIONS, IMAGE_DIMENSIONS, CV_32F, ret.get_data().data.data()};
|
||||
// addWeighted(src1, blend, src2, beta, 0.0, dst);
|
||||
// return ret;
|
||||
// }, "blend_image");
|
||||
static operation_t op_image_sin([](const image_t a) {
|
||||
image_t ret{};
|
||||
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;
|
||||
}, "sin_image");
|
||||
static operation_t op_image_cos([](const image_t a) {
|
||||
image_t ret{};
|
||||
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;
|
||||
}, "cos_image");
|
||||
static operation_t op_image_log([](const image_t a) {
|
||||
image_t ret{};
|
||||
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;
|
||||
else if (v < 0)
|
||||
ret.get_data().data[i] = -filter_nan(std::log(-v));
|
||||
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;
|
||||
}, "log_image");
|
||||
static operation_t op_image_exp([](const image_t a) {
|
||||
image_t ret{};
|
||||
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;
|
||||
}, "exp_image");
|
||||
static operation_t op_image_or([](const image_t a, const image_t b) {
|
||||
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())
|
||||
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;
|
||||
}, "bit_or_image");
|
||||
static operation_t op_image_and([](const image_t a, const image_t b) {
|
||||
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())
|
||||
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;
|
||||
}, "bit_and_image");
|
||||
static operation_t op_image_xor([](const image_t a, const image_t b) {
|
||||
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())
|
||||
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;
|
||||
}, "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{};
|
||||
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));
|
||||
for (const auto& [i, av] : blt::enumerate(std::as_const(a.get_data().data)).flatten())
|
||||
ret.get_data().data[i] = ~av;
|
||||
return ret;
|
||||
}, "bit_not_image");
|
||||
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) {
|
||||
image_t ret{};
|
||||
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,
|
||||
lacunarity + 2, gain + 0.5f, 1.0f, static_cast<int>(octaves));
|
||||
out = blt::mem::type_cast<blt::u32>(stb_perlin_ridge_noise3(static_cast<float>(i % IMAGE_DIMENSIONS) + ofx,
|
||||
static_cast<float>(i / IMAGE_DIMENSIONS) + ofy, ofz, lacunarity + 2,
|
||||
gain + 0.5f, 1.0f, static_cast<int>(octaves)));
|
||||
return ret;
|
||||
}, "perlin_image");
|
||||
static operation_t op_image_perlin_bounded([](float octaves) {
|
||||
octaves = std::min(std::max(octaves, 4.0f), 8.0f);
|
||||
image_t ret{};
|
||||
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,
|
||||
0.4861f, 2, 0.5, static_cast<int>(octaves));
|
||||
out = blt::mem::type_cast<blt::u32>(stb_perlin_fbm_noise3(static_cast<float>(i % IMAGE_DIMENSIONS) + 0.23423f,
|
||||
static_cast<float>(i) / IMAGE_DIMENSIONS + 0.6234f, 0.4861f, 2, 0.5,
|
||||
static_cast<int>(octaves)));
|
||||
return ret;
|
||||
}, "perlin_image_bounded");
|
||||
static operation_t op_sin([](const float a) {
|
||||
|
@ -228,7 +240,7 @@ void setup_operations(gp_program* program)
|
|||
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,
|
||||
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);
|
||||
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();
|
||||
}
|
||||
|
||||
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];
|
||||
}
|
||||
|
@ -362,9 +374,7 @@ void reset_programs()
|
|||
}
|
||||
|
||||
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()
|
||||
{
|
||||
|
|
|
@ -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};
|
||||
}
|
||||
|
||||
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()
|
||||
{
|
||||
float min = std::numeric_limits<float>::max();
|
||||
|
|
21
src/main.cpp
21
src/main.cpp
|
@ -191,7 +191,7 @@ void update(const blt::gfx::window_data& data)
|
|||
|
||||
if (ImGui::BeginTabItem("Reference"))
|
||||
{
|
||||
auto w = data.width;
|
||||
blt::f32 w = data.width;
|
||||
auto h = data.height - top_bar_height - 10;
|
||||
renderer_2d.drawRectangle({static_cast<blt::f32>(w / 2), h / 2, w, h}, "reference");
|
||||
ImGui::EndTabItem();
|
||||
|
@ -241,24 +241,7 @@ void update(const blt::gfx::window_data& data)
|
|||
|
||||
for (blt::size_t i = 0; i < population_size; i++)
|
||||
{
|
||||
auto& image = get_image(i);
|
||||
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);
|
||||
gl_images[i]->upload(get_image(i).data(), IMAGE_DIMENSIONS, IMAGE_DIMENSIONS, GL_RGB, GL_UNSIGNED_INT);
|
||||
}
|
||||
|
||||
if ((blt::gfx::isMousePressed(0) && blt::gfx::mousePressedLastFrame() && !clicked_on_image) || (blt::gfx::isKeyPressed(GLFW_KEY_ESCAPE) && blt::gfx::keyPressedLastFrame()))
|
||||
|
|
Loading…
Reference in New Issue