moved operations into their own class for org. might not keep this
parent
1dc90f9c13
commit
cd930419ea
|
@ -1,5 +1,5 @@
|
||||||
cmake_minimum_required(VERSION 3.25)
|
cmake_minimum_required(VERSION 3.25)
|
||||||
project(blt-gp VERSION 0.0.27)
|
project(blt-gp VERSION 0.0.28)
|
||||||
|
|
||||||
option(ENABLE_ADDRSAN "Enable the address sanitizer" OFF)
|
option(ENABLE_ADDRSAN "Enable the address sanitizer" OFF)
|
||||||
option(ENABLE_UBSAN "Enable the ub sanitizer" OFF)
|
option(ENABLE_UBSAN "Enable the ub sanitizer" OFF)
|
||||||
|
|
|
@ -20,7 +20,6 @@
|
||||||
static constexpr long SEED = 41912;
|
static constexpr long SEED = 41912;
|
||||||
|
|
||||||
blt::gp::type_system type_system;
|
blt::gp::type_system type_system;
|
||||||
std::random_device dev;
|
|
||||||
blt::gp::gp_program program(type_system, std::mt19937_64{SEED}); // NOLINT
|
blt::gp::gp_program program(type_system, std::mt19937_64{SEED}); // NOLINT
|
||||||
|
|
||||||
blt::gp::operation_t add([](float a, float b) { return a + b; });
|
blt::gp::operation_t add([](float a, float b) { return a + b; });
|
||||||
|
@ -37,11 +36,14 @@ int main()
|
||||||
type_system.register_type<float>();
|
type_system.register_type<float>();
|
||||||
type_system.register_type<bool>();
|
type_system.register_type<bool>();
|
||||||
|
|
||||||
program.add_operator(add);
|
blt::gp::gp_operations silly{type_system};
|
||||||
program.add_operator(sub);
|
silly.add_operator(add);
|
||||||
program.add_operator(mul);
|
silly.add_operator(sub);
|
||||||
program.add_operator(pro_div);
|
silly.add_operator(mul);
|
||||||
program.add_operator(lit, true);
|
silly.add_operator(pro_div);
|
||||||
|
silly.add_operator(lit, true);
|
||||||
|
|
||||||
|
program.set_operations(std::move(silly));
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
|
@ -23,9 +23,66 @@
|
||||||
#include <blt/gp/typesystem.h>
|
#include <blt/gp/typesystem.h>
|
||||||
#include <blt/gp/stack.h>
|
#include <blt/gp/stack.h>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
namespace blt::gp
|
namespace blt::gp
|
||||||
{
|
{
|
||||||
|
namespace detail
|
||||||
|
{
|
||||||
|
using callable_t = std::function<void(void*, stack_allocator&)>;
|
||||||
|
struct empty_t
|
||||||
|
{
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Return, typename... Args>
|
||||||
|
struct call_with
|
||||||
|
{
|
||||||
|
template<blt::u64 index>
|
||||||
|
[[nodiscard]] inline constexpr static blt::size_t getByteOffset()
|
||||||
|
{
|
||||||
|
blt::size_t offset = 0;
|
||||||
|
blt::size_t current_index = 0;
|
||||||
|
((offset += (current_index++ > index ? stack_allocator::aligned_size<Args>() : 0)), ...);
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Func, blt::u64... indices, typename... ExtraArgs>
|
||||||
|
inline static constexpr Return exec_sequence_to_indices(Func&& func, stack_allocator& allocator, std::integer_sequence<blt::u64, indices...>,
|
||||||
|
ExtraArgs&& ... args)
|
||||||
|
{
|
||||||
|
// expands Args and indices, providing each argument with its index calculating the current argument byte offset
|
||||||
|
return std::forward<Func>(func)(std::forward<ExtraArgs>(args)..., allocator.from<Args>(getByteOffset<indices>())...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Func, typename... ExtraArgs>
|
||||||
|
Return operator()(Func&& func, stack_allocator& allocator, ExtraArgs&& ... args)
|
||||||
|
{
|
||||||
|
constexpr auto seq = std::make_integer_sequence<blt::u64, sizeof...(Args)>();
|
||||||
|
Return ret = exec_sequence_to_indices(std::forward<Func>(func), allocator, seq, std::forward<ExtraArgs>(args)...);
|
||||||
|
allocator.call_destructors<Args...>();
|
||||||
|
allocator.pop_bytes((stack_allocator::aligned_size<Args>() + ...));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename First, typename... Args>
|
||||||
|
struct first_arg
|
||||||
|
{
|
||||||
|
using type = First;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct first_arg<void>
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename Return, typename, typename... Args>
|
||||||
|
struct call_without_first : public call_with<Return, Args...>
|
||||||
|
{
|
||||||
|
using call_with<Return, Args...>::call_with;
|
||||||
|
};
|
||||||
|
|
||||||
template<typename>
|
template<typename>
|
||||||
class operation_t;
|
class operation_t;
|
||||||
|
|
||||||
|
@ -43,22 +100,6 @@ namespace blt::gp
|
||||||
constexpr explicit operation_t(const Functor& functor): func(functor)
|
constexpr explicit operation_t(const Functor& functor): func(functor)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
template<blt::u64 index>
|
|
||||||
[[nodiscard]] inline constexpr static blt::size_t getByteOffset()
|
|
||||||
{
|
|
||||||
blt::size_t offset = 0;
|
|
||||||
blt::size_t current_index = 0;
|
|
||||||
((offset += (current_index++ > index ? stack_allocator::aligned_size<Args>() : 0)), ...);
|
|
||||||
return offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<blt::u64... indices>
|
|
||||||
inline constexpr Return exec_sequence_to_indices(stack_allocator& allocator, std::integer_sequence<blt::u64, indices...>) const
|
|
||||||
{
|
|
||||||
// expands Args and indices, providing each argument with its index calculating the current argument byte offset
|
|
||||||
return func(allocator.from<Args>(getByteOffset<indices>())...);
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] constexpr inline Return operator()(stack_allocator& allocator) const
|
[[nodiscard]] constexpr inline Return operator()(stack_allocator& allocator) const
|
||||||
{
|
{
|
||||||
if constexpr (sizeof...(Args) == 0)
|
if constexpr (sizeof...(Args) == 0)
|
||||||
|
@ -66,18 +107,47 @@ namespace blt::gp
|
||||||
return func();
|
return func();
|
||||||
} else
|
} else
|
||||||
{
|
{
|
||||||
constexpr auto seq = std::make_integer_sequence<blt::u64, sizeof...(Args)>();
|
return call_with<Return, Args...>()(func, allocator);
|
||||||
Return ret = exec_sequence_to_indices(allocator, seq);
|
|
||||||
allocator.call_destructors<Args...>();
|
|
||||||
allocator.pop_bytes((stack_allocator::aligned_size<Args>() + ...));
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] std::function<void(stack_allocator&)> make_callable() const
|
[[nodiscard]] constexpr inline Return operator()(void* context, stack_allocator& allocator) const
|
||||||
{
|
{
|
||||||
return [this](stack_allocator& values) {
|
// should be an impossible state
|
||||||
values.push(this->operator()(values));
|
if constexpr (sizeof...(Args) == 0)
|
||||||
|
{
|
||||||
|
BLT_ABORT("Cannot pass context to function without arguments!");
|
||||||
|
}
|
||||||
|
auto& ctx_ref = *static_cast<typename first_arg<Args...>::type*>(context);
|
||||||
|
if constexpr (sizeof...(Args) == 1)
|
||||||
|
{
|
||||||
|
return func(ctx_ref);
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
return call_without_first<Return, Args...>()(func, allocator, ctx_ref);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Context>
|
||||||
|
[[nodiscard]] detail::callable_t make_callable() const
|
||||||
|
{
|
||||||
|
return [this](void* context, stack_allocator& values) {
|
||||||
|
if constexpr (sizeof...(Args) == 0)
|
||||||
|
{
|
||||||
|
values.push(this->operator()(values));
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
// annoying hack.
|
||||||
|
if constexpr (std::is_same_v<Context, typename first_arg<Args...>::type>)
|
||||||
|
{
|
||||||
|
// first arg is context
|
||||||
|
values.push(this->operator()(context, values));
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
// first arg isn't context
|
||||||
|
values.push(this->operator()(values));
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -101,7 +171,7 @@ namespace blt::gp
|
||||||
operation_t(Lambda) -> operation_t<decltype(&Lambda::operator())>;
|
operation_t(Lambda) -> operation_t<decltype(&Lambda::operator())>;
|
||||||
|
|
||||||
template<typename Return, typename... Args>
|
template<typename Return, typename... Args>
|
||||||
operation_t(Return (*)(Args...)) -> operation_t<Return(Args...)>;
|
operation_t(Return(*)(Args...)) -> operation_t<Return(Args...)>;
|
||||||
|
|
||||||
// templat\e<typename Return, typename Class, typename... Args>
|
// templat\e<typename Return, typename Class, typename... Args>
|
||||||
// operation_t<Return(Args...)> make_operator(Return (Class::*)(Args...) const lambda)
|
// operation_t<Return(Args...)> make_operator(Return (Class::*)(Args...) const lambda)
|
||||||
|
|
|
@ -46,6 +46,42 @@ namespace blt::gp
|
||||||
static constexpr blt::size_t STATIC_T = 0x1;
|
static constexpr blt::size_t STATIC_T = 0x1;
|
||||||
static constexpr blt::size_t TERMINAL_T = 0x2;
|
static constexpr blt::size_t TERMINAL_T = 0x2;
|
||||||
|
|
||||||
|
template<typename Context = detail::empty_t>
|
||||||
|
class gp_operations
|
||||||
|
{
|
||||||
|
friend class gp_program;
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit gp_operations(type_system& system): system(system)
|
||||||
|
{}
|
||||||
|
|
||||||
|
template<typename Return, typename... Args>
|
||||||
|
void add_operator(const operation_t<Return(Args...)>& op, bool is_static = false)
|
||||||
|
{
|
||||||
|
auto return_type_id = system.get_type<Return>().id();
|
||||||
|
auto operator_id = blt::gp::operator_id(operators.size());
|
||||||
|
|
||||||
|
auto& operator_list = op.get_argc() == 0 ? terminals : non_terminals;
|
||||||
|
operator_list[return_type_id].push_back(operator_id);
|
||||||
|
|
||||||
|
(argument_types[operator_id].push_back(system.get_type<Args>()), ...);
|
||||||
|
operators.push_back(op.template make_callable<Context>());
|
||||||
|
if (is_static)
|
||||||
|
static_types.insert(operator_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
type_system& system;
|
||||||
|
|
||||||
|
// indexed from return TYPE ID, returns index of operator
|
||||||
|
blt::expanding_buffer<std::vector<operator_id>> terminals;
|
||||||
|
blt::expanding_buffer<std::vector<operator_id>> non_terminals;
|
||||||
|
// indexed from OPERATOR ID (operator number)
|
||||||
|
blt::expanding_buffer<std::vector<type>> argument_types;
|
||||||
|
blt::hashset_t<operator_id> static_types;
|
||||||
|
std::vector<detail::callable_t> operators;
|
||||||
|
};
|
||||||
|
|
||||||
class gp_program
|
class gp_program
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -105,19 +141,14 @@ namespace blt::gp
|
||||||
return static_types.contains(static_cast<blt::size_t>(id));
|
return static_types.contains(static_cast<blt::size_t>(id));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Return, typename... Args>
|
template<typename Context>
|
||||||
void add_operator(const operation_t<Return(Args...)>& op, bool is_static = false)
|
inline void set_operations(gp_operations<Context>&& op)
|
||||||
{
|
{
|
||||||
auto return_type_id = system.get_type<Return>().id();
|
terminals = std::move(op.terminals);
|
||||||
auto operator_id = blt::gp::operator_id(operators.size());
|
non_terminals = std::move(op.non_terminals);
|
||||||
|
argument_types = std::move(op.argument_types);
|
||||||
auto& operator_list = op.get_argc() == 0 ? terminals : non_terminals;
|
static_types = std::move(op.static_types);
|
||||||
operator_list[return_type_id].push_back(operator_id);
|
operators = std::move(op.operators);
|
||||||
|
|
||||||
(argument_types[operator_id].push_back(system.get_type<Args>()), ...);
|
|
||||||
operators.push_back(op.make_callable());
|
|
||||||
if (is_static)
|
|
||||||
static_types.insert(operator_id);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -131,7 +162,7 @@ namespace blt::gp
|
||||||
// indexed from OPERATOR ID (operator number)
|
// indexed from OPERATOR ID (operator number)
|
||||||
blt::expanding_buffer<std::vector<type>> argument_types;
|
blt::expanding_buffer<std::vector<type>> argument_types;
|
||||||
blt::hashset_t<operator_id> static_types;
|
blt::hashset_t<operator_id> static_types;
|
||||||
std::vector<std::function<void(stack_allocator&)>> operators;
|
std::vector<detail::callable_t> operators;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
2
lib/blt
2
lib/blt
|
@ -1 +1 @@
|
||||||
Subproject commit cc788e98f4a739f450f487f6a7c758990128a698
|
Subproject commit ac163a34b9d70346df80fcac44054e8dffe9ad43
|
|
@ -40,13 +40,13 @@ namespace blt::gp
|
||||||
base_type = system.select_type(program.get_random());
|
base_type = system.select_type(program.get_random());
|
||||||
} while (program.get_type_non_terminals(base_type.id()).empty());
|
} while (program.get_type_non_terminals(base_type.id()).empty());
|
||||||
|
|
||||||
tree_generator.emplace(program.select_non_terminal(base_type.id()), 0);
|
tree_generator.push(stack{program.select_non_terminal(base_type.id()), 0});
|
||||||
|
|
||||||
return tree_generator;
|
return tree_generator;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Func>
|
template<typename Func>
|
||||||
tree_t create_tree(Func func, gp_program& program, blt::size_t min_depth, blt::size_t max_depth)
|
tree_t create_tree(Func, gp_program& program, blt::size_t, blt::size_t)
|
||||||
{
|
{
|
||||||
std::stack<stack> tree_generator = get_base_generator(program);
|
std::stack<stack> tree_generator = get_base_generator(program);
|
||||||
tree_t tree;
|
tree_t tree;
|
||||||
|
|
Loading…
Reference in New Issue