rice broken
parent
c6a2b5d324
commit
946ddcc572
|
@ -479,5 +479,26 @@
|
|||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=StringLiteralTypo/@EntryIndexRemoved" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CommentTypo/@EntryIndexRemoved" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=IdentifierTypo/@EntryIndexRemoved" />
|
||||
<option name="/Default/CodeStyle/Generate/=CppGettersAndSetters/@KeyIndexDefined" value="true" type="bool" />
|
||||
<option name="/Default/CodeStyle/Generate/=CppGettersAndSetters/Options/=AccessRight/@EntryIndexedValue" value="public" type="string" />
|
||||
<option name="/Default/CodeStyle/Generate/=CppGettersAndSetters/Options/=AccessRight/@EntryIndexRemoved" />
|
||||
<option name="/Default/CodeStyle/Generate/=CppGettersAndSetters/Options/=GetterAndSetterKind/@EntryIndexedValue" value="Getter" type="string" />
|
||||
<option name="/Default/CodeStyle/Generate/=CppGettersAndSetters/Options/=GetterAndSetterKind/@EntryIndexRemoved" />
|
||||
<option name="/Default/CodeStyle/Generate/=CppGettersAndSetters/Options/=AcceptParameterKind/@EntryIndexedValue" value="Value and copy into field" type="string" />
|
||||
<option name="/Default/CodeStyle/Generate/=CppGettersAndSetters/Options/=AcceptParameterKind/@EntryIndexRemoved" />
|
||||
<option name="/Default/CodeStyle/Generate/=CppGettersAndSetters/Options/=ReturnKind/@EntryIndexedValue" value="Value" type="string" />
|
||||
<option name="/Default/CodeStyle/Generate/=CppGettersAndSetters/Options/=ReturnKind/@EntryIndexRemoved" />
|
||||
<option name="/Default/CodeStyle/Generate/=CppGettersAndSetters/Options/=InlineDefinition/@EntryIndexedValue" value="True" type="string" />
|
||||
<option name="/Default/CodeStyle/Generate/=CppGettersAndSetters/Options/=InlineDefinition/@EntryIndexRemoved" />
|
||||
<option name="/Default/CodeStyle/Generate/=CppGettersAndSetters/Options/=InsertVirtualSpecifier/@EntryIndexedValue" value="False" type="string" />
|
||||
<option name="/Default/CodeStyle/Generate/=CppGettersAndSetters/Options/=InsertVirtualSpecifier/@EntryIndexRemoved" />
|
||||
<option name="/Default/CodeStyle/Generate/=CppGettersAndSetters/Options/=UseConstParameterTypes/@EntryIndexedValue" value="True" type="string" />
|
||||
<option name="/Default/CodeStyle/Generate/=CppGettersAndSetters/Options/=UseConstParameterTypes/@EntryIndexRemoved" />
|
||||
<option name="/Default/CodeStyle/Generate/=CppGettersAndSetters/Options/=AddPrefixesToGetters/@EntryIndexedValue" value="True" type="string" />
|
||||
<option name="/Default/CodeStyle/Generate/=CppGettersAndSetters/Options/=AddPrefixesToGetters/@EntryIndexRemoved" />
|
||||
<option name="/Default/CodeStyle/Generate/=CppGettersAndSetters/Options/=AddPrefixesToSetters/@EntryIndexedValue" value="True" type="string" />
|
||||
<option name="/Default/CodeStyle/Generate/=CppGettersAndSetters/Options/=AddPrefixesToSetters/@EntryIndexRemoved" />
|
||||
<option name="/Default/CodeStyle/Generate/=CppGettersAndSetters/Options/=DeclareGettersNodiscard/@EntryIndexedValue" value="True" type="string" />
|
||||
<option name="/Default/CodeStyle/Generate/=CppGettersAndSetters/Options/=DeclareGettersNodiscard/@EntryIndexRemoved" />
|
||||
</component>
|
||||
</project>
|
|
@ -27,29 +27,7 @@ macro(compile_options target_name)
|
|||
sanitizers(${target_name})
|
||||
endmacro()
|
||||
|
||||
macro(blt_add_project name source type)
|
||||
|
||||
project(${name}-${type})
|
||||
|
||||
add_executable(${name}-${type} ${source})
|
||||
|
||||
target_link_libraries(${name}-${type} PRIVATE BLT blt-gp Threads::Threads)
|
||||
|
||||
compile_options(${name}-${type})
|
||||
target_compile_definitions(${name}-${type} PRIVATE BLT_DEBUG_LEVEL=${DEBUG_LEVEL})
|
||||
|
||||
if (${TRACK_ALLOCATIONS})
|
||||
target_compile_definitions(${name}-${type} PRIVATE BLT_TRACK_ALLOCATIONS=1)
|
||||
endif ()
|
||||
|
||||
add_test(NAME ${name} COMMAND ${name}-${type})
|
||||
|
||||
set_property(TEST ${name} PROPERTY FAIL_REGULAR_EXPRESSION "FAIL;ERROR;FATAL;exception")
|
||||
|
||||
project(blt-gp)
|
||||
endmacro()
|
||||
|
||||
project(blt-gp VERSION 0.2.2)
|
||||
project(blt-gp VERSION 0.2.3)
|
||||
|
||||
include(CTest)
|
||||
|
||||
|
@ -94,6 +72,28 @@ if (${TRACK_ALLOCATIONS})
|
|||
target_compile_definitions(blt-gp PRIVATE BLT_TRACK_ALLOCATIONS=1)
|
||||
endif ()
|
||||
|
||||
macro(blt_add_project name source type)
|
||||
|
||||
project(${name}-${type})
|
||||
|
||||
add_executable(${name}-${type} ${source})
|
||||
|
||||
target_link_libraries(${name}-${type} PRIVATE BLT blt-gp Threads::Threads)
|
||||
|
||||
compile_options(${name}-${type})
|
||||
target_compile_definitions(${name}-${type} PRIVATE BLT_DEBUG_LEVEL=${DEBUG_LEVEL})
|
||||
|
||||
if (${TRACK_ALLOCATIONS})
|
||||
target_compile_definitions(${name}-${type} PRIVATE BLT_TRACK_ALLOCATIONS=1)
|
||||
endif ()
|
||||
|
||||
add_test(NAME ${name} COMMAND ${name}-${type})
|
||||
|
||||
set_property(TEST ${name} PROPERTY FAIL_REGULAR_EXPRESSION "FAIL;ERROR;FATAL;exception")
|
||||
|
||||
project(blt-gp)
|
||||
endmacro()
|
||||
|
||||
if (${BUILD_EXAMPLES})
|
||||
|
||||
blt_add_project(blt-symbolic-regression examples/src/symbolic_regression.cpp example)
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
#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_EXAMPLESEXAMPLES_BASE_H
|
||||
#define BLT_GP_EXAMPLESEXAMPLES_BASE_H
|
||||
|
||||
#include <blt/gp/program.h>
|
||||
|
||||
namespace blt::gp::example
|
||||
{
|
||||
class example_base_t
|
||||
{
|
||||
public:
|
||||
template<typename SEED>
|
||||
example_base_t(SEED&& seed, const prog_config_t& config): program{std::forward<SEED>(seed), config}
|
||||
{
|
||||
}
|
||||
|
||||
example_base_t& set_crossover_selection(selection_t& sel)
|
||||
{
|
||||
crossover_sel = &sel;
|
||||
return *this;
|
||||
}
|
||||
|
||||
example_base_t& set_mutation_selection(selection_t& sel)
|
||||
{
|
||||
mutation_sel = &sel;
|
||||
return *this;
|
||||
}
|
||||
|
||||
example_base_t& set_reproduction_selection(selection_t& sel)
|
||||
{
|
||||
reproduction_sel = &sel;
|
||||
return *this;
|
||||
}
|
||||
|
||||
protected:
|
||||
gp_program program;
|
||||
selection_t* crossover_sel = nullptr;
|
||||
selection_t* mutation_sel = nullptr;
|
||||
selection_t* reproduction_sel = nullptr;
|
||||
std::function<bool(const tree_t&, fitness_t&, size_t)> fitness_function_ref;
|
||||
};
|
||||
}
|
||||
|
||||
#endif //BLT_GP_EXAMPLESEXAMPLES_BASE_H
|
|
@ -0,0 +1,139 @@
|
|||
#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_EXAMPLES_RICE_CLASSIFICATION_H
|
||||
#define BLT_GP_EXAMPLES_RICE_CLASSIFICATION_H
|
||||
|
||||
#include "examples_base.h"
|
||||
|
||||
namespace blt::gp::example
|
||||
{
|
||||
class rice_classification_t : public example_base_t
|
||||
{
|
||||
private:
|
||||
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;
|
||||
};
|
||||
|
||||
void make_operators()
|
||||
{
|
||||
static operation_t add{[](const float a, const float b) { return a + b; }, "add"};
|
||||
static operation_t sub([](const float a, const float b) { return a - b; }, "sub");
|
||||
static operation_t mul([](const float a, const float b) { return a * b; }, "mul");
|
||||
static operation_t pro_div([](const float a, const float b) { return b == 0.0f ? 1.0f : a / b; }, "div");
|
||||
static operation_t op_sin([](const float a) { return std::sin(a); }, "sin");
|
||||
static operation_t op_cos([](const float a) { return std::cos(a); }, "cos");
|
||||
static operation_t op_exp([](const float a) { return std::exp(a); }, "exp");
|
||||
static operation_t op_log([](const float a) { return a == 0.0f ? 0.0f : std::log(a); }, "log");
|
||||
static auto lit = blt::gp::operation_t([]()
|
||||
{
|
||||
return program.get_random().get_float(-32000.0f, 32000.0f);
|
||||
}, "lit").set_ephemeral();
|
||||
|
||||
static operation_t op_area([](const rice_record& rice_data)
|
||||
{
|
||||
return rice_data.area;
|
||||
}, "area");
|
||||
|
||||
static operation_t op_perimeter([](const rice_record& rice_data)
|
||||
{
|
||||
return rice_data.perimeter;
|
||||
}, "perimeter");
|
||||
|
||||
static operation_t op_major_axis_length([](const rice_record& rice_data)
|
||||
{
|
||||
return rice_data.major_axis_length;
|
||||
}, "major_axis_length");
|
||||
|
||||
static operation_t op_minor_axis_length([](const rice_record& rice_data)
|
||||
{
|
||||
return rice_data.minor_axis_length;
|
||||
}, "minor_axis_length");
|
||||
|
||||
static operation_t op_eccentricity([](const rice_record& rice_data)
|
||||
{
|
||||
return rice_data.eccentricity;
|
||||
}, "eccentricity");
|
||||
|
||||
static operation_t op_convex_area([](const rice_record& rice_data)
|
||||
{
|
||||
return rice_data.convex_area;
|
||||
}, "convex_area");
|
||||
|
||||
static operation_t op_extent([](const rice_record& rice_data)
|
||||
{
|
||||
return rice_data.extent;
|
||||
}, "extent");
|
||||
}
|
||||
|
||||
bool fitness_function(const tree_t& current_tree, fitness_t& fitness, size_t) const
|
||||
{
|
||||
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<size_t>(fitness.hits) == training_cases.size();
|
||||
}
|
||||
|
||||
void load_rice_data(std::string_view rice_file_path);
|
||||
|
||||
public:
|
||||
template <typename SEED>
|
||||
rice_classification_t(SEED&& seed, const prog_config_t& config): example_base_t{std::forward<SEED>(seed), config}
|
||||
{
|
||||
fitness_function_ref = [this](const tree_t& t, fitness_t& f, const size_t i)
|
||||
{
|
||||
return fitness_function(t, f, i);
|
||||
};
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<rice_record> training_cases;
|
||||
std::vector<rice_record> testing_cases;
|
||||
};
|
||||
}
|
||||
|
||||
#endif //BLT_GP_EXAMPLES_RICE_CLASSIFICATION_H
|
|
@ -25,125 +25,51 @@
|
|||
#include <blt/format/format.h>
|
||||
#include <blt/parse/argparse.h>
|
||||
#include <iostream>
|
||||
#include "operations_common.h"
|
||||
#include "../rice_classification.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);
|
||||
.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(500)
|
||||
.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)
|
||||
void blt::gp::example::rice_classification_t::load_rice_data(std::string_view rice_file_path)
|
||||
{
|
||||
auto rice_file_data = blt::fs::getLinesFromFile(rice_file_path);
|
||||
auto rice_file_data = fs::getLinesFromFile(rice_file_path);
|
||||
size_t index = 0;
|
||||
while (!blt::string::contains(rice_file_data[index++], "@DATA"))
|
||||
{}
|
||||
while (!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))
|
||||
for (std::string_view v : iterate(rice_file_data).skip(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};
|
||||
auto data = 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]), 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;
|
||||
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);
|
||||
|
||||
size_t total_records = c.size() + o.size();
|
||||
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();
|
||||
|
@ -167,7 +93,7 @@ struct test_results_t
|
|||
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;
|
||||
|
@ -179,7 +105,7 @@ struct test_results_t
|
|||
percent_hit += a.percent_hit;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
test_results_t& operator/=(blt::size_t s)
|
||||
{
|
||||
cc /= s;
|
||||
|
@ -191,12 +117,12 @@ struct test_results_t
|
|||
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;
|
||||
|
@ -206,31 +132,31 @@ struct test_results_t
|
|||
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;
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -238,32 +164,32 @@ 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())
|
||||
{
|
||||
|
@ -287,22 +213,23 @@ int main(int argc, const char** argv)
|
|||
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) {
|
||||
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);
|
||||
|
@ -310,26 +237,26 @@ int main(int argc, const char** argv)
|
|||
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)
|
||||
|
@ -341,13 +268,13 @@ int main(int argc, const char** argv)
|
|||
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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,25 +17,47 @@
|
|||
*/
|
||||
#include "../symbolic_regression.h"
|
||||
|
||||
static const unsigned long SEED = std::random_device()();
|
||||
// you can either use a straight numeric seed, or provide a function which produces a u64 output which will initialize the thread local random number generators.
|
||||
static const auto SEED_FUNC = [] { return std::random_device()(); };
|
||||
|
||||
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.0)
|
||||
.set_reproduction_chance(0.25)
|
||||
.set_max_generations(50)
|
||||
.set_pop_size(500)
|
||||
.set_thread_count(0);
|
||||
blt::gp::grow_generator_t grow_generator;
|
||||
blt::gp::full_generator_t full_generator;
|
||||
|
||||
blt::gp::ramped_half_initializer_t ramped_half_initializer;
|
||||
blt::gp::full_initializer_t full_initializer;
|
||||
|
||||
int main()
|
||||
{
|
||||
blt::gp::example::symbolic_regression_t regression{config, SEED};
|
||||
// config options can be chained together to form compound statements.
|
||||
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.25)
|
||||
.set_max_generations(50)
|
||||
.set_pop_size(500)
|
||||
.set_thread_count(16);
|
||||
|
||||
// example on how you can change the mutation config
|
||||
blt::gp::mutation_t::config_t mut_config{};
|
||||
mut_config.generator = full_generator;
|
||||
mut_config.replacement_min_depth = 2;
|
||||
mut_config.replacement_max_depth = 6;
|
||||
|
||||
blt::gp::advanced_mutation_t mut_adv{mut_config};
|
||||
blt::gp::mutation_t mut{mut_config};
|
||||
|
||||
// you can choose to set any type of system used by the GP. Mutation, Crossover, and Initializers
|
||||
// (config options changed do not affect others, so you can programmatically change them at runtime)
|
||||
config.set_initializer(ramped_half_initializer);
|
||||
config.set_mutation(mut_adv);
|
||||
|
||||
// the config is copied into the gp_system so changing the config will not change the runtime of the program.
|
||||
blt::gp::example::symbolic_regression_t regression{SEED_FUNC, config};
|
||||
|
||||
regression.execute();
|
||||
|
||||
BLT_TRACE("%lf vs %lf", blt::gp::parent_fitness.load(std::memory_order_relaxed), blt::gp::child_fitness.load(std::memory_order_relaxed));
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -19,15 +19,14 @@
|
|||
#ifndef BLT_GP_EXAMPLE_SYMBOLIC_REGRESSION_H
|
||||
#define BLT_GP_EXAMPLE_SYMBOLIC_REGRESSION_H
|
||||
|
||||
#include <blt/gp/program.h>
|
||||
#include <blt/gp/tree.h>
|
||||
#include "examples_base.h"
|
||||
#include <blt/std/logging.h>
|
||||
#include <blt/format/format.h>
|
||||
#include <iostream>
|
||||
|
||||
namespace blt::gp::example
|
||||
{
|
||||
class symbolic_regression_t
|
||||
class symbolic_regression_t : public example_base_t
|
||||
{
|
||||
public:
|
||||
struct context
|
||||
|
@ -62,7 +61,8 @@ namespace blt::gp::example
|
|||
}
|
||||
|
||||
public:
|
||||
symbolic_regression_t(const prog_config_t& config, const size_t seed): program{seed, config}
|
||||
template<typename SEED>
|
||||
symbolic_regression_t(SEED seed, const prog_config_t& config): example_base_t{std::forward<SEED>(seed), config}
|
||||
{
|
||||
BLT_INFO("Starting BLT-GP Symbolic Regression Example");
|
||||
BLT_DEBUG("Setup Fitness cases");
|
||||
|
@ -74,6 +74,11 @@ namespace blt::gp::example
|
|||
const auto y = example_function(x);
|
||||
fitness_case = {x, y};
|
||||
}
|
||||
|
||||
fitness_function_ref = [this](const tree_t& t, fitness_t& f, const size_t i)
|
||||
{
|
||||
return fitness_function(t, f, i);
|
||||
};
|
||||
}
|
||||
|
||||
template <typename Ctx>
|
||||
|
@ -100,23 +105,38 @@ namespace blt::gp::example
|
|||
return builder.build(add, sub, mul, pro_div, op_sin, op_cos, op_exp, op_log, lit, op_x);
|
||||
}
|
||||
|
||||
void execute()
|
||||
void setup_operations()
|
||||
{
|
||||
BLT_DEBUG("Setup Types and Operators");
|
||||
operator_builder<context> builder{};
|
||||
program.set_operations(make_operations(builder));
|
||||
make_operations(builder);
|
||||
program.set_operations(builder.grab());
|
||||
}
|
||||
|
||||
void generate_initial_population()
|
||||
{
|
||||
BLT_DEBUG("Generate Initial Population");
|
||||
auto sel = select_tournament_t{};
|
||||
auto fitness = [this](const tree_t& c, fitness_t& f, const size_t i) { return fitness_function(c, f, i); };
|
||||
program.generate_population(program.get_typesystem().get_type<float>().id(), fitness, sel, sel, sel);
|
||||
static auto sel = select_tournament_t{};
|
||||
if (crossover_sel == nullptr)
|
||||
crossover_sel = &sel;
|
||||
if (mutation_sel == nullptr)
|
||||
mutation_sel = &sel;
|
||||
if (reproduction_sel == nullptr)
|
||||
reproduction_sel = &sel;
|
||||
program.generate_population(program.get_typesystem().get_type<float>().id(), fitness_function_ref, *crossover_sel, *mutation_sel,
|
||||
*reproduction_sel);
|
||||
}
|
||||
|
||||
void run_generation_loop()
|
||||
{
|
||||
BLT_DEBUG("Begin Generation Loop");
|
||||
while (!program.should_terminate())
|
||||
{
|
||||
#ifdef BLT_TRACK_ALLOCATIONS
|
||||
auto cross = crossover_calls.start_measurement();
|
||||
auto mut = mutation_calls.start_measurement();
|
||||
auto repo = reproduction_calls.start_measurement();
|
||||
#endif
|
||||
BLT_TRACE("------------{Begin Generation %ld}------------", program.get_current_generation());
|
||||
BLT_TRACE("Creating next generation");
|
||||
program.create_next_generation();
|
||||
|
@ -126,18 +146,23 @@ namespace blt::gp::example
|
|||
program.evaluate_fitness();
|
||||
const auto& stats = program.get_population_stats();
|
||||
BLT_TRACE("Avg Fit: %lf, Best Fit: %lf, Worst Fit: %lf, Overall Fit: %lf",
|
||||
stats.average_fitness.load(std::memory_order_relaxed), stats.best_fitness.load(std::memory_order_relaxed),
|
||||
stats.worst_fitness.load(std::memory_order_relaxed), stats.overall_fitness.load(std::memory_order_relaxed));
|
||||
stats.average_fitness.load(std::memory_order_relaxed), stats.best_fitness.load(std::memory_order_relaxed),
|
||||
stats.worst_fitness.load(std::memory_order_relaxed), stats.overall_fitness.load(std::memory_order_relaxed));
|
||||
#ifdef BLT_TRACK_ALLOCATIONS
|
||||
crossover_calls.stop_measurement(cross);
|
||||
mutation_calls.stop_measurement(mut);
|
||||
reproduction_calls.stop_measurement(repo);
|
||||
const auto total = (cross.get_call_difference() * 2) + mut.get_call_difference() + repo.get_call_difference();
|
||||
BLT_TRACE("Calls Crossover: %ld, Mutation %ld, Reproduction %ld; %ld", cross.get_call_difference(), mut.get_call_difference(), repo.get_call_difference(), total);
|
||||
BLT_TRACE("Value Crossover: %ld, Mutation %ld, Reproduction %ld; %ld", cross.get_value_difference(), mut.get_value_difference(), repo.get_value_difference(), (cross.get_value_difference() * 2 + mut.get_value_difference() + repo.get_value_difference()) - total);
|
||||
#endif
|
||||
BLT_TRACE("----------------------------------------------");
|
||||
std::cout << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
auto get_and_print_best()
|
||||
{
|
||||
const auto best = program.get_best_individuals<3>();
|
||||
|
||||
BLT_INFO("Best approximations:");
|
||||
|
@ -148,18 +173,35 @@ namespace blt::gp::example
|
|||
i.tree.print(program, std::cout);
|
||||
std::cout << "\n";
|
||||
}
|
||||
|
||||
return best;
|
||||
}
|
||||
|
||||
void print_stats() const
|
||||
{
|
||||
// TODO: make stats helper
|
||||
const auto& stats = program.get_population_stats();
|
||||
BLT_INFO("Stats:");
|
||||
BLT_INFO("Average fitness: %lf", stats.average_fitness.load());
|
||||
BLT_INFO("Best fitness: %lf", stats.best_fitness.load());
|
||||
BLT_INFO("Worst fitness: %lf", stats.worst_fitness.load());
|
||||
BLT_INFO("Overall fitness: %lf", stats.overall_fitness.load());
|
||||
// TODO: make stats helper
|
||||
}
|
||||
|
||||
void execute()
|
||||
{
|
||||
setup_operations();
|
||||
|
||||
generate_initial_population();
|
||||
|
||||
run_generation_loop();
|
||||
|
||||
get_and_print_best();
|
||||
|
||||
print_stats();
|
||||
}
|
||||
|
||||
private:
|
||||
gp_program program;
|
||||
mutation_t mut;
|
||||
std::array<context, 200> training_cases{};
|
||||
};
|
||||
}
|
||||
|
|
|
@ -20,9 +20,9 @@
|
|||
#define BLT_GP_ALLOCATOR_H
|
||||
|
||||
#include <blt/std/types.h>
|
||||
#include <blt/gp/stats.h>
|
||||
#include <blt/gp/fwdecl.h>
|
||||
#include <blt/gp/util/trackers.h>
|
||||
#include <cstdlib>
|
||||
#include <vector>
|
||||
|
||||
namespace blt::gp
|
||||
{
|
||||
|
@ -142,6 +142,14 @@ namespace blt::gp
|
|||
{
|
||||
return &lhs != &rhs;
|
||||
}
|
||||
|
||||
#ifdef BLT_TRACK_ALLOCATIONS
|
||||
template<typename T>
|
||||
using tracked_vector = std::vector<T, tracked_allocator_t<T>>;
|
||||
#else
|
||||
template<typename T>
|
||||
using tracked_vector = std::vector<T>;
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif //BLT_GP_ALLOCATOR_H
|
||||
|
|
|
@ -22,12 +22,12 @@
|
|||
#include <functional>
|
||||
#include <blt/std/logging.h>
|
||||
#include <blt/std/types.h>
|
||||
#include <blt/gp/stats.h>
|
||||
#include <ostream>
|
||||
#include <cstdlib>
|
||||
#include <mutex>
|
||||
#include <atomic>
|
||||
#include <blt/std/mmap.h>
|
||||
#include <blt/gp/util/trackers.h>
|
||||
#include <blt/gp/allocator.h>
|
||||
|
||||
namespace blt::gp
|
||||
|
@ -65,18 +65,6 @@ namespace blt::gp
|
|||
template<typename T>
|
||||
class tracked_allocator_t;
|
||||
|
||||
#ifdef BLT_TRACK_ALLOCATIONS
|
||||
template<typename T>
|
||||
using tracked_vector = std::vector<T, tracked_allocator_t<T>>;
|
||||
#else
|
||||
template<typename T>
|
||||
using tracked_vector = std::vector<T>;
|
||||
#endif
|
||||
|
||||
// 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>;
|
||||
|
||||
namespace detail
|
||||
{
|
||||
class operator_storage_test;
|
||||
|
|
|
@ -140,7 +140,7 @@ namespace blt::gp
|
|||
blt::size_t total_so_far = 0;
|
||||
blt::size_t op_pos = 0;
|
||||
|
||||
for (const auto& operation : blt::reverse_iterate(ops.begin(), ops.end()))
|
||||
for (const auto& operation : iterate(ops).rev())
|
||||
{
|
||||
op_pos++;
|
||||
if (operation.is_value)
|
||||
|
@ -157,19 +157,19 @@ namespace blt::gp
|
|||
|
||||
blt::hashset_t<type_id> has_terminals;
|
||||
|
||||
for (const auto& v : blt::enumerate(storage.terminals))
|
||||
for (const auto& [index, value] : blt::enumerate(storage.terminals))
|
||||
{
|
||||
if (!v.second.empty())
|
||||
has_terminals.insert(v.first);
|
||||
if (!value.empty())
|
||||
has_terminals.insert(index);
|
||||
}
|
||||
|
||||
for (const auto& op_r : blt::enumerate(storage.non_terminals))
|
||||
for (const auto& [index, value] : blt::enumerate(storage.non_terminals))
|
||||
{
|
||||
if (op_r.second.empty())
|
||||
if (value.empty())
|
||||
continue;
|
||||
auto return_type = op_r.first;
|
||||
auto return_type = index;
|
||||
tracked_vector<std::pair<operator_id, blt::size_t>> ordered_terminals;
|
||||
for (const auto& op : op_r.second)
|
||||
for (const auto& op : value)
|
||||
{
|
||||
// count number of terminals
|
||||
blt::size_t terminals = 0;
|
||||
|
@ -370,6 +370,11 @@ namespace blt::gp
|
|||
create_threads();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param seed_func Function which provides a new random seed every time it is called.
|
||||
* This will be used by each thread to initialize a new random number generator
|
||||
*/
|
||||
explicit gp_program(std::function<blt::u64()> seed_func): seed_func(std::move(seed_func))
|
||||
{
|
||||
create_threads();
|
||||
|
@ -765,8 +770,8 @@ namespace blt::gp
|
|||
tracked_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);
|
||||
for (const auto& [index, value] : blt::enumerate(current_pop.get_individuals()))
|
||||
values.emplace_back(index, value.fitness.adjusted_fitness);
|
||||
|
||||
std::sort(values.begin(), values.end(), [](const auto& a, const auto& b)
|
||||
{
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#define BLT_GP_SELECTION_H
|
||||
|
||||
#include <blt/gp/fwdecl.h>
|
||||
#include <blt/gp/util/statistics.h>
|
||||
#include <blt/gp/tree.h>
|
||||
#include <blt/gp/config.h>
|
||||
#include <blt/gp/random.h>
|
||||
|
@ -54,16 +55,16 @@ namespace blt::gp
|
|||
{
|
||||
for (blt::size_t i = 0; i < config.elites; i++)
|
||||
{
|
||||
if (ind.second.fitness.adjusted_fitness >= values[i].second)
|
||||
if (ind.value.fitness.adjusted_fitness >= values[i].second)
|
||||
{
|
||||
bool doesnt_contain = true;
|
||||
for (blt::size_t j = 0; j < config.elites; j++)
|
||||
{
|
||||
if (ind.first == values[j].first)
|
||||
if (ind.index == values[j].first)
|
||||
doesnt_contain = false;
|
||||
}
|
||||
if (doesnt_contain)
|
||||
values[i] = {ind.first, ind.second.fitness.adjusted_fitness};
|
||||
values[i] = {ind.index, ind.value.fitness.adjusted_fitness};
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -101,43 +102,45 @@ namespace blt::gp
|
|||
|
||||
const tree_t* p1;
|
||||
const tree_t* p2;
|
||||
double parent_val = 0;
|
||||
// double parent_val = 0;
|
||||
do
|
||||
{
|
||||
p1 = &crossover_selection.select(program, current_pop);
|
||||
p2 = &crossover_selection.select(program, current_pop);
|
||||
|
||||
fitness_t fitness1;
|
||||
fitness_t fitness2;
|
||||
test_fitness_func(*p1, fitness1, 0);
|
||||
test_fitness_func(*p2, fitness2, 0);
|
||||
parent_val = fitness1.adjusted_fitness + fitness2.adjusted_fitness;
|
||||
// fitness_t fitness1;
|
||||
// fitness_t fitness2;
|
||||
// test_fitness_func(*p1, fitness1, 0);
|
||||
// test_fitness_func(*p2, fitness2, 0);
|
||||
// parent_val = fitness1.adjusted_fitness + fitness2.adjusted_fitness;
|
||||
// BLT_TRACE("%ld> P1 Fit: %lf, P2 Fit: %lf", val, fitness1.adjusted_fitness, fitness2.adjusted_fitness);
|
||||
|
||||
c1.copy_fast(*p1);
|
||||
c2->copy_fast(*p2);
|
||||
|
||||
#ifdef BLT_TRACK_ALLOCATIONS
|
||||
crossover_calls.value(1);
|
||||
#endif
|
||||
}
|
||||
while (!config.crossover.get().apply(program, *p1, *p2, c1, *c2));
|
||||
fitness_t fitness1;
|
||||
fitness_t fitness2;
|
||||
test_fitness_func(c1, fitness1, 0);
|
||||
test_fitness_func(*c2, fitness2, 0);
|
||||
// fitness_t fitness1;
|
||||
// fitness_t fitness2;
|
||||
// test_fitness_func(c1, fitness1, 0);
|
||||
// test_fitness_func(*c2, fitness2, 0);
|
||||
|
||||
const auto child_val = fitness1.adjusted_fitness + fitness2.adjusted_fitness;
|
||||
// const auto child_val = fitness1.adjusted_fitness + fitness2.adjusted_fitness;
|
||||
|
||||
auto old_parent_val = parent_fitness.load(std::memory_order_relaxed);
|
||||
while (!parent_fitness.compare_exchange_weak(old_parent_val, old_parent_val + parent_val, std::memory_order_relaxed,
|
||||
std::memory_order_relaxed))
|
||||
{
|
||||
}
|
||||
// auto old_parent_val = parent_fitness.load(std::memory_order_relaxed);
|
||||
// while (!parent_fitness.compare_exchange_weak(old_parent_val, old_parent_val + parent_val, std::memory_order_relaxed,
|
||||
// std::memory_order_relaxed))
|
||||
// {
|
||||
// }
|
||||
|
||||
auto old_child_val = child_fitness.load(std::memory_order_relaxed);
|
||||
while (!child_fitness.compare_exchange_weak(old_child_val, old_child_val + child_val, std::memory_order_relaxed,
|
||||
std::memory_order_relaxed))
|
||||
{
|
||||
}
|
||||
// auto old_child_val = child_fitness.load(std::memory_order_relaxed);
|
||||
// while (!child_fitness.compare_exchange_weak(old_child_val, old_child_val + child_val, std::memory_order_relaxed,
|
||||
// std::memory_order_relaxed))
|
||||
// {
|
||||
// }
|
||||
|
||||
// BLT_TRACE("%ld> C1 Fit: %lf, C2 Fit: %lf", val, fitness1.adjusted_fitness, fitness2.adjusted_fitness);
|
||||
#ifdef BLT_TRACK_ALLOCATIONS
|
||||
|
@ -164,7 +167,9 @@ namespace blt::gp
|
|||
{
|
||||
p = &mutation_selection.select(program, current_pop);
|
||||
c1.copy_fast(*p);
|
||||
#ifdef BLT_TRACK_ALLOCATIONS
|
||||
mutation_calls.value(1);
|
||||
#endif
|
||||
}
|
||||
while (!config.mutator.get().apply(program, *p, c1));
|
||||
#ifdef BLT_TRACK_ALLOCATIONS
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
#include <blt/std/ranges.h>
|
||||
#include <blt/meta/meta.h>
|
||||
#include <blt/gp/fwdecl.h>
|
||||
#include <blt/gp/stats.h>
|
||||
#include <blt/gp/util/trackers.h>
|
||||
#include <utility>
|
||||
#include <stdexcept>
|
||||
#include <cstdlib>
|
||||
|
|
|
@ -246,45 +246,6 @@ namespace blt::gp
|
|||
individual_t& operator=(individual_t&&) = default;
|
||||
};
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
population_stats(population_stats&& move) noexcept:
|
||||
overall_fitness(move.overall_fitness.load()), average_fitness(move.average_fitness.load()), best_fitness(move.best_fitness.load()),
|
||||
worst_fitness(move.worst_fitness.load()), normalized_fitness(std::move(move.normalized_fitness))
|
||||
{
|
||||
move.overall_fitness = 0;
|
||||
move.average_fitness = 0;
|
||||
move.best_fitness = 0;
|
||||
move.worst_fitness = 0;
|
||||
}
|
||||
|
||||
std::atomic<double> overall_fitness = 0;
|
||||
std::atomic<double> average_fitness = 0;
|
||||
std::atomic<double> best_fitness = 0;
|
||||
std::atomic<double> worst_fitness = 1;
|
||||
tracked_vector<double> normalized_fitness{};
|
||||
|
||||
void clear()
|
||||
{
|
||||
overall_fitness = 0;
|
||||
average_fitness = 0;
|
||||
best_fitness = 0;
|
||||
worst_fitness = 0;
|
||||
normalized_fitness.clear();
|
||||
}
|
||||
};
|
||||
|
||||
class population_t
|
||||
{
|
||||
public:
|
||||
|
|
|
@ -0,0 +1,206 @@
|
|||
#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_UTIL_STATISTICS_H
|
||||
#define BLT_GP_UTIL_STATISTICS_H
|
||||
|
||||
#include <blt/gp/util/trackers.h>
|
||||
#include <blt/gp/allocator.h>
|
||||
#include <blt/gp/fwdecl.h>
|
||||
|
||||
namespace blt::gp
|
||||
{
|
||||
struct confusion_matrix_t
|
||||
{
|
||||
public:
|
||||
confusion_matrix_t() = default;
|
||||
|
||||
confusion_matrix_t& is_A_predicted_A()
|
||||
{
|
||||
++is_A_pred_A;
|
||||
return *this;
|
||||
}
|
||||
|
||||
confusion_matrix_t& is_A_predicted_B()
|
||||
{
|
||||
++is_A_pred_B;
|
||||
return *this;
|
||||
}
|
||||
|
||||
confusion_matrix_t& is_B_predicted_A()
|
||||
{
|
||||
++is_B_pred_A;
|
||||
return *this;
|
||||
}
|
||||
|
||||
confusion_matrix_t& is_B_predicted_B()
|
||||
{
|
||||
++is_B_pred_B;
|
||||
return *this;
|
||||
}
|
||||
|
||||
confusion_matrix_t& set_name_a(const std::string& name_a)
|
||||
{
|
||||
name_A = name_a;
|
||||
return *this;
|
||||
}
|
||||
|
||||
confusion_matrix_t& set_name_b(const std::string& name_b)
|
||||
{
|
||||
name_B = name_b;
|
||||
return *this;
|
||||
}
|
||||
|
||||
[[nodiscard]] u64 get_is_a_pred_a() const
|
||||
{
|
||||
return is_A_pred_A;
|
||||
}
|
||||
|
||||
[[nodiscard]] u64 get_is_a_pred_b() const
|
||||
{
|
||||
return is_A_pred_B;
|
||||
}
|
||||
|
||||
[[nodiscard]] u64 get_is_b_pred_b() const
|
||||
{
|
||||
return is_B_pred_B;
|
||||
}
|
||||
|
||||
[[nodiscard]] u64 get_is_b_pred_a() const
|
||||
{
|
||||
return is_B_pred_A;
|
||||
}
|
||||
|
||||
confusion_matrix_t& operator+=(const confusion_matrix_t& op)
|
||||
{
|
||||
is_A_pred_A += op.is_A_pred_A;
|
||||
is_B_pred_A += op.is_B_pred_A;
|
||||
is_A_pred_B += op.is_A_pred_B;
|
||||
is_B_pred_B += op.is_B_pred_B;
|
||||
return *this;
|
||||
}
|
||||
|
||||
confusion_matrix_t& operator/=(const u64 val)
|
||||
{
|
||||
is_A_pred_A /= val;
|
||||
is_B_pred_A /= val;
|
||||
is_A_pred_B /= val;
|
||||
is_B_pred_B /= val;
|
||||
return *this;
|
||||
}
|
||||
|
||||
friend confusion_matrix_t operator+(const confusion_matrix_t& op1, const confusion_matrix_t& op2)
|
||||
{
|
||||
confusion_matrix_t result = op1;
|
||||
result += op2;
|
||||
return result;
|
||||
}
|
||||
|
||||
friend confusion_matrix_t operator/(const confusion_matrix_t& op1, const u64 val)
|
||||
{
|
||||
confusion_matrix_t result = op1;
|
||||
result /= val;
|
||||
return result;
|
||||
}
|
||||
|
||||
[[nodiscard]] std::string pretty_print(const std::string& table_name = "Confusion Matrix") const;
|
||||
|
||||
private:
|
||||
u64 is_A_pred_A = 0;
|
||||
u64 is_A_pred_B = 0;
|
||||
u64 is_B_pred_B = 0;
|
||||
u64 is_B_pred_A = 0;
|
||||
std::string name_A = "A";
|
||||
std::string name_B = "B";
|
||||
};
|
||||
|
||||
struct classifier_results_t : public confusion_matrix_t
|
||||
{
|
||||
public:
|
||||
[[nodiscard]] u64 get_hits() const
|
||||
{
|
||||
return hits;
|
||||
}
|
||||
|
||||
[[nodiscard]] u64 get_size() const
|
||||
{
|
||||
return size;
|
||||
}
|
||||
|
||||
[[nodiscard]] double get_percent_hit() const
|
||||
{
|
||||
return static_cast<double>(hits) / static_cast<double>(hits + misses);
|
||||
}
|
||||
|
||||
void hit()
|
||||
{
|
||||
++hits;
|
||||
}
|
||||
|
||||
void miss()
|
||||
{
|
||||
++misses;
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
u64 hits = 0;
|
||||
u64 misses = 0;
|
||||
};
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
population_stats(population_stats&& move) noexcept:
|
||||
overall_fitness(move.overall_fitness.load()), average_fitness(move.average_fitness.load()), best_fitness(move.best_fitness.load()),
|
||||
worst_fitness(move.worst_fitness.load()), normalized_fitness(std::move(move.normalized_fitness))
|
||||
{
|
||||
move.overall_fitness = 0;
|
||||
move.average_fitness = 0;
|
||||
move.best_fitness = 0;
|
||||
move.worst_fitness = 0;
|
||||
}
|
||||
|
||||
std::atomic<double> overall_fitness = 0;
|
||||
std::atomic<double> average_fitness = 0;
|
||||
std::atomic<double> best_fitness = 0;
|
||||
std::atomic<double> worst_fitness = 1;
|
||||
tracked_vector<double> normalized_fitness{};
|
||||
|
||||
void clear()
|
||||
{
|
||||
overall_fitness = 0;
|
||||
average_fitness = 0;
|
||||
best_fitness = 0;
|
||||
worst_fitness = 0;
|
||||
normalized_fitness.clear();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif //BLT_GP_UTIL_STATISTICS_H
|
2
lib/blt
2
lib/blt
|
@ -1 +1 @@
|
|||
Subproject commit 0869509c6a5fd530efbd57469d2b99b89c22b769
|
||||
Subproject commit 1798980ac6829d5d79c162325a2162aa42917958
|
|
@ -247,7 +247,7 @@ namespace blt::gp
|
|||
blt::size_t total_produced = 0;
|
||||
blt::size_t total_consumed = 0;
|
||||
|
||||
for (const auto& operation : blt::reverse_iterate(operations.begin(), operations.end()))
|
||||
for (const auto& operation : iterate(operations).rev())
|
||||
{
|
||||
if (operation.is_value)
|
||||
{
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* <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/util/statistics.h>
|
||||
#include <blt/format/format.h>
|
||||
#include <numeric>
|
||||
|
||||
namespace blt::gp {
|
||||
|
||||
std::string confusion_matrix_t::pretty_print(const std::string& table_name) const
|
||||
{
|
||||
string::TableFormatter formatter{table_name};
|
||||
formatter.addColumn("Predicted " + name_A);
|
||||
formatter.addColumn("Predicted " + name_B);
|
||||
formatter.addColumn("");
|
||||
|
||||
string::TableRow row;
|
||||
row.rowValues.push_back(std::to_string(is_A_pred_A));
|
||||
row.rowValues.push_back(std::to_string(is_A_pred_B));
|
||||
row.rowValues.push_back("Actual" + name_A);
|
||||
formatter.addRow(row);
|
||||
|
||||
string::TableRow row2;
|
||||
row2.rowValues.push_back(std::to_string(is_B_pred_A));
|
||||
row2.rowValues.push_back(std::to_string(is_B_pred_B));
|
||||
row2.rowValues.push_back("Actual" + name_B);
|
||||
formatter.addRow(row2);
|
||||
|
||||
auto tbl = formatter.createTable(true, true);
|
||||
return std::accumulate(tbl.begin(), tbl.end(), std::string{}, [](const std::string& a, const std::string& b)
|
||||
{
|
||||
return a + "\n" + b;
|
||||
});
|
||||
}
|
||||
|
||||
}
|
|
@ -15,9 +15,10 @@
|
|||
* 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/gp/util/trackers.h>
|
||||
#include <blt/std/logging.h>
|
||||
#include "blt/format/format.h"
|
||||
#include <numeric>
|
||||
|
||||
namespace blt::gp
|
||||
{
|
||||
|
@ -27,4 +28,4 @@ namespace blt::gp
|
|||
BLT_TRACE("%s Allocations: %ld times with a total of %s", name.c_str(), getAllocationDifference(),
|
||||
blt::byte_convert_t(getAllocatedByteDifference()).convert_to_nearest_type().to_pretty_string().c_str());
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue