main
Brett 2024-08-06 21:34:30 -04:00
parent 2a8e334d43
commit a9235e9c17
10 changed files with 223 additions and 9 deletions

View File

@ -1,5 +1,5 @@
cmake_minimum_required(VERSION 3.25)
project(image-gp-6 VERSION 0.0.20)
project(image-gp-6 VERSION 0.0.21)
include(FetchContent)

View File

@ -19,13 +19,15 @@
#ifndef IMAGE_GP_6_CONFIG_H
#define IMAGE_GP_6_CONFIG_H
#include <custom_transformer.h>
inline constexpr size_t log2(size_t n) // NOLINT
{
return ((n < 2) ? 1 : 1 + log2(n / 2));
}
//inline const blt::u64 SEED = std::random_device()();
inline const blt::u64 SEED = 553372510;
inline const blt::u64 SEED = std::random_device()();
//inline const blt::u64 SEED = 553372510;
inline constexpr blt::size_t IMAGE_SIZE = 128;
inline constexpr blt::size_t IMAGE_PADDING = 16;
inline constexpr blt::size_t POP_SIZE = 64;
@ -35,9 +37,15 @@ inline constexpr blt::size_t DATA_CHANNELS_SIZE = DATA_SIZE * CHANNELS;
inline constexpr blt::size_t BOX_COUNT = static_cast<blt::size_t>(log2(IMAGE_SIZE / 2));
inline constexpr float THRESHOLD = 0.3;
inline constexpr auto load_image = "../GSab4SWWcAA1TNR.png";
inline blt::gp::image_crossover_t image_crossover;
inline blt::gp::image_mutation_t image_mutation;
//inline constexpr auto load_image = "../miles.png";
inline blt::gp::prog_config_t config = blt::gp::prog_config_t()
.set_crossover(image_crossover)
.set_mutation(image_mutation)
.set_initial_min_tree_size(4)
.set_initial_max_tree_size(8)
.set_elite_count(2)

View File

@ -19,4 +19,80 @@
#ifndef IMAGE_GP_6_CUSTOM_TRANSFORMER_H
#define IMAGE_GP_6_CUSTOM_TRANSFORMER_H
#include <blt/gp/transformers.h>
namespace blt::gp
{
template<typename T>
inline static constexpr double sum(const T& array)
{
double init = 0.0;
for (double i : array)
init += i;
return init;
}
template<blt::size_t size, typename... Args>
static constexpr std::array<double, size> aggregate_array(Args... list)
{
std::array<double, size> data {list...};
auto total_prob = sum(data);
double sum_of_prob = 0;
for (auto& d : data) {
auto prob = d / total_prob;
d = prob + sum_of_prob;
sum_of_prob += prob;
}
return data;
}
class image_crossover_t : public crossover_t
{
public:
image_crossover_t() = default;
explicit image_crossover_t(const config_t& config): crossover_t(config)
{}
blt::expected<result_t, error_t> apply(gp_program& program, const tree_t& p1, const tree_t& p2) final;
};
class image_mutation_t : public mutation_t
{
public:
enum class mutation_operator : blt::i32
{
EXPRESSION, // Generate a new random expression
ADJUST, // adjust the value of the type.
FUNC, // Change node into a different function. Args will be generated / removed.
SUB_FUNC, // subexpression becomes argument to new random function. Other args are generated.
JUMP_FUNC, // subexpression becomes this new node. Other arguments discarded.
COPY, // node can become copy of another subexpression.
END, // helper
};
image_mutation_t() = default;
explicit image_mutation_t(const config_t& config): mutation_t(config)
{}
tree_t apply(gp_program& program, const tree_t& p) final;
private:
static constexpr auto operators_size = static_cast<blt::i32>(mutation_operator::END);
private:
// this value is adjusted inversely to the size of the tree.
double per_node_mutation_chance = 1.0;
static constexpr std::array<double, operators_size> mutation_operator_chances = aggregate_array<operators_size>(
0.01, // EXPRESSION
0.11, // ADJUST
0.05, // FUNC
0.01, // SUB_FUNC
0.1, // JUMP_FUNC
0.05 // COPY
);
};
}
#endif //IMAGE_GP_6_CUSTOM_TRANSFORMER_H

View File

@ -20,6 +20,7 @@
#define IMAGE_GP_6_HELPER_H
#include <images.h>
#include <stb_perlin.h>
template<typename SINGLE_FUNC>
constexpr static auto make_single(SINGLE_FUNC&& func)

View File

