drop is now being called correctly.

dev-func-drop
Brett 2025-01-15 21:10:35 -05:00
parent 8917fc12f7
commit 8594c44bae
14 changed files with 331 additions and 153 deletions

View File

@ -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)

View File

@ -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);

View File

@ -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{};
};

View File

@ -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;

View File

@ -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)

View File

@ -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.

View File

@ -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)
{

View File

@ -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;
};
/**

@ -1 +1 @@
Subproject commit 4c462dff38a982bc5dc5212337af160bc018cce1
Subproject commit 7864ddc4de9c89f1986f1918180883a5c3580a5b

View File

@ -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))

View File

@ -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

View File

@ -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

View File

@ -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())
{
}

View File

@ -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());
}