almost at evaluation

thread
Brett 2024-06-25 22:21:41 -04:00
parent 7a558f1cc1
commit 7511e2508b
8 changed files with 236 additions and 53 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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
@ -66,6 +87,36 @@ namespace blt::gp
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;
std::vector<op_container_t> operations; std::vector<op_container_t> operations;
@ -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;

View File

@ -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()));
} }
population_t ramped_half_initializer_t::generate(gp_program& program, blt::size_t size, blt::size_t min_depth, blt::size_t max_depth) return pop;
}
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;
} }
} }

33
src/tree.cpp Normal file
View File

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