almost at evaluation
parent
7a558f1cc1
commit
7511e2508b
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -29,6 +29,10 @@ namespace blt::gp
|
|||
|
||||
class type_system;
|
||||
|
||||
struct op_container_t;
|
||||
|
||||
class evaluation_context;
|
||||
|
||||
class tree_t;
|
||||
|
||||
class population_t;
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -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!");
|
||||
|
|
|
@ -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
|
||||
|
@ -65,6 +86,36 @@ namespace blt::gp
|
|||
valid = true;
|
||||
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;
|
||||
|
@ -76,6 +127,10 @@ namespace blt::gp
|
|||
class population_t
|
||||
{
|
||||
public:
|
||||
std::vector<tree_t>& getIndividuals()
|
||||
{
|
||||
return individuals;
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<tree_t> individuals;
|
||||
|
|
|
@ -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()));
|
||||
}
|
||||
|
||||
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