@ -16,9 +16,11 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include <blt/math/vectors.h>
#include <blt/gp/program.h>
#include <functional>
#include <helper.h>
#include <stb_perlin.h>
#ifndef IMAGE_GP_6_IMAGE_OPERATIONS_H
#define IMAGE_GP_6_IMAGE_OPERATIONS_H

View File

@ -20,6 +20,9 @@
#define IMAGE_GP_6_IMAGES_H
#include <config.h>
#include <stb_image.h>
#include <stb_image_resize2.h>
#include <stb_image_write.h>
struct full_image_t
{

@ -1 +1 @@
Subproject commit 593e02b6ffd36cfabda85e9dcfd88ec60b8a8741
Subproject commit b10b4388897b1673b0dbe84b1db34584db0e9660

BIN
meow.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

View File

@ -15,4 +15,132 @@
* 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 <custom_transformer.h>
#include <custom_transformer.h>
#include <blt/gp/program.h>
#include <images.h>
#include <image_operations.h>
#include <float_operations.h>
namespace blt::gp
{
blt::expected<crossover_t::result_t, crossover_t::error_t> image_crossover_t::apply(gp_program& program, const tree_t& p1, const tree_t& p2)
{
return crossover_t::apply(program, p1, p2);
}
tree_t image_mutation_t::apply(gp_program& program, const tree_t& p)
{
// child tree
tree_t c = p;
auto& ops = c.get_operations();
auto& vals = c.get_values();
double node_mutation_chance = per_node_mutation_chance * (1.0 / static_cast<double>(ops.size()));
for (blt::size_t c_node = 0; c_node < ops.size(); c_node++)
{
if (!program.get_random().choice(node_mutation_chance))
continue;
auto selected_point = static_cast<blt::i32>(mutation_operator::COPY);
auto choice = program.get_random().get_double();
for (const auto& [index, value] : blt::enumerate(mutation_operator_chances))
{
if (index == 0)
{
if (choice <= value)
{
selected_point = static_cast<blt::i32>(index);
break;
}
} else
{
if (choice > mutation_operator_chances[index - 1] && choice <= value)
{
selected_point = static_cast<blt::i32>(index);
break;
}
}
}
switch (static_cast<mutation_operator>(selected_point))
{
case mutation_operator::EXPRESSION:
c_node += mutate_point(program, c, c_node);
break;
case mutation_operator::ADJUST:
{
// this is going to be evil >:3
const auto& node = ops[c_node];
if (node.is_value)
{
blt::size_t bytes_from_head = 0;
for (auto it = ops.begin() + static_cast<blt::ptrdiff_t>(c_node) + 1; it != ops.end(); it++)
bytes_from_head += it->is_value ? stack_allocator::aligned_size(it->type_size) : 0;
// is a float
if (node.type_size == sizeof(float))
{
auto& val = vals.from<float>(bytes_from_head);
auto old = val;
val += f_literal.get_function()();
val /= 2.0f;
if (std::isnan(val))
val = old;
} else // is an image
{
auto& val = vals.from<full_image_t>(bytes_from_head);
auto type = program.get_typesystem().get_type<full_image_t>();
auto& terminals = program.get_type_terminals(type.id());
// Annoying. TODO: fix all of this.
operator_id id;
do{
id = program.get_random().select(terminals);
} while(!program.is_static(id));
stack_allocator stack;
program.get_operator_info(id).function(nullptr, stack, stack);
//auto adjustment = lit.get_function()();
auto& adjustment = stack.from<full_image_t>(0);
for (const auto& [index, value] : blt::enumerate(val.rgb_data))
{
auto old = value;
// add and normalize.
value += adjustment.rgb_data[index];
value /= 2.0f;
if (std::isnan(value))
value = old;
}
}
}
}
break;
case mutation_operator::FUNC:
break;
case mutation_operator::SUB_FUNC:
break;
case mutation_operator::JUMP_FUNC:
break;
case mutation_operator::COPY:
break;
case mutation_operator::END:
default:
#if BLT_DEBUG_LEVEL > 1
BLT_ABORT("You shouldn't be able to get here!");
#else
BLT_UNREACHABLE;
#endif
}
}
return c;
}
}

View File

@ -22,10 +22,6 @@
#include <blt/std/memory_util.h>
#include <blt/std/hashmap.h>
#include <blt/std/time.h>
#include <stb_image.h>
#include <stb_image_resize2.h>
#include <stb_image_write.h>
#include <stb_perlin.h>
#include <blt/gfx/window.h>
#include "blt/gfx/renderer/resource_manager.h"
#include "blt/gfx/renderer/batch_2d_renderer.h"