main
Brett 2025-04-11 19:49:57 -04:00
parent d14ccfd1da
commit 62af2584d1
7 changed files with 102 additions and 35 deletions

View File

@ -640,7 +640,7 @@ namespace blt::gp
return thread_helper.lifetime_over;
}
operator_id select_terminal(type_id id)
operator_id select_terminal(const type_id id)
{
// we wanted a terminal, but could not find one, so we will select from a function that has a terminal
if (storage.terminals[id].empty())
@ -648,7 +648,7 @@ namespace blt::gp
return get_random().select(storage.terminals[id]);
}
operator_id select_non_terminal(type_id id)
operator_id select_non_terminal(const type_id id)
{
// non-terminal doesn't exist, return a terminal. This is useful for types that are defined only to have a random value, nothing more.
// was considering an std::optional<> but that would complicate the generator code considerably. I'll mark this as a TODO for v2
@ -657,7 +657,7 @@ namespace blt::gp
return get_random().select(storage.non_terminals[id]);
}
operator_id select_non_terminal_too_deep(type_id id)
operator_id select_non_terminal_too_deep(const type_id id)
{
// this should probably be an error.
if (storage.operators_ordered_terminals[id].empty())
@ -688,32 +688,32 @@ namespace blt::gp
return storage.system;
}
[[nodiscard]] operator_info_t& get_operator_info(operator_id id)
[[nodiscard]] operator_info_t& get_operator_info(const operator_id id)
{
return storage.operators[id];
}
[[nodiscard]] detail::print_func_t& get_print_func(operator_id id)
[[nodiscard]] detail::print_func_t& get_print_func(const operator_id id)
{
return storage.print_funcs[id];
}
[[nodiscard]] detail::destroy_func_t& get_destroy_func(operator_id id)
[[nodiscard]] detail::destroy_func_t& get_destroy_func(const operator_id id)
{
return storage.destroy_funcs[id];
}
[[nodiscard]] std::optional<std::string_view> get_name(operator_id id) const
[[nodiscard]] std::optional<std::string_view> get_name(const operator_id id) const
{
return storage.names[id];
}
[[nodiscard]] tracked_vector<operator_id>& get_type_terminals(type_id id)
[[nodiscard]] tracked_vector<operator_id>& get_type_terminals(const type_id id)
{
return storage.terminals[id];
}
[[nodiscard]] tracked_vector<operator_id>& get_type_non_terminals(type_id id)
[[nodiscard]] tracked_vector<operator_id>& get_type_non_terminals(const type_id id)
{
return storage.non_terminals[id];
}
@ -753,47 +753,55 @@ namespace blt::gp
storage = std::move(op);
}
template <blt::size_t size>
std::array<blt::size_t, size> get_best_indexes()
template <size_t size>
std::array<size_t, size> get_best_indexes()
{
std::array<blt::size_t, size> arr;
std::array<size_t, size> arr;
tracked_vector<std::pair<blt::size_t, double>> values;
tracked_vector<std::pair<size_t, double>> values;
values.reserve(current_pop.get_individuals().size());
for (const auto& [index, value] : blt::enumerate(current_pop.get_individuals()))
for (const auto& [index, value] : enumerate(current_pop.get_individuals()))
values.emplace_back(index, value.fitness.adjusted_fitness);
std::sort(values.begin(), values.end(), [](const auto& a, const auto& b) {
return a.second > b.second;
});
for (blt::size_t i = 0; i < std::min(size, config.population_size); i++)
for (size_t i = 0; i < std::min(size, config.population_size); ++i)
arr[i] = values[i].first;
for (blt::size_t i = std::min(size, config.population_size); i < size; i++)
for (size_t i = std::min(size, config.population_size); i < size; ++i)
arr[i] = 0;
return arr;
}
template <blt::size_t size>
template <size_t size>
auto get_best_trees()
{
return convert_array<std::array<std::reference_wrapper<individual_t>, size>>(get_best_indexes<size>(),
[this](auto&& arr, blt::size_t index) -> tree_t& {
[this](auto&& arr, size_t index) -> tree_t& {
return current_pop.get_individuals()[arr[index]].tree;
}, std::make_integer_sequence<blt::size_t, size>());
}, std::make_integer_sequence<size_t, size>());
}
template <blt::size_t size>
template <size_t size>
auto get_best_individuals()
{
return convert_array<std::array<std::reference_wrapper<individual_t>, size>>(get_best_indexes<size>(),
[this](auto&& arr, blt::size_t index) -> individual_t& {
[this](auto&& arr, size_t index) -> individual_t& {
return current_pop.get_individuals()[arr[index]];
}, std::make_integer_sequence<blt::size_t, size>());
}, std::make_integer_sequence<size_t, size>());
}
void save_generation(fs::writer_t& writer);
void save_state(fs::writer_t& writer);
void load_generation(fs::reader_t& reader);
void load_state(fs::reader_t& reader);
private:
template <typename FitnessFunc>
auto single_threaded_fitness_eval()

