almost at evaluation
parent
7a558f1cc1
commit
7511e2508b
|
@ -1,5 +1,5 @@
|
||||||
cmake_minimum_required(VERSION 3.25)
|
cmake_minimum_required(VERSION 3.25)
|
||||||
project(blt-gp VERSION 0.0.31)
|
project(blt-gp VERSION 0.0.33)
|
||||||
|
|
||||||
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)
|
||||||
|
|
|
@ -345,12 +345,12 @@ int main_old()
|
||||||
alloc.push(20.1230345);
|
alloc.push(20.1230345);
|
||||||
alloc.push(true);
|
alloc.push(true);
|
||||||
alloc.push(false);
|
alloc.push(false);
|
||||||
alloc.push(std::string("SillyString"));
|
//alloc.push(std::string("SillyString"));
|
||||||
alloc.push(&"SillyString");
|
alloc.push(&"SillyString");
|
||||||
|
|
||||||
std::cout << std::endl;
|
std::cout << std::endl;
|
||||||
std::cout << *alloc.pop<decltype(&"SillString")>() << std::endl;
|
std::cout << *alloc.pop<decltype(&"SillString")>() << std::endl;
|
||||||
std::cout << alloc.pop<std::string>() << std::endl;
|
//std::cout << alloc.pop<std::string>() << std::endl;
|
||||||
std::cout << alloc.pop<bool>() << std::endl;
|
std::cout << alloc.pop<bool>() << std::endl;
|
||||||
std::cout << alloc.pop<bool>() << std::endl;
|
std::cout << alloc.pop<bool>() << std::endl;
|
||||||
std::cout << alloc.pop<double>() << std::endl;
|
std::cout << alloc.pop<double>() << std::endl;
|
||||||
|
@ -389,7 +389,7 @@ int main_old()
|
||||||
alloc.push(50);
|
alloc.push(50);
|
||||||
alloc.push(550.3f);
|
alloc.push(550.3f);
|
||||||
alloc.push(20.1230345);
|
alloc.push(20.1230345);
|
||||||
alloc.push(std::string("SillyString"));
|
//alloc.push(std::string("SillyString"));
|
||||||
alloc.push(33.22f);
|
alloc.push(33.22f);
|
||||||
alloc.push(120);
|
alloc.push(120);
|
||||||
alloc.push(true);
|
alloc.push(true);
|
||||||
|
|
|
@ -29,6 +29,10 @@ namespace blt::gp
|
||||||
|
|
||||||
class type_system;
|
class type_system;
|
||||||
|
|
||||||
|
struct op_container_t;
|
||||||
|
|
||||||
|
class evaluation_context;
|
||||||
|
|
||||||
class tree_t;
|
class tree_t;
|
||||||
|
|
||||||
class population_t;
|
class population_t;
|
||||||
|
|
|
@ -25,53 +25,89 @@
|
||||||
namespace blt::gp
|
namespace blt::gp
|
||||||
{
|
{
|
||||||
|
|
||||||
|
struct generator_arguments
|
||||||
|
{
|
||||||
|
gp_program& program;
|
||||||
|
type_id root_type;
|
||||||
|
blt::size_t min_depth;
|
||||||
|
blt::size_t max_depth;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct initializer_arguments
|
||||||
|
{
|
||||||
|
gp_program& program;
|
||||||
|
type_id root_type;
|
||||||
|
blt::size_t size;
|
||||||
|
blt::size_t min_depth;
|
||||||
|
blt::size_t max_depth;
|
||||||
|
|
||||||
|
[[nodiscard]] generator_arguments to_gen_args() const
|
||||||
|
{
|
||||||
|
return {program, root_type, min_depth, max_depth};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// base class for any kind of tree generator
|
// base class for any kind of tree generator
|
||||||
class tree_generator_t
|
class tree_generator_t
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual tree_t generate(gp_program& program, blt::size_t min_depth, blt::size_t max_depth) = 0;
|
virtual tree_t generate(const generator_arguments& args) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
class grow_generator_t : public tree_generator_t
|
class grow_generator_t : public tree_generator_t
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
tree_t generate(gp_program& program, blt::size_t min_depth, blt::size_t max_depth) final;
|
tree_t generate(const generator_arguments& args) final;
|
||||||
};
|
};
|
||||||
|
|
||||||
class full_generator_t : public tree_generator_t
|
class full_generator_t : public tree_generator_t
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
tree_t generate(gp_program& program, blt::size_t min_depth, blt::size_t max_depth) final;
|
tree_t generate(const generator_arguments& args) final;
|
||||||
};
|
};
|
||||||
|
|
||||||
class population_initializer_t
|
class population_initializer_t
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual population_t generate(gp_program& program, blt::size_t size, blt::size_t min_depth, blt::size_t max_depth) = 0;
|
virtual population_t generate(const initializer_arguments& args) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
class grow_initializer_t
|
class grow_initializer_t : public population_initializer_t
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
population_t generate(gp_program& program, blt::size_t size, blt::size_t min_depth, blt::size_t max_depth) final;
|
population_t generate(const initializer_arguments& args) final;
|
||||||
|
|
||||||
|
private:
|
||||||
|
grow_generator_t grow;
|
||||||
};
|
};
|
||||||
|
|
||||||
class full_initializer_t
|
class full_initializer_t : public population_initializer_t
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
population_t generate(gp_program& program, blt::size_t size, blt::size_t min_depth, blt::size_t max_depth) final;
|
population_t generate(const initializer_arguments& args) final;
|
||||||
|
|
||||||
|
private:
|
||||||
|
full_generator_t full;
|
||||||
};
|
};
|
||||||
|
|
||||||
class half_half_initializer_t
|
class half_half_initializer_t : public population_initializer_t
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
population_t generate(gp_program& program, blt::size_t size, blt::size_t min_depth, blt::size_t max_depth) final;
|
population_t generate(const initializer_arguments& args) final;
|
||||||
|
|
||||||
|
private:
|
||||||
|
grow_generator_t grow;
|
||||||
|
full_generator_t full;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ramped_half_initializer_t
|
class ramped_half_initializer_t : public population_initializer_t
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
population_t generate(gp_program& program, blt::size_t size, blt::size_t min_depth, blt::size_t max_depth) final;
|
population_t generate(const initializer_arguments& args) final;
|
||||||
|
|
||||||
|
private:
|
||||||
|
grow_generator_t grow;
|
||||||
|
full_generator_t full;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,8 +41,8 @@ namespace blt::gp
|
||||||
template<typename T>
|
template<typename T>
|
||||||
void push(T&& value)
|
void push(T&& value)
|
||||||
{
|
{
|
||||||
static_assert(std::is_trivially_copyable_v<T> && "Type must be bitwise copyable!");
|
|
||||||
using NO_REF_T = std::remove_reference_t<T>;
|
using NO_REF_T = std::remove_reference_t<T>;
|
||||||
|
static_assert(std::is_trivially_copyable_v<NO_REF_T> && "Type must be bitwise copyable!");
|
||||||
auto ptr = allocate_bytes<T>();
|
auto ptr = allocate_bytes<T>();
|
||||||
head->metadata.offset = static_cast<blt::u8*>(ptr) + aligned_size<T>();
|
head->metadata.offset = static_cast<blt::u8*>(ptr) + aligned_size<T>();
|
||||||
new(ptr) NO_REF_T(std::forward<T>(value));
|
new(ptr) NO_REF_T(std::forward<T>(value));
|
||||||
|
@ -51,6 +51,7 @@ namespace blt::gp
|
||||||
template<typename T>
|
template<typename T>
|
||||||
T pop()
|
T pop()
|
||||||
{
|
{
|
||||||
|
static_assert(std::is_trivially_copyable_v<std::remove_reference_t<T>> && "Type must be bitwise copyable!");
|
||||||
constexpr static auto TYPE_SIZE = aligned_size<T>();
|
constexpr static auto TYPE_SIZE = aligned_size<T>();
|
||||||
if (head == nullptr)
|
if (head == nullptr)
|
||||||
throw std::runtime_error("Silly boi the stack is empty!");
|
throw std::runtime_error("Silly boi the stack is empty!");
|
||||||
|
|
|
@ -24,13 +24,34 @@
|
||||||
#include <blt/gp/fwdecl.h>
|
#include <blt/gp/fwdecl.h>
|
||||||
#include <blt/std/types.h>
|
#include <blt/std/types.h>
|
||||||
|
|
||||||
|
#include <utility>
|
||||||
|
#include <stack>
|
||||||
|
|
||||||
namespace blt::gp
|
namespace blt::gp
|
||||||
{
|
{
|
||||||
|
|
||||||
struct op_container_t
|
struct op_container_t
|
||||||
{
|
{
|
||||||
blt::gp::operator_id op_id;
|
op_container_t(detail::callable_t& func, u16 depth, bool isStatic, u16 argc, u8 argcContext):
|
||||||
|
func(func), depth(depth), is_static(isStatic), argc(argc), argc_context(argcContext)
|
||||||
|
{}
|
||||||
|
|
||||||
|
detail::callable_t& func;
|
||||||
blt::u16 depth;
|
blt::u16 depth;
|
||||||
|
bool is_static: 1;
|
||||||
|
blt::u16 argc: 15;
|
||||||
|
blt::u8 argc_context;
|
||||||
|
};
|
||||||
|
|
||||||
|
class evaluation_context
|
||||||
|
{
|
||||||
|
friend class tree_t;
|
||||||
|
|
||||||
|
private:
|
||||||
|
explicit evaluation_context(stack_allocator values): values(std::move(values))
|
||||||
|
{}
|
||||||
|
|
||||||
|
blt::gp::stack_allocator values;
|
||||||
};
|
};
|
||||||
|
|
||||||
class tree_t
|
class tree_t
|
||||||
|
@ -65,6 +86,36 @@ namespace blt::gp
|
||||||
valid = true;
|
valid = true;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
evaluation_context evaluate(void* context);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper template for returning the result of the last evaluation
|
||||||
|
*/
|
||||||
|
template<typename T>
|
||||||
|
T get_evaluation_value(evaluation_context& context)
|
||||||
|
{
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
return context.values.from<T>(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper template for returning the result of evalutation (this calls it)
|
||||||
|
*/
|
||||||
|
template<typename T>
|
||||||
|
T get_evaluation_value(void* context)
|
||||||
|
{
|
||||||
|
auto results = evaluate(context);
|
||||||
|
return results.values.pop<T>();
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool valid = false;
|
bool valid = false;
|
||||||
|
@ -76,6 +127,10 @@ namespace blt::gp
|
||||||
class population_t
|
class population_t
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
std::vector<tree_t>& getIndividuals()
|
||||||
|
{
|
||||||
|
return individuals;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<tree_t> individuals;
|
std::vector<tree_t> individuals;
|
||||||
|
|
|
@ -21,6 +21,8 @@
|
||||||
|
|
||||||
namespace blt::gp
|
namespace blt::gp
|
||||||
{
|
{
|
||||||
|
// TODO: change how the generators work, but keep how nice everything is within the C++ file. less headers!
|
||||||
|
// maybe have tree call the generate functions with out variables as the members of tree_t
|
||||||
|
|
||||||
struct stack
|
struct stack
|
||||||
{
|
{
|
||||||
|
@ -28,27 +30,27 @@ namespace blt::gp
|
||||||
blt::size_t depth;
|
blt::size_t depth;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline std::stack<stack> get_initial_stack(gp_program& program)
|
inline std::stack<stack> get_initial_stack(gp_program& program, type_id root_type)
|
||||||
{
|
{
|
||||||
std::stack<stack> tree_generator;
|
std::stack<stack> tree_generator;
|
||||||
|
//
|
||||||
auto& system = program.get_typesystem();
|
// auto& system = program.get_typesystem();
|
||||||
// select a type which has a non-empty set of non-terminals
|
// // select a type which has a non-empty set of non-terminals
|
||||||
type base_type;
|
// type base_type;
|
||||||
do
|
// do
|
||||||
{
|
// {
|
||||||
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.push(stack{program.select_non_terminal(base_type.id()), 1});
|
tree_generator.push(stack{program.select_non_terminal(root_type), 1});
|
||||||
|
|
||||||
return tree_generator;
|
return tree_generator;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Func>
|
template<typename Func>
|
||||||
inline tree_t create_tree(Func&& perChild, gp_program& program)
|
inline tree_t create_tree(Func&& perChild, const generator_arguments& args)
|
||||||
{
|
{
|
||||||
std::stack<stack> tree_generator = get_initial_stack(program);
|
std::stack<stack> tree_generator = get_initial_stack(args.program, args.root_type);
|
||||||
blt::size_t max_depth = 0;
|
blt::size_t max_depth = 0;
|
||||||
tree_t tree;
|
tree_t tree;
|
||||||
|
|
||||||
|
@ -57,18 +59,24 @@ namespace blt::gp
|
||||||
auto top = tree_generator.top();
|
auto top = tree_generator.top();
|
||||||
tree_generator.pop();
|
tree_generator.pop();
|
||||||
|
|
||||||
tree.get_operations().push_back({top.id, static_cast<blt::u16>(top.depth)});
|
tree.get_operations().emplace_back(
|
||||||
|
args.program.get_operation(top.id),
|
||||||
|
static_cast<blt::u16>(top.depth),
|
||||||
|
args.program.is_static(top.id),
|
||||||
|
static_cast<blt::u16>(args.program.get_argc(top.id).argc),
|
||||||
|
static_cast<blt::u8>(args.program.get_argc(top.id).argc_context)
|
||||||
|
);
|
||||||
max_depth = std::max(max_depth, top.depth);
|
max_depth = std::max(max_depth, top.depth);
|
||||||
|
|
||||||
if (program.is_static(top.id))
|
if (args.program.is_static(top.id))
|
||||||
{
|
{
|
||||||
program.get_operation(top.id)(nullptr, tree.get_values());
|
args.program.get_operation(top.id)(nullptr, tree.get_values());
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const auto& child : program.get_argument_types(top.id))
|
for (const auto& child : args.program.get_argument_types(top.id))
|
||||||
{
|
{
|
||||||
std::forward<Func>(perChild)(program, tree_generator, child, top.depth + 1);
|
std::forward<Func>(perChild)(args.program, tree_generator, child, top.depth + 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,50 +85,96 @@ namespace blt::gp
|
||||||
return tree;
|
return tree;
|
||||||
}
|
}
|
||||||
|
|
||||||
tree_t grow_generator_t::generate(gp_program& program, blt::size_t min_depth, blt::size_t max_depth)
|
tree_t grow_generator_t::generate(const generator_arguments& args)
|
||||||
{
|
{
|
||||||
return create_tree([min_depth, max_depth](gp_program& program, std::stack<stack>& tree_generator, const type& type, blt::size_t new_depth) {
|
return create_tree([args](gp_program& program, std::stack<stack>& tree_generator, const type& type, blt::size_t new_depth) {
|
||||||
if (new_depth >= max_depth)
|
if (new_depth >= args.max_depth)
|
||||||
{
|
{
|
||||||
tree_generator.push({program.select_terminal(type.id()), new_depth});
|
tree_generator.push({program.select_terminal(type.id()), new_depth});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (program.choice() || new_depth < min_depth)
|
if (program.choice() || new_depth < args.min_depth)
|
||||||
tree_generator.push({program.select_non_terminal(type.id()), new_depth});
|
tree_generator.push({program.select_non_terminal(type.id()), new_depth});
|
||||||
else
|
else
|
||||||
tree_generator.push({program.select_terminal(type.id()), new_depth});
|
tree_generator.push({program.select_terminal(type.id()), new_depth});
|
||||||
}, program);
|
}, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
tree_t full_generator_t::generate(gp_program& program, blt::size_t, blt::size_t max_depth)
|
tree_t full_generator_t::generate(const generator_arguments& args)
|
||||||
{
|
{
|
||||||
return create_tree([max_depth](gp_program& program, std::stack<stack>& tree_generator, const type& type, blt::size_t new_depth) {
|
return create_tree([args](gp_program& program, std::stack<stack>& tree_generator, const type& type, blt::size_t new_depth) {
|
||||||
if (new_depth >= max_depth)
|
if (new_depth >= args.max_depth)
|
||||||
{
|
{
|
||||||
tree_generator.push({program.select_terminal(type.id()), new_depth});
|
tree_generator.push({program.select_terminal(type.id()), new_depth});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
tree_generator.push({program.select_non_terminal(type.id()), new_depth});
|
tree_generator.push({program.select_non_terminal(type.id()), new_depth});
|
||||||
}, program);
|
}, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
population_t grow_initializer_t::generate(gp_program& program, blt::size_t size, blt::size_t min_depth, blt::size_t max_depth)
|
population_t grow_initializer_t::generate(const initializer_arguments& args)
|
||||||
{
|
{
|
||||||
return population_t();
|
population_t pop;
|
||||||
|
|
||||||
|
for (auto i = 0ul; i < args.size; i++)
|
||||||
|
pop.getIndividuals().push_back(grow.generate(args.to_gen_args()));
|
||||||
|
|
||||||
|
return pop;
|
||||||
}
|
}
|
||||||
|
|
||||||
population_t full_initializer_t::generate(gp_program& program, blt::size_t size, blt::size_t min_depth, blt::size_t max_depth)
|
population_t full_initializer_t::generate(const initializer_arguments& args)
|
||||||
{
|
{
|
||||||
return population_t();
|
population_t pop;
|
||||||
|
|
||||||
|
for (auto i = 0ul; i < args.size; i++)
|
||||||
|
pop.getIndividuals().push_back(full.generate(args.to_gen_args()));
|
||||||
|
|
||||||
|
return pop;
|
||||||
}
|
}
|
||||||
|
|
||||||
population_t half_half_initializer_t::generate(gp_program& program, blt::size_t size, blt::size_t min_depth, blt::size_t max_depth)
|
population_t half_half_initializer_t::generate(const initializer_arguments& args)
|
||||||
{
|
{
|
||||||
return population_t();
|
population_t pop;
|
||||||
|
|
||||||
|
for (auto i = 0ul; i < args.size; i++)
|
||||||
|
{
|
||||||
|
if (args.program.choice())
|
||||||
|
pop.getIndividuals().push_back(full.generate(args.to_gen_args()));
|
||||||
|
else
|
||||||
|
pop.getIndividuals().push_back(grow.generate(args.to_gen_args()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return pop;
|
||||||
}
|
}
|
||||||
|
|
||||||
population_t ramped_half_initializer_t::generate(gp_program& program, blt::size_t size, blt::size_t min_depth, blt::size_t max_depth)
|
population_t ramped_half_initializer_t::generate(const initializer_arguments& args)
|
||||||
{
|
{
|
||||||
return population_t();
|
auto steps = args.max_depth - args.min_depth;
|
||||||
|
auto per_step = args.size / steps;
|
||||||
|
auto remainder = args.size % steps;
|
||||||
|
population_t pop;
|
||||||
|
|
||||||
|
for (auto depth : blt::range(args.min_depth, args.max_depth))
|
||||||
|
{
|
||||||
|
for (auto i = 0ul; i < per_step; i++)
|
||||||
|
{
|
||||||
|
if (args.program.choice())
|
||||||
|
pop.getIndividuals().push_back(full.generate({args.program, args.root_type, args.min_depth, depth}));
|
||||||
|
else
|
||||||
|
pop.getIndividuals().push_back(grow.generate({args.program, args.root_type, args.min_depth, depth}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto i = 0ul; i < remainder; i++)
|
||||||
|
{
|
||||||
|
if (args.program.choice())
|
||||||
|
pop.getIndividuals().push_back(full.generate(args.to_gen_args()));
|
||||||
|
else
|
||||||
|
pop.getIndividuals().push_back(grow.generate(args.to_gen_args()));
|
||||||
|
}
|
||||||
|
|
||||||
|
blt_assert(pop.getIndividuals().size() == args.size);
|
||||||
|
|
||||||
|
return pop;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,33 @@
|
||||||
|
/*
|
||||||
|
* <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/>.
|
||||||
|
*/
|
||||||
|
#include <blt/gp/tree.h>
|
||||||
|
|
||||||
|
namespace blt::gp
|
||||||
|
{
|
||||||
|
evaluation_context tree_t::evaluate(void* context)
|
||||||
|
{
|
||||||
|
evaluation_context results {values};
|
||||||
|
|
||||||
|
auto& value_stack = results.values;
|
||||||
|
std::stack<op_container_t> operations_stack;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue