drop is now being called correctly.
parent
8917fc12f7
commit
8594c44bae
|
@ -27,7 +27,7 @@ macro(compile_options target_name)
|
|||
sanitizers(${target_name})
|
||||
endmacro()
|
||||
|
||||
project(blt-gp VERSION 0.3.12)
|
||||
project(blt-gp VERSION 0.3.13)
|
||||
|
||||
include(CTest)
|
||||
|
||||
|
|
|
@ -73,7 +73,7 @@ void blt::gp::example::rice_classification_t::make_operators()
|
|||
static operation_t mul([](const float a, const float b) { return a * b; }, "mul");
|
||||
static operation_t pro_div([](const float a, const float b) { return b == 0.0f ? 0.0f : a / b; }, "div");
|
||||
static operation_t op_exp([](const float a) { return std::exp(a); }, "exp");
|
||||
static operation_t op_log([](const float a) { return a == 0.0f ? 0.0f : std::log(a); }, "log");
|
||||
static operation_t op_log([](const float a) { return a <= 0.0f ? 0.0f : std::log(a); }, "log");
|
||||
static auto lit = operation_t([this]()
|
||||
{
|
||||
return program.get_random().get_float(-32000.0f, 32000.0f);
|
||||
|
|
|
@ -91,7 +91,7 @@ namespace blt::gp::example
|
|||
static operation_t op_sin([](const float a) { return std::sin(a); }, "sin");
|
||||
static operation_t op_cos([](const float a) { return std::cos(a); }, "cos");
|
||||
static operation_t op_exp([](const float a) { return std::exp(a); }, "exp");
|
||||
static operation_t op_log([](const float a) { return a == 0.0f ? 0.0f : std::log(a); }, "log");
|
||||
static operation_t op_log([](const float a) { return a <= 0.0f ? 0.0f : std::log(a); }, "log");
|
||||
static auto lit = operation_t([this]()
|
||||
{
|
||||
return program.get_random().get_float(-1.0f, 1.0f);
|
||||
|
@ -195,6 +195,11 @@ namespace blt::gp::example
|
|||
print_stats();
|
||||
}
|
||||
|
||||
[[nodiscard]] const auto& get_training_cases() const
|
||||
{
|
||||
return training_cases;
|
||||
}
|
||||
|
||||
private:
|
||||
std::array<context, 200> training_cases{};
|
||||
};
|
||||
|
|
|
@ -38,7 +38,7 @@ namespace blt::gp
|
|||
size_t offset = 0;
|
||||
size_t current_index = 0;
|
||||
((offset += (current_index++ > index ? stack_allocator::aligned_size<detail::remove_cv_ref<Args>>() : 0)), ...);
|
||||
(void) current_index;
|
||||
(void)current_index;
|
||||
return offset;
|
||||
}
|
||||
|
||||
|
@ -60,17 +60,28 @@ namespace blt::gp
|
|||
allocator.from<detail::remove_cv_ref<Args>>(getByteOffset<indices>())...);
|
||||
}
|
||||
|
||||
template <typename, typename... NoCtxArgs>
|
||||
void call_destructors_without_first(stack_allocator& read_allocator) const
|
||||
template<typename T>
|
||||
static void call_drop(stack_allocator& read_allocator, const size_t offset)
|
||||
{
|
||||
if constexpr (sizeof...(NoCtxArgs) > 0)
|
||||
if constexpr (blt::gp::detail::has_func_drop_v<T>)
|
||||
{
|
||||
read_allocator.call_destructors<detail::remove_cv_ref<NoCtxArgs>...>();
|
||||
read_allocator.from<detail::remove_cv_ref<T>>(offset).drop();
|
||||
}
|
||||
}
|
||||
|
||||
static void call_destructors(stack_allocator& read_allocator)
|
||||
{
|
||||
if constexpr (sizeof...(Args) > 0)
|
||||
{
|
||||
size_t offset = (stack_allocator::aligned_size<detail::remove_cv_ref<Args>>() + ...) - stack_allocator::aligned_size<
|
||||
detail::remove_cv_ref<typename meta::arg_helper<Args...>::First>>();
|
||||
((call_drop<Args>(read_allocator, offset), offset -= stack_allocator::aligned_size<detail::remove_cv_ref<Args>>()), ...);
|
||||
(void)offset;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Func, typename... ExtraArgs>
|
||||
Return operator()(const bool has_context, Func&& func, stack_allocator& read_allocator, ExtraArgs&&... args)
|
||||
Return operator()(const bool, Func&& func, stack_allocator& read_allocator, ExtraArgs&&... args)
|
||||
{
|
||||
constexpr auto seq = std::make_integer_sequence<u64, sizeof...(Args)>();
|
||||
#if BLT_DEBUG_LEVEL > 0
|
||||
|
@ -78,10 +89,7 @@ namespace blt::gp
|
|||
{
|
||||
#endif
|
||||
Return ret = exec_sequence_to_indices(std::forward<Func>(func), read_allocator, seq, std::forward<ExtraArgs>(args)...);
|
||||
if (has_context)
|
||||
call_destructors_without_first<Args...>(read_allocator);
|
||||
else
|
||||
read_allocator.call_destructors<detail::remove_cv_ref<Args>...>();
|
||||
call_destructors(read_allocator);
|
||||
read_allocator.pop_bytes((stack_allocator::aligned_size<detail::remove_cv_ref<Args>>() + ...));
|
||||
return ret;
|
||||
#if BLT_DEBUG_LEVEL > 0
|
||||
|
@ -115,11 +123,11 @@ namespace blt::gp
|
|||
constexpr operation_t(operation_t&& move) = default;
|
||||
|
||||
template <typename Functor>
|
||||
constexpr explicit operation_t(const Functor& functor, std::optional<std::string_view> name = {}): func(functor), name(name)
|
||||
constexpr explicit operation_t(const Functor& functor, const std::optional<std::string_view> name = {}): func(functor), name(name)
|
||||
{
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr inline Return operator()(stack_allocator& read_allocator) const
|
||||
[[nodiscard]] constexpr Return operator()(stack_allocator& read_allocator) const
|
||||
{
|
||||
if constexpr (sizeof...(Args) == 0)
|
||||
{
|
||||
|
@ -131,7 +139,7 @@ namespace blt::gp
|
|||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr inline Return operator()(void* context, stack_allocator& read_allocator) const
|
||||
[[nodiscard]] constexpr Return operator()(void* context, stack_allocator& read_allocator) const
|
||||
{
|
||||
// should be an impossible state
|
||||
if constexpr (sizeof...(Args) == 0)
|
||||
|
@ -183,14 +191,14 @@ namespace blt::gp
|
|||
return *this;
|
||||
}
|
||||
|
||||
bool is_ephemeral() const
|
||||
[[nodiscard]] bool is_ephemeral() const
|
||||
{
|
||||
return is_ephemeral_;
|
||||
}
|
||||
|
||||
bool return_has_drop() const
|
||||
[[nodiscard]] bool return_has_ephemeral_drop() const
|
||||
{
|
||||
return detail::has_func_drop_v<Return>;
|
||||
return detail::has_func_drop_ephemeral_v<Return>;
|
||||
}
|
||||
|
||||
operator_id id = -1;
|
||||
|
|
|
@ -57,29 +57,6 @@
|
|||
|
||||
namespace blt::gp
|
||||
{
|
||||
struct operator_special_flags
|
||||
{
|
||||
explicit operator_special_flags(const bool is_ephemeral = false, const bool has_drop = false): m_ephemeral(is_ephemeral), m_drop(has_drop)
|
||||
{
|
||||
}
|
||||
|
||||
[[nodiscard]] bool is_ephemeral() const
|
||||
{
|
||||
return m_ephemeral;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool has_drop() const
|
||||
{
|
||||
return m_drop;
|
||||
}
|
||||
|
||||
private:
|
||||
bool m_ephemeral : 1;
|
||||
bool m_drop : 1;
|
||||
};
|
||||
|
||||
static_assert(sizeof(operator_special_flags) == 1, "Size of operator flags struct is expected to be 1 byte!");
|
||||
|
||||
struct argc_t
|
||||
{
|
||||
blt::u32 argc = 0;
|
||||
|
@ -247,7 +224,7 @@ namespace blt::gp
|
|||
info.return_type = return_type_id;
|
||||
info.func = op.template make_callable<Context>();
|
||||
|
||||
((std::is_same_v<detail::remove_cv_ref<Args>, Context> ? info.argc.argc -= 1 : (blt::size_t)nullptr), ...);
|
||||
((std::is_same_v<detail::remove_cv_ref<Args>, Context> ? info.argc.argc -= 1 : 0), ...);
|
||||
|
||||
auto& operator_list = info.argc.argc == 0 ? storage.terminals : storage.non_terminals;
|
||||
operator_list[return_type_id].push_back(operator_id);
|
||||
|
@ -282,7 +259,8 @@ namespace blt::gp
|
|||
switch (type)
|
||||
{
|
||||
case detail::destroy_t::ARGS:
|
||||
alloc.call_destructors<Args...>();
|
||||
// alloc.call_destructors<Args...>();
|
||||
BLT_ERROR("Unimplemented");
|
||||
break;
|
||||
case detail::destroy_t::RETURN:
|
||||
if constexpr (detail::has_func_drop_v<remove_cvref_t<Return>>)
|
||||
|
@ -293,7 +271,7 @@ namespace blt::gp
|
|||
}
|
||||
});
|
||||
storage.names.push_back(op.get_name());
|
||||
storage.operator_flags.emplace(operator_id, operator_special_flags{op.is_ephemeral(), op.return_has_drop()});
|
||||
storage.operator_flags.emplace(operator_id, operator_special_flags{op.is_ephemeral(), op.return_has_ephemeral_drop()});
|
||||
return meta;
|
||||
}
|
||||
|
||||
|
@ -429,7 +407,7 @@ namespace blt::gp
|
|||
Crossover& crossover_selection, Mutation& mutation_selection, Reproduction& reproduction_selection,
|
||||
CreationFunc& func = default_next_pop_creator<Crossover, Mutation, Reproduction>, bool eval_fitness_now = true)
|
||||
{
|
||||
using LambdaReturn = typename decltype(blt::meta::lambda_helper(fitness_function))::Return;
|
||||
using LambdaReturn = std::invoke_result_t<decltype(fitness_function), const tree_t&, fitness_t&, size_t>;
|
||||
current_pop = config.pop_initializer.get().generate(
|
||||
{*this, root_type, config.population_size, config.initial_min_tree_size, config.initial_max_tree_size});
|
||||
next_pop = population_t(current_pop);
|
||||
|
@ -503,7 +481,7 @@ namespace blt::gp
|
|||
BLT_INFO("Starting thread execution service!");
|
||||
std::scoped_lock lock(thread_helper.thread_function_control);
|
||||
thread_execution_service = std::unique_ptr<std::function<void(blt::size_t)>>(new std::function(
|
||||
[this, &fitness_function, &crossover_selection, &mutation_selection, &reproduction_selection, &func](blt::size_t id)
|
||||
[this, &fitness_function, &crossover_selection, &mutation_selection, &reproduction_selection, &func](size_t id)
|
||||
{
|
||||
thread_helper.barrier.wait();
|
||||
|
||||
|
@ -719,9 +697,14 @@ namespace blt::gp
|
|||
return storage.operator_flags.find(static_cast<size_t>(id))->second.is_ephemeral();
|
||||
}
|
||||
|
||||
[[nodiscard]] bool operator_has_drop(const operator_id id) const
|
||||
[[nodiscard]] bool operator_has_ephemeral_drop(const operator_id id) const
|
||||
{
|
||||
return storage.operator_flags.find(static_cast<size_t>(id))->second.has_drop();
|
||||
return storage.operator_flags.find(static_cast<size_t>(id))->second.has_ephemeral_drop();
|
||||
}
|
||||
|
||||
[[nodiscard]] operator_special_flags get_operator_flags(const operator_id id) const
|
||||
{
|
||||
return storage.operator_flags.find(static_cast<size_t>(id))->second;
|
||||
}
|
||||
|
||||
void set_operations(program_operator_storage_t op)
|
||||
|
|
|
@ -42,11 +42,12 @@ namespace blt::gp
|
|||
namespace detail
|
||||
{
|
||||
BLT_META_MAKE_FUNCTION_CHECK(drop);
|
||||
BLT_META_MAKE_FUNCTION_CHECK(drop_ephemeral);
|
||||
}
|
||||
|
||||
class stack_allocator
|
||||
{
|
||||
constexpr static blt::size_t PAGE_SIZE = 0x100;
|
||||
constexpr static size_t PAGE_SIZE = 0x100;
|
||||
template <typename T>
|
||||
using NO_REF_T = std::remove_cv_t<std::remove_reference_t<T>>;
|
||||
using Allocator = aligned_allocator;
|
||||
|
@ -86,7 +87,7 @@ namespace blt::gp
|
|||
static constexpr size_t aligned_size() noexcept
|
||||
{
|
||||
const auto bytes = detail::aligned_size(sizeof(NO_REF_T<T>));
|
||||
if constexpr (blt::gp::detail::has_func_drop_v<T>)
|
||||
if constexpr (blt::gp::detail::has_func_drop_ephemeral_v<T>)
|
||||
return bytes + sizeof(std::atomic_uint64_t*);
|
||||
return bytes;
|
||||
}
|
||||
|
@ -166,10 +167,9 @@ namespace blt::gp
|
|||
static_assert(alignof(NO_REF) <= gp::detail::MAX_ALIGNMENT, "Type alignment must not be greater than the max alignment!");
|
||||
const auto ptr = static_cast<char*>(allocate_bytes_for_size(aligned_size<NO_REF>()));
|
||||
std::memcpy(ptr, &t, sizeof(NO_REF));
|
||||
// what about non ephemeral values?
|
||||
if constexpr (gp::detail::has_func_drop_v<T>)
|
||||
|
||||
if constexpr (gp::detail::has_func_drop_ephemeral_v<T>)
|
||||
{
|
||||
BLT_TRACE("Hello!");
|
||||
const auto* ref_counter_ptr = new std::atomic_uint64_t(1); // NOLINT
|
||||
std::memcpy(ptr + sizeof(NO_REF), &ref_counter_ptr, sizeof(std::atomic_uint64_t*));
|
||||
}
|
||||
|
@ -230,16 +230,16 @@ namespace blt::gp
|
|||
pop_bytes(aligned_bytes);
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
void call_destructors()
|
||||
{
|
||||
if constexpr (sizeof...(Args) > 0)
|
||||
{
|
||||
size_t offset = (aligned_size<NO_REF_T<Args>>() + ...) - aligned_size<NO_REF_T<typename meta::arg_helper<Args...>::First>>();
|
||||
((call_drop<Args>(offset + (gp::detail::has_func_drop_v<Args> ? sizeof(u64*) : 0)), offset -= aligned_size<NO_REF_T<Args>>()), ...);
|
||||
(void) offset;
|
||||
}
|
||||
}
|
||||
// template <typename... Args>
|
||||
// void call_destructors()
|
||||
// {
|
||||
// if constexpr (sizeof...(Args) > 0)
|
||||
// {
|
||||
// size_t offset = (aligned_size<NO_REF_T<Args>>() + ...) - aligned_size<NO_REF_T<typename meta::arg_helper<Args...>::First>>();
|
||||
// ((call_drop<Args>(offset + (gp::detail::has_func_drop_v<Args> ? sizeof(u64*) : 0)), offset -= aligned_size<NO_REF_T<Args>>()), ...);
|
||||
// (void) offset;
|
||||
// }
|
||||
// }
|
||||
|
||||
[[nodiscard]] bool empty() const noexcept
|
||||
{
|
||||
|
@ -338,14 +338,14 @@ namespace blt::gp
|
|||
return aligned_ptr;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void call_drop(const size_t offset)
|
||||
{
|
||||
if constexpr (blt::gp::detail::has_func_drop_v<T>)
|
||||
{
|
||||
from<NO_REF_T<T>>(offset).drop();
|
||||
}
|
||||
}
|
||||
// template <typename T>
|
||||
// void call_drop(const size_t offset)
|
||||
// {
|
||||
// if constexpr (blt::gp::detail::has_func_drop_v<T>)
|
||||
// {
|
||||
// from<NO_REF_T<T>>(offset).drop();
|
||||
// }
|
||||
// }
|
||||
|
||||
u8* data_ = nullptr;
|
||||
// place in the data_ array which has a free spot.
|
||||
|
|
|
@ -29,18 +29,39 @@
|
|||
#include <stack>
|
||||
#include <ostream>
|
||||
#include <atomic>
|
||||
#include <bits/locale_facets_nonio.h>
|
||||
|
||||
namespace blt::gp
|
||||
{
|
||||
struct op_container_t
|
||||
// TODO: i feel like this should be in its own class
|
||||
struct operator_special_flags
|
||||
{
|
||||
op_container_t(const size_t type_size, const operator_id id, const bool is_value):
|
||||
m_type_size(type_size), m_id(id), m_is_value(is_value), m_has_drop(false)
|
||||
explicit operator_special_flags(const bool is_ephemeral = false, const bool has_ephemeral_drop = false): m_ephemeral(is_ephemeral),
|
||||
m_ephemeral_drop(has_ephemeral_drop)
|
||||
{
|
||||
}
|
||||
|
||||
op_container_t(const size_t type_size, const operator_id id, const bool is_value, const bool has_drop):
|
||||
m_type_size(type_size), m_id(id), m_is_value(is_value), m_has_drop(has_drop)
|
||||
[[nodiscard]] bool is_ephemeral() const
|
||||
{
|
||||
return m_ephemeral;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool has_ephemeral_drop() const
|
||||
{
|
||||
return m_ephemeral_drop;
|
||||
}
|
||||
|
||||
private:
|
||||
bool m_ephemeral : 1;
|
||||
bool m_ephemeral_drop : 1;
|
||||
};
|
||||
|
||||
static_assert(sizeof(operator_special_flags) == 1, "Size of operator flags struct is expected to be 1 byte!");
|
||||
|
||||
struct op_container_t
|
||||
{
|
||||
op_container_t(const size_t type_size, const operator_id id, const bool is_value, const operator_special_flags flags):
|
||||
m_type_size(type_size), m_id(id), m_is_value(is_value), m_flags(flags)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -59,16 +80,21 @@ namespace blt::gp
|
|||
return m_is_value;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool has_drop() const
|
||||
[[nodiscard]] bool has_ephemeral_drop() const
|
||||
{
|
||||
return m_has_drop;
|
||||
return m_flags.has_ephemeral_drop();
|
||||
}
|
||||
|
||||
[[nodiscard]] operator_special_flags get_flags() const
|
||||
{
|
||||
return m_flags;
|
||||
}
|
||||
|
||||
private:
|
||||
size_t m_type_size;
|
||||
operator_id m_id;
|
||||
bool m_is_value;
|
||||
bool m_has_drop;
|
||||
operator_special_flags m_flags;
|
||||
};
|
||||
|
||||
class evaluation_context
|
||||
|
@ -76,7 +102,68 @@ namespace blt::gp
|
|||
public:
|
||||
explicit evaluation_context() = default;
|
||||
|
||||
blt::gp::stack_allocator values;
|
||||
stack_allocator values;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class evaluation_ref
|
||||
{
|
||||
public:
|
||||
explicit evaluation_ref(T& value, evaluation_context& context): m_value(&value), m_context(&context)
|
||||
{
|
||||
}
|
||||
|
||||
evaluation_ref(const evaluation_ref& copy) = delete;
|
||||
evaluation_ref& operator=(const evaluation_ref& copy) = delete;
|
||||
|
||||
evaluation_ref(evaluation_ref&& move) noexcept : m_value(move.m_value), m_context(move.m_context)
|
||||
{
|
||||
move.m_value = nullptr;
|
||||
move.m_context = nullptr;
|
||||
}
|
||||
|
||||
evaluation_ref& operator=(evaluation_ref&& move) noexcept
|
||||
{
|
||||
m_value = std::exchange(m_value, move.m_value);
|
||||
m_context = std::exchange(m_context, move.m_context);
|
||||
return *this;
|
||||
}
|
||||
|
||||
T& get()
|
||||
{
|
||||
return *m_value;
|
||||
}
|
||||
|
||||
const T& get() const
|
||||
{
|
||||
return *m_value;
|
||||
}
|
||||
|
||||
explicit operator T&()
|
||||
{
|
||||
return *m_value;
|
||||
}
|
||||
|
||||
explicit operator T&() const
|
||||
{
|
||||
return *m_value;
|
||||
}
|
||||
|
||||
~evaluation_ref()
|
||||
{
|
||||
if constexpr (detail::has_func_drop_v<T>)
|
||||
{
|
||||
if (m_value != nullptr)
|
||||
{
|
||||
m_value->drop();
|
||||
m_context->values.reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
T* m_value;
|
||||
evaluation_context* m_context;
|
||||
};
|
||||
|
||||
class tree_t
|
||||
|
@ -115,14 +202,13 @@ namespace blt::gp
|
|||
|
||||
for (; op_it != operations.end(); ++op_it)
|
||||
{
|
||||
if (op_it->has_drop())
|
||||
if (op_it->has_ephemeral_drop())
|
||||
{
|
||||
|
||||
}
|
||||
if (copy_it == copy.operations.end())
|
||||
break;
|
||||
*op_it = *copy_it;
|
||||
if (copy_it->has_drop())
|
||||
if (copy_it->has_ephemeral_drop())
|
||||
{
|
||||
}
|
||||
++copy_it;
|
||||
|
@ -130,7 +216,7 @@ namespace blt::gp
|
|||
const auto op_it_cpy = op_it;
|
||||
for (; op_it != operations.end(); ++op_it)
|
||||
{
|
||||
if (op_it->has_drop())
|
||||
if (op_it->has_ephemeral_drop())
|
||||
{
|
||||
}
|
||||
}
|
||||
|
@ -167,70 +253,87 @@ namespace blt::gp
|
|||
operations.emplace_back(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
[[nodiscard]] inline tracked_vector<op_container_t>& get_operations()
|
||||
[[nodiscard]] tracked_vector<op_container_t>& get_operations()
|
||||
{
|
||||
return operations;
|
||||
}
|
||||
|
||||
[[nodiscard]] inline const tracked_vector<op_container_t>& get_operations() const
|
||||
[[nodiscard]] const tracked_vector<op_container_t>& get_operations() const
|
||||
{
|
||||
return operations;
|
||||
}
|
||||
|
||||
[[nodiscard]] inline stack_allocator& get_values()
|
||||
[[nodiscard]] stack_allocator& get_values()
|
||||
{
|
||||
return values;
|
||||
}
|
||||
|
||||
[[nodiscard]] inline const blt::gp::stack_allocator& get_values() const
|
||||
[[nodiscard]] const stack_allocator& get_values() const
|
||||
{
|
||||
return values;
|
||||
}
|
||||
|
||||
template <typename T, std::enable_if_t<!(std::is_pointer_v<T> || std::is_null_pointer_v<T>), bool> = true>
|
||||
[[nodiscard]] evaluation_context& evaluate(const T& context) const
|
||||
{
|
||||
return (*func)(*this, const_cast<void*>(static_cast<const void*>(&context)));
|
||||
}
|
||||
|
||||
[[nodiscard]] evaluation_context& evaluate() const
|
||||
{
|
||||
return (*func)(*this, nullptr);
|
||||
}
|
||||
|
||||
blt::size_t get_depth(gp_program& program) const;
|
||||
|
||||
/**
|
||||
* Helper template for returning the result of the last evaluation
|
||||
*/
|
||||
template <typename T>
|
||||
T get_evaluation_value(evaluation_context& context) const
|
||||
{
|
||||
return context.values.pop<T>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper template for returning the result of the last evaluation
|
||||
*/
|
||||
template <typename T>
|
||||
T& get_evaluation_ref(evaluation_context& context) const
|
||||
{
|
||||
return context.values.from<T>(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper template for returning the result of evaluation (this calls it)
|
||||
*/
|
||||
* User function for evaluating this tree using a context reference. This function should only be used if the tree is expecting the context value
|
||||
* This function returns a copy of your value, if it is too large for the stack, or you otherwise need a reference, please use the corresponding
|
||||
* get_evaluation_ref function!
|
||||
*/
|
||||
template <typename T, typename Context>
|
||||
T get_evaluation_value(const Context& context) const
|
||||
{
|
||||
return evaluate(context).values.template pop<T>();
|
||||
auto& ctx = evaluate(context);
|
||||
auto val = ctx.values.template from<T>(0);
|
||||
if constexpr (detail::has_func_drop_v<T>)
|
||||
{
|
||||
ctx.values.template from<T>(0).drop();
|
||||
}
|
||||
ctx.values.reset();
|
||||
return val;
|
||||
}
|
||||
|
||||
/**
|
||||
* User function for evaluating this tree without a context reference. This function should only be used if the tree is expecting the context value
|
||||
* This function returns a copy of your value, if it is too large for the stack, or you otherwise need a reference, please use the corresponding
|
||||
* get_evaluation_ref function!
|
||||
*/
|
||||
template <typename T>
|
||||
T get_evaluation_value() const
|
||||
{
|
||||
return evaluate().values.pop<T>();
|
||||
auto& ctx = evaluate();
|
||||
auto val = ctx.values.from<T>(0);
|
||||
if constexpr (detail::has_func_drop_v<T>)
|
||||
{
|
||||
ctx.values.from<T>(0).drop();
|
||||
}
|
||||
ctx.values.reset();
|
||||
return val;
|
||||
}
|
||||
|
||||
/**
|
||||
* User function for evaluating the tree with context returning a reference to the value.
|
||||
* The class returned is used to automatically drop the value when you are done using it
|
||||
*/
|
||||
template <typename T, typename Context>
|
||||
evaluation_ref<T> get_evaluation_ref(const Context& context) const
|
||||
{
|
||||
auto& ctx = evaluate(context);
|
||||
auto& val = ctx.values.template from<T>(0);
|
||||
return evaluation_ref<T>{val, ctx};
|
||||
}
|
||||
|
||||
/**
|
||||
* User function for evaluating the tree without context returning a reference to the value.
|
||||
* The class returned is used to automatically drop the value when you are done using it
|
||||
*/
|
||||
template <typename T>
|
||||
evaluation_ref<T> get_evaluation_ref() const
|
||||
{
|
||||
auto& ctx = evaluate();
|
||||
auto& val = ctx.values.from<T>(0);
|
||||
return evaluation_ref<T>{val, ctx};
|
||||
}
|
||||
|
||||
void print(gp_program& program, std::ostream& output, bool print_literals = true, bool pretty_indent = false,
|
||||
|
@ -302,6 +405,17 @@ namespace blt::gp
|
|||
}
|
||||
|
||||
private:
|
||||
template <typename T, std::enable_if_t<!(std::is_pointer_v<T> || std::is_null_pointer_v<T>), bool> = true>
|
||||
[[nodiscard]] evaluation_context& evaluate(const T& context) const
|
||||
{
|
||||
return (*func)(*this, const_cast<void*>(static_cast<const void*>(&context)));
|
||||
}
|
||||
|
||||
[[nodiscard]] evaluation_context& evaluate() const
|
||||
{
|
||||
return (*func)(*this, nullptr);
|
||||
}
|
||||
|
||||
template <typename Context, typename Operator>
|
||||
static void execute(void* context, stack_allocator& write_stack, stack_allocator& read_stack, Operator& operation)
|
||||
{
|
||||
|
|
|
@ -48,7 +48,7 @@ namespace blt::gp
|
|||
template <typename T>
|
||||
static type make_type(const type_id id)
|
||||
{
|
||||
return type(stack_allocator::aligned_size<T>(), id, blt::type_string<T>(), detail::has_func_drop<T>::value);
|
||||
return type(stack_allocator::aligned_size<T>(), id, blt::type_string<T>(), detail::has_func_drop_ephemeral_v<T>);
|
||||
}
|
||||
|
||||
[[nodiscard]] size_t size() const
|
||||
|
@ -66,20 +66,20 @@ namespace blt::gp
|
|||
return name_;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool has_drop() const
|
||||
[[nodiscard]] bool has_ephemeral_drop() const
|
||||
{
|
||||
return has_drop_;
|
||||
return has_ephemeral_drop_;
|
||||
}
|
||||
private:
|
||||
type(const size_t size, const type_id id, const std::string_view name, const bool has_drop): size_(size), id_(id), name_(name),
|
||||
has_drop_(has_drop)
|
||||
type(const size_t size, const type_id id, const std::string_view name, const bool has_ephemeral_drop): size_(size), id_(id), name_(name),
|
||||
has_ephemeral_drop_(has_ephemeral_drop)
|
||||
{
|
||||
}
|
||||
|
||||
size_t size_{};
|
||||
type_id id_{};
|
||||
std::string name_{};
|
||||
bool has_drop_ = false;
|
||||
bool has_ephemeral_drop_ = false;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
2
lib/blt
2
lib/blt
|
@ -1 +1 @@
|
|||
Subproject commit 4c462dff38a982bc5dc5212337af160bc018cce1
|
||||
Subproject commit 7864ddc4de9c89f1986f1918180883a5c3580a5b
|
|
@ -64,7 +64,8 @@ namespace blt::gp
|
|||
tree.emplace_operator(
|
||||
args.program.get_typesystem().get_type(info.return_type).size(),
|
||||
top.id,
|
||||
args.program.is_operator_ephemeral(top.id));
|
||||
args.program.is_operator_ephemeral(top.id),
|
||||
args.program.get_operator_flags(top.id));
|
||||
max_depth = std::max(max_depth, top.depth);
|
||||
|
||||
if (args.program.is_operator_ephemeral(top.id))
|
||||
|
|
|
@ -62,7 +62,7 @@ namespace blt::gp
|
|||
auto& i_ref = pop.get_individuals();
|
||||
|
||||
u64 best = program.get_random().get_u64(0, pop.get_individuals().size());
|
||||
for (size_t i = 0; i < selection_size; i++)
|
||||
for (size_t i = 0; i < std::min(selection_size, pop.get_individuals().size()); i++)
|
||||
{
|
||||
u64 sel_point;
|
||||
do
|
||||
|
|
|
@ -522,7 +522,7 @@ namespace blt::gp
|
|||
vals.copy_to(data, total_bytes_after);
|
||||
vals.pop_bytes(static_cast<blt::ptrdiff_t>(total_bytes_after));
|
||||
|
||||
for (blt::ptrdiff_t i = static_cast<blt::ptrdiff_t>(replacement_func_info.argc.argc) - 1;
|
||||
for (ptrdiff_t i = static_cast<ptrdiff_t>(replacement_func_info.argc.argc) - 1;
|
||||
i >= current_func_info.argc.argc; i--)
|
||||
{
|
||||
auto& tree = get_static_tree_tl(program);
|
||||
|
@ -540,8 +540,10 @@ namespace blt::gp
|
|||
}
|
||||
// now finally update the type.
|
||||
ops[c_node] = {
|
||||
program.get_typesystem().get_type(replacement_func_info.return_type).size(), random_replacement,
|
||||
program.is_operator_ephemeral(random_replacement)
|
||||
program.get_typesystem().get_type(replacement_func_info.return_type).size(),
|
||||
random_replacement,
|
||||
program.is_operator_ephemeral(random_replacement),
|
||||
program.get_operator_flags(random_replacement)
|
||||
};
|
||||
}
|
||||
#if BLT_DEBUG_LEVEL >= 2
|
||||
|
@ -636,7 +638,9 @@ namespace blt::gp
|
|||
ops.insert(ops.begin() + static_cast<blt::ptrdiff_t>(c_node),
|
||||
{
|
||||
program.get_typesystem().get_type(replacement_func_info.return_type).size(),
|
||||
random_replacement, program.is_operator_ephemeral(random_replacement)
|
||||
random_replacement,
|
||||
program.is_operator_ephemeral(random_replacement),
|
||||
program.get_operator_flags(random_replacement)
|
||||
});
|
||||
|
||||
#if BLT_DEBUG_LEVEL >= 2
|
||||
|
|
|
@ -177,7 +177,7 @@ namespace blt::gp
|
|||
values_process.pop_back();
|
||||
}
|
||||
value_stack.push_back(local_depth + 1);
|
||||
operations_stack.emplace_back(operation.type_size(), operation.id(), true);
|
||||
operations_stack.emplace_back(operation.type_size(), operation.id(), true, program.get_operator_flags(operation.id()));
|
||||
}
|
||||
|
||||
return depth;
|
||||
|
@ -297,7 +297,7 @@ namespace blt::gp
|
|||
vec.push_back(next);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
tree_t::tree_t(gp_program& program): func(&program.get_eval_func())
|
||||
{
|
||||
|
||||
|
@ -310,7 +310,7 @@ namespace blt::gp
|
|||
func = f;
|
||||
for (const auto& op : operations)
|
||||
{
|
||||
if (op.has_drop())
|
||||
if (op.has_ephemeral_drop())
|
||||
{
|
||||
|
||||
}
|
||||
|
|
|
@ -21,13 +21,48 @@
|
|||
|
||||
using namespace blt::gp;
|
||||
|
||||
std::atomic_uint64_t normal_construct = 0;
|
||||
std::atomic_uint64_t ephemeral_construct = 0;
|
||||
std::atomic_uint64_t normal_drop = 0;
|
||||
std::atomic_uint64_t ephemeral_drop = 0;
|
||||
|
||||
struct drop_type
|
||||
{
|
||||
float silly_type;
|
||||
float value;
|
||||
bool ephemeral = false;
|
||||
|
||||
void drop() const
|
||||
drop_type() : value(0)
|
||||
{
|
||||
BLT_TRACE("Wow silly type of value %f was dropped!", silly_type);
|
||||
++normal_construct;
|
||||
}
|
||||
|
||||
explicit drop_type(const float silly) : value(silly)
|
||||
{
|
||||
++normal_construct;
|
||||
}
|
||||
|
||||
explicit drop_type(const float silly, bool) : value(silly), ephemeral(true)
|
||||
{
|
||||
// BLT_TRACE("Constructor with value %f", silly);
|
||||
++ephemeral_construct;
|
||||
}
|
||||
|
||||
void drop()
|
||||
{
|
||||
if (!ephemeral)
|
||||
++normal_drop;
|
||||
}
|
||||
|
||||
void drop_ephemeral() const
|
||||
{
|
||||
// BLT_TRACE("Wow silly type of value %f was dropped!", value);
|
||||
++ephemeral_drop;
|
||||
}
|
||||
|
||||
friend std::ostream& operator<<(std::ostream& os, const drop_type& dt)
|
||||
{
|
||||
os << dt.value;
|
||||
return os;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -44,39 +79,60 @@ prog_config_t config = prog_config_t()
|
|||
.set_mutation_chance(0.1)
|
||||
.set_reproduction_chance(0.1)
|
||||
.set_max_generations(50)
|
||||
.set_pop_size(500)
|
||||
.set_pop_size(50)
|
||||
.set_thread_count(0);
|
||||
|
||||
|
||||
example::symbolic_regression_t regression{691ul, config};
|
||||
|
||||
operation_t add{[](const float a, const float b) { return a + b; }, "add"};
|
||||
operation_t sub([](const float a, const float b) { return a - b; }, "sub");
|
||||
operation_t mul([](const float a, const float b) { return a * b; }, "mul");
|
||||
operation_t pro_div([](const float a, const float b) { return b == 0.0f ? 0.0f : a / b; }, "div");
|
||||
operation_t op_sin([](const float a) { return std::sin(a); }, "sin");
|
||||
operation_t op_cos([](const float a) { return std::cos(a); }, "cos");
|
||||
operation_t op_exp([](const float a) { return std::exp(a); }, "exp");
|
||||
operation_t op_log([](const float a) { return a == 0.0f ? 0.0f : std::log(a); }, "log");
|
||||
operation_t op_conv([](const drop_type d) { return d.silly_type; }, "conv");
|
||||
operation_t add{[](const drop_type a, const drop_type b) { return drop_type{a.value + b.value}; }, "add"};
|
||||
operation_t sub([](const drop_type a, const drop_type b) { return drop_type{a.value - b.value}; }, "sub");
|
||||
operation_t mul([](const drop_type a, const drop_type b) { return drop_type{a.value * b.value}; }, "mul");
|
||||
operation_t pro_div([](const drop_type a, const drop_type b) { return drop_type{b.value == 0.0f ? 0.0f : a.value / b.value}; }, "div");
|
||||
operation_t op_sin([](const drop_type a) { return drop_type{std::sin(a.value)}; }, "sin");
|
||||
operation_t op_cos([](const drop_type a) { return drop_type{std::cos(a.value)}; }, "cos");
|
||||
operation_t op_exp([](const drop_type a) { return drop_type{std::exp(a.value)}; }, "exp");
|
||||
operation_t op_log([](const drop_type a) { return drop_type{a.value <= 0.0f ? 0.0f : std::log(a.value)}; }, "log");
|
||||
auto lit = operation_t([]()
|
||||
{
|
||||
return drop_type{regression.get_program().get_random().get_float(-1.0f, 1.0f)};
|
||||
return drop_type{regression.get_program().get_random().get_float(-1.0f, 1.0f), true};
|
||||
}, "lit").set_ephemeral();
|
||||
|
||||
operation_t op_x([](const context& context)
|
||||
{
|
||||
return context.x;
|
||||
return drop_type{context.x};
|
||||
}, "x");
|
||||
|
||||
bool fitness_function(const tree_t& current_tree, fitness_t& fitness, size_t)
|
||||
{
|
||||
constexpr static double value_cutoff = 1.e15;
|
||||
for (auto& fitness_case : regression.get_training_cases())
|
||||
{
|
||||
auto val = current_tree.get_evaluation_ref<drop_type>(fitness_case);
|
||||
const auto diff = std::abs(fitness_case.y - val.get().value);
|
||||
if (diff < value_cutoff)
|
||||
{
|
||||
fitness.raw_fitness += diff;
|
||||
if (diff <= 0.01)
|
||||
fitness.hits++;
|
||||
}
|
||||
else
|
||||
fitness.raw_fitness += value_cutoff;
|
||||
}
|
||||
fitness.standardized_fitness = fitness.raw_fitness;
|
||||
fitness.adjusted_fitness = (1.0 / (1.0 + fitness.standardized_fitness));
|
||||
return static_cast<size_t>(fitness.hits) == regression.get_training_cases().size();
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
operator_builder<context> builder{};
|
||||
builder.build(add, sub, mul, pro_div, op_sin, op_cos, op_exp, op_log, lit, op_x);
|
||||
regression.get_program().set_operations(builder.grab());
|
||||
|
||||
regression.generate_initial_population();
|
||||
auto& program = regression.get_program();
|
||||
static auto sel = select_tournament_t{};
|
||||
program.generate_population(program.get_typesystem().get_type<drop_type>().id(), fitness_function, sel, sel, sel);
|
||||
while (!program.should_terminate())
|
||||
{
|
||||
BLT_TRACE("Creating next generation");
|
||||
|
@ -86,4 +142,11 @@ int main()
|
|||
BLT_TRACE("Evaluate Fitness");
|
||||
program.evaluate_fitness();
|
||||
}
|
||||
|
||||
// program.get_best_individuals<1>()[0].get().tree.print(program, std::cout, true, true);
|
||||
|
||||
BLT_TRACE("Created %ld times", normal_construct.load());
|
||||
BLT_TRACE("Dropped %ld times", normal_drop.load());
|
||||
BLT_TRACE("Ephemeral created %ld times", ephemeral_construct.load());
|
||||
BLT_TRACE("Ephemeral dropped %ld times", ephemeral_drop.load());
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue