image-gp-6/src/custom_transformer.cpp

147 lines
5.7 KiB
C++
Raw Normal View History

2024-07-20 15:45:15 -04:00
/*
* <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/>.
*/
2024-08-06 21:34:30 -04:00
#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;
}
}