31 if (conn_a.empty() || conn_b.empty()) {
32 throw std::invalid_argument(
"CompatibilityDistance: both genomes must have at least one connection gene");
35 int max_innovation_a = 0;
36 for (
const auto& c : conn_a) {
37 max_innovation_a = std::max(max_innovation_a, c.innovation);
39 int max_innovation_b = 0;
40 for (
const auto& c : conn_b) {
41 max_innovation_b = std::max(max_innovation_b, c.innovation);
43 int overlap_bound = std::min(max_innovation_a, max_innovation_b);
48 double weight_diff_sum = 0.0;
50 for (
const auto& ca : conn_a) {
51 const auto it = std::find_if(conn_b.begin(), conn_b.end(),
52 [&](
const ConnectionGene& cb) { return cb.innovation == ca.innovation; });
53 if (it != conn_b.end()) {
55 weight_diff_sum += std::fabs(ca.weight - it->weight);
56 }
else if (ca.innovation > overlap_bound) {
62 for (
const auto& cb : conn_b) {
63 const bool in_a = std::any_of(conn_a.begin(), conn_a.end(),
64 [&](
const ConnectionGene& ca) { return ca.innovation == cb.innovation; });
66 if (cb.innovation > overlap_bound) {
74 size_t size_a = conn_a.size();
75 size_t size_b = conn_b.size();
76 size_t larger = std::max(size_a, size_b);
77 double n = (larger < 20) ? 1.0 :
static_cast<double>(larger);
78 double w_bar = (matching > 0) ? weight_diff_sum /
static_cast<double>(matching) : 0.0;
80 return c1 *
static_cast<double>(excess) / n + c2 *
static_cast<double>(disjoint) / n + c3 * w_bar;
97 double compatibility_threshold,
double c1,
double c2,
double c3) {
98 if (population.empty()) {
99 throw std::invalid_argument(
"SpeciatePopulation: population must not be empty");
101 if (compatibility_threshold <= 0.0) {
102 throw std::invalid_argument(
"SpeciatePopulation: compatibility_threshold must be positive");
105 std::vector<std::vector<size_t>> species;
106 std::vector<size_t> representatives;
108 for (
size_t i = 0; i < population.size(); ++i) {
110 for (
size_t s = 0; s < species.size(); ++s) {
112 if (distance < compatibility_threshold) {
113 species[s].push_back(i);
119 species.push_back({i});
120 representatives.push_back(i);
135 const std::vector<std::vector<size_t>>& species) {
136 size_t total_members = 0;
137 for (
const auto& s : species) {
138 total_members += s.size();
140 if (total_members != raw_fitness.size()) {
141 throw std::invalid_argument(
142 "ComputeAdjustedFitness: species must partition exactly raw_fitness.size() individuals");
145 std::vector<double> adjusted(raw_fitness.size(), 0.0);
146 for (
const auto& s : species) {
147 for (
size_t index : s) {
148 adjusted[index] = raw_fitness[index] /
static_cast<double>(s.size());
A NEAT genome: its node and connection genes, growable via structural mutation.
Definition neat_genome.hpp:94
const std::vector< ConnectionGene > & connections() const
Definition neat_genome.hpp:134
Definition acquisition_functions.hpp:16
std::vector< double > ComputeAdjustedFitness(const std::vector< double > &raw_fitness, const std::vector< std::vector< size_t > > &species)
Fitness sharing: each individual's adjusted fitness is its own raw fitness divided by the size of its...
Definition neat_speciation.hpp:134
SpeciesAssignment SpeciatePopulation(const std::vector< NEATGenome > &population, double compatibility_threshold, double c1, double c2, double c3)
Groups population into species: each genome joins the first existing species whose representative (th...
Definition neat_speciation.hpp:96
double CompatibilityDistance(const NEATGenome &a, const NEATGenome &b, double c1, double c2, double c3)
Compatibility distance: delta = c1*E/N + c2*D/N + c3*W_bar, where E is the count of excess genes (inn...
Definition neat_speciation.hpp:28
NEAT genome (Stanley & Miikkulainen, "Evolving Neural Networks through Augmenting Topologies,...
One connection in a NEAT genome: an edge between two node IDs, its weight, whether it is currently ac...
Definition neat_genome.hpp:38
Population grouping into species: each inner vector is a list of indices into the population vector t...
Definition neat_speciation.hpp:85
std::vector< std::vector< size_t > > species
Definition neat_speciation.hpp:86