27
include/blt/gp/sync.h Normal file
View File

@ -0,0 +1,27 @@
#pragma once
/*
* 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/>.
*/
#ifndef BLT_GP_SYNC_H
#define BLT_GP_SYNC_H
namespace blt::gp
{
}
#endif //BLT_GP_SYNC_H

View File

@ -24,6 +24,7 @@
#include <blt/gp/stack.h>
#include <blt/gp/fwdecl.h>
#include <blt/std/types.h>
#include <blt/fs/fwddecl.h>
#include <utility>
#include <stack>
@ -611,11 +612,11 @@ namespace blt::gp
void to_byte_array(std::byte* out) const;
void to_file(FILE* file) const;
void to_file(fs::writer_t& file) const;
void from_byte_array(const std::byte* in);
void from_file(FILE* file);
void from_file(fs::reader_t& file);
~tree_t()
{

@ -1 +1 @@
Subproject commit 322a533fd9412167e216188a4713a5aa4a99c2cd
Subproject commit 78c219cc67f1fe6b3c7076e2c727f8f4cfffd859

View File

@ -56,6 +56,14 @@ namespace blt::gp
return allocator;
}
void gp_program::save_state(fs::writer_t& writer)
{
}
void gp_program::load_state(fs::reader_t& reader)
{
}
void gp_program::create_threads()
{
#ifdef BLT_TRACK_ALLOCATIONS

23
src/sync.cpp Normal file
View File

@ -0,0 +1,23 @@
/*
* <Short Description>
* Copyright (C) 2025 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/sync.h>
namespace blt::gp
{
}

View File

@ -692,18 +692,18 @@ namespace blt::gp
std::memcpy(out, values.data(), val_size);
}
void tree_t::to_file(FILE* file) const
void tree_t::to_file(fs::writer_t& file) const
{
const auto op_size = operations.size();
BLT_ASSERT(std::fwrite(&op_size, sizeof(size_t), 1, file) == sizeof(size_t));
BLT_ASSERT(file.write(&op_size, sizeof(size_t)) == sizeof(size_t));
for (const auto& op : operations)
{
auto id = op.id();
std::fwrite(&id, sizeof(operator_id), 1, file);
file.write(&id, sizeof(operator_id));
}
const auto val_size = values.bytes_in_head();
BLT_ASSERT(std::fwrite(&val_size, sizeof(size_t), 1, file) == sizeof(size_t));
BLT_ASSERT(std::fwrite(values.data(), val_size, 1, file) == val_size);
BLT_ASSERT(file.write(&val_size, sizeof(size_t)) == sizeof(size_t));
BLT_ASSERT(file.write(values.data(), val_size) == val_size);
}
void tree_t::from_byte_array(const std::byte* in)
@ -731,15 +731,15 @@ namespace blt::gp
values.copy_from(reinterpret_cast<const u8*>(in), val_size);
}
void tree_t::from_file(FILE* file)
void tree_t::from_file(fs::reader_t& file)
{
size_t ops_to_read;
BLT_ASSERT(std::fread(&ops_to_read, sizeof(size_t), 1, file) == sizeof(size_t));
BLT_ASSERT(file.read(&ops_to_read, sizeof(size_t)) == sizeof(size_t));
operations.reserve(ops_to_read);
for (size_t i = 0; i < ops_to_read; i++)
{
operator_id id;
BLT_ASSERT(std::fread(&id, sizeof(operator_id), 1, file) == sizeof(operator_id));
BLT_ASSERT(file.read(&id, sizeof(operator_id)) == sizeof(operator_id));
operations.push_back({
m_program->get_typesystem().get_type(m_program->get_operator_info(id).return_type).size(),
id,
@ -748,9 +748,9 @@ namespace blt::gp
});
}
size_t val_size;
BLT_ASSERT(std::fread(&val_size, sizeof(size_t), 1, file) == sizeof(size_t));
BLT_ASSERT(file.read(&val_size, sizeof(size_t)) == sizeof(size_t));
values.resize(val_size);
BLT_ASSERT(std::fread(values.data(), val_size, 1, file) == val_size);
BLT_ASSERT(file.read(values.data(), val_size) == val_size);
}
void tree_t::modify_operator(const size_t point, operator_id new_id, std::optional<type_id> return_type)