Compare commits
No commits in common. "d4e6c40fe1d28ab9ed02dcc3d7484aa49ae743ec" and "e5966789be45685ed73d0a152319c8da1793e53f" have entirely different histories.
d4e6c40fe1
...
e5966789be
|
@ -7,5 +7,7 @@ out/
|
||||||
massif.*
|
massif.*
|
||||||
callgrind.*
|
callgrind.*
|
||||||
*.out.*
|
*.out.*
|
||||||
|
<<<<<<< HEAD
|
||||||
heaptrack.*
|
heaptrack.*
|
||||||
Rice_Cammeo_Osmancik.arff
|
=======
|
||||||
|
>>>>>>> refs/remotes/origin/main
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
cmake_minimum_required(VERSION 3.25)
|
cmake_minimum_required(VERSION 3.25)
|
||||||
project(blt-gp VERSION 0.1.35)
|
project(blt-gp VERSION 0.1.26)
|
||||||
|
|
||||||
include(CTest)
|
include(CTest)
|
||||||
|
|
||||||
|
@ -16,8 +16,6 @@ set(CMAKE_CXX_STANDARD 17)
|
||||||
set(THREADS_PREFER_PTHREAD_FLAG ON)
|
set(THREADS_PREFER_PTHREAD_FLAG ON)
|
||||||
find_package(Threads REQUIRED)
|
find_package(Threads REQUIRED)
|
||||||
|
|
||||||
SET(CMAKE_CXX_FLAGS_RELEASE "-O3 -g")
|
|
||||||
|
|
||||||
if (NOT TARGET BLT)
|
if (NOT TARGET BLT)
|
||||||
add_subdirectory(lib/blt)
|
add_subdirectory(lib/blt)
|
||||||
endif ()
|
endif ()
|
||||||
|
@ -108,7 +106,6 @@ endmacro()
|
||||||
if (${BUILD_EXAMPLES})
|
if (${BUILD_EXAMPLES})
|
||||||
|
|
||||||
blt_add_project(blt-symbolic-regression examples/symbolic_regression.cpp example)
|
blt_add_project(blt-symbolic-regression examples/symbolic_regression.cpp example)
|
||||||
blt_add_project(blt-rice-classification examples/rice_classification.cpp example)
|
|
||||||
|
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
|
|
|
@ -1302,7 +1302,7 @@
|
||||||
,"0x4845DA0: memalign (in /usr/libexec/valgrind/vgpreload_dhat-amd64-linux.so)"
|
,"0x4845DA0: memalign (in /usr/libexec/valgrind/vgpreload_dhat-amd64-linux.so)"
|
||||||
,"0x129674: std::_Function_handler<void (void*, blt::gp::stack_allocator&, blt::gp::stack_allocator&), blt::gp::operation_t<lit::{lambda()#1}, float ()>::make_callable<context>() const::{lambda(void*, blt::gp::stack_allocator&, blt::gp::stack_allocator&)#1}>::_M_invoke(std::_Any_data const&, void*&&, blt::gp::stack_allocator&, blt::gp::stack_allocator&) (in /home/brett/Documents/code/c++/blt-gp/cmake-build-release/blt-SR-playground-example)"
|
,"0x129674: std::_Function_handler<void (void*, blt::gp::stack_allocator&, blt::gp::stack_allocator&), blt::gp::operation_t<lit::{lambda()#1}, float ()>::make_callable<context>() const::{lambda(void*, blt::gp::stack_allocator&, blt::gp::stack_allocator&)#1}>::_M_invoke(std::_Any_data const&, void*&&, blt::gp::stack_allocator&, blt::gp::stack_allocator&) (in /home/brett/Documents/code/c++/blt-gp/cmake-build-release/blt-SR-playground-example)"
|
||||||
,"0x158664: blt::gp::tree_t blt::gp::create_tree<blt::gp::grow_generator_t::generate(blt::gp::generator_arguments const&)::{lambda(blt::gp::gp_program&, std::stack<blt::gp::stack, std::deque<blt::gp::stack, std::allocator<blt::gp::stack> > >&, blt::gp::type_id, unsigned long)#1}>(blt::gp::grow_generator_t::generate(blt::gp::generator_arguments const&)::{lambda(blt::gp::gp_program&, std::stack<blt::gp::stack, std::deque<blt::gp::stack, std::allocator<blt::gp::stack> > >&, blt::gp::type_id, unsigned long)#1}&&, blt::gp::generator_arguments const&) (in /home/brett/Documents/code/c++/blt-gp/cmake-build-release/blt-SR-playground-example)"
|
,"0x158664: blt::gp::tree_t blt::gp::create_tree<blt::gp::grow_generator_t::generate(blt::gp::generator_arguments const&)::{lambda(blt::gp::gp_program&, std::stack<blt::gp::stack, std::deque<blt::gp::stack, std::allocator<blt::gp::stack> > >&, blt::gp::type_id, unsigned long)#1}>(blt::gp::grow_generator_t::generate(blt::gp::generator_arguments const&)::{lambda(blt::gp::gp_program&, std::stack<blt::gp::stack, std::deque<blt::gp::stack, std::allocator<blt::gp::stack> > >&, blt::gp::type_id, unsigned long)#1}&&, blt::gp::generator_arguments const&) (in /home/brett/Documents/code/c++/blt-gp/cmake-build-release/blt-SR-playground-example)"
|
||||||
,"0x15D0C0: void std::vector<blt::gp::individual_t, std::allocator<blt::gp::individual_t> >::_M_realloc_insert<blt::gp::tree_t>(__gnu_cxx::__normal_iterator<blt::gp::individual_t*, std::vector<blt::gp::individual_t, std::allocator<blt::gp::individual_t> > >, blt::gp::tree_t&&) (in /home/brett/Documents/code/c++/blt-gp/cmake-build-release/blt-SR-playground-example)"
|
,"0x15D0C0: void std::vector<blt::gp::individual, std::allocator<blt::gp::individual> >::_M_realloc_insert<blt::gp::tree_t>(__gnu_cxx::__normal_iterator<blt::gp::individual*, std::vector<blt::gp::individual, std::allocator<blt::gp::individual> > >, blt::gp::tree_t&&) (in /home/brett/Documents/code/c++/blt-gp/cmake-build-release/blt-SR-playground-example)"
|
||||||
,"0x15CCFA: blt::gp::ramped_half_initializer_t::generate(blt::gp::initializer_arguments const&) (in /home/brett/Documents/code/c++/blt-gp/cmake-build-release/blt-SR-playground-example)"
|
,"0x15CCFA: blt::gp::ramped_half_initializer_t::generate(blt::gp::initializer_arguments const&) (in /home/brett/Documents/code/c++/blt-gp/cmake-build-release/blt-SR-playground-example)"
|
||||||
,"0x15A9F0: blt::gp::tree_t blt::gp::create_tree<blt::gp::full_generator_t::generate(blt::gp::generator_arguments const&)::{lambda(blt::gp::gp_program&, std::stack<blt::gp::stack, std::deque<blt::gp::stack, std::allocator<blt::gp::stack> > >&, blt::gp::type_id, unsigned long)#1}>(blt::gp::full_generator_t::generate(blt::gp::generator_arguments const&)::{lambda(blt::gp::gp_program&, std::stack<blt::gp::stack, std::deque<blt::gp::stack, std::allocator<blt::gp::stack> > >&, blt::gp::type_id, unsigned long)#1}&&, blt::gp::generator_arguments const&) (in /home/brett/Documents/code/c++/blt-gp/cmake-build-release/blt-SR-playground-example)"
|
,"0x15A9F0: blt::gp::tree_t blt::gp::create_tree<blt::gp::full_generator_t::generate(blt::gp::generator_arguments const&)::{lambda(blt::gp::gp_program&, std::stack<blt::gp::stack, std::deque<blt::gp::stack, std::allocator<blt::gp::stack> > >&, blt::gp::type_id, unsigned long)#1}>(blt::gp::full_generator_t::generate(blt::gp::generator_arguments const&)::{lambda(blt::gp::gp_program&, std::stack<blt::gp::stack, std::deque<blt::gp::stack, std::allocator<blt::gp::stack> > >&, blt::gp::type_id, unsigned long)#1}&&, blt::gp::generator_arguments const&) (in /home/brett/Documents/code/c++/blt-gp/cmake-build-release/blt-SR-playground-example)"
|
||||||
,"0x15C977: blt::gp::ramped_half_initializer_t::generate(blt::gp::initializer_arguments const&) (in /home/brett/Documents/code/c++/blt-gp/cmake-build-release/blt-SR-playground-example)"
|
,"0x15C977: blt::gp::ramped_half_initializer_t::generate(blt::gp::initializer_arguments const&) (in /home/brett/Documents/code/c++/blt-gp/cmake-build-release/blt-SR-playground-example)"
|
||||||
|
@ -1330,7 +1330,7 @@
|
||||||
,"0x1548AB: blt::gp::crossover_t::apply(blt::gp::gp_program&, blt::gp::tree_t const&, blt::gp::tree_t const&) (in /home/brett/Documents/code/c++/blt-gp/cmake-build-release/blt-SR-playground-example)"
|
,"0x1548AB: blt::gp::crossover_t::apply(blt::gp::gp_program&, blt::gp::tree_t const&, blt::gp::tree_t const&) (in /home/brett/Documents/code/c++/blt-gp/cmake-build-release/blt-SR-playground-example)"
|
||||||
,"0x1549A7: blt::gp::crossover_t::apply(blt::gp::gp_program&, blt::gp::tree_t const&, blt::gp::tree_t const&) (in /home/brett/Documents/code/c++/blt-gp/cmake-build-release/blt-SR-playground-example)"
|
,"0x1549A7: blt::gp::crossover_t::apply(blt::gp::gp_program&, blt::gp::tree_t const&, blt::gp::tree_t const&) (in /home/brett/Documents/code/c++/blt-gp/cmake-build-release/blt-SR-playground-example)"
|
||||||
,"0x127C77: blt::gp::default_next_pop_creator<blt::gp::select_tournament_t, blt::gp::select_tournament_t, blt::gp::select_tournament_t>::{lambda(blt::gp::selector_args&&, blt::gp::select_tournament_t&&, blt::gp::select_tournament_t&&, blt::gp::select_tournament_t&&)#1}::operator()(blt::gp::selector_args&&, blt::gp::select_tournament_t&&, blt::gp::select_tournament_t&&, blt::gp::select_tournament_t&&) const [clone .isra.0] (in /home/brett/Documents/code/c++/blt-gp/cmake-build-release/blt-SR-playground-example)"
|
,"0x127C77: blt::gp::default_next_pop_creator<blt::gp::select_tournament_t, blt::gp::select_tournament_t, blt::gp::select_tournament_t>::{lambda(blt::gp::selector_args&&, blt::gp::select_tournament_t&&, blt::gp::select_tournament_t&&, blt::gp::select_tournament_t&&)#1}::operator()(blt::gp::selector_args&&, blt::gp::select_tournament_t&&, blt::gp::select_tournament_t&&, blt::gp::select_tournament_t&&) const [clone .isra.0] (in /home/brett/Documents/code/c++/blt-gp/cmake-build-release/blt-SR-playground-example)"
|
||||||
,"0x1268EF: blt::gp::individual_t& std::vector<blt::gp::individual_t, std::allocator<blt::gp::individual_t> >::emplace_back<blt::gp::individual_t>(blt::gp::individual_t&&) [clone .isra.0] (in /home/brett/Documents/code/c++/blt-gp/cmake-build-release/blt-SR-playground-example)"
|
,"0x1268EF: blt::gp::individual& std::vector<blt::gp::individual, std::allocator<blt::gp::individual> >::emplace_back<blt::gp::individual>(blt::gp::individual&&) [clone .isra.0] (in /home/brett/Documents/code/c++/blt-gp/cmake-build-release/blt-SR-playground-example)"
|
||||||
,"0x127DDE: blt::gp::default_next_pop_creator<blt::gp::select_tournament_t, blt::gp::select_tournament_t, blt::gp::select_tournament_t>::{lambda(blt::gp::selector_args&&, blt::gp::select_tournament_t&&, blt::gp::select_tournament_t&&, blt::gp::select_tournament_t&&)#1}::operator()(blt::gp::selector_args&&, blt::gp::select_tournament_t&&, blt::gp::select_tournament_t&&, blt::gp::select_tournament_t&&) const [clone .isra.0] (in /home/brett/Documents/code/c++/blt-gp/cmake-build-release/blt-SR-playground-example)"
|
,"0x127DDE: blt::gp::default_next_pop_creator<blt::gp::select_tournament_t, blt::gp::select_tournament_t, blt::gp::select_tournament_t>::{lambda(blt::gp::selector_args&&, blt::gp::select_tournament_t&&, blt::gp::select_tournament_t&&, blt::gp::select_tournament_t&&)#1}::operator()(blt::gp::selector_args&&, blt::gp::select_tournament_t&&, blt::gp::select_tournament_t&&, blt::gp::select_tournament_t&&) const [clone .isra.0] (in /home/brett/Documents/code/c++/blt-gp/cmake-build-release/blt-SR-playground-example)"
|
||||||
,"0x127F26: blt::gp::default_next_pop_creator<blt::gp::select_tournament_t, blt::gp::select_tournament_t, blt::gp::select_tournament_t>::{lambda(blt::gp::selector_args&&, blt::gp::select_tournament_t&&, blt::gp::select_tournament_t&&, blt::gp::select_tournament_t&&)#1}::operator()(blt::gp::selector_args&&, blt::gp::select_tournament_t&&, blt::gp::select_tournament_t&&, blt::gp::select_tournament_t&&) const [clone .isra.0] (in /home/brett/Documents/code/c++/blt-gp/cmake-build-release/blt-SR-playground-example)"
|
,"0x127F26: blt::gp::default_next_pop_creator<blt::gp::select_tournament_t, blt::gp::select_tournament_t, blt::gp::select_tournament_t>::{lambda(blt::gp::selector_args&&, blt::gp::select_tournament_t&&, blt::gp::select_tournament_t&&, blt::gp::select_tournament_t&&)#1}::operator()(blt::gp::selector_args&&, blt::gp::select_tournament_t&&, blt::gp::select_tournament_t&&, blt::gp::select_tournament_t&&) const [clone .isra.0] (in /home/brett/Documents/code/c++/blt-gp/cmake-build-release/blt-SR-playground-example)"
|
||||||
,"0x127FE6: blt::gp::default_next_pop_creator<blt::gp::select_tournament_t, blt::gp::select_tournament_t, blt::gp::select_tournament_t>::{lambda(blt::gp::selector_args&&, blt::gp::select_tournament_t&&, blt::gp::select_tournament_t&&, blt::gp::select_tournament_t&&)#1}::operator()(blt::gp::selector_args&&, blt::gp::select_tournament_t&&, blt::gp::select_tournament_t&&, blt::gp::select_tournament_t&&) const [clone .isra.0] (in /home/brett/Documents/code/c++/blt-gp/cmake-build-release/blt-SR-playground-example)"
|
,"0x127FE6: blt::gp::default_next_pop_creator<blt::gp::select_tournament_t, blt::gp::select_tournament_t, blt::gp::select_tournament_t>::{lambda(blt::gp::selector_args&&, blt::gp::select_tournament_t&&, blt::gp::select_tournament_t&&, blt::gp::select_tournament_t&&)#1}::operator()(blt::gp::selector_args&&, blt::gp::select_tournament_t&&, blt::gp::select_tournament_t&&, blt::gp::select_tournament_t&&) const [clone .isra.0] (in /home/brett/Documents/code/c++/blt-gp/cmake-build-release/blt-SR-playground-example)"
|
||||||
|
@ -1366,7 +1366,7 @@
|
||||||
,"0x1247AC: main (in /home/brett/Documents/code/c++/blt-gp/cmake-build-release/blt-SR-playground-example)"
|
,"0x1247AC: main (in /home/brett/Documents/code/c++/blt-gp/cmake-build-release/blt-SR-playground-example)"
|
||||||
,"0x12497D: main (in /home/brett/Documents/code/c++/blt-gp/cmake-build-release/blt-SR-playground-example)"
|
,"0x12497D: main (in /home/brett/Documents/code/c++/blt-gp/cmake-build-release/blt-SR-playground-example)"
|
||||||
,"0x124A4A: main (in /home/brett/Documents/code/c++/blt-gp/cmake-build-release/blt-SR-playground-example)"
|
,"0x124A4A: main (in /home/brett/Documents/code/c++/blt-gp/cmake-build-release/blt-SR-playground-example)"
|
||||||
,"0x126AFC: blt::gp::individual_t& std::vector<blt::gp::individual_t, std::allocator<blt::gp::individual_t> >::emplace_back<blt::gp::tree_t>(blt::gp::tree_t&&) [clone .isra.0] (in /home/brett/Documents/code/c++/blt-gp/cmake-build-release/blt-SR-playground-example)"
|
,"0x126AFC: blt::gp::individual& std::vector<blt::gp::individual, std::allocator<blt::gp::individual> >::emplace_back<blt::gp::tree_t>(blt::gp::tree_t&&) [clone .isra.0] (in /home/brett/Documents/code/c++/blt-gp/cmake-build-release/blt-SR-playground-example)"
|
||||||
,"0x127AE9: blt::gp::default_next_pop_creator<blt::gp::select_tournament_t, blt::gp::select_tournament_t, blt::gp::select_tournament_t>::{lambda(blt::gp::selector_args&&, blt::gp::select_tournament_t&&, blt::gp::select_tournament_t&&, blt::gp::select_tournament_t&&)#1}::operator()(blt::gp::selector_args&&, blt::gp::select_tournament_t&&, blt::gp::select_tournament_t&&, blt::gp::select_tournament_t&&) const [clone .isra.0] (in /home/brett/Documents/code/c++/blt-gp/cmake-build-release/blt-SR-playground-example)"
|
,"0x127AE9: blt::gp::default_next_pop_creator<blt::gp::select_tournament_t, blt::gp::select_tournament_t, blt::gp::select_tournament_t>::{lambda(blt::gp::selector_args&&, blt::gp::select_tournament_t&&, blt::gp::select_tournament_t&&, blt::gp::select_tournament_t&&)#1}::operator()(blt::gp::selector_args&&, blt::gp::select_tournament_t&&, blt::gp::select_tournament_t&&, blt::gp::select_tournament_t&&) const [clone .isra.0] (in /home/brett/Documents/code/c++/blt-gp/cmake-build-release/blt-SR-playground-example)"
|
||||||
,"0x127E76: blt::gp::default_next_pop_creator<blt::gp::select_tournament_t, blt::gp::select_tournament_t, blt::gp::select_tournament_t>::{lambda(blt::gp::selector_args&&, blt::gp::select_tournament_t&&, blt::gp::select_tournament_t&&, blt::gp::select_tournament_t&&)#1}::operator()(blt::gp::selector_args&&, blt::gp::select_tournament_t&&, blt::gp::select_tournament_t&&, blt::gp::select_tournament_t&&) const [clone .isra.0] (in /home/brett/Documents/code/c++/blt-gp/cmake-build-release/blt-SR-playground-example)"
|
,"0x127E76: blt::gp::default_next_pop_creator<blt::gp::select_tournament_t, blt::gp::select_tournament_t, blt::gp::select_tournament_t>::{lambda(blt::gp::selector_args&&, blt::gp::select_tournament_t&&, blt::gp::select_tournament_t&&, blt::gp::select_tournament_t&&)#1}::operator()(blt::gp::selector_args&&, blt::gp::select_tournament_t&&, blt::gp::select_tournament_t&&, blt::gp::select_tournament_t&&) const [clone .isra.0] (in /home/brett/Documents/code/c++/blt-gp/cmake-build-release/blt-SR-playground-example)"
|
||||||
,"0x127EAF: blt::gp::default_next_pop_creator<blt::gp::select_tournament_t, blt::gp::select_tournament_t, blt::gp::select_tournament_t>::{lambda(blt::gp::selector_args&&, blt::gp::select_tournament_t&&, blt::gp::select_tournament_t&&, blt::gp::select_tournament_t&&)#1}::operator()(blt::gp::selector_args&&, blt::gp::select_tournament_t&&, blt::gp::select_tournament_t&&, blt::gp::select_tournament_t&&) const [clone .isra.0] (in /home/brett/Documents/code/c++/blt-gp/cmake-build-release/blt-SR-playground-example)"
|
,"0x127EAF: blt::gp::default_next_pop_creator<blt::gp::select_tournament_t, blt::gp::select_tournament_t, blt::gp::select_tournament_t>::{lambda(blt::gp::selector_args&&, blt::gp::select_tournament_t&&, blt::gp::select_tournament_t&&, blt::gp::select_tournament_t&&)#1}::operator()(blt::gp::selector_args&&, blt::gp::select_tournament_t&&, blt::gp::select_tournament_t&&, blt::gp::select_tournament_t&&) const [clone .isra.0] (in /home/brett/Documents/code/c++/blt-gp/cmake-build-release/blt-SR-playground-example)"
|
||||||
|
|
|
@ -1,33 +0,0 @@
|
||||||
#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_OPERATIONS_COMMON_H
|
|
||||||
#define BLT_GP_OPERATIONS_COMMON_H
|
|
||||||
|
|
||||||
#include <blt/gp/program.h>
|
|
||||||
|
|
||||||
blt::gp::operation_t add([](float a, float b) { return a + b; }, "add");
|
|
||||||
blt::gp::operation_t sub([](float a, float b) { return a - b; }, "sub");
|
|
||||||
blt::gp::operation_t mul([](float a, float b) { return a * b; }, "mul");
|
|
||||||
blt::gp::operation_t pro_div([](float a, float b) { return b == 0.0f ? 1.0f : a / b; }, "div");
|
|
||||||
blt::gp::operation_t op_sin([](float a) { return std::sin(a); }, "sin");
|
|
||||||
blt::gp::operation_t op_cos([](float a) { return std::cos(a); }, "cos");
|
|
||||||
blt::gp::operation_t op_exp([](float a) { return std::exp(a); }, "exp");
|
|
||||||
blt::gp::operation_t op_log([](float a) { return a == 0.0f ? 0.0f : std::log(a); }, "log");
|
|
||||||
|
|
||||||
#endif //BLT_GP_OPERATIONS_COMMON_H
|
|
|
@ -1,353 +0,0 @@
|
||||||
/*
|
|
||||||
* This rice classification example uses data from the UC Irvine Machine Learning repository.
|
|
||||||
* The data for this example can be found at:
|
|
||||||
* https://archive.ics.uci.edu/dataset/545/rice+cammeo+and+osmancik
|
|
||||||
*
|
|
||||||
* 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/program.h>
|
|
||||||
#include <blt/profiling/profiler_v2.h>
|
|
||||||
#include <blt/gp/tree.h>
|
|
||||||
#include <blt/std/logging.h>
|
|
||||||
#include <blt/std/format.h>
|
|
||||||
#include <blt/parse/argparse.h>
|
|
||||||
#include <iostream>
|
|
||||||
#include "operations_common.h"
|
|
||||||
#include "blt/fs/loader.h"
|
|
||||||
|
|
||||||
static const auto SEED_FUNC = [] { return std::random_device()(); };
|
|
||||||
|
|
||||||
enum class rice_type_t
|
|
||||||
{
|
|
||||||
Cammeo,
|
|
||||||
Osmancik
|
|
||||||
};
|
|
||||||
|
|
||||||
struct rice_record
|
|
||||||
{
|
|
||||||
float area;
|
|
||||||
float perimeter;
|
|
||||||
float major_axis_length;
|
|
||||||
float minor_axis_length;
|
|
||||||
float eccentricity;
|
|
||||||
float convex_area;
|
|
||||||
float extent;
|
|
||||||
rice_type_t type;
|
|
||||||
};
|
|
||||||
|
|
||||||
std::vector<rice_record> training_cases;
|
|
||||||
std::vector<rice_record> testing_cases;
|
|
||||||
|
|
||||||
blt::gp::prog_config_t config = blt::gp::prog_config_t()
|
|
||||||
.set_initial_min_tree_size(2)
|
|
||||||
.set_initial_max_tree_size(6)
|
|
||||||
.set_elite_count(2)
|
|
||||||
.set_crossover_chance(0.9)
|
|
||||||
.set_mutation_chance(0.1)
|
|
||||||
.set_reproduction_chance(0)
|
|
||||||
.set_max_generations(50)
|
|
||||||
.set_pop_size(5000)
|
|
||||||
.set_thread_count(0);
|
|
||||||
|
|
||||||
blt::gp::gp_program program{SEED_FUNC, config};
|
|
||||||
|
|
||||||
auto lit = blt::gp::operation_t([]() {
|
|
||||||
return program.get_random().get_float(-32000.0f, 32000.0f);
|
|
||||||
}, "lit").set_ephemeral();
|
|
||||||
|
|
||||||
blt::gp::operation_t op_area([](const rice_record& rice_data) {
|
|
||||||
return rice_data.area;
|
|
||||||
}, "area");
|
|
||||||
|
|
||||||
blt::gp::operation_t op_perimeter([](const rice_record& rice_data) {
|
|
||||||
return rice_data.perimeter;
|
|
||||||
}, "perimeter");
|
|
||||||
|
|
||||||
blt::gp::operation_t op_major_axis_length([](const rice_record& rice_data) {
|
|
||||||
return rice_data.major_axis_length;
|
|
||||||
}, "major_axis_length");
|
|
||||||
|
|
||||||
blt::gp::operation_t op_minor_axis_length([](const rice_record& rice_data) {
|
|
||||||
return rice_data.minor_axis_length;
|
|
||||||
}, "minor_axis_length");
|
|
||||||
|
|
||||||
blt::gp::operation_t op_eccentricity([](const rice_record& rice_data) {
|
|
||||||
return rice_data.eccentricity;
|
|
||||||
}, "eccentricity");
|
|
||||||
|
|
||||||
blt::gp::operation_t op_convex_area([](const rice_record& rice_data) {
|
|
||||||
return rice_data.convex_area;
|
|
||||||
}, "convex_area");
|
|
||||||
|
|
||||||
blt::gp::operation_t op_extent([](const rice_record& rice_data) {
|
|
||||||
return rice_data.extent;
|
|
||||||
}, "extent");
|
|
||||||
|
|
||||||
constexpr auto fitness_function = [](blt::gp::tree_t& current_tree, blt::gp::fitness_t& fitness, blt::size_t) {
|
|
||||||
for (auto& training_case : training_cases)
|
|
||||||
{
|
|
||||||
auto v = current_tree.get_evaluation_value<float>(&training_case);
|
|
||||||
switch (training_case.type)
|
|
||||||
{
|
|
||||||
case rice_type_t::Cammeo:
|
|
||||||
if (v >= 0)
|
|
||||||
fitness.hits++;
|
|
||||||
break;
|
|
||||||
case rice_type_t::Osmancik:
|
|
||||||
if (v < 0)
|
|
||||||
fitness.hits++;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fitness.raw_fitness = static_cast<double>(fitness.hits);
|
|
||||||
fitness.standardized_fitness = fitness.raw_fitness;
|
|
||||||
fitness.adjusted_fitness = 1.0 - (1.0 / (1.0 + fitness.standardized_fitness));
|
|
||||||
return static_cast<blt::size_t>(fitness.hits) == training_cases.size();
|
|
||||||
};
|
|
||||||
|
|
||||||
void load_rice_data(std::string_view rice_file_path)
|
|
||||||
{
|
|
||||||
auto rice_file_data = blt::fs::getLinesFromFile(rice_file_path);
|
|
||||||
size_t index = 0;
|
|
||||||
while (!blt::string::contains(rice_file_data[index++], "@DATA"))
|
|
||||||
{}
|
|
||||||
std::vector<rice_record> c;
|
|
||||||
std::vector<rice_record> o;
|
|
||||||
for (std::string_view v : blt::itr_offset(rice_file_data, index))
|
|
||||||
{
|
|
||||||
auto data = blt::string::split(v, ',');
|
|
||||||
rice_record r{std::stof(data[0]), std::stof(data[1]), std::stof(data[2]), std::stof(data[3]), std::stof(data[4]), std::stof(data[5]),
|
|
||||||
std::stof(data[6]), blt::string::contains(data[7], "Cammeo") ? rice_type_t::Cammeo : rice_type_t::Osmancik};
|
|
||||||
switch (r.type)
|
|
||||||
{
|
|
||||||
case rice_type_t::Cammeo:
|
|
||||||
c.push_back(r);
|
|
||||||
break;
|
|
||||||
case rice_type_t::Osmancik:
|
|
||||||
o.push_back(r);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
blt::size_t total_records = c.size() + o.size();
|
|
||||||
blt::size_t training_size = std::min(total_records / 3, 1000ul);
|
|
||||||
for (blt::size_t i = 0; i < training_size; i++)
|
|
||||||
{
|
|
||||||
auto& random = program.get_random();
|
|
||||||
auto& vec = random.choice() ? c : o;
|
|
||||||
auto pos = random.get_i64(0, static_cast<blt::i64>(vec.size()));
|
|
||||||
training_cases.push_back(vec[pos]);
|
|
||||||
vec.erase(vec.begin() + pos);
|
|
||||||
}
|
|
||||||
testing_cases.insert(testing_cases.end(), c.begin(), c.end());
|
|
||||||
testing_cases.insert(testing_cases.end(), o.begin(), o.end());
|
|
||||||
std::shuffle(testing_cases.begin(), testing_cases.end(), program.get_random());
|
|
||||||
BLT_INFO("Created training set of size %ld, testing set is of size %ld", training_size, testing_cases.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
struct test_results_t
|
|
||||||
{
|
|
||||||
blt::size_t cc = 0;
|
|
||||||
blt::size_t co = 0;
|
|
||||||
blt::size_t oo = 0;
|
|
||||||
blt::size_t oc = 0;
|
|
||||||
blt::size_t hits = 0;
|
|
||||||
blt::size_t size = 0;
|
|
||||||
double percent_hit = 0;
|
|
||||||
|
|
||||||
test_results_t& operator+=(const test_results_t& a)
|
|
||||||
{
|
|
||||||
cc += a.cc;
|
|
||||||
co += a.co;
|
|
||||||
oo += a.oo;
|
|
||||||
oc += a.oc;
|
|
||||||
hits += a.hits;
|
|
||||||
size += a.size;
|
|
||||||
percent_hit += a.percent_hit;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
test_results_t& operator/=(blt::size_t s)
|
|
||||||
{
|
|
||||||
cc /= s;
|
|
||||||
co /= s;
|
|
||||||
oo /= s;
|
|
||||||
oc /= s;
|
|
||||||
hits /= s;
|
|
||||||
size /= s;
|
|
||||||
percent_hit /= static_cast<double>(s);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
friend bool operator<(const test_results_t& a, const test_results_t& b)
|
|
||||||
{
|
|
||||||
return a.hits < b.hits;
|
|
||||||
}
|
|
||||||
|
|
||||||
friend bool operator>(const test_results_t& a, const test_results_t& b)
|
|
||||||
{
|
|
||||||
return a.hits > b.hits;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
test_results_t test_individual(blt::gp::individual_t& i)
|
|
||||||
{
|
|
||||||
test_results_t results;
|
|
||||||
|
|
||||||
for (auto& testing_case : testing_cases)
|
|
||||||
{
|
|
||||||
auto result = i.tree.get_evaluation_value<float>(&testing_case);
|
|
||||||
switch (testing_case.type)
|
|
||||||
{
|
|
||||||
case rice_type_t::Cammeo:
|
|
||||||
if (result >= 0)
|
|
||||||
results.cc++; // cammeo cammeo
|
|
||||||
else
|
|
||||||
results.co++; // cammeo osmancik
|
|
||||||
break;
|
|
||||||
case rice_type_t::Osmancik:
|
|
||||||
if (result < 0)
|
|
||||||
results.oo++; // osmancik osmancik
|
|
||||||
else
|
|
||||||
results.oc++; // osmancik cammeo
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
results.hits = results.cc + results.oo;
|
|
||||||
results.size = testing_cases.size();
|
|
||||||
results.percent_hit = static_cast<double>(results.hits) / static_cast<double>(results.size) * 100;
|
|
||||||
|
|
||||||
return results;
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(int argc, const char** argv)
|
|
||||||
{
|
|
||||||
blt::arg_parse parser;
|
|
||||||
parser.addArgument(blt::arg_builder{"-f", "--file"}.setHelp("File for rice data. Should be in .arff format.").setRequired().build());
|
|
||||||
|
|
||||||
auto args = parser.parse_args(argc, argv);
|
|
||||||
|
|
||||||
if (!args.contains("file"))
|
|
||||||
{
|
|
||||||
BLT_WARN("Please provide path to file with -f or --file");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto rice_file_path = args.get<std::string>("file");
|
|
||||||
|
|
||||||
BLT_INFO("Starting BLT-GP Rice Classification Example");
|
|
||||||
BLT_START_INTERVAL("Rice Classification", "Main");
|
|
||||||
BLT_DEBUG("Setup Fitness cases");
|
|
||||||
load_rice_data(rice_file_path);
|
|
||||||
|
|
||||||
BLT_DEBUG("Setup Types and Operators");
|
|
||||||
|
|
||||||
blt::gp::operator_builder<rice_record> builder{};
|
|
||||||
program.set_operations(builder.build(add, sub, mul, pro_div, op_exp, op_log, lit, op_area, op_perimeter, op_major_axis_length,
|
|
||||||
op_minor_axis_length, op_eccentricity, op_convex_area, op_extent));
|
|
||||||
|
|
||||||
BLT_DEBUG("Generate Initial Population");
|
|
||||||
auto sel = blt::gp::select_tournament_t{};
|
|
||||||
program.generate_population(program.get_typesystem().get_type<float>().id(), fitness_function, sel, sel, sel);
|
|
||||||
|
|
||||||
BLT_DEBUG("Begin Generation Loop");
|
|
||||||
while (!program.should_terminate())
|
|
||||||
{
|
|
||||||
BLT_TRACE("------------{Begin Generation %ld}------------", program.get_current_generation());
|
|
||||||
BLT_TRACE("Creating next generation");
|
|
||||||
BLT_START_INTERVAL("Rice Classification", "Gen");
|
|
||||||
program.create_next_generation();
|
|
||||||
BLT_END_INTERVAL("Rice Classification", "Gen");
|
|
||||||
BLT_TRACE("Move to next generation");
|
|
||||||
BLT_START_INTERVAL("Rice Classification", "Fitness");
|
|
||||||
program.next_generation();
|
|
||||||
BLT_TRACE("Evaluate Fitness");
|
|
||||||
program.evaluate_fitness();
|
|
||||||
BLT_END_INTERVAL("Rice Classification", "Fitness");
|
|
||||||
auto& stats = program.get_population_stats();
|
|
||||||
BLT_TRACE("Stats:");
|
|
||||||
BLT_TRACE("Average fitness: %lf", stats.average_fitness.load());
|
|
||||||
BLT_TRACE("Best fitness: %lf", stats.best_fitness.load());
|
|
||||||
BLT_TRACE("Worst fitness: %lf", stats.worst_fitness.load());
|
|
||||||
BLT_TRACE("Overall fitness: %lf", stats.overall_fitness.load());
|
|
||||||
BLT_TRACE("----------------------------------------------");
|
|
||||||
std::cout << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
BLT_END_INTERVAL("Rice Classification", "Main");
|
|
||||||
|
|
||||||
std::vector<std::pair<test_results_t, blt::gp::individual_t*>> results;
|
|
||||||
for (auto& i : program.get_current_pop().get_individuals())
|
|
||||||
results.emplace_back(test_individual(i), &i);
|
|
||||||
std::sort(results.begin(), results.end(), [](const auto& a, const auto& b) {
|
|
||||||
return a.first > b.first;
|
|
||||||
});
|
|
||||||
|
|
||||||
BLT_INFO("Best results:");
|
|
||||||
for (blt::size_t index = 0; index < 3; index++)
|
|
||||||
{
|
|
||||||
const auto& record = results[index].first;
|
|
||||||
const auto& i = *results[index].second;
|
|
||||||
|
|
||||||
BLT_INFO("Hits %ld, Total Cases %ld, Percent Hit: %lf", record.hits, record.size, record.percent_hit);
|
|
||||||
BLT_DEBUG("Cammeo Cammeo: %ld", record.cc);
|
|
||||||
BLT_DEBUG("Cammeo Osmancik: %ld", record.co);
|
|
||||||
BLT_DEBUG("Osmancik Osmancik: %ld", record.oo);
|
|
||||||
BLT_DEBUG("Osmancik Cammeo: %ld", record.oc);
|
|
||||||
BLT_DEBUG("Fitness: %lf, stand: %lf, raw: %lf", i.fitness.adjusted_fitness, i.fitness.standardized_fitness, i.fitness.raw_fitness);
|
|
||||||
i.tree.print(program, std::cout);
|
|
||||||
|
|
||||||
std::cout << "\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
BLT_INFO("Worst Results:");
|
|
||||||
for (blt::size_t index = 0; index < 3; index++)
|
|
||||||
{
|
|
||||||
const auto& record = results[results.size() - 1 - index].first;
|
|
||||||
const auto& i = *results[results.size() - 1 - index].second;
|
|
||||||
|
|
||||||
BLT_INFO("Hits %ld, Total Cases %ld, Percent Hit: %lf", record.hits, record.size, record.percent_hit);
|
|
||||||
BLT_DEBUG("Cammeo Cammeo: %ld", record.cc);
|
|
||||||
BLT_DEBUG("Cammeo Osmancik: %ld", record.co);
|
|
||||||
BLT_DEBUG("Osmancik Osmancik: %ld", record.oo);
|
|
||||||
BLT_DEBUG("Osmancik Cammeo: %ld", record.oc);
|
|
||||||
BLT_DEBUG("Fitness: %lf, stand: %lf, raw: %lf", i.fitness.adjusted_fitness, i.fitness.standardized_fitness, i.fitness.raw_fitness);
|
|
||||||
|
|
||||||
std::cout << "\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
BLT_INFO("Average Results");
|
|
||||||
test_results_t avg{};
|
|
||||||
for (const auto& v : results)
|
|
||||||
avg += v.first;
|
|
||||||
avg /= results.size();
|
|
||||||
BLT_INFO("Hits %ld, Total Cases %ld, Percent Hit: %lf", avg.hits, avg.size, avg.percent_hit);
|
|
||||||
BLT_DEBUG("Cammeo Cammeo: %ld", avg.cc);
|
|
||||||
BLT_DEBUG("Cammeo Osmancik: %ld", avg.co);
|
|
||||||
BLT_DEBUG("Osmancik Osmancik: %ld", avg.oo);
|
|
||||||
BLT_DEBUG("Osmancik Cammeo: %ld", avg.oc);
|
|
||||||
std::cout << "\n";
|
|
||||||
|
|
||||||
BLT_PRINT_PROFILE("Rice Classification", blt::PRINT_CYCLES | blt::PRINT_THREAD | blt::PRINT_WALL);
|
|
||||||
|
|
||||||
#ifdef BLT_TRACK_ALLOCATIONS
|
|
||||||
BLT_TRACE("Total Allocations: %ld times with a total of %s", blt::gp::tracker.getAllocations(),
|
|
||||||
blt::byte_convert_t(blt::gp::tracker.getAllocatedBytes()).convert_to_nearest_type().to_pretty_string().c_str());
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
|
@ -21,7 +21,6 @@
|
||||||
#include <blt/std/logging.h>
|
#include <blt/std/logging.h>
|
||||||
#include <blt/std/format.h>
|
#include <blt/std/format.h>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include "operations_common.h"
|
|
||||||
|
|
||||||
//static constexpr long SEED = 41912;
|
//static constexpr long SEED = 41912;
|
||||||
static const unsigned long SEED = std::random_device()();
|
static const unsigned long SEED = std::random_device()();
|
||||||
|
@ -31,7 +30,7 @@ struct context
|
||||||
float x, y;
|
float x, y;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::array<context, 200> training_cases;
|
std::array<context, 200> fitness_cases;
|
||||||
|
|
||||||
blt::gp::prog_config_t config = blt::gp::prog_config_t()
|
blt::gp::prog_config_t config = blt::gp::prog_config_t()
|
||||||
.set_initial_min_tree_size(2)
|
.set_initial_min_tree_size(2)
|
||||||
|
@ -41,10 +40,20 @@ blt::gp::prog_config_t config = blt::gp::prog_config_t()
|
||||||
.set_mutation_chance(0.1)
|
.set_mutation_chance(0.1)
|
||||||
.set_reproduction_chance(0)
|
.set_reproduction_chance(0)
|
||||||
.set_max_generations(50)
|
.set_max_generations(50)
|
||||||
.set_pop_size(500)
|
.set_pop_size(5000)
|
||||||
.set_thread_count(0);
|
.set_thread_count(0);
|
||||||
|
|
||||||
blt::gp::gp_program program{SEED, config};
|
blt::gp::type_provider type_system;
|
||||||
|
blt::gp::gp_program program{type_system, SEED, config};
|
||||||
|
|
||||||
|
blt::gp::operation_t add([](float a, float b) { return a + b; }, "add");
|
||||||
|
blt::gp::operation_t sub([](float a, float b) { return a - b; }, "sub");
|
||||||
|
blt::gp::operation_t mul([](float a, float b) { return a * b; }, "mul");
|
||||||
|
blt::gp::operation_t pro_div([](float a, float b) { return b == 0.0f ? 1.0f : a / b; }, "div");
|
||||||
|
blt::gp::operation_t op_sin([](float a) { return std::sin(a); }, "sin");
|
||||||
|
blt::gp::operation_t op_cos([](float a) { return std::cos(a); }, "cos");
|
||||||
|
blt::gp::operation_t op_exp([](float a) { return std::exp(a); }, "exp");
|
||||||
|
blt::gp::operation_t op_log([](float a) { return a == 0.0f ? 0.0f : std::log(a); }, "log");
|
||||||
|
|
||||||
auto lit = blt::gp::operation_t([]() {
|
auto lit = blt::gp::operation_t([]() {
|
||||||
return program.get_random().get_float(-320.0f, 320.0f);
|
return program.get_random().get_float(-320.0f, 320.0f);
|
||||||
|
@ -56,7 +65,7 @@ blt::gp::operation_t op_x([](const context& context) {
|
||||||
|
|
||||||
constexpr auto fitness_function = [](blt::gp::tree_t& current_tree, blt::gp::fitness_t& fitness, blt::size_t) {
|
constexpr auto fitness_function = [](blt::gp::tree_t& current_tree, blt::gp::fitness_t& fitness, blt::size_t) {
|
||||||
constexpr double value_cutoff = 1.e15;
|
constexpr double value_cutoff = 1.e15;
|
||||||
for (auto& fitness_case : training_cases)
|
for (auto& fitness_case : fitness_cases)
|
||||||
{
|
{
|
||||||
auto diff = std::abs(fitness_case.y - current_tree.get_evaluation_value<float>(&fitness_case));
|
auto diff = std::abs(fitness_case.y - current_tree.get_evaluation_value<float>(&fitness_case));
|
||||||
if (diff < value_cutoff)
|
if (diff < value_cutoff)
|
||||||
|
@ -69,7 +78,7 @@ constexpr auto fitness_function = [](blt::gp::tree_t& current_tree, blt::gp::fit
|
||||||
}
|
}
|
||||||
fitness.standardized_fitness = fitness.raw_fitness;
|
fitness.standardized_fitness = fitness.raw_fitness;
|
||||||
fitness.adjusted_fitness = (1.0 / (1.0 + fitness.standardized_fitness));
|
fitness.adjusted_fitness = (1.0 / (1.0 + fitness.standardized_fitness));
|
||||||
return static_cast<blt::size_t>(fitness.hits) == training_cases.size();
|
return static_cast<blt::size_t>(fitness.hits) == fitness_cases.size();
|
||||||
};
|
};
|
||||||
|
|
||||||
float example_function(float x)
|
float example_function(float x)
|
||||||
|
@ -82,7 +91,7 @@ int main()
|
||||||
BLT_INFO("Starting BLT-GP Symbolic Regression Example");
|
BLT_INFO("Starting BLT-GP Symbolic Regression Example");
|
||||||
BLT_START_INTERVAL("Symbolic Regression", "Main");
|
BLT_START_INTERVAL("Symbolic Regression", "Main");
|
||||||
BLT_DEBUG("Setup Fitness cases");
|
BLT_DEBUG("Setup Fitness cases");
|
||||||
for (auto& fitness_case : training_cases)
|
for (auto& fitness_case : fitness_cases)
|
||||||
{
|
{
|
||||||
constexpr float range = 10;
|
constexpr float range = 10;
|
||||||
constexpr float half_range = range / 2.0;
|
constexpr float half_range = range / 2.0;
|
||||||
|
@ -92,12 +101,14 @@ int main()
|
||||||
}
|
}
|
||||||
|
|
||||||
BLT_DEBUG("Setup Types and Operators");
|
BLT_DEBUG("Setup Types and Operators");
|
||||||
blt::gp::operator_builder<context> builder{};
|
type_system.register_type<float>();
|
||||||
|
|
||||||
|
blt::gp::operator_builder<context> builder{type_system};
|
||||||
program.set_operations(builder.build(add, sub, mul, pro_div, op_sin, op_cos, op_exp, op_log, lit, op_x));
|
program.set_operations(builder.build(add, sub, mul, pro_div, op_sin, op_cos, op_exp, op_log, lit, op_x));
|
||||||
|
|
||||||
BLT_DEBUG("Generate Initial Population");
|
BLT_DEBUG("Generate Initial Population");
|
||||||
auto sel = blt::gp::select_tournament_t{};
|
auto sel = blt::gp::select_fitness_proportionate_t{};
|
||||||
program.generate_population(program.get_typesystem().get_type<float>().id(), fitness_function, sel, sel, sel);
|
program.generate_population(type_system.get_type<float>().id(), fitness_function, sel, sel, sel);
|
||||||
|
|
||||||
BLT_DEBUG("Begin Generation Loop");
|
BLT_DEBUG("Begin Generation Loop");
|
||||||
while (!program.should_terminate())
|
while (!program.should_terminate())
|
||||||
|
@ -164,5 +175,13 @@ int main()
|
||||||
blt::byte_convert_t(blt::gp::tracker.getAllocatedBytes()).convert_to_nearest_type().to_pretty_string().c_str());
|
blt::byte_convert_t(blt::gp::tracker.getAllocatedBytes()).convert_to_nearest_type().to_pretty_string().c_str());
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// BLT_TRACE("Allocations:");
|
||||||
|
// auto h = static_cast<blt::ptrdiff_t>(blt::gp::hello.load());
|
||||||
|
// auto u = static_cast<blt::ptrdiff_t>(blt::gp::unhello.load());
|
||||||
|
// BLT_TRACE("Allocated: %ld", h);
|
||||||
|
// BLT_TRACE("Deallocated: %ld", u);
|
||||||
|
// BLT_TRACE("Ratio: %lf Difference: %ld", static_cast<double>(h) / static_cast<double>(u), std::abs(h - u));
|
||||||
|
// BLT_TRACE("Total Allocated Bytes: %ld", blt::gp::hello_bytes.load());
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
|
@ -22,22 +22,16 @@
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <blt/std/logging.h>
|
#include <blt/std/logging.h>
|
||||||
#include <blt/std/types.h>
|
#include <blt/std/types.h>
|
||||||
#include <blt/gp/stats.h>
|
|
||||||
#include <ostream>
|
#include <ostream>
|
||||||
#include <cstdlib>
|
#include <optional>
|
||||||
|
|
||||||
namespace blt::gp
|
namespace blt::gp
|
||||||
{
|
{
|
||||||
inline allocation_tracker_t tracker;
|
|
||||||
|
|
||||||
class gp_program;
|
class gp_program;
|
||||||
|
|
||||||
class type;
|
class type;
|
||||||
|
|
||||||
struct operator_id;
|
|
||||||
|
|
||||||
struct type_id;
|
|
||||||
|
|
||||||
class type_provider;
|
class type_provider;
|
||||||
|
|
||||||
struct op_container_t;
|
struct op_container_t;
|
||||||
|
@ -46,8 +40,6 @@ namespace blt::gp
|
||||||
|
|
||||||
class tree_t;
|
class tree_t;
|
||||||
|
|
||||||
struct individual_t;
|
|
||||||
|
|
||||||
class population_t;
|
class population_t;
|
||||||
|
|
||||||
class tree_generator_t;
|
class tree_generator_t;
|
||||||
|
@ -58,112 +50,6 @@ namespace blt::gp
|
||||||
|
|
||||||
class stack_allocator;
|
class stack_allocator;
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
class tracked_allocator_t;
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
using tracked_vector = std::vector<T, tracked_allocator_t<T>>;
|
|
||||||
|
|
||||||
// using operation_vector_t = tracked_vector<op_container_t>;
|
|
||||||
// using individual_vector_t = tracked_vector<individual_t, tracked_allocator_t<individual_t>>;
|
|
||||||
// using tree_vector_t = tracked_vector<tree_t>;
|
|
||||||
|
|
||||||
class aligned_allocator
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
void* allocate(blt::size_t bytes) // NOLINT
|
|
||||||
{
|
|
||||||
#ifdef BLT_TRACK_ALLOCATIONS
|
|
||||||
tracker.allocate(bytes);
|
|
||||||
#endif
|
|
||||||
return std::aligned_alloc(8, bytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
void deallocate(void* ptr, blt::size_t bytes) // NOLINT
|
|
||||||
{
|
|
||||||
if (ptr == nullptr)
|
|
||||||
return;
|
|
||||||
#ifdef BLT_TRACK_ALLOCATIONS
|
|
||||||
tracker.deallocate(bytes);
|
|
||||||
#else
|
|
||||||
(void) bytes;
|
|
||||||
#endif
|
|
||||||
std::free(ptr);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
class tracked_allocator_t
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
using value_type = T;
|
|
||||||
using reference = T&;
|
|
||||||
using const_reference = const T&;
|
|
||||||
using pointer = T*;
|
|
||||||
using const_pointer = const T*;
|
|
||||||
using void_pointer = void*;
|
|
||||||
using const_void_pointer = const void*;
|
|
||||||
using difference_type = blt::ptrdiff_t;
|
|
||||||
using size_type = blt::size_t;
|
|
||||||
template<class U>
|
|
||||||
struct rebind
|
|
||||||
{
|
|
||||||
typedef tracked_allocator_t<U> other;
|
|
||||||
};
|
|
||||||
|
|
||||||
pointer allocate(size_type n)
|
|
||||||
{
|
|
||||||
#ifdef BLT_TRACK_ALLOCATIONS
|
|
||||||
tracker.allocate(n * sizeof(T));
|
|
||||||
#endif
|
|
||||||
return static_cast<pointer>(std::malloc(n * sizeof(T)));
|
|
||||||
}
|
|
||||||
|
|
||||||
pointer allocate(size_type n, const_void_pointer)
|
|
||||||
{
|
|
||||||
return allocate(n);
|
|
||||||
}
|
|
||||||
|
|
||||||
void deallocate(pointer p, size_type n)
|
|
||||||
{
|
|
||||||
#ifdef BLT_TRACK_ALLOCATIONS
|
|
||||||
tracker.deallocate(n * sizeof(T));
|
|
||||||
#else
|
|
||||||
(void) n;
|
|
||||||
#endif
|
|
||||||
std::free(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class U, class... Args>
|
|
||||||
void construct(U* p, Args&& ... args)
|
|
||||||
{
|
|
||||||
new(p) T(args...);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class U>
|
|
||||||
void destroy(U* p)
|
|
||||||
{
|
|
||||||
p->~T();
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] size_type max_size() const noexcept
|
|
||||||
{
|
|
||||||
return std::numeric_limits<size_type>::max();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template<class T1, class T2>
|
|
||||||
inline static bool operator==(const tracked_allocator_t<T1>& lhs, const tracked_allocator_t<T2>& rhs) noexcept
|
|
||||||
{
|
|
||||||
return &lhs == &rhs;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class T1, class T2>
|
|
||||||
inline static bool operator!=(const tracked_allocator_t<T1>& lhs, const tracked_allocator_t<T2>& rhs) noexcept
|
|
||||||
{
|
|
||||||
return &lhs != &rhs;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace detail
|
namespace detail
|
||||||
{
|
{
|
||||||
class operator_storage_test;
|
class operator_storage_test;
|
||||||
|
@ -180,9 +66,6 @@ namespace blt::gp
|
||||||
};
|
};
|
||||||
|
|
||||||
using destroy_func_t = std::function<void(destroy_t, stack_allocator&)>;
|
using destroy_func_t = std::function<void(destroy_t, stack_allocator&)>;
|
||||||
|
|
||||||
using const_op_iter_t = tracked_vector<op_container_t>::const_iterator;
|
|
||||||
using op_iter_t = tracked_vector<op_container_t>::iterator;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,6 +56,7 @@
|
||||||
|
|
||||||
namespace blt::gp
|
namespace blt::gp
|
||||||
{
|
{
|
||||||
|
|
||||||
struct argc_t
|
struct argc_t
|
||||||
{
|
{
|
||||||
blt::u32 argc = 0;
|
blt::u32 argc = 0;
|
||||||
|
@ -79,22 +80,20 @@ namespace blt::gp
|
||||||
detail::operator_func_t func;
|
detail::operator_func_t func;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct program_operator_storage_t
|
struct operator_storage
|
||||||
{
|
{
|
||||||
// indexed from return TYPE ID, returns index of operator
|
// indexed from return TYPE ID, returns index of operator
|
||||||
blt::expanding_buffer<std::vector<operator_id>> terminals;
|
blt::expanding_buffer<std::vector<operator_id>> terminals;
|
||||||
blt::expanding_buffer<std::vector<operator_id>> non_terminals;
|
blt::expanding_buffer<std::vector<operator_id>> non_terminals;
|
||||||
blt::expanding_buffer<std::vector<std::pair<operator_id, blt::size_t>>> operators_ordered_terminals;
|
blt::expanding_buffer<std::vector<std::pair<operator_id, blt::size_t>>> operators_ordered_terminals;
|
||||||
// indexed from OPERATOR ID (operator number)
|
// indexed from OPERATOR ID (operator number)
|
||||||
blt::hashset_t<operator_id> ephemeral_leaf_operators;
|
blt::hashset_t<operator_id> static_types;
|
||||||
std::vector<operator_info> operators;
|
std::vector<operator_info> operators;
|
||||||
std::vector<detail::print_func_t> print_funcs;
|
std::vector<detail::print_func_t> print_funcs;
|
||||||
std::vector<detail::destroy_func_t> destroy_funcs;
|
std::vector<detail::destroy_func_t> destroy_funcs;
|
||||||
std::vector<std::optional<std::string_view>> names;
|
std::vector<std::optional<std::string_view>> names;
|
||||||
|
|
||||||
detail::eval_func_t eval_func;
|
detail::eval_func_t eval_func;
|
||||||
|
|
||||||
type_provider system;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename Context = detail::empty_t>
|
template<typename Context = detail::empty_t>
|
||||||
|
@ -105,10 +104,11 @@ namespace blt::gp
|
||||||
friend class blt::gp::detail::operator_storage_test;
|
friend class blt::gp::detail::operator_storage_test;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit operator_builder() = default;
|
explicit operator_builder(type_provider& system): system(system)
|
||||||
|
{}
|
||||||
|
|
||||||
template<typename... Operators>
|
template<typename... Operators>
|
||||||
program_operator_storage_t& build(Operators& ... operators)
|
operator_storage& build(Operators& ... operators)
|
||||||
{
|
{
|
||||||
std::vector<blt::size_t> sizes;
|
std::vector<blt::size_t> sizes;
|
||||||
(sizes.push_back(add_operator(operators)), ...);
|
(sizes.push_back(add_operator(operators)), ...);
|
||||||
|
@ -201,7 +201,7 @@ namespace blt::gp
|
||||||
return storage;
|
return storage;
|
||||||
}
|
}
|
||||||
|
|
||||||
program_operator_storage_t&& grab()
|
operator_storage&& grab()
|
||||||
{
|
{
|
||||||
return std::move(storage);
|
return std::move(storage);
|
||||||
}
|
}
|
||||||
|
@ -210,14 +210,10 @@ namespace blt::gp
|
||||||
template<typename RawFunction, typename Return, typename... Args>
|
template<typename RawFunction, typename Return, typename... Args>
|
||||||
auto add_operator(operation_t<RawFunction, Return(Args...)>& op)
|
auto add_operator(operation_t<RawFunction, Return(Args...)>& op)
|
||||||
{
|
{
|
||||||
// check for types we can register
|
|
||||||
(storage.system.register_type<Args>(), ...);
|
|
||||||
storage.system.register_type<Return>();
|
|
||||||
|
|
||||||
auto total_size_required = stack_allocator::aligned_size(sizeof(Return));
|
auto total_size_required = stack_allocator::aligned_size(sizeof(Return));
|
||||||
((total_size_required += stack_allocator::aligned_size(sizeof(Args))), ...);
|
((total_size_required += stack_allocator::aligned_size(sizeof(Args))), ...);
|
||||||
|
|
||||||
auto return_type_id = storage.system.get_type<Return>().id();
|
auto return_type_id = system.get_type<Return>().id();
|
||||||
auto operator_id = blt::gp::operator_id(storage.operators.size());
|
auto operator_id = blt::gp::operator_id(storage.operators.size());
|
||||||
op.id = operator_id;
|
op.id = operator_id;
|
||||||
|
|
||||||
|
@ -266,7 +262,7 @@ namespace blt::gp
|
||||||
});
|
});
|
||||||
storage.names.push_back(op.get_name());
|
storage.names.push_back(op.get_name());
|
||||||
if (op.is_ephemeral())
|
if (op.is_ephemeral())
|
||||||
storage.ephemeral_leaf_operators.insert(operator_id);
|
storage.static_types.insert(operator_id);
|
||||||
return total_size_required * 2;
|
return total_size_required * 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -275,7 +271,7 @@ namespace blt::gp
|
||||||
{
|
{
|
||||||
if constexpr (!std::is_same_v<Context, detail::remove_cv_ref<T>>)
|
if constexpr (!std::is_same_v<Context, detail::remove_cv_ref<T>>)
|
||||||
{
|
{
|
||||||
types.push_back(storage.system.get_type<T>().id());
|
types.push_back(system.get_type<T>().id());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -320,7 +316,8 @@ namespace blt::gp
|
||||||
call_jmp_table_internal(op, context, write_stack, read_stack, std::index_sequence_for<Operators...>(), operators...);
|
call_jmp_table_internal(op, context, write_stack, read_stack, std::index_sequence_for<Operators...>(), operators...);
|
||||||
}
|
}
|
||||||
|
|
||||||
program_operator_storage_t storage;
|
type_provider& system;
|
||||||
|
operator_storage storage;
|
||||||
};
|
};
|
||||||
|
|
||||||
class gp_program
|
class gp_program
|
||||||
|
@ -330,83 +327,29 @@ namespace blt::gp
|
||||||
* Note about context size: This is required as context is passed to every operator in the GP tree, this context will be provided by your
|
* Note about context size: This is required as context is passed to every operator in the GP tree, this context will be provided by your
|
||||||
* call to one of the evaluator functions. This was the nicest way to provide this as C++ lacks reflection
|
* call to one of the evaluator functions. This was the nicest way to provide this as C++ lacks reflection
|
||||||
*
|
*
|
||||||
|
* @param system type system to use in tree generation
|
||||||
* @param engine random engine to use throughout the program.
|
* @param engine random engine to use throughout the program.
|
||||||
* @param context_size number of arguments which are always present as "context" to the GP system / operators
|
* @param context_size number of arguments which are always present as "context" to the GP system / operators
|
||||||
*/
|
*/
|
||||||
explicit gp_program(blt::u64 seed): seed_func([seed] { return seed; })
|
explicit gp_program(type_provider& system, blt::u64 seed):
|
||||||
|
system(system), seed(seed)
|
||||||
{ create_threads(); }
|
{ create_threads(); }
|
||||||
|
|
||||||
explicit gp_program(blt::u64 seed, prog_config_t config): seed_func([seed] { return seed; }), config(config)
|
explicit gp_program(type_provider& system, blt::u64 seed, prog_config_t config):
|
||||||
|
system(system), seed(seed), config(config)
|
||||||
{ create_threads(); }
|
{ create_threads(); }
|
||||||
|
|
||||||
explicit gp_program(std::function<blt::u64()> seed_func): seed_func(std::move(seed_func))
|
|
||||||
{ create_threads(); }
|
|
||||||
|
|
||||||
explicit gp_program(std::function<blt::u64()> seed_func, prog_config_t config): seed_func(std::move(seed_func)), config(config)
|
|
||||||
{ create_threads(); }
|
|
||||||
|
|
||||||
~gp_program()
|
|
||||||
{
|
|
||||||
thread_helper.lifetime_over = true;
|
|
||||||
thread_helper.barrier.notify_all();
|
|
||||||
thread_helper.thread_function_condition.notify_all();
|
|
||||||
for (auto& thread : thread_helper.threads)
|
|
||||||
{
|
|
||||||
if (thread->joinable())
|
|
||||||
thread->join();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void create_next_generation()
|
void create_next_generation()
|
||||||
{
|
{
|
||||||
#ifdef BLT_TRACK_ALLOCATIONS
|
|
||||||
auto gen_alloc = blt::gp::tracker.start_measurement();
|
|
||||||
#endif
|
|
||||||
// should already be empty
|
// should already be empty
|
||||||
next_pop.clear();
|
next_pop.clear();
|
||||||
thread_helper.next_gen_left.store(config.population_size, std::memory_order_release);
|
thread_helper.next_gen_left.store(config.population_size, std::memory_order_release);
|
||||||
(*thread_execution_service)(0);
|
(*thread_execution_service)(0);
|
||||||
#ifdef BLT_TRACK_ALLOCATIONS
|
|
||||||
blt::gp::tracker.stop_measurement(gen_alloc);
|
|
||||||
BLT_TRACE("Generation Allocated %ld times with a total of %s", gen_alloc.getAllocationDifference(),
|
|
||||||
blt::byte_convert_t(gen_alloc.getAllocatedByteDifference()).convert_to_nearest_type().to_pretty_string().c_str());
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void next_generation()
|
|
||||||
{
|
|
||||||
BLT_ASSERT_MSG(next_pop.get_individuals().size() == config.population_size,
|
|
||||||
("pop size: " + std::to_string(next_pop.get_individuals().size())).c_str());
|
|
||||||
std::swap(current_pop, next_pop);
|
|
||||||
current_generation++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void evaluate_fitness()
|
void evaluate_fitness()
|
||||||
{
|
{
|
||||||
#ifdef BLT_TRACK_ALLOCATIONS
|
|
||||||
auto fitness_alloc = blt::gp::tracker.start_measurement();
|
|
||||||
#endif
|
|
||||||
evaluate_fitness_internal();
|
evaluate_fitness_internal();
|
||||||
#ifdef BLT_TRACK_ALLOCATIONS
|
|
||||||
blt::gp::tracker.stop_measurement(fitness_alloc);
|
|
||||||
BLT_TRACE("Fitness Allocated %ld times with a total of %s", fitness_alloc.getAllocationDifference(),
|
|
||||||
blt::byte_convert_t(fitness_alloc.getAllocatedByteDifference()).convert_to_nearest_type().to_pretty_string().c_str());
|
|
||||||
#endif
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void reset_program(type_id root_type, bool eval_fitness_now = true)
|
|
||||||
{
|
|
||||||
current_generation = 0;
|
|
||||||
current_pop = config.pop_initializer.get().generate(
|
|
||||||
{*this, root_type, config.population_size, config.initial_min_tree_size, config.initial_max_tree_size});
|
|
||||||
if (eval_fitness_now)
|
|
||||||
evaluate_fitness_internal();
|
|
||||||
}
|
|
||||||
|
|
||||||
void kill()
|
|
||||||
{
|
|
||||||
thread_helper.lifetime_over = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -427,51 +370,44 @@ namespace blt::gp
|
||||||
using LambdaReturn = typename decltype(blt::meta::lambda_helper(fitness_function))::Return;
|
using LambdaReturn = typename decltype(blt::meta::lambda_helper(fitness_function))::Return;
|
||||||
current_pop = config.pop_initializer.get().generate(
|
current_pop = config.pop_initializer.get().generate(
|
||||||
{*this, root_type, config.population_size, config.initial_min_tree_size, config.initial_max_tree_size});
|
{*this, root_type, config.population_size, config.initial_min_tree_size, config.initial_max_tree_size});
|
||||||
next_pop = population_t(current_pop);
|
|
||||||
if (config.threads == 1)
|
if (config.threads == 1)
|
||||||
{
|
{
|
||||||
BLT_INFO("Starting with single thread variant!");
|
BLT_INFO("Starting with single thread variant!");
|
||||||
thread_execution_service = std::unique_ptr<std::function<void(blt::size_t)>>(new std::function(
|
thread_execution_service = new std::function(
|
||||||
[this, &fitness_function, &crossover_selection, &mutation_selection, &reproduction_selection, &func](blt::size_t) {
|
[this, &fitness_function, &crossover_selection, &mutation_selection, &reproduction_selection, &func](blt::size_t) {
|
||||||
if (thread_helper.evaluation_left > 0)
|
if (thread_helper.evaluation_left > 0)
|
||||||
{
|
{
|
||||||
current_stats.normalized_fitness.clear();
|
for (const auto& ind : blt::enumerate(current_pop.get_individuals()))
|
||||||
double sum_of_prob = 0;
|
|
||||||
for (const auto& [index, ind] : blt::enumerate(current_pop.get_individuals()))
|
|
||||||
{
|
{
|
||||||
if constexpr (std::is_same_v<LambdaReturn, bool> || std::is_convertible_v<LambdaReturn, bool>)
|
if constexpr (std::is_same_v<LambdaReturn, bool> || std::is_convertible_v<LambdaReturn, bool>)
|
||||||
{
|
{
|
||||||
auto result = fitness_function(ind.tree, ind.fitness, index);
|
auto result = fitness_function(ind.second.tree, ind.second.fitness, ind.first);
|
||||||
if (result)
|
if (result)
|
||||||
fitness_should_exit = true;
|
fitness_should_exit = true;
|
||||||
} else
|
} else
|
||||||
fitness_function(ind.tree, ind.fitness, index);
|
|
||||||
|
|
||||||
if (ind.fitness.adjusted_fitness > current_stats.best_fitness)
|
|
||||||
current_stats.best_fitness = ind.fitness.adjusted_fitness;
|
|
||||||
|
|
||||||
if (ind.fitness.adjusted_fitness < current_stats.worst_fitness)
|
|
||||||
current_stats.worst_fitness = ind.fitness.adjusted_fitness;
|
|
||||||
|
|
||||||
current_stats.overall_fitness = current_stats.overall_fitness + ind.fitness.adjusted_fitness;
|
|
||||||
}
|
|
||||||
for (auto& ind : current_pop)
|
|
||||||
{
|
{
|
||||||
auto prob = (ind.fitness.adjusted_fitness / current_stats.overall_fitness);
|
fitness_function(ind.second.tree, ind.second.fitness, ind.first);
|
||||||
current_stats.normalized_fitness.push_back(sum_of_prob + prob);
|
}
|
||||||
sum_of_prob += prob;
|
|
||||||
|
if (ind.second.fitness.adjusted_fitness > current_stats.best_fitness)
|
||||||
|
current_stats.best_fitness = ind.second.fitness.adjusted_fitness;
|
||||||
|
|
||||||
|
if (ind.second.fitness.adjusted_fitness < current_stats.worst_fitness)
|
||||||
|
current_stats.worst_fitness = ind.second.fitness.adjusted_fitness;
|
||||||
|
|
||||||
|
current_stats.overall_fitness = current_stats.overall_fitness + ind.second.fitness.adjusted_fitness;
|
||||||
}
|
}
|
||||||
thread_helper.evaluation_left = 0;
|
thread_helper.evaluation_left = 0;
|
||||||
}
|
}
|
||||||
if (thread_helper.next_gen_left > 0)
|
if (thread_helper.next_gen_left > 0)
|
||||||
{
|
{
|
||||||
static thread_local tracked_vector<tree_t> new_children;
|
static thread_local std::vector<tree_t> new_children;
|
||||||
new_children.clear();
|
new_children.clear();
|
||||||
auto args = get_selector_args(new_children);
|
auto args = get_selector_args(new_children);
|
||||||
|
|
||||||
crossover_selection.pre_process(*this, current_pop);
|
crossover_selection.pre_process(*this, current_pop, current_stats);
|
||||||
mutation_selection.pre_process(*this, current_pop);
|
mutation_selection.pre_process(*this, current_pop, current_stats);
|
||||||
reproduction_selection.pre_process(*this, current_pop);
|
reproduction_selection.pre_process(*this, current_pop, current_stats);
|
||||||
|
|
||||||
perform_elitism(args);
|
perform_elitism(args);
|
||||||
|
|
||||||
|
@ -483,12 +419,12 @@ namespace blt::gp
|
||||||
|
|
||||||
thread_helper.next_gen_left = 0;
|
thread_helper.next_gen_left = 0;
|
||||||
}
|
}
|
||||||
}));
|
});
|
||||||
} else
|
} else
|
||||||
{
|
{
|
||||||
BLT_INFO("Starting thread execution service!");
|
BLT_INFO("Starting thread execution service!");
|
||||||
std::scoped_lock lock(thread_helper.thread_function_control);
|
std::scoped_lock lock(thread_helper.thread_function_control);
|
||||||
thread_execution_service = std::unique_ptr<std::function<void(blt::size_t)>>(new std::function(
|
thread_execution_service = new std::function(
|
||||||
[this, &fitness_function, &crossover_selection, &mutation_selection, &reproduction_selection, &func](blt::size_t id) {
|
[this, &fitness_function, &crossover_selection, &mutation_selection, &reproduction_selection, &func](blt::size_t id) {
|
||||||
thread_helper.barrier.wait();
|
thread_helper.barrier.wait();
|
||||||
if (thread_helper.evaluation_left > 0)
|
if (thread_helper.evaluation_left > 0)
|
||||||
|
@ -542,25 +478,16 @@ namespace blt::gp
|
||||||
}
|
}
|
||||||
if (thread_helper.next_gen_left > 0)
|
if (thread_helper.next_gen_left > 0)
|
||||||
{
|
{
|
||||||
static thread_local tracked_vector<tree_t> new_children;
|
static thread_local std::vector<tree_t> new_children;
|
||||||
new_children.clear();
|
new_children.clear();
|
||||||
auto args = get_selector_args(new_children);
|
auto args = get_selector_args(new_children);
|
||||||
if (id == 0)
|
if (id == 0)
|
||||||
{
|
{
|
||||||
current_stats.normalized_fitness.clear();
|
crossover_selection.pre_process(*this, current_pop, current_stats);
|
||||||
double sum_of_prob = 0;
|
|
||||||
for (auto& ind : current_pop)
|
|
||||||
{
|
|
||||||
auto prob = (ind.fitness.adjusted_fitness / current_stats.overall_fitness);
|
|
||||||
current_stats.normalized_fitness.push_back(sum_of_prob + prob);
|
|
||||||
sum_of_prob += prob;
|
|
||||||
}
|
|
||||||
|
|
||||||
crossover_selection.pre_process(*this, current_pop);
|
|
||||||
if (&crossover_selection != &mutation_selection)
|
if (&crossover_selection != &mutation_selection)
|
||||||
mutation_selection.pre_process(*this, current_pop);
|
mutation_selection.pre_process(*this, current_pop, current_stats);
|
||||||
if (&crossover_selection != &reproduction_selection)
|
if (&crossover_selection != &reproduction_selection)
|
||||||
reproduction_selection.pre_process(*this, current_pop);
|
reproduction_selection.pre_process(*this, current_pop, current_stats);
|
||||||
|
|
||||||
perform_elitism(args);
|
perform_elitism(args);
|
||||||
|
|
||||||
|
@ -596,13 +523,75 @@ namespace blt::gp
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
thread_helper.barrier.wait();
|
thread_helper.barrier.wait();
|
||||||
}));
|
});
|
||||||
thread_helper.thread_function_condition.notify_all();
|
thread_helper.thread_function_condition.notify_all();
|
||||||
}
|
}
|
||||||
if (eval_fitness_now)
|
if (eval_fitness_now)
|
||||||
evaluate_fitness_internal();
|
evaluate_fitness_internal();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void reset_program(type_id root_type, bool eval_fitness_now = true)
|
||||||
|
{
|
||||||
|
current_generation = 0;
|
||||||
|
current_pop = config.pop_initializer.get().generate(
|
||||||
|
{*this, root_type, config.population_size, config.initial_min_tree_size, config.initial_max_tree_size});
|
||||||
|
if (eval_fitness_now)
|
||||||
|
evaluate_fitness_internal();
|
||||||
|
}
|
||||||
|
|
||||||
|
void next_generation()
|
||||||
|
{
|
||||||
|
BLT_ASSERT_MSG(next_pop.get_individuals().size() == config.population_size, ("pop size: " + std::to_string(next_pop.get_individuals().size())).c_str());
|
||||||
|
current_pop = std::move(next_pop);
|
||||||
|
current_generation++;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline auto& get_current_pop()
|
||||||
|
{
|
||||||
|
return current_pop;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<blt::size_t size>
|
||||||
|
std::array<blt::size_t, size> get_best_indexes()
|
||||||
|
{
|
||||||
|
std::array<blt::size_t, size> arr;
|
||||||
|
|
||||||
|
std::vector<std::pair<blt::size_t, double>> values;
|
||||||
|
values.reserve(current_pop.get_individuals().size());
|
||||||
|
|
||||||
|
for (const auto& ind : blt::enumerate(current_pop.get_individuals()))
|
||||||
|
values.emplace_back(ind.first, ind.second.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 < size; i++)
|
||||||
|
arr[i] = values[i].first;
|
||||||
|
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<blt::size_t size>
|
||||||
|
auto get_best_trees()
|
||||||
|
{
|
||||||
|
return convert_array<std::array<std::reference_wrapper<tree_t>, size>>(get_best_indexes<size>(),
|
||||||
|
[this](auto&& arr, blt::size_t index) -> tree_t& {
|
||||||
|
return current_pop.get_individuals()[arr[index]].tree;
|
||||||
|
},
|
||||||
|
std::make_integer_sequence<blt::size_t, size>());
|
||||||
|
}
|
||||||
|
|
||||||
|
template<blt::size_t size>
|
||||||
|
auto get_best_individuals()
|
||||||
|
{
|
||||||
|
return convert_array<std::array<std::reference_wrapper<individual>, size>>(get_best_indexes<size>(),
|
||||||
|
[this](auto&& arr, blt::size_t index) -> individual& {
|
||||||
|
return current_pop.get_individuals()[arr[index]];
|
||||||
|
},
|
||||||
|
std::make_integer_sequence<blt::size_t, size>());
|
||||||
|
}
|
||||||
|
|
||||||
[[nodiscard]] bool should_terminate() const
|
[[nodiscard]] bool should_terminate() const
|
||||||
{
|
{
|
||||||
return current_generation >= config.max_generations || fitness_should_exit;
|
return current_generation >= config.max_generations || fitness_should_exit;
|
||||||
|
@ -613,6 +602,13 @@ namespace blt::gp
|
||||||
return thread_helper.lifetime_over;
|
return thread_helper.lifetime_over;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] random_t& get_random() const;
|
||||||
|
|
||||||
|
[[nodiscard]] inline type_provider& get_typesystem()
|
||||||
|
{
|
||||||
|
return system;
|
||||||
|
}
|
||||||
|
|
||||||
inline operator_id select_terminal(type_id id)
|
inline operator_id select_terminal(type_id id)
|
||||||
{
|
{
|
||||||
// we wanted a terminal, but could not find one, so we will select from a function that has a terminal
|
// we wanted a terminal, but could not find one, so we will select from a function that has a terminal
|
||||||
|
@ -638,49 +634,47 @@ namespace blt::gp
|
||||||
return get_random().select(storage.operators_ordered_terminals[id]).first;
|
return get_random().select(storage.operators_ordered_terminals[id]).first;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline auto& get_current_pop()
|
inline operator_info& get_operator_info(operator_id id)
|
||||||
{
|
|
||||||
return current_pop;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] random_t& get_random() const;
|
|
||||||
|
|
||||||
[[nodiscard]] inline type_provider& get_typesystem()
|
|
||||||
{
|
|
||||||
return storage.system;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] inline operator_info& get_operator_info(operator_id id)
|
|
||||||
{
|
{
|
||||||
return storage.operators[id];
|
return storage.operators[id];
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] inline detail::print_func_t& get_print_func(operator_id id)
|
inline detail::print_func_t& get_print_func(operator_id id)
|
||||||
{
|
{
|
||||||
return storage.print_funcs[id];
|
return storage.print_funcs[id];
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] inline detail::destroy_func_t& get_destroy_func(operator_id id)
|
inline detail::destroy_func_t& get_destroy_func(operator_id id)
|
||||||
{
|
{
|
||||||
return storage.destroy_funcs[id];
|
return storage.destroy_funcs[id];
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] inline std::optional<std::string_view> get_name(operator_id id)
|
inline std::optional<std::string_view> get_name(operator_id id)
|
||||||
{
|
{
|
||||||
return storage.names[id];
|
return storage.names[id];
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] inline std::vector<operator_id>& get_type_terminals(type_id id)
|
inline std::vector<operator_id>& get_type_terminals(type_id id)
|
||||||
{
|
{
|
||||||
return storage.terminals[id];
|
return storage.terminals[id];
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] inline std::vector<operator_id>& get_type_non_terminals(type_id id)
|
inline std::vector<operator_id>& get_type_non_terminals(type_id id)
|
||||||
{
|
{
|
||||||
return storage.non_terminals[id];
|
return storage.non_terminals[id];
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] inline detail::eval_func_t& get_eval_func()
|
inline bool is_static(operator_id id)
|
||||||
|
{
|
||||||
|
return storage.static_types.contains(static_cast<blt::size_t>(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void set_operations(operator_storage op)
|
||||||
|
{
|
||||||
|
storage = std::move(op);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline detail::eval_func_t& get_eval_func()
|
||||||
{
|
{
|
||||||
return storage.eval_func;
|
return storage.eval_func;
|
||||||
}
|
}
|
||||||
|
@ -690,64 +684,66 @@ namespace blt::gp
|
||||||
return current_generation.load();
|
return current_generation.load();
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] inline const auto& get_population_stats() const
|
[[nodiscard]] inline auto& get_population_stats()
|
||||||
{
|
{
|
||||||
return current_stats;
|
return current_stats;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] inline bool is_operator_ephemeral(operator_id id)
|
~gp_program()
|
||||||
{
|
{
|
||||||
return storage.ephemeral_leaf_operators.contains(static_cast<blt::size_t>(id));
|
thread_helper.lifetime_over = true;
|
||||||
|
thread_helper.barrier.notify_all();
|
||||||
|
thread_helper.thread_function_condition.notify_all();
|
||||||
|
for (auto& thread : thread_helper.threads)
|
||||||
|
{
|
||||||
|
if (thread->joinable())
|
||||||
|
thread->join();
|
||||||
|
}
|
||||||
|
auto* cpy = thread_execution_service.load(std::memory_order_acquire);
|
||||||
|
thread_execution_service = nullptr;
|
||||||
|
delete cpy;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void set_operations(program_operator_storage_t op)
|
void kill()
|
||||||
{
|
{
|
||||||
storage = std::move(op);
|
thread_helper.lifetime_over = true;
|
||||||
}
|
|
||||||
|
|
||||||
template<blt::size_t size>
|
|
||||||
std::array<blt::size_t, size> get_best_indexes()
|
|
||||||
{
|
|
||||||
std::array<blt::size_t, size> arr;
|
|
||||||
|
|
||||||
std::vector<std::pair<blt::size_t, double>> values;
|
|
||||||
values.reserve(current_pop.get_individuals().size());
|
|
||||||
|
|
||||||
for (const auto& ind : blt::enumerate(current_pop.get_individuals()))
|
|
||||||
values.emplace_back(ind.first, ind.second.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 < size; i++)
|
|
||||||
arr[i] = values[i].first;
|
|
||||||
|
|
||||||
return arr;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<blt::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& {
|
|
||||||
return current_pop.get_individuals()[arr[index]].tree;
|
|
||||||
},
|
|
||||||
std::make_integer_sequence<blt::size_t, size>());
|
|
||||||
}
|
|
||||||
|
|
||||||
template<blt::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& {
|
|
||||||
return current_pop.get_individuals()[arr[index]];
|
|
||||||
},
|
|
||||||
std::make_integer_sequence<blt::size_t, size>());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
inline selector_args get_selector_args(tracked_vector<tree_t>& next_pop_trees)
|
type_provider& system;
|
||||||
|
|
||||||
|
operator_storage storage;
|
||||||
|
population_t current_pop;
|
||||||
|
population_stats current_stats{};
|
||||||
|
population_t next_pop;
|
||||||
|
std::atomic_uint64_t current_generation = 0;
|
||||||
|
std::atomic_bool fitness_should_exit = false;
|
||||||
|
|
||||||
|
blt::u64 seed;
|
||||||
|
prog_config_t config{};
|
||||||
|
|
||||||
|
struct concurrency_storage
|
||||||
|
{
|
||||||
|
std::vector<std::unique_ptr<std::thread>> threads;
|
||||||
|
|
||||||
|
std::mutex thread_function_control;
|
||||||
|
std::mutex thread_generation_lock;
|
||||||
|
std::condition_variable thread_function_condition{};
|
||||||
|
|
||||||
|
std::atomic_uint64_t evaluation_left = 0;
|
||||||
|
std::atomic_uint64_t next_gen_left = 0;
|
||||||
|
|
||||||
|
std::atomic_bool lifetime_over = false;
|
||||||
|
blt::barrier barrier;
|
||||||
|
|
||||||
|
explicit concurrency_storage(blt::size_t threads): barrier(threads, lifetime_over)
|
||||||
|
{}
|
||||||
|
} thread_helper{config.threads == 0 ? std::thread::hardware_concurrency() : config.threads};
|
||||||
|
|
||||||
|
// for convenience, shouldn't decrease performance too much
|
||||||
|
std::atomic<std::function<void(blt::size_t)>*> thread_execution_service = nullptr;
|
||||||
|
|
||||||
|
inline selector_args get_selector_args(std::vector<tree_t>& next_pop_trees)
|
||||||
{
|
{
|
||||||
return {*this, next_pop_trees, current_pop, current_stats, config, get_random()};
|
return {*this, next_pop_trees, current_pop, current_stats, config, get_random()};
|
||||||
}
|
}
|
||||||
|
@ -763,48 +759,12 @@ namespace blt::gp
|
||||||
|
|
||||||
void evaluate_fitness_internal()
|
void evaluate_fitness_internal()
|
||||||
{
|
{
|
||||||
statistic_history.push_back(current_stats);
|
|
||||||
current_stats.clear();
|
current_stats.clear();
|
||||||
thread_helper.evaluation_left.store(current_pop.get_individuals().size(), std::memory_order_release);
|
thread_helper.evaluation_left.store(current_pop.get_individuals().size(), std::memory_order_release);
|
||||||
(*thread_execution_service)(0);
|
(*thread_execution_service)(0);
|
||||||
|
|
||||||
current_stats.average_fitness = current_stats.overall_fitness / static_cast<double>(config.population_size);
|
current_stats.average_fitness = current_stats.overall_fitness / static_cast<double>(config.population_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
|
||||||
program_operator_storage_t storage;
|
|
||||||
std::function<blt::u64()> seed_func;
|
|
||||||
prog_config_t config{};
|
|
||||||
|
|
||||||
population_t current_pop;
|
|
||||||
population_t next_pop;
|
|
||||||
|
|
||||||
std::atomic_uint64_t current_generation = 0;
|
|
||||||
|
|
||||||
std::atomic_bool fitness_should_exit = false;
|
|
||||||
|
|
||||||
population_stats current_stats{};
|
|
||||||
std::vector<population_stats> statistic_history;
|
|
||||||
|
|
||||||
struct concurrency_storage
|
|
||||||
{
|
|
||||||
std::vector<std::unique_ptr<std::thread>> threads;
|
|
||||||
|
|
||||||
std::mutex thread_function_control{};
|
|
||||||
std::mutex thread_generation_lock{};
|
|
||||||
std::condition_variable thread_function_condition{};
|
|
||||||
|
|
||||||
std::atomic_uint64_t evaluation_left = 0;
|
|
||||||
std::atomic_uint64_t next_gen_left = 0;
|
|
||||||
|
|
||||||
std::atomic_bool lifetime_over = false;
|
|
||||||
blt::barrier barrier;
|
|
||||||
|
|
||||||
explicit concurrency_storage(blt::size_t threads): barrier(threads, lifetime_over)
|
|
||||||
{}
|
|
||||||
} thread_helper{config.threads == 0 ? std::thread::hardware_concurrency() : config.threads};
|
|
||||||
|
|
||||||
std::unique_ptr<std::function<void(blt::size_t)>> thread_execution_service = nullptr;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,7 +25,93 @@
|
||||||
namespace blt::gp
|
namespace blt::gp
|
||||||
{
|
{
|
||||||
|
|
||||||
using random_t = blt::random::random_t;
|
#define BLT_RANDOM_FUNCTION blt::random::murmur_random64
|
||||||
|
#define BLT_RANDOM_FLOAT blt::random::murmur_float64
|
||||||
|
#define BLT_RANDOM_DOUBLE blt::random::murmur_double64
|
||||||
|
|
||||||
|
class random_t
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit random_t(blt::u64 seed): seed(seed)
|
||||||
|
{}
|
||||||
|
|
||||||
|
void set_seed(blt::u64 s)
|
||||||
|
{
|
||||||
|
seed = s;
|
||||||
|
}
|
||||||
|
|
||||||
|
float get_float()
|
||||||
|
{
|
||||||
|
return BLT_RANDOM_FLOAT(seed);
|
||||||
|
}
|
||||||
|
|
||||||
|
double get_double()
|
||||||
|
{
|
||||||
|
return BLT_RANDOM_DOUBLE(seed);
|
||||||
|
}
|
||||||
|
|
||||||
|
// [min, max)
|
||||||
|
double get_double(double min, double max)
|
||||||
|
{
|
||||||
|
return BLT_RANDOM_FUNCTION(seed, min, max);
|
||||||
|
}
|
||||||
|
|
||||||
|
// [min, max)
|
||||||
|
float get_float(float min, float max)
|
||||||
|
{
|
||||||
|
return BLT_RANDOM_FUNCTION(seed, min, max);
|
||||||
|
}
|
||||||
|
|
||||||
|
i32 get_i32(i32 min, i32 max)
|
||||||
|
{
|
||||||
|
return BLT_RANDOM_FUNCTION(seed, min, max);
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 get_u32(u32 min, u32 max)
|
||||||
|
{
|
||||||
|
return BLT_RANDOM_FUNCTION(seed, min, max);
|
||||||
|
}
|
||||||
|
|
||||||
|
i64 get_i64(i64 min, i64 max)
|
||||||
|
{
|
||||||
|
return BLT_RANDOM_FUNCTION(seed, min, max);
|
||||||
|
}
|
||||||
|
|
||||||
|
u64 get_u64(u64 min, u64 max)
|
||||||
|
{
|
||||||
|
return BLT_RANDOM_FUNCTION(seed, min, max);
|
||||||
|
}
|
||||||
|
|
||||||
|
blt::size_t get_size_t(blt::size_t min, blt::size_t max)
|
||||||
|
{
|
||||||
|
return BLT_RANDOM_FUNCTION(seed, min, max);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool choice()
|
||||||
|
{
|
||||||
|
return BLT_RANDOM_DOUBLE(seed) < 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool choice(double cutoff)
|
||||||
|
{
|
||||||
|
return BLT_RANDOM_DOUBLE(seed) <= cutoff;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Container>
|
||||||
|
auto& select(Container& container)
|
||||||
|
{
|
||||||
|
return container[get_u64(0, container.size())];
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Container>
|
||||||
|
const auto& select(const Container& container)
|
||||||
|
{
|
||||||
|
return container[get_u64(0, container.size())];
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
blt::u64 seed;
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -32,7 +32,7 @@ namespace blt::gp
|
||||||
struct selector_args
|
struct selector_args
|
||||||
{
|
{
|
||||||
gp_program& program;
|
gp_program& program;
|
||||||
tracked_vector<tree_t>& next_pop;
|
std::vector<tree_t>& next_pop;
|
||||||
population_t& current_pop;
|
population_t& current_pop;
|
||||||
population_stats& current_stats;
|
population_stats& current_stats;
|
||||||
prog_config_t& config;
|
prog_config_t& config;
|
||||||
|
@ -44,8 +44,7 @@ namespace blt::gp
|
||||||
|
|
||||||
if (config.elites > 0)
|
if (config.elites > 0)
|
||||||
{
|
{
|
||||||
static thread_local tracked_vector<std::pair<std::size_t, double>> values;
|
std::vector<std::pair<std::size_t, double>> values;
|
||||||
values.clear();
|
|
||||||
|
|
||||||
for (blt::size_t i = 0; i < config.elites; i++)
|
for (blt::size_t i = 0; i < config.elites; i++)
|
||||||
values.emplace_back(i, current_pop.get_individuals()[i].fitness.adjusted_fitness);
|
values.emplace_back(i, current_pop.get_individuals()[i].fitness.adjusted_fitness);
|
||||||
|
@ -88,8 +87,8 @@ namespace blt::gp
|
||||||
{
|
{
|
||||||
// auto state = tracker.start_measurement();
|
// auto state = tracker.start_measurement();
|
||||||
// crossover
|
// crossover
|
||||||
auto& p1 = crossover_selection.select(program, current_pop);
|
auto& p1 = crossover_selection.select(program, current_pop, current_stats);
|
||||||
auto& p2 = crossover_selection.select(program, current_pop);
|
auto& p2 = crossover_selection.select(program, current_pop, current_stats);
|
||||||
|
|
||||||
auto results = config.crossover.get().apply(program, p1, p2);
|
auto results = config.crossover.get().apply(program, p1, p2);
|
||||||
|
|
||||||
|
@ -110,7 +109,7 @@ namespace blt::gp
|
||||||
{
|
{
|
||||||
// auto state = tracker.start_measurement();
|
// auto state = tracker.start_measurement();
|
||||||
// mutation
|
// mutation
|
||||||
auto& p = mutation_selection.select(program, current_pop);
|
auto& p = mutation_selection.select(program, current_pop, current_stats);
|
||||||
next_pop.push_back(std::move(config.mutator.get().apply(program, p)));
|
next_pop.push_back(std::move(config.mutator.get().apply(program, p)));
|
||||||
// tracker.stop_measurement(state);
|
// tracker.stop_measurement(state);
|
||||||
// BLT_TRACE("Mutation Allocated %ld times with a total of %s", state.getAllocationDifference(),
|
// BLT_TRACE("Mutation Allocated %ld times with a total of %s", state.getAllocationDifference(),
|
||||||
|
@ -122,7 +121,7 @@ namespace blt::gp
|
||||||
{
|
{
|
||||||
// auto state = tracker.start_measurement();
|
// auto state = tracker.start_measurement();
|
||||||
// reproduction
|
// reproduction
|
||||||
auto& p = reproduction_selection.select(program, current_pop);
|
auto& p = reproduction_selection.select(program, current_pop, current_stats);
|
||||||
next_pop.push_back(p);
|
next_pop.push_back(p);
|
||||||
// tracker.stop_measurement(state);
|
// tracker.stop_measurement(state);
|
||||||
// BLT_TRACE("Reproduction Allocated %ld times with a total of %s", state.getAllocationDifference(),
|
// BLT_TRACE("Reproduction Allocated %ld times with a total of %s", state.getAllocationDifference(),
|
||||||
|
@ -147,9 +146,9 @@ namespace blt::gp
|
||||||
* @param stats the populations statistics
|
* @param stats the populations statistics
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
virtual tree_t& select(gp_program& program, population_t& pop) = 0;
|
virtual tree_t& select(gp_program& program, population_t& pop, population_stats& stats) = 0;
|
||||||
|
|
||||||
virtual void pre_process(gp_program&, population_t&)
|
virtual void pre_process(gp_program&, population_t&, population_stats&)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
virtual ~selection_t() = default;
|
virtual ~selection_t() = default;
|
||||||
|
@ -158,19 +157,19 @@ namespace blt::gp
|
||||||
class select_best_t : public selection_t
|
class select_best_t : public selection_t
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
tree_t& select(gp_program& program, population_t& pop) final;
|
tree_t& select(gp_program& program, population_t& pop, population_stats& stats) final;
|
||||||
};
|
};
|
||||||
|
|
||||||
class select_worst_t : public selection_t
|
class select_worst_t : public selection_t
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
tree_t& select(gp_program& program, population_t& pop) final;
|
tree_t& select(gp_program& program, population_t& pop, population_stats& stats) final;
|
||||||
};
|
};
|
||||||
|
|
||||||
class select_random_t : public selection_t
|
class select_random_t : public selection_t
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
tree_t& select(gp_program& program, population_t& pop) final;
|
tree_t& select(gp_program& program, population_t& pop, population_stats& stats) final;
|
||||||
};
|
};
|
||||||
|
|
||||||
class select_tournament_t : public selection_t
|
class select_tournament_t : public selection_t
|
||||||
|
@ -178,11 +177,11 @@ namespace blt::gp
|
||||||
public:
|
public:
|
||||||
explicit select_tournament_t(blt::size_t selection_size = 3): selection_size(selection_size)
|
explicit select_tournament_t(blt::size_t selection_size = 3): selection_size(selection_size)
|
||||||
{
|
{
|
||||||
if (selection_size == 0)
|
if (selection_size < 1)
|
||||||
BLT_ABORT("Unable to select with this size. Must select at least 1 individual_t!");
|
BLT_ABORT("Unable to select with this size. Must select at least 1 individual!");
|
||||||
}
|
}
|
||||||
|
|
||||||
tree_t& select(gp_program& program, population_t& pop) final;
|
tree_t& select(gp_program& program, population_t& pop, population_stats& stats) final;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const blt::size_t selection_size;
|
const blt::size_t selection_size;
|
||||||
|
@ -191,7 +190,9 @@ namespace blt::gp
|
||||||
class select_fitness_proportionate_t : public selection_t
|
class select_fitness_proportionate_t : public selection_t
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
tree_t& select(gp_program& program, population_t& pop) final;
|
void pre_process(gp_program& program, population_t& pop, population_stats& stats) final;
|
||||||
|
|
||||||
|
tree_t& select(gp_program& program, population_t& pop, population_stats& stats) final;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,7 +27,6 @@
|
||||||
#include <blt/std/ranges.h>
|
#include <blt/std/ranges.h>
|
||||||
#include <blt/std/meta.h>
|
#include <blt/std/meta.h>
|
||||||
#include <blt/gp/fwdecl.h>
|
#include <blt/gp/fwdecl.h>
|
||||||
#include <blt/gp/stats.h>
|
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
|
@ -38,11 +37,141 @@
|
||||||
|
|
||||||
namespace blt::gp
|
namespace blt::gp
|
||||||
{
|
{
|
||||||
|
|
||||||
namespace detail
|
namespace detail
|
||||||
{
|
{
|
||||||
BLT_META_MAKE_FUNCTION_CHECK(drop);
|
BLT_META_MAKE_FUNCTION_CHECK(drop);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class allocation_tracker_t
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
struct allocation_data_t
|
||||||
|
{
|
||||||
|
blt::u64 start_allocations = 0;
|
||||||
|
blt::u64 start_deallocations = 0;
|
||||||
|
blt::u64 start_allocated_bytes = 0;
|
||||||
|
blt::u64 start_deallocated_bytes = 0;
|
||||||
|
|
||||||
|
blt::u64 end_allocations = 0;
|
||||||
|
blt::u64 end_deallocations = 0;
|
||||||
|
blt::u64 end_allocated_bytes = 0;
|
||||||
|
blt::u64 end_deallocated_bytes = 0;
|
||||||
|
|
||||||
|
[[nodiscard]] blt::u64 getAllocationDifference() const
|
||||||
|
{
|
||||||
|
return end_allocations - start_allocations;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] blt::u64 getDeallocationDifference() const
|
||||||
|
{
|
||||||
|
return end_deallocations - start_deallocations;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] blt::u64 getAllocatedByteDifference() const
|
||||||
|
{
|
||||||
|
return end_allocated_bytes - start_allocated_bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] blt::u64 getDeallocatedByteDifference() const
|
||||||
|
{
|
||||||
|
return end_deallocated_bytes - start_deallocated_bytes;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
void allocate(blt::size_t bytes)
|
||||||
|
{
|
||||||
|
allocations++;
|
||||||
|
allocated_bytes += bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
void deallocate(blt::size_t bytes)
|
||||||
|
{
|
||||||
|
deallocations++;
|
||||||
|
deallocated_bytes += bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] blt::u64 getAllocations() const
|
||||||
|
{
|
||||||
|
return allocations;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] blt::u64 getDeallocations() const
|
||||||
|
{
|
||||||
|
return deallocations;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] blt::u64 getAllocatedBytes() const
|
||||||
|
{
|
||||||
|
return allocated_bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] blt::u64 getDeallocatedBytes() const
|
||||||
|
{
|
||||||
|
return deallocated_bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] blt::u64 getAllocationDifference() const
|
||||||
|
{
|
||||||
|
return std::abs(static_cast<blt::i64>(getAllocations()) - static_cast<blt::i64>(getDeallocations()));
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] blt::u64 getCurrentlyAllocatedBytes() const
|
||||||
|
{
|
||||||
|
return getAllocatedBytes() - getDeallocatedBytes();
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] allocation_data_t start_measurement() const
|
||||||
|
{
|
||||||
|
allocation_data_t data{};
|
||||||
|
data.start_allocations = allocations;
|
||||||
|
data.start_deallocations = deallocations;
|
||||||
|
data.start_allocated_bytes = allocated_bytes;
|
||||||
|
data.start_deallocated_bytes = deallocated_bytes;
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
void stop_measurement(allocation_data_t& data) const
|
||||||
|
{
|
||||||
|
data.end_allocations = allocations;
|
||||||
|
data.end_deallocations = deallocations;
|
||||||
|
data.end_allocated_bytes = allocated_bytes;
|
||||||
|
data.end_deallocated_bytes = deallocated_bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::atomic_uint64_t allocations = 0;
|
||||||
|
std::atomic_uint64_t deallocations = 0;
|
||||||
|
std::atomic_uint64_t allocated_bytes = 0;
|
||||||
|
std::atomic_uint64_t deallocated_bytes = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline allocation_tracker_t tracker;
|
||||||
|
|
||||||
|
class aligned_allocator
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void* allocate(blt::size_t bytes) // NOLINT
|
||||||
|
{
|
||||||
|
#ifdef BLT_TRACK_ALLOCATIONS
|
||||||
|
tracker.allocate(bytes);
|
||||||
|
#endif
|
||||||
|
return std::aligned_alloc(8, bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
void deallocate(void* ptr, blt::size_t bytes) // NOLINT
|
||||||
|
{
|
||||||
|
if (ptr == nullptr)
|
||||||
|
return;
|
||||||
|
#ifdef BLT_TRACK_ALLOCATIONS
|
||||||
|
tracker.deallocate(bytes);
|
||||||
|
#else
|
||||||
|
(void) bytes;
|
||||||
|
#endif
|
||||||
|
std::free(ptr);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
class stack_allocator
|
class stack_allocator
|
||||||
{
|
{
|
||||||
constexpr static blt::size_t PAGE_SIZE = 0x100;
|
constexpr static blt::size_t PAGE_SIZE = 0x100;
|
||||||
|
|
|
@ -1,134 +0,0 @@
|
||||||
#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_STATS_H
|
|
||||||
#define BLT_GP_STATS_H
|
|
||||||
|
|
||||||
#include <blt/std/types.h>
|
|
||||||
#include <atomic>
|
|
||||||
#include <cmath>
|
|
||||||
|
|
||||||
namespace blt::gp
|
|
||||||
{
|
|
||||||
|
|
||||||
class allocation_tracker_t
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
struct allocation_data_t
|
|
||||||
{
|
|
||||||
blt::u64 start_allocations = 0;
|
|
||||||
blt::u64 start_deallocations = 0;
|
|
||||||
blt::u64 start_allocated_bytes = 0;
|
|
||||||
blt::u64 start_deallocated_bytes = 0;
|
|
||||||
|
|
||||||
blt::u64 end_allocations = 0;
|
|
||||||
blt::u64 end_deallocations = 0;
|
|
||||||
blt::u64 end_allocated_bytes = 0;
|
|
||||||
blt::u64 end_deallocated_bytes = 0;
|
|
||||||
|
|
||||||
[[nodiscard]] blt::u64 getAllocationDifference() const
|
|
||||||
{
|
|
||||||
return end_allocations - start_allocations;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] blt::u64 getDeallocationDifference() const
|
|
||||||
{
|
|
||||||
return end_deallocations - start_deallocations;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] blt::u64 getAllocatedByteDifference() const
|
|
||||||
{
|
|
||||||
return end_allocated_bytes - start_allocated_bytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] blt::u64 getDeallocatedByteDifference() const
|
|
||||||
{
|
|
||||||
return end_deallocated_bytes - start_deallocated_bytes;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
void allocate(blt::size_t bytes)
|
|
||||||
{
|
|
||||||
allocations++;
|
|
||||||
allocated_bytes += bytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
void deallocate(blt::size_t bytes)
|
|
||||||
{
|
|
||||||
deallocations++;
|
|
||||||
deallocated_bytes += bytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] blt::u64 getAllocations() const
|
|
||||||
{
|
|
||||||
return allocations;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] blt::u64 getDeallocations() const
|
|
||||||
{
|
|
||||||
return deallocations;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] blt::u64 getAllocatedBytes() const
|
|
||||||
{
|
|
||||||
return allocated_bytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] blt::u64 getDeallocatedBytes() const
|
|
||||||
{
|
|
||||||
return deallocated_bytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] blt::u64 getAllocationDifference() const
|
|
||||||
{
|
|
||||||
return std::abs(static_cast<blt::i64>(getAllocations()) - static_cast<blt::i64>(getDeallocations()));
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] blt::u64 getCurrentlyAllocatedBytes() const
|
|
||||||
{
|
|
||||||
return getAllocatedBytes() - getDeallocatedBytes();
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] allocation_data_t start_measurement() const
|
|
||||||
{
|
|
||||||
allocation_data_t data{};
|
|
||||||
data.start_allocations = allocations;
|
|
||||||
data.start_deallocations = deallocations;
|
|
||||||
data.start_allocated_bytes = allocated_bytes;
|
|
||||||
data.start_deallocated_bytes = deallocated_bytes;
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
void stop_measurement(allocation_data_t& data) const
|
|
||||||
{
|
|
||||||
data.end_allocations = allocations;
|
|
||||||
data.end_deallocations = deallocations;
|
|
||||||
data.end_allocated_bytes = allocated_bytes;
|
|
||||||
data.end_deallocated_bytes = deallocated_bytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::atomic_uint64_t allocations = 0;
|
|
||||||
std::atomic_uint64_t deallocations = 0;
|
|
||||||
std::atomic_uint64_t allocated_bytes = 0;
|
|
||||||
std::atomic_uint64_t deallocated_bytes = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif //BLT_GP_STATS_H
|
|
|
@ -29,6 +29,8 @@ namespace blt::gp
|
||||||
{
|
{
|
||||||
namespace detail
|
namespace detail
|
||||||
{
|
{
|
||||||
|
using op_iter = std::vector<blt::gp::op_container_t>::iterator;
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
inline static constexpr double sum(const T& array)
|
inline static constexpr double sum(const T& array)
|
||||||
{
|
{
|
||||||
|
|
|
@ -53,6 +53,7 @@ namespace blt::gp
|
||||||
|
|
||||||
class tree_t
|
class tree_t
|
||||||
{
|
{
|
||||||
|
using iter_type = std::vector<op_container_t>::const_iterator;
|
||||||
public:
|
public:
|
||||||
explicit tree_t(gp_program& program);
|
explicit tree_t(gp_program& program);
|
||||||
|
|
||||||
|
@ -65,12 +66,12 @@ namespace blt::gp
|
||||||
blt::ptrdiff_t end;
|
blt::ptrdiff_t end;
|
||||||
};
|
};
|
||||||
|
|
||||||
[[nodiscard]] inline tracked_vector<op_container_t>& get_operations()
|
[[nodiscard]] inline std::vector<op_container_t>& get_operations()
|
||||||
{
|
{
|
||||||
return operations;
|
return operations;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] inline const tracked_vector<op_container_t>& get_operations() const
|
[[nodiscard]] inline const std::vector<op_container_t>& get_operations() const
|
||||||
{
|
{
|
||||||
return operations;
|
return operations;
|
||||||
}
|
}
|
||||||
|
@ -132,7 +133,7 @@ namespace blt::gp
|
||||||
blt::ptrdiff_t find_parent(blt::gp::gp_program& program, blt::ptrdiff_t start) const;
|
blt::ptrdiff_t find_parent(blt::gp::gp_program& program, blt::ptrdiff_t start) const;
|
||||||
|
|
||||||
// valid for [begin, end)
|
// valid for [begin, end)
|
||||||
static blt::size_t total_value_bytes(detail::const_op_iter_t begin, detail::const_op_iter_t end)
|
static blt::size_t total_value_bytes(iter_type begin, iter_type end)
|
||||||
{
|
{
|
||||||
blt::size_t total = 0;
|
blt::size_t total = 0;
|
||||||
for (auto it = begin; it != end; it++)
|
for (auto it = begin; it != end; it++)
|
||||||
|
@ -160,7 +161,7 @@ namespace blt::gp
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
tracked_vector<op_container_t> operations;
|
std::vector<op_container_t> operations;
|
||||||
blt::gp::stack_allocator values;
|
blt::gp::stack_allocator values;
|
||||||
detail::eval_func_t* func;
|
detail::eval_func_t* func;
|
||||||
};
|
};
|
||||||
|
@ -173,41 +174,30 @@ namespace blt::gp
|
||||||
blt::i64 hits = 0;
|
blt::i64 hits = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct individual_t
|
struct individual
|
||||||
{
|
{
|
||||||
tree_t tree;
|
tree_t tree;
|
||||||
fitness_t fitness;
|
fitness_t fitness;
|
||||||
|
|
||||||
individual_t() = delete;
|
individual() = default;
|
||||||
|
|
||||||
explicit individual_t(tree_t&& tree): tree(std::move(tree))
|
explicit individual(tree_t&& tree): tree(std::move(tree))
|
||||||
{}
|
{}
|
||||||
|
|
||||||
explicit individual_t(const tree_t& tree): tree(tree)
|
explicit individual(const tree_t& tree): tree(tree)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
individual_t(const individual_t&) = default;
|
individual(const individual&) = default;
|
||||||
|
|
||||||
individual_t(individual_t&&) = default;
|
individual(individual&&) = default;
|
||||||
|
|
||||||
individual_t& operator=(const individual_t&) = delete;
|
individual& operator=(const individual&) = delete;
|
||||||
|
|
||||||
individual_t& operator=(individual_t&&) = default;
|
individual& operator=(individual&&) = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct population_stats
|
struct population_stats
|
||||||
{
|
{
|
||||||
population_stats() = default;
|
|
||||||
|
|
||||||
population_stats(const population_stats& copy):
|
|
||||||
overall_fitness(copy.overall_fitness.load()), average_fitness(copy.average_fitness.load()), best_fitness(copy.best_fitness.load()),
|
|
||||||
worst_fitness(copy.worst_fitness.load())
|
|
||||||
{
|
|
||||||
normalized_fitness.reserve(copy.normalized_fitness.size());
|
|
||||||
for (auto v : copy.normalized_fitness)
|
|
||||||
normalized_fitness.push_back(v);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::atomic<double> overall_fitness = 0;
|
std::atomic<double> overall_fitness = 0;
|
||||||
std::atomic<double> average_fitness = 0;
|
std::atomic<double> average_fitness = 0;
|
||||||
std::atomic<double> best_fitness = 0;
|
std::atomic<double> best_fitness = 0;
|
||||||
|
@ -230,7 +220,7 @@ namespace blt::gp
|
||||||
class population_tree_iterator
|
class population_tree_iterator
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
population_tree_iterator(tracked_vector<individual_t>& ind, blt::size_t pos): ind(ind), pos(pos)
|
population_tree_iterator(std::vector<individual>& ind, blt::size_t pos): ind(ind), pos(pos)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
auto begin()
|
auto begin()
|
||||||
|
@ -275,11 +265,11 @@ namespace blt::gp
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
tracked_vector<individual_t>& ind;
|
std::vector<individual>& ind;
|
||||||
blt::size_t pos;
|
blt::size_t pos;
|
||||||
};
|
};
|
||||||
|
|
||||||
tracked_vector<individual_t>& get_individuals()
|
std::vector<individual>& get_individuals()
|
||||||
{
|
{
|
||||||
return individuals;
|
return individuals;
|
||||||
}
|
}
|
||||||
|
@ -325,7 +315,7 @@ namespace blt::gp
|
||||||
population_t& operator=(population_t&&) = default;
|
population_t& operator=(population_t&&) = default;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
tracked_vector<individual_t> individuals;
|
std::vector<individual> individuals;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -85,13 +85,12 @@ namespace blt::gp
|
||||||
type_provider() = default;
|
type_provider() = default;
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
inline void register_type()
|
inline type register_type()
|
||||||
{
|
{
|
||||||
if (has_type<T>())
|
|
||||||
return;
|
|
||||||
auto t = type::make_type<T>(types.size());
|
auto t = type::make_type<T>(types.size());
|
||||||
types.insert({blt::type_string_raw<T>(), t});
|
types.insert({blt::type_string_raw<T>(), t});
|
||||||
types_from_id[t.id()] = t;
|
types_from_id[t.id()] = t;
|
||||||
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
|
@ -100,11 +99,6 @@ namespace blt::gp
|
||||||
return types[blt::type_string_raw<T>()];
|
return types[blt::type_string_raw<T>()];
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
inline bool has_type(){
|
|
||||||
return types.find(blt::type_string_raw<T>()) != types.end();
|
|
||||||
}
|
|
||||||
|
|
||||||
inline type get_type(type_id id)
|
inline type get_type(type_id id)
|
||||||
{
|
{
|
||||||
return types_from_id[id];
|
return types_from_id[id];
|
||||||
|
|
2
lib/blt
2
lib/blt
|
@ -1 +1 @@
|
||||||
Subproject commit 79e080cfd34fb47342f67f19b95ffa27efb0f715
|
Subproject commit 6632d045286b42d257eb3783e96256c13b588186
|
|
@ -64,10 +64,10 @@ namespace blt::gp
|
||||||
tree.get_operations().emplace_back(
|
tree.get_operations().emplace_back(
|
||||||
args.program.get_typesystem().get_type(info.return_type).size(),
|
args.program.get_typesystem().get_type(info.return_type).size(),
|
||||||
top.id,
|
top.id,
|
||||||
args.program.is_operator_ephemeral(top.id));
|
args.program.is_static(top.id));
|
||||||
max_depth = std::max(max_depth, top.depth);
|
max_depth = std::max(max_depth, top.depth);
|
||||||
|
|
||||||
if (args.program.is_operator_ephemeral(top.id))
|
if (args.program.is_static(top.id))
|
||||||
{
|
{
|
||||||
info.func(nullptr, tree.get_values(), tree.get_values());
|
info.func(nullptr, tree.get_values(), tree.get_values());
|
||||||
continue;
|
continue;
|
||||||
|
|
|
@ -46,7 +46,7 @@ namespace blt::gp
|
||||||
|
|
||||||
random_t& gp_program::get_random() const
|
random_t& gp_program::get_random() const
|
||||||
{
|
{
|
||||||
thread_local static blt::gp::random_t random_engine{seed_func()};
|
thread_local static blt::gp::random_t random_engine{seed};
|
||||||
return random_engine;
|
return random_engine;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -76,7 +76,7 @@ namespace blt::gp
|
||||||
if (should_thread_terminate())
|
if (should_thread_terminate())
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
execution_function = thread_execution_service.get();
|
execution_function = thread_execution_service.load(std::memory_order_acquire);
|
||||||
}
|
}
|
||||||
if (execution_function != nullptr)
|
if (execution_function != nullptr)
|
||||||
(*execution_function)(i);
|
(*execution_function)(i);
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
namespace blt::gp
|
namespace blt::gp
|
||||||
{
|
{
|
||||||
|
|
||||||
tree_t& select_best_t::select(gp_program&, population_t& pop)
|
tree_t& select_best_t::select(gp_program&, population_t& pop, population_stats&)
|
||||||
{
|
{
|
||||||
auto& first = pop.get_individuals()[0];
|
auto& first = pop.get_individuals()[0];
|
||||||
double best_fitness = first.fitness.adjusted_fitness;
|
double best_fitness = first.fitness.adjusted_fitness;
|
||||||
|
@ -37,7 +37,7 @@ namespace blt::gp
|
||||||
return *tree;
|
return *tree;
|
||||||
}
|
}
|
||||||
|
|
||||||
tree_t& select_worst_t::select(gp_program&, population_t& pop)
|
tree_t& select_worst_t::select(gp_program&, population_t& pop, population_stats&)
|
||||||
{
|
{
|
||||||
auto& first = pop.get_individuals()[0];
|
auto& first = pop.get_individuals()[0];
|
||||||
double worst_fitness = first.fitness.adjusted_fitness;
|
double worst_fitness = first.fitness.adjusted_fitness;
|
||||||
|
@ -53,27 +53,32 @@ namespace blt::gp
|
||||||
return *tree;
|
return *tree;
|
||||||
}
|
}
|
||||||
|
|
||||||
tree_t& select_random_t::select(gp_program& program, population_t& pop)
|
tree_t& select_random_t::select(gp_program& program, population_t& pop, population_stats&)
|
||||||
{
|
{
|
||||||
return pop.get_individuals()[program.get_random().get_size_t(0ul, pop.get_individuals().size())].tree;
|
return pop.get_individuals()[program.get_random().get_size_t(0ul, pop.get_individuals().size())].tree;
|
||||||
}
|
}
|
||||||
|
|
||||||
tree_t& select_tournament_t::select(gp_program& program, population_t& pop)
|
tree_t& select_tournament_t::select(gp_program& program, population_t& pop, population_stats&)
|
||||||
{
|
{
|
||||||
blt::u64 best = program.get_random().get_u64(0, pop.get_individuals().size());
|
|
||||||
auto& i_ref = pop.get_individuals();
|
auto& first = pop.get_individuals()[program.get_random().get_size_t(0ul, pop.get_individuals().size())];
|
||||||
for (blt::size_t i = 0; i < selection_size; i++)
|
individual* ind = &first;
|
||||||
|
double best_guy = first.fitness.adjusted_fitness;
|
||||||
|
for (blt::size_t i = 0; i < selection_size - 1; i++)
|
||||||
{
|
{
|
||||||
auto sel_point = program.get_random().get_u64(0ul, pop.get_individuals().size());
|
auto& sel = pop.get_individuals()[program.get_random().get_size_t(0ul, pop.get_individuals().size())];
|
||||||
if (i_ref[sel_point].fitness.adjusted_fitness > i_ref[best].fitness.adjusted_fitness)
|
if (sel.fitness.adjusted_fitness > best_guy)
|
||||||
best = sel_point;
|
{
|
||||||
|
best_guy = sel.fitness.adjusted_fitness;
|
||||||
|
ind = &sel;
|
||||||
}
|
}
|
||||||
return i_ref[best].tree;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
tree_t& select_fitness_proportionate_t::select(gp_program& program, population_t& pop)
|
return ind->tree;
|
||||||
|
}
|
||||||
|
|
||||||
|
tree_t& select_fitness_proportionate_t::select(gp_program& program, population_t& pop, population_stats& stats)
|
||||||
{
|
{
|
||||||
auto& stats = program.get_population_stats();
|
|
||||||
auto choice = program.get_random().get_double();
|
auto choice = program.get_random().get_double();
|
||||||
for (const auto& [index, ref] : blt::enumerate(pop))
|
for (const auto& [index, ref] : blt::enumerate(pop))
|
||||||
{
|
{
|
||||||
|
@ -87,8 +92,20 @@ namespace blt::gp
|
||||||
return ref.tree;
|
return ref.tree;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
BLT_WARN("Unable to find individual_t with fitness proportionate. This should not be a possible code path! (%lf)", choice);
|
BLT_WARN("Unable to find individual with fitness proportionate. This should not be a possible code path! (%lf)", choice);
|
||||||
return pop.get_individuals()[0].tree;
|
return pop.get_individuals()[0].tree;
|
||||||
//BLT_ABORT("Unable to find individual");
|
//BLT_ABORT("Unable to find individual");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void select_fitness_proportionate_t::pre_process(gp_program&, population_t& pop, population_stats& stats)
|
||||||
|
{
|
||||||
|
stats.normalized_fitness.clear();
|
||||||
|
double sum_of_prob = 0;
|
||||||
|
for (auto& ind : pop)
|
||||||
|
{
|
||||||
|
auto prob = (ind.fitness.adjusted_fitness / stats.overall_fitness);
|
||||||
|
stats.normalized_fitness.push_back(sum_of_prob + prob);
|
||||||
|
sum_of_prob += prob;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -1,24 +0,0 @@
|
||||||
/*
|
|
||||||
* <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/stats.h>
|
|
||||||
#include <blt/std/logging.h>
|
|
||||||
|
|
||||||
namespace blt::gp
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
|
@ -36,7 +36,7 @@ namespace blt::gp
|
||||||
return new_tree;
|
return new_tree;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline blt::size_t accumulate_type_sizes(detail::op_iter_t begin, detail::op_iter_t end)
|
inline blt::size_t accumulate_type_sizes(detail::op_iter begin, detail::op_iter end)
|
||||||
{
|
{
|
||||||
blt::size_t total = 0;
|
blt::size_t total = 0;
|
||||||
for (auto it = begin; it != end; ++it)
|
for (auto it = begin; it != end; ++it)
|
||||||
|
@ -468,7 +468,7 @@ namespace blt::gp
|
||||||
}
|
}
|
||||||
// now finally update the type.
|
// now finally update the type.
|
||||||
ops[c_node] = {program.get_typesystem().get_type(replacement_func_info.return_type).size(), random_replacement,
|
ops[c_node] = {program.get_typesystem().get_type(replacement_func_info.return_type).size(), random_replacement,
|
||||||
program.is_operator_ephemeral(random_replacement)};
|
program.is_static(random_replacement)};
|
||||||
}
|
}
|
||||||
#if BLT_DEBUG_LEVEL >= 2
|
#if BLT_DEBUG_LEVEL >= 2
|
||||||
if (!c.check(program, nullptr))
|
if (!c.check(program, nullptr))
|
||||||
|
@ -556,7 +556,7 @@ namespace blt::gp
|
||||||
|
|
||||||
ops.insert(ops.begin() + static_cast<blt::ptrdiff_t>(c_node),
|
ops.insert(ops.begin() + static_cast<blt::ptrdiff_t>(c_node),
|
||||||
{program.get_typesystem().get_type(replacement_func_info.return_type).size(),
|
{program.get_typesystem().get_type(replacement_func_info.return_type).size(),
|
||||||
random_replacement, program.is_operator_ephemeral(random_replacement)});
|
random_replacement, program.is_static(random_replacement)});
|
||||||
|
|
||||||
#if BLT_DEBUG_LEVEL >= 2
|
#if BLT_DEBUG_LEVEL >= 2
|
||||||
if (!c.check(program, nullptr))
|
if (!c.check(program, nullptr))
|
||||||
|
|
|
@ -92,7 +92,7 @@ namespace blt::gp
|
||||||
if (print_literals)
|
if (print_literals)
|
||||||
{
|
{
|
||||||
create_indent(out, indent, pretty_print);
|
create_indent(out, indent, pretty_print);
|
||||||
if (program.is_operator_ephemeral(v.id))
|
if (program.is_static(v.id))
|
||||||
{
|
{
|
||||||
program.get_print_func(v.id)(out, reversed);
|
program.get_print_func(v.id)(out, reversed);
|
||||||
reversed.pop_bytes(stack_allocator::aligned_size(v.type_size));
|
reversed.pop_bytes(stack_allocator::aligned_size(v.type_size));
|
||||||
|
|
|
@ -107,7 +107,7 @@ struct context
|
||||||
float x, y;
|
float x, y;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::array<context, 200> training_cases;
|
std::array<context, 200> fitness_cases;
|
||||||
|
|
||||||
blt::gp::prog_config_t config = blt::gp::prog_config_t()
|
blt::gp::prog_config_t config = blt::gp::prog_config_t()
|
||||||
.set_initial_min_tree_size(2)
|
.set_initial_min_tree_size(2)
|
||||||
|
@ -141,7 +141,7 @@ blt::gp::operation_t op_x([](const context& context) {
|
||||||
|
|
||||||
constexpr auto fitness_function = [](blt::gp::tree_t& current_tree, blt::gp::fitness_t& fitness, blt::size_t) {
|
constexpr auto fitness_function = [](blt::gp::tree_t& current_tree, blt::gp::fitness_t& fitness, blt::size_t) {
|
||||||
constexpr double value_cutoff = 1.e15;
|
constexpr double value_cutoff = 1.e15;
|
||||||
for (auto& fitness_case : training_cases)
|
for (auto& fitness_case : fitness_cases)
|
||||||
{
|
{
|
||||||
auto ctx = current_tree.evaluate(&fitness_case);
|
auto ctx = current_tree.evaluate(&fitness_case);
|
||||||
auto diff = std::abs(fitness_case.y - *current_tree.get_evaluation_ref<move_float>(ctx));
|
auto diff = std::abs(fitness_case.y - *current_tree.get_evaluation_ref<move_float>(ctx));
|
||||||
|
@ -157,7 +157,7 @@ constexpr auto fitness_function = [](blt::gp::tree_t& current_tree, blt::gp::fit
|
||||||
}
|
}
|
||||||
fitness.standardized_fitness = fitness.raw_fitness;
|
fitness.standardized_fitness = fitness.raw_fitness;
|
||||||
fitness.adjusted_fitness = (1.0 / (1.0 + fitness.standardized_fitness));
|
fitness.adjusted_fitness = (1.0 / (1.0 + fitness.standardized_fitness));
|
||||||
return static_cast<blt::size_t>(fitness.hits) == training_cases.size();
|
return static_cast<blt::size_t>(fitness.hits) == fitness_cases.size();
|
||||||
};
|
};
|
||||||
|
|
||||||
float example_function(float x)
|
float example_function(float x)
|
||||||
|
@ -170,7 +170,7 @@ int main()
|
||||||
BLT_INFO("Starting BLT-GP Symbolic Regression Example");
|
BLT_INFO("Starting BLT-GP Symbolic Regression Example");
|
||||||
BLT_START_INTERVAL("Symbolic Regression", "Main");
|
BLT_START_INTERVAL("Symbolic Regression", "Main");
|
||||||
BLT_DEBUG("Setup Fitness cases");
|
BLT_DEBUG("Setup Fitness cases");
|
||||||
for (auto& fitness_case : training_cases)
|
for (auto& fitness_case : fitness_cases)
|
||||||
{
|
{
|
||||||
constexpr float range = 10;
|
constexpr float range = 10;
|
||||||
constexpr float half_range = range / 2.0;
|
constexpr float half_range = range / 2.0;
|
||||||
|
|
Loading…
Reference in New Issue