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)
project(blt-gp VERSION 0.0.31)
project(blt-gp VERSION 0.0.33)
option(ENABLE_ADDRSAN "Enable the address 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(true);
alloc.push(false);
alloc.push(std::string("SillyString"));
//alloc.push(std::string("SillyString"));
alloc.push(&"SillyString");
std::cout << 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<double>() << std::endl;
@ -389,7 +389,7 @@ int main_old()
alloc.push(50);
alloc.push(550.3f);
alloc.push(20.1230345);
alloc.push(std::string("SillyString"));
//alloc.push(std::string("SillyString"));
alloc.push(33.22f);
alloc.push(120);
alloc.push(true);

View File

@ -29,6 +29,10 @@ namespace blt::gp
class type_system;
struct op_container_t;
class evaluation_context;
class tree_t;
class population_t;

View File

@ -25,53 +25,89 @@
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
class tree_generator_t
{
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
{
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
{
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
{
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:
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:
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:
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:
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>
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>;
static_assert(std::is_trivially_copyable_v<NO_REF_T> && "Type must be bitwise copyable!");
auto ptr = allocate_bytes<T>();
head->metadata.offset = static_cast<blt::u8*>(ptr) + aligned_size<T>();
new(ptr) NO_REF_T(std::forward<T>(value));
@ -51,6 +51,7 @@ namespace blt::gp
template<typename T>
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>();
if (head == nullptr)
throw std::runtime_error("Silly boi the stack is empty!");

View File

@ -24,13 +24,34 @@
#include <blt/gp/fwdecl.h>
#include <blt/std/types.h>
#include <utility>
#include <stack>
namespace blt::gp
{
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;
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
@ -66,6 +87,36 @@ namespace blt::gp
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:
bool valid = false;
std::vector<op_container_t> operations;
@ -76,6 +127,10 @@ namespace blt::gp
class population_t
{
public:
std::vector<tree_t>& getIndividuals()
{
return individuals;
}
private:
std::vector<tree_t> individuals;

View File

@ -21,6 +21,8 @@
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
{
@ -28,27 +30,27 @@ namespace blt::gp
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;
auto& system = program.get_typesystem();
// select a type which has a non-empty set of non-terminals
type base_type;
do
{
base_type = system.select_type(program.get_random());
} while (program.get_type_non_terminals(base_type.id()).empty());
tree_generator.push(stack{program.select_non_terminal(base_type.id()), 1});
//
// auto& system = program.get_typesystem();
// // select a type which has a non-empty set of non-terminals
// type base_type;
// do
// {
// base_type = system.select_type(program.get_random());
// } while (program.get_type_non_terminals(base_type.id()).empty());
//
tree_generator.push(stack{program.select_non_terminal(root_type), 1});
return tree_generator;
}
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;
tree_t tree;
@ -57,18 +59,24 @@ namespace blt::gp
auto top = tree_generator.top();
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);
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;
}
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;
}
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) {
if (new_depth >= max_depth)
return create_tree([args](gp_program& program, std::stack<stack>& tree_generator, const type& type, blt::size_t new_depth) {
if (new_depth >= args.max_depth)
{
tree_generator.push({program.select_terminal(type.id()), new_depth});
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});
else
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) {
if (new_depth >= max_depth)
return create_tree([args](gp_program& program, std::stack<stack>& tree_generator, const type& type, blt::size_t new_depth) {
if (new_depth >= args.max_depth)
{
tree_generator.push({program.select_terminal(type.id()), new_depth});
return;
}
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;
}
}